Стараюсь писать про Аксапту, хотя частенько тянет в Офис
-
Сумма прописью (RU): Axapta, VBA и Excel (в одной ячейке!)
К сожалению, приаттаченные к сообщениям файлы могут видеть только зарегистрированные участники форума. Если Вы - незарегистрированный гость, но хотели бы получить файл - напишите мне об этом на Gustav@axforum.info и я пришлю его. Возможно, придется подождать несколько дней (так как проверяю этот адрес не каждый день).Запись от Gustav размещена 23.03.2012 в 19:57 -
Построение сводной таблицы на форме с загрузкой данных из ADODB.Recordset
Мне кажется метод не коректно отрабатывает, хотя я могу ошибаться.
Когда вы сделали сводную таблицу и нажимаете на кнопку "экспорт в эксель" у вас происходит выгрузка? у меня вылезает ошибка
DAX 2009
Я потратил много времени, чтобы выяснить что именно не так.
Надо добавить строку
X++:#define.adAffectAll(3) ... rst.UpdateBatch(#adAffectAll);
Запись от refined размещена 31.03.2011 в 16:11
Обновил(-а) refined 31.03.2011 в 18:25 -
Вывод в Excel сводной таблицы "пользователи-группы"
К великой моей радости загрузка disconnected рекордсета в OWC PivotTable возможна!!
Хотя и не через кэш (а нам, в принципе, какая разница?)
См. Построение сводной таблицы на форме с загрузкой данных из ADODB.RecordsetЗапись от Gustav размещена 17.05.2010 в 19:28 -
Оперативная сортировка по убыванию
Давно хотел написать комментарий. На самом деле интересный эксперимент, однако получилось очень много кода, причем не самого простого в восприятии. Честно говоря, если бы я сейчас решал подобную задачу, то я бы сделал следующим образом: создал бы классы обертки для всех нужных базовых типов, которые предполагается сортировать. Имплементировал бы для них аналог .NET-овских или Java "компараторов". Суть в том, что данный интерфейс имеет всего один метод "сравнить с" и возвращает 0 если объекты равны, отрицательное значение в случае если наш текущий объект меньше того, с которым сравниваем и наоборот если больше. Кстати, путем инвертирования сразу получаем и обратную сортировку.
Дальше взять какой нить QuickSort(хотя поскольку он рекурсивный, возможно не лучший выбор для больших массивов) и реализовать его один раз, именно вокруг ссылок на интерфейс "компаратора". Таким образом мы получили бы универсальный сортировщик для любых типов данных, кроме таблиц конечно. Такие вот мысли вслух.Запись от Lemming размещена 30.04.2010 в 19:02 -
Использование OWC Spreadsheet в диалоге
А вот и модифицированный код:
Весь код метода, наверное, не так интересен - хотя бы потому, что его невозможно запустить в автономном режиме как джоб. Тем не менее, я привожу его полностью - хотя бы потому, что замена несущественного в рамках темы кода на комментарии вида "// bla-bla-bla" представляет собой дополнительную работу, которую мне делать не хочетсяX++:void ChangeLifeTime() { DialogRunBase dialog = new Dialog(); DialogField dialogDate,dialogLifeTime,dialogStandardId; RAssetLifeTime dialogLifeTimeValue; RAssetStandardId dialogStandardValue; TransDate dialogDateValue; int i = 0; common urRec; RassetTable urRAssetTable; RassetStandards urRassetStandards; DialogGroup dialogGroupSS; // группа, в которую помещается Spreadsheet FormGroupControl groupSS; // та же группа, только уже как контрол FormActiveXControl ss; // собственно Spreadsheet COM range; COM temp; COM currCell; COMVariant cv; int lastRow; int row; RassetId currRassetId; RAssetLifeTime currLifeTime; ; urRec = RAssetTable_ds.getFirst(1); if (! urRec) urRec = RAssetTable_ds.cursor(); if (urRec) { dialog.caption("Новые значения"); // KKu, 22.09.2009 --> модификация на случай разных сроков службы dialog.addGroup('Основные параметры'); // KKu, 22.09.2009 <-- DialogDate = dialog.addField(typeId(TransDate)); DialogDate.value(today()); dialogStandardId = dialog.addField(typeId(RAssetStandardId)); dialogLifeTime = dialog.addField(typeId(RAssetLifeTime)); dialogDate.widthMode(formwidth::ColumnWidth); dialogStandardId.widthMode(formwidth::ColumnWidth); dialogLifeTime.widthMode(formwidth::ColumnWidth); // KKu, 22.09.2009 --> модификация на случай разных сроков службы // без группы Spreadsheet показывался неуправляемо // только при помощи группы он более-менее обуздался dialogGroupSS = dialog.addGroup('В случае разных сроков службы'); groupSS = dialogGroupSS.formGroup(); groupSS.addControl(FormControlType::ActiveX, 'MySpreadSheet'); dialog.doInit(); ss = dialog.formRun().design().controlName('MySpreadSheet'); ss.className('{0002E541-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 10.0 //ss.className('{0002E559-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 11.0 ss.height(300); ss.width(600); // гасим ярлычки листов ss.DisplayWorkbookTabs(false); range = ss.Range('A1'); range.Value2('Инв. номер ОС'); range = ss.Range('B1'); range.Value2('Новый срок службы'); range = ss.Range('C1'); range.Value2('Инструкция'); range = ss.Range('C2'); range.Value2('Если Вы хотите выполнить обновление'); range = ss.Range('C3'); range.Value2('сроков службы для нескольких ОС'); range = ss.Range('C4'); range.Value2('разными значениями сроков,'); range = ss.Range('C5'); range.Value2('то поставьте "Срок службы" равным -1'); range = ss.Range('C6'); range.Value2('в группе полей "Основные параметры"'); range = ss.Range('C7'); range.Value2('и введите данные в колонки A и B,'); range = ss.Range('C8'); range.Value2('начиная со строки 2.'); range = ss.Range('A1:C1'); temp = range.Font(); temp.Bold(true); temp = range.EntireColumn(); temp.AutoFit(); // KKu, 22.09.2009 <-- if (dialog.run()) { dialogDateValue = DialogDate.value(); dialogStandardValue = dialogStandardId.value(); dialogLifeTimeValue = dialogLifeTime.value(); if (! (dialogDateValue && dialogStandardValue && dialogLifeTimeValue)) { checkFailed(strFmt("Заполните все поля")); return; } if (! RAssetStandardTable::Find(dialogStandardValue)) { checkFailed(strFmt("Значение '%1' не найдено в таблице модели учета", dialogStandardValue)); return; } // KKu, 22.09.2009 --> модификация на случай разных сроков службы if (dialogLifeTimeValue != -1) // KKu, 22.09.2009 <-- { // старое продолжение While (urRec) { i++; RAssetTable_ds.findRecord(urRec); if (RAssetTable_ds) { historyDialog.lifetimeDate(dialogDateValue); ttsBegin; urRassetStandards = RassetStandards::find( urRec.(fieldNum(RAssetTable,AccountNum)),dialogStandardValue, true); urRassetStandards.Lifetime = dialogLifeTimeValue; urRassetStandards.update(historyDialog); ttsCommit; RAssetTable_ds.reread(); RAssetTable_ds.refresh(); } urRec = RAssetTable_ds.getNext(); } } // KKu, 22.09.2009 --> модификация на случай разных сроков службы else { // новое продолжение // определяем последнюю строку lastRow = xlRanges::countRows(range.CurrentRegion()); for (row=2; row <=lastRow; row++) { // читаем из Spreadsheet Инв.номер ОС currCell = xlRanges::cellRC(range, row, 1, true); cv = currCell.Value(); currRassetId = cv.bStr(); // читаем из Spreadsheet Новый срок службы currCell = xlRanges::cellRC(range, row, 2, true); cv = currCell.Value(); currLifeTime = cv.double(); urRAssetTable = RAssetTable::find(currRassetId); if (urRAssetTable) { i++; historyDialog.lifetimeDate(dialogDateValue); ttsBegin; urRassetStandards = RassetStandards::find( urRAssetTable.AccountNum, dialogStandardValue, true); urRassetStandards.Lifetime = currLifeTime; // dialogLifeTimeValue; urRassetStandards.update(historyDialog); ttsCommit; info(strFmt('%1 --- %2', currRassetId, currLifeTime)); } } } // KKu, 22.09.2009 <-- info(strFmt("Операция по смене срока службы по %1 ОС модели %2 успешно завершена", int2Str(i),dialogStandardValue)); } } }
В интересующих нас в данный момент строчках кода, относящихся к Spreadsheet, имеются вызовы двух статических методов моего класса xlRanges, который я планирую подробно рассмотреть в одном из ближайших сообщений своего блога. Пока же чисто справочно приведу эти методы "as is":
X++:static int countRows(COM parentRange) { // COM parentRange может быть Excel.Application (подразумевается ActiveSheet) или Worksheet или Range // в случае Spreadsheet - Spreadsheet.Application или Worksheet или Range return any2int(COM::createFromObject( parentRange.Rows() ).Count()); } static COM cellRC(COM parentRange, int row, int col, boolean forSpreadsheet = false) { // COM parentRange может быть Excel.Application (подразумевается ActiveSheet) или Worksheet или Range // в случае Spreadsheet - Spreadsheet.Application или Worksheet или Range // row и col могут быть меньше единицы (0 и отрицательные) - и для Excel, и для Spreadsheet // но меньше единицы - только для Range (не для Application, и не для Worksheet) // возвращает объект Range COM cells; ; cells = parentRange.Cells(); if (! forSpreadsheet) // Excel return COM::createFromVariant( cells.Item( row, col )); else // Spreadsheet return cells.Item( row, col ); }
Запись от Gustav размещена 15.10.2009 в 17:50
Обновил(-а) Gustav 16.10.2009 в 17:55 -
Контроль возможности создания журнала
Цитата:
А так они просто знают, что для смены филиала им надо выполнить такую-то команду, находящуюся в интерфейсе там-то. Не так же трудно щёлкнуть по "Сервис", а потом по "Параметры"? А далее даже сделано такое облегчение: им не надо раскрывать список филиалов в StringEdit с lookup, а достаточно пощелкать двойными щелчками, как в ComboBox'е, для переключения филиалов по кругу. Сделано это при помощи такого несложного метода:
Пользователям нравитсяX++:// для того, чтобы первичная группа пользователя // менялась по кругу при очередном щелчке public int mouseDblClick(int _x, int _y, int _button, boolean _Ctrl, boolean _Shift) { int ret; str groupToFind; container filials = ['Head','Branch1','Branch2','']; int pos; ret = super(_x, _y, _button, _Ctrl, _Shift); groupToFind = SysUserInfo.UserGroupDim; pos = conFind(filials, groupToFind); pos++; if (pos > conLen(filials)) pos = 1; SysUserInfo.UserGroupDim = conPeek(filials, pos); SysUserInfo.write(); SysUserInfo_ds.reread(); SysUserInfo_ds.refresh(); return ret; }
Запись от Gustav размещена 15.10.2009 в 10:30 -
Контроль возможности создания журнала
А пользователям удобно каждый раз залезать в Сервис/Параметры чтобы снять фильтр по филиалу?
И потом еще раз, чтобы вернуть фильтр.
Может на форме галочку добавить "А можно всех посмотреть?"?Запись от Кирилл размещена 14.10.2009 в 16:32
Обновил(-а) Кирилл 14.10.2009 в 16:36 -
Функция определения рабочего статуса дня
Да, это - исключительно советское извращение. (Я называю это извращением потому, что заранее со 100%-ой вероятностью не знаешь, работаешь ли в выбранный день в будущем, или нет.) Если в Австрии праздник попадает на выходной, то считай, не повезло. А алгоритм пришлось бы расширять на вычисление Пасхи и Троицы.Запись от EVGL размещена 02.10.2009 в 16:51
Обновил(-а) EVGL 02.10.2009 в 16:54 -
Функция определения рабочего статуса дня
Евгений, ну так... запустить ее в цикле за год без блока "исключений" и сгенерить календарь, нет?
Руками потом, да - информация о новых исключениях все равно обычно появляется тогда, когда календари на след. год в системах уже в основном заготовлены.
Кстати, в Австрии тоже есть такие сдвиги выходных из-за праздников, попавших на уик-энд? Или это исключительно российская особенность?Запись от Gustav размещена 01.10.2009 в 18:53 -
Функция определения рабочего статуса дня
Упражнение в программировании, не более того. Определенный интерес представляла бы функция, которая генерировала бы календарь по этой схеме, а "исключения" заносились бы руками в готовый календарь.Запись от EVGL размещена 29.09.2009 в 20:59 -
Запись от mazzy размещена 08.09.2009 в 14:35 -
Функция определения рабочего статуса дня
Собственно я прервал предыдущий пост, потому что напоролся на ограничение в 10 тысяч символов!! Поэтому продолжаю уже в этом комментарии
Способ с макросом я использовал для демонстрационного примера. Каждое исключение характеризуется двумя датами: день, который переносят, и день, НА который переносят. Глобальный макрос HolidayExceptions наполнен информацией о реальных переносах-исключениях в 2007-2009 годах:
X++:/* %1 holiday exceptions map */ #LOCALMACRO.holidayExceptionsInsert // ФОРМИРОВАНИЕ СПИСКА ИСКЛЮЧЕНИЙ - на основании Постановлений Правительства РФ // В соответствии c Постановлением Правительства РФ от 11 ноября 2006 года N 661 // переносятся следующие выходные дни 2007 года // с субботы 28 апреля на понедельник 30 апреля %1.insert( 28\04\2007, 2); // 2 - т.к. перенос с предпраздничного дня %1.insert( 30\04\2007, 0); // с субботы 9 июня на понедельник 11 июня %1.insert( 09\06\2007, 2); // 2 - т.к. перенос с предпраздничного дня %1.insert( 11\06\2007, 0); // с субботы 29 декабря на понедельник 31 декабря %1.insert( 29\12\2007, 2); // 2 - т.к. перенос с предпраздничного дня %1.insert( 31\12\2007, 0); // В соответствии с Постановлением Правительства РФ от 11.08.2007 № 512 // переносятся следующие выходные дни 2008 года: // с воскресенья 4 мая на пятницу 2 мая %1.insert( 04\05\2008, 1); // 4 мая 2008 стал рабочим днем %1.insert( 02\05\2008, 0); // 2 мая 2008 стал выходным днем // с субботы 7 июня на пятницу 13 июня %1.insert( 07\06\2008, 1); // 7 июня 2008 стал рабочим днем %1.insert( 13\06\2008, 0); // 13 июня 2008 стал выходным днем // с субботы 1 ноября на понедельник 3 ноября %1.insert( 01\11\2008, 2); // // 2 - т.к. перенос с предпраздничного дня %1.insert( 03\11\2008, 0); // // В соответствии c Постановлением Правительства от 26.11.2008 № 877 // переносятся следующие выходные дни 2009 года: // с воскресенья 11 января на пятницу 9 января. %1.insert( 11\01\2009, 1); %1.insert( 09\01\2009, 0); #ENDMACRO
Запись от Gustav размещена 28.08.2009 в 15:19
Обновил(-а) Gustav 28.08.2009 в 16:11 -
Оставьте комментарии к этому посту
Цитата:
И обратите внимание - внизу есть поле статус записи, которое можно сначала выставить как черновик и запись не будет отображаться, т.е. ее можно пописать в несколько приемов, а потом предъявить общественности уже отшлифованное творение.
Но вообще согласен. Не всё здесь так очевидно, как хотелось быЗапись от Gustav размещена 24.08.2009 в 18:52 -
Оставьте комментарии к этому посту
то ль лыжи не едут...
Граждане, а как свои записи добавлять? Я чего-то не врубился Зашел в "управление блогом", насоздавал там 5 страниц, и мне сказали "хватит с тебя"... Чувствую, что это было что-то не то
Добавление записей пока смертным не доступно, правильно я понимаю?Запись от Ruff размещена 21.08.2009 в 22:29
Обновил(-а) Ruff 22.08.2009 в 02:02 -
Я осваиваю Office 2007
Теперь, вроде, модно называть это лентой
Да, клёво! Заодно напомню (это, правда, было и раньше, но, может, кто еще не знает), что при вращении колеса мыши при удерживаемой клавише Ctrl изменяется масштаб. Масштаб теперь можно менять и более явно - при помощи ползунка в строке состояния, а управляется отображение этого ползунка из контекстного меню строки состояния (из того же, которое управляет отображением агрегатных функций)Запись от Gustav размещена 21.08.2009 в 09:48 -
Я осваиваю Office 2007
еще можно сказать, что закладки вверух переключаются колесом мыши.
а также стоит упомянуть о том, что любимые иконки из тулбара можно (и нужно) помещать наверх в панель быстрого доступа (правой кнопкой мыши на любой иконке). Я например, всегда кнопку Preview туда вешаю.Запись от mazzy размещена 20.08.2009 в 17:57 -
Я осваиваю Office 2007
вроде у Майкрософта есть Microsoft Office Compatibility Pack for Word, Excel, and PowerPoint 2007 File Formats для 2003 офиса.
этот апдейт позволяет читать форматы 2007 офиса, не выходя из 2003.Запись от mazzy размещена 20.08.2009 в 17:55 -
Контроль возможности создания журнала
Думаю, что не выдам страшную тайну, сказав о том, что эти вопросы уже поднимались в модераторских кулуарах и даже зафиксированы в плане на доработку. Функционал блогов проходит обкатку, поэтому блоги пока и не афишируются широко. Но не писать же все время тестово о погоде или ау-ау. Вот я и решил начать писать по существу - надо же посмотреть, как будет выглядеть в блоге реальное обсуждение по профессиональной тематике.Запись от Gustav размещена 11.08.2009 в 11:24 -
Контроль возможности создания журнала
Отчего столь содержательное обсуждение не выносится в форум? И как быть с разрастанием информационного поля, т.е. если раньше достаточно было мониторить форум, то теперь еще и блоги шерстить? Есть ли глобальный поиск по контенту (форум+блоги)?Запись от player размещена 11.08.2009 в 07:20 -
Контроль возможности создания журнала
Цитата:
Так вот, во всех, перечисленных таблицах, кроме LedgerJournalTable, метод validateWrite содержит вызов :X++:private static JournalTableData construct( JournalTableMap _journalTable ) { switch (_journalTable.tableId) { case tableNum(TutorialJournalTable): return new tutorialJournalTableData(_journalTable); case tableNum(ProjJournalTable): return new ProjJournalTableData(_journalTable); case tableNum(LedgerJournalTable): return new LedgerJournalTableData(_journalTable); case tableNum(WMSJournalTable): return new WMSJournalTableData(_journalTable); case tableNum(InventJournalTable): return new InventJournalTableData(_journalTable); case tableNum(ProdJournalTable): return prodJournalTableData::newTable(_journalTable); case tableNum(RPayJournalTable): return new RPayJournalTableData(_journalTable); case tableNum(RHRMOrderTable): return new RHRMJournalTableData(_journalTable); default : return new JournalTableData(_journalTable); } }
Для сравнения залез в AX 4.0 и бинго! данный вызов имеется и на таблице LedgerJournalTable.X++:ret = _journalTableData.validateWritePre(ret);
Так что по всей видимости для AX 3.0 наблюдается баг, в отношении создания журналов.
Думаю, если добавить данный вызов и в AX 3.0 в метод validateWrite таблицы LedgerJournalTable, то можно использовать JournalTableData\validateWritePre, причем, этим способом можно защиться и в случае, когда журнал создается из кода, конечно, если идет вызов метода validateWriteЗапись от SRF размещена 03.08.2009 в 12:15