|
10.11.2020, 14:17 | #1 |
Участник
|
Закрытие склада во вторичной валюте
Коллеги, обнаружил что в методе класса \Classes\InventCostItemDim\updateMarking используется отбор проводок определённого типа:
X++: // load while select forupdate inventTrans index hint OpenItemIdx where inventTrans.ValueOpen == InventTransOpen::Yes && inventTrans.ItemId == _itemId && inventTrans.InventRefTransId != '' join inventDim where inventDim.InventDimId == inventTrans.InventDimId { ... Таким образом, при закрытии склада во вторичной валюте после закрытия в основной, мы не можем отобрать нужные проводки (потому что фильтрация по inventTrans.ValueOpen == InventTransOpen::Yes) и вообще не получаем сопоставлений, аналогичных тем, что были в основной валюте. То же самое видим в методе класса \Classes\InventCostItemDim\updateServiceItemTrans: X++: while select forupdate inventTrans index hint OpenItemIdx where inventTrans.ValueOpen == InventTransOpen::Yes && inventTrans.ItemId == _itemId && (inventTrans.StatusIssue == StatusIssue::Sold || inventTrans.StatusReceipt == StatusReceipt::Purchased) && inventTrans.DateStatus <= inventClosing.TransDate && inventTrans.InventRefTransId == '' //marked service item transactions will be settled according to marking principle { ... Заметили только что, потому что наша бизнес-логика активно использует эти сопоставления (коррекции себестоимости) в основной и во вторичной валюте. Думаю исправить сие вручную. Но, может, кому известны какие-нибудь подводные камни?
__________________
MS Dynamics AX 2009 Kernel 5.0.1600.4110 Application 5.0.1500.6491 |
|
10.11.2020, 15:32 | #2 |
Участник
|
Если есть возможность загляните в AX 2012 R3, может быть там не только эти баги исправлены, вот как выглядят данные выборки в InventCostItemDim
X++: countryRegion_RU = SysCountryRegionCode::isLegalEntityInCountryRegion([#isoRU]); X++: // load while select forupdate inventTrans index hint OpenItemIdx // <GEERU> where (countryRegion_RU && ((inventTransCurrency == InventTransCurrency_RU::PrimaryCur && inventTrans.ValueOpen == InventTransOpen::Yes) || (inventTransCurrency == InventTransCurrency_RU::SecondaryCur && inventTrans.ValueOpenSecCur_RU == InventTransOpen::Yes)) || (!countryRegion_RU && (inventTrans.ValueOpen == InventTransOpen::Yes))) // </GEERU> && inventTrans.ItemId == _itemId && inventTrans.MarkingRefInventTransOrigin join inventDim where inventDim.InventDimId == inventTrans.InventDimId X++: protected void updateServiceItemTrans(ItemId _itemId) { InventTrans inventTrans; InventSettlement inventSettlement; RecordInsertList recordInsertList = new RecordInsertList(tableNum(InventSettlement),true,true); // Optimization note: All columns are expected to be included in the index while select forupdate inventTrans index hint OpenItemIdx // <GEERU> where ((countryRegion_RU && ((inventTransCurrency == InventTransCurrency_RU::PrimaryCur && inventTrans.ValueOpen == InventTransOpen::Yes) || (inventTransCurrency == InventTransCurrency_RU::SecondaryCur && inventTrans.ValueOpenSecCur_RU == InventTransOpen::Yes))) || (!countryRegion_RU && inventTrans.ValueOpen == InventTransOpen::Yes)) // </GEERU> && inventTrans.ItemId == _itemId && (inventTrans.StatusIssue == StatusIssue::Sold || inventTrans.StatusReceipt == StatusReceipt::Purchased) && inventTrans.DateStatus <= inventClosing.TransDate && inventTrans.MarkingRefInventTransOrigin == 0 // marked service item transactions will be settled according to marking principle { // <GEERU> if (countryRegion_RU) { inventSettlement = this.initInventSettlement(inventTrans, inventTransCurrency == InventTransCurrency_RU::PrimaryCur ? inventTrans.financialOpenQty() : inventTrans.financialOpenQtySecCur_RU(), inventTransCurrency == InventTransCurrency_RU::PrimaryCur ? inventTrans.financialOpenValue() : inventTrans.financialOpenValueSecCur_RU(), 0, InventSettleModel::ServiceItem, inventTrans.Qty >= 0 ? InventSettleType::Receipt : InventSettleType::Issue, #initLedgerDrop ); } else { // </GEERU> inventSettlement = this.initInventSettlement(inventTrans, inventTrans.financialOpenQty(), inventTrans.financialOpenValue(), 0, InventSettleModel::ServiceItem, inventTrans.Qty >= 0 ? InventSettleType::Receipt : InventSettleType::Issue, #initLedgerDrop ); // <GEERU> } // </GEERU> inventSettlement.SettleTransId = InventSettlement::nextSettleTransId(); inventSettlement.insertUsingInsertList(recordInsertList); // <GEERU> if (!countryRegion_RU || inventTransCurrency == InventTransCurrency_RU::PrimaryCur) { // </GEERU> inventTrans.QtySettled += inventTrans.financialOpenQty(); inventTrans.CostAmountSettled += inventTrans.financialOpenValue(); // <GEERU> } else { inventTrans.QtySettledSecCur_RU += inventTrans.financialOpenQtySecCur_RU(); inventTrans.CostAmountSettledSecCur_RU += inventTrans.financialOpenValueSecCur_RU(); } // </GEERU> this.updateCostAmountStd(inventTrans); inventTrans.update(); } recordInsertList.insertDatabase(); }
__________________
Sergey Nefedov |
|
|
За это сообщение автора поблагодарили: Sergey Petrov (1). |
10.11.2020, 16:03 | #3 |
Участник
|
Но это далеко не все артефакты вторичного закрытия в валюте, на одном приложении делал вот такие исправления в DAX2012 R3, думаю в AX2009 такая же беда
InventCostItemDim\updateReceiptAdjustmentTrans X++: while select forceplaceholders pessimisticlock #settlementFieldList from settlementReceipt index hint RecIdTypeIdx where settlementReceipt.TransRecId == _receipt.RecId && settlementReceipt.SettleType == InventSettleType::Receipt && settlementReceipt.InventTransId == _receipt.inventTransOrigin().InventTransId // <GEERU> && (!countryRegion_RU || settlementReceipt.InventTransCurrency_RU == inventTransCurrency) // </GEERU> && settlementReceipt.Cancelled == 0 && settlementReceipt.QtySettled > 0 join forupdate #settlementFieldList from settlementIssue index hint TransactionIdx where settlementIssue.SettleTransId == settlementReceipt.SettleTransId && settlementIssue.SettleType == InventSettleType::Issue //+ sn //// <GEERU> //&& (!countryRegion_RU || settlementReceipt.InventTransCurrency_RU == inventTransCurrency) //// </GEERU> && (!countryRegion_RU || settlementIssue.InventTransCurrency_RU == inventTransCurrency) //- sn && settlementIssue.Cancelled == 0 && settlementIssue.QtySettled < 0 X++: ... if (adjustment && (abs(adjustment) < inventClosing.MinTransferValue || (_receipt.CostAmountSecCurAdjustment_RU - _adjustmentLater == 0 && //+ sn // Currency::amount(_receipt.CostAmountSettledSecCur_RU / _receipt.QtySettled) == Currency::amount(costAmount / _receipt.QtySettled)))) Currency::amount(_receipt.CostAmountSettledSecCur_RU / _receipt.QtySettledSecCur_RU, secondaryCurrency) == Currency::amount(costAmount / _receipt.QtySettledSecCur_RU, secondaryCurrency)))) //- sn ... while select forceplaceholders pessimisticlock #settlementFieldList from settlementReceipt index hint RecIdTypeIdx where settlementReceipt.TransRecId == _receipt.RecId && settlementReceipt.SettleType == InventSettleType::Receipt && settlementReceipt.InventTransId == _receipt.inventTransOrigin().InventTransId && settlementReceipt.InventTransCurrency_RU == inventTransCurrency && settlementReceipt.Cancelled == 0 && settlementReceipt.QtySettled > 0 join forupdate #settlementFieldList from settlementIssue index hint TransactionIdx where settlementIssue.SettleTransId == settlementReceipt.SettleTransId && settlementIssue.SettleType == InventSettleType::Issue //+ sn //&& settlementReceipt.InventTransCurrency_RU == inventTransCurrency && settlementIssue.InventTransCurrency_RU == inventTransCurrency //- sn && settlementIssue.Cancelled == 0 && settlementIssue.QtySettled < 0 ... //+ sn //settleValue = Currency::amount(settleValueDec, secondaryCurrency); // //if (abs(settleValueDec) < abs(settleValue)) //{ // settleValue += (settleValueDec > 0 ? -roundOffunit : roundOffunit); //} if (abs(settleValueDec) > abs(roundOffunit)) { settleValue = Currency::amount(settleValueDec, secondaryCurrency); } else { settleValue = sign(settleValueDec) * roundOffunit; } //- sn X++: public void updateItemReturnAdjustments(ItemId _itemId = inventCostList.ItemId) { ... this.updateTransKeyAdjust(); //sn } X++: //+ sn //CostAmount costAmount = _inventTrans.isUpdatedFinancial() ? _inventTrans.financialOpenValueSecCur_RU() : _inventTrans.CostAmountSecCurPhysical_RU; CostAmount costAmount = _inventTrans.isUpdatedFinancial() && _inventTrans.DateFinancial <= inventClosing.TransDate ? _inventTrans.financialOpenValueSecCur_RU() : _inventTrans.CostAmountSecCurPhysical_RU; //-sn Но самым интересным квестом оказался следующий : 1. Если у вас используется две модели по средней(для первичного и для вторичного), то когда вы запускаете вторичное закрытие виртуальный перенос по средней созданный в рамках первичного закрытия становится Нефинансовым (рвётся маркировка между лотами) со всеми вытекающими последствиями. 2. В результате такой ошибки при начислении НР за прошлые периоды все проводки зависают на средней и не корректируют связанные расходы.
__________________
Sergey Nefedov |
|
10.11.2020, 17:36 | #4 |
Участник
|
Спасибо за помощь! Посмотрю ещё и в других местах. Вроде у нас проблемы только с указанными мной ранее, но мало ли...
__________________
MS Dynamics AX 2009 Kernel 5.0.1600.4110 Application 5.0.1500.6491 |
|
10.11.2020, 20:16 | #5 |
SAP
|
Странно, что автор (один из) сего чуда присутствует на форуме, но скромно молчит.))
|
|
10.11.2020, 23:36 | #6 |
Banned
|
Цитата:
и исчезают, пока осталось только это: https://docs.microsoft.com/en-us/dyn...n-capabilities Если вчитаться, то это лишь доработка нового Учета затрат в D365 до уровня старого в AX2012, и результат в бухгалтерские книги не попадает. |
|
10.11.2020, 23:48 | #7 |
Banned
|
P.S. Если поизучать сайт https://experience.dynamics.com/idea...4-000d3a4f1244 , то можно убедиться, что речь идет о третьем месте самых нужных функций для D365 в расчете себестоимости. В мире. Не в России. Причем Райнхард напрямую просит улучшить русскую фичу в том плане, чтобы было две и более модели для одной валюты, т.е. стандартная себестоимость в евро + средняя в евро. Так что стеб абсолютно неуместен.
|
|
11.11.2020, 15:56 | #8 |
Участник
|
Коллеги, а что бы вы могли посоветовать, если у нас такое замечено только на паре номенклатур с типом "Услуга"? Откатывать закрытие склада до начала времён не хочется. Может, есть какие-то точечные инструменты?
Вот подумали и решили для начала просто пересчёт запустить. По идее, если там ничего не работало, то накопленные недосопоставленные суммы должны раскидаться. В общем, пересчёт склада по отдельным позициям (причём, как во вторичной, так и в основной валютах) помог. Всё стало ровненько-красивенько.
__________________
MS Dynamics AX 2009 Kernel 5.0.1600.4110 Application 5.0.1500.6491 Последний раз редактировалось Sergey Petrov; 11.11.2020 в 17:04. |
|
|
|