Долг было непонятно как записать, и не зря. Оплата была просто денежным
полем с полной суммой: долг получался, если догадаться стереть число
и вписать ноль. Дальше — хуже. Подсказка при этом продолжала уверять, что
оплачено полностью, а любая правка строк подставляла полную сумму обратно
и молча стирала выставленный долг.
Теперь выбор явный: заплатил полностью / взял в долг целиком / заплатил
часть. Пересчёт работает только в первом режиме. Поле суммы осталось
живым — вписанное руками число само зажигает подходящий переключатель.
Долг без имени записать нельзя: на экране долгов такая запись попадает
в кучу «без контрагента», и с кого спрашивать — уже не узнать. В быстром
вводе это предупреждение, а не запрет: внося историю, можно и правда не
помнить, кто это был.
На экране долгов человека можно выбрать целиком и рассчитаться сразу за
всё: деньги приходят одной суммой, а гасятся долги по очереди, со старых.
Цены фасовок переехали в «Цены и история». Они меняются одним решением
поставщика вместе с ценой товара, а история была только у товара —
у коробки цена уезжала молча. Заодно закрыт второй вход: в карточке
товара цены фасовок теперь только показываются, правится там состав.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Коробка печенья из 20 штук обходится дешевле, чем 20 штук поодиночке —
ради этого её и берут. Своей была только цена продажи, а себестоимость
выводилась умножением поштучной цены на размер фасовки, то есть опт
считался по цене розницы. В каждой закупке сумму приходилось править
руками.
Теперь у фасовки обе цены свои и обе за упаковку целиком. Ноль означает
«своей цены нет, считай от базовой» — прежнее поведение, поэтому цифры
в уже заведённых базах не поехали.
Карточка товара расшифровывает результат построчно: «коробка = 20 шт ·
закупка 300,00 ₽ (15,00 ₽ за шт) · продажа 500,00 ₽ (25,00 ₽ за шт)».
Цена вводится за упаковку, а думает человек о ней поштучно, и без
пересчёта на виду ошибку в размер фасовки замечаешь уже в закупке.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Надо было отдать 5 500, взяли 5 000, полтысячи оставили. Долг закрыт,
но денег никто не отдавал.
У расчёта с пекарней появился вид: деньги или прощённый остаток. Свалить
их в одну кучу нельзя — тогда «Отдано пекарне» в статистике показывало бы
суммы, которых не платил. Поэтому «Отдано» — только живые деньги,
«Прощено» — отдельная колонка везде: в закупках, в сводке, в статистике
по периодам и по времени.
В прибыль прощённое идёт целиком: эти деньги предназначались пекарне,
а остались у тебя. «Осталось собрать» на ту же сумму уменьшается —
собирать под прощённый остаток уже не надо. Простить больше долга нельзя:
лишнее не засчитывается и, в отличие от переплаты деньгами, никуда
не переливается.
В диалоге платежа галочка «Остаток простили — закрыть партию»: вводишь
сколько отдал, остаток уходит отдельной записью, партия закрывается сама,
потому что её долг становится нулём.
Миграция схемы 3→4 помечает всё записанное раньше как живые деньги.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Деньги сверх стоимости товара. Хранятся на продаже отдельным полем, а не
внутри платежей: иначе чаевые раздували бы «оплачено», и продажа выглядела
бы закрытой, когда за булки ещё должны.
Ввёл оплату больше суммы — булка 70, дали 100 — разница уходит в чаевые
сама. Разбор делается по окончании ввода, а не на каждом нажатии, иначе
поле дёргалось бы посреди набора. То же при приёме оплаты по долгу:
заплатили больше, чем оставалось, — излишек становится чаевыми, а не
теряется, как было раньше.
В расчётах чаевые идут в покрытие партии (это живые деньги, ими так же
рассчитываются с пекарней) и целиком добавляются в прибыль, но не входят
в выручку и не создают долга. Продажа, списанная с нескольких партий,
делит чаевые между ними пропорционально выручке.
По съеденному и подаренному чаевых не бывает — поле отключается.
Миграция схемы 2→3 проставляет ноль: у кого чаевых нет, тот появления
этой фичи не заметит.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Три правки по замечаниям.
1. База и код разъехались по разным репозиториям. Автокоммит и раньше
трогал только vault.fmdb, но лежал он в той же ветке, что и исходники,
поэтому пуш тащил всю историю программы. Теперь data/ — самостоятельный
клон food-records со своим .git, а исходники его игнорируют целиком.
При первом запуске приложение встаёт на уже существующую историю
сервера, а не заводит параллельную.
2. Фасовки товара. Пачка печенья 10 шт за 200 ₽ и та же печенька поштучно
за 30 ₽ — один товар с двумя фасовками. Остатки, себестоимость и FIFO
считаются в базовых единицах, поэтому поштучные продажи вычитаются из
купленных пачек. Размер фасовки хранится в документе слепком.
Миграция схемы 1→2 не меняет поведение уже заведённых данных.
3. Быстрый ввод продаж за период: выбор диапазона дат, строка таблицы —
отдельная продажа, ввод с клавиатуры, запись всех разом. Незнакомое имя
заводится как контрагент, повтор периода подсвечивается.
Тесты больше не имеют настроенного remote, чтобы не ходить в сеть.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Десктопное приложение на PySide6. Вся база — один JSON-документ,
зашифрованный AES-256-GCM под паролем (ключ через scrypt), лежит
в data/vault.fmdb и раз в час уезжает в этот репозиторий.
Основное:
- партии с дедлайном возврата себестоимости пекарне, FIFO-разнос продаж
по партиям и прогресс покрытия к сроку;
- типы выбытия: розница, другу по себестоимости, съел сам, подарок,
списание — съеденное вычитается из прибыли, за него платить всё равно;
- долги контрагентов с частичными оплатами;
- номенклатура с историей изменения цен;
- журнал изменений внутри базы: git хранит непрозрачные снимки,
поэтому настоящая история ведётся здесь.
Синхронизация коммитит только путь базы и схлопывает часовые пуши
в один коммит на день через amend + force-with-lease.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>