feat: moneta 2.0, MONETA.Assistant payment module for PHPShop 6.7+
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user