16 сентября 2014

Проверка и исправление INVENTSUM в Axapta 2009 (международная версия без пакетов обновлений). V. 2

Данная информация представлена исключительно в ознакомительных целях.

Действия, описанные в этом посте, нельзя выполнять в производственном окружении.

Статья относится к международной версии 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

2 комментария:

  1. Это ни в коем случае нельзя использовать на рабочей базе, INVENTSUM может разнести в мелкие дребезги. ;) Вы об ACID слышали когда-нибудь? ;)

    ОтветитьУдалить
    Ответы
    1. Уважаемый Anonymous!
      Я не стану вступать в дискуссию с анонимусами.
      Я отвечу Вам персонально, если Вы укажете своё имя.

      Вопрос, поднятый Вами, считаю важным. Я отражу ответ на него в теле поста в течение пары дней

      Удалить