Данная информация представлена исключительно в ознакомительных целях.
Действия, описанные в этом посте, нельзя выполнять в производственном окружении.
Статья относится к международной версии Microsoft Axapta 2009 5.0.593.0, без российской локализации.
В Аксапте уже существует метод InventSumRecalcItem. Данная статья является не заменой, а дополнением к этому методу.
Причина создания этой статьи в том, что проблемы, связанные с корректностью данных склада встречаются не редко и исправление таких ошибок даётся нелегко. В статье описываются действия по исправлению одной из возможных причин.
Наличие ошибок в данных (битых данных, или ненужных данных), может приводить к трудноуловимым ошибкам в функционировании и может оказывать негативное влияние на надёжность системы. Искать и исправлять такие ошибки — нужно. По моему личному мнению, это лучше делать превентивно.
INVENTSUM — первая таблица, которую стоит проверить. Строки с некорректными количествами будут приводить к ошибкам в отчётах, т.к. многие отчёты для расчета количеств «на дату» берут последние количества из INVENTSUM и отнимают проводки до указанной даты.
Моя методика основывается на аксиоме, что информация в INVENTSUM полностью зависит от складских проводок и ни от чего больше.
Т.е. мы можем взять складские проводки, пересчитать их, получить в памяти копию верной рассчитанной INVENTSUM. После этого сравним её с физической таблицей и внесём необходимые правки в физическую таблицу — добавим нужные строки, поправим количества и стоимости, ненужные строки удалим.
Я так и сделал. Вот скрипт Это версия 8.
В скрипте есть одно ограничение:
Для существующих строк не проверяются и не изменяются поля LastUpdDateExpected и LastUpdDatePhysical. Для созданных в ходе проверки строк в них проставляется текущая дата.
Реализовать проверку этих полей, в принципе, возможно, но такой расчёт будет относительно сложным (в противовес простой функции sum(), которая применена для расчёта количеств). Я могу сделать это по запросу. Для этого пишите по почте.
Проверка и исправление выполняются в 2 фазы:
1. Пересчёт полей, которые зависят от INVENTTRANS. Это: POSTEDQTY, RECEIVED, REGISTERED, ARRIVED, ORDERED, QUOTATIONRECEIPT, DEDUCTED, PICKED, RESERVPHYSICAL, RESERVORDERED, ONORDER, QUOTATIONISSUE, POSTEDVALUE, PHYSICALVALUE
2. Пересчёт полей, которые зависят от полей первой группы, это: AVAILORDERED, AVAILPHYSICAL, PHYSICALINVENT, CLOSEDQTY, CLOSED
Исправления выполняется оператором MERGE. Этот оператор хорош тем, что в одной команде можно сделать и INSERT и UPDATE и DELETE — синхронизировать физическую таблицу INVENTSUM с рассчитанной в памяти таблицей INVENTSUM одной командой.
Оператор содержит фразу OUTPUT, которая даёт подробный лог того, что было сделано.
Перед тем как применять изменения (COMMIT) на тестовой базе, надо просмотреть и проанализировать лог. И применять изменения есть смысл лишь в том случае, если вы согласны с каждой строкой лога. Не бывает таких скриптов, чтобы год хранить в БД ошибки, потом запустить скрипт, и база стала конфеткой.
Все операторы надо выполнять в режиме NO AUTOCOMMIT. Так есть возможность получить лог для анализа, и сказать серверу ROLLBACK — т.е. получить лог оператора НЕ применяя изменения оператора — откатив транзакцию.
Оператор первой фазы большой, но большая часть его относится к форматированию лога.
Если кто-то решить применить мой метод у себя — я очень рекомендую разобраться с тем, как работают операторы.
А именно, в первой фазе в представление T1 собираются рассчитанные значения полей первой группы. Но эти значения для каждой строки INVENTSUM пока расположены «в столбик», а не в строку.
Представление T2 производит транспонирование «столбец в строку».
Представление T3 удаляет строки, относящиеся к услугам и добавляет поле NEW_RECID, которое нам понадобится, если дальше оператору MERGE придётся добавлять строки в INVENTSUM. Алгоритм расчёта RecID такой: определяется минимальный RECID, который существует в таблице INVENTSUM, и для добавляемых строк он отматывается вниз. Аксапта добавляет «вверх», а мы будем «вниз», поэтому мы никогда не пересечёмся.
Дальше идёт тело оператора MERGE. Вначале указываются две таблицы — в качестве целевой использовать физическую таблицу INVENTSUM, в качестве исходной — полученное нами ранее представление T3 (представление T3 по сути представляет собой полностью посчитанную «в уме» INVENTSUM, основываясь только на складских проводках).
Напомню, что первичным ключом в INVENTSUM являются поля DATAAREAID, ITEMID, INVENTDIMID. По этим полям две таблицы и соединяются.
Потом идёт указание о том, как поступать, если строки, совпадающие по ключу:
А) найдены, и значения полей первой группы в чём-то не совпадают. Тогда — обновить в целевой таблице.
Б) есть строка в физической таблице, для которой нет пары в рассчитанной таблице. Удалить.
В) есть строка в рассчитанной таблице, для которой нет пары в физической таблице. Добавить.
А после фразы OUTPUT идёт форматирование вывода лога
Оператор второй фазы похож на первый, за исключением того, что там уже нет команд вставки новых строк и удаления ненужных — это всё было сделано на первой фазе, осталось только проверить поля, которые зависят от полей первой фазы, а не от INVENTTRANS.
В оба лога слева выводятся три ключевых поля.
Справа в логах идут поля INVENTSUM. Поля идут парами, сначала прежнее значение, потом новое.
Неизменённые значения не выводятся. Благодаря это в логе видно, какие именно поля пересчитали операторы.
Это была теория, а теперь практика.
Я тестировал на демобазе от Аксапты 2009.
Перед запуском я удалил одну строку из INVENTSUM, и в одной изменил количество.
В результате запуска удалённая строка восстанавливается, изменённая — исправляется.
И удаляется — 121 строка. Это оправданно, потому что такой комбинации DATAAREAID + ITEMID + INVENTDIMID в проводках действительно нет.
Во второй фазе обновляется 1 строка. Это та строка, которую я добавил на первой фазе. При добавлении поля второй группы были пустыми, и сейчас мы их пересчитали.
Если у кого-то возникнет реальная необходимость поправить такие ошибки в производственном окружении — обращайтесь ко мне по почте.
Что касается комментария Anonymous’а, то он наверно имел ввиду не ACID (концепцию), а уровни изоляции транзакций (Transaction Isolation Level), это варианты реализации ACID'а.
Это верное замечание. Но мне неизвестно, использует ли Axapta dirty reads, да и обсуждение TIL выходит за рамки данной статьи, поэтому я решил поступить по-простому — запускайте на тестовой и в однопользовательском режиме (чтобы пользователи в Управлении запасами не ютились).
Благодарности за комментарии пользователям Logger, raz и Anonymous