мета-данные страницы
Описание формы
За написание и тестирование скриптов (как ДС, так и ВДС) отвечает модуль TestingScripts.pas с соответствующим классом TTestingScripts
В этом классе для определения вида скрипта отвечает поле scriptType. Это поле в дальнейшем отвечает за всё остальное поведение формы.
В зависимости от вида скрипта открывается та или иная страница на pcTypeScript, содержащие в себе нужные сценарии проверки.
Все страницы взаимодействуют с основными контролами класса TAgbMemo - поле ввода mScript и результат его работы mResult.
Форму ни в коем случае нельзя закрывать с сохранением данных, если были внесены изменения в mScript и они не прошли сценарий проверки.
Отработка написанных скриптов
При выполнении скриптов ДС-ВДС (как для проверки, так и в режиме работы из заказа) задействуются функции из модуля UDiscountTools. Все расчёты в конечном счёте приведут именно к ним.
// выполняет скрипт расчёта скрипта ВДС; function ExecuteExternalDiscScript(doc_id: int64; script: string; var errScripts: string; AUpTr: TpFIBTransaction; out ExtScriptResInfo: TExtScriptResInfo): Double; // выполняет скрипт расчёта скрипта ДС. function ExecuteSimpleDiscScript(AContrID, ATovarID:int64; Control:Integer; ASchemeID: variant; showException: boolean ; script, Dat: string; var errScripts: string; ARdTr, AUpTr: TpFIBTransaction):double;
Основная разница у них в перечне входных и выходных параметров.
Скрипт ВДС передаёт принимает 1 параметр doc_id (ВнНомер документа заказа), возвращает количество бонусов для начисления и целый блок дополнительной информации, содержащийся в ExtScriptResInfo.
Скрипт ДС передаёт принимает 3 параметра - ID клиента, ID товара и ссылку на контрол из формы заказа. Возвращает размер скидки на конкретную позицию по клиенту.
Общий принцип их работы таков:
1. В модуле UDiscountTools Создаётся объект класса TScriptExecutor se, в конструктор передаётся записывающая транзакция;
se := TScriptExecutor.Create(_UpTr);
2. В модуле ScriptFunctions Конструктор TScriptExecutor создаёт объект PSScript паскалевского скриптера класса TPSScript из библиотеки uPSComponent;
PSScript:=TPSScript.Create(Nil);
3. В модуле UDiscountTools Запускается попытка скомпилировать скрипт se.CompileScript(script, true, errScripts). В случае неудачного выполнения будет возвращен False, а errScripts будет содержать в себе список ошибок;
if not se.CompileScript(script, true, errScripts) then raise EExternal.Create('Ошибка выполнения скрипта расчёта скидки!');
4. В модуле ScriptFunctions При компиляции в объект PSScript передаётся текст скрипта и запускается его компиляция:
PSScript.Script.Text:=Script; Result:=PSScript.Compile;
5. В модуле ScriptFunctions В случае неуспешной компиляции объект PSScript будет иметь в себе заполненные поля PSScript.CompilerMessageCount (количество сообщений) и коллекцию PSScript.CompilerMessages сами сообщения об ошибках), из которых потом и собирается итоговая строка со списком ошибок;
if not Result then begin for i:=0 to PSScript.CompilerMessageCount-1 do begin if showMSG then SimpleMessage(PSScript.CompilerMessages[i].MessageToString); if messages = '' then messages := PSScript.CompilerMessages[i].MessageToString else messages := messages + #13#10 + PSScript.CompilerMessages[i].MessageToString; end; end;
6. В модуле UDiscountTools определяется наличие заголовка GetDiscount:
ProcNo := se.PSScript.Exec.GetProc('GetDiscount'); if ProcNo = InvalidVal then errScripts := 'Unknown procedure GetDiscount'
7. В модуле UDiscountTools если такой заголовок был найден (ProcNo <> InvalidVal), то пытается выполниться сам скрипт с переданным в него массивом входящих параметров (на примере ДС). Выполнение делается в try..except, а ошибки при выполнении записываются в errScripts :
try Result := se.PSScript.ExecuteFunction([AContrID,ATovarID,Control],'GetDiscount'); except on E: EFIBError do errScripts := E.IBMessage; on E:Exception do errScripts := E.Message; end;
Какими функциями и процедурами можно пользоваться при написании скриптов
После создания объекта PSScript ему, в конструкторе класса TScriptExecutor, присваиваются обработчики для импорта тех или иных функций. Это делается так:
PSScript.OnExecImport:=ClassesPluginExecImport; - здесь регистрируются классы, типы и методы, которые используются в рантайме; PSScript.OnCompImport:=ClassesPluginCompImport; - здесь регистрируются базовые классы, типы и методы, которые используются при компиляции.
Также для рантайма и компиляции мы дополнительно регистрируем ряд функций и методов, передавая соответствующие адреса и названия, которые планируется использовать в скрипте. В качестве методов мы сейчас берём работу с базой данных, т.к. класс TScriptExecutor содержит в себе транзакцию для работы с ней.
Регистрация методов и функций для рантайма делается так:
exec.RegisterDelphiMethod(Self, @TScriptExecutor.FastSQLVal,'FastSQLVal', cdRegister); exec.RegisterDelphiFunction(@DaysBetween,'DaysBetween', cdRegister);
Регистрация остальных, кастомных методов и функций для компиляции делается в обработчике TScriptExecutor.PSScriptCompile:
Sender.AddMethod(Self, @TScriptExecutor.FastSQLVal,'Function FastSQLVal(Data: string):Variant'); Sender.AddFunction(@DaysBetween,'function DaysBetween(ANow, AThen: TDateTime): Integer');
Все базовые функции и методы, на которые мы ссылаемся при регистрации, должны иметь реализацию в своих соответствующих модулях, доступ к которым должен быть из класса TScriptExecutor. Так, функция DaysBetween объявлена в модуле DateUtils.
Также стоит обязательно обратить внимание на данную статью:
https://doc.agb.is/special_params_in_scripts
Пройти тест можно по ссылке: