Files
PHPShop/moneta/class/host/CheckoutView.php
T

185 lines
7.2 KiB
PHP

<?php
declare(strict_types=1);
namespace MonetaPhpShop\host;
use MonetaPhpShop\form\AmountText;
use MonetaPhpShop\form\PaymentForm;
use MonetaPhpShop\form\ReturnAccess;
use MonetaPhpShop\form\ReturnUrls;
use MonetaPhpShop\order\Order;
use MonetaPhpShop\order\PaymentEligibility;
use MonetaPhpShop\protocol\AssistantProtocol;
use MonetaPhpShop\Settings;
/**
* Êíîïêà îïëàòû äëÿ õóêîâ âèòðèíû: ïîñëå îôîðìëåíèÿ çàêàçà (`send_to_order`) è â ëè÷íîì
* êàáèíåòå (`userorderpaymentlink`). Îøèáêà ìîäóëÿ íå äîëæíà ðîíÿòü ñòðàíèöó ìàãàçèíà:
* ïîêóïàòåëü âèäèò íåéòðàëüíûé òåêñò, ïîäðîáíîñòè — â æóðíàëå PHP.
*/
final class CheckoutView
{
private const MESSAGES = [
PaymentEligibility::NOT_CONFIGURED => 'Îïëàòà ÷åðåç Ìîíåòó âðåìåííî íåäîñòóïíà. Ñâÿæèòåñü ñ ìàãàçèíîì.',
PaymentEligibility::ALREADY_PAID => 'Çàêàç îïëà÷åí.',
PaymentEligibility::CANCELLED => 'Çàêàç îòìåí¸í.',
PaymentEligibility::AWAITING_STATUS => 'Çàêàç îáðàáàòûâàåòñÿ ìåíåäæåðîì.',
PaymentEligibility::UNSUPPORTED_CURRENCY => 'Îïëàòà ÷åðåç Ìîíåòó âîçìîæíà òîëüêî â ðóáëÿõ.',
PaymentEligibility::ZERO_AMOUNT => 'Îïëàòà íå òðåáóåòñÿ.',
];
/** Òåêñò êíîïêè îïëàòû; íà êàðòî÷êå ïîñëå îôîðìëåíèÿ ê íåìó äîáàâëÿåòñÿ ñóììà. */
private const BUTTON_TITLE = 'Îïëàòèòü';
private const UNAVAILABLE = 'Îïëàòà âðåìåííî íåäîñòóïíà. Ïîïðîáóéòå ïîçæå èëè ñâÿæèòåñü ñ ìàãàçèíîì.';
/** @var SettingsRepository */
private $settingsRepository;
/** @var OrderRepository */
private $orderRepository;
/** @var ShopContext */
private $shopContext;
public function __construct(
SettingsRepository $settingsRepository,
OrderRepository $orderRepository,
ShopContext $shopContext
) {
$this->settingsRepository = $settingsRepository;
$this->orderRepository = $orderRepository;
$this->shopContext = $shopContext;
}
public static function create(): self
{
return new self(new SettingsRepository(), new OrderRepository(), new ShopContext());
}
/**
* Áëîê íà ñòðàíèöå «Çàêàç îôîðìëåí»: ñóììà è êíîïêà, åñëè çàêàç óæå ìîæíî îïëàòèòü, èíà÷å
* òåêñò î ñîñòîÿíèè çàêàçà. Ðàçìåòêó ñîáèðàåò øàáëîí `payment_forma.tpl` â õóêå; ÷àñòè — â cp1251.
*/
public function afterCheckout(int $orderId): CheckoutBlock
{
return $this->block($orderId, true);
}
/**
* ß÷åéêà «Ñïîñîá îïëàòû» â ëè÷íîì êàáèíåòå: îïèñàíèå îïëàòû è êíîïêà èëè ñîñòîÿíèå çàêàçà, áåç ñóììû.
*/
public function inAccount(int $orderId): string
{
$block = $this->block($orderId, false);
if ($block->isEmpty()) {
return '';
}
$info = ($block->getInfo() === '') ? '' : '<p class="moneta-payment-info">' . $block->getInfo() . '</p>';
return HostCharset::toPage('<div class="moneta-payment">' . $info . $block->getForm() . '</div>');
}
/**
* ×òî ïîêàçàòü ïî ñîñòîÿíèþ çàêàçà: ôîðìó îïëàòû ñ ñóììîé, åñëè çàêàç ìîæíî îïëàòèòü,
* èíà÷å — òåêñò î ñîñòîÿíèè.
*
* @param string $formHtml ôîðìà îïëàòû; íóæíà òîëüêî äëÿ {@see PaymentEligibility::PAYABLE}
* @param string $total ñóììà ê îïëàòå òåêñòîì; ïîêàçûâàåòñÿ òîëüêî âìåñòå ñ ôîðìîé
* @param string $description «Îïèñàíèå îïëàòû» îáû÷íûì òåêñòîì; ïîêàçûâàåòñÿ òîëüêî âìåñòå ñ ôîðìîé:
* «Îïëàòèòå çàêàç» áåç êíîïêè (çàêàç æä¸ò ìåíåäæåðà) ñáèâàë áû ñ òîëêó
*/
public static function compose(
string $eligibility,
string $formHtml,
string $total = '',
string $description = ''
): CheckoutBlock {
if ($eligibility === PaymentEligibility::PAYABLE) {
return new CheckoutBlock($formHtml, $total, self::descriptionHtml($description));
}
return new CheckoutBlock('<p>' . (self::MESSAGES[$eligibility] ?? self::UNAVAILABLE) . '</p>');
}
private function block(int $orderId, bool $afterCheckout): CheckoutBlock
{
try {
$settings = $this->settingsRepository->load();
$order = $this->orderRepository->findById($orderId);
if ($order === null) {
return new CheckoutBlock('');
}
// Ëè÷íûé êàáèíåò îòêðûâàåò çàêàç ïî îäíîìó uid, íå ñâåðÿÿ âëàäåëüöà
// (`users.core/action_order_info.php` ÿäðà): ôîðìó è çàïèñü â ñåññèþ — òîëüêî âëàäåëüöó.
if (!$afterCheckout && !ReturnAccess::isOwner($order, $this->shopContext->sessionUserId())) {
return new CheckoutBlock('');
}
$currency = $this->shopContext->orderCurrency();
$eligibility = PaymentEligibility::check($settings, $order, $currency);
if ($eligibility !== PaymentEligibility::PAYABLE) {
return self::compose($eligibility, '');
}
$this->shopContext->rememberPayableOrder($order->getId());
// Íà êàðòî÷êå ïîñëå îôîðìëåíèÿ — ñóììà îòäåëüíîé ñòðîêîé è â êíîïêå,
// ñî çíàêîì âàëþòû âèòðèíû; â ÿ÷åéêå ëè÷íîãî êàáèíåòà — êîðîòêàÿ êíîïêà.
$amount = '';
$currencyIcon = '';
if ($afterCheckout) {
$amount = AmountText::format($order->getAmount(), $this->shopContext->priceDecimals());
$currencyIcon = $this->shopContext->currencyIcon();
}
$suffix = ($currencyIcon === '') ? '' : ' ' . $currencyIcon;
$formHtml = $this->form(
$settings,
$order,
(string) AssistantProtocol::normalizeCurrency($currency),
($amount === '') ? self::BUTTON_TITLE : self::BUTTON_TITLE . ' ' . $amount,
($amount === '') ? '' : $suffix,
);
$total = ($amount === '') ? '' : $amount . $suffix;
$description = HostCharset::fromDatabase($settings->getPaymentDescription());
return self::compose($eligibility, $formHtml, $total, $description);
} catch (\Throwable $exception) {
(new ErrorLogLogger())->error(
'Êíîïêà îïëàòû çàêàçà ' . $orderId . ' íå ïîñòðîåíà: ' . $exception->getMessage(),
);
return new CheckoutBlock('<p>' . self::UNAVAILABLE . '</p>');
}
}
/**
* Òåêñò ìåð÷àíòà èç íàñòðîåê — â HTML: ýêðàíèðîâàíèå, ïåðåíîñû ñòðîê — `<br>`.
*/
private static function descriptionHtml(string $text): string
{
$text = trim($text);
return ($text === '') ? '' : nl2br(htmlspecialchars($text, ENT_QUOTES, 'Windows-1251'), false);
}
private function form(
Settings $settings,
Order $order,
string $currency,
string $buttonTitle,
string $buttonSuffixHtml
): string {
return PaymentForm::create(
$settings,
$order,
$currency,
$this->shopContext->now(),
new ReturnUrls($this->shopContext->returnPageUrl()),
'Îïëàòà çàêàçà ¹' . $order->getUid(),
$this->shopContext->cms(),
AssistantProtocol::normalizeLocale($this->shopContext->shopLocale()),
)->toHtml($buttonTitle, $buttonSuffixHtml);
}
}