findOne(['id' => '=' . $id]); } public function findByUid(string $uid): ?Order { if (preg_match('/\A' . TransactionId::ORDER_UID . '\z/', $uid) !== 1) { return null; } return $this->findOne(['uid' => "='" . $uid . "'"]); } /** * Как штатные модули ядра: строка в журнале оплат, `changeStatus()` (письмо покупателю, * склад, мессенджеры — по настройкам статуса) и флаг `paid`. `ofd()` ядра не вызывается: * чек пробивает касса MONETA. */ public function markPaid(Order $order, int $paidStatus, Money $amount): void { $database = Database::fromHost(); if ($paidStatus === Settings::STATUS_PAID_BY_GATEWAY) { $this->ensurePaidByGatewayStatus($database); } $this->logPayment($database, $order, $amount); $orderFunction = new PHPShopOrderFunction($order->getId()); $orderFunction->changeStatus($paidStatus, $order->getStatusId()); $orderFunction->changePaymentStatus(1); } /** * `phpshop_payment`: ключ — номер заказа без дефиса числом (`4-36` -> 436), по нему ядро * показывает дату оплаты (`PHPShopOrderFunction::checkPay()`). Номер не штатного вида * (переопределён хуком `setNum`) в эту таблицу не записывается — запись пропускается. */ private function logPayment(Database $database, Order $order, Money $amount): void { if (preg_match('/\A([0-9]+)-([0-9]+)\z/', $order->getUid(), $matches) !== 1) { return; } $database->execute( 'INSERT IGNORE INTO `' . self::table('payment') . '` (uid, name, sum, datas) VALUES (?, ?, ?, ?)', [(int) ($matches[1] . $matches[2]), self::PAYMENT_LOG_NAME, $amount->toDecimal(), time()], ); } private function ensurePaidByGatewayStatus(Database $database): void { $database->execute( 'INSERT IGNORE INTO `' . self::table('order_status') . "` (id, name, color, external_code, bot_message)" . " VALUES (?, ?, '#ccff00', '', '')", [Settings::STATUS_PAID_BY_GATEWAY, HostCharset::toDatabase(self::STATUS_PAID_BY_GATEWAY_NAME)], ); } private static function table(string $key): string { $table = $GLOBALS['SysValue']['base'][$key] ?? 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("Нет таблицы ядра {$key} в конфигурации."); } return $table; } /** * @param array $where */ private function findOne(array $where): ?Order { $orm = new PHPShopOrm($GLOBALS['SysValue']['base']['orders']); $orm->debug = false; $row = $orm->select(['*'], $where, false, ['limit' => 1]); if (!is_array($row) || empty($row['id'])) { return null; } $details = @unserialize((string) ($row['orders'] ?? ''), ['allowed_classes' => false]); if (!is_array($details)) { $details = []; } foreach (['fio', 'tel'] as $field) { if (isset($row[$field]) && is_string($row[$field])) { $row[$field] = HostCharset::fromDatabase($row[$field]); } } // Названия товаров в корзине — в кодировке БД, как и остальные строки заказа. if (isset($details['Cart']['cart']) && is_array($details['Cart']['cart'])) { foreach ($details['Cart']['cart'] as $key => $product) { if (is_array($product) && isset($product['name']) && is_string($product['name'])) { $details['Cart']['cart'][$key]['name'] = HostCharset::fromDatabase($product['name']); } } } return Order::fromRow($row, $details); } }