Repository navigation
feat(core): add opt-in inventory reserve, commit and release - #603
Conversation
… release Conflict resolution: combine with merged PR 596 lifecycle gate — ms3_order_status factory now takes lifecycle ports + OrderInventoryCoordinator, dependency map merged, persistStatusWithInventory supersedes inline persist, event-failure path runs undoUncommittedNewStatus + rollbackStatus.
|
Этот PR включён в тестовую интеграционную сборку всех открытых PR MiniShop3: AgelxNash/MiniShop3, ветка Сборка нужна, чтобы проверить совместимость взаимозависимых серий PR до их мержа — при последовательном слиянии они конфликтуют друг с другом. Это не ревью и не конкурирующий PR: авторство сохранено (1 PR = 1 коммит с исходным автором), ветка пересобирается по мере обновления PR. Как вошёл в сборку: Конфликт со слитым #596 (lifecycle gate) разрешён: фабрика |
|
Желаю скорейшего ревью и мержа! Красивый PR 👏 |
0edad25 to
0856c69
Compare
|
Проверил. С текущей Архитектурный вопрос общий с #596 — описал там: #596 (comment). Коротко: порты из #596 складу не подходят, а откаты двух PR при объединении дают рассинхрон статуса и остатка. Нужна одна модель смены статуса с транзакцией, в которой резерв может запретить переход. Ниже — то, что относится только к складу. 1. Гонка внутри одного заказа
Два одновременных вызова для одного заказа (двойной клик «Отменить», повтор запроса) оба увидят Переход состояния журнала нужно сделать условным — 2. Незаполненный остаток
Там же стоит указать, что остаток общий на товар: Порядок вливанияПосле вливания любого PR линии остальные конфликтуют. Предлагаю порядок #605 → #604 → #596 → #603, то есть этот PR — последним, после ребейза на |
0856c69 to
54eedad
Compare
|
Rebased onto current |
b492158 to
32b2abb
Compare
|
@Ibochkarev после ревью 14.09 ветки #596 и #603 только перебазированы на Открытыми остаются: Модель смены статуса (#596 и #603 вместе) — #596 (comment). В #596 по-прежнему порты после #603, гонка внутри одного заказа. #603, незаполненный остаток. Прежде чем смотреть дальше, нужен ответ по модели смены статуса. |
* feat(order): lifecycle gate with ports, idempotency, and rollback Make OrderStatusService the non-draft status gate: optional transition allow-list, NullOrderLifecyclePorts for #589–#591, idempotent retries, and status rollback when after-event or a port fails. * refactor(order): align status change with in-TX ports, no post-commit rollback Ports run before status_id persist inside an optional DB transaction. msOnChangeOrderStatus failure no longer compensates with a second save, so status and future inventory stay consistent (#596 / #603 contract). * fix(order): join open transactions and log status before the after-event Nested beginTransaction() threw when change() ran inside an existing PDO transaction. The status log is written after commit and before msOnChangeOrderStatus, and shipment sync uses ensure() so a webhook retry is not rejected as already set. * fix(order): detect an open transaction on xPDO's PDO handle xPDO has no inTransaction() method, so the previous check never started a transaction on MODX. Use $modx->pdo->inTransaction() instead. * fix(order): align shipment status mocks with ensure() and PHPStan Webhook tests still stubbed change() after sync moved to ensure(), so CI saw no status update. Drop the null coalesce on xPDO's pdo property.
32b2abb to
18b5015
Compare
|
Ветка на текущей beta, #596 уже влит. Если
В Коммит |
|
Спасибо за переделку — условный переход журнала и предупреждение в описании настройки на месте, замечания от 14.09 закрыты. Ветка сливается с актуальной Но при включённой настройке на живом MODX складской учёт не работает вообще. 1. Склад ломает любую смену статусаПроверил на dev:
В журнале MODX: Причина в проводке. Проверил обе ветки напрямую на dev:
Почему не поймали тесты: юнит-тесты используют Правка на строку: передавать 2.
|
Stock on msProductData was display-only, so checkout could oversell. Core now exposes ms3_inventory with a default atomic store, wired into submit and status changes, off unless ms3_inventory_enabled is on.
…ency Failed New after-events now release stock, numbered drafts drop num when inventory is on, and release/commit paths no longer leave a half-written ledger.
ms3_inventory_reservations is PDO-backed with no xPDO map; testbench schema check must skip it the same way as shipment event tables.
Two releases of one order could both read reserved and both restore stock. Stock now changes only after a conditional state update, and the setting text warns that empty stock is zero and shared across option variants.
The stock store was built with modX, which has beginTransaction() but no inTransaction(), so every status change nested a transaction and failed. Pass $modx->pdo, keep committed status after the after-event, and compensate a failed save without treating the in-memory paid status as final.
38e162e to
7a1182b
Compare
PdoInventoryStockStore now takes PDO, so method_exists($db, 'prepare') is dead.
Описание
Поле
stockбыло только для витрины и импорта. Корзина и оформление его не читали, списания не было, два покупателя могли взять последний экземпляр.В Core появился контракт
InventoryServiceInterface(DIms3_inventory) и реализация наms3_products.stockплюс журналms3_inventory_reservations. Учёт включается настройкойms3_inventory_enabled(по умолчанию выключена). Тогда:ms3_status_new) резервирует остаток атомарнымUPDATE … WHERE stock >= qtyв одной транзакции со сменойstatus_idms3_status_paid) фиксирует резервms3_status_canceled) до commit возвращает остатокpayment->send()(в том числеfalseвместо массива) переводит заказ в отмену, чтобы не оставлять New без холдаmsOnChangeOrderStatusпосле перехода в New отпускает резерв и откатываетstatus_idВнешний склад подменяется через
ms3_inventory. СобытияmsOnBeforeInventory*/msOnInventory*(Reserve, Commit, Release).releaseне восстанавливает stock, если резерв уже committed (обходOrderStatusServiceу кастомных провайдеров). Мультисклад, партии и ERP-sync в этот PR не входят.Документация вызовов:
setting_ms3_inventory_enabled_desc(ru/en) и phpdocInventoryServiceInterface.Тип изменений
Связанные Issues
Closes #589
Как это было протестировано?
GitHub Actions на HEAD
0edad252(run 32212167139):composer ci:php,composer stan,npm run lint:ciв CI)ms3_inventory_enabled=1Конфигурация тестирования:
feat/issue-589-inventory-abstractionотbeta(коммитыec5b1bbd,0edad252)Скриншоты (если применимо)
N/A, backend.
Чеклист
composer stan)npm run lint:ci) — CI pass, Vue не тронутДополнительные заметки
Второй коммит закрыл разрывы ревью:
send() === falseбольше не оставляет New с холдом, after-event на New отпускает сток, номер черновика снимается при фейле до New, ledger reserve/commit/release пишется в одной TX со сменой статуса, mysql-тест гонки идёт на двух соединениях,InMemoryInventoryStockStoreлежит вtests/support/.Номер заказа и reserve по-прежнему в разных транзакциях. Assert до номера, reserve в TX со сменой статуса на New. Второй checkout последнего qty может получить номер и упасть на reserve. Номер тогда снимается, дырявого hold нет.