25.02.2005, 15:05 | #21 |
Участник
|
Да, и еще вопрос: почему Минимальная коррекция пропускной способности, должна быть в 10 раз больше чем округление по валюте?
Вот где вопросик, так вопросик!!! |
|
25.02.2005, 19:01 | #22 |
Участник
|
Так. Все. Сам с собой разговариваю Тот кусок кода, который приведен мной выше, распределяет по расходу ту себестоимость, которую сделает процедура дооценки прихода. Поэтому то в ней приход больше и не корректируется! Вот она правда сермяжная! Принимаю ответственное решение - удалить эту процедуру, вырвать ее как гнилой зуб! Долой непонятные функциональности! Ура!
|
|
25.02.2005, 19:41 | #23 |
Участник
|
просто не успеваю.
на самом деле хочу попробовать повторить эффект на своей версии. кусок кода занятный. мдя.. |
|
26.02.2005, 13:16 | #24 |
Участник
|
Итак, что мы сделали: мы поставили "заглушку" в этой функции. Т.е. сделали так что она ничего не делает и при входе в нее сразу стоит return. Пересчитали склад. Вроде все ок!!! Теперь я буду много думать
|
|
26.02.2005, 18:59 | #25 |
Moderator
|
Во первых - зря ты эту функцию заблокировал. На второй и последующих итерациях закрытия она (вместе с cобственно функцией updateReceiptAdjustmentTrans) занимается передвижением стоимости по лотам. То есть - скажем скорректировали расход по приходу, а оказалось что это не просто расход - а перенос на соседний склад. И соответственно надо там приходную проводку тоже скорректировать (собственно - отсуюда и название метода). То есть - по большому счету -все итерации закрытия с номером >1 - это и есть выполнение этой функции до тех пор пока на очередной итерации сумма протаскиваемой по цепочке коррекции не станет меньше минимальной коррекции пропускной способности.
Еще для некоторого понимания хочется сказать что laterAdjustment - эта сумма коррекций сеебстоимости прихода, проведенных на дату ПОСЛЕ закрытия склада. Ну скажем - ты откорректировал на 15 января себестоимость прихода (скажем - накладные расходы по накладной доначислил). 20 января ты начал закрывать склад на 31 декабря. Так аксапта чтобы как говорится два раза не вставать еще и проведет твои коррекции от 15 января на проводки списания выполненные в декабре. Мне кажется что это архитектурный просчет. Правильнее было бы их списывать на прибыли и убытки. Но к твоемй случаю это не относится Теперь о несколько более более полезных для тебя вещах К тому времени когда эта функция на второй и последующих итерациях вызывается, себестоимость ПРИХОДНОЙ проводки уже скорректирована функцией updateTransIdReceipt. И собственно - данная функция пытается просчитать пропорцию, чтобы понять какую собственно долю коррекции себестоимости приходной проводки надо транзитом перекинуть на уже (возможно) сопоставленную с ней расходную... Делается это этой строкой: adjustment = Currency::amount((_receipt.costValue() - _adjustmentLater) / _receipt.qty * _receipt.qtySettled - _receipt.costAmountSettled); То есть - посчитали сумму коррекции на одну единицу товара и помножили на количество сопоставленных единиц товара, после чего отняли от результата общую сумму сопоставленной с расходом стоимости прихода. Только вот как мне кажется отнимать уже заведомо округленную _receipt.costAmounSettled (сопоставленную сумму прихода) от неокругленной второй половины выражения - в корне не верно. Мне на одном из моих бывших проектов помогла следующая корректировка этого куска кода: adjustment = Currency::amount((_receipt.costValue() - _adjustmentLater) / _receipt.qty * _receipt.qtySettled) - _receipt.costAmountSettled; То есть - прежде чем вычитать из рассчитанной суммы уже округленную сумму сопоставления данного прихода с расходом - стоит эту рассчитанную сумму тоже округлить. В противном случае - копейка будет гулять бесконечно.... |
|
27.02.2005, 16:08 | #26 |
Участник
|
Вобщем-то понятно. Но, меня больше всего интересует вызов функции: CreateErrorAdjustment.
Я буду говорить не как програмист (вобщем-то я и не програмист : эта функция корректирует проводки ЗАКРЫТОГО периода, и соответственно, на основании этих проводок в ИнвентТранс делаются и проводки в ГК! Но клиента такой расклад не устраивает, клиент хочет закрыв период больше не думать о нем! К тому же за 2004 год выверен склад (складская стоимость соответствует бухгалтерской), а теперь этот CreateErrorAdjustment, начинает делать складские проводки, естественно 2004 годом, а бухгалтерские проводки идут уже естественно 2005 годом. Как потом разбиратся? Как сводить бухгалтерию и склад за 2005 год? Что делать с получившимся разрывом за 2004 год. При всем притом что это просто не допустимо! Вы ощущаете проблему? ЗЫ: И конечно респект и благодарность за ОЧЕНЬ полезную информацию. |
|
27.02.2005, 18:23 | #27 |
Moderator
|
А скажи пожалуйста - откуда вызывается этот самый createErrorAdjustment ?
То есть - буквально - ткни в тот кусок кода который приводит к ее вызову... Может я чего и подскажу. Но вообще-то - судя по симптомам - код вызывается из той же процедуры updateReceiptAdjustmentTrans. Сразу после процитированного мною куска кода, вычисляющего сумму коррекции себестоимости (который и я посоветовал править) там есть код который вызывает твой createErrorAdjustment: if (! this.financialOpenQty(_receipt)) // Fix HQ-307-902-qc72 Error adjustment must only be done when the transaction is completely settled this.createErrorAdjustment(_receipt,-adjustment); Собственно - смысл этого куска состоит в том что если у нас коррекция себестоимости добралась до полностью сопоставленного и закрытого прихода - то дальше по цепочке товародвижения эту коррекцию себестоимости тащить не надо, достаточно просто скорректировать себестоимость прихода. Кстати - метод createErrorAdjustment используется еще и для того чтобы куда-нибудь "пристроить" сумму коррекции, если на очередной итерации оказалось что сумма коррекции меньше минимальной пропускной способности. Так вот я и говорю о том, что по моему зря ты беспокоишься по поводу метода createErrorAdjustment. Проблема не в нем, а в том куске кода, который пытается рассчитать сумму коррекции и который я тебе предложил подправить. P.S. Кстати - посмотри - по моему if перед вызовом createErrorAdjustment появился только в SP3 и у тебя его нету. Можно его вставить, хотя эта проверка, как мне кажется, борется не с твоей проблеммой, а с совсем другой |
|
28.02.2005, 11:44 | #28 |
Участник
|
Отвечаю где у меня вызывается createErrorAdjustment. Вот весь метод:
<div class='XPPtop'>X++</div><div class='XPP'> [color=:blue]protected[/color] [color=:blue]void[/color] updateReceiptAdjustmentTrans( InventTrans _receipt, CostAmount _adjustmentLater ) { InventSettlement settlementReceipt; InventSettlement settlementIssue; InventTrans issue; CostAmount allocateValue; InventQty allocateQty; CostAmount settleValue; CostAmount settleValueDec; CostAmount adjustment; CostAmount errorAmount; ; [color=:blue]if[/color] (this.inventModelGroup(inventCostList.ItemId).standardCost) { adjustment = Currency::amount(_receipt.costAmountStd) - Currency::amount(_receipt.costValue()); [color=:blue]if[/color] (adjustment != 0) _receipt.updateStdCostAdjust(adjustment,inventClosing.transDate,inventClosing.voucher,_receipt.dimensionF inancial()); } [color=:blue]if[/color] (_receipt.qty != 0 && _receipt.qtySettled > 0) { adjustment = Currency::amount((_receipt.costValue() - _adjustmentLater) / _receipt.qty * _receipt.qtySettled - _receipt.costAmountSettled); [color=:blue]if[/color] (adjustment && abs(adjustment) < inventClosing.MinTransferValue) { this.createErrorAdjustment(_receipt,-adjustment); adjustment = 0; } allocateQty = _receipt.qtySettled; allocateValue = adjustment; [color=:blue]if[/color] (allocateValue != 0) { [color=:blue]while[/color] [color=:blue]select[/color] forcePlaceholders [color=:blue]forceSelectOrder[/color] [color=:blue]forceNestedloop[/color] [color=:blue]forupdate[/color] #settlementFieldList [color=:blue]from[/color] settlementReceipt [color=:blue]index[/color] hint RecIdTypeIdx [color=:blue]where[/color] settlementReceipt.transRecId [color=:blue]==[/color] _receipt.recId && settlementReceipt.settleType [color=:blue]==[/color] InventSettleType::Receipt && settlementReceipt.inventTransId [color=:blue]==[/color] _receipt.inventTransId && settlementReceipt.InventTransCurrency_RU [color=:blue]==[/color] inventTransCurrency && settlementReceipt.cancelled [color=:blue]==[/color] 0 && settlementReceipt.qtySettled > 0 join [color=:blue]forupdate[/color] [color=:blue]firstOnly[/color] #settlementFieldList [color=:blue]from[/color] settlementIssue [color=:blue]index[/color] hint TransactionIdx [color=:blue]where[/color] settlementIssue.settleTransId [color=:blue]==[/color] settlementReceipt.settleTransId && settlementIssue.settleType [color=:blue]==[/color] InventSettleType::Issue && settlementReceipt.InventTransCurrency_RU [color=:blue]==[/color] inventTransCurrency && settlementIssue.cancelled [color=:blue]==[/color] 0 && settlementIssue.QtySettled < 0 { settleValueDec = settlementReceipt.qtySettled * adjustment / _receipt.qtySettled; settleValue = Currency::amount(settleValueDec); [color=:blue]if[/color] (abs(settleValueDec) < abs(settleValue)) settleValue += (settleValueDec > 0 [color=:blue]?[/color] -roundOffUnit : roundOffUnit); settleValue = abs(settleValue) > abs(allocateValue) [color=:blue]?[/color] allocateValue: settleValue; allocateQty -= settlementReceipt.qtySettled; allocateValue -= settleValue; [color=:blue]if[/color] (settleValue != 0) { [color=:blue]if[/color] (mapInventTrans && mapInventTrans.[color=:blue]exists[/color](settlementIssue.TransRecId)) issue = mapInventTrans.lookup(settlementIssue.TransRecId); [color=:blue]else[/color] issue = settlementIssue.inventTrans([color=:blue]true[/color]); [color=:blue]if[/color] (! issue.recId) { this.createErrorAdjustment(_receipt,-settleValue); } [color=:blue]else[/color] { [color=:blue]if[/color] (issue.costValue() - settleValue > 0) { errorAmount = issue.costValue() - settleValue; this.createErrorAdjustment(_receipt,errorAmount); settleValue -= errorAmount; } _receipt.costAmountSettled += settleValue; issue.costAmountSettled -= settleValue; issue.costAmountAdjustment -= settleValue; this.updateInventTrans(issue); [color=:blue]if[/color] (settlementReceipt.transDate [color=:blue]==[/color] inventClosing.transDate && settlementReceipt.voucher [color=:blue]==[/color] inventClosing.voucher) { settlementReceipt.costAmountSettled += settleValue; settlementReceipt.update(); settlementIssue.costAmountSettled -= settleValue; settlementIssue.costAmountAdjustment -= settleValue; settlementIssue.update(); } [color=:blue]else[/color] { this.updateSettlementReceipt(settlementReceipt,settleValue); this.updateSettlementIssue(settlementIssue,settleValue); } this.updateTrans(issue,-settleValue); } } [color=:blue]if[/color] (allocateQty [color=:blue]==[/color] 0) { [color=:blue]break[/color]; } } this.updateInventTrans(_receipt); [color=:blue]if[/color] (allocateValue != 0) this.createErrorAdjustment(_receipt,-allocateValue); } } [color=:blue]return[/color]; }</div> Так вот, в мною приведенном примере (см. приложение) в строчке: <div class='XPPtop'>X++</div><div class='XPP'> adjustment = Currency::amount((_receipt.costValue() - _adjustmentLater) / _receipt.qty * _receipt.qtySettled - _receipt.costAmountSettled);</div> расчитывается то самое: (1009,33/101)*39 - 389,7=0,04 и если вы заметили, то перестановка скобок (то что вы советовали), недает здесь эффекта. Потом процедура заходит в цикл и начинает вычислять ошибку по каждому сопоставлению: <div class='XPPtop'>X++</div><div class='XPP'> settleValueDec = settlementReceipt.qtySettled * adjustment / _receipt.qtySettled; settleValue = Currency::amount(settleValueDec);</div> а так как ошибка каждый раз меньше 0.005 то в этом куске: <div class='XPPtop'>X++</div><div class='XPP'> allocateQty -= settlementReceipt.qtySettled; allocateValue -= settleValue;</div> переменная allocateValue уменьшается каждый раз на 0. Т.е. учитываю что: <div class='XPPtop'>X++</div><div class='XPP'> allocateValue = adjustment;</div> она остается равной 0,04. Затем, при выходе из цикла мы видим последник строчки: <div class='XPPtop'>X++</div><div class='XPP'> [color=:blue]if[/color] (allocateValue != 0) this.createErrorAdjustment(_receipt,-allocateValue);</div> таким вот образом этот метод и делает корректировку прихода на 0,04 копейки!!! Появилась мысль: после закрытия склада, расщеплять проводки прихода, таким образом чтобы в новой проводке получившейся количество было равно сопоставленному количеству, а сумма равнялась сопоставленной сумме! Естественно что в другой проводке от соответствующих количеств и сумм, отнимать суммы и количества новой. Ну, чтобы общие суммы оставались правильными. Ну вобщем вы поняли, для того чтобы получилась одна закрытая проводка и одна открытая, и естественно в закрытой выставим ValueOpen=0 и дату закрытия Голова кипит. Как вы смотрите на такую идею? |
|
28.02.2005, 16:39 | #29 |
Moderator
|
В принципе - можно попробовать.
Только какую дату ты будешь ставить в расщепленную проводку ? И будет ли по ней запись в inventTransPosting ? Кстати - я не очень понял - чем тебя вообще напрягает нынешнее поведение ? Ведь запись в inventSettlement которая себестоимость корректирует делается не прошедшим периодом, а текущим. Собирать складские обороты только по InventTrans без учета inventSettlement методологически неверно... И мне кажется что проблема вообще не решается без изменения идеологии закрытия. ну скажем - можно было бы в inventTrans хранить не только сумму и сумму коррекции, но и себестоимость единицы - причем с максимальной точностью - без округления до копеек. Тогда проблема бы не выростала вообще, поскольку погрешности не случалось бы. Но это довольно серьезного перелопачивания всей логистики потребует... В общем - я еще не закончил думать, но чтобы решить проблеу в общем - явно не хватает дополнительных полей в inventTrans, которые хранили бы всяческие суммы в неокругленном виде... |
|
28.02.2005, 17:16 | #30 |
Участник
|
Цитата:
Сообщение от fed
Собирать складские обороты только по InventTrans без учета inventSettlement методологически неверно...
... явно не хватает дополнительных полей в inventTrans, которые хранили бы всяческие суммы в неокругленном виде... А что думаешь насчет inventTrans.CostAmountAdjustment. Ведь там автоматом собирается сумма всех коррекций. Я понимаю насчет вмешательства программистом... Но при целостной базе ведь можно и им пользоваться. Или у тебя есть какие-то соображения? Насчет округления. Нет, любой компьютер хранит только округленные значения. Всегда. В Аксапте сделана попытка управлять процессом округления. |
|
28.02.2005, 17:19 | #31 |
Участник
|
Цитата:
Сообщение от fed
Только какую дату ты будешь ставить в расщепленную проводку ?
И будет ли по ней запись в inventTransPosting ? А inventTransPosting, я не знаю надо ли расщеплять. Насколько я знаю он коннектится с ИнвентТрансом, номером лота, итемйди, ну может еще датой... ваучером... не знаю точно. Но эти все параметры будут у расщепленных проводок одинаковы. Я воспользуюсь стандартным "Проводки\Функции\Разьиение", только сумму буду разбивать не пропорционально, а согласно сопоставленной сумме. И насчет "Собирать складские обороты только по InventTrans без учета inventSettlement методологически неверно...", раз уж заикнулись, можно ознакомить с методологией? Она одна на всех? Для любого клиента? Универсальная? |
|
28.02.2005, 17:29 | #32 |
Участник
|
MAZZY, не могли бы вы оценить со своей колокольни идею о расщеплении приходных проводок? Скажу заранее: идея работает (проверял), но последствия идеи пока мною не продуманы.
|
|
28.02.2005, 17:33 | #33 |
Участник
|
Цитата:
Сообщение от slava09
MAZZY, не могли бы вы...
Проверять надо. Вся беда в том, что сейчас времени нет. А задача безумно интересная. |
|
28.02.2005, 19:24 | #34 |
Moderator
|
насчет расщепления - еще подумаю Честно говоря - когда писал предыдущее письмо - не вполне осознал смысл твоего предложения.
Теперь немножко об идеологии: Надо понимать что понятие ЗАКРЫТИЯ относится только к закрытию по количеству. Ну то есть проводка считается закрытой и на ней ставится dateClosed в тот момент когда по ней полностью сопоставилось КОЛИЧЕСТВО. С точки зрения аксапты допустимой считается ситуация когда производится коррекция себестоимости (ну скажем доначисление или наоборот сторно накладных расходов по накладной) уже по закрытой проводке. Поэтому для того чтобы посчитать сальдо по проводке на некую дату, надо взять costAmountPosted и посчитать сумму коррекций по проводке (в inventSettlement) на эту дату. Кстати - начиная кажется с sp3 в MBS исправили ошибку в оборотке по складу, которая как раз раньше не использовала inventSettlement и считала себестоимость на дату просто как сумму costAmountPosted и costAmountAdjustment. to mazzy - насчет точности и округления - тоже надо думать... Я пока не вижу универсального способа решения в нынешней идеологии. Расщепление проводок при закрытии кажется достаточно интересным - но тоже надо думать сначала. И еще - я совершенно не понял - почему закрытая проводка ВООБЩЕ попала на вход процедуры updateReceiptAdjustment. Скажите мне пожалуйста - она в эту процедуру попала из метода run (то есть на второй и последующих итерациях закрытия) или из метода updateItemDim ? (то есть как раз на первой итерации закрытия) |
|
01.03.2005, 17:10 | #35 |
Участник
|
Цитата:
Сообщение от fed
И еще - я совершенно не понял - почему закрытая проводка ВООБЩЕ попала на вход процедуры updateReceiptAdjustment.
А как вы смотрите, на то чтобы вызывать updateReceiptAdjustmentTrans если текущий номер итерации>0 ??? |
|
01.03.2005, 18:02 | #36 |
Moderator
|
[quote=slava09]
Цитата:
Сообщение от fed
И
А как вы смотрите, на то чтобы вызывать updateReceiptAdjustmentTrans если текущий номер итерации>0 ??? Как я понимаю - вызов updateReceiptAdjustment из метода updateItemDim нужен только для того чтобы в момент закрытия распределить на расходы, связанные с данным приходом later Adjustments (то есть корректировки сеебстоимости прихода сделанные датой ПОСЛЕ закрытия склада). Поскольку данный подход, IMHO, просто бредовый (события в полседующем отчетном периоде проводят к проводкам в предыдущем), то на мой взгляд так и нужно делать... Хотя я бы тогда проверил - будут ли подобные корректировки отрабатывать при следующих закрытиях. ТО есть - закооментировал бы вызов из updateItemDim, сделал бы скажем проводку в декабре, доначислил накладные январем, списал бы январем, потом закрыл бы декабрь и январь. А после этого посморел бы - попали январские накладные расходы в корректировки себестоимости расхода в декабрьском закрытии и январском закрытии. Я правда совсем не понимаю как будет эта схема отрабатывать если у нас и приход и расход были в декабре, а корректировка себестоимости прихода прошла январем. Но по моему такая схема учета заведомо бредовая. Опоздавший накладняк надо на прибыли и убытки списывать, а не в себестоимость включать. Кстати - схема с расщеплением проводок мне тоже нравится. Можно ее тоже попробовать. Тем более такой подход используется при сопоставлении макрированных проводок в методе updateSettleRefItem |
|
01.03.2005, 18:21 | #37 |
Участник
|
Расщепление я протестировал - работает. И вроде видимых проблем нет. Кстати идея не моя, а программиста который помогал рыть код Ему респект и благодарность!
Насчет вызова при итерации > 0, завтра сделаем и потестирую (эта идея моя . |
|
02.03.2005, 16:06 | #38 |
Участник
|
Цитата:
Сообщение от fed
Нормально смотрю. Я как раз хотел предложить это попробовать.
|
|
02.03.2005, 18:07 | #39 |
Moderator
|
В inventCostItemDim::updateItemDim надо попробовать просто закомментировать вызов updateReceiptAdjustment.
|
|
02.03.2005, 18:15 | #40 |
Участник
|
Цитата:
Сообщение от fed
В inventCostItemDim::updateItemDim надо попробовать просто закомментировать вызов updateReceiptAdjustment.
<div class='XPPtop'>X++</div><div class='XPP'> [color=:blue]if[/color] (inventCostList.NumOfIteration > 0) this.updateReceiptAdjustment();</div> прокатит? |
|