feat(core): add opt-in inventory reserve, commit and release - #603
feat(core): add opt-in inventory reserve, commit and release#603Ibochkarev wants to merge 2 commits into
Conversation
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.
… 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 👏 |
Описание
Поле
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 нет.