В завершение темы про ошибки в средней себестоимости:
Вот как работает рассчет средней себестоимость в западном приложении:
1. Для каждого закрываемого периода система создает фиктивный перенос. (Все последующие рассуждения относятся к модели "Средняя за период". В модели "Средняя на дату" система фактически разбивает месяц по датам каждого прихода и периоды между приходами трактует как отдельный период в модели "Средняя за период").
2. Система суммирует все приходы открытые на начало прихода и все приходы за период и присваивает рассчитанную себестоимость и количество в проводки фиктивного переноса.
3. Все расходы периода сопоставляются с приходной проводкой по фиктивному переносу, все приходы периода (и незакрытые приходы на начало периода) сопоставляются с расходной проводкой по переносу.
4. Система имеет специальный режим восстановления после сбоев. Если при обработке периода был найден уже существующий фиктивный перенос с нужной датой, система просто повторно использует его, не меняя суммы и количества.
5. Если закрытие склада отменяется, система удаляет все фиктивные переносы периода и все связанные с ними складские сопоставления и корректировки стоимости.
Если приглядется на код локализованного метода InventCostClosingCancel_WorkInvent.deleteVirtualTransfers() (или InventCostClosingCancel_End.deleteVirtualTransfers() - в зависимости от версии rollup), то можно найти следующий замечательный код:
X++:
while select forupdate inventTrans order by InventTransId
where inventTrans.ValueOpen == InventTransOpen::Yes
&& inventTrans.ValueOpenSecCur_RU == InventTransOpen::Yes
&& inventTrans.Voucher == cancelClosing.Voucher
&& inventTrans.TransType == InventTransType::SummedUp
Если у вас разрешена российская функциональность, но запрещен двухвалютный склад (а учитывая его качество - он у 95% пользователей запрещен), то условие inventTrans.ValueOpenSecCur_RU == InventTransOpen::Yes вернет false и никакие записи не будут обработаны (и, соответственно, никакие фиктивные переносы не будут удалены). Дальше - интереснее. Если вы закрыли склад, потом отменили закрытие, запостили парочку новых приходов и расходов, то следующее закрытие, наткнувшись на болтающиеся старые фиктивные переносы, с радостью примет их за результаты сбойного закрытия и попытается повторно их использовать. Правда, поскольку закрытие ничего плохого не подозревает, оно не поменяет стоимость и количество в этих переносах. А потом не проверяя, сопоставит со всеми приходами и расходами. В результате у фиктивного переноса может получиться пересопоставление - типа в qty стоит 100 штук, а в qtySettled - 120. Ну и конечно вся себестоимость едет и накрывается медным тазом...
Рекомендую поменять указанный выше код на что-нибудь типа
X++:
while select forupdate inventTrans order by InventTransId
where inventTrans.ValueOpen == InventTransOpen::Yes
&& (!isconfigurationKeyEnabled( configurationkeynum(InventClosingSecCur_RU)) || inventTrans.ValueOpenSecCur_RU == InventTransOpen::Yes)
&& inventTrans.Voucher == cancelClosing.Voucher
&& inventTrans.TransType == InventTransType::SummedUp
Еще очень рекомендую сначала попробовать предложенные мною и участником Bega правки на тестовой базе и потом пару месяцев попробовать позакрывать склад и посмотреть за результатами. А то один мой польский клиент сначала исправил ошибку, а потом, когда новые закрытия стали налетать на изуродованные складские проводки старых закрытий, получил не мало проблем...