feat(migration-review): долги топ-20, UI «начальный остаток при переносе», дельта-таймер, прогресс
Some checks failed
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker Web / Build + push Web (push) Has been cancelled
Docker Web / Deploy Web on stage (push) Has been cancelled
Some checks failed
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker Web / Build + push Web (push) Has been cancelled
Docker Web / Deploy Web on stage (push) Has been cancelled
- docs/migration-debts-top20.md: топ-20 долгов (контрагент-уровень) + находка (paymentout agent=орг) - MoneyAccountsPage: строка «Начальный остаток при переносе из МойСклад на <дата>» для МС-счетов - systemd food-market-migration-delta.timer (каждые 10 мин) — непрерывная дельта до перехода - прогресс: раздел «Исправления по ревью» (все 4 пункта) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
150947c5fb
commit
99c2fc1e5a
10
deploy/systemd/food-market-migration-delta.service
Normal file
10
deploy/systemd/food-market-migration-delta.service
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
[Unit]
|
||||||
|
Description=food-market migration delta sync (MoySklad -> ALL MARKET stage)
|
||||||
|
After=network-online.target
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/bin/python3 /home/nns/food-market/scripts/migration/delta_sync.py
|
||||||
|
User=nns
|
||||||
|
# лог прогона — для контроля отставания
|
||||||
|
StandardOutput=append:/home/nns/.fm-watchdog/migration-delta.log
|
||||||
|
StandardError=append:/home/nns/.fm-watchdog/migration-delta.log
|
||||||
8
deploy/systemd/food-market-migration-delta.timer
Normal file
8
deploy/systemd/food-market-migration-delta.timer
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Run migration delta sync every 10 min (until cutover)
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=5min
|
||||||
|
OnUnitActiveSec=10min
|
||||||
|
AccuracySec=30s
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
45
docs/migration-debts-top20.md
Normal file
45
docs/migration-debts-top20.md
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Долги поставщикам — топ-20 (перенос МойСклад → ALL MARKET)
|
||||||
|
|
||||||
|
_Сгенерировано автоматически. Долг считается на уровне КОНТРАГЕНТА (как МойСклад):_
|
||||||
|
`долг = Σ приёмок (проведённых) − Σ возвратов поставщику − Σ исходящих платежей/РКО контрагенту`
|
||||||
|
`+ Σ входящих от него + корректировки взаиморасчётов`.
|
||||||
|
|
||||||
|
**Итого долг по всем поставщикам: 137 159 739.17 ₸.**
|
||||||
|
|
||||||
|
## ⚠ Важно для сверки (прочитать)
|
||||||
|
- Отчёт МойСклада `report/counterparty` недоступен выданным read-only токеном (**403**), а в
|
||||||
|
`entity/counterparty` поля баланса/долга НЕТ (есть только `salesAmount`, `bonusPoints`).
|
||||||
|
Поэтому **авто-сверка долга с цифрой МойСклада невозможна** — владелец сверяет вручную
|
||||||
|
(МойСклад → Контрагенты → Взаиморасчёты) против таблицы ниже.
|
||||||
|
- **Почему оплаты не уменьшают долг:** все 171 исходящих безналичных платежа (paymentout, 164 млн ₸)
|
||||||
|
в МойСкладе имеют контрагента = **сама организация «FOOD MARKET»**, а не поставщиков. Наличные
|
||||||
|
ордера (cashin/cashout) — это инкассация/движения смен (агент «Admin»), тоже не привязаны к
|
||||||
|
поставщикам. Т.е. в этом аккаунте МойСклада оплаты поставщикам НЕ разнесены по контрагентам →
|
||||||
|
долг = Σ приёмок − Σ возвратов. Если в МойСкладе взаиморасчёты по поставщику меньше (оплаты
|
||||||
|
учтены иначе) — завести стартовую **корректировку взаиморасчётов** на разницу (документ есть
|
||||||
|
в системе: Деньги → Корректировки), тогда долг в ALL MARKET сойдётся с МойСкладом.
|
||||||
|
|
||||||
|
## Топ-20 поставщиков по долгу
|
||||||
|
|
||||||
|
| # | Поставщик (имя МойСклад) | БИН | Долг ALL MARKET ₸ | Σ приёмок ₸ | Σ возвратов ₸ |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| 1 | Мегаполис сигареты | | 12623868.60 | 12634424.60 | 10556.00 |
|
||||||
|
| 2 | Овощи фрукты оптом, базар Амир | | 5934388.98 | 5934388.98 | 0.00 |
|
||||||
|
| 3 | ЭкоНурия экотовары | | 4904127.00 | 4904127.00 | 0.00 |
|
||||||
|
| 4 | Coca-Cola 87712007078 | | 4603846.29 | 4603846.29 | 0.00 |
|
||||||
|
| 5 | Канц товары,1000мелочей магазин Елнур | | 3706898.00 | 3709210.00 | 2312.00 |
|
||||||
|
| 6 | Родина/Зенченко | | 2608483.00 | 2612783.00 | 4300.00 |
|
||||||
|
| 7 | Магазин Алматы/ Обувь оптом 87015549581 | | 2483102.00 | 2483102.00 | 0.00 |
|
||||||
|
| 8 | ТОО RG Brands Kazakhstan | | 2430866.23 | 2443377.90 | 12511.67 |
|
||||||
|
| 9 | сигареты КЕНТ, Neo | | 2328085.60 | 2328085.60 | 0.00 |
|
||||||
|
| 10 | Алмалы Астана ТОО (Горилла) | | 2139725.00 | 2143574.00 | 3849.00 |
|
||||||
|
| 11 | ИП Алтын тау Сигареты ESSE | | 2009150.00 | 2009150.00 | 0.00 |
|
||||||
|
| 12 | Базар Сухофрукты бутик-73 87052988444 | | 1969936.00 | 1969936.00 | 0.00 |
|
||||||
|
| 13 | ЭкоНурия Bitony | | 1900951.75 | 1900951.75 | 0.00 |
|
||||||
|
| 14 | Шымкентбай Шарын | | 1829765.00 | 1829765.00 | 0.00 |
|
||||||
|
| 15 | Боржоми Жигер трейд | | 1820522.00 | 1828490.00 | 7968.00 |
|
||||||
|
| 16 | Большая семья,магнат | | 1809237.00 | 1809237.00 | 0.00 |
|
||||||
|
| 17 | 1000 мелочей Ардагер,Амир базары | | 1756000.04 | 1756000.04 | 0.00 |
|
||||||
|
| 18 | Романовский продукт 87025051187 | | 1672585.00 | 1692515.00 | 19930.00 |
|
||||||
|
| 19 | KDV Казахстан(яшкино) | | 1619745.40 | 1619745.40 | 0.00 |
|
||||||
|
| 20 | КИНДЕР Прима | | 1593057.00 | 1593057.00 | 0.00 |
|
||||||
|
|
@ -84,6 +84,34 @@ Part 1 (инвентаризация) и Part 3 (орг) — выполнены.
|
||||||
дельта — это основной объём и многочасовой прогон → отдельная(ые) сессия(и) продолжения.
|
дельта — это основной объём и многочасовой прогон → отдельная(ые) сессия(и) продолжения.
|
||||||
Условие DONE (перенос + сверка 0 + дельта) НЕ достигнуто — работа продолжается.
|
Условие DONE (перенос + сверка 0 + дельта) НЕ достигнуто — работа продолжается.
|
||||||
|
|
||||||
|
## Исправления по ревью Mac-Claude (09.10)
|
||||||
|
1. **Штрихкод больше НЕ уникален, карточки НЕ сливаются** («минимум как МойСклад»). Снята UNIQUE с
|
||||||
|
`(OrganizationId,Code)` product_barcodes (Phase44); импорт не сливает/не пропускает карточки с
|
||||||
|
дублем ШК (MergeByBarcode=false, dupeInInput не пропускает, артикул-дубль дизамбигуируется
|
||||||
|
суффиксом msId). Перенос вернул **49 ранее слитых карточек** (каталог 30993 = МойСклад). Дубли
|
||||||
|
ШК видны в «Проверке данных» → dup-barcode (чек уже есть). На кассе/в приёмке при скане
|
||||||
|
неоднозначного ШК фронт должен показывать выбор товара — серверные данные (несколько товаров с
|
||||||
|
одним ШК) и справочник dup-barcode для этого готовы. **Остатки пересчитаны**: см. раздел сверки —
|
||||||
|
`align-stock` выравнивает к снимку `report/stock/all` (движения `Initial` «МС-выравнивание») →
|
||||||
|
расхождений 0 кроме живой дельты.
|
||||||
|
2. **Долги — на уровне КОНТРАГЕНТА** (SupplierDebts переписан): Σприёмок − Σвозвратов − Σисходящих
|
||||||
|
(PaymentOut/CashOut по CounterpartyId) + Σвходящих (PaymentIn/CashIn) + корректировки. Топ-20 →
|
||||||
|
`docs/migration-debts-top20.md` (владелец сверяет вручную). **Находка:** все 171 paymentout (164 млн)
|
||||||
|
в МойСкладе имеют контрагентом САМУ ОРГ (не поставщиков), наличные ордера — инкассация/смены
|
||||||
|
(агент «Admin»); т.е. оплаты поставщикам в этом аккаунте НЕ разнесены по контрагентам → долг =
|
||||||
|
Σприёмок − Σвозвратов = **137 159 739 ₸**. `report/counterparty` — 403, в `entity/counterparty`
|
||||||
|
поля баланса нет → авто-сверка невозможна; расхождение закрывается стартовой корректировкой.
|
||||||
|
3. **Балансы счетов — «плуг»** OpeningBalance = баланс МС (report/money/byaccount) − Σ перенесённых
|
||||||
|
проводок. **Что НЕ перенесено движениями и почему:** розничная выручка (нал/карта) и движения
|
||||||
|
кассовых смен МойСклада НЕ материализованы у нас как проводки по счёту (чеки перенесены как
|
||||||
|
RetailSale, но не как внесение в кассу смены — модель смен у нас иная). Поэтому эти суммы учтены
|
||||||
|
в НАЧАЛЬНОМ ОСТАТКЕ счёта (плуг), а не как отдельные движения; текущий баланс = МойСклад точно.
|
||||||
|
В UI счёта (Деньги → Счета) показывается «Начальный остаток при переносе из МойСклад на 2026-10-09».
|
||||||
|
4. **Дельта — непрерывно**: systemd-таймер `food-market-migration-delta.timer` каждые 10 мин
|
||||||
|
(на dev-vm), лог `~/.fm-watchdog/migration-delta.log`, состояние `migration-delta-state.json`.
|
||||||
|
Последний прогон подтянул 23 документа (1 приёмка + 22 чека) — догнал октябрьское отставание.
|
||||||
|
Отставание ≤ 10 мин (интервал таймера).
|
||||||
|
|
||||||
## Сверка на 09.10 (после полного прогона + деплоя)
|
## Сверка на 09.10 (после полного прогона + деплоя)
|
||||||
- **Документы:** приёмки 7131=7131 ✓, возвраты поставщику 550=550 ✓, оприходования 72=72 ✓,
|
- **Документы:** приёмки 7131=7131 ✓, возвраты поставщику 550=550 ✓, оприходования 72=72 ✓,
|
||||||
списания 3068=3068 ✓, розничные возвраты 438=438 ✓, розничные продажи ≈ (Δ −1..−2 — живой
|
списания 3068=3068 ✓, розничные возвраты 438=438 ✓, розничные продажи ≈ (Δ −1..−2 — живой
|
||||||
|
|
|
||||||
|
|
@ -120,11 +120,18 @@ export function MoneyAccountsPage() {
|
||||||
empty="Счетов пока нет. Добавьте кассу магазина и, если нужно, банковские счета."
|
empty="Счетов пока нет. Добавьте кассу магазина и, если нужно, банковские счета."
|
||||||
columns={[
|
columns={[
|
||||||
{ header: 'Название', cell: (r) => (
|
{ header: 'Название', cell: (r) => (
|
||||||
|
<span className="flex flex-col">
|
||||||
<span className="flex items-center gap-1.5">
|
<span className="flex items-center gap-1.5">
|
||||||
{r.name}
|
{r.name}
|
||||||
{r.isDefault && <Star className="w-3.5 h-3.5 text-amber-500" aria-label="По умолчанию" />}
|
{r.isDefault && <Star className="w-3.5 h-3.5 text-amber-500" aria-label="По умолчанию" />}
|
||||||
{!r.isActive && <Archive className="w-3.5 h-3.5 text-slate-400" aria-label="Архив" />}
|
{!r.isActive && <Archive className="w-3.5 h-3.5 text-slate-400" aria-label="Архив" />}
|
||||||
</span>
|
</span>
|
||||||
|
{r.name.includes('из МойСклад') && (
|
||||||
|
<span className="text-xs text-slate-400">
|
||||||
|
Начальный остаток при переносе из МойСклад на {r.openingDate?.slice(0, 10)}: {fmt(r.openingBalance ?? 0)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
)},
|
)},
|
||||||
{ header: 'Тип', width: '150px', cell: (r) => ACCOUNT_KIND_LABEL[r.kind] ?? r.kind },
|
{ header: 'Тип', width: '150px', cell: (r) => ACCOUNT_KIND_LABEL[r.kind] ?? r.kind },
|
||||||
{ header: 'Банк / магазин', cell: (r) => r.bankName ?? r.storeName ?? '—' },
|
{ header: 'Банк / магазин', cell: (r) => r.bankName ?? r.storeName ?? '—' },
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue