Příklady pokročilého skriptování
Tato kapitola doplňuje obecný úvod do problematiky skriptování v systému ABRA Gen o ukázky pokročilých praktických příkladů.
Pokročilé příklady skriptování
Příklady skriptování pro pokročilé
 Vrácení první hodnoty z SQl dotazu (SQLSelectFirst)
Vrácení první hodnoty z SQl dotazu (SQLSelectFirst)
                                                        Funkce SQLSelectFirst slouží na vrácení prvního řádku výsledku SQL dotazu. 
Konkrétně se jedná o funkce SQLSelectFirstAsString , SQLSelectFirstAsInteger, SQLSelectFirstAsExtended, SQLSelectFirstAsBlob
Příklad použití:
..
mBlob:=Self.ObjectSpace.SQLSelectFirstAsBlob('SELECT NOTE FROM FIRMS'); //Vrátí hodnotu jako TBytes
mString:=Self.ObjectSpace.SQLSelectFirstAsString('SELECT NAME FROM FIRMS'); //Vrátí hodnotu jako String
mInt:=Self.ObjectSpace.SQLSelectFirstAsInteger('SELECT CODE FROM FIRMS'); //Vrátí hodnotu jako Integer
mExt:=Self.ObjectSpace.SQLSelectFirstAsExtended('SELECT PENALTYPERCENT FROM FIRMS'); //Vrátí hodnotu jako Extended
						
//Hodnoty po provedení funkce jsou následující
//mBlob = ABRA Software a.s. je technologická firma...
//mString = ABRA Software a.s.
//mInt = 00001
//mExt = 1,25
.. Převod ČASu na Unixtime (DateTimeToUnix)
Převod ČASu na Unixtime (DateTimeToUnix)
                                                        Na převod času na UnixTime slouží funkce DateTimeToUnix.
Příklad použití:
..
mDateTimeNow1:= DateTimeToUnix(Now(), True); //vrací výsledek UnixTime s časovým posunem
mDateTimeNow2:= DateTimeToUnix(Now(), False); //vrací výsledek UnixTime v UTC 
//Hodnoty po provedení funkce jsou následovný
//mDateTimeNow1 = 1665079779
//mDateTimeNow2 = 1665072579
.. Parametrizovatelné SQL (SQLSelect, SQLSelect2 a SQLExecute) SQL Input Params
Parametrizovatelné SQL (SQLSelect, SQLSelect2 a SQLExecute) SQL Input Params
                                                        Od verze 19.4.3 je možné používat parametrizované SQL dotazy ze skriptování. Používání parametrů v SQL je snadnější, bezpečnější a pro SQL servery i rychlejší na vykonání díky cachování plánů SQL dotazů. Přes parametry lze snadno a bezpečně přenést libovolný datový typ, tedy i binary blob data.
Příklad použití parametrů při vykonávání SQL dotazů (SQLExecute):
UPDATE GlobData SET DueTerm = :DueTerm, Logo = :Logo..
mInputParams := TNxParameters.Create;
try
  mInputParams.NewFromDataType(dtInteger, 'DueTerm').AsInteger := 10;
  mRawParameter := TNxRawParameter(mInputParams.NewFromDataType(dtVarBytes, 'Logo'));
  mStream := TMemoryStream.Create;
  try
    mStream.SetBytes(cBytes);
    mRawParameter.LoadDataFromStream(mStream);
  finally
    mStream.Free;
  end; 
  mRowsAffected := ObjectSpace.SQLExecute('UPDATE GlobData SET DueTerm = :DueTerm, Logo = :Logo', mInputParams);
  FxCheckValue_Integer(mRowsAffected, 1, 'nebyl modifikován jeden záznam');
finally
  mInputParams.Free;
end;
..Příklad použití parametrů při získávání dat z databáze (SQLSelect, SQLSelect2):
SELECT DueTerm FROM GlobData WHERE ID = :ID..
mInputParams := TNxParameters.Create;
try
  mInputParams.NewFromDataType(dtString, 'ID').AsString := cCompanyGlobDataID;
  mSQLResult := TStringList.Create;
  try
    ObjectSpace.SQLSelect('SELECT DueTerm FROM GlobData WHERE ID = :ID', mSQLResult, mInputParams);
    FxCheckValue_String(mSQLResult.Text, '10' + #13#10, 'nedošlo k modifikaci dat nebo došlo k chybnému přečtení');
  finally
    mSQLResult.Free;
  end;
  mMemTable := TMemTable.Create(nil);
  try
    ObjectSpace.SQLSelect2('SELECT DueTerm, Logo FROM GlobData WHERE ID = :ID', mMemTable, mInputParams);
    FxCheck(mMemTable.RecordCount = 1, 'mMemTable.RecordCount <> 1');
    mMemTable.First;
    mMemTable.Next;
    FxCheckValue_Integer(mMemTable.FieldByName('DueTerm').AsInteger, 10, 'DueTerm <> 10');
    FxCheckValue_TBytes(mMemTable.FieldByName('Logo').AsBytes, cBytes, 'Logo <> 0x0102...FF');
  finally
    mMemTable.Free;
  end;
finally
  mInputParams.Free;
end;
.. použití funkce na dohledání placeného dokladu (FindPaymentDestByVarsymb)
použití funkce na dohledání placeného dokladu (FindPaymentDestByVarsymb)
                                                        Funkce FindPaymentDestByVarsymb slouží na na dohledání placeného dokladu.
function NxFindPaymentDestinationsByVarSymb(
  AObjectSpace: TNxCustomObjectSpace;
  ACredit: Boolean; AVarSymbol: string; ADocTypes, AOIDS: TStrings;
  AFlag, AFlagForOneFound: Integer; AAmount: Extended; ACurrency_ID: String;
  AFirm_ID: TNxOID)';
Popis parametrů:
// AObjectSpace			ObjectSpace
// ACredit				True/False typ platby Kredit/Debet 
// AVarSymbol			Hledaný variabilní symbol
// ADocTypes			TStrings do kterých funkce vrací typ dohledaných dokladů
// AOIDS				TStrings do kterých funkce vrací OID dohledaných dokladů
// AFlag				Příznak jak dohledávat podle částky a zaplacení
// 						-1 - Vrátit vše vyhovující dle VS bez ohledu na stav zaplacení a částku - ignoruje nastavení parametrů v agendě Firemní údaje 	 
// 			 		 	 0 - Vrátit vyhovující dle VS, částky a stavu zaplacení s ohledem na nastavení parametrů v agendě Firemní údaje 	
// AFlagForOneFound 	Příznak jak dohledávat podle částky
// 					 	 0 - Musí vyhovovat jen VS
// 					 	 1 - Musí vyhovovat VS i částkaa měna placeného dokladu 
// AAmount				Částka - když je 0, nebere se při vyhledávání na částku zřetel
// ACurrency_ID			Měna
// AFirm_ID				Firma - pokud je vyplněno, při vyhledávání se bere zřetel i na firmu na dokladuPříklad použití:
procedure find_payment_destination_by_varsymb(
  ACredit: Boolean; AVarSymb: string; AAmount: EWxtended;
  mFlag, mFlagForOneFound: Integer;
  ACurrency_ID, AFirm_ID: TNxOID);
var
  mObjectSpace: TNxCustomObjectSpace;
  mDocTypes, mOIDs: TStrings;
begin
  ... 
  mOIDs := TStringList.Create;
  try
    mDocTypes := TStringList.Create;
    try
      NxFindPaymentDestinationsByVarSymb(
        mObjectSpace, ACredit, AVarSymb, mDocTypes, mOIDS, AFlag, AFlagForOneFound,
        AAmount,  ACurrency_ID, AFirm_ID);
        // V StringListech mDocTypes a mOIDS jsou vráceny identifikace dohledaných dokladů (Typ dokladu a OID)
        ...
    finally
      mDoctypes.Free;
    end;
  finally
    mOIDs.Free;
  end;
end; použití metod na práci s ručním párováním dokladů (PairingByHand)
použití metod na práci s ručním párováním dokladů (PairingByHand)
                                                        Jde o následující metody třídy TNxCustomAccountedDocument:
function AttachSourceGroup(const ASourceGroup_ID: TNxOID);
function RemoveSourceGroup(const ASourceGroup_ID: TNxOID);
function IsSourceGroupAttached(const ASourceGroup_ID: TNxOID): Boolean;
function GetSourceGroup: TNxOID;Příklad použití:
procedure pair_it;
var
  mReceivedInvoice, mReceiptCard: TNxCustomBusinessObject;
  mSourceGroup_ID: TNxOID;
begin
  ...
  // Připojení dokladu do ručního párování
  // Zde připojujeme existující příjemku do párovací skupiny faktury přijaté
  mSourceGroup_ID := TNxCustomAccountedDocument(mReceiptCard).GetSourceGroup;
  TNxCustomAccountedDocument(mReceivedInvoice].AttachSourceGroup(mSourceGroup_ID);
  mReceivedInvoice.Save;  // !!! POZOR - Připojení se projeví až po Save objektu
  ...
  // Odpojení dokladu z ručního párování
  // Zde odpojujeme již připojenou příjemku z párovací skupiny faktury přijaté
  mSourceGroup_ID := TNxCustomAccountedDocument(mReceiptCard).GetSourceGroup;
  TNxCustomAccountedDocument(mReceivedInvoice].RemoveSourceGroup(mSourceGroup_ID);
  mReceivedInvoice.Save;  // !!! POZOR - Odpojení se projeví až po Save objektu
  ...
  // Zjištění, zda je dokument připojen v ručním párování
  // Zde zjišťujeme zda je příjemka připojena do párovací skupiny faktury přijaté
  mSourceGroup_ID := TNxCustomAccountedDocument(mReceiptCard).GetSourceGroup;
  if TNxCustomAccountedDocument(mReceivedInvoice].IsSourceGroupAttached(mSourceGroup_ID) then
  begin
    ...
  end;
  ...
end; Přidání řádku do rozeditovaného dokladu
Přidání řádku do rozeditovaného dokladu
                                                        Ukázkový skript, který přidá řádek do rozeditovaného dokladu: 
{
Přidání řádku do rozeditovaného dokladu
}
procedure InsertRow(Sender : TButton);
var
  mSite: TSiteForm;
  mControl: TControl;
  mDataset: TNxRowsObjectDataSet;
  mRow: TNxCustomBusinessObject;
begin
  try
    mSite := TComponent(Sender).Site;
    mControl:= mSite.FindChildControl('tabRows.grdRows');
    mDataset := TNxRowsObjectDataSet(TMultiGrid(mControl).DataSource.DataSet);
    if Assigned(mDataset) then
    begin
      mDataSet.DisableControls;
      mRow := mDataSet.CreateBusinessObject;
      mRow.Prefill;
      mRow.SetFieldValueAsInteger('RowType',3);
      mRow.SetFieldValueAsInteger('PosIndex',1);
      mRow.SetFieldValueAsString('Store_Id','2100000101');
      mRow.SetFieldValueAsString('Division_ID','2100000101');
      mRow.SetFieldValueAsString('Storecard_Id','2100000101');
      mRow.SetFieldValueAsFloat('Quantity', 1);
    end;
  finally
    TDynSiteForm(mSite).ActiveDataSet.UpdateFields; //Aby se o změně dozvěděl hlavičkový dataset
    mDataset.RefreshAndRestoreLastSelectedItem;
    mDataSet.EnableControls;
  end;
end;
{
Vyvolává se po vytvoření instance formuláře.
}
procedure FormCreate_Hook(Self: TSiteForm);
var
  mAction: TBasicAction;
  mMAction: TMultiAction;
begin
  // Vytorime novou jednoduchou akci
  mAction := Self.GetNewAction;
  mAction.ShowControl := True;
  mAction.ShowMenuItem := True;
  mAction.Caption := 'Přidání řádku';
  mAction.Hint := 'Přidání řádku a aktualizace datasetu';
  mAction.Category := 'tabDetail';
  mAction.OnExecute := @InsertRow;
end;
begin
end. Úpravy záložky X-vazby
Úpravy záložky X-vazby
                                                        1. Ukázkový skript, který umožňuje rozšířit seznam objektů na záložce X-vazby, a to jak přidáním objektů, tak i celých nových skupin objektů: 
{
Umožňuje rozšířit seznam objektů na záložce X-vazby, a to jak přidáním objektů, tak i celých nových skupin objektů. Doporučujeme přidávat objekty na obě strany, tedy jak na zdrojový, tak cílový objekt, poté uživatel uvidí např. na objektu typu A objekty typu B a také naopak z B uvidí A.
Ukázka skriptu rozšiřující X-vazby business objektu Sklad o skupinu Nabídky vydané a v ní všechny záznamy s pořadovým číslem 1. 
A dále o skupinu Skladové karty se záznamy s kódem začínajícím na 0.
}
procedure AddLinks(Self: TNxCustomBusinessObject; const AGroups, AObjects: TStringList; const ASite: TSiteForm);
var
  mInputParameters: TNxParameters;
  mIDs: TStringList;
  I: Integer;
begin
  AGroups.Add(Class_IssuedOffer + '=' + 'Nabídky vydané');
  mInputParameters := TNxParameters.Create;
  try
    mInputParameters.NewFromDataType(dtInteger, 'OrdNumber').AsInteger := 1;
    mIDs := TStringList.Create;
    try
      Self.ObjectSpace.SQLSelect('SELECT ID FROM IssuedOffers WHERE OrdNumber = :OrdNumber AND Revided_ID IS NULL', mIDs, mInputParameters);
      for I := 0 to mIDs.Count - 1 do begin
        AObjects.Add(Class_IssuedOffer + '=' + mIDs[I]);
      end;
    finally
      mIDs.Free;
    end;
  finally
    mInputParameters.Free;
  end;
  AGroups.Add(Class_StoreCard + '=' + 'Skladové karty');
  mInputParameters := TNxParameters.Create;
  try
    mInputParameters.NewFromDataType(dtString, 'StartWith').AsString := '0%';
    mIDs := TStringList.Create;
    try
      Self.ObjectSpace.SQLSelect('SELECT ID FROM StoreCards WHERE Code LIKE :StartWith AND Hidden = ''N''', mIDs, mInputParameters);
      for I := 0 to mIDs.Count - 1 do begin
        AObjects.Add(Class_StoreCard + '=' + mIDs[I]);
      end;
    finally
      mIDs.Free;
    end;
  finally
    mInputParameters.Free;
  end;
  // Lze použít i objekty definovatelných číselníků
  //AGroups.Add('1NPNI4M2JIVOFBV23CHPHFPN5W=Eshop - Číselníkové hodnoty vlastnosti skladové karty');
  //AObjects.Add('1NPNI4M2JIVOFBV23CHPHFPN5W=1000000101');
  // Ukázka prázdné skupiny
  //AGroups.Add(Class_IssuedOrder + '=Objednávky přijaté');
  //AGroups.Add(Class_Division + '=Střediska');
end;
begin
end.
2. Ukázkový skript, který umožňuje upravit poznámku zobrazovanou ve vizuálnu na záložce X-vazby.: 
{
  Ukázka skriptu pro business objekt Skladová karta. Na všech X-vazbách skladových karet přidá do poznámky EAN. V X-vazbách agendy Sklady navíc ještě přidává množství dle vybraného skladu.
}
procedure GetLinkDescription2_Hook(Self: TNxCustomBusinessObject; var Result: String; const ASite: TSiteForm);
var
  mObjectSpace: TNxCustomObjectSpace;
  mStoreID: String;
  mQuantity: Double;
begin
  if (ASite <> nil) then begin
    if (ASite.GetSiteCLSID = Site_Stores) and (TBusRollSiteForm(ASite).CurrentObject <> nil) then begin
      mObjectSpace := TBusRollSiteForm(ASite).BaseObjectSpace;
      mStoreID := TBusRollSiteForm(ASite).CurrentObject.GetFieldValueAsString('ID');
      mQuantity := mObjectSpace.SQLSelectFirstAsExtended('SELECT Quantity FROM StoreSubCards WHERE Store_ID = ' +
        QuotedStr(mStoreID) + ' AND StoreCard_ID = ' + QuotedStr(Self.GetFieldValueAsString('ID')));
      Result := NxTrim(Result + '; Quantity: ' + FloatToStr(mQuantity), ';');
    end;
  end;
  if Self.GetFieldCode('EAN') > 0 then
    Result := NxTrim(Result + '; EAN: ' + Self.GetFieldValueAsString('EAN'), ';');
end;
begin
end
3. Příklad založení uživatelské vazby ze skriptování: 
  {
  Ukázka části skriptu na vytvoření X-vazby v tabulce UserXLink mezi záznamy agend Objednávky přijaté -> Došlá pošta. Záznamy jsou označeny jako systémové.
  }
  mUserXLink := ObjectSpace.CreateObject(Class_UserXLink);
  try
    mUserXLink.New;
    mUserXLink.Prefill;
    mUserXLink.SetFieldValueAsString('SourceCLSID', Class_ReceivedOrder);
    mUserXLink.SetFieldValueAsString('Source_ID', mReceivedOrderID);
    mUserXLink.SetFieldValueAsString('DestinationCLSID', Class_PDMReceivedDoc);
    mUserXLink.SetFieldValueAsString('Destination_ID', mPDMReceivedDocID);
    mUserXLink.SetFieldValueAsBoolean('DisplayAsSystem', True);
    mUserXLink.Save;
  finally
    mUserXLink.Free;
  end;
   filtrování číselníků ze skriptingu (ONSELECTSQL_HOOK)
filtrování číselníků ze skriptingu (ONSELECTSQL_HOOK)
                                                        Háček umožňuje přímo ovlivnit SQL. Kdykoliv číselník potřebuje data z databáze, sestavuje se SQL. Háček se volá před sestavením SQL.
procedure OnSelectSQL_Hook(Self: TNxBusinessRoll; AParams: TNxParameters; ADSQL: TRollDynamicSQL; AKind: TRollOnSelectSQLKind);
//Self
//Číselník, pro který se háček vyvolal
//AParams
//Parametry, se kterými se číselník zavolal. AParams typicky připravuje CompleteRollValidateParams háček na BO. AParams jsou jenom pro čtení.
//ADSQL
//Prostředník pro úpravu SQL.
//AKind
//Informace, z jaké části číselníku se háček vyvolal
//sskPage - při získání stránky s daty
//sskWhisperer - při zobrazení našeptávače
//sskExists - Služba číselníku - LookUp
//sskOIDByPart - Služba číselníku - FindPart
//sskOID - Služba číselníku - CheckOnly
//sskAllID - Služba číselníku - GetIds
//sskOIDByPrefill - Služba číselníku - Prefill
//sskCorrectSelected - Služba číselníku - CorrectSelected'
 Příklad:
Chceme, aby uživatel Daniel Rasák (‘4300000101’) viděl pouze firmy s názvem začínajícím na A. (Jednoduchý příklad nad demodaty)
procedure OnSelectSQL_Hook(Self: TNxBusinessRoll; AParams: TNxParameters; ADSQL: TRollDynamicSQL; AKind: TRollOnSelectSQLKind);
begin
  if NxGetActualUserID(Self.ObjectSpace) = '4300000101' then
  begin
    // do WHERE doplníme SQL podmínku
    ADSQL.Where.Add('A.Name LIKE ''A%''');
  end;
end;Když není dostupný zdroj dat (tabulka), mohu si současně s podmínkou zdroj dat přidat:
Název aliasu volte s rozumem, nesmí kolidovat s existujícími.
Dejte si pozor, aby join nezmnožil řádky místo toho, aby je omezil.
procedure OnSelectSQL_Hook(Self: TNxBusinessRoll; AParams: TNxParameters; ADSQL: TRollDynamicSQL; AKind: TRollOnSelectSQLKind);
begin
  ADSQL.Joins.Add('MT', 'join MyTable MT on MT.ID = A.Tab_ID', 'MT.Code LIKE ''A%''')
end;Ve většině případů vystačíte s výše uvedenými příklady. 
Máme ale k dispozici ještě jednu variantu, která je složitá na pochopení, ale v určitých případech může zásadně ovlivnit rychlost provedení dotazu.
Jádro ji používá např. pro FULLTEXT.
Zkuste použít, pokud základní WHERE anebo JOIN+WHERE budou pomalé.
procedure OnSelectSQL_Hook(Self: TNxBusinessRoll; AParams: TNxParameters; ADSQL: TRollDynamicSQL; AKind: TRollOnSelectSQLKind);
begin
  ADSQL.Joins.Tweak.Add('select ID as Parent_ID from table');
end;Poddotaz musí splňovat tato kritéria:
- vracet jeden sloupec s názvem Parent_ID
- Parent_ID musí být ID z číselníku, ze kterého se získávají data (podmínka omezuje proti A.ID
- hodnoty Parent_ID musí být unikátní
 ovlivnit zobrazované záznamy v číselníku podle toho, z jakého místa se s číselníkem pracuje
ovlivnit zobrazované záznamy v číselníku podle toho, z jakého místa se s číselníkem pracuje
                                                        Příklad:
- rozpoznání místa objednávka přijatá řádek s ukázkou předání hodnoty z jiného pole
- rozpoznání X položky na řádku objednávky přijaté
- rozpoznání, že se jedná o vizuální editaci z definovatelného formuláře
Háček: Business objekt: Objednávka přijatá - řádek
procedure CompleteRollValidateParams_Hook(Self: TNxCustomBusinessObject; AFieldCode: integer; AParams: TNxParameters);
begin
  // Doplnění identifikace položky, pro kterou je číselník používán a tím umožnění v háčku OnSelectSQL_Hook číselníku zohlednění daného místa.
  if AFieldCode = Self.GetFieldCode('StoreCard_ID') then begin
    AParams.GetOrCreateParam(dtString, 'ObjPri_StoreCard_ID');
    // Navíc ukázka předání hodnoty jiného pole, které ovlivní výsledné omezení.
    AParams.GetOrCreateParam(dtString, 'ObjPri_Store_IDValue').AsString := Self.GetFieldValueAsString('Store_ID');
  end;
  if AFieldCode = Self.GetFieldCode('X_StoreCard_ID') then begin
    AParams.GetOrCreateParam(dtString, 'ObjPri_X_StoreCard_ID');
  end;
end;Háček: Číselník: Číselník skladových karet
procedure OnSelectSQL_Hook(Self: TNxBusinessRoll; AParams: TNxParameters; ADSQL: TRollDynamicSQL; AKind: TRollOnSelectSQLKind);
const
  cStorePraha = '2100000101';
begin
  if AParams.ParamExist('ObjPri_StoreCard_ID') and
    (AParams.GetOrCreateParam(dtString, 'ObjPri_Store_IDValue').AsString = cStorePraha) then begin
    // Příklad jen jednoduché karty, kterým název začíná na písmeno A
    ADSQL.Where.Add('A.Category = 0 AND A.Name LIKE ''A%''');
  end;
  if AParams.ParamExist('ObjPri_X_StoreCard_ID') then begin
    // Příklad jen karty se sériovými čísly
    ADSQL.Where.Add('A.Category = 1');
    if AParams.ParamExist('ObjPri_X_StoreCard_ID_FromDefForm') then begin
      // Omezení jek pokud je pole editováno z definovatelného formuláře. Tzn. omezení za název nebude použit pro tvorbu např. z API
      ADSQL.Where.Add('A.Name LIKE ''B%''');
    end;
  end;
end;Doplnění parametru z definice definovatelného formuláře.
                                                                 
                                                            
 založení nového záznamu do agendy logování (CFxLog)
založení nového záznamu do agendy logování (CFxLog)
                                                        Příklad použití třídy CFxLog s metodou SaveLog, která vytvoří a uloží nový log v agendě Logy:
..
var
  mLog: CFxLog;
  mContext: TNxContext;
  mCustomObjectSpace: TNxCustomObjectSpace;
begin
  mCustomObjectSpace := Self.BaseObjectSpace;
  mContext := NxCreateContext(mCustomObjectSpace);
  mLog.SaveLog(mContext, 'LOGIE', 'Test_01', 'Poznámka_01', 0, Now);
  mLog.SaveLog(mContext, 'LOGIE', 'Test_02', 'Poznámka_02', 1, Now);
  mLog.SaveLog(mContext, 'LOGIE', 'Test_03', 'Poznámka_03', 2, Now);
.. Otevření číselníku a zpracování vybrané hodnoty
Otevření číselníku a zpracování vybrané hodnoty
                                                        Příklad jak otevřít číselník a vybranou hodnotu zpracovat:
// Vyloučení některých záznamů
//mParams.GetOrCreateParam(dtString, '_Excluded').AsString := '1J50000101;M100000101';
// Omezení jen na seznam povolených záznamů
//mParams.GetOrCreateParam(dtString, '_Allowed').AsString := '1J50000101;M100000101';
procedure SelectOneFromRoll(Sender : TObject);
var
  mSite: TSiteForm;
  mSiteContext: TNxContext;
  mParams: TNxParameters;
  mID: String;
begin
  mSite := TComponent(Sender).Site;
  mSiteContext := mSite.SiteContext;
  mParams := TNxParameters.Create;
  try
    mParams.GetOrCreateParam(dtString, '_ID').AsString := 'O100000101'; // Otevření na konkrétním záznamu. '' - bez určení
    if NxShowRoll(mSiteContext, Roll_StoreCards, mParams, 0, '', mSite.GetParentForm) then begin
      mID := mParams.ParamByName('_ID').AsString;
      ShowMessage('Vybraný záznam: ' + mID);
    end;
  finally
    mParams.Free;
  end;
end;
procedure MultiSelectFromRoll(Sender : TObject);
var
  mSite: TSiteForm;
  mSiteContext: TNxContext;
  mParams: TNxParameters;
  mIDs: String;
  mSelectedList: TNxParameters;
  i: Integer;
begin
  mSite := TComponent(Sender).Site;
  mSiteContext := mSite.SiteContext;
  mSelectedList := TNxParameters.Create;
  try
    mParams := TNxParameters.Create;
    try
      // Označení vybraných záznamů
      mSelectedList.GetOrCreateParam(dtString, '4100000101').AsString := '4100000101';
      mSelectedList.GetOrCreateParam(dtString, 'E100000101').AsString := 'E100000101';
      mParams.GetOrCreateParam(dtObject, '_SelectedList').AsObject := mSelectedList;
      if NxShowRoll(mSiteContext, Roll_StoreCards, mParams, 0, '', mSite.GetParentForm) then begin
        mIDs := '';
        for i := 0 to mSelectedList.Count - 1 do
        begin
          mIDs := mIDs + mSelectedList.Params[i].AsString + ';';
        end;
        ShowMessage('Vybrané záznamy: ' + mIDs);
      end;
    finally
      mParams.Free;
    end;
  finally
    mSelectedList.Free;
  end;
end; Naplnění business objektu firmy hodnotami z portálu ARES (CZ) nebo veřejné databáze (SK)
Naplnění business objektu firmy hodnotami z portálu ARES (CZ) nebo veřejné databáze (SK)
                                                        Příklad použití funkce GetARESCZData popř. GetSKFirmData - vytvoření business objektu firmy a zavolání příslušných funkcí na naplnění (k vyzkoušení ve vizuálnu s interakcí uživatele):
procedure OnExecute_FillByOrgIdentNumber(Sender: TObject);
  var
  mSite: TSiteForm;
  mFirm: TNxCustomBusinessObject;
  mErrText: string;
  mOrgIdentNumber: string;
begin
  mSite := TComponent(Sender).BusRollSite;
  mFirm := mSite.BaseObjectSpace.CreateObject(Class_Firm);
  mFirm.New;
  mFirm.Prefill;
  //zadání IČO k otestování
  mOrgIdentNumber := InputBox('IČO pro vyhledání firmy', 'Zadejte IČO:', '00000000');
  //naplnění firmy z portálu ARES (CZ)
  mFirm.SetFieldValueAsString('OrgIdentNumber', mOrgIdentNumber);
  mErrText := '';
  TNxFirm(mFirm).GetARESCZData(mErrText, True);
  if mErrText = '' then
    ShowMessage(mFirm.GetFieldValueAsString('Name'));
  else
    ShowMessage(mErrText);
  //naplnění firmy z veřejné databáze (SK)
  mFirm.SetFieldValueAsString('OrgIdentNumber', mOrgIdentNumber);
  mErrText := '';
  TNxFirm(mFirm).GetSKFirmData( mErrText, True);
  if mErrText = '' then
    ShowMessage(mFirm.GetFieldValueAsString('Name'));
  else
    ShowMessage(mErrText);
end; Vyvolání výjimky ve skriptování z nástroje ScriptDebuggeru
Vyvolání výjimky ve skriptování z nástroje ScriptDebuggeru
                                                        V nástroji ScriptDebugger existuje možnost ve skriptu ručně vyvolat výjimku z breakpointů nebo za přímého běhu.
Po stisku tlačítka Vyvolat výjimku a potvrzení dialogu, kde lze změnit text výjimky se zašle do Abry požadavek na budoucí výjimku. Abra při příštím vykonání uměle selže. 
Oproti vyvolání výjimky přímo ze skriptování příkazem RaiseException se ovšem ale nezobrazuje CallStack, kde chyba vznikla. 
                                                                 
                                                            
                                                                 
                                                            
 Ovlivnění vizuálna z AfterSetFieldValue_Hook na business objektu
Ovlivnění vizuálna z AfterSetFieldValue_Hook na business objektu
                                                        Uvedený příklad demonstruje, jak lze na základě logiky v business objektu (objednávky přijaté) - po nastavení řady dokladu - docílit zapnutí/vypnutí řádkové slevy, a následně zobrazení/skrytí sloupců v gridu řádků té objednávky:
//v BO po vyplnění určité řady chceme, aby se aktivovala sleva
procedure AfterSetFieldValue_Hook(Self: TNxCustomBusinessObject; AFieldCode: Integer; AValue: TNxParameter; AOriginalValue: TNxParameter);
begin
  if AFieldCode = 11000 then //řada dokladů
  begin
    if AValue.AsString = '1OU0000101' then //uvedená hodnota může reprezentovat např. řadu"OP" - tohle vyplyne z nějaké x položky nebo nějak jinak
    begin
      Self.SetFieldValueAsBoolean('IsRowDiscount', True)
    end
    else
    begin
      Self.SetFieldValueAsBoolean('IsRowDiscount', False)
    end
  end;
end;
//ve vizuálnu budeme potřebovat globální proměnnou
var
  fSite: TSiteForm;
//ve vizuálnu vytvoříme proceduru pro zpracování události změny na řadě dokladu
procedure InitSite_Hook(Self: TSiteForm);
var
  mpnDocQueue_ID: TNxGeneralRollMovablePanel;
begin
  mpnDocQueue_ID := TNxGeneralRollMovablePanel(Self.FindComponent('mpnDocQueue_ID'));
  mpnDocQueue_ID.onInEditAdmit := @DQEditAdmit; //Vytvoření procedury pro zpracování události zadání té řady dokladů
  fSite := Self;
end;
//a v rámci té události si ve vizuálnu nastavíme, co potřebujeme - tady to je zobrazení popř. skrytí sloupců v gridu řádků
procedure DQEditAdmit;
var
  mpnIsRowDiscount: TNxCheckBoxMovablePanel;
  colRowDiscount1: TNxMultiGridColumn;
  colRowDiscount2: TNxMultiGridColumn;
  colRowDiscount3: TNxMultiGridColumn;
begin
  mpnIsRowDiscount := TNxCheckBoxMovablePanel(fSite.FindComponent('mpnIsRowDiscount'));
  colRowDiscount1 := TNxMultiGridColumn(fSite.FindComponent('colRowDiscount1'));
  colRowDiscount2 := TNxMultiGridColumn(fSite.FindComponent('colRowDiscount2'));
  colRowDiscount3 := TNxMultiGridColumn(fSite.FindComponent('colRowDiscount3'));
  colRowDiscount1.Visible := mpnIsRowDiscount.InCheckBox_Checked;
  colRowDiscount2.Visible := mpnIsRowDiscount.InCheckBox_Checked;
  colRowDiscount3.Visible := mpnIsRowDiscount.InCheckBox_Checked;
end; práce s přílohami PDF Dokumentů
práce s přílohami PDF Dokumentů
                                                        Jedná se o třídy TPDFDocument a TPDFFileAttachment, které umožňují práci s přílohami PDF dokumentů. Třídy jsou založeny na produktu třetí strany SecureBlackBox, který je součástí systému ABRA Gen, umí jak načíst existující přílohy, tak vložit nové: 
procedure AddFileToPDF(const APDFFileName: string;
  const AAddFileName: string; const AAddFileType: string; const AAddFileDescription: string);
var
  i: Integer;
  mPDFStream,
  mPDFAttachmentStream: TFileStream;
  mPDFDocument: TPDFDocument;
  mPDFAttachment: TPDFFileAttachment;
begin
  mPDFDocument := TPDFDocument.Create(nil);
  try
    // otevřeme stream s existujícím PDF souborem
    mPDFStream := TFileStream.Create(APDFFileName, fmOpenReadWrite);
    try
      // pomocí streamu načteme PDF do objektu pro práci s PDF
      mPDFDocument.Open(mPDFStream);
      // do PDF přidáme přílohu
      i := mPDFDocument.AddAttachedFile;
      mPDFAttachment := mPDFDocument.AttachedFiles[i];
      // vložíme novou přílohu načtením z disku
      mPDFAttachmentStream := TFileStream.Create(AAddFileName, fmOpenRead);
      try
        // načteme obsah přílohy ze souboru
        mPDFAttachment.LoadFromStream(mPDFAttachmentStream);
      finally
        mPDFAttachmentStream.Free;
      end;
      // doplníme další informace k příloze
      mPDFAttachment.ObjectName := ExtractFileName(AAddFileName);
      mPDFAttachment.FileName := ExtractFileName(AAddFileName);
      mPDFAttachment.UnicodeFilename := ExtractFileName(AAddFileName);
      mPDFAttachment.SubType := AAddFileType;
      mPDFAttachment.Description := AAddFileDescription;
      mPDFAttachment.CreationDate := Now;
      mPDFAttachment.ModificationDate := Now;
      // uložíme změny do souboru PDF
      mPDFDocument.Close(True);
    finally
      mPDFStream.Free;
    end;
  finally
    mPDFDocument.Free;
  end;
end;procedure ExtractFilesFromPDF(const APDFFileName: string;
  const AExtractPath: string);
var
  i: Integer;
  mPDFStream,
  mPDFAttachmentStream: TFileStream;
  mPDFDocument: TPDFDocument;
  mPDFAttachment: TPDFFileAttachment;
  mFilesInformation: TStringList;
begin
  mFilesInformation := TStringList.Create;
  try
    // vytvoříme objekt pro práci s PDF
    mPDFDocument := TPDFDocument.Create(nil);
    try
      // otevřeme stream s existujícím PDF souborem
      mPDFStream := TFileStream.Create(APDFFileName, fmOpenReadWrite);
      try
        // pomocí streamu načteme PDF do objektu pro práci s PDF
        mPDFDocument.Open(mPDFStream);
        // procházíme všechny přílohy vložené do PDF a uložíme je na disk
        for i := 0 to mPDFDocument.AttachedFileCount - 1 do
        begin
          mPDFAttachment := mPDFDocument.AttachedFiles[i];
          // do Stringlistu si uložíme případné informace o souborech
          mFilesInformation.Add('Informace o příloze č. ' + IntToStr(i + 1) + ':' + nxCrLf +
            '  ObjectName: ' + mPDFAttachment.ObjectName + nxCrLf +
            '  FileName: ' + mPDFAttachment.FileName + nxCrLf +
            '  UnicodeFilename: ' + mPDFAttachment.UnicodeFilename + nxCrLf +
            '  SubType: ' + mPDFAttachment.SubType + nxCrLf +
            '  Description: ' + mPDFAttachment.Description + nxCrLf +
            '  CreationDate: ' + DateTimeToStr(mPDFAttachment.CreationDate) + nxCrLf +
            '  ModificationDate: ' + DateTimeToStr(mPDFAttachment.ModificationDate) + nxCrLf +
            '  Size: ' + IntToStr(mPDFAttachment.Size) + nxCrLf +
            '================================================'+ nxCrLf + nxCrLf
          );
          mPDFAttachmentStream := TFileStream.Create(AExtractPath + mPDFAttachment.UnicodeFilename, fmCreate);
          try
            // přílohu z PDF uložíme přes stream na disk
            mPDFAttachment.SaveToStream(mPDFAttachmentStream);
          finally
            mPDFAttachmentStream.Free;
          end;
        end;
        mPDFDocument.Close(False);
        //Uložíme informace o extrahovaných souborech do stejného adresáře kam se soubory extrahovali.
        mFilesInformation.SaveToFile(AExtractPath + '_AttahcmentInfo.txt');
      finally
        mPDFStream.Free;
      end;
    finally
      mPDFDocument.Free;
    end;
  finally
    mFilesInformation.Free;
  end;
end; Zpřístupnění zdrojového business objektu při vytváření CRM aktivity z jiné agendy
Zpřístupnění zdrojového business objektu při vytváření CRM aktivity z jiné agendy
                                                        V tomto příkladu potřebujeme přenést zakázku a projekt z výrobního příkazu do CRM aktivity. V agendách existuje akce Aktivity - Založit novou aktivitu a připojit, standardně ale nemáme ve skriptingových háčcích při otevření aktivity přes tuto akci k dispozici zdrojový business objekt (zde výrobní příkaz). Tento příklad ukáže, jak se dá potřebný BO získat a použít v nějakém háčku (zde AfterSiteOpen_Hook).
V _InitSelectionParams_Hook si zapamatujeme objekt zdrojového dokladu a z něj pak přebíráme údaje v AfterSiteOpen_Hook.
Zdrojový kód skriptu - Agenda Aktivity:
var
  fJO: TNxCustomBusinessObject;
procedure _InitSelectionParams_Hook(Self: TDynSiteForm; ASelection, AParams: TNxParameters);
var
  mPar: TNxParameter;
begin
  mPar := AParams.ParamByName('DocumentToConnect');
  if assigned(mPar) then
  begin
    fJO := TNxCustomBusinessObject(mPar.asobject);
    if fJO.CLSID <> Class_PLMJobOrder then //v této ukázce přebíráme jen z výrobních příkazů
    begin
      fJO := nil;
    end;
  end;
end;
procedure AfterSiteOpen_Hook(Self: TSiteForm);
var
  mActivity: TNxCustomBusinessObject;
begin
  mActivity := TDynSiteForm(Self).ActiveDataSet.CurrentObject;
  try
    if assigned(fJO) and assigned(mActivity) then //aktivita vytvořena z výrobního příkazu
    begin
      try
        //tady údaje převezmeme
        mActivity.SetFieldValueAsString('BusOrder_ID', fJO.GetFieldValueAsString('BusOrder_ID'));
        mActivity.SetFieldValueAsString('BusProject_ID', fJO.GetFieldValueAsString('BusProject_ID'));
      finally
        fJO := nil;
      end;
      TDynSiteForm(Self).ActiveDataSet.UpdateFields;
    end;
  finally
    mActivity.Free;
  end;
end;
begin
end. Odeslání e-mailu přes outlook
Odeslání e-mailu přes outlook
                                                        Zde je příklad, jak ze skriptingu vytvořit a odeslat e-mail v aplikaci Outlook. Pomocí skriptování můžeme vytvořit jakýkoliv zaregistrovaný objekt ve Windows, tedy i například Outlook.Application. Používá se k tomu metoda CreateOleObject.
Jaké vlastnosti, události nebo metody objekt používá, je možné najít v dokumentaci: Application object (Outlook) | Microsoft Learn.
procedure exeOutlookSend(Sender: TBasicAction);
var
  mOutlook, mItem: Variant;
begin
  mOutlook := CreateOleObject('Outlook.Application');
  if VarIsNull(mOutlook) then NxShowSimpleMessage('Chyba při získání instance Outlooku', Sender.Site)
  else begin
    mItem := mOutlook.CreateItem(0);
    
    mItem.To := 'adresa1@firma.cz';  //adresa příjemce
    mItem.CC := 'adresa2@firma.cz; adresa3@firma.cz'; //adresy příjemců kopie
    mItem.Subject := 'Předmět e-mailu';
    mItem.Body := 'Tělo e-mailu';
    mItem.Attachments.Add('C:\Users\jmeno\priloha.pdf');  //připojení souboru
    
    //zobrazení okna Outlooku s vyvořeným e-mailem
    mItem.Display; //případně .Send pro odeslání
  end;
  mOutlook := Null;
end; Použití háčku po přihlášení
Použití háčku po přihlášení
                                                        Při přihlášení se volá háček Aplikační modul: Systémové události - AfterLogon_Hook. Tento háček se však nevolá pouze při prvotním přihlášení uživatele do AbraGen.exe, ale při každém vytvoření kontextu z klienta na aplikační server. K vytváření více kontextů na aplikační server (z jedné aplikace AbraGen.exe ) dochází od verze 23.2, a to při vyhodnocení údajů definovatelných panelů, které nyní probíhá v samostatném vlákně.
Existence více vláken má vliv i na použití globální proměnné GlobParams, parametry v ní lze použít jen v rámci jednoho vlákna. Hodnotu parametru nastavenou v jednom vlákně tak nelze získat v jiném vlákně. Aby bylo možné sdílet hodnoty parametrů mezi různými vlákny, byla vytvořena nová proměnná GlobThreadParams.
Následující příklad demonstruje, jak zabezpečit, aby se kód v háčku AfterLogon_Hook zavolal pouze jednou (při přihlášení uživatele do ABRA Gen), a jak hodnotu parametru nastavenou v jednom vlákně (při přihlášení uživatele do ABRA Gen) získat v jiném vlákně (při vyhodnocení definovatelného panelu).
Zároveň je třeba mít na paměti, že v háčku AfterLogon_Hook lze přistoupit ke GUI (například zobrazit formulář) pouze, pokud je kód vyvolán z hlavního vlákna. Pokud k přístupu ke GUI dojde z jiného vlákna, celá aplikace může zamrznout.
const
  cParSelectedDivisionID = 'SelectedDivisionID';  //Název parametru jehož hodnota se ukládá do GlobThreadParams
//Vyvolává se při tvorbě kontextu z klienta na aplikační server (nejen při přihlášení uživatele).
procedure AfterLogon_Hook(AContext: TNxContext);
begin
  if NxIsMainThread and              //Kód je volán z hlavního vlákna, ve kterém je možné zobrazit formulář
    (GetSelectedDivisionID = '') and //Středisko ještě nebylo vybráno
    Application.NxIsInteractive then //Jedná se o GUI aplikaci, která umožňuje zobrazení oken
  begin
    SetSelectedDivisionID(SelectDivisionID(AContext));
  end;
end;
//Vyvolá výběr hodnoty z číselníku středisek.
function SelectDivisionID(AContext: TNxContext): String;
var
  mRollParams: TNxParameters;
begin
  mRollParams := TNxParameters.Create;
  try
    mRollParams.GetOrCreateParam(dtString, '_ID').AsString := ''; // Otevření na konkrétním záznamu. '' - bez určení
    if NxShowRoll(AContext, Roll_Divisions, mRollParams, 0, '', nil) then
    begin
      Result := mRollParams.ParamByName('_ID').AsString;
    end else
      Result := SelectDivisionID(AContext); //Abychom donutili uživatele nějaké středisko vybrat
  finally
    mRollParams.Free;
  end;
end;
//Uloží hodnotu do parametru SelectedDivisionID.
procedure SetSelectedDivisionID(AValue: String);
var
  mParameters: TNxParameters;
  mParameter: TNxParameter;
begin
  mParameters := GlobThreadParams.LockParams;
  try
    mParameter := mParameters.GetOrCreateParam(dtString, cParSelectedDivisionID);
    mParameter.AsString := AValue;
  finally
    GlobThreadParams.UnLockParams;
  end;
end;
//Zjistí hodnotu parametru SelectedDivisionID.
//Tato metoda vrátí správně hodnotu parametru bez ohledu na to, z kterého vlákna je vyvolána.
//Například jí tedy lze použít v definovatelném panelu.
function GetSelectedDivisionID: String;
var
  mParameters: TNxParameters;
begin
  mParameters := GlobThreadParams.LockParams;
  try
    Result := mParameters.ParamAsString(cParSelectedDivisionID, '');
  finally
    GlobThreadParams.UnLockParams;
  end;
end; Načtení uživatelských parametrů pro vybraný objekt a změna hodnoty uživatelského parametru
Načtení uživatelských parametrů pro vybraný objekt a změna hodnoty uživatelského parametru
                                                        Příklad použití funkce GetUserParameters pro získání uživatelských parametrů na business objektu skladu, změna hodnoty vybraného parametru a uvolnění cache pro uživatelské parametry pro daný sklad pomocí ClearUserParametersCache:
Příklad použití:
procedure OnExecute_ChangeUserParamValue(Sender: TObject);
var
  mSite: TSiteForm;
  mStore: TNxCustomBusinessObject;
  mUserParamValue: TNxCustomBusinessObject;
  mUserParams: TNxParameters;
begin
  mSite := TComponent(Sender).BusRollSite;
  mStore := mSite.BaseObjectSpace.CreateObject(Class_Store);
  try
    mUserParamValue := mSite.BaseObjectSpace.CreateObject(Class_UserParamValue);
    try
      mUserParams := TNxParameters.Create;
      try
        // načtení BO, v tomto případě skladu
        mStore.Load('3200000101');
        // získání jeho uživatelských parametrů
        mStore.GetUserParameters(mUserParams);
        // vypsání hodnoty parametru s kódem "param01" ze skupiny parametrů s kódem "ParamGroup01"
        ShowMessage(mUserParams.AsList.ParamByName('ParamGroup01').AsList.ParamByName('UserParameters').AsList.ParamByName('param01').AsList.ParamByName('ParamValue').AsString);
        
        // načtení BO hodnoty parametru
        mUserParamValue.Load(mUserParams.AsList.ParamByName('ParamGroup01').AsList.ParamByName('UserParameters').AsList.ParamByName('param01').AsList.ParamByName('ParamValue_ID').AsString);
        // změna hodnoty parametru
        mUserParamValue.SetFieldValueAsString('ParamValue', 'Nová hodnota');
        mUserParamValue.Save;
        
        // vyprázdnění keše parametrů pro daný BO
        mStore.ClearUserParametersCache;
        
        // vypsání změněné hodnoty
        mStore.GetUserParameters(mUserParams);
        ShowMessage(mUserParams.AsList.ParamByName('ParamGroup01').AsList.ParamByName('UserParameters').AsList.ParamByName('param01').AsList.ParamByName('ParamValue').AsString);
      finally
        mUserParams.Free;
      end;
    finally
      mUserParamValue.Free;
    end;
  finally
    mStore.Free;
  end;
end;
.. Tvorba JSON
Tvorba JSON
                                                        Příklad tvorby JSON objektu s poli:
  mJSON := TJSONSuperObject.Create;
  try
    mJSON.I['cislo_cele'] := 12345;
    mJSON.D['desetinne_cislo'] := 8282.12;
    mJSON.S['retezec'] := 'příliš žluťoučký koníček';
    mJSON.O['subjson'] := mJSON.CreateJSON;
    mJSON.O['subjson'].I['cislo_cele'] := 12345;
    mJSON.O['subjson'].D['desetinne_cislo'] := 8282.12;
    mJSON.O['subjson'].S['retezec'] := 'příliš žluťoučký koníček';
    mJSON.O['pole'] := mJSON.CreateJSONArray;
    for i := 0 to 3 do begin
      mJSON.A['pole'].I[i] := i;
      mJSON.A['pole'].S[i + 3] := IntToStr(i);
    end;
    mJSON.O['jinepole'] := mJSON.CreateJSONArray;
    mJSONArray := mJSON.O['jinepole'].AsArray;
    for i := 0 to 4 do begin
      mItem := mJSON.CreateJSON;
      mItem.S['name'] := 'Str' + IntToStr(i);
      mJSONArray.Add(mItem);
    end;
    mJSON.O['dalsiprikladpole'] := mJSON.CreateJSONArray;
    mJSONArray := mJSON.O['dalsiprikladpole'].AsArray;
    for i := 0 to 2 do begin
      mSubArray := mJSON.CreateJSONArray;
      for ii := 0 to i do begin
        mItem := mJSON.CreateJSON;
        mItem.S['Str' + IntToStr(ii)] := IntToStr(i) + ' ' + IntToStr(ii);
        mItem.I['Int' + IntToStr(ii)] := ii;
        mSubArray.AsArray.Add(mItem)
      end;
      mJSONArray.Add(mSubArray);
    end;
    ShowMessage(mJSON.AsJson);
  finally
    mJSON.Free;
  end;Skript založí následující JSON:
{
  "desetinne_cislo": 8282.12,
  "retezec": "příliš žluťoučký koníček",
  "subjson": {
    "desetinne_cislo": 8282.12,
    "retezec": "příliš žluťoučký koníček",
    "cislo_cele": 12345
  },
  "dalsiprikladpole": [
    [
      {
        "Str0": "0 0",
        "Int0": 0
      }
    ],
    [
      {
        "Str0": "1 0",
        "Int0": 0
      },
      {
        "Str1": "1 1",
        "Int1": 1
      }
    ],
    [
      {
        "Str0": "2 0",
        "Int0": 0
      },
      {
        "Str1": "2 1",
        "Int1": 1
      },
      {
        "Str2": "2 2",
        "Int2": 2
      }
    ]
  ],
  "pole": [
    0,
    1,
    2,
    3,
    "1",
    "2",
    "3"
  ],
  "jinepole": [
    {
      "name": "Str0"
    },
    {
      "name": "Str1"
    },
    {
      "name": "Str2"
    },
    {
      "name": "Str3"
    },
    {
      "name": "Str4"
    }
  ],
  "cislo_cele": 12345
} Spuštění exportu do souboru dle zadaných podmínek (export tvoří HTML obsah, který lze otevřít v MS Excel)
Spuštění exportu do souboru dle zadaných podmínek (export tvoří HTML obsah, který lze otevřít v MS Excel)
                                                        Příklad spuštění exportu Účetní exporty - Export předvahy do MS Excel, který vytváří HTML obsah, který je uložen jako soubor s přílohou XLS. Takovýto soubor umí následně otevřít MS Excel a lze pracovat s hodnotami.
Příklad použití:
// Uložení exportu do souboru
procedure GenerateEpxportTrialBalance(const AOS: TNxCustomObjectSpace; const AFrom, ATo: TDateTime; const APath: string);
const
  cExportTrialBalanceID = 'P300000001'; // Identifikátor exportu Účetní exporty - Export předvahy do MS-Excel
var
  mFile, mDynSourceID: string;
  mContext: TNxContext;
  mParameter, mCondParameter, mValuesParameter: TNxParameter;
  mConditions: TNxParameters;
begin
  mFile := APath + '\Předvaha_' + FormatDateTime('YYYYMMDD', AFrom) + '_' + FormatDateTime('YYYYMMDD', ATo) + '.xls';
  if FileExists(mFile) then
    DeleteFile(mFile);
  mDynSourceID := AOS.SQLSelectFirstAsString('SELECT DataSource FROM Exports WHERE ID =''' + cExportTrialBalanceID + '''');
  mContext := NxCreateContext(AOS);
  try
    mConditions := TNxParameters.Create;
    try
      // Nastavení data od do podmínky Datum účtování
      mParameter := mConditions.GetOrCreateParam(dtList, 'AccDate').AsList;
      mParameter.AsList.NewFromDataType(dtInteger, 'USEDKIND', pkUnknown).AsInteger := 2; //ckRange;
      mValuesParameter := mParameter.AsList.NewFromDataType(dtList, 'VALUES', pkUnknown);
      mValuesParameter.AsList.NewFromDataType(dtFloat,'{:VALUE}', pkUnknown).AsFloat := AFrom;
      mValuesParameter.AsList.NewFromDataType(dtFloat,'{:VALUEHIGH}', pkUnknown).AsFloat := ATo;
      CFxReportManager.ExportByConditions(mContext, mConditions, mDynSourceID, cExportTrialBalanceID, 0, '', mFile);
    finally
      mConditions.Free;
    end;
  finally
    mContext.Free;
  end;
end;
procedure FormCreate_Hook(Self: TSiteForm);
var
  mAction, mAction2: TBasicAction;
begin
  mAction := Self.GetNewAction;
  mAction.ShowControl := True;
  mAction.ShowMenuItem := True;
  mAction.Caption := 'Spuštění exportu předvahy';
  mAction.Category := 'tabList';
  mAction.OnExecute := @RunGenerateEpxportTrialBalance;
end;
procedure RunGenerateEpxportTrialBalance(Sender : TObject);
var
  mSite: TSiteForm;
  mObjectSpace: TNxCustomObjectSpace;
begin
  mSite := TComponent(Sender).Site;
  mObjectSpace := mSite.BaseObjectSpace;
  GenerateEpxportTrialBalance(mObjectSpace, StrToDate('1.1.2000'), StrToDate('1.1.2025'), 'c:\temp')
end;
 Používání jádrového logování do souboru ze skritpování
Používání jádrového logování do souboru ze skritpování
                                                        Ve skriptování je možné využít snadného zápisu do logu, který se konfiguruje za pomocí standardního nastavení přes nexus.cfg. Nastavením lze snadno určit, do jaké míry bude logování ze skriptování detailní, pomocí určení hodnoty úrovně (Level).
Pro zapnutí logování (nastavení Enabled=1) není třeba restartovat klienty ani aplikační server. Nastavení si všechny aplikace jednou za cca 60 sekund obnovují.
Příklad: Obsah Nexus.cfg
[Logs]
LogsDirectory=\\Server\složka_pro_zápis
[Log.Scripting]
Enabled=1
# Pro zápis chyb do logu nastavíme Level=2, pro zápis varování hodnotu Level=3 a pro detailní výpis Level=5  
Level=5
Uvedená cesta LogsDirectory je třeba, aby směřovala na síťové úložiště, kam mají klienti přístup zápisu.
V případě chybné cesty může docházet k velkému výkonovému zpomalení celého systému.
Příklad skriptu:
procedure ExampleUseNxScriptingLog;
begin
  if NxScriptingLog.Active then begin
    // Úrovně závažnosti jsou definovány výčtem TNxLogLevel = (logSystem,logCritical,logError,logWarning,logNotice,logInfo,logDebug)
    // Nejvyšší úroveň závažnosti logSystem hodnota 0, ve skritpování nepoužíváme.
    // NxScriptingLog.WriteEvent(logError, 'Text systémové chyby');
    // Úroveň vznikla chyba Level=2
    NxScriptingLog.WriteEvent(logError, 'Text vznikla chyby');
    // Úroveň varování Level=3
    NxScriptingLog.WriteEvent(logWarning, 'Text varování');
    // Úroveň detailní výpis informací Level=5
    NxScriptingLog.WriteEvent(logInfo, 'Informativní text');
    NxScriptingLog.EnterSection('Logování bloku');
    try
      try
        Sleep(1000);
        RaiseException('Odchycena očekávaná výjimka');
      except
        NxScriptingLog.WriteEvent(logWarning, ExceptionMessage);
      end;
    finally
      NxScriptingLog.LeaveSection('Logování bloku');
    end;
  end;
end;
procedure FormCreate_Hook(Self: TSiteForm);
var
  mAction: TBasicAction;
begin
  mAction := Self.GetNewAction;
  mAction.ShowControl := True;
  mAction.ShowMenuItem := True;
  mAction.Caption := 'Zalogování textu do textového logu';
  mAction.Category := 'tabList';
  mAction.OnExecute := @RunWriteToLog;
end;
procedure RunWriteToLog(Sender: TObject);
begin
  ExampleUseNxScriptingLog;
end;
Výsledkem je zápis do souboru s názvem, který obsahuje datum a čas vzniku souboru, název aplikace, proces, identifikátor aplikace a jméno počítače.
Příklad jména vzniklého logu: 24-03-26 16-32-17-946 AbraGen 16556 JAVU-SRV.JAVU-NTB ABRAGen.log
Obsah souboru z uvedeného příkladu:
26.03.2024 22:03:43.483 [2] 00001A68 (Scripting) Text vznikla chyby
26.03.2024 22:03:43.483 [3] 00001A68 (Scripting) Text varování
26.03.2024 22:03:43.483 [5] 00001A68 (Scripting) Informativní text
26.03.2024 22:03:43.483 [4] 00001A68 (Scripting) Logování bloku
26.03.2024 22:03:43.483 [4] 00001A68 (Scripting) ->
26.03.2024 22:03:44.501 [3] 00001A68 (Scripting) Error in ExampleUseNxScriptingLog (Exception):
  očekávaná výjimka
  scripting callstack:
  ExampleUseNxScriptingLog ():  .RaiseException (40:23)
  RunWriteToLog (ExampleUseNxScriptingLog.Faktury přijaté (Agenda)):  ExampleUseNxScriptingLog (16:27)
   RunWriteToLog (14:1)
26.03.2024 22:03:44.501 [5] 00001A68 (Scripting)<-- (Logování bloku)
 Digitální podpis XML zprávy pro komunikaci se SÚKL
Digitální podpis XML zprávy pro komunikaci se SÚKL
                                                        Příklad demonstruje vytvoření XML dokumentu s digitálním podpisem a jeho vložení do SOAP obálky za účelem komunikace se SÚKL (Státní ústav pro kontrolu léčiv):
procedure SignXmlSukl(Sender: TComponent);
var
  mSite: TSiteForm;
  mOS: TNxCustomObjectSpace;
  mXML, mXMLEnvelope: TNxScriptingXMLWrapper;
  mCertStore, mCertHash, mMsgGUID: String;
  mContext: TNxContext;
begin
  mSite:= Sender.Site;
  mOS:= mSite.BaseObjectSpace;
  mContext:= NxCreateContext(mOS);
  try
    //vyvoláme dialog s výběrem podpisového certifikátu a uložíme si jeho hash a místo uložení
    mCertHash:= SelectCertificateDlg(mContext, mCertStore, mSite);
    //vygenerujeme si GUID odesílané zprávy
    mMsgGUID:= NxTrim(LowerCase(GUIDToString(CFxGuid.CreateNew())),'{}');
    mXML:= TNxScriptingXMLWrapper.Create;
    try
      //vytvoříme zprávu k podepsání
      mXML.DateTimeFormat:= 'yyyy-mm-dd"T"hh:nn:ss.zzz';
      mXML.CreateEmpty('com:AppPingZEPDotaz', 'xmlns:com="http://www.sukl.cz/erp/common"');
      mXML.setAttributeValue('com:AppPingZEPDotaz', 'xmlns:com', 'http://www.sukl.cz/erp/common');
      mXML.setElementAsString('com:Doklad.com:Pristupujici.com:Uzivatel', cUserLogin);
      mXML.setElementAsString('com:Doklad.com:Pristupujici.com:Pracoviste', cPremiseCode);
      mXML.setElementAsString('com:Zprava.com:ID_Zpravy', mMsgGUID);
      mXML.setElementAsString('com:Zprava.com:Verze', cSUKLInterfaceVersion);
      mXML.setElementAsDateTime('com:Zprava.com:Odeslano', Now);
      mXML.setElementAsString('com:Zprava.com:SW_Klienta', 'ABRASW');
      //uděláme XML kanonickým, a podepíšeme (Kanonozizace upraví xml do konzistentní standardizované formy)
      mXML.MakeXMLCannonical(0, false);
      mXML.SignXML(mCertHash, mCertStore, 1, mContext, 'ds');
      //vytvoříme obálku
      mXMLEnvelope:= TNxScriptingXMLWrapper.Create;
      try
        mXMLEnvelope.CreateEmpty('soapenv:Envelope', 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"');
        mXMLEnvelope.setAttributeValue('soapenv:Envelope', 'xmlns:soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
        mXMLEnvelope.setAttributeValue('soapenv:Envelope', 'xmlns:com', 'http://www.sukl.cz/erp/common');
        mXMLEnvelope.setAttributeValue('soapenv:Envelope', 'xmlns:ds', 'http://www.w3.org/2000/09/xmldsig#');
        mXMLEnvelope.addElement('soapenv:Header');
        //podepsanou XML zprávu vložíme do obálky
        mXMLEnvelope.AddXMLEncodedElement('soapenv:Body', mXML.getElementXML('com:AppPingZEPDotaz'));
        mXMLEnvelope.saveToFile('F:\testXML1.xml', 'UTF-8');
      finally
        mXMLEnvelope.Free;
      end;
    finally
      mXML.Free;
    end;
  finally
    mContext.Free;
  end;
end; Použití interního OLE
Použití interního OLE
                                                        Při použití interního OLE se skriptingu dbejte na jeho uvolnění!
Nejen, že neuvolněné OLE způsobuje Memory Leaky, ale v kombinaci s přihlášením jiného uživatele může vést k situaci, kdy systém přestane fungovat, neboť dojde k částečné likvidaci původního ObjectSpace, který již pro další použití není plně funkční !!!
Je třeba dbát na to, aby byly uvolněny i všechny další objekty, které s OLE mohou dále držet, například objekt vytvořený prostřednictvím metody CreateDocumentDriver.
try
  mOLE := mContext.GetAbraOLEApplication();
  mOleDoc := mOLE.CreateDocumentDriver();
  ... 
finally
  //Tyto řádky zajistí uvolnění OLE a jsou nezbytné pro další správnou funkci systému
  mOleDoc := nil; 
  mOLE := nil; 
end; Použití funkce ConvertOnlyRowsCSVData pro konverzi dat v definovatelných importech
Použití funkce ConvertOnlyRowsCSVData pro konverzi dat v definovatelných importech
                                                        Práce s definovatelnými importy: Definovatelné importy (txt, xls a csv) vyžadují, aby v importním souboru byla rozlišena hlavička a řádky pomocí masky. Pokud tomu tak není, jsou jednotlivé řádky ze souboru importovány jako samostatné doklady.
Pro případ, kdy jsou v importních datech pouze řádkové položky více než jedné hlavičky a zároveň jde o řádky jen jednoho druhu business objektu, byly vytvořeny nové skritptingové funkce dostupné na třídě TNxIEImportDefinition.
Soubor typu TXT:
Funkce ConvertOnlyRowsTXTData, metoda ConvertOnlyRowsTXTData, procedure ConvertOnlyRowsTXTData(var ATXTInputData: TStringList; const AKeyPositions: TStringList; const AHeadersPrefix, ARowsPrefix: string; ATrimSpaces: Boolean)
{
Vyvolává se po nastavení importního dokumentu před spuštěním parsingu - umožňuje změnit obsah importního dokumentu.
}
procedure IEImportExport_AfterSetImportDocument_Hook(AContext: TNxContext; const AImportDefinition_BO: TNxCustomBusinessObject; var ADocumentContent: TStringList);
var
  mKeyPositions: TStringlist;
begin
  mKeyPositions := TStringlist.Create;
  try
    mKeyPositions.Add('1;12');
    mKeyPositions.Add('13;12');
    mKeyPositions.Add('27;11');
    TNxIEImportDefinition(AImportDefinition_BO).ConvertOnlyRowsTXTData(ADocumentContent, mKeyPositions, 'HEAD ', 'ROW  ', false);
{    TNxIEImportDefinition(AImportDefinition_BO).ConvertOnlyRowsTXTData(ADocumentContent, mKeyPositions, 'HEAD ', 'ROW  ', true);
}
  finally
    mKeyPositions.Free;
  end;
end;
begin
end.Soubor typu CSV a XLS (soubor XLS se při importu převede na CSV formát):
Funkce ConvertOnlyRowsCSVData, metoda ConvertOnlyRowsCSVData, procedure ConvertOnlyRowsCSVData(var ACSVInputData: TStringList; const AKeyPositions: TStringList; const AHeadersPrefix, ARowsPrefix: string)
{
Vyvolává se po nastavení importního dokumentu před spuštěním parsingu - umožňuje změnit obsah importního dokumentu.
}
procedure IEImportExport_AfterSetImportDocument_Hook(AContext: TNxContext; const AImportDefinition_BO: TNxCustomBusinessObject; var ADocumentContent: TStringList);
var
  mKeyPositions: TStringlist;
begin
  mKeyPositions := TStringlist.Create;
  try
    mKeyPositions.Add('0');
    mKeyPositions.Add('1');
    mKeyPositions.Add('3');
    TNxIEImportDefinition(AImportDefinition_BO).ConvertOnlyRowsCSVData(ADocumentContent, mKeyPositions, 'HEAD', 'ROW');
  finally
    mKeyPositions.Free;
  end;
end;
begin
end. Sekvenční Update definovatelné položky – skript spouštěn z naplánované úlohy
Sekvenční Update definovatelné položky – skript spouštěn z naplánované úlohy
                                                        Příklad použití:
Na skladové kartě potřebujeme zobrazit hodnotu prodeje za posledních 365 dnů. Nechceme však, aby se tato hodnota načítala dynamicky (například do sloupce přes NxSQLSelect) ale, aby byla perzistentní. Dle dané položky lze i řadit seznam, případně hodnotu použít pro další výpočty.
Načtení bude probíhat naplánovanou úlohou typu skript. Skript zapíše pro všechny skladové karty prodej za posledních 365 dnů. Zápis probíhá sekvenčně, aby nedošlo k uzamčení tabulky StoreCards.
Příklad nastavení a provedení:
Na objektu skladové karty vytvoříme definovatelnou položku X_Prodej365 typu Číslo.
Položku X_Prodej365 si zobrazíme do sloupce v agendě Skladové karty. Před prvním přepočtem je pochopitelně hodnota 0 u každé skladové karty – výchozí hodnota (z definice definovatelné položky).
V agendě Balíčky skriptů založíme skript pro výpočet prodejů za posledních 365 dnů.
Ve zdrojovém kódu je možné rychle vygenerovat hlavičku skriptu „Volání z naplánované úlohy“.
Success – určuje, jestli úloha proběhla v pořádku
LogInfoStr – naplánované úloze můžeme vrátit dodatečné informace o průběhu, například počet změněných záznamů, případně jiné informace.
Metodu pojmenujeme a dopíšeme obsah dle následujícího příkladu.
procedure Run( ObjectSpace: TNxCustomObjectSpace; var Success: Boolean; var LogInfoStr: String); const cStoreCards = ' SELECT SC.ID AS ID, SUM(RO2.DeliveredQuantity) AS DeliveredQuantity FROM ReceivedOrders2 RO2' + ' JOIN ReceivedOrders RO ON RO.ID = RO2.Parent_ID' + ' JOIN StoreCards SC ON RO2.StoreCard_ID = SC.ID' + ' WHERE' + ' SC.Hidden = ''N'' AND' + ' RO.DocDate$DATE >= :FromDate' + ' GROUP BY SC.ID'; cUpdateStoreCard = 'UPDATE StoreCards SET X_Prodej365 = :X_Prodej365 WHERE ID = :ID'; var mStoreCardsData: TMemoryDataset; I: Integer; mInputParams: TNxParameters; mSC: TNxCustomBusinessObject; mStoreCardID: String; mDeliveredQuantity: Extended; begin Success := True; LogInfoStr := ''; mStoreCardsData := TMemoryDataset.Create(nil); try mInputParams := TNxParameters.Create; try // Získání dat přes SQL dotaz mInputParams.Clear; mInputParams.NewFromDataType(dtFloat, 'FromDate').AsFloat := Date - 365; ObjectSpace.SQLSelect2(cStoreCards, mStoreCardsData, mInputParams); // Sekvenčně - modifikace položky X_Prodej365 // A. Změna přes SQL Update - přímá DB změna bez zápisu sledování změn - obchází business logiku // B. Změna přes business logiku - změny jsou viditelné v sledování změn pokud je nastaveno na třídě mStoreCardsData.First; while not mStoreCardsData.Eof do begin mStoreCardID := mStoreCardsData.Fields.FieldByName('ID').AsString; mDeliveredQuantity := mStoreCardsData.Fields.FieldByName('DeliveredQuantity').AsFloat; // A. Změna přes SQL Update mInputParams.Clear; mInputParams.NewFromDataType(dtString, 'ID').AsString := mStoreCardID; mInputParams.NewFromDataType(dtFloat, 'X_Prodej365').AsFloat := 666; ObjectSpace.SQLExecute(cUpdateStoreCard, mInputParams); // ---A. // nebo // B. Změna přes business logiku mSC := ObjectSpace.CreateObject(Class_StoreCard); try mSC.Load(mStoreCardID); mSC.SetFieldValueAsFloat('X_Prodej365', mDeliveredQuantity); mSC.Save; finally mSC.Free; end; // ---B. mStoreCardsData.Next; end; finally mInputParams.Free; end; finally mStoreCardsData.Free; end; end; begin end.
Skript nejdřív načte data prodejů za posledních 365 dnů a hodnoty uloží do MemoryDataset. Poté sekvenčně projde všechny záznamy datasetu a provede změnu definovatelné položky X_Prodej365. Tady máme na výběr z dvou možností:
A. Změna přes SQL Update - přímá DB změna bez zápisu sledování změn - obchází business logiku
B. Změna přes business logiku - změny hodnot jsou viditelné v sledování změn (pokud je nastaveno na dané třídě).
(v ukázkovém skriptu teda ponechat jenom jednu z možností)
                                                                
Založíme novou naplánovanou úlohu typu Skript.
Provedení naplánované úlohy vykoná přepočet prodejů a hodnoty zapíše do položky X_Prodej365. V číselníku skladových karet po občerstvení již máme napočtené hodnoty prodejů za posledních 365 dnů. Dle položky X_Prodej365 lze seznam i řadit nebo třídit.
 Google Charts v okně náhledů
Google Charts v okně náhledů
                                                        Pro agendu Skladové karty se v okně náhledů zobrazí záložka Prodej, kde bude na Google Charts grafech ukázán prodej 
Je třeba mít vystavěné faktury se zbožím za posledních 14 a 30 dnů na různá střediska, aby skript zobrazoval data.
Druh skriptu je Aplikační modul - Systémové události.
{
Vyvolá se během načítání záložek pro náhled příloh.
}
procedure DocumentsViewer_AddTabs_Hook(const AContext: TNxContext; const ASourceObject: TNxCustomBusinessObject; const ASiteCLSID: string; var AParams: TNxParameters);
var
  mTabData: TNxParameters;
begin
  if ASourceObject.CLSID = Class_StoreCard then
  begin
    mTabData := TNxParameters.Create;
    mTabData.GetOrCreateParam(dtString, 'Name').AsString := 'Prodeje';
    mTabData.GetOrCreateParam(dtString, 'ID').AsString := ASourceObject.OID;
    AParams.AsList.Add(mTabData);
  end;
end;
{
Vyvolá se při kliknutí na záložku bez dat vytvořenou skriptem.
}
procedure DocumentsViewer_AddContent_Hook(const AContext: TNxContext; const ASourceObject: TNxCustomBusinessObject; const ASiteCLSID: string; AID: string; var AParams: TNxParameters);
var
  mInputParams: TNxParameters;
  mTableParams: TNxParameters;
  mParams, mSteppedChartParams: TNxParameters;
  mMemTable: TMemTable;
  mChartPage: TGoogleChartsHtmPage;
  mTableChart, mPieChart, mSteppedChart: string;
  mTableColumns, mPieChartNames: array of string;
  mPieChartValues: array of Double;
  I: Integer;
begin
  if (ASourceObject.CLSID = Class_StoreCard) then
  begin
    mInputParams := TNxParameters.Create;
    mMemTable := TMemTable.Create(nil);
    mTableParams := TNxParameters.Create;
    mSteppedChartParams := TNxParameters.Create;
    try
      mInputParams.NewFromDataType(dtString, 'ID').AsString := ASourceObject.OID;
      mInputParams.NewFromDataType(dtDate, 'DateFrom30').AsDateTime := Now - 30;
      mInputParams.NewFromDataType(dtDate, 'DateFrom14').AsDateTime := Now - 14;
      AContext.SQLSelect2(
        'SELECT D.Code AS Code, '+
        '(SELECT SUM(II2.QUANTITY) '+
          'FROM ISSUEDINVOICES2 II2 '+
          'LEFT JOIN ISSUEDINVOICES II ON II2.Parent_ID = II.ID '+
          'WHERE '+
        '	  II2.DIVISION_ID = D.ID AND '+
          '   II2.StoreCard_ID = :ID AND '+
          '   II.DOCDATE$DATE >= :DateFrom30 '+
          ') AS Q30, '+
          '(SELECT SUM(II2.QUANTITY) '+
          'FROM ISSUEDINVOICES2 II2 '+
          'LEFT JOIN ISSUEDINVOICES II ON II2.Parent_ID = II.ID '+
        '  WHERE '+
        '	  II2.DIVISION_ID = D.ID AND '+
          '   II2.StoreCard_ID = :ID AND '+
          '   II.DOCDATE$DATE >= :DateFrom14 '+
          ') AS Q14 '+
        'FROM DIVISIONS D',
      mMemTable, mInputParams);
      SetLength(mPieChartNames, mMemTable.RecordCount);
      SetLength(mPieChartValues, mMemTable.RecordCount);
      mParams := mSteppedChartParams.NewFromDataType(dtList, '').AsList;
      mParams.NewFromDataType(dtString, '').AsString := 'Středisko';
      mParams.NewFromDataType(dtString, '').AsString := 'Q14';
      mParams.NewFromDataType(dtString, '').AsString := 'Q30';
      mMemTable.First;
      while not mMemTable.Eof do
      begin
        mParams := mTableParams.NewFromDataType(dtList, IntToStr(mMemTable.RecNo)).AsList;
        mParams.NewFromDataType(dtString, 'Středisko').AsString := mMemTable.FieldByName('Code').AsString;
        mParams.NewFromDataType(dtFloat, 'Q14').AsFloat := mMemTable.FieldByName('Q14').AsFloat;
        mParams.NewFromDataType(dtFloat, 'Q30').AsFloat := mMemTable.FieldByName('Q30').AsFloat;
        mPieChartNames[mMemTable.RecNo - 1] := mMemTable.FieldByName('Code').AsString;
        mPieChartValues[mMemTable.RecNo - 1] := mMemTable.FieldByName('Q30').AsFloat;
        mParams := mSteppedChartParams.NewFromDataType(dtList, '').AsList;
        mParams.NewFromDataType(dtString, '').AsString := mMemTable.FieldByName('Code').AsString;
        mParams.NewFromDataType(dtFloat, '').AsFloat := mMemTable.FieldByName('Q14').AsFloat;
        mParams.NewFromDataType(dtFloat, '').AsFloat := mMemTable.FieldByName('Q30').AsFloat;
        mMemTable.Next;
      end;
      SetLength(mTableColumns, 3);
      mTableColumns[0] := 'Středisko';
      mTableColumns[1] := 'Q14';
      mTableColumns[2] := 'Q30';
      mTableChart := CFxGoogleCharts.RenderTableChart('tablechart_Sales', 'Sales', mTableColumns, mTableParams);
      mPieChart := CFxGoogleCharts.RenderPieChart('piechart_Sales', 'Sales', 'Střediska', 'Počet prodaných kusů', mPieChartNames, mPieChartValues);
      mSteppedChart := CFxGoogleCharts.RenderSteppedAreaChart('steppedchart_Sales', 'Sales', mSteppedChartParams);
      mChartPage := TGoogleChartsHtmPage.Create;
      try
        mChartPage.AddChart(mTableChart);
        mChartPage.AddChart(mPieChart);
        mChartPage.AddChart(mSteppedChart);
        AParams.NewFromDataType(dtString, 'Content').AsString := mChartPage.Render('Sales Chart');;
        AParams.NewFromDataType(dtString, 'Format').AsString := 'HTML';
      finally
        mChartPage.Free;
      end;
    finally
      mMemTable.Free;
      mInputParams.Free;
      mTableParams.Free;
      mSteppedChartParams.Free;
    end;
  end;
end;
begin
end. HTML galerie v okně náhledů
HTML galerie v okně náhledů
                                                        
Následující skript načítá pro okno náhledů v agendě Servisované předměty z definovatelné extra položky s názvem Folder a datového typu Znaky cestu k adresáři (cestu zadáváme bez uvozovek), ve kterém můžeme mít uložené přílohy. Ty se zobrazí v samostatných záložkách okna náhledů. Pokud je navíc v této externí složce podsložka s názvem Fotodokumentace, ve které jsou uložené obrázky, vytvoří z těchto obrázků skript náhledovou HTML galerii, která je v okně náhledů zobrazena jako jedna samostatná záložka.
Výsledek v agendě Servisované předměty
Druh skriptu je Aplikační modul - Systémové události.
procedure DocumentsViewer_AddTabs_Hook(const AContext: TNxContext; const ASourceObject: TNxCustomBusinessObject; const ASiteCLSID: string; var AParams: TNxParameters);
var
mPath: string;
mData: TmemoryDataSet;
procedure FillParametersFromUNCFiles;
var
  mList: TStringList;
  i: integer;
  mTabData: TNxParameters;
  mName: string;
  mPathName: string;
begin
  mList := TStringList.Create();
  try
    NxGetFileList(mPath, mList, '*.*', false);
    if mList.Count > 0 then
    begin
      for i := 0 to mList.Count - 1 do
      begin
        mName := extractFileName(mList[i]);
        mPathName := mPath + '\' + mList[i];
        if (not DirectoryExists(mPathName)) then
        begin
          mTabData := TNxParameters.Create;
          mTabData.GetOrCreateParam(dtString, 'Name').AsString := mName;
          mTabData.GetOrCreateParam(dtString, 'ID').AsString := mPath + IntToStr(i);
          mTabData.GetOrCreateParam(dtString, 'Path').AsString := mPathName;
          AParams.AsList.Add(mTabData);
        end;
      end;
    end;
  finally
    mList.Free;
  end;
end;
procedure FillGaleryTabFromUNCFiles(aName: String);
var
  mTabData: TNxParameters;
begin
  mTabData := TNxParameters.Create;
  mTabData.GetOrCreateParam(dtString, 'Name').AsString := aName;
  mTabData.GetOrCreateParam(dtString, 'ID').AsString := mPath;
  AParams.AsList.Add(mTabData);
end;
begin
case ASourceObject.CLSID of
  Class_Storecard:
    begin
      mPath := NxEvalObjectExprAsStringDef(ASourceObject, 'X_Folder', '');
      if DirectoryExists(mPath) and (mPath <> '') then FillParametersFromUNCFiles;
    end;
  Class_BusOrder:
    begin
      mPath := NxEvalObjectExprAsStringDef(ASourceObject, 'X_Folder', '');
      if DirectoryExists(mPath) and (mPath <> '') then FillParametersFromUNCFiles;
    end;
  Class_PLMProduceRequest, Class_PLMJobOrder:
    begin
      mPath := NxEvalObjectExprAsStringDef(ASourceObject, 'Storecard_ID.X_Folder', '');
      if DirectoryExists(mPath) and (mPath <> '') then FillParametersFromUNCFiles;
      mPath := NxEvalObjectExprAsStringDef(ASourceObject, 'BusOrder_ID.X_Folder', '');
      if DirectoryExists(mPath) and (mPath <> '') then FillParametersFromUNCFiles;
    end;
  Class_ServiceDocument:
    begin
      mPath := NxEvalObjectExprAsStringDef(ASourceObject, 'ServicedObject_ID.X_Folder', '');
      if DirectoryExists(mPath) and (mPath <> '') then FillParametersFromUNCFiles;
      mPath := NxEvalObjectExprAsStringDef(ASourceObject, 'BusOrder_ID.X_Folder', '');
      if DirectoryExists(mPath) and (mPath <> '') then FillParametersFromUNCFiles;
      mPath := NxEvalObjectExprAsStringDef(ASourceObject, 'ServicedObject_ID.X_Folder', '') + '\Fotodokumentace';
      if DirectoryExists(mPath) and (mPath <> '') then FillGaleryTabFromUNCFiles('Fotodokumentace');
    end;
  Class_ServicedObject:
    begin
      mPath := NxEvalObjectExprAsStringDef(ASourceObject, 'X_Folder', '');
      if DirectoryExists(mPath) and (mPath <> '') then FillParametersFromUNCFiles;
      mPath := NxEvalObjectExprAsStringDef(ASourceObject, 'X_Folder', '') + '\Fotodokumentace';
      if DirectoryExists(mPath) and (mPath <> '') then FillGaleryTabFromUNCFiles('Fotodokumentace');
    end;
  Class_ServicedObjectType:
    begin
      try
        mData := TMemoryDataSet.Create(nil);
        ASourceObject.ObjectSpace.SQLSElect2('select x_folder,x_sn from servicedobjects where servicedobjecttype_id = ' + QuotedStr(ASourceObject.OID), mData);
        if mData.Active then
        begin
          mData.First;
          while not mData.Eof do
          begin
            mPath := mData.FieldByName('X_Folder').AsString + '\Fotodokumentace';
            if DirectoryExists(mPath) and (mPath <> '') then FillGaleryTabFromUNCFiles(mData.FieldByName('x_sn').AsString);
            mData.Next;
          end;
        end;
      finally
        mData.Free;
      end;
    end;
end;
end;
procedure DocumentsViewer_AddContent_Hook(const AContext: TNxContext; const ASourceObject: TNxCustomBusinessObject; const ASiteCLSID: string; AID: string; var AParams: TNxParameters);
var
mPath: string;
procedure FillDataSetFromUNCPictures;
var
  mList, mHTMLPict: TStringList;
  i: integer;
  mFileNamepict: string;
  mContent: TNxParameters;
begin
  mList := TStringList.Create();
  mHTMLPict := TStringList.Create();
  try
    NxGetFileList(mPath, mList, '*.jpg', false);
    if mList.Count > 0 then
      for i := 0 to mList.Count - 1 do
        if Fileexists(mPath + '\' + mList[i]) then
          mHTMLPict.Add('<strong>' + mList[i] + '</strong><br /><a href="' + mPath + '\' + mList[i] + '" target="_blank"><img src="' + mPath + '\' + mList[i] + '" width="350"  /></a><br />');
    NxGetFileList(mPath, mList, '*.jpeg', false);
    if mList.Count > 0 then
      for i := 0 to mList.Count - 1 do
        if Fileexists(mPath + '\' + mList[i]) then
          mHTMLPict.Add('<strong>' + mList[i] + '</strong><br /><a href="' + mPath + '\' + mList[i] + '" target="_blank"><img src="' + mPath + '\' + mList[i] + '" width="350"  /></a><br />');
    NxGetFileList(mPath, mList, '*.png', false);
    if mList.Count > 0 then
      for i := 0 to mList.Count - 1 do
        if Fileexists(mPath + '\' + mList[i]) then
          mHTMLPict.Add('<strong>' + mList[i] + '</strong><br /><a href="' + mPath + '\' + mList[i] + '" target="_blank"><img src="' + mPath + '\' + mList[i] + '" width="350"  /></a><br />');
    NxGetFileList(mPath, mList, '*.bmp', false);
    if mList.Count > 0 then
      for i := 0 to mList.Count - 1 do
        if Fileexists(mPath + '\' + mList[i]) then
          mHTMLPict.Add('<strong>' + mList[i] + '</strong><br /><a href="' + mPath + '\' + mList[i] + '" target="_blank"><img src="' + mPath + '\' + mList[i] + '" width="350"  /></a><br />');
    if mHTMLPict.Count > 0 then
    begin
      AParams.NewFromDataType(dtString, 'Content').AsString := mHTMLPict.Text;
      AParams.NewFromDataType(dtString, 'Format').AsString := 'HTML';
    end;
  finally
    mList.Free;
    mHTMLPict.Free;
  end;
end;
begin
mPath := AID;
case ASourceObject.CLSID of
  Class_ServiceDocument:
  begin
    if DirectoryExists(mPath) and (mPath <> '') then FillDataSetFromUNCPictures;
  end;
  Class_ServicedObject:
  begin
    if DirectoryExists(mPath) and (mPath <> '') then FillDataSetFromUNCPictures;
  end;
  Class_ServicedObjectType:
  begin
    if DirectoryExists(mPath) and (mPath <> '') then FillDataSetFromUNCPictures;
  end;
end;
end;
begin
end. Příklad získání přístupového tokenu pro Firebase Cloud Messaging API (V1)
 Příklad získání přístupového tokenu pro Firebase Cloud Messaging API (V1)
                                                        Následující příklad ukazuje, jak získat přístupový token potřebný pro autentizaci při komunikaci s novým Firebase Cloud Messaging API (V1) pomocí protokolu OAuth 2.0. Token je generován na základě privátního klíče servisního účtu Google a obsahuje oprávnění specifická pro službu Firebase Messaging.
procedure GetAccessToken(Sender: TBasicAction);
const
  GOOGLE_AUTH_JSON = '{' +
	'"type": "service_account",' +
	'"project_id": "**********",' +
	'"private_key_id": "**************************************",' +
	'"private_key": "-----BEGIN PRIVATE KEY-----\*******************************' +
	  '****************************\n-----END PRIVATE KEY-----\n",' +
	'"client_email": "firebase-adminsdk-*****@********.iam.gserviceaccount.com",' +
	'"client_id": "*******************",' +
	'"auth_uri": "https://accounts.google.com/o/oauth2/auth",' +
	'"token_uri": "https://oauth2.googleapis.com/token",' +
	'"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",' +
	'"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-************.iam.gserviceaccount.com",' +
	'"universe_domain": "googleapis.com"' +
	'}';
begin
  // získáme access token ke službě "firebase.messaging" přes OAuth 2.0 na základě údajů Google servisního účtu
  ShowMessage(CFxInternet.GetGoogleOAuth2AccessToken(GOOGLE_AUTH_JSON, 'https://www.googleapis.com/auth/firebase.messaging', jwtaRS256, 60));
end; Otevření dokladové agendy ze skriptování s vyplněnými podmínkami v omezení
Otevření dokladové agendy ze skriptování s vyplněnými podmínkami v omezení
                                                        
procedure InitSite_Hook(Self: TSiteForm);
var
 mAction: TMultiAction;
begin
  mAction := Self.GetNewMultiAction;
  mAction.ShowControl := True;
  mAction.ShowMenuItem := True;
  mAction.Caption := 'Dohledat ve fakturách';
  mAction.Items.Add('Dohledat ve fakturách vydaných (script)');
  mAction.Category := 'tabList';
  mAction.OnExecuteItem := @Test;
end;
procedure Test(Sender: TObject; AIndex :Integer);
var
  mSite: TSiteForm;
  mParams, mDefaultSelection: TNxParameters;
  mParCondition: TNxParameter;
  mTmpList: TStringList;
  mTmpPar: TNxParameter;
  mValues: TNxParameters;
begin
 mSite := TComponent(Sender).Site;
 mParams := TNxParameters.Create;
 try
   mParams.NewFromDataType(dtString, '_SelectionCaption').AsString := 'Otevřeno ze skriptování řada FV nezaplacené pro firmy A%';
   mDefaultSelection := mParams.NewFromDataType(dtList, '_DefaultSelection').AsList;
   mParCondition := mDefaultSelection.AsList.NewFromDataType(dtList, 'CONDITIONS');
   mTmpPar := mParCondition.AsList.NewFromDataType(dtList, 'DocDate');
   mTmpPar.AsList.NewFromDataType(dtInteger, 'USEDKIND').AsInteger := ckRange;
   mValues := mTmpPar.AsList.NewFromDataType(dtList, 'VALUES').AsList;
   mValues.NewFromDataType(dtString, '{:LOW}').AsString := '0';
   mValues.NewFromDataType(dtString, '{:HIGH}').AsString := '45659';
   mTmpPar := mParCondition.AsList.NewFromDataType(dtList, 'PaidStatus');
   mTmpPar.AsList.NewFromDataType(dtInteger, 'USEDKIND').AsInteger := ckSingle;
   mValues := mTmpPar.AsList.NewFromDataType(dtList, 'VALUES').AsList;
   mValues.NewFromDataType(dtString, '{:VALUE}').AsString := '1;2;';
   mTmpPar := mParCondition.AsList.NewFromDataType(dtList, 'UserDynSQLCondition');
   mTmpPar.AsList.NewFromDataType(dtInteger, 'USEDKIND').AsInteger := ckSingle;
   mValues := mTmpPar.AsList.NewFromDataType(dtList, 'VALUEBAG').AsList;
   mValues.NewFromDataType(dtString, 'DYNUSERSQL').AsString := '(SELECT Name FROM Firms UserSQLFirm WHERE UserSQLFirm.ID = A.Firm_ID) LIKE ''A%''';
   mTmpPar := mParCondition.AsList.NewFromDataType(dtList, 'DocQueue_ID');
   mTmpPar.AsList.NewFromDataType(dtInteger, 'USEDKIND').AsInteger := ckList;
   mTmpPar.AsList.NewFromDataType(dtString, 'VALUELIST').AsString := '''5600000101''';
   mSite.ShowDynForm(Site_IssuedInvoices, mParams, nil, True, '');
  finally
    mParams.Free;
  end;
end;
begin
end. Autorizace pomocí protokolu OAuth 2.0
Autorizace pomocí protokolu OAuth 2.0
                                                        Od verze 25.0.93 lze využít tento poměrně rozšířený a bezpečný standard přímo z prostředí skriptování pomocí třídy TOAuth2Wizard. Díky tomu jsme schopni využívat služeb poskytovatelů, kteří podporují ověření uživatele prostřednictvím třetí strany, případně sami používají vlastní identity server.
Příklad napojení na službu Everifin, která poskytuje služby otevřeného bankovnictví s licencí PSD2:
procedure UserLogin(aSite: TSiteForm);
var
  mOauth: TOAuth2Wizard;
begin
  mOauth := TOAuth2Wizard.Create(aSite.SiteContext);
  try
    mOauth.ClientSecret := 'XXXXX';
    mOauth.ClientId := 'abra-test';
    mOauth.Scope := 'ais';
    mOauth.AuthorizationUrl := 'https://api.everifin.com/auth/realms/everifin_app/protocol/openid-connect/auth?...';
    mOauth.OnResponse := @OAuth2Wizard_Response;
    mOauth.SkipLoginPage := True;
    mOauth.Execute(aSite.FindParentForm);
  finally
    mOauth.Free;
  end;
end;procedure OAuth2Wizard_Response(Sender: TObject; aRequestParams: TStrings; var aState: TNxOAuth2ResultAuthorizationStatus; var aMessage: string);
var
  mCode: String;
  mOS: TNxCustomObjectSpace;
  mToken: String;
  mTokenEncrypted: String;
begin
  aState := noasNone;
  aMessage := '';
  try
    mCode := aRequestParams.Values('code');
    if NxIsBlank(mCode) then begin
      RaiseException('Parameter ''code'' se nenašel.');
    end;
    if not (Sender is TOAuth2Wizard) then begin
      RaiseException('Incompatible sender type.');
    end;
    mOS := TOAuth2Wizard(Sender).ObjectSpace;
    mToken := ObtainAccessToken(mOS, mCode); // Získání přístupového tokenu přes Web API
    mTokenEncrypted := CFxCrypt.EncryptWithANSIKeyToBase64(cCryptoSecretKey, TEncoding.UTF8.GetBytes(mToken)); // Zašifrování tokenu
    // Zde může přijít uchování zašifrovaného tokenu.
    aState := noasOK;
  except
    aState := noasError;
    aMessage := TrimExMessage(ExceptionMessage);
  end;
end;Proces ověření ve zkratce:
- 
                                                                    Vyvolání průvodce OAuth2 
- 
                                                                    Zadání přihlašovacích údajů 
- 
                                                                    V případě úspěšného ověření přesměrování na adresu uvedenou v parametru „redirect_uri“ vlastnosti AuthorizationURL 
- 
                                                                    V obsluze události OnResponse získáme autorizační kód, pomocí kterého požádáme o přístupový token 
- 
                                                                    Získaný token zašifrujeme s využitím třídy CFxCrypt a uložíme např. do CompanyCache ABRA Gen 
 Zobrazení údajů z objednávky přijaté v okně náhledů
Zobrazení údajů z objednávky přijaté v okně náhledů
                                                        Pro agendu Objednávky přijaté (OP) se v okně náhledů zobrazí záložka Objednávka přijatá, kde bude zobrazeno číslo dokladu, celková lokální cena a řádky dané objednávky
Nejprve je třeba vytvořit soubor style.css, který umístíme do instalačního adresář sytému ABRA Gen, podsložky _Nahledy. V našem příkladu se jedná o cestu:
c:/ABRA/INSTALACE/DEVELOP/CS/25.2/AbraGen-25.3.0-cs-CZ-debug-250318-1919-d2fc8a6/_Nahledy/style.css
Ve skriptu níže je tuto cestu třeba nahradit dle vaší potřeby.
Obsah style.css:
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f8f8f8;
color: #333;
}
h1 {
color: #0057a3;
font-size: 24px;
margin-bottom: 10px;
}
h2 {
color: #0057a3;
font-size: 18px;
margin-bottom: 10px;
}
p {
font-size: 14px;
line-height: 1.6;
}Dále vytvoříme skript v agendě Balíčky skriptů. Druh skriptu bude Aplikační modul - Systémové události.
procedure DocumentsViewer_AddTabs_Hook(const AContext: TNxContext; const ASourceObject: TNxCustomBusinessObject;
  const ASiteCLSID: string; var AParams: TNxParameters);
var
  mTabData: TNxParameters;
begin
  if ASourceObject.CLSID = Class_ReceivedOrder then
  begin
	mTabData := TNxParameters.Create;
	mTabData.GetOrCreateParam(dtString, 'Name').AsString := 'Objednávka přijatá';  // Název záložky
	mTabData.GetOrCreateParam(dtString, 'ID').AsString := 'HTMLFormTab_' + ASourceObject.OID;
	AParams.AsList.Add(mTabData);
  end;
end;
procedure DocumentsViewer_AddContent_Hook(const AContext: TNxContext; const ASourceObject: TNxCustomBusinessObject;
  const ASiteCLSID: string; AID: string; var AParams: TNxParameters);
var
  mHtml: string;
  mMemTableAmount, mMemTableRows: TMemTable;
  mInputParams: TNxParameters;
  mAmount: Double;
  mRowType: Integer;
  mText, mStoreCardName, mDisplayText: string;
  mOrderNumber: string;
  mDocQueueCode, mPeriodCode: string;
begin
  if (ASourceObject.CLSID = Class_ReceivedOrder) and (AID = 'HTMLFormTab_' + ASourceObject.OID) then
  begin
	mInputParams := TNxParameters.Create;
	mMemTableAmount := TMemTable.Create(nil);
	mMemTableRows := TMemTable.Create(nil);
	try
	  mInputParams.NewFromDataType(dtString, 'ID').AsString := ASourceObject.OID;
	  // Načtení hlavičkových údajů: Amount, DQ.Code, OrdNumber, P.Code
	  AContext.SQLSelect2(
		'SELECT RO.LOCALAMOUNT, RO.ORDNUMBER, DQ.CODE AS DOCQUEUECODE, P.CODE AS PERIODCODE ' +
		'FROM RECEIVEDORDERS RO ' +
		'JOIN PERIODS P ON P.ID = RO.PERIOD_ID ' +
		'JOIN DOCQUEUES DQ ON DQ.ID = RO.DOCQUEUE_ID ' +
		'WHERE RO.ID = :ID',
		mMemTableAmount,
		mInputParams
	  );
	  if not mMemTableAmount.IsEmpty then
	  begin
		mAmount := mMemTableAmount.FieldByName('LOCALAMOUNT').AsFloat;
		mDocQueueCode := mMemTableAmount.FieldByName('DOCQUEUECODE').AsString;
		mPeriodCode := mMemTableAmount.FieldByName('PERIODCODE').AsString;
		mOrderNumber := mDocQueueCode + '-' + IntToStr(mMemTableAmount.FieldByName('ORDNUMBER').AsInteger) + '/' + mPeriodCode;
	  end
	  else
	  begin
		mAmount := 0;
		mOrderNumber := '[neznámé číslo]';
	  end;
	  // Načtení řádků objednávky
	  AContext.SQLSelect2(
		'SELECT RO2.ROWTYPE, RO2.TEXT, SC.NAME ' +
		'FROM RECEIVEDORDERS2 RO2 ' +
		'LEFT JOIN STORECARDS SC ON SC.ID = RO2.STORECARD_ID ' +
		'WHERE RO2.PARENT_ID = :ID',
		mMemTableRows,
		mInputParams
	  );
	  // HTML výstup
	  mHtml :=
		'<!DOCTYPE html>'#13#10 +
		'<html>'#13#10 +
		'<head>'#13#10 +
		'  <meta charset="UTF-8">'#13#10 +
		'  <link rel="stylesheet" href="file:///c:/ABRA/INSTALACE/DEVELOP/CS/25.2/AbraGen-25.3.0-cs-CZ-debug-250318-1919-d2fc8a6/_Nahledy/style.css">'#13#10 +
		'  <title>Objednávka přijatá</title>'#13#10 +
		'</head>'#13#10 +
		'<body>'#13#10 +
		'  <h1>' + mOrderNumber + '</h1>'#13#10 +
		'  <p><strong>Celková cena (lok.):</strong> ' + FormatFloat('#,##0.00 Kč', mAmount) + '</p>'#13#10 +
		'  <h2>Řádky:</h2>'#13#10 +
		'  <ul>'#13#10;
	  mMemTableRows.First;
	  while not mMemTableRows.Eof do
	  begin
		mRowType := mMemTableRows.FieldByName('ROWTYPE').AsInteger;
		mText := mMemTableRows.FieldByName('TEXT').AsString;
		mStoreCardName := mMemTableRows.FieldByName('NAME').AsString;
		if mRowType = 3 then
		  mDisplayText := mStoreCardName
		else
		  mDisplayText := mText;
		mHtml := mHtml + '    <li>Typ (' + IntToStr(mRowType) + ') - ' + mDisplayText + '</li>'#13#10;
		mMemTableRows.Next;
	  end;
	  mHtml := mHtml +
		'  </ul>'#13#10 +
		'</body>'#13#10 +
		'</html>'#13#10;
	  AParams.NewFromDataType(dtString, 'Content').AsString := mHtml;
	  AParams.NewFromDataType(dtString, 'Format').AsString := 'HTML';
	finally
	  mMemTableAmount.Free;
	  mMemTableRows.Free;
	  mInputParams.Free;
	end;
  end;
end;
begin
end. Příklad pro práci se slevami na kase v Maloobchodním prodeji
 Příklad pro práci se slevami na kase v Maloobchodním prodeji
                                                        Toto je příklad skriptu, který vyplňuje text do políčka “Popis slevy” v závislosti na hodnotách objektu slev. V tomto skriptu je využit háček BeforeShowPOSCashDiscountParamsForm_Hook. Háček je dostupný ve všech aplikačních modulech kas. Háček se vyvolá před zobrazením formuláře pro zadání slevy. V parametrech háčku je předávaný objekt slev na kase a vlastní formulář pro zadání slev.
{
Vyvolá se před zobrazením formuláře pro zadání slevy.)
}
procedure BeforeShowPOSCashDiscountParamsForm_Hook(AContext: TNxContext; ADiscount: TNxCustomBusinessObject; var APOSCashDiscountParamsForm: TForm);
var
  edDiscountText: TEdit;
  mDiscountKind: integer;
  mDiscountKindText: string;
begin
  edDiscountText := TEdit(APOSCashDiscountParamsForm.FindChildControl('edDiscountText'));
  //edDiscountText.Text := 'init sleva kód: ' + ADiscount.GetFieldValueAsString('Code');
  mDiscountKind := ADiscount.GetFieldValueAsInteger('DiscountKind');
  {
  0 - Akční sleva
  1 - Finanční na zboží automatická
  2 - Finanční na řádek
  3 - Finanční na zboží
  4 - Finanční na doklad
  5 - Procentní na doklad
  6 - Automatická procentní na zboží na dokladu
  7 - Procentní řádková
  8 - Procentní řádková na zboží
  9 - Procentní...
  }
  case mDiscountKind of
    0: mDiscountKindText := 'Akční';
    1..4: mDiscountKindText := 'Finanční';
    5..9: mDiscountKindText := 'Procentní';
  else
    mDiscountKindText := 'Mimo rozsah';
  end;
  edDiscountText.Text := ADiscount.GetFieldValueAsString('Code') + '-' + mDiscountKindText + ': ' + ADiscount.GetFieldValueAsString('DiscountDescription') + ' (' + IntToStr(mDiscountKind) + ')';
end;
begin
end.; Tisk ze skriptu pomocí NxPrintByIDs a CFxReportManager.PrintByIDs (rozšířené použití)
 Tisk ze skriptu pomocí NxPrintByIDs a CFxReportManager.PrintByIDs (rozšířené použití)
                                                        Přiklady použití NxPrintByIDs, NxPrintByConditions:
procedure PrintReports_Test(Sender: TControl);
var
  mContext: TNxContext;
  i: Integer;
  mSite: TSiteForm;
  mSCList: TStringList;
  mConditions, mCondParams, mCondParamsValues, mExtraParams: TNxParameters;
begin
  mSite := TSiteForm(TComponent(Sender).Site);
  mContext := NxCreateContext(mSite.BaseObjectSpace);
  try
    mConditions := TNxParameters.Create;
    try
      mSCList := TStringList.Create;
		try
//Tisk Reportu (Agenda Reporty)
//Nastavení omezení reportu za datum, sklady a skladové karty					
        //Omezení za Datum
        mCondParams := mConditions.NewFromDataType(dtList, 'Date').AsList;
        mCondParams.NewFromDataType(dtInteger, 'UsedKind').AsInteger := ckRange;
        mCondParamsValues := mCondParams.NewFromDataType(dtList, 'Values').AsList;
        // Omezení za datum je sice typu ckRange, ale jako údaj pro omezení (k datu)
        // se bere jenom hodnota "LOW"
        mCondParamsValues.NewFromDataType(dtFloat, '{:LOW}').AsFloat := 43449;    // 15.12.2018
        //mCondParamsValues.NewFromDataType(dtFloat, '{:HIGH}').AsFloat := Date;    // dnes
        // Omezení za sklady (výběr seznamem - řetězec reprezentující seznam ID - oddělené Entrem)
        mCondParams := mConditions.NewFromDataType(dtList, 'Store_ID').AsList;
        mCondParams.NewFromDataType(dtInteger, 'UsedKind').AsInteger := ckList;
        mCondParams.NewFromDataType(dtString, 'ValueList').AsString := '2100000101'#13#10'3500000101';
        // Omezení za skladové karty (výběr seznamem - TStringList)
        // StringList naplníme přes SQL SELECT
        mSite.BaseObjectSpace.SQLSelect('SELECT ID FROM StoreCards WHERE Code LIKE ''0%''', mSCList);
        mCondParams := mConditions.NewFromDataType(dtList, 'StoreCard_ID').AsList;
        mCondParams.NewFromDataType(dtInteger, 'UsedKind').AsInteger := ckList;
        mCondParams.NewFromDataType(dtString, 'ValueList').AsString := NxStringsToCkListStr(mSCList);					
//Provede tisk přímo na tiskárnu dle omezení v mConditions - Report "Stav skladu k datu"					
						
						
        // tisk přímo na tiskárnu
        NxPrintByConditions(mContext,
        mConditions,                         //  Omezení pro report - podmínky
        'DCGGWH4VRREL3FWD002BG34ZPK',        //  DynSQL - "Sklad - Stav k datu"
        'V700000001',                        //  Report ID - "Stav skladu k datu"
        rtoPrint,                            //  Typ operace - Tisk na tiskárnu
        pekARP,                              //  Typ exportu
        'KONICA MINOLTA C223',               //  Výstup - název tiskárny
        '');                                 //  (slouží pro název souboru v případě tisku do souboru)						
        //Provede tisk do souboru PDF dle omezení v mConditions - Report "Stav skladu k datu"
        // tisk do souboru PDF
        NxPrintByConditions(mContext,
        mConditions,                         //  Omezení pro report - podmínky
        'DCGGWH4VRREL3FWD002BG34ZPK',        //  DynSQL - "Sklad - Stav k datu"
        'V700000001',                        //  Report ID - "Stav skladu k datu"
        rtoFile,                             //  Typ operace - Tisk na tiskárnu
        pekPDF,                              //  Typ expByCoortu
        'C:\ABRA',                           //  Výstup - cesta k souboru  (zadávat formát C:\ABRA\)
        'Report Skladu - Stav k datu.pdf');  //  Název souboru
						
						
        //Tisk tiskových sestav dle identifikací objektů
        //S rozšířeným nastavením tiskárny (Collate, Duplex)
						
        // Rozšířené nastavení riskárny
        mExtraParams := TNxParameters.Create;
        try
        //  Zapneme kompletování kopií
        //  true -> kopie budou tisknuty    1,2,3     1,2,3
        //  false -> kopie budou tisknuty   1,1   2,2   3,3
        mExtraParams.GetOrCreateParam(dtBoolean, 'REPORT_COLLATE').AsBoolean := True;
        //  Zapneme oboustranný tisk
        mExtraParams.GetOrCreateParam(dtBoolean, 'REPORT_DUPLEX').AsBoolean := True;						
						
        //Provede tisk tiskové sestavy “Seznam zboží (kód)” přímo na tiskárnu - omezení je dáno seznamem ID skladových karet
        // tisk tiskové sestavy
        NxPrintByIDs(mContext,
        mSCList,                             //  Seznam ID skladových karet
        'OGQQA2C25JDL342N01C0CX3FCC',        //  DynSource - Skladové karty
        'F300000001',                        //  Report ID - "Seznam zboží (kód)"
        rtoPrint,                            //  Typ operace - Tisk na tiskárnu
        pekARP,                              //  Typ expByCoortu
        'KONICA MINOLTA C223',               //  Výstup - cesta k souboru
        '',                                  //  Název souboru
        2,                                   //  Počet kopií
        false,                               //  Emulovat kopie
        mExtraParams);                       //  Předává parametry pro tisk - Duplex nebo Collate
        
    
        //Provede tisk tiskové sestavy “Seznam zboží (kód)” do souboru PDF - omezení je dáno seznamem ID skladových karet
        // tisk tiskové sestavy.do souboru
        NxPrintByIDs(mContext,
        mSCList,                             //  Seznam ID skladových karet
        'OGQQA2C25JDL342N01C0CX3FCC',        //  DynSource - Skladové karty
        'F300000001',                        //  Report ID - "Seznam zboží (kód)"
        rtoFile,                             //  Typ operace - Tisk na tiskárnu
        pekPDF,                              //  Typ expByCoortu
        'C:\ABRA',                           //  Výstup - cesta k souboru (zadávat formát C:\ABRA\)
        'Seznam zboží(kód).pdf',             //  Název souboru
        2);                                  //  Počet kopií
						
        //  Provede tisk tiskové sestavy "Seznam zboží (kód)" do souboru PDF - omezení je dáno seznamem ID skladových karet
        //  Parametr tiskárny při tisku do souboru způsobí, že se vynutí převzetí nastavení papíru z této tiskárny			
        CFxReportManager.PrintByIDs(mContext,
        mSCList,                             //  Seznam ID skladových karet
        'OGQQA2C25JDL342N01C0CX3FCC',        //  DynSource - Skladové karty
        'F300000001',                        //  Report ID - "Seznam zboží (kód)"
        rtoFile,                             //  Typ operace - Tisk na tiskárnu
        pekPDF,                              //  Typ exoortu
        'C:\ABRA\test\develop',              //  Výstup - cesta k souboru
        'Seznam zboží(kód)_printer_KM.pdf',  //  Název souboru
        1, false, nil,                       //  Počet kopií + emulateCopies + AParams
        'KONICA MINOLTA C223');              //  Název tiskárny, z které se přebírá nastavení stránky/papíru
						
        finally
          mExtraParams.Free;
        end;
      finally
        mSCList.Free;
      end;
    finally
      mConditions.Free;
    end;
  finally
    mContext.Free;
  end;
end;			Nastavení kompletace a oboustranný tisk se předává pomocí parametru třídy TNxParameters.
Emulace kopií se používá pro tiskárny, které nepřebírají počet kopií.
POZOR: Pokud tiskárna umožňuje přebírání počtu kopií, mějte parametr EmulateCopies vypnutý. V opačném případě bude tiskárna tisknout exponenciální počet kopií, místo 2 vytiskne 4, místo 3 vytiskne 9 atd.
Funkce NxPrintByConditions umožňuje tisk Reportů (agenda Reporty) dle zadaného omezení, například Stav skladu k datu , Prodané zboží dle skladů, Obraty účtů atd.
Parametr určující název tiskárny Počet kopií a emulace byli přidány jako parametry funkce již ve verzi 19.0.
Od verze 25.3 byla přidána možnost výběru tiskárny při tisku do souboru - tím se vynutí převzetí nastavení .
 Přidání prvku do stromu kusovníku
 Přidání prvku do stromu kusovníku
                                                        Příklad na přidání náhledu obrázku skladové karty do levé části stromu kusovníku. Při přechodu položkami stromu se v levé části zobrazuje obrázek z dané skladové karty. Pokud položka obrázek nemá, načteme předem připraven obrázek no_image. To může být například bílý obrázek nebo upozoronění, že obrázek nebyl načten.
{
Vyvolává se po provedení inicializace agendy/formuláře. V tento okamžik je již na formuláři dostupný SiteContext.
}
procedure InitSite_Hook(Self: TSiteForm);
var
  TreeView: TVirtualStringTree;
begin
  With TPanel.Create(Self) do
  begin
    Parent:= TTabSheet(Self.FindChildControl('tabTree'));
    Align:= alLeft;
    Width:= 600;
    Name:= 'Tree_Pict';
    Caption:= '';
  end;
  with TImage.Create(TPanel(Self.FindChildControl('Tree_Pict'))) do
  begin
    Parent:= TPanel(Self.FindChildControl('Tree_Pict'));
    Name:= 'pctStoreCard_Picture';
    Align:= alClient;
    AutoSize:=True;
  end;
  TreeView:= TVirtualStringTree(TTabSheet(Self.FindChildControl('tabTree')).FindChildControl('TreeView'));
  if Assigned(TreeView) then
  begin
    TreeView.OnAfterFocusChanged := @My_OnAfterFocusChanged;
  end;
end;
{
Vyvolá se před zobrazením formuláře pro zadání slevy.)
}
procedure My_OnAfterFocusChanged(Sender: TObject);
var
mPicture: TNxCustomBusinessObject;
mStream: TMemoryStream;
  mBO: TNxCustomBusinessObject;
  mSQL,mID: String;
begin
  try
    if Assigned(TImage(TVirtualStringTree(Sender).GetParentForm.FindChildControl('pctStoreCard_Picture'))) then
      if TVirtualStringTree(Sender).GetFocusedNodeTextByColumn(0) <> '' then					
      begin
        mBO:= TVirtualStringTree(Sender).Site.BaseObjectSpace.CreateObject(Class_StoreCard);
        try
          // TVirtualStringTree(Sender).GetFocusedNodeTextByColumn(0) - získá z prvního sloupce kód skladové karty
		  mSQL:= 'Select ID '+
          'From StoreCards '+
          'Where Hidden = ''N'' and Code = '+QuotedStr(TVirtualStringTree(Sender).GetFocusedNodeTextByColumn(0));
          mID:= TVirtualStringTree(Sender).Site.BaseObjectSpace.SQLSelectFirstAsString(mSQL,'');
          // Obrázek uložený na Skl. Kartě
          if Not NxIsEmptyOID(mID) then
          begin
            mBO.Load(mID,nil);
            mStream:= TMemoryStream.Create;
            mPicture:= TVirtualStringTree(Sender).Site.BaseObjectSpace.CreateObject(Class_Picture);
            try
              if mPicture.Test(mBO.GetFieldValueAsString('Picture_ID')) then
              begin
                mPicture.Load(mBO.GetFieldValueAsString('Picture_ID'),nil);
                mStream.SetBytes(mPicture.GetFieldValueAsBytes('BlobData'));
                TImage(TVirtualStringTree(Sender).Site.FindChildControl('pctStoreCard_Picture')).Picture.LoadMultiFormatFromStream(mStream);
              end
              else
                // Pokud položka nemá obrázek, načteme předem připraven obrázek no_image - to může být například upozornění, že neobsahuje obrázek nebo prázdný obrázek
                TImage(TVirtualStringTree(Sender).Site.FindChildControl('pctStoreCard_Picture')).Picture.LoadFromFile('.\no_image.png');
            finally
              mPicture.Free;
              mStream.Free;
            end;
          end;
        finally
          mBO.Free;
        end;
      end;
  except
    // Zahazuju chyby - případně vyvést chybu pomocí RaiseException 
    // nebo do okna s obrázkem vypsat text chyby (ExceptionMessage)
  end;
end;
 Testování hodnoty
Testování hodnoty null a existence parametru v objektu TJSONSuperObject
                                                        Tento příklad ukazuje, jak v prostředí skriptování testovat, zda má parametr v objektu TJSONSuperObject hodnotu null, a jak takovou hodnotu výslovně zapsat. Zároveň ukazuje, jak ověřit existenci parametru, který může nebo nemusí být ve vstupním JSONu přítomen.
var
  mSQL: string;
  mJSON: TJSONSuperObject;
  mO: TJSONSuperObject;
begin
  mJSON := TJSONSuperObject.Create;
  try
    mJSON.O['hodnotaNull'] := TJSONSuperObject.CreateByDataType(jtNull); // Nastavení null hodnoty
    mJSON.I['cislo_cele'] := 12345;
    ShowMessage(mJSON.AsJson);
    mO := mJSON.O['neexistuje'];
    if not mO.Exists then // Test existence parametru
      ShowMessage('O[''neexistuje''].Exists = False');
    if mJSON.O['hodnotaNull'].DataType = jtNull then // Test null hodnoty
      ShowMessage('mJSON.O[''hodnotaNull''].DataType = jtNull');
  finally
    mJSON.Free;
  end;
end;Výsledek skriptu:
|   |   |   | 












