19.08.2009, 21:16 | #1 |
Участник
|
DAX4 Интеркомпани, ошибка разноски внутрихолдинговой накладной
Для информации, может быть кому понадобится.
Совместно с rINT обнаружили ошибку расчета количества при разноске внутрихолдинговой накладной. При разноске накладной по внутрихолдинговому заказу на продажу автоматически разносится накладная по внутрихолдинговому заказу на покупку. При этом определяется количество, которое нужно разносить. В классе SalesFormLetter в методе createParmLine есть следующий код: X++: [newSalesParmLine.DeliverNow, newSalesParmLine.RemainBefore , newSalesParmLine.RemainAfter] = this.qtySales (_salesLineOrig, this.interCompanyParmLineQty(_salesLineOrig)); [newSalesParmLine.InventNow , newSalesParmLine.RemainBeforeInvent, newSalesParmLine.RemainAfterInvent] = this.qtyInvent (_salesLineOrig, this.interCompanyParmLineQty(_salesLineOrig)); Решение проблемы: для второго вызова interCompanyParmLineQty результат необходимо пересчитать в складские единицы. |
|
|
За это сообщение автора поблагодарили: kashperuk (5). |
20.08.2009, 10:23 | #2 |
Участник
|
Есть такое дело. Тоже исправлял. Вообще в Intercompany я много косяков в свое время нарыл. Такое ощущение, что эту функциональность плохо тестировали.
|
|
21.08.2009, 13:04 | #3 |
Участник
|
Raven, а расскажите плз, как именно вы исправляли эту ошибку. Передачей true при втором вызове метода interCompanyParmLineQty?
И, если будет время, было бы здорово привести сценарий, с помощью которого можно воспроизвести это поведение в стандартном функционале. Спасибо Последний раз редактировалось kashperuk; 21.08.2009 в 13:07. |
|
|
За это сообщение автора поблагодарили: Raven Melancholic (4). |
21.08.2009, 15:08 | #4 |
Участник
|
Лично я исправлял как Вы сказали:
Цитата:
Передачей true при втором вызове метода interCompanyParmLineQty
создать цепочку заказов (внутрихолд заказ продажи - внутрихолд заказ покупки - исходный заказ) типа прямая поставка. И разнести ее. |
|
|
За это сообщение автора поблагодарили: Raven Melancholic (2). |
21.08.2009, 15:33 | #5 |
Участник
|
Тогда уже исправили. Спасибо
|
|
|
За это сообщение автора поблагодарили: mazzy (2). |
21.08.2009, 17:17 | #6 |
Участник
|
Ну тогда, позвольте я еще про одну ошибку изложу. Скажу сразу, что толком не помню как ее воспроизвести (давненько это было). Кроется она в классе IntercompanyTransferInventDim метод transfer:
X++: ... while (qr.next()) { fromInventTrans = qr.get(tablenum(InventTrans)); fromInventDim = qr.get(tablenum(InventDim)); ... fromQty = -fromInventTrans.Qty; if (inventDimParm.InventLocationIdFlag && fromInventDim.InventLocationId) { convInventLocation = new TradeInterCompanyConv(); salesInventLocationId = fromInventDim.InventLocationId; convInventLocation.axInventLocationId(fromValueMap, fromInventDim.InventLocationId); } ... changecompany(_toDataAreaId) { toInventTrans = null; select forceplaceholders sum(Qty) from toInventTrans where toInventTrans.InventTransId == _toInventTransId && (toInventTrans.StatusReceipt <= StatusReceipt::Registered || toInventTrans.InterCompanyInventDimTransferred == true) && toInventTrans.StatusIssue == StatusIssue::None #inventDimJoin(toInventTrans.InventDimId,toInventDim,fromInventDim,inventDimParm); fromQty -= toInventTrans.Qty; .... P.S.: надеюсь понятно пояснил, как-то сумбурно получилось, млин |
|
21.08.2009, 17:20 | #7 |
Участник
|
Забыл добавить: DAX 4.0 SP2
|
|
21.08.2009, 20:53 | #8 |
Участник
|
Ошибка проявляется в именно так, как описал JeS.
Ой, насчет: Цитата:
Кроется она в классе IntercompanyTransferInventDim метод transfer
Он неправильно отрабатывает в случаях, когда были кредит-ноты по строке, лечилось добавлением в выборки (те, которые зависят от того, какие аналитики включены) условий (то, что выделено комментариями): Код: select forceplaceholders sum(Qty) from fromInventTrans where fromInventTrans.InventTransId == _fromInventTransId && fromInventTrans.StatusIssue <= _statusIssue && fromInventTrans.StatusReceipt == StatusReceipt::None // ААК: МФД40_09_01_0013_001 11.07.2009 [Сторнирование и копирование документов] --> && fromInventTrans.InvoiceReturned == NoYes::No && fromInventTrans.PackingSlipReturned == NoYes::No // ААК: МФД40_09_01_0013_001 11.07.2009 [Сторнирование и копирование документов] <-- join InventLocationId, InventBatchId, InventSerialId, InventGtdId_RU from fromInventDim group by InventLocationId, InventBatchId, InventSerialId, InventGtdId_RU where fromInventDim.InventDimId == fromInventTrans.InventDimId; X++: select forupdate toInventTrans index hint TransIdIdx where toInventTrans.InventTransId == _toInventTransId && toInventTrans.StatusReceipt == StatusReceipt::Ordered && toInventTrans.StatusIssue == StatusIssue::None && toInventTrans.InterCompanyInventDimTransferred == false; Для воспроизведения этой ошибки нужно чтобы проводки по лоту были расщеплены как со стороны заказа на продажу, так и со стороны заказа на покупку. Причем, иногда везет и комплектуются те записи, по которым установили флаг, но везение не всегда случается. Эту проблему решили, но грубо (стояли отгрузки, поэтому было не до изящности): вместо X++: inventTransUpd.InterCompanyInventDimTransferred = true; X++: //lex 24.04.2009 при регистрации могла выбраться еще необработанная проводка и на пересечении...--> if (!_registerReceipt) { inventTransUpd.InterCompanyInventDimTransferred = true; } //lex 24.04.2009 при регистрации могла выбраться еще необработанная проводка и на пересечении...<-- X++: //lex 24.04.2009 при регистрации могла выбраться еще необработанная проводка и на пересечении...--> update_recordset refInventTrans setting InterCompanyInventDimTransferred = true where refInventTrans.InventTransId == inventTransUpd.InventTransId && refInventTrans.StatusReceipt == StatusReceipt::Registered && !refInventTrans.InterCompanyInventDimTransferred; //lex 24.04.2009 при регистрации могла выбраться еще необработанная проводка и на пересечении...<-- |
|
|
За это сообщение автора поблагодарили: JeS (1). |
21.08.2009, 21:18 | #9 |
Участник
|
Еще один недостаток этого метода. Бывает, что в компании, в которой производится продажа конечному клиенту, требуются данные не только номера партии, а и то, что есть в таблице партий (например, дата производства, если существует контроль и предоставление клиенту информации о сроках годности), тоже может требоваться по серийным номерам и, естественно, нужна страна по ГТД. Однако, в методе создаются записи только с номером:
X++: if (!InventBatch::exist(toInventTrans.ItemId,inventDimUpd.InventBatchId))
{
inventBatch.clear();
inventBatch.ItemId = toInventTrans.ItemId;
inventBatch.InventBatchId = inventDimUpd.InventBatchId;
inventBatch.insert();
} X++: while (fromInventTrans) { // ААК: МФД40_08_01_0003 19.03.2009 [Планирование сделок] --> inventBatchFrom = null; if (fromInventDim.inventBatchId) { inventBatchFrom = InventBatch::find(fromInventDim.inventBatchId, itemIdFrom); } ... X++: if (!InventBatch::exist(toInventTrans.ItemId,inventDimUpd.InventBatchId)) { inventBatch.clear(); inventBatch.ItemId = toInventTrans.ItemId; inventBatch.InventBatchId = inventDimUpd.InventBatchId; // ААК: МФД40_08_01_0003 19.03.2009 [Планирование сделок] --> inventBatch.initFromInventBatch_OVK(inventBatchFrom); // ААК: МФД40_08_01_0003 19.03.2009 [Планирование сделок] <-- inventBatch.insert(); } |
|
21.08.2009, 21:30 | #10 |
Участник
|
Цитата:
Поэтому лучше получить данные методом interCompanyParmLineQty для единиц закупки/продажи и приводить к складским уже в компании-покупателе. |
|
24.08.2009, 10:11 | #11 |
Участник
|
В предыдущем сообщении, где приводил пример кода, я допустил ошибку. Исправляюсь. Код в базовой функциональности должен выглядеть так:
X++: while (fromInventTrans) { ... fromQty = -fromInventTrans.Qty; if (inventDimParm.InventLocationIdFlag && fromInventDim.InventLocationId) { convInventLocation = new TradeInterCompanyConv(); salesInventLocationId = fromInventDim.InventLocationId; convInventLocation.axInventLocationId(fromValueMap, fromInventDim.InventLocationId); } ... changecompany(_toDataAreaId) { toInventTrans = null; select forceplaceholders sum(Qty) from toInventTrans where toInventTrans.InventTransId == _toInventTransId && (toInventTrans.StatusReceipt <= StatusReceipt::Registered || toInventTrans.InterCompanyInventDimTransferred == true) && toInventTrans.StatusIssue == StatusIssue::None #inventDimJoin(toInventTrans.InventDimId,toInventDim,fromInventDim,inventDimParm); fromQty -= toInventTrans.Qty; .... Кстати непонятно зачем нужно было писать такую "этажерку" в этом методе до вышеописанного цикла: X++: if (inventDimParm.InventLocationIdFlag && inventDimParm.InventBatchIdFlag && inventDimParm.InventSerialIdFlag) { select forceplaceholders sum(Qty) from fromInventTrans where fromInventTrans.InventTransId == _fromInventTransId && fromInventTrans.StatusIssue <= _statusIssue && fromInventTrans.StatusReceipt == StatusReceipt::None join InventLocationId, InventBatchId, InventSerialId from fromInventDim group by InventLocationId, InventBatchId, InventSerialId where fromInventDim.InventDimId == fromInventTrans.InventDimId; } else if (inventDimParm.InventLocationIdFlag && inventDimParm.InventBatchIdFlag) { select forceplaceholders sum(Qty) from fromInventTrans where fromInventTrans.InventTransId == _fromInventTransId && fromInventTrans.StatusIssue <= _statusIssue && fromInventTrans.StatusReceipt == StatusReceipt::None join InventLocationId, InventBatchId from fromInventDim group by InventLocationId, InventBatchId where fromInventDim.InventDimId == fromInventTrans.InventDimId; } else if (inventDimParm.InventLocationIdFlag && inventDimParm.InventSerialIdFlag) { ... |
|
24.08.2009, 10:20 | #12 |
Участник
|
to Raven
Цитата:
К сожалению это не одна ошибка в этом методе
Цитата:
даже если отбросить тот факт, что про ГТД в этом методе ничего нет
|
|
29.08.2009, 21:08 | #13 |
Участник
|
Еще наткнулись. Ка-то странно работает кэш (я про это уже писал, но тогда было только тестирование и как-то не зациклились на этой теме).
У нас в разных компаниях номенклатура ведет себя по разному (например, в производственной это спецификация с номенклатурной группой "Готовая продукция", в торговых домах это номенклатура с номенклатурной группой Товар, ну и т.п.). Поэтому справочник не общий, а в каждой компании свой (есть доработка по вводу и синхронизации определенных номенклатур, но суть не в этом). Так вот, простой код джоба: X++: itemId = 'ВентиляторWRW50/40'; intentTable = InventTable::find(itemId); changeCompany('TRD') { inventTableChg = null; select firstOnly inventTableChg where inventTableChg == itemId; ... } То же происходит если в разных компаниях номера складских лотов совпадают. Если после переключения компании искать складские операции по номеру лота, совпадающему с тем, что был выполнен ранее, то вернется ранее найденный лот. Помогает включения в код запрет кэша: X++: itemId = 'ВентиляторWRW50/40'; intentTable = InventTable::find(itemId); changeCompany('TRD') { inventTableChg = null; inventTableChg.disableCash(true); select firstOnly inventTableChg where inventTableChg == itemId; ... } Такое впечатление, то кэш игнорирует компании. вобщем-то можно было бы отключить кэш DAX для всех таблиц (кэш MS SQL хорошо справляется со своей работой), но InventTrans не кэшируется DAX! Так же понятно, что из-за этой проблемы следует стараться иметь для одних и тех же таблиц в разных компаниях разные уникальные идентификаторы. Но, в нашем случае, это возможно для InventTrans, но не интересно для InvntTable. Можно всегда добавлять disableCach, но в наших разработках мы так и делаем, но есть стандартный код! PS: кстати, без использования disableCash Trasert MS SQL показывает, что к базе данных было только оно обращение, то есть цепочка: поиск в одной компании, changeCompany, поиск в другой компании того же значения обрабатывает DAx независимо от типа кэширования. Последний раз редактировалось Raven Melancholic; 29.08.2009 в 21:16. |
|
|
За это сообщение автора поблагодарили: JeS (1), Kabardian (3). |
29.08.2009, 21:30 | #14 |
Участник
|
Еще один момент. Правда это не ошибка, но непонятка.
В SalesLine и PurchLine для механизма Интеркомпани есть поле InterCompanyInventTransId по которому связаны строки заказа на покупки и заказа на продажу Интеркомпани. Но в классах, наследниках от TradeInterCompany поиск связанной строки почему-то происходит не по этим лотам, а по номерам строк. Я, конечно, понимаю, что индекс, включающий номер строки является кластерным и когда требуется получить все данные строки он работает быстро (тем более, что в интерфейсе поле LineNum не представлено, а в методах InteCompanyMirror оно синхронизируется). Но, все-таки, во всех остальных местах связь идет по полю InterCompanyInventTransId, к тому же, индекс, включающий LineNumне уникальный, что позволяет при работе не из интерфейса, а из кода дублировать номера строк (кстати, в стандартном приложении бывает, что номер строки несколько раз бывает нулевым, правда это относится не к заказам на покупку-продажу, а складским журналам и журналам ГК). Почему для классов, наследников TradeInterCompany сделано исключение из общего правила? |
|