|
19.06.2015, 12:46 | #1 |
Участник
|
Определение используемых полей
Доброго времени суток!
Пытаюсь разобраться в тонкостях системы ax 2009, стоит задача определить какие поля из каких таблиц и при каких параметрах выводятся в отчет. Отчет company->Расчеты с поставщиками->Запросы->Оборотно-сальдовая ведомость Определил что всю работу делает класс RLedgerSheetEngine унаследованный от RunBase. В его методе query формируется запрос который использует лишь одну таблицу - LedgerTrans. (Хотя дебагер говорит что данный метод не используется). В общем помогите разобраться с вопросом, я в AX новичок, подскажите с чего нужно начинать поиск при подобных задачах, ведь запросы могут строится не только в коде. В общем буду признателен любой информации по данному вопросу, ато я уже себе голову сломал и ничего найти не смог... |
|
19.06.2015, 13:09 | #2 |
Участник
|
Полагаю в ошиблись в изысканиях.
Там есть 3 класса наследника - для расчетов с поставщиками (табличка VendTrans) для расчетов с клиентами (табличка custTrans) для главной книги (табличка LedgerTrans) Если вы действительно смотрите Отчет company->Расчеты с поставщиками->Запросы->Оборотно-сальдовая ведомость то смотрите наследник обрабатывающий vendTrans |
|
19.06.2015, 13:24 | #3 |
Участник
|
Logger, я с вами полностью согласен. В данном случае наследник LedgerSheetEngine_TurnoverVend, тут используется одна таблица - VendTrans, но по идее поля в отчете берутся не только из нее, я не могу понять где они выбираются. Еще в диалоге есть комбобокс custVendDetailBalans, в зависимости от его значения отчет ведет себя по разному и показывает разные столбцы - этого в коде я тоже пока не смог найти.
|
|
19.06.2015, 13:26 | #4 |
Участник
|
Попробуйте выбрать простой случай когда обрабатывается 1-2 проводки.
И пройдитесь с отладчиком по шагам. |
|
|
За это сообщение автора поблагодарили: syl (1). |
19.06.2015, 14:04 | #5 |
Участник
|
Прошел.
Запрос так и не обнаружил, но выяснил что данные добавляются построчно и берутся они из turnoverIterator = new MapIterator(mapData); mapData: mapData = rLedgerSheetServerCV.getMap(); rLedgerSheetServerCV: не понятно от куда берется... |
|
19.06.2015, 14:39 | #6 |
Участник
|
Цитата:
Посмотрите начало метода getDataFromServer(), где выполняется определение переменных X++: protected void getDataFromServer() { RLedgerSheetServer_TurnoverCustVend rLedgerSheetServerCV = rLedgerSheetServer; (...) Т.е. rLedgerSheetServerCV - это просто "перименование" ранее созданного объекта rLedgerSheetServer. Смысл такого "переименования" в том, что в переменной rLedgerSheetServer записана ссылка на экземпляр базового класса RLedgerSheetServer. А "переименование" записывает в переменную rLedgerSheetServerCV уже экземпляр класса-наследника RLedgerSheetServer_TurnoverCustVend
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... Последний раз редактировалось Владимир Максимов; 19.06.2015 в 14:45. |
|
19.06.2015, 14:35 | #7 |
Участник
|
Общая логика работы всех оборотно-сальдовых ведомостей в Ax2009 выглядит примерно так
К пункту меню привязана форма RLedgerSheet В событии init формы RLedgerSheet создается экземпляр класса наследника от RLedgerSheetEngine, который открывает диалог с пользователем для установки ряда настроек и фильтров для последующего расчета. После установки настроек пользователем, если была нажата кнопка «Ок», то выполняется ряд расчетов в этом же классе. А, кроме того, создается и запускается экземпляр класса наследника от RLedgerSheetServer, который формирует и хранит список записей по документам-источникам и суммовые показатели по этим документам. X++: // init формы RLedgerSheet // Создается класс-наследник от RLedgerSheetEngine rLedgerSheetEngine = RLedgerSheetEngine::construct(element.args()); super(); // Диалог с пользователем if (! rLedgerSheetEngine.prompt()) { // Если нажади "Отмена", то закрываем форму this.close(); return; } // Передаем в класс ссылку на объект ListView на форме rLedgerSheetEngine.parmFormListControl(turnoverAmount); // Собственно выполнение расчета rLedgerSheetEngine.run(); X++: this.initFieldsData(); this.initValuesData(); this.initValuesData() – это метод, в котором можно инициализировать переменные. Как правило, не используется. Предполагается, что по умолчанию все переменные пустые, а пользователь их заполняет, если необходимо Метод run() перекрыт в классе наследнике RLedgerSheetClient. Если убрать «обвязку», то имеем следующее X++: this.initAccounts(); // Инициализация this.createRLedgerSheetServer(); // Создание экземпляра класса RLedgerSheetServer для расчета this.executeRLedgerSheetServer(); // Собственно расчет this.getDataFromServer(); // перекачка данных из расчетного класса в текущий this.initListView(); // Формирование столбцов объекта формы ListView this.fetchNextRows(); // Заполнение строк объекта формы ListView this.setItem(); // включение/выключение ряда объектов и установка фокуса X++: rLedgerSheetServer = RLedgerSheetServer::construct(this.parmRLedgerSheetType()); rLedgerSheetServer.initParameters(this.queryRun(), this.getParmContainer()); rLedgerSheetServer.run(this.initRunQuery()); this.queryRun() – настроенный пользователем QueryRun this.initRunQuery() – если не перекрыт, то queryRun.query() RLedgerSheetEngine::Construct(args). Определяет, какие именно классы-наследники от RLedgerSheetEngine и RLedgerSheetServer будут созданы. this.getParmContainer() – контейнер, содержащий список переменных с настройками пользователя X++: return [ currencyType, //Тип валюты, в которой выполнять расчет (основная, вторичная, указанная) deleteZero, //Из диапазона расчета исключить даты, не имеющие ни одной заявки на оплату showSumAccount, //Отображать строки с итоговыми суммами dimensionCriteria, //Финансовые аналитики fromDate, //Начальная дата диапазона toDate, //Конечная дата диапазона operationsTax, //По какому уровню рассчитывать бухгалтерское сальдо (Base Enum) currencyCode, //Код валюты, в которой выполнять расчет, если currencyType = указанная selectedFieldsOrder //Выбранные поля сортировки (поставщик, договор, счет ГК) ];
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: Ruff (5). |
19.06.2015, 15:01 | #8 |
Участник
|
Да, собственно запрос - это метод rLedgerSheetEngine.query(), который вызывается при инициализации переменной queryRun в методе rLedgerSheetEngine.queryRun(). Естественно, для разных классов-наследников наполнение метода rLedgerSheetEngine.query() разное.
Для ОСВ по поставщику - это таблица vendTrans - Проводки по поставщику.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: syl (1). |
19.06.2015, 15:37 | #9 |
Участник
|
Я выявил такой запрос:
NAME: qbds VALUE: SELECT FIRSTFAST * FROM VendTrans WHERE ((TransDate<={ts '2014-12-31 00:00:00.000'})) AND ((Dimension[4] = N'GRUPPOTECN')) AND ((EmplAccount_RU = ' ')) TYPE: QueryBuildDataSource Но я так и не понял где именно он формируется. Везде где в наследниках есть метод Query пытался дебажить, эти методы просто не вызываются. Я уже разобрал последовательность вызов и логику работы, но мне нужно найти где именно формируется запрос, и что он туда пихает и из каких таблиц. Либо дебагер перехватывает не все методы, либо я что то упустил... X++: //RLedgerSheetEngine.Run() SysQueryRun runQuery; ; this.initAccounts(); runQuery = new SysQueryRun(this.initRunQuery()); while(runQuery.next()) { this.loopAction(runQuery); } X++: protected Query initRunQuery() { return queryRun.query(); } Последний раз редактировалось syl; 19.06.2015 в 16:04. |
|
19.06.2015, 16:08 | #10 |
Дмитрий Ерин
|
Запросы могут упаковываться/распаковываться (то есть хранить выбранные пользователем значения в промежутках между запусками). Смотрите методы pack(), unpack().
|
|
19.06.2015, 16:58 | #11 |
Участник
|
Цитата:
С самим запросом я походу разобрался, он формируется в методе query rLedgerSheetEngine_TurnoverVend, потом по ходу алгоритма на него накладываются фильтры. Затем в методе loopBalanceTrans rLedgerSheetEngine_TurnoverCustVend происходит расчет, fetchNextRows построчно добавляет данные. Последнее что осталось определить какие поля выводятся на конечную форму... Последний раз редактировалось syl; 19.06.2015 в 17:07. |
|
20.06.2015, 18:03 | #12 |
Участник
|
Посмотрите здесь: Кнопка Выбрать в окне диалога.
QueryRun - это переменная, определенная в родительском классе RunBase. Она создается на основе переменной Query (которая формируется в rLedgerSheetEngine.query()) + все те настройки, которые может добавить пользователь, нажав кнопку "Выбрать". Можно сказать так: query - настройки запроса по умолчанию при первом открытии диалога с пользователем, queryRun - реальные значения запроса, указанные пользователем в диалоге PS: Российская локализация ОСВ сильно "покорежила" стандартную идеологию работы с классами-наследниками RunBase. Как обычно, впрочем... Почему-то российские локализаторы всегда идут "своим путем" даже не пытаясь понять идеологию Axapta.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
20.06.2015, 15:20 | #13 |
Участник
|
Вообще все данные по для получения сальдо/оборотов по поставщику, в основном, находятся в трех таблицах, это VendTrans, VendTransOpen и VendSettlement. Ну, за некоторыми данными нужно лезть в самого поставщика VendTable.
Дальше уже зависит от того, какая задача стоит. Если нужно что-то изменить в ОСВ по поставщикам, то придется продираться через механизм ОСВ Российской локализации, про которую пишет Владимир Максимов. Если же этот отчет нужен только для того, чтобы понять как получить остатки и обороты по поставщикам, то лучше не нужно. На мой взгляд, эта подситстема ОСВ в DAX является явным антипатерном - показывает как не нужно делать в DAX. Тут явно при локализации была задача от заказчика "сделайте как в 1С". Возможно, что задача и нужная, но её реализация кривая. Если хотите просто узнать как получать данные по оборотам и остаткам (не исключено, что в связке с условиями оплаты), то смотрите стандартные отчеты:
|
|