use yii\db\Expression;
use yii\db\Query;
use yii\helpers\ArrayHelper;
+use yii\helpers\Json;
use yii_app\helpers\DataHelper;
use yii_app\models\FlowwowOrdersForm;
use yii_app\records\MarketplaceOrderDelivery;
'testResults' => $testResults,
]);
}
+
+ /**
+ * Эмуляция обработки заказа из JSON (как будто получен через API)
+ * @return string
+ */
+ public function actionTestProcessOrder()
+ {
+ $result = null;
+ $error = null;
+ $orderData = null;
+ $createdOrder = null;
+
+ if (Yii::$app->request->isPost) {
+ $jsonData = Yii::$app->request->post('json_data');
+ $campaignId = Yii::$app->request->post('campaign_id', 109969229);
+
+ try {
+ // Декодируем JSON
+ $data = Json::decode($jsonData);
+
+ // Десериализуем в OrderDTO
+ $orderDto = ObjectSerializer::deserialize($data, '\OpenAPI\Client\Model\OrderDTO', []);
+
+ if (!$orderDto) {
+ throw new \Exception('Не удалось десериализовать данные в OrderDTO');
+ }
+
+ // Формируем структуру как в fetchOrder
+ $orderData = [$campaignId => [$orderDto]];
+
+ // Обрабатываем заказ
+ $result = \yii_app\services\MarketplaceService::processOrders($orderData);
+
+ // Ищем созданный заказ
+ $createdOrder = MarketplaceOrders::find()
+ ->where(['marketplace_order_id' => (string)$orderDto->getId()])
+ ->with(['items', 'delivery'])
+ ->one();
+
+ Yii::$app->session->setFlash('success', 'Заказ успешно обработан!');
+ } catch (\Exception $e) {
+ $error = $e->getMessage();
+ Yii::error("Ошибка обработки тестового заказа: " . $e->getMessage() . "\n" . $e->getTraceAsString());
+ Yii::$app->session->setFlash('error', 'Ошибка: ' . $error);
+ }
+ }
+
+ return $this->render('test-process-order', [
+ 'result' => $result,
+ 'error' => $error,
+ 'orderData' => $orderData,
+ 'createdOrder' => $createdOrder,
+ ]);
+ }
}
}
try {
+ Yii::warning(
+ "fetchOrder: Начало запроса к API - campaignId={$campaignId}, orderId={$orderId}",
+ 'marketplace_fetch_order'
+ );
+
$response = $apiInstance->getOrder($campaignId, $orderId, $contentType);
$order = $response->getOrder();
+ if (!$order) {
+ Yii::error("fetchOrder: API вернуло NULL вместо заказа - campaignId={$campaignId}, orderId={$orderId}", 'marketplace_fetch_order');
+ return [];
+ }
+
// Диагностика для проверки данных заказа
$itemsCount = $order->getItems() ? count($order->getItems()) : 0;
$hasDelivery = $order->getDelivery() !== null;
Yii::warning(
- "fetchOrder: orderId={$orderId}, campaignId={$campaignId}, items={$itemsCount}, delivery=" . ($hasDelivery ? 'YES' : 'NO'),
+ "fetchOrder SUCCESS: orderId={$orderId}, campaignId={$campaignId}, items={$itemsCount}, delivery=" . ($hasDelivery ? 'YES' : 'NO'),
'marketplace_fetch_order'
);
return [$campaignId => [$order]];
} catch (ApiException $e) {
- Yii::error('Ошибка при получении заказа: ' . $e->getMessage());
+ Yii::error(
+ "fetchOrder ERROR: campaignId={$campaignId}, orderId={$orderId}, " .
+ "code={$e->getCode()}, message={$e->getMessage()}, " .
+ "response=" . $e->getResponseBody(),
+ 'marketplace_fetch_order'
+ );
+ return [];
+ } catch (\Exception $e) {
+ Yii::error(
+ "fetchOrder EXCEPTION: campaignId={$campaignId}, orderId={$orderId}, " .
+ "error={$e->getMessage()}, line={$e->getLine()}, file={$e->getFile()}",
+ 'marketplace_fetch_order'
+ );
return [];
}
}
}
}
+ Yii::warning(
+ "Попытка сохранения нового заказа: marketplace_order_id={$marketplaceOrder->marketplace_order_id}, fake={$marketplaceOrder->fake}",
+ 'marketplace_order_creation'
+ );
+
if ($marketplaceOrder->save()) {
+ Yii::warning(
+ "Заказ успешно сохранен, ID={$marketplaceOrder->id}",
+ 'marketplace_order_creation'
+ );
+
self::sendMessageToTelegram($marketplaceOrder->guid, "Новый заказ из ЯМ");
$newOrdersCount += 1;
// Сохраняем данные доставки
$delivery = $order->getDelivery();
+ $items = $order->getItems();
Yii::warning(
- "Новый заказ #{$marketplaceOrder->id}: delivery=" . ($delivery ? 'present' : 'NULL') . ", items count=" . count($order->getItems() ?? []),
+ "Новый заказ #{$marketplaceOrder->id}: delivery=" . ($delivery ? 'present' : 'NULL') .
+ ", items=" . ($items ? count($items) : 'NULL') .
+ ", delivery type=" . ($delivery ? get_class($delivery) : 'N/A'),
'marketplace_order_creation'
);
if ($delivery) {
if ($gps) {
$deliveryModel->latitude = $gps->getLatitude();
$deliveryModel->longitude = $gps->getLongitude();
+ } else {
+ // GPS координаты отсутствуют, устанавливаем значения по умолчанию
+ $deliveryModel->latitude = 0.0;
+ $deliveryModel->longitude = 0.0;
}
}
$shipments = $delivery->getShipments();
// Сохраняем позиции заказа
$items = $order->getItems();
+ Yii::warning(
+ "Начало создания товаров для заказа #{$marketplaceOrder->id}: items=" .
+ ($items ? (is_array($items) ? count($items) : 'not array') : 'NULL') .
+ ", items type=" . ($items ? gettype($items) : 'NULL'),
+ 'marketplace_order_creation'
+ );
+
if (!empty($items)) {
- foreach ($items as $item) {
+ Yii::warning("Товары найдены, начинаем цикл создания", 'marketplace_order_creation');
+ foreach ($items as $idx => $item) {
+ Yii::warning("Создание товара #{$idx}: offerId={$item->getOfferId()}, name={$item->getOfferName()}", 'marketplace_order_creation');
+
$orderItem = new MarketplaceOrderItems();
$orderItem->order_id = $marketplaceOrder->id;
$orderItem->external_item_id = $item->getId();
$orderItem->vat = $item->getVat();
$orderItem->shop_sku = $item->getShopSku();
$orderItem->subsidy = $item->getSubsidy() ?? 0;
- $orderItem->partner_warehouse_id = $item->getPartnerWarehouseId() ?? '';
+ // Если partner_warehouse_id отсутствует, устанавливаем значение по умолчанию
+ $orderItem->partner_warehouse_id = $item->getPartnerWarehouseId() ?? 'N/A';
$orderItem->promos = json_encode($item->getPromos(), JSON_UNESCAPED_UNICODE);
$orderItem->subsidies = json_encode($item->getSubsidies(), JSON_UNESCAPED_UNICODE);
Yii::warning("Товар успешно создан для заказа #{$marketplaceOrder->id}: {$orderItem->offer_name}", 'marketplace_order_creation');
}
}
+ Yii::warning("Завершен цикл создания товаров для заказа #{$marketplaceOrder->id}", 'marketplace_order_creation');
} else {
- Yii::warning("ТоваÑ\80Ñ\8b не Ñ\81озданÑ\8b длÑ\8f заказа #{$marketplaceOrder->id}: items is empty", 'marketplace_order_creation');
+ Yii::warning("ТоваÑ\80Ñ\8b Ð\9dÐ\95 Ñ\81озданÑ\8b длÑ\8f заказа #{$marketplaceOrder->id}: items is empty or NULL", 'marketplace_order_creation');
}
// проверяем и устанавливаем ready_to = 1
$baseUrl = "https://partner.market.yandex.ru/order/";
if ($gps) {
$deliveryModel->latitude = $gps->getLatitude();
$deliveryModel->longitude = $gps->getLongitude();
+ } else {
+ // GPS координаты отсутствуют, устанавливаем значения по умолчанию
+ $deliveryModel->latitude = 0.0;
+ $deliveryModel->longitude = 0.0;
}
}
$dates = $delivery->getDates();
$orderItem->vat = $item->getVat();
$orderItem->shop_sku = $item->getShopSku();
$orderItem->subsidy = $item->getSubsidy() ?? 0;
- $orderItem->partner_warehouse_id = $item->getPartnerWarehouseId() ?? '';
+ // Если partner_warehouse_id отсутствует, устанавливаем значение по умолчанию
+ $orderItem->partner_warehouse_id = $item->getPartnerWarehouseId() ?? 'N/A';
$orderItem->promos = json_encode($item->getPromos(), JSON_UNESCAPED_UNICODE);
$orderItem->subsidies = json_encode($item->getSubsidies(), JSON_UNESCAPED_UNICODE);
$orderItem->count = $item->getCount();
$orderItem->vat = $item->getVat();
$orderItem->shop_sku = $item->getShopSku();
- $orderItem->subsidy = $item->getSubsidy();
- $orderItem->partner_warehouse_id = $item->getPartnerWarehouseId();
+ $orderItem->subsidy = $item->getSubsidy() ?? 0;
+ // Если partner_warehouse_id отсутствует, устанавливаем значение по умолчанию
+ $orderItem->partner_warehouse_id = $item->getPartnerWarehouseId() ?? 'N/A';
$orderItem->promos = json_encode($item->getPromos(), JSON_UNESCAPED_UNICODE);
$orderItem->subsidies = json_encode($item->getSubsidies(), JSON_UNESCAPED_UNICODE);
$orderItem->count = $item->getCount();
$orderItem->vat = $item->getVat();
$orderItem->shop_sku = $item->getShopSku();
- $orderItem->subsidy = $item->getSubsidy();
- $orderItem->partner_warehouse_id = $item->getPartnerWarehouseId();
+ $orderItem->subsidy = $item->getSubsidy() ?? 0;
+ // Если partner_warehouse_id отсутствует, устанавливаем значение по умолчанию
+ $orderItem->partner_warehouse_id = $item->getPartnerWarehouseId() ?? 'N/A';
$orderItem->promos = json_encode($item->getPromos(), JSON_UNESCAPED_UNICODE);
$orderItem->subsidies = json_encode($item->getSubsidies(), JSON_UNESCAPED_UNICODE);
if ($gps) {
$deliveryModel->latitude = $gps->getLatitude();
$deliveryModel->longitude = $gps->getLongitude();
+ } else {
+ // GPS координаты отсутствуют, устанавливаем значения по умолчанию
+ $deliveryModel->latitude = 0.0;
+ $deliveryModel->longitude = 0.0;
}
}
$shipments = $delivery->getShipments();
$orderItem->vat = $item->getVat();
$orderItem->shop_sku = $item->getShopSku();
$orderItem->subsidy = $item->getSubsidy() ?? 0;
- $orderItem->partner_warehouse_id = $item->getPartnerWarehouseId() ?? '';
+ // Если partner_warehouse_id отсутствует, устанавливаем значение по умолчанию
+ $orderItem->partner_warehouse_id = $item->getPartnerWarehouseId() ?? 'N/A';
$orderItem->promos = json_encode($item->getPromos(), JSON_UNESCAPED_UNICODE);
$orderItem->subsidies = json_encode($item->getSubsidies(), JSON_UNESCAPED_UNICODE);
<?= Html::a('Проверка почты', ['/marketplace-orders/get-flowwow-orders'], ['class' => 'btn btn-success']) ?>
<?= Html::a('Статусы заказов в 1С', ['/crud/marketplace-order1c-statuses/index'], ['class' => 'btn btn-success']) ?>
<?= Html::a('Остатки Яндекс', ['/marketplace-orders/yandex-stocks'], ['class' => 'btn btn-success']) ?>
+ <?= Html::a('🧪 Тест обработки JSON', ['/marketplace-orders/test-process-order'], ['class' => 'btn btn-warning']) ?>
</p>
<div class="create-test-order-form mb-4">
--- /dev/null
+<?php
+
+use yii\helpers\Html;
+use yii\helpers\Json;
+use yii\widgets\ActiveForm;
+
+/** @var yii\web\View $this */
+/** @var array|null $result */
+/** @var string|null $error */
+/** @var array|null $orderData */
+/** @var \yii_app\records\MarketplaceOrders|null $createdOrder */
+
+$this->title = 'Тест обработки заказа из JSON';
+$this->params['breadcrumbs'][] = ['label' => 'Заказы маркетплейсов', 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+
+// Пример JSON для заполнения
+$exampleJson = <<<JSON
+{
+ "id": 52296662465,
+ "status": "PROCESSING",
+ "substatus": "STARTED",
+ "creationDate": "18-12-2025 17:39:57",
+ "updatedAt": "18-12-2025 17:39:57",
+ "currency": "RUR",
+ "itemsTotal": 2126,
+ "deliveryTotal": 149,
+ "buyerItemsTotal": 2126,
+ "buyerTotal": 2275,
+ "buyerItemsTotalBeforeDiscount": 2126,
+ "buyerTotalBeforeDiscount": 2275,
+ "paymentType": "POSTPAID",
+ "paymentMethod": "CARD_ON_DELIVERY",
+ "fake": true,
+ "items": [
+ {
+ "id": 1015257692,
+ "offerId": "FW0201",
+ "offerName": "Нежный весенний букет из 5 белых французских роз в белой упаковке",
+ "price": 2126,
+ "buyerPrice": 2126,
+ "buyerPriceBeforeDiscount": 2126,
+ "priceBeforeDiscount": 2126,
+ "count": 1,
+ "vat": "VAT_20",
+ "shopSku": "FW0201",
+ "promos": null,
+ "instances": null,
+ "details": null,
+ "subsidies": null,
+ "requiredInstanceTypes": null,
+ "tags": null
+ }
+ ],
+ "subsidies": null,
+ "delivery": {
+ "type": "DELIVERY",
+ "serviceName": "Доставка",
+ "deliveryPartnerType": "YANDEX_MARKET",
+ "dates": {
+ "fromDate": "19-12-2025",
+ "toDate": "19-12-2025",
+ "fromTime": "10:00:00",
+ "toTime": "18:00:00"
+ },
+ "region": {
+ "id": 47,
+ "name": "Нижний Новгород",
+ "type": "CITY"
+ },
+ "address": {
+ "country": "Россия",
+ "city": "Нижний Новгород",
+ "street": "Тест",
+ "house": "1",
+ "entrance": "1",
+ "apartment": "1"
+ },
+ "vat": "VAT_20",
+ "deliveryServiceId": 1999,
+ "liftPrice": 0,
+ "tracks": null,
+ "shipments": [
+ {
+ "id": 811965629,
+ "shipmentDate": "19-12-2025",
+ "tracks": null,
+ "boxes": [
+ {
+ "id": 731661535,
+ "fulfilmentId": "52296662465-1"
+ }
+ ]
+ }
+ ]
+ },
+ "buyer": {
+ "type": "PERSON"
+ },
+ "notes": "Тест",
+ "taxSystem": "OSN",
+ "cancelRequested": false
+}
+JSON;
+
+?>
+
+<div class="marketplace-orders-test-process p-4">
+ <h1><?= Html::encode($this->title) ?></h1>
+
+ <div class="alert alert-info">
+ <h4>Инструкция:</h4>
+ <ol>
+ <li>Вставьте JSON данные заказа в поле ниже (пример уже заполнен)</li>
+ <li>Укажите Campaign ID (по умолчанию 109969229)</li>
+ <li>Нажмите "Обработать заказ"</li>
+ <li>Система эмулирует получение заказа через API и создаст его в БД</li>
+ </ol>
+ <p><strong>Примечание:</strong> Если заказ с таким ID уже существует, он будет обновлен.</p>
+ </div>
+
+ <?php if (Yii::$app->session->hasFlash('success')): ?>
+ <div class="alert alert-success alert-dismissible">
+ <button type="button" class="close" data-dismiss="alert">×</button>
+ <?= Yii::$app->session->getFlash('success') ?>
+ </div>
+ <?php endif; ?>
+
+ <?php if (Yii::$app->session->hasFlash('error')): ?>
+ <div class="alert alert-danger alert-dismissible">
+ <button type="button" class="close" data-dismiss="alert">×</button>
+ <?= Yii::$app->session->getFlash('error') ?>
+ </div>
+ <?php endif; ?>
+
+ <div class="row">
+ <div class="col-md-6">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Входные данные</h3>
+ </div>
+ <div class="panel-body">
+ <?php $form = ActiveForm::begin(['method' => 'post']); ?>
+
+ <div class="form-group">
+ <label for="campaign_id">Campaign ID</label>
+ <input type="text"
+ class="form-control"
+ id="campaign_id"
+ name="campaign_id"
+ value="109969229"
+ placeholder="109969229">
+ <small class="form-text text-muted">ID кампании в Яндекс.Маркет</small>
+ </div>
+
+ <div class="form-group">
+ <label for="json_data">JSON данные заказа</label>
+ <textarea class="form-control"
+ id="json_data"
+ name="json_data"
+ rows="20"
+ style="font-family: monospace; font-size: 12px;"
+ placeholder="Вставьте JSON здесь..."><?= Html::encode($exampleJson) ?></textarea>
+ <small class="form-text text-muted">JSON структура OrderDTO из Яндекс.Маркет API</small>
+ </div>
+
+ <div class="form-group">
+ <?= Html::submitButton('Обработать заказ', ['class' => 'btn btn-primary btn-lg']) ?>
+ <?= Html::a('Очистить', ['test-process-order'], ['class' => 'btn btn-default']) ?>
+ </div>
+
+ <?php ActiveForm::end(); ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-md-6">
+ <?php if ($result !== null): ?>
+ <div class="panel panel-success">
+ <div class="panel-heading">
+ <h3 class="panel-title">Результат обработки</h3>
+ </div>
+ <div class="panel-body">
+ <h4>Статистика:</h4>
+ <ul>
+ <li><strong>Новых заказов:</strong> <?= $result['newOrders'] ?? 0 ?></li>
+ <li><strong>Обновленных заказов:</strong> <?= $result['updateOrders'] ?? 0 ?></li>
+ </ul>
+
+ <?php if ($createdOrder): ?>
+ <hr>
+ <h4>Созданный/обновленный заказ:</h4>
+ <table class="table table-bordered table-sm">
+ <tr>
+ <th>ID в ERP</th>
+ <td><?= $createdOrder->id ?></td>
+ </tr>
+ <tr>
+ <th>ID заказа МП</th>
+ <td><?= $createdOrder->marketplace_order_id ?></td>
+ </tr>
+ <tr>
+ <th>Магазин</th>
+ <td><?= $createdOrder->store ? $createdOrder->store->name : '-' ?></td>
+ </tr>
+ <tr>
+ <th>Маркетплейс</th>
+ <td><?= $createdOrder->marketplace_name ?? '-' ?></td>
+ </tr>
+ <tr>
+ <th>Статус</th>
+ <td><?= $createdOrder->status ? $createdOrder->status->code : '-' ?></td>
+ </tr>
+ <tr>
+ <th>Подстатус</th>
+ <td><?= $createdOrder->substatus ? $createdOrder->substatus->code : '-' ?></td>
+ </tr>
+ <tr>
+ <th>Сумма</th>
+ <td><?= Yii::$app->formatter->asCurrency($createdOrder->total, 'RUB') ?></td>
+ </tr>
+ <tr>
+ <th>Тестовый</th>
+ <td><?= $createdOrder->fake ? 'Да' : 'Нет' ?></td>
+ </tr>
+ <tr>
+ <th>Дата создания</th>
+ <td><?= $createdOrder->creation_date ?></td>
+ </tr>
+ </table>
+
+ <h4>Товары (<?= count($createdOrder->items) ?>):</h4>
+ <?php if (!empty($createdOrder->items)): ?>
+ <table class="table table-bordered table-sm">
+ <thead>
+ <tr>
+ <th>ID</th>
+ <th>Артикул</th>
+ <th>Название</th>
+ <th>Цена</th>
+ <th>Кол-во</th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($createdOrder->items as $item): ?>
+ <tr>
+ <td><?= $item->id ?></td>
+ <td><?= Html::encode($item->offer_id) ?></td>
+ <td><?= Html::encode($item->offer_name) ?></td>
+ <td><?= Yii::$app->formatter->asCurrency($item->price, 'RUB') ?></td>
+ <td><?= $item->count ?></td>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+ </table>
+ <?php else: ?>
+ <div class="alert alert-warning">Товары не созданы!</div>
+ <?php endif; ?>
+
+ <h4>Доставка:</h4>
+ <?php if ($createdOrder->delivery): ?>
+ <table class="table table-bordered table-sm">
+ <tr>
+ <th>Тип</th>
+ <td><?= Html::encode($createdOrder->delivery->type) ?></td>
+ </tr>
+ <tr>
+ <th>Сервис</th>
+ <td><?= Html::encode($createdOrder->delivery->service_name) ?></td>
+ </tr>
+ <tr>
+ <th>Адрес</th>
+ <td>
+ <?= Html::encode($createdOrder->delivery->city) ?>,
+ <?= Html::encode($createdOrder->delivery->street) ?>
+ <?= Html::encode($createdOrder->delivery->house) ?>
+ </td>
+ </tr>
+ <tr>
+ <th>Период доставки</th>
+ <td>
+ <?= $createdOrder->delivery->delivery_start ?? '-' ?> -
+ <?= $createdOrder->delivery->delivery_end ?? '-' ?>
+ </td>
+ </tr>
+ </table>
+ <?php else: ?>
+ <div class="alert alert-warning">Доставка не создана!</div>
+ <?php endif; ?>
+
+ <div class="mt-3">
+ <?= Html::a('Просмотреть заказ', ['view', 'id' => $createdOrder->id], ['class' => 'btn btn-success']) ?>
+ <?= Html::a('Список заказов', ['index'], ['class' => 'btn btn-default']) ?>
+ </div>
+ <?php endif; ?>
+ </div>
+ </div>
+ <?php endif; ?>
+
+ <?php if ($error): ?>
+ <div class="panel panel-danger">
+ <div class="panel-heading">
+ <h3 class="panel-title">Ошибка обработки</h3>
+ </div>
+ <div class="panel-body">
+ <pre style="color: red;"><?= Html::encode($error) ?></pre>
+ </div>
+ </div>
+ <?php endif; ?>
+ </div>
+ </div>
+
+ <div class="panel panel-info mt-4">
+ <div class="panel-heading">
+ <h3 class="panel-title">Проверка логов</h3>
+ </div>
+ <div class="panel-body">
+ <p>Для просмотра детальных логов обработки выполните в контейнере:</p>
+ <pre>tail -f erp24/runtime/logs/app.log | grep -E "marketplace_order_creation|marketplace_fetch_order"</pre>
+
+ <p>Или проверьте последние записи:</p>
+ <pre>tail -100 erp24/runtime/logs/app.log | grep marketplace_order_creation</pre>
+ </div>
+ </div>
+</div>
+
+<style>
+.panel {
+ margin-bottom: 20px;
+}
+.panel-heading {
+ padding: 10px 15px;
+ border-bottom: 1px solid transparent;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel-title {
+ margin-top: 0;
+ margin-bottom: 0;
+ font-size: 16px;
+ font-weight: bold;
+}
+.panel-body {
+ padding: 15px;
+}
+.panel-default {
+ border-color: #ddd;
+}
+.panel-default > .panel-heading {
+ background-color: #f5f5f5;
+ border-color: #ddd;
+}
+.panel-success {
+ border-color: #d6e9c6;
+}
+.panel-success > .panel-heading {
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+ color: #3c763d;
+}
+.panel-danger {
+ border-color: #ebccd1;
+}
+.panel-danger > .panel-heading {
+ background-color: #f2dede;
+ border-color: #ebccd1;
+ color: #a94442;
+}
+.panel-info {
+ border-color: #bce8f1;
+}
+.panel-info > .panel-heading {
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+ color: #31708f;
+}
+</style>
+