118 lines
5.0 KiB
PHP
118 lines
5.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace paygw_moneta\local;
|
|
|
|
use core\message\message;
|
|
use core_payment\helper;
|
|
use core_user;
|
|
use paygw_moneta\local\order\Order;
|
|
|
|
/**
|
|
* Сообщения покупателю через систему сообщений Moodle (`db/messages.php`):
|
|
* «оплата принята» (`payment_received`) и «ссылка на оплату» (`payment_link`).
|
|
* Плагин не выбирает канал и не шлёт почту сам: веб-уведомление и/или письмо
|
|
* через исходящую почту сайта — по настройкам уведомлений пользователя.
|
|
*
|
|
* @package paygw_moneta
|
|
* @copyright 2026 Moneta Labs {@link https://moneta.ru/}
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
final class BuyerNotifier
|
|
{
|
|
public const PROVIDER = 'payment_received';
|
|
public const PROVIDER_LINK = 'payment_link';
|
|
|
|
public function __construct(
|
|
private readonly Logger $logger = new ErrorLogLogger(),
|
|
) {}
|
|
|
|
/**
|
|
* Сообщение по оплаченному заказу; сбой отправки не должен ломать ответ на
|
|
* Pay URL, поэтому ошибки только логируются.
|
|
*
|
|
* @return int|false id сообщения либо false, если отправка не состоялась
|
|
*/
|
|
public function notifyPaid(Order $order): int|false
|
|
{
|
|
return $this->send(
|
|
order: $order,
|
|
provider: self::PROVIDER,
|
|
stringKey: 'message:paid',
|
|
extra: static fn(Order $order): array => [
|
|
'operationid' => (string) $order->providerTransactionId,
|
|
'url' => helper::get_success_url($order->component, $order->paymentArea, $order->itemId)->out(false),
|
|
],
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Ссылка на оплату только что созданного заказа (настройка шлюза «Отправлять
|
|
* ссылку оплаты на почту»): покупатель может оплатить позже, со страницы
|
|
* `checkout.php`. Сбой отправки не мешает перейти к оплате сейчас.
|
|
*
|
|
* @return int|false id сообщения либо false, если отправка не состоялась
|
|
*/
|
|
public function notifyPaymentLink(Order $order): int|false
|
|
{
|
|
return $this->send(
|
|
order: $order,
|
|
provider: self::PROVIDER_LINK,
|
|
stringKey: 'message:link',
|
|
extra: static fn(Order $order): array => [
|
|
'url' => PaymentFormPage::resumeUrl($order)->out(false),
|
|
],
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param callable(Order): array<string, string> $extra поля строки сообщения сверх общих; `url` обязателен
|
|
*/
|
|
private function send(Order $order, string $provider, string $stringKey, callable $extra): int|false
|
|
{
|
|
try {
|
|
$user = core_user::get_user($order->userId);
|
|
if ($user === false || !empty($user->deleted) || isguestuser($user)) {
|
|
return false;
|
|
}
|
|
|
|
// Значения для подстановок {$a->…} в строках message:* (имя $a задаёт get_string()).
|
|
$placeholders = (object) ([
|
|
'firstname' => $user->firstname,
|
|
'fullname' => fullname($user),
|
|
'description' => $order->snapshot->description,
|
|
'amount' => helper::get_cost_as_string((float) $order->amount->toDecimal(), $order->currency),
|
|
'sitename' => format_string(get_site()->fullname),
|
|
] + $extra($order));
|
|
$body = get_string($stringKey, 'paygw_moneta', $placeholders);
|
|
|
|
$bodyForHtml = get_string(
|
|
$stringKey,
|
|
'paygw_moneta',
|
|
(object) (['url' => '<' . $placeholders->url . '>'] + (array) $placeholders),
|
|
);
|
|
|
|
$message = new message();
|
|
$message->component = 'paygw_moneta';
|
|
$message->name = $provider;
|
|
$message->userfrom = core_user::get_noreply_user();
|
|
$message->userto = $user;
|
|
$message->subject = get_string($stringKey . ':subject', 'paygw_moneta', $placeholders);
|
|
$message->fullmessage = $body;
|
|
$message->fullmessageformat = FORMAT_MARKDOWN;
|
|
$message->fullmessagehtml = markdown_to_html($bodyForHtml);
|
|
$message->smallmessage = $message->subject;
|
|
$message->notification = 1;
|
|
$message->contexturl = $placeholders->url;
|
|
$message->contexturlname = $order->snapshot->description;
|
|
|
|
return message_send($message);
|
|
} catch (\Throwable $exception) {
|
|
$this->logger->error('Сообщение покупателю не отправлено: ' . get_class($exception));
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|