04 апр. 2014 г.

Пролог

Аналогов в Беларуси просто нет. Ниже приведен фрагмент кода программы расчета заработной платы на языке Prolog . Работает в режиме промышленной эксплуатации на двух крупных предприятиях (более 1000 работников на каждом).

% среднедневной заработок по сотруднику (по среднечасовому)
% - для отпусков
calc_avg_wage(Scope, PK, AvgWage, Rule) :-
Rule = by_avg_houre,
% правило действительно
is_valid_rule(Scope, PK, _, Rule),
% подготовка временных данных для расчета
prep_avg_wage(Scope, PK, Periods),
% взять заработок
findall( Wage,
% за каждый период проверки
( member(Y1-M1, Periods),
% взять данные по заработку
get_month_wage(Scope, PK, Y1, M1, _, Wage) ),
% в список заработков
Wages ),
% итоговый заработок
sum_list(Wages, Amount),
% взять часы
findall( THoures,
% за период проверки
( member(Y2-M2, Periods),
% взять данные по часам за месяц
get_month_norm_tab(Scope, PK, Y2-M2, _, _, _, THoures)
),
% в список часов
Durations),
% всего часов по табелю
sum_list(Durations, TotalTab),
% среднечасовой заработок
catch( AvgHoureWage is Amount / TotalTab, _, fail ),
% разложить первичный ключ
PK = [pEmplKey-EmplKey, pFirstMoveKey-FirstMoveKey],
% всего часов по графику за расчетный год
get_data(Scope, in, usr_wg_TblYearNorm, [
fEmplKey-EmplKey, fFirstMoveKey-FirstMoveKey,
fWHoures-TotalNorm]),
% среднемесячное количество расчетных рабочих часов
AvgMonthNorm is TotalNorm / 12,
% среднемесячное количество календарных дней
get_param(Scope, in, pAvgDays-AvgDays),
% среднедневной заработок
catch( AvgWage0 is AvgHoureWage * AvgMonthNorm / AvgDays, _, fail ),
AvgWage is round(AvgWage0),
!.

03 апр. 2014 г.

Как избежать расхождений при делении и последующем округлении массы единицы сырья или товара

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

Пример: учет ведется с точностью до 0.1 кг, на весы загнали три единицы и получили общую массу 511.1 кг. Простое деление даст нам 170.3666666666667 кг на единицу или 170.4 кг после округления. Когда в итоговом отчете три единицы посуммируются получится 511.2 кг, т.е. возникнет расхождение с исходными показаниями весов.

Правильно в данном случае поступить следующим образом:

  1. Общую массу перевести в целочисленное количество минимальных единиц. В нашем случае такой единицей будет 0.1 кг, соответственно,
    511.1 кг = 5111 по 0.1 кг
  2. Целочисленно разделить полученное число на количество единиц в партии:
    5111 div 3 = 1703 = D
  3. Вычислить остаток от целочисленного деления:
    5111 mod 3 = 2 = M
  4. Для произвольных M единиц в партии принять учетную массу (D + 1) для остальных -- D.
Т.е. в нашем случае получится следующая учетная масса каждой единицы в партии:
  1. (1703 + 1) * 0.1 = 170.4 кг
  2. (1703 + 1) * 0.1 = 170.4 кг
  3. 1703 * 0.1 = 170.3 кг
В сумме -- ровно 511.1 кг.

01 апр. 2014 г.

На заметку. Если в процедуре встретится конструкция:
...
INSERT INTO table1 
  SELECT * FROM table2;
...
то возникнет зависимость между процедурой и всеми полями из table2, хотя они тут и не прописаны явно.

21 марта 2014 г.

Архивирование удаленного SVN репозитория

На случай ядерной войны (как бы грустно не звучало, но это теперь не шутка) решили подстраховаться и локально заархивировать наш проект с code.google.com. Действия не сложные, может кому пригодятся:
  1. Понадобятся утилиты командной строки SVN. На официальном сайте доступны несколько пакетов для Windows, в которых нам было лень разбираться, поэтому мы просто переустановили TortoiseSVN, указав в процессе галку Устанавливать утилиты командной строки.
  2. Запускаем режим командной строки и идем в папку C:\Program Files\TortoiseSVN\bin
  3. Создаем локальный репозиторий:
    svnadmin create c:\temp\gedemin_svn
  4. Теперь надо в папке c:\temp\gedemin_svn\hooks создать пустой файл pre-revprop-change.bat. Это похоже на вуду, но так надо.
  5. Указываем откуда мы будем синхронизировать данные:
    svnsync init file:///c:/temp/gedemin_svn https://gedemin.googlecode.com/svn/trunk/. Обратите внимание на слэши в обратную сторону (юникс стайл) и их количество.
  6. И запускаем процесс:
    svnsync sync file:///c:/temp/gedemin_svn
  7. Ждем...
  8. По окончании, для проверки, можно создать чистую папку и с помощью TortoiseSVN чек-аутнуть туда проект из нашего локального репозитория. Для этого указываем источник file:///c:/temp/gedemin_svn.
  9. Последующие запуски команды svnsync sync file:///c:/temp/gedemin_svn через день, неделю, месяц, будут загружать только изменения, скомиченные на сервер с момента последней синхронизации.

Неограниченное наследование бизнес-классов

