OBS/Makros und Scripting/Anwendungsbereiche/Drucke: Unterschied zwischen den Versionen

Aus OBS Wiki
Zur Navigation springen Zur Suche springen
Zeile 50: Zeile 50:


Beispiel eines angepassten Angebot-Drucks mit diversen Anpassungen:  
Beispiel eines angepassten Angebot-Drucks mit diversen Anpassungen:  
<source lang="delphi">
  //------------------------------------------------------------------------------
  //------------------------------------------------------------------------------
  // Unit Name: Angebot
  // Unit Name: Angebot
Zeile 164: Zeile 165:
     result := StartProc(cVar, cAngNr, nParCnt, lPrintModusi, obj);     
     result := StartProc(cVar, cAngNr, nParCnt, lPrintModusi, obj);     
  end;
  end;
 
</source>
Dazugehörige User.inx:  
Dazugehörige User.inx:  
 
<source lang="delphi">
  //------------------------------------------------------------------
  //------------------------------------------------------------------
  //Ausgabe Ansprechpartner/Projekt im Kopf
  //Ausgabe Ansprechpartner/Projekt im Kopf
Zeile 215: Zeile 216:
     qRep_PictPrint(EZ,GL_EXEPath+'data\druck\user\Briefbogen.png',-100,800,1150,-220);
     qRep_PictPrint(EZ,GL_EXEPath+'data\druck\user\Briefbogen.png',-100,800,1150,-220);
  end;
  end;
</source>


===Beispiel 2: Einrichtung eines neuen Methoden-Zeigers===
===Beispiel 2: Einrichtung eines neuen Methoden-Zeigers===

Version vom 13. September 2023, 14:59 Uhr


Drucke sind eine spezielle Form der Makros im OBS, da sie zusätzlich über Funktionalitäten für den Export in bestimmte Dateiformate (z. B. PDF) oder Ausdruck verfügen. Sie sind an der Endung .pax zu erkennen und befinden sich in der Verzeichnisstruktur vom OBS unter ..\data\druck und ..\data\druck\user. Der Unterschied zwischen den beiden Verzeichnissen ist klein, aber mit großer Wirkung. Alle Druck-Dateien, die standardmäßig im OBS enthalten sind, befinden sich im Verzeichnis ..\data\druck und werden dort auch bei jedem Update ersetzt. Wer vom Standard abweichen möchte, muss die "pax"-Datei im Verzeichnis ..\data\druck\user hinterlegen.

Besonderheiten

Vorgangsdrucke mit Methoden-Zeigern (Method Pointer)

Falscher (alter) Weg: Den Druck in den user-Ordner kopieren und in der Datei die entsprechenden Änderungen einbauen. Warum: Wenn Änderungen an den Standarddrucken durchgeführt werden (z.B. neue gesetzliche Vorgaben) wird der user-Druck nicht mit angepasst.

Richtiger Weg (ab Version 004097, 14.09.2022):

user-Druck anlegen in folgendem Stil (Beispiel rechnung.pax):

// Verlinkung des Standard-Drucks
{$I .\data\druck\rechnung.pax}

// Kopie der StartProc die dann die Standard-StartProc aufruft
function StartProcCustom(cRechNr: String; nParCnt: Integer; lPrintModusi: Boolean; obj: TObject): Boolean;
begin
    result := StartProc(cRechNr, nParCnt, lPrintModusi, obj);
end;

Damit wird erstmal der Standard-Rechnungsdruck 1:1 ausgeführt. Jetzt kann ich über Custom-Methoden den Druck verändern.

Beispiel 1: Nutzung eines vorhandenen Methoden-Zeigers

Anforderung: Leerzeilen sollen immer zwei statt einer Zeile hoch sein.

Dafür existiert bereits ein Methoden-Zeiger den ich nutzen kann:

{$I .\data\druck\rechnung.pax}

// neue Custom-Methode
procedure LeerzeilePosCustom();
begin
    y := y + 2;
end;

function StartProcCustom(cRechNr: String; nParCnt: Integer; lPrintModusi: Boolean; obj: TObject): Boolean;
begin
    // Grund-Initialisierung der Zeiger, MUSS als erstes ausgeführt werden weil die Zeiger sonst während des Drucks neu gesetzt werden
    InitMethodPointers(true);

    // Zuweisung meiner Custom-Methode auf dem Methoden-Zeiger für den Leerzeilendruck
    oMethodPointer.pLeerzeile := LeerzeilePosCustom;

    result := StartProc(cRechNr, nParCnt, lPrintModusi, obj);
end;

Beispiel eines angepassten Angebot-Drucks mit diversen Anpassungen:

 //------------------------------------------------------------------------------
 // Unit Name: Angebot
 // History:   2023-09-13 - Umstellung auf Method Pointer
 //------------------------------------------------------------------------------
 
 {$I .\data\druck\angebot.pax}
 {$I .\data\druck\user\user.inx }
 
 //------------------------------------------------------------------------------
 //  Procedure: CustomRabattSpalten
 //  Author:    Schinke
 //  Date:      2023-09-13
 //  Comment:   Zusätzliche Spalte für RabattEinzellpreis
 //------------------------------------------------------------------------------
 procedure CustomRabattSpalten();
 begin
     if (A_Query.A2C('a_rabposjn') = 'J') then begin
         qRep_SAddGruppe(EZ, 'aBody', 'Rabatt'      , 6 , tajRightJustify, 'N');
         qRep_SAddGruppe(EZ, 'aBody', 'RabattEPreis', 10, tajRightJustify, 'N');
     end;    
 end;
 
 //------------------------------------------------------------------------------
 //  Procedure: PosHeaderZusatz
 //  Author:    Schinke
 //  Date:      2023-09-13
 //  Comment:   Überschrift für Rabatt Einzelpreis Spalte
 //------------------------------------------------------------------------------
 procedure PosHeaderZusatz();
 begin
     qRep_SText(EZ, 'RabattEPreis' , 'Rab E-Preis', qRep_YPos(EZ, y));
 end; 
 
 //------------------------------------------------------------------------------
 //  Procedure: CustomPosRabatt
 //  Author:    Schinke
 //  Date:      2023-09-13
 //  Comment:   Wert für Rabatt Einzelpreis
 //------------------------------------------------------------------------------
 procedure CustomPosRabatt();
 begin
     if (Alltrim(TStr(Roundy(AZ_Query.A2F('az_rabatt'), 2), 12, 2)) <> '0,00') then begin
         if (AZ_Query.A2C('az_posart') < '6') then begin
             qRep_SText(EZ, 'rabatt'      , TStr(Roundy(AZ_Query.A2F('az_rabatt'), 2), 12, 2)                              , qRep_YPos(EZ, y));
             qRep_SText(EZ, 'rabattEPreis', TStr(Roundy(AZ_Query.A2F('az_epreis')/100*AZ_Query.A2F('az_rabatt'), 2), 12, 2), qRep_YPos(EZ,y));
         end;
     end; 
 end; 
 
 //------------------------------------------------------------------------------
 //  Procedure: CustomAngebotKopfZusatzinfo
 //  Author:    Schinke
 //  Date:      2023-09-13
 //  Comment:   Ansprechpartner/Projekt im Kopf
 //------------------------------------------------------------------------------
 procedure CustomAngebotKopfZusatzinfo();
 begin    
     UserAnsprechpartner(1);
 end; 
 
 //------------------------------------------------------------------------------
 //  Procedure: CustomKopfFolgeSeite
 //  Author:    Schinke
 //  Date:      2023-09-13
 //  Comment:   Angepasster Folgeseiten Kopf ohne Adresse
 //------------------------------------------------------------------------------
 procedure CustomKopfFolgeSeite();
 begin
 
     y := 1;
 
     if (not empty(cLogo2)) then begin
         BriefbogenStd(cLogo2);
     end;
 
     //AdressKopf(KopffreieZeilen);
 
     y := KopffreieZeilen - 10;
     
     qRep_SText(EZ,'1', cKopf1,qRep_YPos(EZ, y+2));
 
     qRep_SText(EZ,'2', cKopf8+A_Query.A2C('a_nr'),qRep_YPos(EZ, y+2));
     qRep_SText(EZ,'3', cKopf9, qRep_YPos(EZ, y));
     qRep_SText(EZ,'3', cKopf5, qRep_YPos(EZ, y+1));
     qRep_SText(EZ,'3', cAllg8, qRep_YPos(EZ, y+2));
 
     qRep_SText(EZ,'4', ': '+A_Query.A2C('a_datum') , qRep_YPos(EZ, y));
     qRep_SText(EZ,'4', ': '+A_Query.A2C('a_knr')   , qRep_YPos(EZ, y+1));
     qRep_SText(EZ,'4', ': '+IntToStr(nEZ_CurPage)  , qRep_YPos(EZ, y+2));
 
     y := y + 3.5;
 
 end;
 
 //------------------------------------------------------------------------------
 //  Procedure: StartProcCustom
 //  Author:    Schinke
 //  Date:      2023-09-13
 //------------------------------------------------------------------------------
 function StartProcCustom(cVar, cAngNr: String; nParCnt: Integer; lPrintModusi: Boolean; obj: TObject): Boolean;
 begin
     // Grund-Initialisierung der Zeiger, MUSS als erstes ausgeführt werden weil die Zeiger sonst während des Drucks neu gesetzt werden
     InitMethodPointers(true);
     InitPosGlobalPointers();
      
     oMethodPointer.pRabattSpalten            := CustomRabattSpalten;               //Steuert die Spalten, wenn ein PosRbatt vorhanden ist. Standard: Eine Spalte
     oMethodPointer.pPosHeaderZusatz          := PosHeaderZusatz;                   //Wird nach den Überschriften der PosSpalten ausgeführt    
     oMethodPointer.pPosRabatt                := CustomPosRabatt;                   //Ausgabe des Rabatts in der Posline
 
     oPrinterPrintPage.pBeforePrint           := BriefbogenMehrseitig;              //Ausgelagerte Funktion in User.inx um den Briefbogen zu drucken. 
     oPrinterPrintPage.pAngebotKopfZusatzinfo := CustomAngebotKopfZusatzinfo;
 
     result := StartProc(cVar, cAngNr, nParCnt, lPrintModusi, obj);    
 end;

