Как правильно организовать хранение наличия и истории приходов/расходов в интернет магазине на php + mysql?
В БД есть таблицы: приходы, расходы, актуальное наличие, логи наличия ежеквартально (чтобы быстрее строить отчеты по операциям, которые включают "было" и "стало").
При сохранении операций все понятно, я просто прохожу построчно массив с моделями в операции и добавляю/вычитаю количество в операции к/из количества в логах и наличии, создаю записи в таблице операций.
А при обновлении операции, например, "приход", я должен сделать обновление актуального наличия и всех логов приходов, следующих за датой данного прихода.
Вопрос в том, как правильнее делать обновление логов наличия. Делать промежуточный массив с разницей добавляемого количества и того, которое уже сохранено (делая построчный обход массива моделей в операции и проверяя на каждой итерации, есть ли такая строка в таблице приходов, я ведь обновляю операцию)? Есть ли более оптимальный способ?
Корректно ли делать обход построчно (может быть, например, 100 позиций в операции)
Если я правильно понял ваше описание - поле актуальное наличие противоречит 3 нормальной форме, из за этого возникает вопрос как его контролировать в денормализованной структуре. Так?
sangan, класс! Мне тоже кажется что я дал хорошее объяснение вопросу, точнее даже "попал своим грязным пальцем прям в больное место", но без элементарных знаний архитектуры приложений и правил проектирования бд вы будете всегда писать каку. Советую все же прочитать про нормальные формы.
ThunderCat, когда я обновляю, например, приход, мне нужно вычислить для каждой позиции на сколько я изменил количество и обновить соответствующие позиции в истории наличия и актуальном наличии. Корректно ли для каждой позиции из массива делать запрос и формировать новый массив уже не с количеством пришедших единиц, а с количеством, на которое нужно изменить таблицы истории наличия и актуального наличия исходя из реального количества пришедших единиц и тем, что по ошибке уже введено в таблицу операций?
Я не представляю, как без хранения истории наличия высчитывать "было" и "стало", не обходя все записи таблицы операций с запуска проекта.
ThunderCat, для того, чтобы каждый раз не высчитывать количество из миллионов полей, а иметь оперативный доступ к нему. Или это не нужно? Тогда не нужно, тем более, и хранение истории наличия.
Евгений Ромашкан, Например, нашли на складе неучтенный товар. Или в уходе - позвонили и сказали, что не дошло, при проверке оказалось, что вещь на складе. Ну, например, сегодня я сохранял операцию и нужно ее изменить - это ок. Вчера - тоже вроде может такое быть. Почему тогда не сделать, чтобы все операции можно было редактировать?
Евгений Ромашкан, Допустим. Ну не логично делать уход, если случайно в приходе поставил на одну единицу больше. Я просто думаю, что есть какой-то адекватный способ сделать все-таки возможность редактирования операций.
Наверное, нужно при сохранении операции проверить, есть ли такая позиция в операциях, отминусовать количество, добавленное в старой операции из наличия и удалить старую операцию, после чего сохранить новую с добавлением нового количества?
sangan, Не, удаление тоже меняет состояние )
Я к тому что если сохранённые операции прихода/расхода не изменять, а просто создавать корректирующие записи, результаты подсчёта итогового числа можно сохранять периодически или при каждом расчёте, и получение итогового числа каждый раз не будет занимать много времени т.к. будет сводиться к получению последнего сохранённого состояния и применения к нему новых операций в хронологическом порядке если такие имеются.
А записи в логе менять в принципе не придётся.
upd: Перечитал вопрос, вообще можно и не менять логику получения итогового состояния, вопреки советам комментатора выше, неизменяемость записей уже сводит проблемы с каскадными изменениями на нет
sangan, Просто немного смущает ситуация на самом деле, если товар затерялся на складе а спустя неделю нашёлся, зачем обновлять логи наличия?
По сути, получается что с точки зрения покупателя и с точки зрения программы, купить его было невозможно, и он стал доступен лишь сейчас
Евгений Ромашкан, я собирался изменять только логи, следующие за изменяемой операцией. Например, меняю вчерашнюю операцию, а лог сохранился сегодня в 0:00 и его нужно поменять. А если я меняю один лог, то ничего не стоит сделать так, чтобы можно было поменять все следующие логи, даже если операцию совершили год назад. Иначе непонятно, какой срок давать на редактирование операции и зачем создавать такое ограничение.
Все приходы, расходы, продажи и тп можно хранить в одной таблице. Пишите туда, например, product_id, статус, например, status = 1, это приход, 2 - расход и тп.
Поле с количеством пусть может принимать отрицательные значения.
Итого получается, пришёл товар:
product_id = 1, count = 10, status = 1
Продаю 2 шт:
product_id = 1, count = -2, status = 2
Хочу узнать наличие:
SELECT SUM(count) FROM table WHERE product_id = 1
Все примерно так и есть. Проблема возникает в момент, когда операция уже сохранена, например: product_id = 1, count = 10, status = 1, а я её хочу обновить и отправить в таблицу: product_id = 1, count = 12, status = 1.
Для этого, как я понимаю, мне нужно определить разницу между count=10 (в БД) и count_new=12 (в массиве в скрипте). В таблице операций я просто обновляю count, но в таблице истории наличия и актуального наличия я должен добавить разницу count, которое было добавлено ранее, при сохранении операции (взять можно из таблицы операций по id текущей операции) и cunt, которое я добавляю в текущей операции (обновляю операцию).
sangan, никакой проблемы нет, нужно просто создать новую запись
product_id = 1, count = 2, status = 1, к уже имеющейся.
а не обновлять старую. Подумайте, для чего используется SUM(count)?