14.02.2011, 12:43 | #1 |
Участник
|
Проблемы при закрытии склада DAX2009 SP1 RU5/RU6
Решил поделиться проблемами и решениями, которые возникли при закрытии склада. Большая часть проблем связана с расширенным расчетом производственной себестоимости, который был добавлен RU5.
ПРОБЛЕМА 1: Неверная себестоимость расходов при расширенном расчете себестоимости. Основная логика по закрытию склада находится в классе InventCostItemDim. В методе updateItem вызывается updateLevelAdjustment() в котором коррекции, которые «прилетели» на данную номенклатуру с предыдущих шагов, распределяются на приходные проводки этой номенклатуры. X++: while select sum(Adjustment) from inventCostListTrans index hint ItemIdx group by InventTransId,InventTransIdReturn,VoucherPhysical where inventCostListTrans.Voucher == inventClosing.Voucher && inventCostListTrans.NumOfIteration == inventCostList.NumOfIteration && inventCostListTrans.ItemId == inventCostList.ItemId { // <GEEU> if (calculationProdWIP_RU && inventCostListTrans.InventTransId && this.calcWIPProdHistoricalCost_RU(inventCostListTrans.InventTransId, inventCostListTrans.VoucherPhysical)) { continue; } // </GEEU> this.updateTransIdReceipt(inventCostListTrans.InventTransId, inventCostListTrans.Adjustment, inventCostListTrans.InventTransIdReturn, inventCostListTrans.VoucherPhysical); } Если включен расширенный расчет себестоимости и приходная проводка имеет тип «Производство», то вызывается метод calcWIPProdHistoricalCost (), в нем вызывается написанная в RU5 логика, рассчитывается фактическая себестоимость расходов по производственному заказу, себестоимость выходов (побочной и основной продукции), делается коррекция приходов. Так вот, первая проблема связана с тем, что наши локализаторы забыли для основного выхода сделать вставку в вышеупомянутый mapInventTrans и все коррекции, которые были добавлены к приходам, не распространялись на расходы. РЕШЕНИЕ Нужно в конце метода ProdCalculatingWIPEngine_RU:: createAdjustSettlement() вызвать inventCostItemDim.updateInventTrans(_inventTrans): X++: //+ DPL InventClosingFix_OK 11.02.2011 OK if (inventCostItemDim != null) { inventCostItemDim.updateInventTrans(_inventTrans); } else //- DPL InventClosingFix_OK 11.02.2011 OK _inventTrans.update(); } X++: //+ DPL InventClosingFix_OK 11.02.2011 OK //protected void updateInventTrans(InventTrans _inventTrans) public void updateInventTrans(InventTrans _inventTrans) //- DPL InventClosingFix_OK 11.02.2011 OK ... |
|
|
За это сообщение автора поблагодарили: fed (30), Logger (15), madm (1), zhan (2), imir (1). |
14.02.2011, 12:47 | #2 |
Участник
|
ПРОБЛЕМА 2. Неверная себестоимость расходов по побочной продукции.
Эта проблема очень похожа на предыдущую, но причина немного в другом. Рассмотрим на примере. Вся логика выполняется на 0-й итерации. Есть продукция «какао-масло» и побочная «жмых», в расход идет «какао-тертое». На предыдущих шагах закрытия склада были сделаны коррекции «какао-тертого», то есть изменилась себестоимость расхода. Эта коррекция попала в таблицу inventCostListTrans, чтобы система переоценила стоимость связанных выходов «какао-масла» и «какао-тертого». Далее система доходит до расчета «какао-масла», запускает расчет RU5, рассчитывается стоимость выхода основной и побочной продукции. Для побочной продукции локализаторы , в отличие от проблемы №1 сделали правильно – вызвали из своей логики метод updateTransIdReceipt(), который отразил коррекцию на приходе побочной продукции и добавил проводку в mapInventTrans, чтобы «распространить» коррекцию на сопоставленные расходные проводки. Все бы было хорошо, если бы это не было 0-й итерации и самым первым расчетом для «какао-масла». На нулевой итерации в методе InventCostItemDim:: updateItem() запускается сопоставление по модели: X++:
se = setInventDim.getEnumerator();
while (se.moveNext())
{
inventDim = se.current();
this.initMapInventTrans();
this.load(inventDim);
this.updateReceiptAdjustment();
this.updateModel(inventDim);
} РЕШЕНИЕ В методе InventCostItemDim:: updateItem() перед циклом сопоставления нужно вызвать updateReceiptAdjustment(): X++: else { // if this is not a closing, or if this is the first time, then match .. // first match issues and receipts that are marked this.updateSettleRefItem(inventCostList.ItemId); //+ DPL InventClosingFix_OK 12.02.2011 OK //если здесь не вызвать этот метод-не идут дальше коррекции по побочной продукции if (calculationProdWIP_RU) this.updateReceiptAdjustment(); //- DPL InventClosingFix_OK 12.02.2011 OK // then match remaining issues and receipts according to inventory model if (! isServiceItem) { setInventDim = new Set(Types::Record); // find all financial dimension combinations queryRun = inventCostHelp.initQueryRunTrans(this.inventTable(inventCostList.ItemId), this.inventModelGroup(inventCostList.ItemId)); while (queryRun.next()) { inventDim = queryRun.get(tablenum(InventDim)); setInventDim.add(inventDim); } // match issues and receipts per financial dimension combination se = setInventDim.getEnumerator(); while (se.moveNext()) { inventDim = se.current(); this.initMapInventTrans(); this.load(inventDim); this.updateReceiptAdjustment(); this.updateModel(inventDim); } setInventDim = null; } } |
|
14.02.2011, 12:49 | #3 |
Участник
|
ПРОБЛЕМА 3. Все коррекции, сделанные по приходным проводкам с типом «Производство» при помощи коррекции проводок в форме «Закрытие и коррекция» отменяются!
При расширенном расчете себестоимости, который запускается из InventCostItemDim ::calcWIPProdHistoricalCost_RU после расчета стоимости основного выхода, себестоимость этого выхода корректируется в ProdCalculatingWIPEngine_RU ::createProdReceiptAdjust по формуле [коррекция] = [рассчитанная стоимость] – [текущая стоимость]. Таким образом, если вы перед закрытием распределили затраты на приходы из производства, то эти суммы будут успешно отменены и себестоимость выходов будет равна себестоимости расходов по производственному заказу. РЕШЕНИЕ На таблице InventTrans создайте метод: X++: // DPL InventClosingFix_OK 13.02.2011 OK //расчет суммы коррекций добавленной распределением затрат Amount calcManualCorrAmount_OK() { InventSettlement invSettlement; InventClosing inventClosing; ; select sum(CostAmountAdjustment) from invSettlement where invSettlement.Cancelled == NoYes::No && invSettlement.TransRecId == this.RecId exists join inventClosing where inventClosing.Voucher == invSettlement.Voucher && inventClosing.AdjustmentType == InventAdjustmentType::Transaction; return invSettlement.CostAmountAdjustment; } X++: //+ DPL InventClosingFix_OK 13.02.2011 OK //отнимаем чтобы не отсторнировать распределение затрат costAmount -= inventTrans.calcManualCorrAmount_OK(); //- DPL InventClosingFix_OK 13.02.2011 OK ProdWIPHistoricalCostTable_RU::createProductionRecord(prodTable.ProdId, |
|
14.02.2011, 12:51 | #4 |
Участник
|
ПРОБЛЕМА 4 . Есть проблемы с производительностью при расширенном расчете себестоимости.
Есть неоптимальные запросы, которые вызываются из логики, добавленной в RU5. РЕШЕНИЕ. Рекомендую добавить следующие индексы: 1. На таблице InventTrans по полям InventTransIdFather,DateFinancial. 2. На таблице InventTrans по полям TransRefId, TransType, DatePhysical. 3. На таблице ProdWIPHistoricalCostTable_RU по полю ReleaseRefRecId. 4. На таблице InventByProductTable_RU включить индекс на RecId. |
|
|
За это сообщение автора поблагодарили: Poleax (3). |
14.02.2011, 12:52 | #5 |
Участник
|
ПРОБЛЕМА 5 . Не работает отмена закрытия или пересчета в пакетном режиме, если есть выделенный пакетный сервер.
Если делать отмену закрытия в пакетном режиме и указывать пакетную группу, система создает первую задачу с указанной пакетной группой, а все остальные, от которых зависит первая создает с пустой пакетной группой. Если на эту пустую группу не настроен ни один АОС, то она никогда не завершится. РЕШЕНИЕ. Если без доработок, то нужно добавить пустую пакетную группу к какому-либо серверу. |
|
|
За это сообщение автора поблагодарили: b_nosoff (1). |
14.02.2011, 13:12 | #6 |
Moderator
|
Цитата:
Сообщение от Bega
ПРОБЛЕМА 5 . Не работает отмена закрытия или пересчета в пакетном режиме, если есть выделенный пакетный сервер.
Если делать отмену закрытия в пакетном режиме и указывать пакетную группу, система создает первую задачу с указанной пакетной группой, а все остальные, от которых зависит первая создает с пустой пакетной группой. Если на эту пустую группу не настроен ни один АОС, то она никогда не завершится. РЕШЕНИЕ. Если без доработок, то нужно добавить пустую пакетную группу к какому-либо серверу. |
|
14.02.2011, 13:13 | #7 |
Участник
|
|
|
14.02.2011, 13:19 | #8 |
Участник
|
Вы наверное имели в виду InventParameters.CloseBatchGroupId - это поле у нас заполнено, однако в связанных пакетных задачах все равно не было подставлено.
|
|
14.02.2011, 13:27 | #9 |
Moderator
|
Цитата:
В принципе - это не совсем баг, это скорее misfeature, заложенная датскими разработчиками... |
|
25.02.2011, 16:49 | #10 |
Участник
|
Обнаружена такая проблема:
Производство не используется (отключена лицензия). При закрытии склада система пытается сделать какой-то расчет по производственным заказам (InventCostHelp.runProdWIPCalculation_RU()), при этом не находит номерной серии, которая должна быть настроена в параметрах модуля Производство и закрытие останавливается с ошибкой. Я так понимаю, проверка на то, что вообще нужен этот расчет, должна быть до начала каких-либо действий. Стоит добавить проверку на конфигурационный ключ Prod или есть какой-то еще признак, который позволит это сделать?
__________________
Ivanhoe as is.. |
|
25.02.2011, 16:54 | #11 |
Участник
|
Цитата:
Сообщение от Ivanhoe
Обнаружена такая проблема:
Производство не используется (отключена лицензия). При закрытии склада система пытается сделать какой-то расчет по производственным заказам (InventCostHelp.runProdWIPCalculation_RU()), при этом не находит номерной серии, которая должна быть настроена в параметрах модуля Производство и закрытие останавливается с ошибкой. Я так понимаю, проверка на то, что вообще нужен этот расчет, должна быть до начала каких-либо действий. Стоит добавить проверку на конфигурационный ключ Prod или есть какой-то еще признак, который позволит это сделать? X++: .. if (masterClient && CompanyInfo::features_W() == CRSEFeatures_W::RU //+DPL && isConfigurationkeyEnabled(configurationkeynum(Prod)) //-DPL ) { ... Последний раз редактировалось Bega; 25.02.2011 в 16:58. |
|
|
За это сообщение автора поблагодарили: EVGL (10). |
25.02.2011, 16:58 | #12 |
Участник
|
Собственно так и сделал Странно, что нет нормального управления этим. По факту там дальше перебираются все производственные заказы в периоде и по каждому проверяется - нужно ли считать эту расширенную себестоимость. Кому-то "опять двойка"
__________________
Ivanhoe as is.. |
|
25.02.2011, 17:00 | #13 |
Участник
|
Да, локализаторы в 5-м роллапе допустили много ошибок, как-то в попыхах все, на бегу
|
|
25.02.2011, 18:06 | #14 |
Moderator
|
|
|
25.02.2011, 19:22 | #15 |
Участник
|
Ну раз пошла такая пьянка
Отмена закрытия склада при отключенном ключе двух-валютного склада пропускает удаление проводок SummedUp со всеми вытекающими вкусностями Class / InventCostClosingCancel_WorkInvent / deleteVirtualTransfers X++: ... while select forupdate inventTrans order by InventTransId where inventTrans.ValueOpen == InventTransOpen::Yes // <GEEU> // && inventTrans.ValueOpenSecCur_RU == InventTransOpen::Yes && inventTrans.ValueOpenSecCur_RU == (isConfigurationKeyEnabled(configurationkeynum(InventClosingSecCur_RU)) ? InventTransOpen::Yes : InventTransOpen::No) // </GEEU> ... PS. Интересно, много ли еще таких мест ? |
|
|
За это сообщение автора поблагодарили: EVGL (5), Bega (1). |
25.02.2011, 20:29 | #16 |
Banned
|
Bega, а вы с Microsoft по поводу этих багов связались? Как-то не хотелось бы править из версии в версию.
|
|
28.02.2011, 09:31 | #17 |
Участник
|
|
|
28.02.2011, 17:54 | #18 |
Участник
|
Цитата:
X++: ... while select forupdate inventTrans order by InventTransId where inventTrans.ValueOpen == InventTransOpen::Yes // <GEEU> //+ DPL InventClosingFix_OK 28.02.2011 OK //inventTrans.ValueOpenSecCur_RU == InventTransOpen::Yes) && ( !isConfigurationKeyEnabled(configurationkeynum(InventClosingSecCur_RU)) || inventTrans.ValueOpenSecCur_RU == InventTransOpen::Yes) //- DPL InventClosingFix_OK 28.02.2011 OK ... |
|
01.03.2011, 12:40 | #19 |
SDET, Dynamics AX
|
Цитата:
Сообщение от Bega
ПРОБЛЕМА 5 . Не работает отмена закрытия или пересчета в пакетном режиме, если есть выделенный пакетный сервер.
Если делать отмену закрытия в пакетном режиме и указывать пакетную группу, система создает первую задачу с указанной пакетной группой, а все остальные, от которых зависит первая создает с пустой пакетной группой. Если на эту пустую группу не настроен ни один АОС, то она никогда не завершится. РЕШЕНИЕ. Если без доработок, то нужно добавить пустую пакетную группу к какому-либо серверу. Отличная тема. Попросил соответствующих людей чтоб посмотрели что тут описано. |
|
02.03.2011, 13:47 | #20 |
Участник
|
Если уж начали перечислять баги закрытия, то добавлю свои 5 копеек.
В методах \Classes\ClassFactory\inventLastClosingDate \Classes\ClassFactory\inventLastClosingDateSecCur_RU некорректно сделано кеширование даты последнего закрытия склада. Оно не учитывает тот факт, что закрытие склада выполняется в конкретной компании. Поэтому если мы поработали в одной компании, в которой период закрыт, а потом переключаемся в другую, в которой период не закрыт, и пытаемся в этом периоде разносить что-то - то получаем ошибку. Лечится например так : X++: TransDate inventLastClosingDate(boolean reSelect = false) { // GRD_FixLastClosingDateCalc_pkoz // pkoz 16.01.2011 --> // проект GRD_FixLastClosingDateCalc_pkoz сделан для того чтбы исправить кеширование даты последнего закрытия склада // это кеширование не учитывало компанию, так что если, например, у нас в одной компании // склад закрыт по одоной число, а в другой по другое, то аксапта могла для обоих компаний считать дату одинаковой - // в случае если сперва метод вызвали в одной компании, а потом в другой #define.GRD_date("_date") #define.GRD_integer("_integer") sysglobalCache GRD_globalCache = this.globalCache(); // получаем через метод так как может оказаться неинициализированным // GRD_FixLastClosingDateCalc_pkoz // pkoz 16.01.2011 <-- ; // GRD_FixLastClosingDateCalc_pkoz // pkoz 16.01.2011 --> inventLastClosingDate = GRD_globalCache.get(funcname() + #GRD_date, curExt(), dateNull()); inventClosingTtsVersion = GRD_globalCache.get(funcname() + #GRD_integer, curExt(), 0); // GRD_FixLastClosingDateCalc_pkoz // pkoz 16.01.2011 <-- if (inventClosingTtsVersion != appl.ttsVersion() || reSelect || (!inventClosingTtsVersion && !inventLastClosingDate)) { // pkoz 02.01.2009 --> // слишком много коррекций накопилось - так будет быстрее // inventLastClosingDate = (select maxOf(transDate) from inventClosing inventLastClosingDate = (select forceliterals maxOf(transDate) from inventClosing // pkoz 02.01.2009 <-- index hint TypeActiveIdx where inventClosing.active == NoYes::Yes && // <GEEU> inventClosing.InventTransCurrency_RU == InventTransCurrency_RU::PrimaryCur && // </GEEU> inventClosing.adjustmentType == InventAdjustmentType::Closing).transDate; inventClosingTtsVersion = appl.ttsVersion(); // GRD_FixLastClosingDateCalc_pkoz // pkoz 16.01.2011 --> GRD_globalCache.set(funcname() + #GRD_date, curExt(), inventLastClosingDate); GRD_globalCache.set(funcname() + #GRD_integer, curExt(), inventClosingTtsVersion); // GRD_FixLastClosingDateCalc_pkoz // pkoz 16.01.2011 <-- } return inventLastClosingDate; } |
|
Теги |
баг, закрытие склада, ошибка, ошибка при закрытии склада, себестоимость |
|
|