Задачу можно разбить на следующие шаги:
  1. Разобраться с таблицей gd_documenttype. Есть ли в ней ограничения на вложения одного типа в другой? Убрать.
  2. Разобраться с бизнес объектом TgdcDocumentType и его экранными формами. Есть ли там, код, который препятствует вложению типов документов? Есть ли там экранные элементы, которые позволяют просматривать\выбирать родительский тип? Работает ли перетаскивание в дереве?
  3. Разобраться с деревом классов в Проводнике из Редактора скрипт-объектов. Оно должно отображать, загружать, сохранять методы классов в случае неограниченной вложенности.
  4. Разобраться с механизмом вызова наследованных методов в Гедымине. Расставить точки останова. Изучить как и в какой последовательности вызывается и взаимодействует между собой код VBScript и Delphi. Реализовать вызов наследованного кода в случае неограниченной вложенности бизнес-классов.
  5. Разобраться с механизмом загрузки экранных форм. Доработать его для поддержки вложенности бизнес-классов.
  6. Разобраться с механизмом привязки ТХО и ТП к конкретному классу. Определить необходимость вызова наследованного кода и (если надо) реализовать его.
Поле DISABLED должно быть не булевским, а целочисленным со следующими значениями:
  • 0 -- запись полностью отключена. Нигде не показывается, нигде не выбирается. Это вариант, когда запись надо полностью убрать, но удалить из БД нельзя из-за ссылочной целостности.
  • 1 -- запись доступна везде.
  • 2 -- запись недоступна для выбора при создании\изменении объекта, но везде отображается и доступна для выбора в параметрах отчетов и фильтров.
  • 3 -- запись отображается, но не доступна нигде для выбора.

15 марта 2014 г.

В Беларуси разрешено использовать электронные товарно-транспортные накладные

Скоро в Гедымине:

В Беларуси разрешено использовать электронные товарно-транспортные накладные. Это предусмотрено постановлением Совета Министров Беларуси №202 от 7 марта 2014 года "О создании товарно-транспортных и товарных накладных в виде электронных документов", который опубликован на Национальном правовом интернет-портале Беларуси, сообщает БЕЛТА.

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

В постановлении отмечено, что передача и получение электронных накладных осуществляются EDI-провайдерами, резидентами Беларуси, получившими в установленном законодательством порядке аттестат оператора электронного документооборота. Информация об EDI-провайдерах, получивших в установленном законодательством порядке аттестат оператора электронного документооборота, размещается в глобальной компьютерной сети Интернет на официальном сайте научно-инженерного республиканского унитарного предприятия "Межотраслевой научно-практический центр систем идентификации и электронных деловых операций" НАН Беларуси, указано в документе.

Кроме того, в постановлении определены обязанности EDI-провайдеров. Они должны обеспечить: соблюдение законодательства в сфере обращения электронных документов, возможность круглосуточного и бесперебойного осуществления получения, передачи электронных накладных, наличие программно-аппаратных средств, расположенных на территории Беларуси и реализующих электронный документооборот в утвержденных форматах и порядке, защиту и хранение информации об электронных накладных, круглосуточное предоставление налоговым органам информации об электронных накладных, а также иных электронных документах и сообщениях, необходимых для обеспечения создания электронных накладных, посредством удаленного доступа к информационной системе (системам) электронного документооборота.

08 марта 2014 г.

Україно, ми з тобою!

23 февр. 2014 г.

К нам на сайт вот-вот заглянет миллионный посетитель!

19 февр. 2014 г.

I Am A Ukrainian

Из этих людей можно делать гвозди

Руками остановить БТР. Никто не победит народа, который сражается за свою свободу.

10 февр. 2014 г.

Циклическое сканирование таблиц документов

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

Пусть, H1, H2, H3... HN -- таблицы шапок документов и связанные с ними 1-к-1 (или "нашей" связью 1-к-1, как в USR$INV_ADDINFO). P1, P2, P3... PN -- таблицы позиций документов и связанные с ними 1-к-1. H1K1, H1K2... H1KN -- поля ссылки на документ в таблице H1. P1K1, P1K2... P1KN -- поля ссылки на документ в таблице P1.

Тогда алгоритм выглядит следующим образом:

  1. Формируем массив ИД документов, которые остаются в БД:

    SELECT SUM(g_his_add(1, id))
    FROM gd_document
    WHERE documentdate >= :D


    Обратите внимание, что и шапки и позиции сразу попадут в выборку, так как у позиции документа дата обязательно совпадает с шапкой.
  2. Организуем цикл по таблицам H. Для каждой формируем и выполняем запрос:

    SELECT
    SUM(g_his_add(1, HjK1)),
    COUNT(HjK1),
    SUM(g_his_add(1, HjK2)),
    COUNT(HjK2),
    ...
    FROM Hj
    WHERE g_his_has(1, documentkey)


    Важно собрать все поля в один запрос, чтобы обойтись только одним сканом таблицы.

  3. Для позиций:

    SELECT
    COUNT(*), SUM(g_his_add(1, documentkey)),
    SUM(g_his_add(1, PjK1)),
    COUNT(PjK1),
    SUM(g_his_add(1, PjK2)),
    COUNT(PjK2),
    ...
    FROM Pj
    WHERE g_his_has(1, masterkeykey)


  4. Если после обработки всех таблиц шапок и всех позиций, все суммы сложились в ноль, то значит ни одной записи не добавилось к сохраняемому множеству ИД. Если больше нуля, то повторяем, начиная с шага 2.
  5. Если после обработки таблицы мы получили:

    COUNT(HjKi)- SUM(g_his_add(1, HjKi)) = 0

    То такую колонку исключаем из дальнейшей обработки. Если в таблице исключены все колонки, то в дальнейшем такую таблицу не обрабатываем.