AXForum  
Вернуться   AXForum > Блоги > Gustav'ово бложище, или Записки DAX-дилетанта-III
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

Стараюсь писать про Аксапту, хотя частенько тянет в Офис
  1. Старый комментарий
    Аватар для Gustav

    Сумма прописью (RU): Axapta, VBA и Excel (в одной ячейке!)

    К сожалению, приаттаченные к сообщениям файлы могут видеть только зарегистрированные участники форума. Если Вы - незарегистрированный гость, но хотели бы получить файл - напишите мне об этом на Gustav@axforum.info и я пришлю его. Возможно, придется подождать несколько дней (так как проверяю этот адрес не каждый день).
    Запись от Gustav размещена 23.03.2012 в 19:57 Gustav is offline
  2. Старый комментарий

    Построение сводной таблицы на форме с загрузкой данных из ADODB.Recordset

    Мне кажется метод не коректно отрабатывает, хотя я могу ошибаться.
    Когда вы сделали сводную таблицу и нажимаете на кнопку "экспорт в эксель" у вас происходит выгрузка? у меня вылезает ошибка
    DAX 2009

    Я потратил много времени, чтобы выяснить что именно не так.
    Надо добавить строку
    X++:
    #define.adAffectAll(3)
    ...
    rst.UpdateBatch(#adAffectAll);
    Запись от refined размещена 31.03.2011 в 16:11 refined is offline
    Обновил(-а) refined 31.03.2011 в 18:25
  3. Старый комментарий
    Аватар для Gustav

    Вывод в Excel сводной таблицы "пользователи-группы"

    К великой моей радости загрузка disconnected рекордсета в OWC PivotTable возможна!!
    Хотя и не через кэш (а нам, в принципе, какая разница?)

    См. Построение сводной таблицы на форме с загрузкой данных из ADODB.Recordset
    Запись от Gustav размещена 17.05.2010 в 19:28 Gustav is offline
  4. Старый комментарий
    Аватар для Lemming

    Оперативная сортировка по убыванию

    Давно хотел написать комментарий. На самом деле интересный эксперимент, однако получилось очень много кода, причем не самого простого в восприятии. Честно говоря, если бы я сейчас решал подобную задачу, то я бы сделал следующим образом: создал бы классы обертки для всех нужных базовых типов, которые предполагается сортировать. Имплементировал бы для них аналог .NET-овских или Java "компараторов". Суть в том, что данный интерфейс имеет всего один метод "сравнить с" и возвращает 0 если объекты равны, отрицательное значение в случае если наш текущий объект меньше того, с которым сравниваем и наоборот если больше. Кстати, путем инвертирования сразу получаем и обратную сортировку.

    Дальше взять какой нить QuickSort(хотя поскольку он рекурсивный, возможно не лучший выбор для больших массивов) и реализовать его один раз, именно вокруг ссылок на интерфейс "компаратора". Таким образом мы получили бы универсальный сортировщик для любых типов данных, кроме таблиц конечно. Такие вот мысли вслух.
    Запись от Lemming размещена 30.04.2010 в 19:02 Lemming is offline
  5. Старый комментарий
    Аватар для Gustav

    Использование OWC Spreadsheet в диалоге

    А вот и модифицированный код:
    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));
            }
        }
    }
    Весь код метода, наверное, не так интересен - хотя бы потому, что его невозможно запустить в автономном режиме как джоб. Тем не менее, я привожу его полностью - хотя бы потому, что замена несущественного в рамках темы кода на комментарии вида "// bla-bla-bla" представляет собой дополнительную работу, которую мне делать не хочется

    В интересующих нас в данный момент строчках кода, относящихся к 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 is offline
    Обновил(-а) Gustav 16.10.2009 в 17:55
  6. Старый комментарий
    Аватар для Gustav

    Контроль возможности создания журнала

    Цитата:
    Сообщение от Кирилл Просмотреть комментарий
    А пользователям удобно каждый раз залезать в Сервис/Параметры чтобы снять фильтр по филиалу?
    И потом еще раз, чтобы вернуть фильтр.
    Может на форме галочку добавить "А можно всех посмотреть?"?
    Да, вроде, не жаловались пользователи, что им неудобно. Галочку на форму добавить, конечно, не вопрос, но так можно огрести доп.работу самому себе - пользователи увидят галочку на одной форме и захотят на других.

    А так они просто знают, что для смены филиала им надо выполнить такую-то команду, находящуюся в интерфейсе там-то. Не так же трудно щёлкнуть по "Сервис", а потом по "Параметры"? А далее даже сделано такое облегчение: им не надо раскрывать список филиалов в 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 Gustav is offline
  7. Старый комментарий

    Контроль возможности создания журнала

    А пользователям удобно каждый раз залезать в Сервис/Параметры чтобы снять фильтр по филиалу?
    И потом еще раз, чтобы вернуть фильтр.
    Может на форме галочку добавить "А можно всех посмотреть?"?
    Запись от Кирилл размещена 14.10.2009 в 16:32
    Обновил(-а) Кирилл 14.10.2009 в 16:36
  8. Старый комментарий

    Функция определения рабочего статуса дня

    Да, это - исключительно советское извращение. (Я называю это извращением потому, что заранее со 100%-ой вероятностью не знаешь, работаешь ли в выбранный день в будущем, или нет.) Если в Австрии праздник попадает на выходной, то считай, не повезло. А алгоритм пришлось бы расширять на вычисление Пасхи и Троицы.
    Запись от EVGL размещена 02.10.2009 в 16:51 EVGL is offline
    Обновил(-а) EVGL 02.10.2009 в 16:54
  9. Старый комментарий
    Аватар для Gustav

    Функция определения рабочего статуса дня

    Евгений, ну так... запустить ее в цикле за год без блока "исключений" и сгенерить календарь, нет?

    Руками потом, да - информация о новых исключениях все равно обычно появляется тогда, когда календари на след. год в системах уже в основном заготовлены.

    Кстати, в Австрии тоже есть такие сдвиги выходных из-за праздников, попавших на уик-энд? Или это исключительно российская особенность?
    Запись от Gustav размещена 01.10.2009 в 18:53 Gustav is offline
  10. Старый комментарий

    Функция определения рабочего статуса дня

    Упражнение в программировании, не более того. Определенный интерес представляла бы функция, которая генерировала бы календарь по этой схеме, а "исключения" заносились бы руками в готовый календарь.
    Запись от EVGL размещена 29.09.2009 в 20:59 EVGL is offline
  11. Старый комментарий
    Запись от mazzy размещена 08.09.2009 в 14:35 mazzy is offline
  12. Старый комментарий
    Аватар для Gustav

    Функция определения рабочего статуса дня

    Собственно я прервал предыдущий пост, потому что напоролся на ограничение в 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 is offline
    Обновил(-а) Gustav 28.08.2009 в 16:11
  13. Старый комментарий
    Аватар для Gustav

    Оставьте комментарии к этому посту

    Цитата:
    Сообщение от Ruff Просмотреть комментарий
    Зашел в "управление блогом", насоздавал там 5 страниц, и мне сказали "хватит с тебя"... Чувствую, что это было что-то не то
    Добавление записей пока смертным не доступно, правильно я понимаю?
    Не, страницы это какая-то другая хрень, это еще не осваивалось. А запись (тему) можно создать так: Мой кабинет \ Блог \ Ваш блог \ Новая запись.

    И обратите внимание - внизу есть поле статус записи, которое можно сначала выставить как черновик и запись не будет отображаться, т.е. ее можно пописать в несколько приемов, а потом предъявить общественности уже отшлифованное творение.

    Но вообще согласен. Не всё здесь так очевидно, как хотелось бы
    Запись от Gustav размещена 24.08.2009 в 18:52 Gustav is offline
  14. Старый комментарий
    Аватар для Ruff

    Оставьте комментарии к этому посту

    то ль лыжи не едут...

    Граждане, а как свои записи добавлять? Я чего-то не врубился Зашел в "управление блогом", насоздавал там 5 страниц, и мне сказали "хватит с тебя"... Чувствую, что это было что-то не то
    Добавление записей пока смертным не доступно, правильно я понимаю?
    Запись от Ruff размещена 21.08.2009 в 22:29 Ruff is offline
    Обновил(-а) Ruff 22.08.2009 в 02:02
  15. Старый комментарий
    Аватар для Gustav

    Я осваиваю Office 2007

    Цитата:
    Сообщение от mazzy Просмотреть комментарий
    ...из тулбара...
    Теперь, вроде, модно называть это лентой
    Цитата:
    Сообщение от mazzy Просмотреть комментарий
    еще можно сказать, что закладки вверух переключаются колесом мыши.
    Да, клёво! Заодно напомню (это, правда, было и раньше, но, может, кто еще не знает), что при вращении колеса мыши при удерживаемой клавише Ctrl изменяется масштаб. Масштаб теперь можно менять и более явно - при помощи ползунка в строке состояния, а управляется отображение этого ползунка из контекстного меню строки состояния (из того же, которое управляет отображением агрегатных функций)
    Запись от Gustav размещена 21.08.2009 в 09:48 Gustav is offline
  16. Старый комментарий
    Аватар для mazzy

    Я осваиваю Office 2007

    еще можно сказать, что закладки вверух переключаются колесом мыши.

    а также стоит упомянуть о том, что любимые иконки из тулбара можно (и нужно) помещать наверх в панель быстрого доступа (правой кнопкой мыши на любой иконке). Я например, всегда кнопку Preview туда вешаю.
    Запись от mazzy размещена 20.08.2009 в 17:57 mazzy is offline
  17. Старый комментарий
    Аватар для mazzy

    Я осваиваю Office 2007

    вроде у Майкрософта есть Microsoft Office Compatibility Pack for Word, Excel, and PowerPoint 2007 File Formats для 2003 офиса.
    этот апдейт позволяет читать форматы 2007 офиса, не выходя из 2003.
    Запись от mazzy размещена 20.08.2009 в 17:55 mazzy is offline
  18. Старый комментарий
    Аватар для Gustav

    Контроль возможности создания журнала

    Цитата:
    Сообщение от player Просмотреть комментарий
    Отчего столь содержательное обсуждение не выносится в форум? И как быть с разрастанием информационного поля, т.е. если раньше достаточно было мониторить форум, то теперь еще и блоги шерстить? Есть ли глобальный поиск по контенту (форум+блоги)?
    Думаю, что не выдам страшную тайну, сказав о том, что эти вопросы уже поднимались в модераторских кулуарах и даже зафиксированы в плане на доработку. Функционал блогов проходит обкатку, поэтому блоги пока и не афишируются широко. Но не писать же все время тестово о погоде или ау-ау. Вот я и решил начать писать по существу - надо же посмотреть, как будет выглядеть в блоге реальное обсуждение по профессиональной тематике.
    Запись от Gustav размещена 11.08.2009 в 11:24 Gustav is offline
  19. Старый комментарий

    Контроль возможности создания журнала

    Отчего столь содержательное обсуждение не выносится в форум? И как быть с разрастанием информационного поля, т.е. если раньше достаточно было мониторить форум, то теперь еще и блоги шерстить? Есть ли глобальный поиск по контенту (форум+блоги)?
    Запись от player размещена 11.08.2009 в 07:20 player is offline
  20. Старый комментарий

    Контроль возможности создания журнала

    Цитата:
    Сообщение от Gustav Просмотреть комментарий
    А вот чего-то все равно не получилось: вставил return false; и запись журнала спокойно создалась...
    Посмотрел в код и вот, что обнаружил, в методе construct класса JournalTableData, содержится некий список таблиц
    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);
        }
    }
    Так вот, во всех, перечисленных таблицах, кроме LedgerJournalTable, метод validateWrite содержит вызов :
    X++:
    ret = _journalTableData.validateWritePre(ret);
    Для сравнения залез в AX 4.0 и бинго! данный вызов имеется и на таблице LedgerJournalTable.

    Так что по всей видимости для AX 3.0 наблюдается баг, в отношении создания журналов.

    Думаю, если добавить данный вызов и в AX 3.0 в метод validateWrite таблицы LedgerJournalTable, то можно использовать JournalTableData\validateWritePre, причем, этим способом можно защиться и в случае, когда журнал создается из кода, конечно, если идет вызов метода validateWrite
    Запись от SRF размещена 03.08.2009 в 12:15 SRF is offline


Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 05:10.