<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.technet.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru"><title type="html">Investigating Dynamics AX</title><subtitle type="html" /><id>http://blogs.technet.com/denisfed/atom.xml</id><link rel="alternate" type="text/html" href="http://blogs.technet.com/denisfed/default.aspx" /><link rel="self" type="application/atom+xml" href="http://blogs.technet.com/denisfed/atom.xml" /><generator uri="http://communityserver.org" version="2.1.61025.2">Community Server</generator><updated>2007-03-23T12:51:00Z</updated><entry><title>Обновление статьи о закрытии склада.</title><link rel="alternate" type="text/html" href="http://blogs.technet.com/denisfed/archive/2009/05/07/3236804.aspx" /><id>http://blogs.technet.com/denisfed/archive/2009/05/07/3236804.aspx</id><published>2009-05-07T14:55:00Z</published><updated>2009-05-07T14:55:00Z</updated><content type="html">Выложил обновленную версию &lt;A title="Себестоимость и закрытие склада" href="http://blogs.technet.com/denisfed/pages/3236801.aspx" mce_href="http://blogs.technet.com/denisfed/pages/3236801.aspx"&gt;статьи&lt;/A&gt; о принципах работы с себестоимостью в Dynamics AX. Обновление сделано с учетом новых возможностей Dynamics AX 2009.&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=3236804" width="1" height="1"&gt;</content><author><name>denisfed</name><uri>http://blogs.technet.com/members/denisfed.aspx</uri></author></entry><entry><title>Пример создания нового складского документа</title><link rel="alternate" type="text/html" href="http://blogs.technet.com/denisfed/archive/2007/10/29/2281265.aspx" /><id>http://blogs.technet.com/denisfed/archive/2007/10/29/2281265.aspx</id><published>2007-10-29T17:23:00Z</published><updated>2007-10-29T17:23:00Z</updated><content type="html">&lt;P&gt;Выложил &lt;A class="" href="http://www.ms-dynamics.ru/blog/2007/10/26/primer-sozdaniya-novogo-skladskogo-dokumenta" mce_href="http://www.ms-dynamics.ru/blog/2007/10/26/primer-sozdaniya-novogo-skladskogo-dokumenta"&gt;статью&lt;/A&gt; c примером создания нового складского документа в DAX. В статье рассматривается&amp;nbsp;пример с созданием объекта в DAX объекта "клипборд резервов". Предполагается что во всех обычных складских документах появляется две новых операции - "Снять резервы в клипборд" и "Резервировать из клипборда". Приведен пример реализации данного объекта с поддержкой интеграции с модулем логистики - системой складских проводок и складских остатков.&lt;/P&gt;
&lt;P&gt;Кроме того, в конце статьи приведен пример полностью программного (без использования журналов или других складских документов) создания приходов, списаний и переносов номенклатуры в DAX.&lt;/P&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=2281265" width="1" height="1"&gt;</content><author><name>denisfed</name><uri>http://blogs.technet.com/members/denisfed.aspx</uri></author><category term="Логистика" scheme="http://blogs.technet.com/denisfed/archive/tags/_1B043E04330438044104420438043A043004_/default.aspx" /><category term="Dynamics AX" scheme="http://blogs.technet.com/denisfed/archive/tags/Dynamics+AX/default.aspx" /></entry><entry><title>Об архитектуре разноски в ГК и корреспонденции счетов</title><link rel="alternate" type="text/html" href="http://blogs.technet.com/denisfed/archive/2007/09/20/1999716.aspx" /><id>http://blogs.technet.com/denisfed/archive/2007/09/20/1999716.aspx</id><published>2007-09-20T09:35:00Z</published><updated>2007-09-20T09:35:00Z</updated><content type="html">Выложил статью "&lt;A class="" title="Ссылка на запись Немного об архитектуре разноски в ГК и проблеме корреспонденции счетов" href="http://www.ms-dynamics.ru/blog/2007/08/28/nemnogo-ob-arxitekture-raznoski-v-gk-i-probleme-korrespondencii-schetov/" rel=bookmark mce_href="http://www.ms-dynamics.ru/blog/2007/08/28/nemnogo-ob-arxitekture-raznoski-v-gk-i-probleme-korrespondencii-schetov/"&gt;Немного об архитектуре разноски в ГК и проблеме корреспонденции счетов&lt;/A&gt;". Хотя в статье довольно много информации об API работы с главной книгой, в первую очередь статья была написана, чтобы рассказать о том, откуда вообще выросла проблема реализации корреспонденции счетов при локализации западных ERP систем. Кроме того - рассматриваются некоторые общие подходы по интеграции модулей DAX с главной книгой.&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=1999716" width="1" height="1"&gt;</content><author><name>denisfed</name><uri>http://blogs.technet.com/members/denisfed.aspx</uri></author><category term="Dynamics AX" scheme="http://blogs.technet.com/denisfed/archive/tags/Dynamics+AX/default.aspx" /><category term="Главная книга" scheme="http://blogs.technet.com/denisfed/archive/tags/_13043B04300432043D0430044F04_+_3A043D04380433043004_/default.aspx" /></entry><entry><title>Dynamics AX 4 и IMTS</title><link rel="alternate" type="text/html" href="http://blogs.technet.com/denisfed/archive/2007/06/08/dynamics-ax-4-imts.aspx" /><id>http://blogs.technet.com/denisfed/archive/2007/06/08/dynamics-ax-4-imts.aspx</id><published>2007-06-08T11:22:00Z</published><updated>2007-06-08T11:22:00Z</updated><content type="html">Выложил статью &lt;A class="" title="Dynamics AX 4 и IMTS" href="http://www.ms-dynamics.ru/blog/2007/06/07/dynamics-ax-4-i-imts/" mce_href="http://www.ms-dynamics.ru/blog/2007/06/07/dynamics-ax-4-i-imts/"&gt;Dynamics AX 4 и IMTS&lt;/A&gt;&amp;nbsp;посвященную проблеме блокировок в логистическом модуле Dynamics AX.&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=1181368" width="1" height="1"&gt;</content><author><name>denisfed</name><uri>http://blogs.technet.com/members/denisfed.aspx</uri></author><category term="Логистика" scheme="http://blogs.technet.com/denisfed/archive/tags/_1B043E04330438044104420438043A043004_/default.aspx" /><category term="Dynamics AX" scheme="http://blogs.technet.com/denisfed/archive/tags/Dynamics+AX/default.aspx" /></entry><entry><title>Новые поля в складских проводках</title><link rel="alternate" type="text/html" href="http://blogs.technet.com/denisfed/archive/2007/05/23/1029577.aspx" /><id>http://blogs.technet.com/denisfed/archive/2007/05/23/1029577.aspx</id><published>2007-05-23T16:57:00Z</published><updated>2007-05-23T16:57:00Z</updated><content type="html">&lt;H1&gt;&lt;/H1&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;Общие вопросы&lt;/H1&gt;
&lt;P&gt;При внедрении DAX часто возникает примерно следующая задача: Клиент говорит что-нибудь типа "Мне нужно добавить в заказы (складские журналы, закупки, производственные заказы и т.п.) новое поле - направление продаж (код продавца, номер&amp;nbsp;автомобиля для отгрузки, идентификатор кредитной линии клиента и тп). Кроме того - мне нужно уметь строить отчеты (обычные или OLAP) по складским списаниям (приходам) в разрезе этого нового поля". 
&lt;P&gt;Первое что приходит в голову - это просто добавить новое поле в строки заказов и потом переделать некоторые складские отчеты таким образом, чтобы они строились по соединению (join) таблицы складских проводок с исходным документом. Проблема в том, что в реальности постоянно возникают ситуации, при которых&amp;nbsp;клиент, задним числом вспоминает что неплохо бы это поле добавить не только в заказы (например), но и в складские журналы списания или переноса. В этой ситуации внедренцу приходится либо плодить кучу отчетов - по одному для каждого вида складских документов, либо строить какой-то хитромудрый отчет, который собирает данные из множества таблиц. Очевидно, что оба подхода имеют свои минусы и почти не имеют плюсов. 
&lt;P&gt;Второй, более продвинутый вариант - это добавление нового поля либо в таблицу складских проводок (inventTrans) либо в таблицу складской аналитики (inventDim). Надо понимать, что с точки зрения нагрузки на систему, вариант добавления в таблицу inventDim новых полей значительно более затратный. Это связано с тем, что с ростом&amp;nbsp;числа&amp;nbsp;записей в таблице&amp;nbsp;inventDim, растет и таблица inventSum (запасы в наличии). Поскольку&amp;nbsp;модуль логистики&amp;nbsp;ПОСТОЯННО использует таблицу inventSum для получения текущего складского остатка, критически важно для производительности, чтобы эта таблица не разросталась. Поэтому, добавлять новые поля в складскую аналитику имеет смысл только при выполнении следующих условий: 
&lt;P&gt;1. Имеет смысл сальдирование по этой аналитике. Грубо говоря - количественный или денежный остаток&amp;nbsp;в разрезе этой&amp;nbsp;аналитики имеет экономический смысл. 
&lt;P&gt;2. Предполагается, что система должна проверять неотрицательность остатка в разрезе этой складской аналитики. 
&lt;P&gt;Поэтому - реально добавлять новые поля в складскую аналитику приходится достаточно нечасто. Например - ни код продавца, ни номер автомобиля явно не проходят по обоим условиям. Мне приходилось добавлять, например, складскую аналитику "Материально ответственное лицо" или "Вид продукции" (своя, комисионная, давальческая) и некоторые другие. Причем добавлять ее приходилось в первую очередь даже не для отчетности, а для контроля - чтобы нечаянно не списать с аналитики "МОЛ" или "Вид продукции" больше номенклатуры, чем на нее изначально было оприходовано. 
&lt;P&gt;Для всех остальных случаев - правильнее добавлять новое поле в inventTrans. Причем я для себя выработал следующий приблизительный критерий, позволяющий принимать решение - добавлять новое поле в inventTrans или попытаться обойтись хитрым запросом (с джойном inventTrans и исходного документа): Добавлять новое поле в inventTrans следует если выполняется одно из следующих условий: 
&lt;P&gt;1. Новый аттрибут есть более чем в одном типе складского документа 
&lt;P&gt;2. Новый аттрибут будет заполняться для более чем 25% складских проводок данного вида (то есть - либо приходов, либо расходов) 
&lt;P&gt;3. Новый аттрибут будет использоваться для вычисления дополнительных количеств в таблице остатков в наличии (Об этом подходе я напишу в другой раз. Основная идея состоит в том, чтобы в остатках в наличии иметь не только поле, допустим, "Зарезервировано", но&amp;nbsp;еще и&amp;nbsp;дополнительное поле "Зарезервировано в журналах перемещения".) 
&lt;P&gt;Наивный подход к реализации заполнения нового поля в складских проводках состоит в том, чтобы переопределить методы insert()&amp;nbsp;или update() таблиц inventTrans и, допустим, SalesLine таким образом, чтобы при обеспечить синхронизацию этого нового поля между двумя таблицами. Надо сказать, что во первых этот метод приводит к серьезному возрастанию нагрузки не систему во время обновления, во вторых - очень сильно не вяжется с идеологией логистического модуля DAX. 
&lt;P&gt;Цель данной заметки состоит как раз в том, чтобы дать приблизительное описание той инфраструктуры которая обеспечивает интерфейс между исходными логистическими документами (заказами, закупками, складскими журналами, производственными заказами и т.п.) и стандартными механизмами логистических операций DAX, а затем дать простой пример того как можно обеспечить копирование аттрибутов из исходных документов в складские проводки. 
&lt;H1&gt;Немного о программной инфраструктуре логистики&lt;/H1&gt;
&lt;P&gt;На мой взгляд - инфраструктура логистического модуля, это очень наглядный пример мощи объектно ориентированного подхода. При проектировании классов этого модуля разработчиками было принято очень простое решение: 
&lt;P&gt;1. Классы отвечающие за выполнение типовых логистических операций - резервирования, комплектации, регистрации, физической и финансовой разноски ничего не знают о том, на основании какого исходного документа выполняются эти операции. 
&lt;P&gt;2. Вся логика, связанная со специфическими операциями по конкретному складскому документу инкапуслирована в иерархию классов (inventMov_*).&amp;nbsp; При этом каждому виду складского документа соответствует ОДИН конкретный класс в этой иерархии. 
&lt;P&gt;3. При выполнении логистических операций классы InventUpd* либо запрашивают у классов InventMov* нужную им информацию (например код номенклатуры или заказанную дату), либо вызывают методы классов inventMov, чтобы те выполнили некторые операции, специфичные для данного складского документа. 
&lt;P&gt;Рассмотрим несколько конкретных примеров: 
&lt;P&gt;В иерархии классов inventMovement&amp;nbsp;имеется метод mustBeAutoReserved. Этот метод вызывается классов inventUpd_expected, отвечающим за создание и обновление складских проводок в статусе "Заказано"/"В заказе" для того чтобы определить - не следует ли автоматически резервировать данную проводку списания. В классе inventMovement этот метод возвращает значение false. В классе inventMov_sales (отвечающим за модуль заказов) - возвращает значение в зависимости от режима авторезервирования в шапке заказа, а в классе InventMov_QuarantineOrder (отвечающем за карантинный заказ) этот метод всегда возвращает значение true, чтобы по карантинному заказу у нас товар автоматически резервировался на карантинном складе. 
&lt;P&gt;Метод inventMovement.updateLedgerFinancial() используется для создания проводок в ГК по приходным операциям. В большинстве случаев, эта операция выполняется методом самого базового класса, который вытаскивает из дочернего класса (относящегося к данному виду приходного документа) данные о счете и коррсчете проводки (через методы accountBalanceSheet() и accountOperations()), финансовой аналитике (через метод Dimension()) и разноске в ГК (методы postingBalanceSheet() и postingOperations()). Для закупок, этот метод был переопределен в классе inventMov_purch(), поскольку по закупкам разноска по коррсчету делается совсем другим классом (vendVoucher), который также создает запись в проводках по поставщику (vendTrans). Поэтому - в методе inventMov_purch.updateLedgerFinancial() создется только вторая половина проводки - приход на инвентарный счет (10.x или 41.x). 
&lt;P&gt;Метод inventMov.addRemainFinancialUnit() обновляет недопоставленное количество в исходном складском документе. В базовом классе inventMovement этот метод определен так, чтобы он ничего не делал если для данного типа складского документа обновление недопоставленного количества не требуется и чтобы он выдавал сообщение об ошибке если таковое обновление требуется. В классах inventMov_purch,inventMov_sales, inventMov_prodLine этот метод переопределен таким образом, чтобы он обновлял соответствующие количества в строке закупки, заказа и производственной спецификации. 
&lt;P&gt;Ну и так далее... 
&lt;P&gt;При создании экземпляра класса inventMovement используется constructor controlled inheritance: Для создания экземпляра класса используется метод inventMovement::construct(common table). При этом, логика внутри метода contruct (точнее даже метода constructNoThrow, который вызывается из construct), на основании информации о типе таблицы со строкой исходного складского документа, создает нужный экземпляр конкретного наследника класса inventMovement. При этом, переданный экземпляр строки исходного складского документа храниться в переменной buffer, доступной из класса inventMovement и его наследников. Кроме того - существует еще один метод создания экземпляра класса inventMovement. В таблице inventTrans существует метод inventMovement, который находит нужную строку таблицы с исходным документом, а затем через inventMovement::construct() создает и возвращает соответствующий экземпляр объекта класса inventMovement. 
&lt;H1&gt;Конкретный пример.&lt;/H1&gt;
&lt;P&gt;Заказчик – крупная торговая организация. Им для работы требуется четко контролировать складские резервы в двух дополнительных разрезах: 
&lt;P&gt;1. Менеджер по продажам (сейл), к которому относится резерв 
&lt;P&gt;2. Срок жизни резерва. Резервы, которые кто-то создал и потом в течении N-дней не продал – должны автоматически удаляться системой. 
&lt;P&gt;Если транслировать эту задачу в более приземленные термины, то нужно: 
&lt;P&gt;1. Добавить в таблицу складских проводок (inventTrans) поле "Сейл" и копировать туда поле "Ответственный продавец" из шапки заказа (возможно – и из некого дополнительного поля, которое мы добавим в шапку складского журнала – для резервов по складским журналам). 
&lt;P&gt;2. Добавить в таблицу складских проводок поле "Дата автоматического снятия резерва". При резервировании – в это поле должна заносится текущая дата + 5 дней. Желательно сделать механизм расчета автоматической даты снятия расширяемым, поскольку велика вероятность того, что в дальнейшем метод расчета срока жизни резерва будет зависеть от типа исходного документа, номенклатуры, клиента под которого ставиться резерв и тп. 
&lt;P&gt;3. Разработать процедуру удаления просроченных резервов. Здесь я эту тему рассматривать не буду - оставлю для самостоятельного изучения :) 
&lt;P&gt;Для начала попытаемся решить задачу с ответственным продавцом. Для этого: 
&lt;P&gt;· В классе inventMovement создадим метод salesResponsible(), возвращающий значение типа emplId. В базовом классе этот метод будет возвращать пустую строку. 
&lt;P&gt;· В классе inventMov_sales (связанном со строкой заказа) переопределяем этот метод таким образом, чтобы он возвращал значение salesResponsible из шапки соответствующего заказа. 
&lt;P&gt;· Добавляем поле salesResponsible в таблицу inventTrans 
&lt;P&gt;· Изменяем метод inventMovement.initInventTransFromBuffer() таким образом, чтобы он инициализировал новое поле значением, полученным из метода inventMovement.salesResponsible(). 
&lt;P&gt;Первичное тестирование данная доработка пройдет. Если при создании заказа заполнить в шапке поле "Ответственный продавец", то при создании строк оно попадет в складские проводки. Но вот если попробовать изменить это поле у уже созданного заказа, то в складских проводках так и останется старое значение. Почему это происходит ? Давайте попробуем изменить в шапке заказа поле "Дата заказа" и протрассировать метод inventUpd_estimated.updateNow(), который где-то в своих недрах должен изменить значение поля dateExpected таблицы складских проводок. При трассировке довольно быстро натыкаешься на код метода updateFieldsChange(), который вызывает метод инициализации полей складской проводки (inventMovement.initInventTransFromBuffer()) в том случае, если метод inventMovement.mustUpdateInventTransFields() вернул true. Если заглянуть в этот метод, то можно обнаружить следующий код: 
&lt;P&gt;return (this.transDate() != _movement_orig.transDate() || 
&lt;P&gt;this.shippingDateRequested()!= _movement_orig.shippingDateRequested()|| 
&lt;P&gt;this.transSchedTime() != _movement_orig.transSchedTime() || 
&lt;P&gt;this.transItemBOMId() != _movement_orig.transItemBOMId() || 
&lt;P&gt;this.transItemRouteId() != _movement_orig.transItemRouteId() || 
&lt;P&gt;this.transIdReturn() != _movement_orig.transIdReturn() || 
&lt;P&gt;this.projCategoryId() != _movement_orig.projCategoryId() || 
&lt;P&gt;this.custVendAc() != _movement_orig.custVendAc() || 
&lt;P&gt;this.assetId() != _movement_orig.assetId() || 
&lt;P&gt;this.inventRefTransId() != _movement_orig.inventRefTransId()) || 
&lt;P&gt;this.probabilityId() != _movement_orig.probabilityId(). 
&lt;P&gt;Попросту говоря – система создает на основании старой (не измененной) копии строки исходного документа (доставаемой через buffer.Orig()) экземпляр класса InventMovement() и сравнивает значение некоторых методов, значения которых в дальнейшем попадают в складские проводки. Значит – для того чтобы добиться правильного поведения системы нам нужно: 
&lt;P&gt;1. Добавить в этот метод сравнение значений, возвращаемых методом salesResponsible() 
&lt;P&gt;2. Для того чтобы логика сравнения отработала нам придется добавить в СТРОКИ заказа копию поля salesResponsible. (Ведь метод пляшет от сравнения СТРОКИ ЗАКАЗА до и после обновления, а не от значения шапки заказа.). Нам придется переопределить метод обновления шапки заказа (salesTableType.update()) таким образом, чтобы при изменении ответственного продавца в шапке заказа, новое значение поля копировалось бы и в строки заказа. При этом – обновление строки заказа у нас будет вызывать обращение к inventUpd_estimated.updateNow(), порождая таким образом обновление информации и в складских проводках. 
&lt;P&gt;Теперь попробуем разобраться с датой автоматического снятия резерва. 
&lt;P&gt;· Для начала добавим в таблицу складских проводок новое поле dateExpired 
&lt;P&gt;· Поскольку хочется сделать механизм расчета даты автоматического снятия максимально гибким, создадим метод inventMovement.dateExpired(). Этот метод получает в качестве параметра дату создания резерва, а возвращает рассчитанную на ее основе дату снятия резерва (на первых порах – просто дату+5 дней). 
&lt;P&gt;· Подправим метод inventUpd_Reservation.updateReserveMore() (этот метод собственно и резервирует складские проводки), таким образом, чтобы в поле inventTrans,dateExpired записывалось значение, полученное из нового метода inventMovement.dateExpired(). 
&lt;P&gt;· В методе inventUpdReservation.updateReserveLess() (он снимает резервы) вставляем очистку поля dateExpired – чтобы дата снятия резерва не была заполнена для проводок в статусе "Заказанно" 
&lt;P&gt;· Наконец – для того чтобы дата снятия резерва не стояла у уже отгруженных проводок – вставляем очистку даты резервирования в методе inventMovement.initInventTransPhysical(), который вызывается для заполнения полей inventTrans при физической разноске складских проводок. (Кстати – inventMovement.initInventTransFinancial выполняет аналогичную ситуацию при финансовой разноске). Поле salesResponsible я бы не стал зачищать в этом методе, поскольку достаточно удобно, когда это поле заполнено в проводках с любым статусом – а не только в проводках резервирования. 
&lt;P&gt;Если после выполнения этих модификаций поэкспериментировать с резервированием, выясняется что в целом все работает, однако есть один тонкий момент: Как известно, DAX умеет схлопывать записи в inventTrans в рамках одного номера лота, если КЛЮЧЕВЫЕ поля этих записей совпадают. В том случае, если галка "Автоматическое добавление" в параметрах модуля управления запасами установлена – это происходит автоматически – при любом обновлении inventTrans. Если галка не установлена, аналогичного эффекта можно добиться через пункт меню "Суммирование" в форме складских проводок. Так вот – если мы нарезервировали по одному и тому же лоту в разное время, с разными датами автоматического снятия резерва, система при схлопывании проводок может схлопнуть проводки с разными датами снятия резерва, подставив в результирующую проводку первую попавшуюся из нескольких дат. Для того чтобы предотвратить подобный эффект, нужно изменить метод inventTrans.setSumAmount(), так чтобы он дополнительно проверял совпадение даты резервирования и ответственного продавца в двух проводках. 
&lt;P&gt;NB. Кстати – если у вас на проекте есть проблемы с ростом inventTrans, посмотрите – включена ли галка "Автоматическое добавление". Если не включена – попробуйте оценить выигрыш от ее включения. Напишите джобик, который пробежится по существующим складским проводкам и проверит их на совпадение полей, проверяемых в методе inventTrans.setSumAmount. На моей практике – установка этой галки однажды позволила уменьшить число записей в inventTrans по заказам почти в два раза. Хотя с другой стороны – включение этой галки заведомо замедляет обновление inventTrans. 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Подводя общий итог рассмотренному примеру, можно дать следующую рекомендацию: 
&lt;OL&gt;
&lt;LI&gt;&amp;nbsp;Если аттрибут копируется в складскую проводку из исходного документа, то необходимо дополнить метод inventMovement.initInventTrans* инициализацией нового поля из вновь созданного метода класса InventMovement.&lt;/LI&gt;
&lt;LI&gt;Если аттрибут тем или иным образом рассчитывается в процессе выполнения логистической операции, следует поместить инициализацию этого аттрибута в методы соответствующего класса inventUpd_*. &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;P.S. Рассмотренный пример (по крайней мере&amp;nbsp;- с датой автоматического снятия резеров) хорошо работает только при отсутствии резервирования в заказанных. По логике вещей - автоматическое снятие резерва должно работать только для товара, уже находящегося на складе. Для товара в пути эта логика в принципе не работает, поскольку время обработки закупки поставщиком и транспортировки закупленного товара до его прибытия на склад достаточно непредсказуемо и, обычно, значительно больше типичного времени жизни резерва на складе. Поэтому, в случае использования резервирования в заказанных, надо во первых заблокировать удаление просроченных резервов в заказанных, а во вторых - подправить метод inventUpdate.updateDimReserveChange(), таким образом, чтобы при приходе товара, у складской проводки резервирования повторно инициализировалась дата автоматического снятия резерва. (Попросту говоря - этот метод при вызывается при физическом приходе товара, ищет по двум разным алгоритмам подходящую проводку в статусе "Зарезервировано в заказанных" и переводит ее в статус "Физически зарезервировано").&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Update: Когда готовил контрольный пример для статьи, забыл об одном интересном нюансе. Для того чтобы снятие резервов работало интуитивно понятно для пользователя, первыми внутри данного лота должны сниматься резервы с наиболее ранней датой автоматического снятия. Для того чтобы система&lt;/EM&gt; &lt;EM&gt;действовала именно таким образом, необходимо в методе inventUpd_reservation.updateReserveLess поставить сортировку по дате автоматического снятия в те несколько запросов, которые отбирают строки inventTrans для перевода в статус "Заказанно".&lt;/EM&gt;&lt;/P&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=1029577" width="1" height="1"&gt;</content><author><name>denisfed</name><uri>http://blogs.technet.com/members/denisfed.aspx</uri></author><category term="Логистика" scheme="http://blogs.technet.com/denisfed/archive/tags/_1B043E04330438044104420438043A043004_/default.aspx" /><category term="Dynamics AX" scheme="http://blogs.technet.com/denisfed/archive/tags/Dynamics+AX/default.aspx" /><category term="Разработка" scheme="http://blogs.technet.com/denisfed/archive/tags/_2004300437044004300431043E0442043A043004_/default.aspx" /></entry><entry><title>Себестоимость и длинные производственные заказы</title><link rel="alternate" type="text/html" href="http://blogs.technet.com/denisfed/archive/2007/04/23/808703.aspx" /><id>http://blogs.technet.com/denisfed/archive/2007/04/23/808703.aspx</id><published>2007-04-23T15:02:32Z</published><updated>2007-04-23T15:02:32Z</updated><content type="html">&lt;p&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Существует следующая достаточно типовая жалоба на производственный модуль DAX: "Мы не можем посчитать себестоимость списания материалов в производство до завершения производственного заказа. У нас на внедрении, цикл производства одного ПЗ занимает 2-3 недели. Получается что материал давно списан из цеховой кладовой, его уже распилили, нарезали и смонтировали, а по бухгалтерии он до сих пор числится на 10ом счету. Даже если мы включим разноску физических складских операций, они не будут включены в закрытие склада, соответственно - истинную себестоимость списания в производство нам не сосчитать до завершения ПЗ. Получается - наш бухгалтерский баланс отстает от реальности на 2-3 недели. Если ПЗ начат и завершен в разных отчетных периодах - это фатально...".  &lt;p&gt;Давайте попробуем разобраться почему подобная ситуация возникает и как можно исправить ситуацию.  &lt;p&gt;После того как заказ запущен в производство, материалы списываться на производственный заказ через журнал отгрузочных накладных. При этом в складских проводках образуются ФИЗИЧЕСКИЕ проводки списания. При приемке готовой продукции по журналу приемки, у нас также образуются ФИЗИЧЕСКИЕ приходные складские проводки. Кроме того - если мы по ПЗ разносим журналы карты маршрута или карты заданий, у нас в затратах по производственному заказу (таблица ProdCalcTrans, которую можно посмотреть из формы ПЗ по кнопке Запросы-&amp;gt;Рассчет цены) накапливается информация о нематериальных затратах на производство по данному ПЗ. При этом делается проводка на сумму нематериальных затрат по дебету счета "Счет НЗП" и кредиту счета "Расход НЗП". В зависимости от настроек ПЗ, эти счета беруться из настроек рабочего центра, категории затрат по маршруту или производственных групп. Наконец, при завершении производственного заказа, система переводит проводки списания и оприходования в статус финансовых списаний и приходов и проводит эти списания и приходы по счетам ГК. Кроме того, проводки по списанию нематериальных затрат реверсируются,&amp;nbsp;затем вместо них делаются проводки по ГК на те же суммы по счетам прихода и расхода из настроек калькуляции себестоимости.  &lt;p&gt;Почему так сделано ? С приходными проводками - все понятно. Пока заказ не завершен, на него могут быть отнесены новые затраты, соответственно - посчитать окончательную себестоимость прихода мы не можем и делать финансовые приходы по складу рановато. С проводками списания, как мне кажется,такая ситуация вызвана скорее техническими проблемами. При закрытии склада, в случае корректировки себестоимости по финансовой складской проводке списания в производство, необходимо также скорректировать и приходную финансовую складскую проводку по производству. А у нас этой проводки до завершения ПЗ просто нету. Мне кажется - в принципе можно было бы попытаться изменить процедуру закрытия склада таким образом, чтобы эта ситуация обрабатывалась (Например - накапливать сумму коррекций где-нибудь в шапке ПЗ, чтобы потом использовать при создании финансовой складской проводки по приходу из производства). Тем не менее - разработчики процедуры закрытия склада нашли более простое решение этой проблемы, о котором мы и поговорим ниже. Ну и наконец&amp;nbsp;- я совершенно не понимаю, почему реверсируются и заново проводятся проводки списания нематериальных затрат. Судя по коду - предварительные (это те которых потом реверсируют) и окончательные проводки в принципе не могут различаться по суммам. Так что это - либо какое-то требование западного учета, либо идея из серии "reserved for future use"&amp;nbsp; и разработчики планируют в дальнейшем сделать какой-то механизм который позволит пересчитывать окончательные нематериальные затраты и они будут отличаться от предварительных (которые мы по журналу карт маршрута или карт заданий разносим).  &lt;p&gt;Возникает вопрос - что же делать ? То что у нас себестоимость прихода из ПЗ не рассчитывается до завершения ПЗ - полбеды. В общем-то можно как-то объяснить почему мы ее не считаем до накопления всех затрат по ПЗ. Но вот что с себестоимостями списаний делать ? В закрытие склада они не попадают, коррекции на них не проводяться и к концу периода мы можем получить неадекватное сальдо на 10ом счете...  &lt;p&gt;Дело в том, что распространенное мнение, что закрытие и пересчет склада работают только с финансовыми складскими проводками, начиная с версии 3.0sp2 не соответствует истине. Дело в том, что начиная с этой версии, рассчет себестоимости обрабатывает ФИЗИЧЕСКИЕ складские проводки по той номенклатуре, у которой в группе складских моделей стоит галочка "Включать физическую себестоимость".  &lt;p&gt;Система позволяет сопоставить друг с другом физическую и финансовую проводку (например - приход по отборочной накладной и списание по накладной, или, как в нашем случае, приход по накладной и списание в производство по отгрузочной накладной). Кардинальное отличие от&amp;nbsp;обычного сопоставления финансовых проводок состоит в том, что если одна из сопоставляемых проводок - физическая, то данные о сопоставлении не записываются в таблицу сопоставлений, сопоставление делается только в памяти, как при выполнении процедуры пересчета склада.&amp;nbsp;Кроме того, если в результате сопоставления произошла коррекция по физической расходной складской проводке, то коррекция не протягивается по цепочке себестомости. Тем не менее, коррекции себестоимости списания записываются в таблицу складских сопоставлений и если по данному списанию у нас выполнялась разноска в ГК по физической складской проводке, то в результате разноски в ГК закрытия или пересчета в главную книгу попадет и сумма коррекции. Надо отметить, что коррекции физических проводок списания записываются в таблицу складских сопоставлений с специальной моделью (поле settleModel) -"Физическое значение". Соответственно - эти коррекции можно легко вычленить при анализе результатов закрытия/пересчета склада.  &lt;p&gt;Значит для того, чтобы у нас корректно списывалась себестоимость по складским проводкам списания по ПЗ нам нужно сделать следующее:  &lt;p&gt;· Надо для всех материалов включить в настройках складской модели режим "Включать физическую себестоимость"  &lt;p&gt;· Для того чтобы у нас делались проводки по ГК при выполнении физических списаний нужно не только включить разноску физических запасов в параметрах складских моделей но и включить галку "Разнести отгрузочную накладную в главную книгу" в параметрах модуля производство.  &lt;p&gt;· Хотя, строго говоря, к проблеме списания номенклатуры в производство это не имеет отношения, но было бы полезно если бы при приемке ГП у нас тоже делались проводки по ГК. Для этого надо у ГП включить режим разноски физических операций в параметрах складской модели и галку "Отчет о разноске принятого в ГК" в параметрах складского модуля. Кроме того, для того чтобы система порождала правдоподобную себестоимость при физическом оприходовании ГП по операции приемки, надо поставить в параметрах модуля производства галку "Использовать оцененную себестоимость". Если эта галка включена – система будет рассчитывать себестоимость прихода на основании списка накопленных по ПЗ затрат в таблице ProdCalcTrans.  &lt;p&gt;· Наконец – надо в настройке разноски по складу, прописать в качестве счета и корсчета отгрузочной накладной те же счета что и для расхода и корсчета расхода. (20.xx и 10.xx). Для счета и корсчета приемки, надо поставить те же счета что и прихода и корсчета прихода (43.xx и 20.xx)  &lt;p&gt;· Для счетов нематериальных затрат, надо прописать одинаковые счета и корсчета и для НЗП и для счетов по калькуляции себестоимости. (скажем – 20.xx и 70.xx)  &lt;p&gt;В таком случае – мы получаем следующую картину:  &lt;p&gt;1. При списании номенклатуры по журналу отборочных накладных, получаем проводки Д 20.xx К 10.xx с правдоподобной суммой. (Фактически – мгновенной себестоимостью)  &lt;p&gt;2. При приходовании номенклатуры по журналу приемки также получаем разумные проводки Д 43.xx К 20.xx с разумной себестоимостью.  &lt;p&gt;3. При списании нематериальных затрат – проводки Д 20.xx К 70.xx  &lt;p&gt;4. В случае если производственный заказ длиться долго и закрытие склада произошло раньше чем заказ был завершен – то при закрытии склада получаем проводки коррекции Д20.xx К 10.xx, которые доводят остаток на 10 счете до правильного значения.  &lt;p&gt;5. При завершении заказа – получаем сначала реверсивные проводки по складу (реверс физической операции) Д 10.xx К 20.xx для расхода и Д20.xx К 43.xx для прихода. При этом в качестве суммы реверсивной проводки берется сумма С УЧЕТОМ накопленной при закрытии склада коррекции. Кроме того – реверсируются нематериальные затраты (Д 70 К 20). После этого – делаются обычные финансовые складские проводки прихода и списания с разноской в ГК (Д 20.xx К 10.xx и Д 43.xx К 20.xx) и проводки на нематериальные затраты (Д 20.xx К 70.xx).  &lt;p&gt;6. При следующем закрытии склада у нас делаются обычные коррекции Д 20.xx К 10.xx и Д 43.xx К 20.xx как при обычном закрытии склада. При этом – прошлые проводки коррекции по закрытию склада уже не играют, поскольку при выполнении финансовой разноски складских проводок, они были отреверсированы.  &lt;p&gt;В общем – получается чуток странноватая с точки зрения русского бухгалтера, но в целом вполне жизненная схема. Единственное что выглядит странным – это то что при завершении ПЗ, предварительные проводки не сторнируются, а реверсируются.  &lt;p&gt;Но эту особенность можно достаточно легко вылечить. Для того чтобы реверс складских операций выполнялся как сторно, достаточно в методах updateFinancialIssue и updateFinancialReceipt класса inventUpd_financial найти кусок кода, который вызывывает метод разноски физических складских операций по ГК: movement.updateLedgerPhysical(ledgerVoucher,inventTrans,this,inventOnhand);  &lt;p&gt;&amp;nbsp;До и после этого метода надо вставить следующий кусочек кода, который переключает режим сторнирования:  &lt;p&gt;ledgerVoucher.findLedgerVoucherObject().parmCorrection(!ledgerVoucher.findLedgerVoucherObject().parmCorrection());  &lt;p&gt;Наконец – для того чтобы заменить реверс начисления нематериальных затрат а сторно, достаточно вставить аналогичные куски кода в метод UpdateCalcLedger класса ProdJobType. В его начале есть следующий кусок:  &lt;p&gt;if (prodRouteTrans.PostingWIPValuation &amp;amp;&amp;amp; prodRouteTrans.Amount)  &lt;p&gt;{  &lt;p&gt;…………  &lt;p&gt;}  &lt;p&gt;Если в начале и конце кода, выполняемого по условию If () вставить знакомый нам кусок кода для включения/выключения сторнировки – реверс замениться сторнированием.  &lt;p&gt;Нужно помнить, что включив в классе inventUpd_Financial сторнирование вместо реверсирования мы включим его не только для производства, но и для обычных заказов и закупок. Соответственно, в случае если у нас по отборочной накладной по заказу или закупке проводились проводки в главную книгу, то при оформлении обычной накладной, эти проводки будут не отреверсированы, а отсторнированы.  &lt;p&gt;Наконец, чтобы завершить тему себестоимости по производству, надо упомянуть о галке "Обновить производство" в параметрах закрытия/пересчета склада. Если эта галка установлена, то данные о коррекции проводок списания в производство попадают не только в ГК и таблицу складских сопоставлений, но и в поле realCostAdjustment (Корректировка) той записи таблицы ProdCalcTrans (Рассчет), которая привязана к корректируемой складской проводке списания, а также в поле Adjustment (корректировка) журнала отгрузочных накладных. Кроме того – при этом обновляется сумма корректировки в той записи таблицы ProdCalcTrans, которая привязана к проводке по приходу готовой продукции по ПЗ. &lt;/p&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=808703" width="1" height="1"&gt;</content><author><name>denisfed</name><uri>http://blogs.technet.com/members/denisfed.aspx</uri></author><category term="Логистика" scheme="http://blogs.technet.com/denisfed/archive/tags/_1B043E04330438044104420438043A043004_/default.aspx" /><category term="Dynamics AX" scheme="http://blogs.technet.com/denisfed/archive/tags/Dynamics+AX/default.aspx" /><category term="Производство" scheme="http://blogs.technet.com/denisfed/archive/tags/_1F0440043E043804370432043E0434044104420432043E04_/default.aspx" /></entry><entry><title>Как сторнировать журнал спецификаций?</title><link rel="alternate" type="text/html" href="http://blogs.technet.com/denisfed/archive/2007/04/04/725719.aspx" /><id>http://blogs.technet.com/denisfed/archive/2007/04/04/725719.aspx</id><published>2007-04-04T10:18:32Z</published><updated>2007-04-04T10:18:32Z</updated><content type="html">&lt;p&gt;Вчера бывший коллега задал мне именно этот вопрос.Самый банальный подход - просто создать аналогичный журнал, подставив туда количества с обратным знаком&amp;nbsp; - не работает. Во первых - в процедуре редактирования и разноски этого журнала есть куча проверок, которые не дадут этого сделать. Во вторых - этот журнал предназначен для СБОРКИ изделий, но никак не для РАЗБОРКИ таковых. В третьих - если подумать - у нас ведь стоит задача не разобрать чего-то, а просто отсторнировать исходный журнал.&lt;/p&gt; &lt;p&gt;На самом деле, задача сторнировки журнала спецификаций решается с помощью журнала складских проводок. Оприходованную по журналу спецификаций номенклатуру надо списать в складском журнале на коррсчет прихода из настроек складской разноски по производству. После этого - надо это списание примаркировать к приходу по журналу спецификаций. Списанную по журналу спецификаций номенклатуру надо оприходовать с коррсчета расхода из настроек складской разноски по производству. При этом - обязательно нужно указать номер возвращаемого лота, прописав туда ссылку на тот лот, по которому эта номенклатура списывалась по журналу спецификаций. Себестоимость в этих страках журнала можно поставить нулевую, поскольку после закрытия склада или пересчета, система поставит по&amp;nbsp;складским проводкам правильную себестоимость, равную себестоимости списания по журналу спецификации.&lt;/p&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=725719" width="1" height="1"&gt;</content><author><name>denisfed</name><uri>http://blogs.technet.com/members/denisfed.aspx</uri></author></entry><entry><title>Перемещаем товар программно</title><link rel="alternate" type="text/html" href="http://blogs.technet.com/denisfed/archive/2007/03/27/710328.aspx" /><id>http://blogs.technet.com/denisfed/archive/2007/03/27/710328.aspx</id><published>2007-03-27T13:12:27Z</published><updated>2007-03-27T13:12:27Z</updated><content type="html">&lt;p&gt;На проектах время от времени возникает ситуация, при которой заказчик хочет приделать какой-то свой собственный интерфейс к складским перемещениям. Классический пример - для автоматизации транспортной компании нужно сделать какой-то модуль, который бы отслеживал перемещение транспорта и накапливал бы затраты на перемещение, а также&amp;nbsp; попутно переносил бы в логистическом модуле товар между складами, каждый из которых соответствует путевым точкам или маршрутам от точки до точки. Обычно, в таком случае, в таком случае разработчики приписывают к данному модулю механизм, который создает и разносит журналы переноса. Этот механизм получается достаточно тяжеловесным и неудобным. Кроме того - есть шансы что при неаккуратной настройке журналов переноса этот механизм интеграции с логистикой сломается и будет выдавать непонятные пользователю сообщения (скажем - об отсутствии имени складского журнала или номерной серии для нумерации журналов).&lt;/p&gt; &lt;p&gt;Существует гораздо более изящный и удобный механизм, позволяющий перемещать товар между складскими аналитиками. Этот механизм&amp;nbsp;- использование функции InventUpd_Financial::updateVirtuelTransfer(). Вот список ее параметров:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;static void updateVirtuelTransfer(&lt;br&gt;ItemId _itemId,&lt;br&gt;InventDimId _fromInventDimId,&lt;br&gt;InventDimId _toInventDimId,&lt;br&gt;TransDate _transDate,&lt;br&gt;InventQty _qty, // Positive&lt;br&gt;NoYes _mustBeQuarantineControlled&lt;br&gt;)  &lt;p&gt;Думаю - по названию параметров их смысл и так понятен - номенклатура, складская аналитика-источник, складская-аналитика приемник, дата, количество (положительное) и признак использования карантинного склада (я бы его всегда выключал). Для того чтобы это все работало - достаточно настроить&amp;nbsp;в параметрах модуля управления запасами номерную серию "Операция журнала". (В третьей версии этот параметр, кажется, назывался "Документ ГК по журналу").&lt;/p&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=710328" width="1" height="1"&gt;</content><author><name>denisfed</name><uri>http://blogs.technet.com/members/denisfed.aspx</uri></author><category term="Логистика" scheme="http://blogs.technet.com/denisfed/archive/tags/_1B043E04330438044104420438043A043004_/default.aspx" /><category term="Dynamics AX" scheme="http://blogs.technet.com/denisfed/archive/tags/Dynamics+AX/default.aspx" /><category term="Разработка" scheme="http://blogs.technet.com/denisfed/archive/tags/_2004300437044004300431043E0442043A043004_/default.aspx" /></entry><entry><title>Себестоимость и закрытие склада</title><link rel="alternate" type="text/html" href="http://blogs.technet.com/denisfed/archive/2007/03/23/705202.aspx" /><id>http://blogs.technet.com/denisfed/archive/2007/03/23/705202.aspx</id><published>2007-03-23T14:51:00Z</published><updated>2007-03-23T14:51:00Z</updated><content type="html">&lt;DIV class=Section1&gt;Текст статьи (с обновлениями для Dynamics AX 2009) переехал по адресу: 
&lt;H1 style="MARGIN: 24pt 0cm 0pt"&gt;&lt;FONT color=#365f91 size=5 face=Cambria&gt;&lt;A href="http://blogs.technet.com/denisfed/pages/3236801.aspx" mce_href="http://blogs.technet.com/denisfed/pages/3236801.aspx "&gt;Себестоимость и закрытие склада&lt;/A&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/H1&gt;&lt;/DIV&gt;&lt;img src="http://blogs.technet.com/aggbug.aspx?PostID=705202" width="1" height="1"&gt;</content><author><name>denisfed</name><uri>http://blogs.technet.com/members/denisfed.aspx</uri></author></entry></feed>