database = $database; } public function findPaidOperation(int $orderId): ?string { $value = $this->database->fetchValue( 'SELECT operation_id FROM `' . self::table() . '` WHERE paid_order_id = ? LIMIT 1', [$orderId], ); return $value === null ? null : (string) $value; } public function recordPaid(CallbackNotification $notification, Order $order, string $event): bool { try { $this->insert($notification, $order, $event, ResultCode::paid(), $order->getId()); } catch (RuntimeException $exception) { if ($exception->getCode() === Database::ER_DUP_ENTRY) { return false; } throw $exception; } return true; } public function note( CallbackNotification $notification, ?Order $order, string $event, ?ResultCode $resultCode ): void { $this->insert($notification, $order, $event, $resultCode, null); } /** * Последние записи журнала для админки, новые сверху. * * @param string|null $orderUid только записи этого заказа ({@see TransactionId::orderUidFromInput()}): * с этим `order_uid` или — если заказ не распознан — с `MNT_TRANSACTION_ID` вида `<номер>_…` * * @return array> */ public function latest(int $limit, ?string $orderUid = null): array { $where = ''; $params = []; if ($orderUid !== null) { // В номере заказа нет `_` и `%` (TransactionId::ORDER_UID) — экранировать в LIKE // нужно только сам разделитель `_`. $where = ' WHERE order_uid = ? OR transaction_id LIKE ?'; $params = [$orderUid, $orderUid . '\\' . TransactionId::SEPARATOR . '%']; } $params[] = $limit; return $this->database->fetchAll( 'SELECT id, created_at, command, transaction_id, operation_id, order_id, order_uid, amount,' . ' test_mode, result_code, event FROM `' . self::table() . '`' . $where . ' ORDER BY id DESC LIMIT ?', $params, ); } public static function table(): string { $table = $GLOBALS['SysValue']['base'][ModuleInfo::PATH]['moneta_operations'] ?? null; // Явный класс, а не \w: без /u \w следует локали, а PHPShop ставит свою (setlocale в // class/base.class.php) — в cp1251 \w пропустил бы кириллицу в имя таблицы, которое идёт в SQL. if (!is_string($table) || preg_match('/\A[0-9A-Za-z_]+\z/', $table) !== 1) { throw new RuntimeException('Модуль не установлен: нет таблицы операций в конфигурации.'); } return $table; } private function insert( CallbackNotification $notification, ?Order $order, string $event, ?ResultCode $resultCode, ?int $paidOrderId ): void { $amount = $notification->getAmount(); $this->database->execute( 'INSERT INTO `' . self::table() . '` (created_at, command, transaction_id, operation_id, order_id,' . ' order_uid, amount, test_mode, result_code, event, paid_order_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [ time(), $notification->isCheck() ? $notification->getCommand() : self::COMMAND_PAY, $notification->getTransactionId(), $notification->getOperationId(), ($order !== null) ? $order->getId() : 0, ($order !== null) ? $order->getUid() : '', ($amount !== null) ? $amount->toDecimal() : '', $notification->getRawTestMode(), ($resultCode !== null) ? $resultCode->getValue() : null, $event, $paidOrderId, ], ); } }