Dazugehörige User.inx:

 
 //------------------------------------------------------------------
 //Ausgabe Ansprechpartner/Projekt im Kopf
 //------------------------------------------------------------------
 procedure UserAnsprechpartner(yKorrektur:Double);
 var cBuffer : String;
 begin 
     //Sachbearbeiter Kunde (Ansprechpartner)
     cBuffer := DB_ReadSQLValue(oDB,'perssta','ps_verkauf','ps_nr=' + DB_SQLVal(A_Query.A2C('a_knr'),'C'));
     if not(empty(cBuffer)) then begin
         //Sachbearbeiter Kunde Name
         cBuffer := 'Ansprechpartner: ' + DB_ReadSQLValue(oDB,'S_VERK', 'v_name', 'v_nr=' + DB_SQLVal(cBuffer, 'C'));
     end; 
 
     //Projekt
     if not(empty(A_Query.A2C('a_projnr'))) then begin
         if not(empty(cBuffer)) then begin
             cBuffer := cBuffer + ' / ';
         end;
 
         cBuffer := cBuffer + 'Projekt: '+ A_Query.A2C('a_projnr');
     end; 
     qRep_Text3(EZ, iLinkerRand, qRep_YPos(EZ, y-yKorrektur), cBuffer);
     y := y + 1;
 end; 
 
 //------------------------------------------------------------------
 //Briefbogen ab Seite 2 ohne Kopf
 //Es muss im User, der dies verwendet eine CustomKopfFolgeSeite()
 //Procedure vorhanden sein. 
 //------------------------------------------------------------------
 procedure BriefbogenMehrseitig();
 begin
     oPrinterPrintPage.pKopfFolgeSeite := CustomKopfFolgeSeite;    
 
     if nEZ_CurPage = 1 then begin
         qRep_PictPrint(EZ,GL_EXEPath+'data\druck\user\Briefbogen.png',-100,800,1150,-220);
     end else begin
         qRep_PictPrint(EZ,GL_EXEPath+'data\druck\user\briefbogen_FolgeSeite.png',-100,800,1150,-220);
     end; 
 end;
 
 //------------------------------------------------------------------
 //Briefbogen Folgeseiten
 //------------------------------------------------------------------
 procedure Briefbogen();
 begin
     qRep_PictPrint(EZ,GL_EXEPath+'data\druck\user\Briefbogen.png',-100,800,1150,-220);
 end;

Beispiel 2: Einrichtung eines neuen Methoden-Zeigers

HINWEIS: Neue Methoden-Zeiger können nur duch den OBS-Support angelegt werden! Bitte wenden Sie sich im Bedarfsfall an den Support.

Anforderung: Positionsmenge sollen im Druck nicht mit ausgegeben werden. Das ist kein sinnvolles Szenario und dient lediglich als Beispiel.

Dafür gibt es noch keinen Methoden-Zeiger, wir brauchen einen Neuen. Wie gehe ich vor:


1. Die Stelle im Code identifizieren die geändert werden soll

In unserem Beispiel die Prozedur PosLineMengeEinheit() in PosReportFunktionen.inx

    [...]
    if ((not lEmpty) and (not lLiefNach) and (not lMultiSteuerPos)) then begin
        qRep_SText(EZ,'menge'  ,TStr(AZ_Query.A2F('az_menge'),12,StrToIntDef(PMode_Var(457),2)),qRep_YPos(EZ,y));
        qRep_SText(EZ,'einheit',GetEinheit_Lan(oDB,cLanguage,AZ_Query.A2C('az_einheit'),'se_name'),qRep_YPos(EZ,y));
    end else if (lLiefNach and lDruckNachgeliefert) then begin
        WirdNachgeliefert();
    end;
    [...]

2. Für die Ausgabe der Menge lege ich nun einen neuen Methoden-Zeiger an

Datei: PosReportPositionen.inx

    TPosMethodPointer = record
    public
        pPosHeader            : TPosMethod;
        [...]
        pPosLineMenge         : TPosMethod;  // <-- neuer Zeiger
    end;

3. Statt der Ausführung des Codes setzte ich nun den Methoden-Zeiger ein

Datei: Ort der Druckänderung (im Beispiel PosReportFunktionen.inx)

    [...]
    if ((not lEmpty) and (not lLiefNach) and (not lMultiSteuerPos)) then begin
        oMethodPointer.pPosLineMenge();   // <-- Methoden-Aufruf
        qRep_SText(EZ,'einheit',GetEinheit_Lan(oDB,cLanguage,AZ_Query.A2C('az_einheit'),'se_name'),qRep_YPos(EZ,y));
    end else if (lLiefNach and lDruckNachgeliefert) then begin
        WirdNachgeliefert();
    end;
    [...]

4. Für den Standard baue ich eine neue Prozedur

Datei: Ort der Druckänderung (im Beispiel PosReportFunktionen.inx)

procedure PosLineMengeDefault();
begin
    qRep_SText(EZ,'menge'  ,TStr(AZ_Query.A2F('az_menge'),12,StrToIntDef(PMode_Var(457),2)),qRep_YPos(EZ,y));
end;

5. Ich ergänze die Initialisierung der Methoden-Zeiger

Datei: PosReportPositionen.inx

procedure InitMethodPointers(lPrintPreise : Boolean = true);
begin
    oMethodPointer.pPosHeader           := PosHeader;               
    [...]
    oMethodPointer.pPosLineMenge        := PosLineMengeDefault;   // <-- das hier ist die neue Zeile

    InitPosParams(lPrintPreise);
end;

6. Jetzt kann ich in meinem user-Druck den Zeiger benutzen

Datei User-Druck (im Beispiel user\rechnung.pax)

procedure PosLineMengeCustom();
begin
    // keine Menge ausgeben
end;

function StartProcCustom(cRechNr: String; nParCnt: Integer; lPrintModusi: Boolean; obj: TObject): Boolean;
begin
    // Grund-Initialisierung der Zeiger, MUSS als erstes ausgeführt werden weil die Zeiger sonst während des Drucks neu gesetzt werden
    InitMethodPointers(true);

    // Setzten der neue Methode
    oMethodPointer.pPosLineMenge := PosLineMengeCustom;

    result := StartProc(cRechNr, nParCnt, lPrintModusi, obj);
end;

Übersteuern von Textbausteinen

Mit der Variable cDBNamePDF im Druck können Textbausteine übersteuert werden.


aktuell verwendet in:

RUECKSENDEAUFTRAG.PAX

ABHOLSCHEIN.PAX

Benutzt in  i_Uti.pas function PDFMail_Ext

    cDBName    := 'AUFTRAG';
    cDBNamePDF := 'ABHOLSCHEIN';

Script_Lib Funktion

Neue Script_Lib Funktion

Name :        PDFMail

Methode :     PDFParameter

Parameter:

Hier kann alles übersteuert werden (Mailtexte usw)

Alle Änderungen gehen auch zurück

oParameter ist vom Typ TOBSParameter (Script)

oParameter.V13 ist der Mail Text

           Script_Lib_RunNamePara(oDB,

                                 'PDFMail_Ext',

                                 'PDFParameter',

                                 [

                                      TObject(oParameter),

                                      cDB,

                                      cDB_PDF,

                                      cPsNr

                                 ]);

           oParameter.Obj := oDB;

           oParameter.V1  := cVonEmailAdr;

           oParameter.V2  := cEmailAdr;

           oParameter.V3  := lSofortSenden;

           oParameter.V4  := cPDFFile;

           oParameter.V5  := lAnzeige;

           oParameter.V6  := cFileExt;

           oParameter.V7  := cAddAttach;

           oParameter.V8  := cCC;

           oParameter.V9  := cBCC;

           oParameter.V10 := lLeseBestaetigung;

           oParameter.V11 := cMyBetreff;

           oParameter.V12 := cMyMailText;

           oParameter.V13 := cBuffer;

           oParameter.V14 := cTB;