15.05.2012, 12:47 | #1 |
Участник
|
Программный ввод складских остатков
День добрый!
благодаря желанию пользователей, которые хотят что-то проанализировать, вышла следующая задача, которая коротко выглядит следующим образом: поиграться с различными исходами планирования в результате различных складских остатков. Естественно это на отдельной компании, поэтому можно ломать всё что угодно, лишь бы master planning правильно считал и видел новые остатки. Версия 2009 Итак, складские остатки при работе пользователей как я понимаю, вводятся следующим образом: 1) создаётся журнал с типом "Проводка" 2) создаются и заполняются строки в этом журнале 3) журнал разносится 4) остатки пересчитываются автоматически Вопрос: как это реализовать программно? Пусть на входе будет таблица типа, в которой будет наименование и код журнала, код номенклатуры, количество, дата, номенклатурные аналитики, вообще всё вобщем, что потребуется для ввода. То есть данные на входе для ввода остатков именно таким образом есть. Вопрос в том, с какими классами будет правильнее работать и с таблицами ли, так, чтобы избежать подводных камней. (функционал не изменён, чистый стандарт допустим) Поправьте меня. если я что-то неправильно понял: журнал находится в таблице InventJournalTable, создать можно классом AxInventJournalTable. Сами строки журнала находятся где-то в InventJournalTrans, работать с ней проще через AxInventJournalTrans. А как дальше разнести всё это добро?) Как пересчитать остатки или при разноске это происходит автоматически? Всё это ооочень интересная тема Заранее спасибо p,s. интересно, что будет если вводить также строки с минусовым количеством, для анализа ситуации, когда "о боже, у нас же на складе на 1 штуку меньше, чем нужно". |
|
15.05.2012, 12:53 | #2 |
Ищущий знания...
|
Цитата:
X++: InventJournalCheckPost::newPostJournal(inventJournalTable).run();
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
|
За это сообщение автора поблагодарили: niksen (1). |
15.05.2012, 13:01 | #3 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: niksen (1). |
15.05.2012, 13:07 | #4 |
Аманд
|
А можно так:
1. Создать Новый Сводный план (отключить учёт проводок и наличия), включить прогнозный план. 2. Создать Прогнозный план (Продажи, Закупки, Остатки) 3. Связать Новый план с прогнозным планом, выполнить планирование. Это можно делать на рабочей системе и затем сравнить результаты рабочего и расчётного плана. |
|
|
За это сообщение автора поблагодарили: S.Kuskov (2), niksen (1). |
15.05.2012, 14:19 | #5 |
Участник
|
Закачка строк складского журнала (СЖ) из Ехеля штатно (через шаблон по таблице) возможна, но ничего толком не даст, тк в момент инсерта строк должны делаться складские проводки + есть связанная таблица аналитик, которую в одной "простыне" Ехели заполнять неудобно.
Поэтому у нас уже оч много лет (с первого внедрения АХ) реализован импорт СЖ из Ехель. И вот им уже заливается нужный набор начальных данных по номенклатуре. |
|
|
За это сообщение автора поблагодарили: niksen (1). |
15.05.2012, 16:25 | #6 |
Участник
|
Цитата:
Сообщение от BOAL
Закачка строк складского журнала (СЖ) из Ехеля штатно (через шаблон по таблице) возможна, но ничего толком не даст, тк в момент инсерта строк должны делаться складские проводки + есть связанная таблица аналитик, которую в одной "простыне" Ехели заполнять неудобно.
Поэтому у нас уже оч много лет (с первого внедрения АХ) реализован импорт СЖ из Ехель. И вот им уже заливается нужный набор начальных данных по номенклатуре. Если же создавать журнал и не разносить его в рабочей базе, можно получить много проблем, ведь в данный момент в ней работают и неправильный рассчёт будет очень некстати. Если использовать прогнозный план и т.д. - нужно опять-таки использовать огромное количество всякого функционала, который нужно дополнительно настраивать и ему же обучать, на это нет сил и времени. А вот написать небольшой импорт для отдельной базы чтобы с ней иногда играть и делать какие-то выводы - это самое то. И другим не мешают. И сами делают, что хотят, - набили файл в экселе с нужным количеством, загрузили его, посчитали, удалили и всё ок. |
|
16.05.2012, 07:25 | #7 |
Участник
|
Цитата:
Цитата:
Человек, идущий через лес, и наблюдающий как мужик старательно рубит дерево тупым топором, обращается к нему:
- Мужик, ты бы топор заточил. Мужик: - Да некогда мне – я дерево рублю. |
|
16.05.2012, 10:18 | #8 |
Участник
|
|
|
16.05.2012, 11:53 | #9 |
Участник
|
|
|
16.05.2012, 12:23 | #10 |
Участник
|
|
|
16.05.2012, 13:37 | #11 |
Участник
|
Пример создания складского журнала. Хотя присоединяюсь к вышесказанному, экспериментировать со сводным планированием (для получения результата) стоит с наличием 5-10 операций по одной номенклатур, котрые можно создать и руками.
|
|
16.05.2012, 14:05 | #12 |
Участник
|
Цитата:
я немного по-другому сделал, попозже выложу |
|
21.05.2012, 16:14 | #13 |
Участник
|
X++: void TmpTableToDBTable() { timeofday timeCounter; str 20 JournalId; InventLocation InventLocation; InventLocationId InventLocationId; InventDim InventDim; InventDimId InventDimId; int cnt; InventSite InventSite; InventSiteId SiteId; InventTrans InventTrans; InventTransId InventTransId; ; updated = 0; created = 0; info(time2str(timenow(),1,1) + ' начало загрузки в рабочую БД'); timeCounter = timenow(); journalid = '000101_131'; delete_from InventJournalTrans where InventJournalTrans.JournalId == journalId; //journalId = strfmt(time2str(timenow(),1,1)+'начдан'); select firstonly InventLocation where InventLocation.InventLocationType == InventLocationType::Standard; { InventLocationId = InventLocation.InventLocationId; /// первый попавшийся склад } select firstonly InventSite; { SiteId = InventSite.SiteId; /// первый попавшийся сайт } info('выбран склад'); ttsbegin; while select forupdate DAXInventItem { inventDim = null; inventDim.InventLocationId = InventLocationId; inventDim.InventSiteId = SiteId; inventDim = InventDim::findOrCreate(inventDim); DAXInventItem.inventDimId = inventDim.inventDimId; DAXInventItem.update(); } ttscommit; info('обновлена аналитика'); ttsbegin; if (InventJournalTable::exist(journalId)) { info('журнал найден'); } else { /// создание журнала select forupdate firstonly InventJournalTable where InventJournalTable.JournalId == journalId; { ++created; AxInventJournalTable = AxInventJournalTable::construct(); AxInventJournalTable.inventJournalTable(InventJournalTable); AxInventJournalTable.parmJournalId(journalId); AxInventJournalTable.parmJournalType(InventJournalType::Movement); AxInventJournalTable.parmPosted(NoYes::No); AxInventJournalTable.parmReservation(ItemReservation::None); AxInventJournalTable.parmSystemBlocked(NoYes::No); AxInventJournalTable.parmVoucherDraw(JournalVoucherDraw::Entering); AxInventJournalTable.parmVoucherChange(InventJournalVoucherChange::DateChange); AxInventJournalTable.parmDeletePostedLines(NoYes::No); AxInventJournalTable.parmDetailSummary(DetailSummary::Detail); AxInventJournalTable.parmJournalNameId('ЖурПр.'); AxInventJournalTable.save(); InventJournalTable = AxInventJournalTable.inventJournalTable(); InventJournalTable.update(); } info('создан журнал'); } ttscommit; cnt = 0; ttsbegin; while select DAXInventItem { select forupdate InventJournalTrans where InventJournalTrans.JournalId == journalId && InventJournalTrans.ItemId == DAXInventItem.ItemId && InventJournalTrans.Qty == DAXInventItem.Qty && InventJournalTrans.TransDate == DAXInventItem.TransDate; { ++created; ++cnt; InventJournalTrans.initValue(); InventJournalTrans.InventDimId= DAXInventItem.InventDimId; InventJournalTrans.ItemId = DAXInventItem.ItemId; InventJournalTrans.Qty = DAXInventItem.Qty; InventJournalTrans.TransDate = DAXInventItem.TransDate; InventJournalTrans.JournalType = InventJournalType::Movement; InventJournalTrans.PriceUnit = 1.00; InventJournalTrans.LineNum = InventJournalTrans::lastLineNum(journalId)+1; InventJournalTrans.CostPrice = 0.00; InventJournalTrans.CostAmount =0.00; InventJournalTrans.CostMarkup = 0.00; InventJournalTrans.SalesAmount = 0.00; InventJournalTrans.LedgerAccountIdOffset = "Корр.Счёт"; InventJournalTrans.BOMLine = NoYes::No; InventJournalTrans.AssetTransType = AssetTransTypeJournal::None; InventJournalTrans.Voucher = ''; InventJournalTrans.JournalId = journalId; InventJournalTrans.CostPrice = 0.00; InventJournalTrans.PriceUnit = 1.00; InventJournalTrans.CostMarkup = 0.00; InventJournalTrans.CostAmount = 0.00; InventJournalTrans.SalesAmount = 0.00; InventJournalTrans.ProjTransId = ""; InventJournalTrans.InventTransId = int2str(00027231+cnt+1)+'_129'; InventJournalTrans.InventTransIdFather = ''; InventJournalTrans.InventOnHand = 0.00; InventJournalTrans.Counted = 0.00; InventJournalTrans.Dimension[1] = ""; InventJournalTrans.Dimension[2] = ""; InventJournalTrans.Dimension[3] = ""; InventJournalTrans.InventTransIdReturn = ""; InventJournalTrans.ProjCategoryId = ""; InventJournalTrans.ProjId = ""; InventJournalTrans.DEL_CorrectedInvoiceId = ""; InventJournalTrans.ToInventTransId = ""; InventJournalTrans.ReasonRefRecId = 0; InventJournalTrans.ToInventDimId = ""; InventJournalTrans.ReqPOId = ""; InventJournalTrans.EmplId = ""; InventJournalTrans.AssetTransType = AssetTransTypeJournal::None; InventJournalTrans.AssetId = ""; InventJournalTrans.AssetBookId = ""; InventJournalTrans.ProjTaxGroupId = ""; InventJournalTrans.ProjSalesCurrencyId = ""; InventJournalTrans.ProjLinePropertyId = ""; InventJournalTrans.ProjTaxItemGroupId = ""; InventJournalTrans.ProjUnitID = ""; InventJournalTrans.ProjSalesPrice = 0.00; InventJournalTrans.InventRefType = InventRefType::None; InventJournalTrans.InventRefId = ""; InventJournalTrans.InventRefTransId = ""; InventJournalTrans.ProfitSet = CostProfitSet::Standard; InventJournalTrans.ActivityNumber = ""; InventJournalTrans.Storno_RU = NoYes::No; InventJournalTrans.ServiceTariffId_PL = ""; InventJournalTrans.ScrapTypeId_RU = ""; InventJournalTrans.write(); } } ttscommit; info('создано записей ' + int2str(created)); info('обновлено записей ' + int2str(updated)); info(time2str(timenow(),1,1) + ' конец загрузки в рабочую БД'); timeCounter = timenow()-timeCounter; info('времени загрузки в основную БД '+time2str(timeCounter,1,1)); } используется одна временная таблица, в которой аналитика проставляется исходя из 1 сайта и склада, можете указать нужный сайт и склад, дело ваше Косяк конечно у меня с transId, если кто подскажет, исправить, буду рад p.s. этот код загружает данные, но не разносит журнал. Разносил я вручную, т.к. мне нравится контролировать процесс |
|
21.05.2012, 16:31 | #14 |
Участник
|
зачем велосипед изобретать.
2009 под рукой нет, есть 3.0, так вот в ней есть \Classes\TutorialJournalCreateExample и в нем метод создания журнла X++: TutorialJournalTable journalTable; TutorialJournalTrans journalTrans; TutorialJournalTableData journalTableData = JournalTableData::newTable(journalTable); TutorialJournalTransData journalTransData = journalTableData.JournalStatic().newJournalTransData(journalTrans,journalTableData); Integer x; ; // Init journalTable journalTable.journalId = journalTableData.nextJournalId(); journalTable.journalType = InventJournalType::Movement; journalTable.journalNameId = journalTableData.JournalStatic().standardJournalNameId(journalTable.journalType); journalTableData.initFromJournalName(journalTableData.JournalStatic().findJournalName(journalTable.journalNameId)); // OR // // journalTable.initFromJournalName(TutorialJournalName::find(journalTable.journalNameId)); // Loop lines for (x = 1; x <= 15; x++) { journalTrans.clear(); journalTransData.initFromJournalTable(); journalTrans.transDate = systemdateGet() + x div 2; journalTrans.exItemId = (select firstOnly inventTable).itemId; journalTrans.exCostAmount = x; journalTransData.create(); } journalTable.insert(); |
|