Files
Moodle/classes/local/BuyerNotifier.php
T

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;
}
}
}