From: wulf@coulmann.de Date: Thu, 13 Jan 2011 17:39:08 +0000 (+0100) Subject: fancy LaTeX initial X-Git-Tag: release-2.7.0beta1~125^2 X-Git-Url: http://wagnertech.de/git?a=commitdiff_plain;h=f0e9585f5e47401746e78b8b939078d80a848120;p=kivitendo-erp.git fancy LaTeX initial siehe doc/2011-12-14_alternatives_vorlagensystem_f-tex.txt --- diff --git a/doc/2011-12-14_alternatives_vorlagensystem_f-tex.txt b/doc/2011-12-14_alternatives_vorlagensystem_f-tex.txt new file mode 100644 index 000000000..d4c5b4f3d --- /dev/null +++ b/doc/2011-12-14_alternatives_vorlagensystem_f-tex.txt @@ -0,0 +1,245 @@ +README lx-office Fancy-LaTeX (f-tex) + +# Revision 1.0-u (16.11.2011) +# Revision 0.9 (13.11.2011) +# Revision 0.8 (12.09.2011) +# Revision 0.7 (12.07.2011) +# Revision 0.6 (16.06.2011) +# Revision 0.5 (15.04.2011) +# Revision 0.4 (14.02.2011) +# Revision 0.3 (03.01.2011) +# Revision 0.2 (24.12.2010) +# Revision 0.1 (03.11.2009) + + +# Einleitung + + Es gibt ein alternatives LaTeX Vorlagensystem im Verzeichnis + templates/f-tex + Fuer das Einrichten der Vorlagen gibt es ein Setup-Script + + +# Voraussetzung: + + - funktionierende Lx-Office Intallation + - mindestens eine Mandantendatenbank + weiter ist es hilfreich: + - mindestens einen Benutzer mit Verweis auf ein Vorlagenverzeichs + - Bereits angelegte Sprachkuerzel, wenn mehrsprachige Dokumente erstellt + werden sollen. + +# Feature Uebersicht + + - einfach Nutzung durch mitgeliefertes Setup-Script + - Keine Retundanz. Es wird ein und die selbe Latex-Vorlage fuer alle + briefartigen Dokumente verwendet. Also Angebot, Rechnung, + Performarechnung, Lieferschein, aber eben nicht fuer Paketaufkleber + etc.. + - Leichte Anpassung an das Firmen Layout durch verwendung eines Hintergrund-PDF + dieses kann leicht mit dem eigenen Lieblingsprogramm erstellt werden + (Openoffice, Inkscape, Gimp, Adobe*) + - Hintergrundpdf um schaltbar auf "nur erste Seite" (default) oder "alle Seiten" + (option "bgPdfFirstPageOnly" in Datei letter.lco) + - Hintergrundpdf fuer Ausdruck auf bereits bedrucktem Briefpapier Abschaltbar, + es wird dann nur bei per email versendeten Dokumenten eingebunden. + (Option "bgPdfEmailOnly" in Datei letter.lco) + - Nutzung der Layout-Funktionen von Latex fuer Seitenumbruch, + wiederholung von Kopfzeilen, Zwischensummen etc. (danke an Kai-Martin fuer + die Vorarbeit) + - Anzeige des Empfaengerlandes im Adressfeld nur, wenn es vom Land des + eigenen Unternehmens abweicht (also die Rechnung das Land verlaesst). + - Multisprachfaehig leicht um weitere Sprachen zu erweitern, alle + Übersetzungen in der Datei translatinos.tex. + - Auflistung von Bruttopreisen fuer Endverbraucher. + + + + +# die Installation + + Wenn es noch keine LaTeX installation gibt, installiere die folgenden Pakete + (Debian) + aptitude install \ + texlive-base-bin \ + texlive-latex-recommended \ + texlive-fonts-recommended \ + texlive-latex-extra \ + texlive-lang-german \ + texlive-generic-extra + (Info fuer != Debian Installationen: die Abhaengigkeiten werden waehrend des + Setups nochmals geprueft) + + Rufe das folgende Script auf: + [lxo-home]/templates/f-tex/setup.sh + und folge den Anweisungen. + + Erstelle eine pdf-Hintergrund Datei und verlinke sie nach ./letter_head.pdf + + Editiere den Bereich "settings" in der datei letter.lco "" + + # oder etwas Detaillierter: + Es wird eine Datei sample.lco erstellt und diese nach letter.lco verlinkt. + Eigentlich ist dies die Datei die fuer die Firmenspezifischen Anpassungen + gedacht ist. Da die Einstiegshuerde in LaTeX nicht ganz niedrig ist, wird in + dieser Datei auf ein Hintergrundpdf verwiesen. Ich empfehle ueber dieses pdf + die persoenlichen Layoutanpassungen vorzunehmen und sample.lco unveraendert zu + lassen. Die die Anpassung ueber eine *.lco Datei die letztlich auf letter.lco + verlinkt ist ist aber auch moeglich. + + Es wird eine Datei sample_head.pdf mit ausgeliefert, diese wird nach + letter_head.pdf verlinkt. Damit gibt es schon mal eine Funktionsfaehige + Vorlage. Schau Dir nach Abschluss der Installation die Datei sample_haed.pdf + an und erstelle ein entsprechendes pdf passend zum Briefkopf Deiner Firma, + diese dann im Template Verzeichniss ablegen und statt sample_head.pdf nach + letter_head.pdf verlinken. + + per default erstellt das Setupscript einen symbolischen Link + ./sample_head.pdf -> ./letter_head.pdf + letzlich muss ./letter_head.pdf auf das passende Hintergrundpdf verweisen, + welches gewuenschten Briefkopf enthaelt. Bei Updates oder nach erneutem + Aufruf des setup Scripts werden bestehende Links nicht ohne Rueckfrage + ersetzt, wer also schon seinen Briefkopf verlinkt hat, braucht diesen Link + nicht immer wieder neu anlegen. Das gleiche Prinzip gilt fuer letter.lco. + + Es wird eine Datei mydata.tex erstellt, sie ist mit der aus + lp (Label Print in erp) kompatibel. Diese braucht man also nur einmal + fuer jedes template Verzeichnis zu generieren. + Bei Formatierungsschwierigkeiten bitte mit + [lxo-home]/templates/f-tex/mydata.tex.example vergleichen. + + Alle Anpassungen zum Briefkopf, Fusszeilen, Firmenlogos, etc. + sollten ueber die Hintergrund pdf datei oder die *.lco Datei erfolgen. + + +# einheitliche Latex-Vorlagen -- Background + + Das Konzept von lx-office sieht vor, fuer jedes Dokument + (Auftragsbestaetigung, Lieferschein, Rechnung, etc.) eine + Latex-Vorlage vorzuhalten, dies ist sehr Wartungsunfreundlich. Auch + das Einlesen einer einheitlichen Quelle fuer den Briefkopf bringt nur + bedingte Vorteile, da hier leicht die Pflege der Artikel-Tabellen aus + dem Ruder laeuft. Bei dem vorliegenden Ansatz wird fuer alle + Briefartigen Dokumente mit Artikel-Tabellen eine einheitliche + Latexvorlage verwendet, welche ueber Codeweichen die Besonderheiten + der jeweiligen Dokumente Beruecksichtigt + - Tabellen mit oder ohne Preis + - Sprache der Tabellenueberschriften etc. + - Anpassung der Bezugs-Zeile (z.B. Rechnungsnummer versus + Angebotsnummer) + - Darstellung von Brutto oder Netto-Preisen in der Auflistung + (Endverbraucher versus Gewerblicher Kunde) + Dies laesst sich in lx-office nur ueber einen Kunstgriff realisieren, + da zum einen die perl-Anwendung nach latex-Vorlagen mit bestimmten + Namen sucht (z.B. sales_order_de.tex fuer die deutschsprachige + Auftragsbestaetigung -- wenn deutsch mit dem Vorlagenkuerzel de + angelegt wurde) und zum Anderen die Information um welches Dokument es + sich handelt nicht direkt innerhalb von Latex zur Verfuegung steht. + + Umgesetzt wurde dies hier nun ueber symbolische Links im Dateisystem. Es + gibt also eine Vorlage letter.tex (die ihrerseits weitere tex-Dateien + einbindet) und fuer jeden Dokumenttyp der durch letter.tex abgedeckt on von + jedem dieser wiederum in jeder verfuegbaren Sprache legt das setup Script einen + link in der lx-office Namenskonvention an, der auf die Datei letter.tex + verweist. Die Datei letter.tex wertet den Namen der Aufgerufenen Datei aus und + passt ihre Ausgabe dementsprechend an. Wenn zum Beispiel lx-office die Datei + packing_list_de.tex aufruft (die ja nur ein Link nach letter.tex ist) liegt die + Information des aktuellen Dokumentnamen (packing_list_de.tex) vor und latex + weiss, keine Preise, Lieferscheinnummer anzeigen, deutsche sprachumgebung, usw. + + Es liegt mit der Datei setup.sh ein script vor, welches die Abhaengigkeiten + im System prueft und die benotigten Dateien und symbolischen Links erstellt. + Das script ist so aufgebaut, dass es bei Updates auch auf bestehende f-tex + Vorlagenordner angewendet werden kann, ohne vorhandene Personalisierungen zu + ueberschreiben. Die Benoetigten Informationen wie Template-Verzeichniss, + vorhandene Sprachkuerzel, etc werden waerend des setupprozesses abgefragt. Der + Setupprozess kann also sooft wie benoetigt wiederholt werden, auch wenn bereits + ein templateverzeichniss existiert. + + + Nachteil: + Ja, alles hat seinen Preis ... + Latex hat ohnehin eine sehr steile Lehrnkurve. Die Datei letter.tex + ist sehr komplex und verstaerkt damit diesen Effekt noch einmal erheblich. + Wer Latex-Erfahrung hat, oder geuebt ist Scriptsparachen nachzuvollziehen kann + natuerlich auch innerhalb der Tabellendarstellung gut persoenliche Anpassungen + vornehmen. Aber man kann sich hier bei Veraenderungen sehr schnell haeftig in + den Fuss schiessen. + Wer nicht so tief in die Materie einsteigen will oder leicht zu + frustrieren ist, sollte sein Hintergrund PDF auf Basis der mitglieferten + Datei sample_head.pdf erstellen, und sich an der Form der dargestellten Tabellen + wie sie ausgeliefert werden, erfreuen. + Kleiner Tipp: + + Nicht zu viel auf einmal wollen, lieber kleine kontinuierliche + Schritte gehen. + + Alternativ kann man sich natuerlich fuer die Latex-Vorlagen + professionelle Hilfe hohlen. + + +Bruttopreise fuer Endvorbraucher + Der auszuweisende Bruttopreis wird innerhalb der LaTeX Umgebung berechnet. + + - Background: + es gibt zwar ein Feld um bei Auftraegen "alle Preise Brutto" auszuwaehlen, + aber: + - hierfuer muessen die Preise auch in Brutto in der Datenbank stehen + (ja -- das laesst sich ueber die Preisgruppen und die Zuordung einer Default-Preisgruppe + handhaben) + - man darf beim Anlegen des Vorgangs nicht vergessen Dieses Haekchen zu setzen. + (das ist in der Praxis wenn man sowohl Endverbraucher- wie Gewerbekunden beliefert + der eigentliche Knackpunkt) + + Es gibt mit f-tex eine weitere Alternative. Die Information ob Brutto oder + Nettorechnung wird mit den Zahlarten verknuepft. Zahlarten bei denen + Rechnungen, Angebote, etc, in Brutto ausgegeben werden sollen enden mit "_E" + (fuer Endverbraucher) Falls identische Zahlarten fuer Gewerbekunden und + Endverbraucher vorhanden sind legt man diese einfach doppelt an (einmal mit + der Namensendung "_E") + - Gewinn: + - die Entscheidung ob Netopreise ausgewiesen werden ist nicht mehr fix + mit einer Preisliste Verbunden. + - die Default-Zahlart kann im Kundendatensatz hinterlegt werden und man + muss nicht mehr daran denken "alle Preise Netto" auszuwaehlen. + - Die Entscheidung ob Netto/Oder Bruttopreise ausgewiesen werden kann direkt + beim Drucken reviediert werden, ohne dass sich der Auftragswert aendert. + +Lieferadressen + + - in Lieferscheinen kommen shipto* -Variablen im Adressfeld zum Einsatz + - wenn die shipto*variable leer ist wird die entsprechende + Adressvariable eingesetzt. Wenn Also die Lieferadresse in Strasse, + Hausnummer und Ort abweicht, muessen auch nur diese Felder in der + Lieferadresse ausgefuellt werden. Fuer den Firmenname wird der Wert der + Hauptadresse angezeigt. + +Troubleshooting -- Fehler suchen: + Wenn sich das Problem nicht auf Grund der ausgabe im Webbrowser verifizieren laesst: + + editiere [flxo-home]/config/lx_office.conf und aendere "keep_tmp_files" auf 1 + keep_temp_files = 1; + + bei fastcgi oder mod_perl den Webserver neu Starten + + Nochmal einen Druckversuch im Webfrontend ausloesen + + wechsele in das users Verzeichnis von lxo + cd [lxo-home]/users + + LaTeX Suchpfad anpassen: + export TEXINPUTS=".:[lxo-home]/templates/[aktuelles_template_verzeichniss]:" + + Finde herraus welche datei lxo beim letzten Durchlauf erstellt hat + ls -lahtr ./1*.tex + Es sollte die letzte Datei ganz unten sein + + fuer besseren Hinweis auf Fehler texdatei nochmals uebersetzen + pdflatex ./1*.tex + + in der *.tex datei nach dem Fehler suchen. + +Changelogeintrag fuer offiziellen tree: + Kleine Verbesserungen: + Zusaetzliches alternatives LaTeX Templatesystem + + diff --git a/doc/changelog b/doc/changelog index 7fb438619..918667df7 100644 --- a/doc/changelog +++ b/doc/changelog @@ -2,6 +2,13 @@ # Veränderungen von Lx-Office ERP # ################################### +- Alternatives Vorlagenstemsystem f-tex + * Setup Script + * mehrsprachig + * leichte Integration des Firmenbriefkopfs + * Ausgabe von Bruttopreisen in den Positionen fuer Endverbraucher moeglich + siehe doc/2011-12-14_alternatives_vorlagensystem_f-tex.txt + - Ein neuer Vorlagensatz RB kam hinzu, der einige Ideen aufgreift, die in folgendem Vortrag erwähnt wurden: http://www.lx-office.org/uploads/media/Lx-Office_Anwendertreffen_LaTeX-Druckvorlagen-31.01.2011_01.pdf diff --git a/templates/f-tex/letter.tex b/templates/f-tex/letter.tex new file mode 100644 index 000000000..726f5fddf --- /dev/null +++ b/templates/f-tex/letter.tex @@ -0,0 +1,563 @@ +% ---------------------------------------------------------- +% letter.tex +% Globale Vorlage fuer Briefartige Documente LX-Office 2.6 +% +% Changelog: see gitlog + \newcommand{\ftLetterVersion}{1.0-u (16.11.2011)} +% +% Lizenz +% http://www.gnu.de/licenses/gpl-3.0.html +% +% Siehe ./README +% +% Autor: Wulf Coulmann scripts_at_gpl.coulmann.de +% Aufgebaut auf invoice.tex 0.1 kmk@lilalaser.de +% +% ---------------------------------------------------------- + +\documentclass[letter,fontsize=11pt]{scrlttr2} + + +\begingroup + \makeatletter + \@latex@warning@no@line{ #### this is letter.tex \ftLetterVersion #####} +\endgroup + + +\usepackage{ifpdf} +\usepackage{graphicx} +\usepackage{german} +\usepackage{textcomp} +\usepackage{lastpage} +\usepackage{filecontents} +\usepackage{etex} +\usepackage{ltxtable} +\usepackage{tabularx} +\usepackage{longtable} +\usepackage{booktabs} +\usepackage{numprint} +\usepackage{xstring} +\newcommand{\leer}{} +\usepackage{zwischensumme} +\ifthenelse{\isundefined{\employeecountry}}{\input{mydata}}{} + + + +% Dateinamen einlesen und auswertbar machen +\scantokens\expandafter{% + \expandafter\def\expandafter\docname\expandafter{\jobname}} + +%%%%%%%%% Report-Variablen umsetzen, damit latex sie in lxbriefkopf.tex sieht. +%%%% Die eigenen Daten +\newcommand{\employeename}{<%employee_name%>} +\newcommand{\employeecompany}{<%employee_company%>} +\newcommand{\employeeaddress}{<%employee_address%>} +\newcommand{\employeetel}{<%employee_tel%>} +\newcommand{\employeefax}{<%employee_fax%>} +\newcommand{\employeecoustid}{<%employee_co_ustid%>} +\newcommand{\employeetaxnumber}{<%employee_taxnumber%>} +\newcommand{\media}{<%media%>} + + +%%%% Adressat +\newcommand{\name}{<%name%>} +\newcommand{\Shipname}{\ifthenelse{\equal{<%shiptoname%>}{\leer}}{<%name%>}{<%shiptoname%>}} +\newcommand{\departmentone}{<%department_1%>} +\newcommand{\departmenttwo}{<%department_2%>} +\newcommand{\cpgreeting}{<%cp_greeting%>} +\newcommand{\cptitle}{<%cp_title%>} +\newcommand{\cpgivenname}{<%cp_givenname%>} +\newcommand{\cpname}{<%cp_name%>} +\newcommand{\street}{<%street%>} +\newcommand{\Shipstreet}{\ifthenelse{\equal{<%shiptostreet%>}{\leer}}{<%street%>}{<%shiptostreet%>}} +\newcommand{\country}{<%country%>} +\newcommand{\Shipcountry}{\ifthenelse{\equal{<%shiptocountry%>}{\leer}}{<%country%>}{<%shiptocountry%>}} +\newcommand{\UstId}{<%ustid%>} +\newcommand{\zipcode}{<%zipcode%>} +\newcommand{\Shipzipcode}{\ifthenelse{\equal{<%shiptozipcode%>}{\leer}}{<%zipcode%>}{<%shiptozipcode%>}} +\newcommand{\city}{<%city%>} +\newcommand{\Shipcity}{\ifthenelse{\equal{<%shiptocity%>}{\leer}}{<%city%>}{<%shiptocity%>}} +\newcommand{\phone}{<%customerphone%>} +\newcommand{\fax}{<%customerfax%>} + +%%%% Variablen, die sich auf das ganze Dokument beziehen +\newcommand{\kundennummer}{<%customernumber%>} +\newcommand{\vendornumber}{<%vendornumber%>} +\newcommand{\quonumber}{<%quonumber%>} % Angebotsnummer +\newcommand{\ordnumber}{<%ordnumber%>} % Auftragsnummer bei uns +\newcommand{\cusordnumber}{<%cusordnumber%>} % Auftragsnummer beim Kunden +\newcommand{\invnumber}{<%invnumber%>} % Rechnungsnummer +\newcommand{\donumber}{<%donumber%>} % Lieferscheinnummer +%\newcommand{\docnumber}{Rechnungsnummer: \invnumber} +\newcommand{\quodate}{<%quodate%>} % Angebotsdatum +\newcommand{\orddate}{<%orddate%>} % Auftragsdatum +\newcommand{\reqdate}{<%reqdate%>} % gewuenschtes Lieferdatum +\newcommand{\deliverydate}{<%deliverydate%>} % Lieferdatum +\newcommand{\invdate}{<%invdate%>} % Rechnungsdatum +\newcommand{\transdate}{<%transdate%>} % Lieferscheindatum +\newcommand{\terms}{<%terms%>} % Zahlungsfrist +\newcommand{\duedate}{<%duedate%>} % Fälligkeitsdatum +\newcommand{\invtotal}{<%invtotal%>} % Gesamtbetrag +\newcommand{\paid}{<%paid%>} % Schon bezahlt +\newcommand{\total}{<%total%>} % Restbetrag +\newcommand{\subtotal}{<%subtotal NOFORMAT%>} % Restbetrag +\newcommand{\paymentterms}{<%payment_terms%>} % Zahlungsbedingungen +\newcommand{\paymentPrivatEnd}{E} % Endung bei Privatkunden +\newcommand{\paymenttype}{<%payment_description%>} % name der Zahlungs-art - fuer Steuerung brutto/netto + + +%%%% Lieferadresse +\newcommand{\shiptoname}{<%shiptoname%>} +\newcommand{\shiptocontact}{<%shiptocontact%>} +\newcommand{\shiptodepartmentone}{<%shiptodepartment_1%>} +\newcommand{\shiptodepartmenttwo}{<%shiptodepartment_2%>} +\newcommand{\shiptostreet}{<%shiptostreet%>} +\newcommand{\shiptocity}{<%shiptocity%>} +\newcommand{\shiptocountry}{<%shiptocountry%>} +\newcommand{\shiptophone}{<%shiptophone%>} +\newcommand{\shiptozipcode}{<%shiptozipcode%>} +\newcommand{\shiptofax}{<%shiptofax%>} + +%%%% Die Waehrungsvariable in Waehrunszeichen umsetzen +\newcommand{\currency}{<%currency%>} +\ifthenelse{\equal{\currency}{EUR}}{\let\currency\euro}{} +\ifthenelse{\equal{\currency}{YEN}}{\let\currency\textyen}{} +\ifthenelse{\equal{\currency}{GBP}}{\let\currency\pounds}{} +\ifthenelse{\equal{\currency}{USD}}{\let\currency\$}{} + +%%%%%%%%%%%%% Ende Reportvariablen-Umsetzung + +\newcommand{\NoValue}{0} +\newcommand{\Picklist}{0} +\newcommand{\PurchaseOrder}{0} +\newcommand{\trash}{0} +\newcommand{\nonemptyline}[2]{\ifthenelse{\equal{#2}{\leer}}{}{#1#2~\\}} +\newcommand{\MyAdress}{\IfSubStr{\docname}{sales_delivery_order}{\Shipname~\\ + % lieferadresse wenn Lieferschein + \nonemptyline{\cpgreeting{ }\cpgivenname{ }}{\cpname} + \nonemptyline{}{\departmentone} + \Shipstreet ~\\ + \Shipzipcode{ }\Shipcity + \ifthenelse{\equal{\Shipcountry}{\employeecountry}}{}{ + \ifthenelse{\equal{\Shipcountry}{\leer}}{}{ ~\\ \Shipcountry} } % Laenderangabe wird nur gedruckt, + ~ % wenn der Empfaenger nicht im eigenen Land sitzt. + }{ + \name~\\ + \nonemptyline{\cpgreeting{ }\cpgivenname{ }}{\cpname} + \nonemptyline{}{\departmentone} + \street ~\\ + \zipcode{ }\city + \ifthenelse{\equal{\country} {\employeecountry}}{}{ + \ifthenelse{\equal{\country}{\leer}}{}{ ~\\ \country} } % Laenderangabe wird nur gedruckt, + ~ % wenn der Empfaenger nicht im eigenen Land sitzt. + } +} + + + +\begin{document} + +%%% dei folgenden Funktionen lesen den Dokumentennamen aus und _muessen_nach_ \begin{dokument} stehen. + +% ==== statische Begriffe in der aktuellen Sprache einlesen +\input{translations} + + +\ifthenelse{\bgPdfEmailOnly = 1 }{ + \ifthenelse{\equal{\media}{email}}{ + }{ + \firsthead{} + \watermark{} + } +}{} + + +% ==== dokumenttyp ermitteln +\IfSubStr{\docname}{pick_list}{ + % Sammelliste + \setkomavar{backaddress}{\DeliveryAddress} + \firsthead{ + \hspace{-3mm} + \resizebox{\useplength{firstheadwidth}-50mm}{!}{% + \huge \TitlePicklist + } + } + \renewcommand{\NoValue}{1} + \renewcommand{\Picklist}{1} + \newcommand{\doctype}{} + \newcommand{\MyDocdate}{\transdate} + \newcommand{\DocNoTitle}{\DelorderNumber} + \newcommand{\docnumber}{\donumber} + \renewcommand{\deliverydate}{\transdate} + % 2. Documentnummer + \ifthenelse{\equal{\ordnumber}{\leer}}{ + % wenn keine Auftragsnummer -> Angebotsnummer + \newcommand{\SecNoTitle}{\QuotationNumber} + \newcommand{\secnumber}{\quonumber} + }{ + \newcommand{\SecNoTitle}{\OrderNumber} + \newcommand{\secnumber}{\ordnumber} + } +}{} +\IfSubStr{\docname}{sales_delivery_order}{ + % Lieferschein + \renewcommand{\NoValue}{1} + \newcommand{\doctype}{\TitleDelorder} + \newcommand{\MyDocdate}{\transdate} + \newcommand{\DocNoTitle}{\DelorderNumber} + \newcommand{\docnumber}{\donumber} + \renewcommand{\deliverydate}{\transdate} + % 2. Documentnummer + \ifthenelse{\equal{\ordnumber}{\leer}}{ + % wenn keine Auftragsnummer -> Angebotsnummer + \newcommand{\SecNoTitle}{\QuotationNumber} + \newcommand{\secnumber}{\quonumber} + }{ + \newcommand{\SecNoTitle}{\OrderNumber} + \newcommand{\secnumber}{\ordnumber} + } +}{} +\IfSubStr{\docname}{invoice}{ + % Rechnung + \newcommand{\doctype}{\TitleInv} + \newcommand{\MyDocdate}{\invdate} + \newcommand{\DocNoTitle}{\InvNumber} + \newcommand{\docnumber}{\invnumber} + % 2. Documentnummer + \ifthenelse{\equal{\ordnumber}{\leer}}{ + % wenn keine Auftragsnummer -> Angebotsnummer + \newcommand{\SecNoTitle}{\QuotationNumber} + \newcommand{\secnumber}{\quonumber} + }{ + \newcommand{\SecNoTitle}{\OrderNumber} + \newcommand{\secnumber}{\ordnumber} + } +}{} +\IfSubStr{\docname}{proforma}{ + \newcommand{\doctype}{\TitleProforma} + \newcommand{\MyDocdate}{\invdate} + \newcommand{\DocNoTitle}{\InvNumber} + \newcommand{\docnumber}{\invnumber} + % 2. Documentnummer + \ifthenelse{\equal{\ordnumber}{\leer}}{ + % wenn keine Auftragsnummer -> Angebotsnummer + \newcommand{\SecNoTitle}{\QuotationNumber} + \newcommand{\secnumber}{\quonumber} + }{ + \newcommand{\SecNoTitle}{\OrderNumber} + \newcommand{\secnumber}{\ordnumber} + } +}{} +\IfSubStr{\docname}{purchase_order}{ + \renewcommand{\PurchaseOrder}{1} + \newcommand{\doctype}{\TitlePurchaseOrder} + \newcommand{\MyDocdate}{\orddate} + \newcommand{\DocNoTitle}{\RequestOrderNumber} + \newcommand{\docnumber}{\ordnumber} + \renewcommand{\deliverydate}{\reqdate} + \renewcommand{\DelDate}{\ReqByTitle} + \renewcommand{\CustomerID}{\VendorID} + \renewcommand{\kundennummer}{\vendornumber} + \newcommand{\SecNoTitle}{} + \newcommand{\secnumber}{} +}{} +\IfSubStr{\docname}{credit_note}{ + \newcommand{\doctype}{\TitleCreditNote} + \newcommand{\MyDocdate}{\invdate} + \newcommand{\DocNoTitle}{\CredNumber} + \newcommand{\docnumber}{\invnumber} + % keine 2. Documentnummer + \newcommand{\SecNoTitle}{} + \newcommand{\secnumber}{} +}{} +\IfSubStr{\docname}{sales_order}{ + % Auftragsbestaetigung + \newcommand{\doctype}{\TitleSalesOrder} + \newcommand{\MyDocdate}{\orddate} + \renewcommand{\deliverydate}{\reqdate} + \newcommand{\DocNoTitle}{\OrderNumber} + \newcommand{\docnumber}{\ordnumber} + % 2. Documentnummer + \ifthenelse{\equal{\ordnumber}{\leer}}{ + % wenn keine Angebotsnummer -> leer + \newcommand{\SecNoTitle}{} + \newcommand{\secnumber}{} + }{ + \newcommand{\SecNoTitle}{\QuotationNumber} + \newcommand{\secnumber}{\quonumber} + } +}{ } +\IfSubStr{\docname}{sales_quotation}{ + % Angebot + \newcommand{\doctype}{\TitleSalesQuotation} + \newcommand{\MyDocdate}{\quodate} + \renewcommand{\DelDate}{\ValidUntil} + \renewcommand{\deliverydate}{\reqdate} + \newcommand{\DocNoTitle}{\QuotationNumber} + \newcommand{\docnumber}{\quonumber} + % 2. Documentnummer + \newcommand{\SecNoTitle}{} + \newcommand{\secnumber}{} +}{ } + + + +% ==== \paid auf 0.00 falls leer +\IfSubStr{\paid}{\DecimalSign}{}{\renewcommand{\paid}{0{\DecimalSign}00}} + + + +\setkomavar{date}{} + + +\begin{letter}{{\ifthenelse{\isnamedefined{MyAdressfield}}{\MyAdressfield + }{\MyAdress + }} +} +\opening{} + +%========Datum und Nummern==================================================== + +\newcommand{\DocId}{ + \begin{tabular*}{\textwidth+1em }{@{\extracolsep{\fill}}llllr} + \MakeUppercase{\tiny \DocNoTitle} & + \MakeUppercase{\tiny \CustomerID} & + \MakeUppercase{\tiny \SecNoTitle } & + \MakeUppercase{\tiny \DelDate } & + \MakeUppercase{\tiny \Date}~\\ + \mainfont\docnumber & + \mainfont\kundennummer & + \mainfont\secnumber & + \mainfont\deliverydate & + \mainfont\MyDocdate~\\ +\end{tabular*} ~\\ +} + +\hspace{-0.5em} \DocId + + + + +\nexthead{ + \ifthenelse{\bgPdfFirstPageOnly = 1 }{ + \hspace{-4mm} \DocId + }{} +} +\vspace{ 5mm} + +{\noindent\textbf\doctype}~\\ +\IfEndWith{\paymenttype}{\paymentPrivatEnd}{\PriceInclTax }{ } + + +%======Die eigentliche-Tabelle======================================== + +% temporaere Datei mit Tabelle anlegen +\begin{filecontents}{tabelle.tex} +\mainfont +\resetlaufsumme + + + + \ifthenelse{\NoValue > 0 } + { % Tabelle ohne Preisen + \ifthenelse{\Picklist = 1 }{ + + \begin{longtable}{@{}rlX@{ }rlrrrl@{}} + }{ + \begin{longtable}{@{}rlX@{ }rlrr@{}} + + } + % Kopfzeile der Tabelle + + {\Pos} & + {\Number} & + {\ItemNo} & + {\Count} & + {\Unit} \hspace{2mm} + \ifthenelse{\Picklist = 1 }{& {\Take} & {\Storage} }{} + ~\\ + \midrule + \endfirsthead + + % Tabellenkopf nach dem Umbruch + {\Pos} & + {\Number} & + {\ItemNo} & + {\Count} & + {\Unit} \hspace{2mm} + \ifthenelse{\Picklist = 1 }{& {\Take} & {\Storage} }{} + ~\\ + + \midrule + \endhead + + <%foreach number%> + <%runningnumber%> % Laufende Positionsnummer + & + <%number%> % Artikelnummer + & + <%description%> % Kurzbeschreibung des Artikels + \ifthenelse{\equal{<%longdescription%>}{\leer}}{}{ \newline <%longdescription%>} + % Ein zeilenweises Auslieferdatum, wenn es gesetzt bei der Position hinterlegt ist. + \ifthenelse{\equal{<%deliverydate_oe%>}{\leer}}{}{ + \newline \DelDate:~<%deliverydate_oe%>} + & + <%qty NOFORMAT%> % Menge + & + <%unit%> % Einheit + %\ifthenelse{\Picklist = 1 }{& {x} & {x} }{} + %\ifthenelse{\Picklist = 1 }{& {x} & {x} \hhline{~~~~~--} }{~\\} + \ifthenelse{\Picklist = 1 }{& {\underline{;~~~~~~~~~}} & {\underline{;~~~~~~~~~}}~\\ }{~\\} + %~\\ % + <%end number%> + \end{longtable} % Ende der zentralen Tabelle + }{ % Tabelle mit Preisen + \begin{longtable}{@{}rlX@{ }rlrrr@{}} + % Kopfzeile der Tabelle + + {\Pos} & + {\Number} & + {\ItemNo} & + {\Count} & + {\Unit} & + {\Fee} & + {\Dis} & + {\Total} \hspace{2mm} ~\\ + \midrule + \endfirsthead + + % Tabellenkopf nach dem Umbruch + {\Pos} & + {\Number} & + {\ItemNo} & + {\Count} & + {\Unit} & + {\Fee} & + {\Dis} & + {\Total} \hspace{2mm} ~\\ + \midrule + \multicolumn{7}{r}{ \rule{0mm}{5mm} \TabCarry{:} \MarkZwsumPos} + \endhead + + + % Fuss der Teiltabellen + \multicolumn{7}{r}{ \rule{0mm}{5mm} \TabSubTotal{:} \MarkZwsumPos } ~\\ + \endfoot + + % Das Ende der Tabelle + \midrule + \multicolumn{7}{r}{ \rule{0mm}{5mm} \TabSubTotal{:} \MarkZwsumPos} ~\\ + \endlastfoot + + <%foreach number%> + <%runningnumber%> % Laufende Positionsnummer + & + <%number%> % Artikelnummer + & + <%description%> % Kurzbeschreibung des Artikels + \ifthenelse{\equal{<%longdescription%>}{\leer}}{}{ \newline <%longdescription%>} + % Ein zeilenweises Auslieferdatum, wenn es gesetzt ist. + \ifthenelse{\equal{<%reqdate%>}{\leer}}{}{ + \newline \DelDate:~<%reqdate%>} + & + <%qty NOFORMAT%> % Menge + & + <%unit%> % Einheit + & + %\IfEndWith{\paymentterms}{_e}{EN}{\brutto{<%sellprice NOFORMAT%>}{<%qty NOFORMAT%>}{<%p_discount%>}} + \IfEndWith{\paymenttype}{\paymentPrivatEnd}{ + \BruttoSellPrice{<%sellprice NOFORMAT%>}{<%tax_rate%>} + & + \ifthenelse{\equal{<%p_discount%>}{0}}{}{ -<%p_discount%>\%} + & + \BruttoWert{<%linetotal NOFORMAT%>}{<%tax_rate%>} + }{ + \numprint{<%sellprice NOFORMAT%>} + & + \ifthenelse{\equal{<%p_discount%>}{0}}{}{ -<%p_discount%>\%} + & + \Wert{<%linetotal NOFORMAT%>} % Zeilensumme addieren + } + ~\\ % + <%end number%> + \end{longtable} % Ende der zentralen Tabelle + } +\end{filecontents} % Ende der Hilfsdatei. + +\LTXtable{\textwidth}{tabelle.tex} + +\rule{\textwidth}{0pt} % Ein (unsichtbarer) Strich quer ueber die Seite +\vspace{ 5mm} +\vspace{-2em plus 10em minus 2em}~\\ +\ifthenelse{\NoValue > 0 } +{ % wenn keine Zahlen +}{ % Wenn Zahlen + \parbox{\textwidth}{ + \mainfont + % + % + \setlength{\tabcolsep}{0.2em} + \ifthenelse{\equal{\paid}{0{\DecimalSign}00} } + { % Wenn noch nichts gezahlt wurde + \IfSubStr{\invtotal}{\DecimalSign}{}{ + \fpAdd{\invtotal}{0}{<%subtotal NOFORMAT%>} + <%foreach tax%> + \fpAdd{\invtotal}{\invtotal}{<%tax NOFORMAT%>} + <%end tax%> + } + \hfill + \begin{tabular}{@{}rrr@{}} + %{Summe vor Steuern:}& {\numprint{<%subtotal NOFORMAT%>}} & ~\\ + + % Die unterschiedlichen Steueranteile getrennt ausweisen + <%foreach tax%> + { \IfEndWith{\paymenttype}{\paymentPrivatEnd}{\TaxInc }{ } <%taxdescription%>} + & + {\numprint{<%tax NOFORMAT%>}}& ~\\ + <%end tax%> + \midrule[1pt] + {\Sum~ \currency:} & \textbf{\numprint{\invtotal}} + \end{tabular} + } + { % Wenn bereits etwas gezahlt wurde + \hfill + \begin{tabular}{@{}rrr@{}} + + {\EbT}& {\numprint{<%subtotal NOFORMAT%>}} & ~\\ + + % Die unterschiedlichen Steueranteile getrennt ausweisen + <%foreach tax%> + {<%taxdescription%>} + & + {\numprint{<%tax NOFORMAT%>}}& ~\\ + <%end tax%> + + \midrule % Ein dünner Strich + \Sum & \numprint{\invtotal} & ~\\ + + <%foreach payment%> + \AlreadyPayed~ {<%paymentdate%>}:& -{\numprint{<%payment%>}} & ~\\ + <%end paymentdate%> + + \midrule[2pt] % Ein etwas dickerer Strich + {\Left~ \currency:} & \numprint{\total} + \end{tabular} + }% ende ithenelse + + } %Ende des Summenkasten +} + +\vfill % Den Rest-Text soweit wie möglich nach unten schieben +\ifthenelse{\isempty{<%notes%>}}{}{ + \mainfont +\noindent <%notes%> ~\\[2em] + }% +\small +\noindent \YourOrder +\ifthenelse{\Picklist = 0}{\noindent \ifthenelse{\equal{<%ustid%>}{\leer}}{}{\UstidTitle} \UstId}{} +\noindent \paymenthints % ist in translations.tex deffiniert +\ifthenelse{\PurchaseOrder = 0}{\noindent \paymentterms}{} + + +\end{letter} +\end{document} diff --git a/templates/f-tex/mydata.tex.example b/templates/f-tex/mydata.tex.example new file mode 100644 index 000000000..6758fec9c --- /dev/null +++ b/templates/f-tex/mydata.tex.example @@ -0,0 +1,21 @@ + +% \employeecountry wird fuer lxo fancy LaTeX benoetigt +\newcommand{\employeecountry}{Deutschland} + + + +% die folgenden definitionen koennten auch direkt in der Steuerdatei *.lco stehen +\newcommand{\MYfromname}{Die globalen Problemlöser} +\newcommand{\MYaddrsecrow}{Gesellschaft für anderer Leute Sorgen mbH} +\newcommand{\MYrechtsform}{Handelsregister: HRA 123456789 } +\newcommand{\MYfromaddress}{Hauptstraße 5\\12345 Hier} +\newcommand{\MYfromphone}{Tel: +49 (0)12 3456780} +\newcommand{\MYfromfax}{Fax: +49 (0)12 3456781} +\newcommand{\MYfromemail}{mail@g-problemloeser.com} +\newcommand{\MYsignature}{Herbert Wichtig - Geschäftsführer} +\newcommand{\MYustid}{UstID: DE 123 456 789} +\newcommand{\MYfrombank}{Bankverbindung\\ + Ensifera Bank\\ + Kto 1234567800\\ + BLZ 123 456 78 +} diff --git a/templates/f-tex/sample.lco b/templates/f-tex/sample.lco new file mode 100644 index 000000000..a76a4b458 --- /dev/null +++ b/templates/f-tex/sample.lco @@ -0,0 +1,142 @@ +% ---------------------------------------------------------- +% letter.lco +% Steuerdatei Briefklasse f-tex +% +% Changelog: see gitlog + \newcommand{\ftLcoVTversion}{1.0-u (16.11.2011)} +% +% Lizenz +% http://www.gnu.de/licenses/gpl-3.0.html +% +% Siehe ./README +% +% Autor: Wulf Coulmann scripts_at_gpl.coulmann.de +% +% +% ---------------------------------------------------------- + + +\begingroup + \makeatletter + \@latex@warning@no@line{ #### this is letter.lco \ftLcoVTversion #####} +\endgroup + + + +\ProvidesFile{letter.lco}[% + 2002/07/09 v0.9a LaTeX2e unsupported letter-class-option] + +\KOMAoptions{foldmarks=false} +\usepackage{graphicx} +\usepackage[utf8]{inputenc} +\usepackage{ngerman} +\usepackage{lmodern} +\usepackage{xcolor} +\usepackage{watermark} +\usepackage{xifthen} + + +% ================== settings ============================== + + % Name der pdf Datei die den Briefkopf enthaelt + \newcommand{\bgPdfName}{letter_head.pdf} + + % Hintergrund pdf nur bei erster Dokumentseite [1|0] + \newcommand{\bgPdfFirstPageOnly}{1} + + % Hintergrundpdf nur bei versand per email [1|0] + % (setze diesen Wert auf 1, wenn auf bereits Bedruktes Briefpapier ausgedruckt werden soll) + \newcommand{\bgPdfEmailOnly}{0} + + % Trennlienie unter der Seitenkopfzeile ab Seite 2 ff. + \KOMAoptions{headsepline=on} + + % der Abstand zu den Fusszeilen + \addtolength{\textheight}{23mm} + + % zusaetzlicher Zwischenraum zur Fusszeile ab Seite 2 ff. + % (nur bei bgPdfFirstPageOnly = 1) + \addtolength{\footskip}{10mm} + + +% ================== end settings ============================== + + + +\setkomavar{backaddress}{} + +\setkomavar{fromname}{\MYfromname} +\newcommand\addrsecrow{\MYaddrsecrow} +\newcommand\rechtsform{\MYrechtsform} +\setkomavar{fromaddress}{\MYfromaddress} +\setkomavar{fromphone}{\MYfromphone} +\setkomavar{fromfax}{\MYfromfax} +\setkomavar{fromemail}{\MYfromemail} +\setkomavar{signature}{\MYsignature} +\newcommand\ustid{\MYustid} +\setkomavar{frombank}{\MYfrombank} + +\renewcommand{\rmdefault}{cmss} +\newlength\entrytblsub +\setlength\entrytblsub{\dimexpr\tabcolsep+1.3mm+\arrayrulewidth\relax} +\setlength\textwidth{166mm} +\oddsidemargin -0.4mm +\KOMAoptions{headsepline=on} + +\pagestyle{myheadings} +\@addtoplength{firstfootvpos}{18mm} +\@addtoplength{foldmarkhpos}{5mm} +\@setplength{firstheadvpos}{0mm} +\@setplength{firstheadwidth}{165mm} +\@setplength{firstfootwidth}{165mm} +\@setplength{toaddrhpos}{25mm} +\@setplength{toaddrvpos}{38mm} +\@setplength{refhpos}{26mm} +\@addtoplength{refvpos}{-18mm} + +\font\mainfont=cmss9 + + + +\ifthenelse{\bgPdfFirstPageOnly = 0 }{ + \addtolength{\headheight}{50mm} + \watermark{ + \setlength{\unitlength}{1mm} + \put(-22,-226){ + \includegraphics[width=210mm]{\bgPdfName} + } + } +}{} + +\firsthead{ + \ifthenelse{\bgPdfFirstPageOnly = 1 }{ + \put(-69,0){ % Mit diesem put-Befehl wird die Position des Logos bestimmt. + \includegraphics[width=210mm]{\bgPdfName} + } + }{} +} + + + + +\firstfoot{% +} + +\nextfoot{% + \parbox{\useplength{firstfootwidth}}{ + \hspace{-\entrytblsub} + \begin{tabular}{l} + \usekomavar{fromname} + \end{tabular}\hfill + \begin{tabular}{r} + \thepage + \end{tabular} + \hspace{-\entrytblsub} + } + \vspace{10mm} +} + + + +\endinput +% vim: set filetype=tex :EOF diff --git a/templates/f-tex/sample_head.pdf b/templates/f-tex/sample_head.pdf new file mode 100644 index 000000000..6d14e7eea Binary files /dev/null and b/templates/f-tex/sample_head.pdf differ diff --git a/templates/f-tex/setup.sh b/templates/f-tex/setup.sh new file mode 100755 index 000000000..b557e8061 --- /dev/null +++ b/templates/f-tex/setup.sh @@ -0,0 +1,1082 @@ +#!/bin/bash + + +# Setup script fuer die Nutzung der fancy-LaTeX Umgebung oder +# der Label-Print erweiterung (lp) in LX-Office-erp. +# Welches Setup ist von der Position innerhalb des Dateisystems abhaengig. +# Das Script kann auch nach erfolgtem Setup erneut aufgerufen werden + +# see ./setup.sh -h + + + + + +# Revision 0.2 (13.02.2011) add lp +# setup add determination of company data +# Revision 0.1 (19.12.2010) initial script create + + +# config + +DB_AUTH='../../config/lx_office.conf' + +FILE_LIST_FTEX=' + letter.tex + sample.lco + sample_head.pdf + translations.tex + xstring.sty + zwischensumme.sty +' + +FILE_LIST_LP=' + label_abs_a7_de.tex + label_nn_brief_a4_de.tex + zweckform_3427.tdf + zweckform_3483.tdf +' + + +DOC_TYPE_FTEX=' + invoice + proforma + sales_quotation + sales_order + sales_delivery_order + credit_note + pick_list + purchase_order +' + + +LXO_DETERMINE=' + ../../SL/Form.pm + ../../config/lx_office.conf.default + ../../doc/changelog +' + +CHK_RAWNUMBER_PATCH=' + ../../SL/DO.pm + ../../SL/IS.pm + ../../SL/OE.pm +' + +MY_DATA=' + employeecountry + labelcompanyname + labelbankname + labelbankcode + labelbankaccount + MYfromname + MYaddrsecrow + MYrechtsform + MYfromaddress + MYfromphone + MYfromfax + MYfromemail + MYsignature + MYustid + MYfrombank +' + +BASE_DIR=`readlink -f $0 | sed 's/setup\.sh$//'` + +MODUL=`basename ${BASE_DIR}` +export TEXINPUTS=".:${BASE_DIR}:" + +OK='...... [ok]' +MARK='\033[1;34m' +UNMARK='\033[0m' +TIME=`date +%s` + +USAGE="\n\n setup LaTeX templates for lx-office erp (www.lx-office.org) +\n\n USAGE: ./`basename $0` [OPTION] \n +\n + -h print this Help\n +\n +\n + OPTIONS for trouble shooting:\n\n + -D don't connect to any database\n + -C no colored output (don't use any terminal escape character)\n +\n\n + RECOMMENDED USE ./setup.sh + +\n +" + +# script control + +DATABASE=1 + +while getopts "hDC" flag +do + case $flag in + h) + echo -e ${USAGE} + exit + ;; + D) + DATABASE=0 + ;; + C) + NO_COLOR=1 + ;; + esac +done + +# Disclaim + +cat << EOD + + ########################################################################## + # Disclaimer # + ########################################################################## + # # + # Dies ist ein Script zum Einrichten von LaTeX Templates # + # (fancy-latex (f-tex)) oder (label-print (lp) fuer # + # # + # lx-office erp (www.lx-erp.org) # + # # + # Obwohl LX-Office sich an deutschsprachige Anwender richtet ist dieses # + # Script in Englisch und soll auch nicht uebersetzt werden. # + # # + # * es richtet sich an System-Administratoren # + # * da es das Script nur in einer Sprache gibt, ist es viel leichter # + # bei Fehlern und Fehlermeldungen aus dem Script selbst, im Internet # + # nach Loesungen zu suchen. # + # # + ########################################################################## + # # + # This script provides an easy to use setup for the fancy LaTeX # + # environment of lx-office erp (templates/f-tex) # + # # + # Normal use is to run ./setup.sh without any parameter. You may also # + # check # + # ./setup.sh -h # + # for help. # + # # + # The script tries to be as save as possible to avoid unwanted file # + # overwriting by being very interactive. It's designed to be invoked # + # multiple times inside the same template directory. So it is possible # + # to rerun the script if there are updates available or after you break # + # your LaTeX templates by any changes. # + # # + # I recommend to backup your installation and database before you run # + # this script. # + # # + # ANYHOW: I do not take responsibility for any harm initiated by this # + # script. (Wulf Coulmann -- scripts_at_gpl.coulmann.de) # + # # + ########################################################################## + + +EOD + +QUESTION=' I understand the above warnings [YES/NO/Q]:' + +echo -n "${QUESTION} " + + +[ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} +read ANSWER +[ "${NO_COLOR}" = 1 ] || echo -ne "${UNMARK}" + + +until [ "${ANSWER}" = YES ]\ + || [ "${ANSWER}" = NO ] \ + || [ "${ANSWER}" = N ] \ + || [ "${ANSWER}" = n ] \ + || [ "${ANSWER}" = q ] \ + || [ "${ANSWER}" = Q ] ; do + echo -n "${QUESTION} " + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + read ANSWER + [ "${NO_COLOR}" = 1 ] || echo -ne "${UNMARK}" +done + +case ${ANSWER} in + YES) + echo -n ' accepted' + ;; + NO|n|N|q|Q) + echo + echo ' script aborted by user input' + exit 72 + ;; +esac + + +FEEDBACK='################################\n # FEEDBACK:\n +' + + +# load functions + +function error { + echo '[error]' ...... $1 ...... '[terminate script]' + exit 72 +} + +function mark { + [ "${NO_COLOR}" = 1 ] || echo -ne "${MARK}" + echo -n "${1}" + [ "${NO_COLOR}" = 1 ] || echo -ne "${UNMARK}" +} + + + +function ask_yn { + local QUESTION=$1 + until [ "${ANSWER}" = y ]\ + || [ "${ANSWER}" = Y ] \ + || [ "${ANSWER}" = j ] \ + || [ "${ANSWER}" = J ] \ + || [ "${ANSWER}" = n ] \ + || [ "${ANSWER}" = N ] \ + || [ "${ANSWER}" = Q ] \ + || [ "${ANSWER}" = q ] ; do + echo -n "${QUESTION}" + read ANSWER + done + + case ${ANSWER} in + y|Y|j|J) + return + ;; + n|N) + return + ;; + q|Q) + [ "${NO_COLOR}" = 1 ] || echo -ne "${UNMARK}" + echo + echo ' script aborted by user input' + exit 72 + ;; + esac +} + +function latex_pack_check { + echo ' -> search LaTeX package '$1' ' + echo -n ' ' + if [ ! `kpsewhich ${1}.sty` ] ; then + echo + echo " can't find package ${1}" + echo " on debian systems you may install apt-file" + echo " aptitude install apt-file" + echo " apt-file update" + echo " apt-file search ${1}.sty" + echo " this will show which package contains the needet LaTeX .sty file" + echo " on other systems, please refer to their documentation on how to " + echo " find matching packages." + echo + echo " If you are done, rerun this script" + echo " [unsatisfied dependencies]' ...... ${1} ...... [terminate script]" + exit 72 + else + echo \ \ ${OK} + fi + +} + +function check_accepted_names { + echo ' -> check for suspect characters in '${2} + echo -n ${1} | egrep '[^-_\.!A-Za-z0-9]' && echo ' [suspect characters found] in ... '${2}' ... [terminate script]' && exit 72 +} + +function check_int { + echo ' -> check for suspect characters in '${2} + echo -n ${1} | egrep '[^0-9]' && echo ' [suspect characters found] in ... '${2}' ... [terminate script]' && exit 72 +} + +function create_file { + ANSWER=0 + if [ "${1}" = ln ] ;then + DO=1 + echo -n ' -> try to create symbolic link '${3} + if [ -e "${3}" ] ; then + if [ -L "${3}" ] ; then + if [ "`ls -l ${3} | awk '{print $10}'`" = "${2}" ]; then + echo ' ... symbolic link already exists, nothing to do!' + DO=0 + else + echo ' ... symbolic link with different target exist!' + ls -lah "${3}" + echo ' you may' + echo ' [d] delete and replace the current link' + echo ' [m] move current link to '${3}.${TIME}.old + echo ' [s] skip -- leave it as it is' + echo ' [q] abort setup.sh' + QUESTION=' what do do? [d/m/s/q]: ' + echo -en ${QUESTION} + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + read ANSWER + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + until [ "${ANSWER}" = D ] \ + || [ "${ANSWER}" = d ] \ + || [ "${ANSWER}" = m ] \ + || [ "${ANSWER}" = s ] \ + || [ "${ANSWER}" = q ] ; do + echo -n "${QUESTION}" + read ANSWER + done + + case ${ANSWER} in + d) + rm -f ${3} || error ' unable to delete symbolic link '${3} + ;; + m) + mv -f ${3} ${3}.${TIME}.old || error ' unable to move symbolic link '${3} + ;; + s) + echo ' as you decide, we leave it as it is!' + DO=0 + ;; + q) + [ "${NO_COLOR}" = 1 ] || echo -ne "${UNMARK}" + echo + echo ' script aborted by user input' + exit 72 + ;; + esac + fi + else + echo ' ... file already exists where I tried to create a symbolic link!' + ls -lah "${3}" + echo ' you may' + echo ' [S] show the file (exit file display with "q")' + echo ' [m] move current file to '${3}.${TIME}.old + echo ' [d] delete and replace the file with symbolic link' + echo ' [s] skip -- leave it as it is' + echo ' [q] abort setup.sh' + QUESTION='what to do? [S/d/m/s/q]:' + echo -en " ${QUESTION} " + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + read ANSWER + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + until [ "${ANSWER}" = S ] \ + || [ "${ANSWER}" = d ] \ + || [ "${ANSWER}" = m ] \ + || [ "${ANSWER}" = s ] \ + || [ "${ANSWER}" = q ] ; do + echo -n " ${QUESTION} " + read ANSWER + done + + case ${ANSWER} in + S) + echo + echo + less "${3}" + echo + echo + create_file "${1}" "${2}" "${3}" + return + ;; + m) + mv -f ${3} ${3}.${TIME}.old || error ' unable to move file '${3} + ;; + d) + rm -f ${3} || error ' unable to delete file '${3} + ;; + s) + echo ' as you decide, we leave it as it is!' + DO=0 + ;; + q) + [ "${NO_COLOR}" = 1 ] || echo -ne "${UNMARK}" + echo + echo ' script aborted by user input' + exit 72 + ;; + esac + fi + fi + if [ "${DO}" = "1" ] ;then ln -s "${2}" "${3}" || error ' failed to create symbolic link '${3} ; fi + [ "${DO}" = "1" ] && echo \ \ ${OK} + fi + + if [ "${1}" = cp ] ;then + echo -n ' -> try to copy file '${3} + DO=1 + if [ -e "${3}" ] ; then + echo ' ... file already exists!' + diff "${2}" "${3}" >/dev/null + if [ "$?" = 0 ] ; then + echo ' files are equal, we leave it as it is!' + DO=0 + else + ls -lah "${3}" + echo ' you may' + echo ' [D] show a diff between the new and current file' + echo ' [m] move current file to '${3}.${TIME}.old + echo ' [d] delete and replace with new file' + echo ' [s] skip -- leave it as it is' + echo ' [q] abort setup.sh' + QUESTION='what to do? [D/m/d/s/q]:' + echo -en " ${QUESTION} " + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + read ANSWER + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + until [ "${ANSWER}" = D ] \ + || [ "${ANSWER}" = d ] \ + || [ "${ANSWER}" = m ] \ + || [ "${ANSWER}" = s ] \ + || [ "${ANSWER}" = q ] ; do + echo -n " ${QUESTION} " + read ANSWER + done + + case ${ANSWER} in + D) + echo + echo + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + echo '---------------------------------------' + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + diff -C 3 "${2}" "${3}" + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + echo '---------------------------------------' + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + echo + echo + create_file "${1}" "${2}" "${3}" + ;; + m) + mv -f ${3} ${3}.${TIME}.old || error ' unable to move file '${3} + ;; + d) + rm -f ${3} || error ' unable to delete file '${3} + ;; + s) + echo ' as you decide, we leave it as it is!' + DO=0 + ;; + q) + [ "${NO_COLOR}" = 1 ] || echo -ne "${UNMARK}" + echo + echo ' script aborted by user input' + exit 72 + ;; + esac + fi + fi + if [ "${DO}" = "1" ] ;then cp "${2}" "${3}" || error ' failed to copy '${3} ; fi + [ "${DO}" = "1" ] && echo \ \ ${OK} + fi + +} + +function create_mydata { + + VALUE=${1} + DB=${2} + NODATA=' did not get a value corresponding to your template dir' + + SQL=" + SELECT regexp_replace( u1.cfg_value, E'\n' ,E'\\\\\\\\\\\\' || E'\n') + FROM auth.user_config u1, auth.user_config u2 + WHERE u1.user_id = u2.user_id + AND u1.cfg_key = '"${DB}"' + AND u2.cfg_key = 'templates' + AND u2.cfg_value = 'templates/"${TEMP_DIR}"' + ORDER BY u1.cfg_value DESC + LIMIT 1; + " + case ${DB} in + tel) + PRE='Tel:' + ;; + fax) + PRE='fax:' + ;; + co_ustid) + if [ ! `psql --pset tuples_only -h "${PGHOST}" -U "${PGUSER}" "${PGDATABASE}" -c "${SQL}"`"" ] ; then + SQL=" + SELECT regexp_replace( u1.cfg_value, E'\n' ,E'\\\\\\\\\\\\' || E'\n') + FROM auth.user_config u1, auth.user_config u2 + WHERE u1.user_id = u2.user_id + AND u1.cfg_key = 'taxnumber' + AND u2.cfg_key = 'templates' + AND u2.cfg_value = 'templates/"${TEMP_DIR}"' + ORDER BY u1.cfg_value DESC + LIMIT 1; + " + PRE='StNr.:' + else + PRE='UstIdNr:' + fi + ;; + *) + PRE='' + ;; + esac + + + + if [ "${2}" ] ; then + ANSWER=`psql --pset tuples_only -h "${PGHOST}" -U "${PGUSER}" "${PGDATABASE}" -c "${SQL}"` || error "unable to connect to auth db" + if [ ! "${VALUE}" ] ; then + echo ' please fix this later' + ANSWER=FIX_ME + else + echo ' found: '${ANSWER} + fi + else + if [ ! "${2}" ] && [ ${1} = "employeecountry" ] ; then + read ANSWER + else + echo ' please fix this later' + ANSWER=FIX_ME + fi + fi + + echo -e "\0134"'newcommand{'"\0134"${VALUE}'}{'${PRE}${ANSWER}'}' >> mydata.tex + +} + +function read_db_conf { + + perl -e 'use Config::Std; + read_config "'${DB_AUTH}'.default" => my %config_default; + my $val_default = $config_default{"authentication/database"}{'${1}'}; + read_config "'${DB_AUTH}'" => %config; + my $val = $config{"authentication/database"}{'${1}'} if $config{"authentication/database"}{'${1}'}; + if ( $val ) { + print $val; + }else{ + print $val_default; + }' + +} + + + + + +# check for dependencies +echo -n ' -> search kpsewhich ' + which kpsewhich >/dev/null + [ "$?" = 0 ] || error 'unable find programm "kpsewhich" -- is there a propper installed LaTeX? (on debian: aptitude install texlive-base-bin)' + echo \ \ ${OK} + +if [ "${MODUL}" = "f-tex" ] ; then + echo ' -> search LaTeX documentclass scrlttr2' + echo -n ' ' + if [ ! `kpsewhich scrlttr2.cls` ] ; then + echo + echo " can't find documentclass scrlttr2" + echo " on debian systems you may install it by" + echo " aptitude install texlive-latex-recommended" + echo " on other systems, please refer to their documentation how to find" + echo " matching packages." + echo + echo " If you are done, rerun this script" + echo " [unsatisfied dependencies]' ...... documentclass scrlttr2 ...... [terminate script]" + exit 72 + else + echo \ \ ${OK} + fi +elif [ "${MODUL}" = "lp" ] ; then + echo ' -> search LaTeX package ticket and check vor needed version ' + echo -n ' ' + HOLD_TEXINPUTS=${TEXINPUTS} + export TEXINPUTS='' + if [ `kpsewhich ticket.sty` ] ; then + grep rowmode `kpsewhich ticket.sty` > /dev/null + if [ "$?" -gt "0" ] ;then + FILE_LIST_LP=${FILE_LIST_LP}" ticket.sty" + echo \ \ "your version of LaTeX Package ticket does not support rowmode - we use our own ticket.sty" + echo \ \ \ \ \ \ "ticket.sty supports option rowmode from version v0.4b" + echo \ \ \ \ \ \ ${OK} + fi + else + FILE_LIST_LP=${FILE_LIST_LP}" ticket.sty" + echo \ \ "can't find LaTeX Package ticket, but we use our own ticket.sty because we need version => v0.4b" + echo \ \ \ \ \ \ "ticket.sty supports option rowmode from version v0.4b" + echo \ \ \ \ \ \ ${OK} + fi + export TEXINPUTS=${HOLD_TEXINPUTS} +else + error "no valid install modul - is the install script inside ~/templates/f-tex or ~/templates/lp ?" +fi + +for PACK in `grep usepackage ${BASE_DIR}/*.tex ${BASE_DIR}/*.sty ${BASE_DIR}/*.lco |awk -F '{' '{print $2}'|awk -F '}' '{print $1}'| sort | uniq`; do + latex_pack_check ${PACK} +done + + +# decide the installation target (template directory) +echo -n ' -> cd to base directory: '${BASE_DIR}' ' + + cd ${BASE_DIR} || error "unable to change directory" + echo \ \ ${OK} + + + +echo ' -> check if we are inside an lxo installation' + +if [ ! -e ../../SL/Form.pm ] ; then + + dpkg -l | grep lx-office-erp | egrep '^ii' + if [ "$?" = 0 ] ; then + echo ' seams like this is a Debian-package' + DB_AUTH='/etc/lx-office-erp/lx_office.conf' + + LXO_DETERMINE=' + /usr/lib/lx-office-erp/SL/Form.pm + /etc/lx-office-erp/lx_office.conf.default + /usr/share/doc/lx-office-erp/changelog + ' + + CHK_RAWNUMBER_PATCH=' + /usr/lib/lx-office-erp/SL/DO.pm + /usr/lib/lx-office-erp/SL/IS.pm + /usr/lib/lx-office-erp/SL/OE.pm + ' + + fi + +fi + +for now in ${LXO_DETERMINE} ; do + [ -e ${now} ] || error 'missing '${now}', do not run this script outside an lx-office installation!. Is setup.sh located inside an lxo installation in templates/'${MODUL}'?' +done +echo \ \ ${OK} + +if [ "${MODUL}" = "f-tex" ] ; then + echo ' -> search raw numbers patch ' + RAW_NUM=`egrep -oh '\{[^{]*_nofmt\}' ${CHK_RAWNUMBER_PATCH} |wc -l` + + if [ "${RAW_NUM}" -lt 20 ] ; then + echo ' did not find the raw_number values' + echo + egrep -oh '\{[^{]*_nofmt\}' ${CHK_RAWNUMBER_PATCH} + echo ' seems like you added fancy LaTeX separate and needed raw_number values are missing' + echo ' this is already part of the dev-source code.' + echo ' please use this script in the environment you got it from' + error 'missing raw_number values' + fi + echo \ \ ${OK} +fi + + +if [ ${DATABASE} = 1 ] ; then + + echo ' -> request Auth-DB ' + [ -r ${DB_AUTH} ] || [ -r ${DB_AUTH}.default ] || error "unable to read ${DB_AUTH} or ${DB_AUTH}.default -- you must be able to read db credentials" + + export PGDATABASE=`read_db_conf db` + check_accepted_names ${PGDATABASE} database_name + export PGPASSWORD=`read_db_conf password` + check_accepted_names ${PGPASSWORD} database_pw + export PGUSER=`read_db_conf user` + check_accepted_names ${PGUSER} database_user + export PGPORT=`read_db_conf port` + [ "${#PGPORT}" -lt 1 ] && PGPORT=5432 + check_int ${PGPORT} database_port + export PGHOST=`read_db_conf host` + [ "${#PGHOST}" -lt 1 ] && PGHOST=localhost + check_accepted_names ${PGHOST} database_host + + SQL=" + SELECT + substring(cfg_value from E'[^/]*$') as template_dir + FROM auth.user_config + WHERE cfg_key = 'templates' + GROUP BY cfg_value ; + " + + + echo ' -> search active template dirs ' + echo + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + + psql --pset tuples_only -h "${PGHOST}" -U "${PGUSER}" "${PGDATABASE}" -c "${SQL}" || error "unable to connect to auth db" + + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + echo ' I found the above listed template directorys in '`mark '[lxo-home]/templates'`' by requesting your user configuration.' + echo ' in database '`mark "${PGDATABASE}"`'.' +fi + +echo ' Type in which template directory to use (by typing in a name)' +echo ' * if template_dir does not exist, it will be created' +echo ' * template_dir must also be configured in your user administration' +echo ' to make it active.' +echo +echo -en ' type name of template dirctory: ' +[ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} +read TEMP_DIR +[ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + + +[ "${#TEMP_DIR}" -gt 0 ] || error 'no value for template dir provided ' + + +if [ -d "../${TEMP_DIR}" ] ; then + MV_DIR=${TEMP_DIR}.${TIME}.old + echo + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + ls -lah ../${TEMP_DIR} + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + echo + echo ' the directory already exists and contains the above listed files' + echo ' you can:' + echo -e ' - move the directory to '`mark "templates/${MV_DIR}"`' and create a empty one, or' + echo ' - install the templates in the existing directory by interactive overwriting existing files' + echo + ask_yn ' move templates/'${TEMP_DIR}' to templates/'${MV_DIR}'? [y/n/q]: ' + + + + if [ "${ANSWER}" = y ] ; then + echo ' -> check for permission to move template directory ' + mv -i ../${TEMP_DIR} ../${MV_DIR} || error "unable to move directory " + echo -n ' -> original directory moved to '${MV_DIR} + echo \ \ ${OK} + fi + if [ "${ANSWER}" = n ] ; then + echo ' -> check for permission to write in template directory [lxo-home]/templates/'${TEMP_DIR} + [ -w ../${TEMP_DIR} ] || error "no permission to write directory " + echo \ \ ${OK} + fi + ANSWER=0 +fi + + +if [ ! -d "../${TEMP_DIR}" ] ; then + echo -n ' -> check for permission to create new template directory ' + mkdir "../"${TEMP_DIR} || error "unable to write to `echo ${PWD} | sed 's/\/'${MODUL}'$//'` -- you must be able to write in ~/templates " + echo \ \ ${OK} + echo -n ' -> '${TEMP_DIR}' created' + echo \ \ ${OK} +fi + +echo -n ' -> cd to template directory: '${TEMP_DIR}' ' + + cd ../${TEMP_DIR} || error "unable to change directory" + echo \ \ ${OK} +pwd + + +if [ -e mydata.tex ] ;then + echo ' -> check mydata.tex' + grep koma ./mydata.tex && FEEDBACK=${FEEDBACK}' # looks like a DEPRECATED mydata.tex -- please compare to f-tex/mydata.tex.example \n' + for now in ${MY_DATA} ; do + grep ${now} ./mydata.tex || FEEDBACK=${FEEDBACK}' # missing '${now}' in mydata.tex -- please compare to f-tex/mydata.tex.example \n' + done + + echo -e \ \ "your current mydata.tex looks like" + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + cat mydata.tex + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + +else + if [ ${DATABASE} = 1 ] ; then + # mydata voodooo goes here + SQL=" + SELECT + u1.cfg_value as company, + u2.cfg_value as address, + u3.cfg_value as tel, + u4.cfg_value as fax, + u5.cfg_value as texnumber, + u6.cfg_value as co_ustid + FROM + auth.user_config u1, + auth.user_config u2, + auth.user_config u3, + auth.user_config u4, + auth.user_config u5, + auth.user_config u6 + WHERE + u1.user_id = u2.user_id and + u2.user_id = u3.user_id and + u3.user_id = u4.user_id and + u4.user_id = u5.user_id and + u5.user_id = u6.user_id and + u1.cfg_key = 'company' and + u2.cfg_key = 'address' and + u3.cfg_key = 'tel' and + u4.cfg_key = 'fax' and + u5.cfg_key = 'taxnumber' and + u6.cfg_key = 'co_ustid' + GROUP BY + u1.cfg_value, + u2.cfg_value, + u3.cfg_value, + u4.cfg_value, + u5.cfg_value, + u6.cfg_value + ORDER BY + company; + " +# [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} +# +# psql -h "${PGHOST}" -U "${PGUSER}" "${PGDATABASE}" -c "${SQL}" || error "unable to connect to auth db" +# +# [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + echo ' There is no mydata.tex, we try to create it' + echo ' please answer the following questions' + echo -n ' - country your company is located eg:"Deutschland" : ' + create_mydata employeecountry + echo ' - owner of the bankaccount for label print' + echo ' used for "pay on delivery (Nachnahme)"' + echo -n ' type ~ instead of blanks eg: "Herbert~Wichtig" : ' + create_mydata labelcompanyname + echo ' - name of the bank for label print' + echo ' used for "pay on delivery (Nachnahme)"' + echo -n ' type ~ instad of blanks eg: "Ensifera~Bank" : ' + create_mydata labelbankname + echo ' - bank account number for label print' + echo ' used for "pay on delivery (Nachnahme)"' + echo -n ' no blanks eg: "123456789" : ' + create_mydata labelbankcode + echo ' - bank code (BLZ) for label print' + echo ' used for "pay on delivery (Nachnahme)' + echo -n ' no blanks eg: "10010010" : ' + create_mydata labelbankaccount + echo ' - company name for dokuments' + echo ' used for invoice, sales_quotation, etc.' + echo -n ' eg: "Die globalen Problemlöser" : ' + create_mydata MYfromname company + echo ' - company name second row for documents' + echo ' used for invoice, sales_quotation, etc.' + echo -n ' eg: "Gesellschaft für anderer Leute Sorgen mbH" : ' + create_mydata MYaddrsecrow + echo ' - legal form for documents' + echo ' used for invoice, sales_quotation, etc.' + echo ' eg: "Handelsregister: HRA 123456789" : ' + echo -n ' or: "Inhaber Herbert Wichtig" : ' + create_mydata MYrechtsform + echo ' - company address for documents' + echo ' used for invoice, sales_quotation, etc.' + echo ' multirow, type \\ as row dilimiter ' + echo -n ' eg: "Hauptstraße 5\\12345 Hier" : ' + create_mydata MYfromaddress address + echo ' - tel for documents' + echo ' used for invoice, sales_quotation, etc.' + echo -n ' eg: "Tel: +49 (0)12 3456780" : ' + create_mydata MYfromphone tel + echo ' - fax for documents' + echo ' used for invoice, sales_quotation, etc.' + echo -n ' eg: "Fax: +49 (0)12 3456781" : ' + create_mydata MYfromfax fax + echo ' - email for documents' + echo ' used for invoice, sales_quotation, etc.' + echo -n ' eg: "mail@g-problemloeser.com" : ' + create_mydata MYfromemail + echo ' - signatur for documents' + echo ' used for invoice, sales_quotation, etc.' + echo -n ' eg: "Herbert Wichtig - Geschäftsführer" : ' + create_mydata MYsignature + echo ' - tax number for documents' + echo ' used for invoice, sales_quotation, etc.' + echo ' it is common to use ustid but if you have none' + echo ' type in your main tax number' + echo ' eg: "UstID: DE 123 456 789" : ' + echo -n ' or: "StrNr: 12/345/6789" : ' + create_mydata MYustid co_ustid + echo ' - bank account for documents' + echo ' used for invoice, sales_quotation, etc.' + echo ' multirow, type \\ as row delimiter ' + echo -n ' eg: "Bankverbindung\\Ensifera Bank\\Kto 1234567800\\BLZ 123 456 78" : ' + create_mydata MYfrombank + + # damn escaping -- gnarf + perl -pi -e 's/([^\$\{])\\/$1\\\\/g' mydata.tex + perl -pi -e 's/([\&\%])/\\$1/g' mydata.tex + else + cp ../f-tex/mydata.tex.example mydata.tex + FEEDBACK=${FEEDBACK}' # I generate a mydata.tex please edit this file to match to your needs \n' + fi + FEEDBACK=${FEEDBACK}' # I generate a mydata.tex please edit this file to match to your needs \n' +fi + + +if [ "${MODUL}" = "f-tex" ] ; then + # search for installed languages + if [ ${DATABASE} = 1 ] ; then + SQL=" + SELECT + u1.cfg_value || ';' || + u2.cfg_value || ';' || + u3.cfg_value || ';' || + u4.cfg_value || ';' || + u5.cfg_value + FROM + auth.user_config u1, + auth.user_config u2, + auth.user_config u3, + auth.user_config u4, + auth.user_config u5 + WHERE + u1.user_id = u2.user_id and + u2.user_id = u3.user_id and + u3.user_id = u4.user_id and + u4.user_id = u5.user_id and + u1.cfg_key = 'dbname' and + u2.cfg_key = 'dbhost' and + u3.cfg_key = 'dbport' and + u4.cfg_key = 'dbuser' and + u5.cfg_key = 'dbpasswd' + GROUP BY + u1.cfg_value, + u2.cfg_value, + u3.cfg_value, + u4.cfg_value, + u5.cfg_value; + " + + echo ' -> try to determine aktive languages ....' + echo ' -> search database '${PGDATABASE}' to find lxo-erp databases ....' + + DBS=`psql --pset tuples_only -h "${PGHOST}" -U "${PGUSER}" "${PGDATABASE}" -c "${SQL}"` || error "unable to connect to auth db" + + for db in ${DBS} ; do + + PGDATABASE=`echo -n ${db} | awk -F ';' '{print $1}'` + echo -e ' -> prepare to request db '`mark ${PGDATABASE}` + check_accepted_names ${PGDATABASE} database_name + PGHOST=`echo -n ${db} | awk -F ';' '{print $2}'` + [ "${#PGHOST}" -lt 1 ] && PGHOST=localhost + check_accepted_names ${PGHOST} database_host + PGPORT=`echo -n ${db} | awk -F ';' '{print $3}'` + [ "${#PGPORT}" -lt 1 ] && PGPORT=5432 + check_int ${PGPORT} database_port + PGUSER=`echo -n ${db} | awk -F ';' '{print $4}'` + check_accepted_names ${PGUSER} database_user + PGPASSWORD=`echo -n ${db} | awk -F ';' '{print $5}'` + check_accepted_names ${PGPASSWORD} database_pw + DELCHECK=`echo -n ${db} | awk -F ';' '{print $6}'` + [ "${#DELCHECK}" = 0 ] || error 'field delimiter conflict: there may be a ";" in one of your database definitions (db/host/port/user/pw)' + SQL="SELECT template_code FROM language ;" + echo \ \ ${OK} + RES=`psql --pset tuples_only -h "${PGHOST}" -U "${PGUSER}" "${PGDATABASE}" -c "${SQL}"` || error "unable to connect to db "${PGDATABASE} + echo -e ' -> found '`mark "${RES}"` + echo \ \ ${OK} + LANGS=${LANGS}' '${RES} + done + + LANGS=`echo ${LANGS} | sed 's/\ /\n/g'|sort | uniq` + echo ' -> join language codes ...' + echo + echo + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + echo -e ' '${LANGS} + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + echo + echo ' I found the above listed language template_codes (see: System -> Languages -> List Languages)' + echo ' - you may add more template_codes by type in a [space] seperated list (e.g.: ru it fr)' + echo ' - or you may replace it with your own values by type in a [space] seperated list (e.g.: ru it fr)' + ask_yn ' add template_codes? [y/n/q]: ' + + if [ "${ANSWER}" = y ] ; then + echo -n ' type [space] seperated template_code list to add to current values: ' + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + read TMP_CO + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + echo -n ' list of template_codes is now: ' + LANGS=${LANGS}' '${TMP_CO} + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + echo -e ' '${LANGS} + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + echo \ \ ${OK} + fi + ANSWER=0 + + ask_yn ' replace the current template_codes? [y/n/q]: ' + + if [ "${ANSWER}" = y ] ; then + echo -n ' type [space] seperated template_code list to replace current values: ' + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + read TMP_CO + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + echo -n ' list of template_codes is now: ' + LANGS=${TMP_CO} + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + echo -e ' '${LANGS} + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + echo \ \ ${OK} + fi + ANSWER=0 + else + echo -n ' type [space] seperated template_code list (see: System -> Languages -> List Languages eg: de en fr): ' + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + read TMP_CO + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + echo -n ' list of template_codes is now: ' + LANGS=${TMP_CO} + [ "${NO_COLOR}" = 1 ] || echo -ne ${MARK} + echo -e ' '${LANGS} + [ "${NO_COLOR}" = 1 ] || echo -ne ${UNMARK} + echo \ \ ${OK} + fi + + echo + echo + echo -e ' your current language template_codes are: '`mark "${LANGS}"` + echo + echo + + # copy files and create links + + + + for now in ${FILE_LIST_FTEX} ; do + create_file cp ../f-tex/${now} ${now} + done + + for now in ${LANGS} ; do + echo -n ' -> check if language code '${now}' is present in translations.tex' + egrep '^[^%]*\\IfEndWith{\\docname}{_'${now}'}' translations.tex > /dev/null + if [ "$?" -gt 0 ] ;then + HINT=' edit '${TEMP_DIR}'/translations.tex -- no representation of template_code '${now} + echo ' [warning] '${HINT} + FEEDBACK=${FEEDBACK}' # '${HINT}'\n' + fi + echo \ \ ${OK} + done + + + for doc in ${DOC_TYPE_FTEX} ; do + create_file ln ./letter.tex ./${doc}.tex + for now in ${LANGS} ; do + create_file ln ./letter.tex ./${doc}_${now}.tex + done + done + + create_file ln ./sample_head.pdf ./letter_head.pdf + create_file ln ./sample.lco ./letter.lco + +fi + + + +if [ "${MODUL}" = "lp" ] ; then + + for now in ${FILE_LIST_LP} ; do + create_file cp ../lp/${now} ${now} + done + +fi + +echo +echo +echo -en ' '${FEEDBACK} +echo -e ' ################################' +echo +echo ' If there are warnings listed in the feedback box above' +echo ' this is totally ok if you know what you do' +echo +echo ' done -> enjoy' +echo ' ### please check "settings" in '`pwd`'letter.lco ' + + +# company +# address +# co_ustid +# email +# taxnumber +# tel +# fax diff --git a/templates/f-tex/translations.tex b/templates/f-tex/translations.tex new file mode 100644 index 000000000..aebdd394b --- /dev/null +++ b/templates/f-tex/translations.tex @@ -0,0 +1,198 @@ +% ---------------------------------------------------------- +% translations.tex +% Zentrale Uebersetzungsdatei f-tex +% +% Changelog: see gitlog + \newcommand{\ftTranslationsVersion}{1.0-u (16.11.2011)} +% +% Lizenz +% http://www.gnu.de/licenses/gpl-3.0.html +% +% Siehe ./README +% +% Autor: Wulf Coulmann scripts_at_gpl.coulmann.de +% +% +% ---------------------------------------------------------- + + +\begingroup + \makeatletter + \@latex@warning@no@line{ #### this is translations.tex \ftTranslationsVersion #####} +\endgroup + + +%%%%% Anleitung zum zufuegen neuer Sprachen %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Am Beispiel Franzoesisch (fr) % +% - Es wird empfohlen die Datei translations.tex im Vorlagenordner % +% und _nicht_ in [lxo-home]/templates/f-tex zu aendern. % +% - Kopiere den Block % +% "\newcommand{\LoadDE}{" % +% bis zur schliessenden Klammer % +% "}" % +% und fuege ihn am Ende der Datei bei % +% "codeblock mit neuer Sprache hier einfuegen" % +% an % +% - uebersetze die deutschen Begriffe im neu eingefuegten Block in % +% die neue Sprache % +% - aendere den Kommandonamen entsprechend der Neuen Sprache % +% "\newcommand{\LoadFR} % +% - fuege am Ende der Datei eine neue Zeile mit dem neuen Sprachkuerzel % +% und dem neuen Funktionsnamen an. % +% "\IfEndWith{\docname}{_fr}{\loadFR}{} % +% - pruefe, ob lxo bereits ueber eine Konfiguration zu der neuen Sprache % +% verfuegt. Das Feld Vorlagenkuerzel muss den zur hier zugefuegten Sprache % +% passenden Wert enthalten (in unserem Beispiel "fr") % +% - rufe das script [lxo-home]/templates/f-tex/setup.sh erneut auf, um % +% sicherzustellen, dass die benoetigten Symlinks vorhanden sind. % +% - schicke die neue Version dieser Datei an % +% scripts_at_gpl.coulmann.de % +% damit in Zukunft die neue Sprache auch anderen Nutzern % +% von lxo zur Verfuegung steht % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + +% ===== de =========== +\newcommand{\loadDE}{ + + \renewcommand{\TitleInv}{Rechnung} + \newcommand{\TitleProforma}{Proformarechnung} + \newcommand{\TitleCreditNote}{Gutschrift} + \newcommand{\TitleSalesOrder}{Auftragsbestätigung} + \newcommand{\TitleSalesQuotation}{Angebot} + \newcommand{\TitleDelorder}{Lieferschein} + \newcommand{\TitlePicklist}{Sammelliste} + \newcommand{\TitlePurchaseOrder}{Bestellung} + \newcommand{\DelorderNumber}{Lieferscheinnummer} + \newcommand{\DeliveryAddress}{Lieferadresse} + \newcommand{\InvNumber}{Rechnungsnummer} + \newcommand{\CredNumber}{Gutschriftnummer} + \newcommand{\OrderNumber}{Auftragsnummer} + \newcommand{\RequestOrderNumber}{Bestellauftragsnummer} + \newcommand{\QuotationNumber}{Angebotsnummer} + \newcommand{\CustomerID}{Kundennummer} + \newcommand{\VendorID}{Lieferantennummer} + \newcommand{\DelDate}{Lieferdatum} + \newcommand{\ReqByTitle}{Lieferung bis} + \newcommand{\ValidUntil}{gültig bis} + \newcommand{\Date}{Datum} + \newcommand{\Pos}{Pos} + \newcommand{\Number}{Best Nr.} + \newcommand{\ItemNo}{Artikel} + \newcommand{\Count}{Anz} + \newcommand{\Unit}{Einh} + \newcommand{\Storage}{Lagerplatz} + \newcommand{\Take}{entnommen} + \newcommand{\Fee}{Einzelp} + \newcommand{\Total}{Total} + \newcommand{\Sum}{Gesamtbetrag} + \newcommand{\EbT}{Summe vor Steuern} + \newcommand{\Left}{Restbetrag} + \newcommand{\AlreadyPayed}{bereits gezahlt am} + \newcommand{\TabSubTotal}{Zwischensumme} + \newcommand{\TabCarry}{Übertrag} + \newcommand{\Dis}{Rab} + \newcommand{\TaxInc}{bereits enthalten: } + \newcommand{\PriceInclTax}{Alle Preise incl. Mehrwertsteuer} + \newcommand{\UstidTitle}{Ihre Umsatzsteueridentnummer:} + + + % Zahlungshinweise + \newcommand{\paymenthints}{ + + \IfSubStr{\docname}{Angebot}{ + Das Angebot hat 4 Wochen Gültigkeit.\\ + }{} + } + + \newcommand{\YourOrder}{ + \ifthenelse{\equal{\cusordnumber}{\leer}} + {} + {Ihre Bestellung {\bf\cusordnumber}}\\[0.5em] + } + +} + +% ===== uk oder en =========== +\newcommand{\loadUK}{ + + \renewcommand{\TitleInv}{Invoice} + \newcommand{\TitleProforma}{Pro Forma Invoice} + \newcommand{\TitleCreditNote}{Credit Note} + \newcommand{\TitleSalesOrder}{Sales Order} + \newcommand{\TitleSalesQuotation}{Sales Quotation} + \newcommand{\DelorderNumber}{delivery note no} + \newcommand{\DeliveryAddress}{delivery address} + \newcommand{\TitleDelorder}{Delivery Note} + \newcommand{\TitlePicklist}{Pick List} + \newcommand{\TitlePurchaseOrder}{Purchase Order} + \newcommand{\InvNumber}{invoice number} + \newcommand{\CredNumber}{credit number} + \newcommand{\OrderNumber}{order number} + \newcommand{\RequestOrderNumber}{purchase order no.} + \newcommand{\QuotationNumber}{quotation no} + \newcommand{\CustomerID}{customer id} + \newcommand{\VendorID}{vendor id} + \newcommand{\DelDate}{date of delivery} + \newcommand{\ReqByTitle}{required by} + \newcommand{\ValidUntil}{valid until} + \newcommand{\Date}{date} + \newcommand{\Pos}{pos} + \newcommand{\Number}{item id} + \newcommand{\ItemNo}{item} + \newcommand{\Count}{count} + \newcommand{\Unit}{unit} + \newcommand{\Storage}{location} + \newcommand{\Take}{taken} + \newcommand{\Fee}{fee} + \newcommand{\Total}{total} + \newcommand{\Sum}{total amount} + \newcommand{\EbT}{total without taxes} + \newcommand{\Left}{residue} + \newcommand{\AlreadyPayed}{already payed at} + \newcommand{\TabSubTotal}{subtotal} + \newcommand{\TabCarry}{carry} + \newcommand{\Dis}{dis} + \newcommand{\TaxInc}{already included: } + \newcommand{\PriceInclTax}{Prices incl. tax} + \newcommand{\UstidTitle}{Your VAT number:} + + % Zahlungshinweise Rechnung + \newcommand{\paymenthints}{ + \IfSubStr{\docname}{Angebot}{ + The offer is valid for 4 weeks.\\ + }{} + } + + \newcommand{\YourOrder}{ + \ifthenelse{\equal{\cusordnumber}{\leer}} + {} + {Your Order Number {\bf\cusordnumber}}\\[0.5em] + } + +} + +% ====== neuen Sprache ================================ + + % codeblock mit neuer Sprache hier einfuegen + + +% ====== Ende Sprachblock ========= +\newcommand{\checkVal}{unknowen} +\newcommand{\TitleInv}{\checkVal} + + +\IfEndWith{\docname}{_de}{\loadDE}{} +\IfEndWith{\docname}{_uk}{\loadUK}{} +\IfEndWith{\docname}{_en}{\loadUK}{} +% neue Zeile mit dem neuen Sprachkuerzel und dem neuen Funktionsnamen hier anfuegen + + + +% ====== unterhalb dieser Zeile nichts aendern ========================== + +% defaultsprache + \ifthenelse{\equal{\TitleInv}{\checkVal}}{\loadDE}{} + diff --git a/templates/f-tex/xstring.sty b/templates/f-tex/xstring.sty new file mode 100644 index 000000000..cf55c27b5 --- /dev/null +++ b/templates/f-tex/xstring.sty @@ -0,0 +1,704 @@ +% __________________________________________________ +% | | +% | | +% | xstring v1.0 | +% | | +% | July, 4th 2008 | +% | | +% |__________________________________________________| +% +% This is xtring.sty +% +% Christian Tellechea 2008 +% email : unbonpetit@gmail.com +% ------------------------------------------------------------------- +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% +% http://www.latex-project.org/lppl.txt +% +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% ------------------------------------------------------------------- +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Christian Tellechea +% +% This work consists of the files +% xstring.sty (this file) +% readme.txt +% xstring_doc_fr.tex, xstring_doc_fr.pdf (manual in french) +% xstring_doc_en.tex, xstring_doc_en.pdf (manual in english) +% xstring_test.tex, xstring_test.pdf (test file) +% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{xstring}[2008/07/04 v1.0 Extended macros for strings. C Tellechea] + +% Messages pour situations particulières +\newcommand\@xs@BadNumArg {\PackageInfo{xstring}{numerical argument out of range}} +\newcommand\@xs@ArgNotFound {\PackageInfo{xstring}{substring not found in string}} +\newcommand\@xs@ArgEmpty {\PackageInfo{xstring}{empty argument}} + +% Ouvre un groupe où les catcodes sont à 12 et à 10 pour les espaces +% ensuite, appelle \@xs@ReadVerb qui lit un argument entre délimiteurs verb +\newcommand\@xs@MakeVerb{% lit 1 argument et le transforme en verb + \begingroup% groupe où les catcodes sont à 12 pour la lecture suivante + \let\do\@makeother + \dospecials% on entre dans le mode verb + \obeyspaces% et on tient compte des espaces + \@xs@ReadVerb}% et on va lire l'argument + +% Définit \@xs@ReadVerb qui lit un argument entre délimiteurs verb +\newcommand\setverbdelim[1]{% définit quel est le délimiteur de verb + \@xs@StrLen{#1}[\@len@verbdelim]% + \ifnum\@len@verbdelim=\@ne + \else + \PackageWarning{xstring}{verb delimiter is not a single char}% + \fi + \def\@xs@ReadVerb##1#1##2#1{% lit ##2 qui est entre les délimiteurs de verb + \endgroup% on ferme le groupe + \@xs@afterreadverb{##2}}}% on appelle l'exécution de fin + +% Assigne l'argument entre délimiteur verb dans la sc #1 +\newcommand\verbtocs[1]{% + \def\@xs@afterreadverb##1{\edef#1{##1}}% + \@xs@MakeVerb} + +% A l'aide d'un pont d'\expandafter, développe d'un niveau toutes +% les sc de #1 puis et assigne le résultat à \result +\def\@xs@expandallonelevel#1#2\@nil{% + \expandafter\expandafter\expandafter\def% plein d'expandafter + \expandafter\expandafter\expandafter\result% pour développer #1 d'un niveau + \expandafter\expandafter\expandafter{\expandafter\result#1}% et l'ajouter à \result + \ifx\@empty#2\@empty\else\@xs@expandallonelevel#2\@nil\fi}% s'il reste des sc, on boucle + +% \scancs développe #3 autant de fois que spécifié en #1 +% puis le développement obtenu est verbatimisé. +% On utilise \@xs@expandalltodepth autant de fois que #1 le spécifie +% puis on invoque \detokenize à la fin +\newcount\depth@scancs +\newcommand\scancs{% + \@ifstar% + {\PackageWarning{xstring}{if third argument or its expansion have braces or spaces, they will be removed when scanned! Use starred \string\scancs* macro with care}% + \def\@testornot{\@notestcs}% + \@xs@scancs}% + {\def\@testornot{\@testcs}% + \@xs@scancs}} +\newcommand\@xs@scancs[3][1]{% +% #1 : profondeur à développer avant de verbatimiser +% #2 : nom de la sc recevant la chaine verb +% #3 : nom de la sc à développer et à transformer en verb + \depth@scancs\z@ + \def\@notestcs##1\@nil{\relax}% + \def\@testcs##1##2\@nil{% + \ifx\@empty##2\@empty + \else% si la séquence de contrôle n'est pas seule, on gueule + \PackageError{xstring}{third argument or its expansion is not a single control sequence! Use \string\scancs* instead of \string\scancs (see manual).}% + \fi}% + \def\@xs@expandalltodepth##1\@nil{% développe de #1 niveaux toutes les sc de #3 et l'assigne à \the@result + \def\result{}% + \ifnum\depth@scancs<#1% tant que la profondeur de développement n'est pas atteinte + \@testornot##1\@nil% on teste éventuellement si le développement comporte 1 seule sc + \expandafter\@xs@expandallonelevel\the@result\@nil% on développe tout d'un niveau + \expandafter\def\expandafter\the@result\expandafter{\result}% + \advance\depth@scancs\@ne + \expandafter\@xs@expandalltodepth\the@result\@nil% et on recommence + \fi}% + \def\the@result{#3}% + \@xs@expandalltodepth#3\@nil + \expandafter\def\expandafter#2\expandafter{\detokenize\expandafter{\the@result}}} + +% Cette macro développe #2 au maximum (ce qui doit donner du texte), +% puis le transforme en token et l'assigne à #1 +% On ouvre un groupe dans lequel un \@nil est inséré à la fin du fichier virtuel +% lu avec \scantokens. Ce \@nil sert à l'argument délimité de \@AssignResult +\newcommand\tokenize[2]{% + \begingroup + \expandafter\@xs@def\expandafter\the@text\expandafter{#2}% on développe en accord avec \fullexpandarg ou \noexpandarg + \def\@AssignResult##1\@nil{\def#1{##1}}% on assigne en tenant compte du \@nil qui vient de la fin du fichier virtuel + \everyeof{\@nil}% met un \@nil à la fin du fichier virtuel + \endlinechar\m@ne + \expandafter\expandafter\expandafter\endgroup% on retarde la fermeture du groupe + \expandafter\@AssignResult\scantokens\expandafter{\the@text}}% pout faire l'assignation + +% Macro très simple qui assigne ou affiche le résultat, selon la présence +% ou non de #2 qui est l'argument optionnel venant en dernière position des macros +\newcommand\@xs@ReturnResult[2]{% + \expandafter\ifx\expandafter\@empty\detokenize{#2}\@empty% pas de nom ? + #1% on affiche #1 + \else% il y a un nom donc + \edef#2{#1}% on met #1 dans #3 avec edef + \fi} + +% Pas d'expansion des arguments +\newcommand\normalexpandarg{% + \let\@xs@def\def% on définit\@call avec \def + \let\@xs@expand\@empty}% et on neutralise \@xs@expand + +% Expansion des arguments +\newcommand\fullexpandarg{% + \let\@xs@def\edef% on définit\@call avec \edef + \let\@xs@expand\noexpand}% et on utilise \noexpand + +% Cette macro interne enlève le 1er caractère de la chaine passée en argument +\def\@xs@RemoveFirst#1[#2]{% + \ifx\@empty#1\@empty + \edef#2{}% + \else + \@xs@IfBeginWith{#1}{ }% + {\@xs@StrBehind[1]{#1}{ }[#2]}% + {\def\@xs@RemoveFirst@ii##1##2\@nil{\edef#2{##2}}% + \@xs@RemoveFirst@ii#1\@nil}% + \fi} + +% Cette macro interne renvoie le 1er caractère de la chaine passée en argument +\def\@xs@ReturnFirst#1[#2]{% + \ifx\@empty#1\@empty% + \edef#2{}% + \else + \@xs@IfBeginWith{#1}{ }% + {\edef#2{ }}% + {\def\@xs@ReturnFirst@ii##1##2\@nil{\edef#2{##1}}% + \@xs@ReturnFirst@ii#1\@nil}% + \fi} + +% Cette macro interne est utilisée dans les macros étoilées pour : +% 1) développer l'argument selon qu'on a choisit \fullexpandarg +% ou \normalexpandarg, et ceci à l'aide de la macro \@xs@def +% 2) Ensuite, on détokenize ce développement de façon n'avoir plus que +% des catcodes de 10 pour les espaces et 12 pour le reste. +\newcommand\@xs@expand@and@detokenize[2]{% + \@xs@def#1{#2}% on développe #2 selon \fullexpandarg ou \normalexpandarg + \edef#1{\detokenize\expandafter{#1}}}% puis on détokenize et on assigne à #1 + +% Cette macro teste si une chaine (#2) en contient au moins n(#1) fois une autre (#3) +% Pour cela, on teste "ce qu'il reste" après #2. On construit une récursivité sur le +% compteur d'occurences \Occurrence@IfSubStr. Si "ce qu'il reste" est vide avant d'atteindre +% l'occurence voulue, le test est négatif, sinon on poursuit par récursivité sur "ce qu'il reste" +% jusqu'à l'occurrence voulue. Si l'on atteint l'occurrence voulue, le test est positif. +% On utilise la séquence de contrôle non définie \@delimit pour éviter un effet +% indésirable qui ferait que \IfSubStr{a}{aa}{V}{F} renverrait V +\newcommand\IfSubStr{\@ifstar\@xs@IfSubStr@@\@xs@IfSubStr@}% +\newcommand\@xs@IfSubStr@@[3][1]{% + \@xs@expand@and@detokenize{\xsarg@a}{#2}% + \@xs@expand@and@detokenize{\xsarg@b}{#3}% + \edef\@call{\noexpand\@xs@IfSubStr[\@xs@expand#1]{\xsarg@a}{\xsarg@b}}% + \@call} +\newcommand\@xs@IfSubStr@[3][1]{% + \@xs@def\@call{\@xs@expand\@xs@IfSubStr[#1]{#2}{#3}}% + \@call} +\newcount\Occurrence@IfSubStr +\def\@xs@IfSubStr[#1]#2#3{% +% est ce que la chaine #2 contient au moins #1 fois la sous chaine #3 ? + \ifnum#1<\@ne% on gère les cas spéciaux + \def\@xsresult@IfSubStr{\expandafter\@secondoftwo}% #1<1 -> on exécute #5 + \else + \ifx\@empty#3\@empty% + \def\@xsresult@IfSubStr{\expandafter\@secondoftwo}% si #3 est vide -> on écécute #5 + \else + \Occurrence@IfSubStr\z@ + \def\@xs@IfSubStr@i##1#3##2\@nil{% + \advance\Occurrence@IfSubStr\@ne + \ifx\@empty##2\@empty%% qu'y a t-il apès la sous chaine ? + \def\@xsresult@IfSubStr{\expandafter\@secondoftwo}% rien -> on exécute #5 + \else% si ce qu'il est reste n'est pas vide + \ifnum\Occurrence@IfSubStr<#1% tant que le nombre d'occurrence n'est pas atteint + \@xs@IfSubStr@i##2\@nil% on recommence + \else + \def\@xsresult@IfSubStr{\expandafter\@firstoftwo}% nombre d'occurrences atteint : on renvoie #4 + \fi + \fi}% + \@xs@IfSubStr@i#2\@delimit#3\@nil% \@delimit pour éviter le cas de \IfSubStr{a}{aa}{V}{F} qui renverrait V + \fi + \fi + \@xsresult@IfSubStr} + +\newcommand\IfBeginWith{\@ifstar\@xs@IfBeginWith@@\@xs@IfBeginWith@}% +\newcommand\@xs@IfBeginWith@@[2]{% + \@xs@expand@and@detokenize{\xsarg@a}{#1}% + \@xs@expand@and@detokenize{\xsarg@b}{#2}% + \edef\@call{\noexpand\@xs@IfBeginWith{\xsarg@a}{\xsarg@b}} + \@call} +\newcommand\@xs@IfBeginWith@[2]{% + \@xs@def\@call{\@xs@expand\@xs@IfBeginWith{#1}{#2}}% + \@call} +\newcommand\@xs@IfBeginWith[2]{% + \@xs@IfSubStr[1]{#1}{#2}% + {\ifx\@empty#2\@empty% + \def\@xs@IfBeginWith@i##1\@nil{\expandafter\@firstoftwo}% si #2 est vide, on renvoie vrai + \else + \def\@xs@IfBeginWith@i##1#2##2\@nil{% qu'y a t-il avant #2 ? + \ifx\@empty##1\@empty + \expandafter\@firstoftwo% rien, donc #2 est au début, on renvoie vrai + \else + \expandafter\@secondoftwo + \fi}% + \fi}% + {\def\@xs@IfBeginWith@i##1\@nil{\expandafter\@secondoftwo}}% si #2 n'est pas dans #1, on renvoie faux + \@xs@IfBeginWith@i#1\@delimit#2\@nil} + +\newcommand\IfEndWith{\@ifstar\@xs@IfEndWith@@\@xs@IfEndWith@}% +\newcommand\@xs@IfEndWith@@[2]{% + \@xs@expand@and@detokenize{\xsarg@a}{#1}% + \@xs@expand@and@detokenize{\xsarg@b}{#2}% + \edef\@call{\noexpand\@xs@IfEndWith{\xsarg@a}{\xsarg@b}} + \@call} +\newcommand\@xs@IfEndWith@[2]{% + \@xs@def\@call{\@xs@expand\@xs@IfEndWith{#1}{#2}}% + \@call} +\newcommand*\@xs@IfEndWith[2]{% +% Est ce que la chaine #1 finit par la chaine #2 ? + \@xs@IfSubStr[1]{#1}{#2}% + {\ifx\@empty#2\@empty% si #2 est vide -> test vrai + \def\@xs@remove@begining##1\@nil{\expandafter\@firstoftwo}% + \else + \def\@xs@remove@begining##1#2##2\@nil{% on isole ce qui est après #2, la chaine restante ##2 + \@xs@IfSubStr[1]{##2}{#2}% tant que #2 est dans la chaine restante.. + {\@xs@remove@begining##2\@nil}% ...on recommence + {\ifx\@empty##2\@empty% sinon, on regarde ce qui reste + \expandafter\@firstoftwo% rien -> test vrai + \else + \expandafter\@secondoftwo% quelque chose -> test faux + \fi + }% + }% + \fi}% + {\def\@xs@remove@begining##1\@nil{\expandafter\@secondoftwo}}% si #2 n'est pas dans #1 -> test faux + \@xs@remove@begining#2#1\@nil} + +\newcount\Occurrence@StrBefore +% Renvoie ce qui est à gauche de l'occurence n°#1 de la sous chaine #3 dans la chaine #2 +\newcommand\StrBefore{\@ifstar\@xs@StrBefore@@\@xs@StrBefore@} +\newcommand\@xs@StrBefore@@[3][1]{% + \@xs@expand@and@detokenize{\xsarg@a}{#2}% + \@xs@expand@and@detokenize{\xsarg@b}{#3}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrBefore[\@xs@expand#1]{\xsarg@a}{\xsarg@b}}{}}% + \@call} +\newcommand\@xs@StrBefore@[3][1]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrBefore[#1]{#2}{#3}}{}}% + \@call} +\def\@xs@StrBefore[#1]#2#3[#4]{% + \ifx\@empty#3\@empty% + \@xs@ArgNotFound% warning + \edef\@xs@result@StrBefore{}% + \else + \edef\@xs@result@StrBefore{}% resultat nul pour l'instant + \Occurrence@StrBefore\z@ + \def\@xs@StrBefore@i##1#3##2\@nil{% + \advance\Occurrence@StrBefore\@ne% on incrémente + \ifx\@empty##2\@empty% pas trouvé ? + \@xs@ArgNotFound% warning + \edef\@xs@result@StrBefore{}% renvoie vide + \else + \ifnum\Occurrence@StrBefore<#1% tant que c'est pas la bonne occurrence + \edef\@xs@result@StrBefore{\@xs@result@StrBefore##1#3}% on ajoute le début au résultat final + \@xs@StrBefore@i##2\@nil% on recommence avec la chaine restante + \else + \edef\@xs@result@StrBefore{\@xs@result@StrBefore##1}% on n'ajoute pas la chaine frontière #3 la dernière fois ! + \fi + \fi}% + \@xs@StrBefore@i#2\@delimit#3\@nil% + \fi + \@xs@ReturnResult{\@xs@result@StrBefore}{#4}} + +\newcount\Occurrence@StrBehind +% Renvoie ce qui est à droite de l'occurence n°#1 de la sous chaine #3 dans la chaine #2 +\newcommand\StrBehind{\@ifstar\@xs@StrBehind@@\@xs@StrBehind@} +\newcommand\@xs@StrBehind@@[3][1]{% + \@xs@expand@and@detokenize{\xsarg@a}{#2}% + \@xs@expand@and@detokenize{\xsarg@b}{#3}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrBehind[\@xs@expand#1]{\xsarg@a}{\xsarg@b}}{}}% + \@call} +\newcommand\@xs@StrBehind@[3][1]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrBehind[#1]{#2}{#3}}{}}% + \@call} +\def\@xs@StrBehind[#1]#2#3[#4]{% + \ifx\@empty#3\@empty% + \@xs@ArgNotFound% warning + \edef\@xs@result@StrBehind{}% + \else + \Occurrence@StrBehind\z@ + \def\@xs@StrBehind@i##1#3##2\@nil{% + \advance\Occurrence@StrBehind\@ne% on incrémente + \ifnum\Occurrence@StrBehind<#1% tant que c'est pas la bonne occurrence + \@xs@IfSubStr[1]{##2}{#3}% tant que la chaine restante contient #3 + {\@xs@StrBehind@i##2\@nil}% on recommence avec la chaine restante + {\@xs@ArgNotFound% sinon, info + \edef\@xs@result@StrBehind{}}% et on renvoie vide + \else + \edef\@xs@result@StrBehind{##2}% on renvoie la chaine restante + \fi}% + \@xs@IfSubStr[1]{#2}{#3}% + {\@xs@StrBehind@i#2\@nil}% + {\@xs@ArgNotFound% warning + \edef\@xs@result@StrBehind{}}% + \fi + \@xs@ReturnResult{\@xs@result@StrBehind}{#4}} + +\newcommand\IfSubStrBefore{\@ifstar\@xs@IfSubStrBefore@@\@xs@IfSubStrBefore@} +% est ce que l'occurrence #1 de la sous chaine #4 se trouve avant +% l'occurrence n°#2 de la sous chaine #5 dans la chaine #3? +\newcommand\@xs@IfSubStrBefore@@[4][1,1]{% + \@xs@expand@and@detokenize{\xsarg@a}{#2}% + \@xs@expand@and@detokenize{\xsarg@b}{#3}% + \@xs@expand@and@detokenize{\xsarg@c}{#4}% + \edef\@call{\noexpand\@xs@IfSubStrBefore[\@xs@expand#1]{\xsarg@a}{\xsarg@b}{\xsarg@c}}% + \@call} +\newcommand\@xs@IfSubStrBefore@[4][1,1]{% + \@xs@def\@call{\@xs@expand\@xs@IfSubStrBefore[#1]{#2}{#3}{#4}}% + \@call} +\def\@xs@IfSubStrBefore[#1,#2]#3#4#5{% + \@xs@StrPosition[#2]{#3}{#5}[\@xs@posMax@IfSubStrBefore]% on trouve les positions + \@xs@StrPosition[#1]{#3}{#4}[\@xs@posPattern@IfSubStrBefore]% + \ifnum\@xs@posMax@IfSubStrBefore<\@ne% + \def\@xs@result@IfSubStrBefore{\expandafter\@secondoftwo}% si pas trouvé #5 : 0 renvoie faux + \else + \ifnum\@xs@posPattern@IfSubStrBefore<\@ne% + \def\@xs@result@IfSubStrBefore{\expandafter\@secondoftwo}% si pas trouvé #4 : 0 renvoie faux + \else + \ifnum\@xs@posPattern@IfSubStrBefore<\@xs@posMax@IfSubStrBefore% + \def\@xs@result@IfSubStrBefore{\expandafter\@firstoftwo}% + \else + \def\@xs@result@IfSubStrBefore{\expandafter\@secondoftwo}% + \fi + \fi + \fi + \@xs@result@IfSubStrBefore} + +% Est ce que l'occurrence #1 de la sous chaine #4 se trouve avant +% l'occurrence n°#2 de la sous chaine #5 dans la chaine #3? +\newcommand\IfSubStrBehind{\@ifstar\@xs@IfSubStrBehind@@\@xs@IfSubStrBehind@} +\newcommand\@xs@IfSubStrBehind@@[4][1,1]{% + \@xs@expand@and@detokenize{\xsarg@a}{#2}% + \@xs@expand@and@detokenize{\xsarg@b}{#3}% + \@xs@expand@and@detokenize{\xsarg@c}{#4}% + \edef\@call{\noexpand\@xs@IfSubStrBehind[\@xs@expand#1]{\xsarg@a}{\xsarg@b}{\xsarg@c}}% + \@call} +\newcommand\@xs@IfSubStrBehind@[4][1,1]{% + \@xs@def\@call{\@xs@expand\@xs@IfSubStrBehind[#1]{#2}{#3}{#4}}% + \@call} +\def\@xs@IfSubStrBehind[#1,#2]#3#4#5{% + \@xs@StrPosition[#2]{#3}{#5}[\@xs@posMax@IfSubStrBehind]% on trouve les positions + \@xs@StrPosition[#1]{#3}{#4}[\@xs@posPattern@IfSubStrBehind]% + \ifnum\@xs@posMax@IfSubStrBehind<1\relax% + \def\@xs@result@IfSubStrBehind{\expandafter\@secondoftwo}% si pas trouvé : 0 renvoie faux + \else + \ifnum\@xs@posPattern@IfSubStrBehind<1% + \def\@xs@result@IfSubStrBehind{\expandafter\@secondoftwo}% si pas trouvé : 0 renvoie faux + \else + \ifnum\@xs@posPattern@IfSubStrBehind>\@xs@posMax@IfSubStrBehind% + \def\@xs@result@IfSubStrBehind{\expandafter\@firstoftwo}% + \else + \def\@xs@result@IfSubStrBehind{\expandafter\@secondoftwo}% + \fi + \fi + \fi + \@xs@result@IfSubStrBehind} + +\newcount\Gobble@StrBetween +% Renvoie ce qui est strictement compris entre les occurrences n°#1 et n°#2 +% des chaines #4 et #5 dans la chaine #3 +\newcommand\StrBetween{\@ifstar\@xs@StrBetween@@\@xs@StrBetween@} +\newcommand\@xs@StrBetween@@[4][1,1]{% + \@xs@expand@and@detokenize{\xsarg@a}{#2}% + \@xs@expand@and@detokenize{\xsarg@b}{#3}% + \@xs@expand@and@detokenize{\xsarg@c}{#4}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrBetween[\@xs@expand#1]{\xsarg@a}{\xsarg@b}{\xsarg@c}}{}}% + \@call} +\newcommand\@xs@StrBetween@[4][1,1]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrBetween[#1]{#2}{#3}{#4}}{}}% + \@call} +\def\@xs@StrBetween[#1,#2]#3#4#5[#6]{% + \ifx\@empty#5\@empty% + \edef\@xs@StringBefore@StrBetween{}% + \else + \@xs@StrBefore[#2]{#3}{#5}[\@xs@StringBefore@StrBetween]% on extrait ce qui est à gauche de l'occurrence de #5 + \@xs@StrPosition[#1]{#3}{#4}[\@xs@Pos@StrBetween]% position de l'occurrence de #3 + \Gobble@StrBetween\@xs@Pos@StrBetween% + \@xs@StrLen{#4}[\@xs@Pos@StrBetween]% + \advance\Gobble@StrBetween\@xs@Pos@StrBetween% on lui ajoute la longueur de #3 + \advance\Gobble@StrBetween\m@ne% et on enlève 1 + \expandafter\expandafter\expandafter\@xs@StrGobbleLeft% + \expandafter\expandafter\expandafter{\expandafter\@xs@StringBefore@StrBetween\expandafter}% + \expandafter{\Gobble@StrBetween}[\@xs@result@StrBetween]% pour manger ce nombre de caractère au début de \@xs@StringBefore@StrBetween + \fi + \@xs@ReturnResult{\@xs@result@StrBetween}{#6}} + +\newcount\Occurrence@StrSubstitute +% Remplace les #1 premières occurences de la chaine #3 +% par la chaine #4 dans la chaine #2 +\newcommand\StrSubstitute{\@ifstar\@xs@StrSubstitute@@\@xs@StrSubstitute@} +\newcommand\@xs@StrSubstitute@@[4][0]{% + \@xs@expand@and@detokenize{\xsarg@a}{#2}% + \@xs@expand@and@detokenize{\xsarg@b}{#3}% + \@xs@expand@and@detokenize{\xsarg@c}{#4}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrSubstitute[\@xs@expand#1]{\xsarg@a}{\xsarg@b}{\xsarg@c}}{}}% + \@call} +\newcommand\@xs@StrSubstitute@[4][0]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrSubstitute[#1]{#2}{#3}{#4}}{}}% + \@call} +\def\@xs@StrSubstitute[#1]#2#3#4[#5]{% + \Occurrence@StrSubstitute\z@ + \ifx\@empty#3\@empty% si #3 est vide, on ne fait rien + \@xs@ArgEmpty% warning + \edef\@result@StrSubstitute{#2}% + \else + \edef\@result@StrSubstitute{}% on initialise à vide, histoire d'enlever le statut undefined + \def\@xs@StrSubstitute@i##1#3##2\@nil{% + \edef\@result@StrSubstitute{\@result@StrSubstitute##1#4}% on recopie jusqu'à la 1ere occurrence, et on remplace #3 par #4 + \ifnum#1>\z@% si on compte les occurrences + \advance\Occurrence@StrSubstitute\@ne% on incrémente le compteur + \@xs@IfSubStr[1]{##2}{#3}% tant que la chaine restante contient #3 + {\ifnum\Occurrence@StrSubstitute<#1% tant qu'on n'a pas atteint la bonne occurrence, + \@xs@StrSubstitute@i##2\@nil% on recommence + \else + \edef\@result@StrSubstitute{\@result@StrSubstitute##2}% l'occurrence est atteinte : on rajoute ce qui reste + \fi}% + {\edef\@result@StrSubstitute{\@result@StrSubstitute##2}}% si on ne peut plus substituter, on rajoute ce qui reste + \else% ici , on ne compte pas les occurrences, donc... + \@xs@IfSubStr[1]{##2}{#3}% ...tant que la chaine restante contient #3 + {\@xs@StrSubstitute@i##2\@nil}% on recommence + {\edef\@result@StrSubstitute{\@result@StrSubstitute##2}}% si on ne peut plus substituter, on rajoute ce qui reste + \fi}% + \@xs@IfSubStr[1]{#2}{#3}% + {\@xs@StrSubstitute@i#2\@nil}% si #2 contient #3, on exécute la macro + {\edef\@result@StrSubstitute{#2}}% sinon, on renvoie la chaine #2 + \fi + \@xs@ReturnResult{\@result@StrSubstitute}{#5}} + +% Supprime les #1 premières occurrences de #3 dans #2 +\newcommand\StrDel{\@ifstar\@xs@StrDel@@\@xs@StrDel@} +\newcommand\@xs@StrDel@@[3][0]{% + \@xs@expand@and@detokenize{\xsarg@a}{#2}% + \@xs@expand@and@detokenize{\xsarg@b}{#3}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrSubstitute[\@xs@expand#1]{\xsarg@a}{\xsarg@b}{}}{}}% + \@call} +\newcommand\@xs@StrDel@[3][0]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrSubstitute[#1]{#2}{#3}{}}{}}% + \@call} + +\newcount\Length@StrLen +% Compte combien de caractères contient la chaine #1 ? +\newcommand\StrLen{\@ifstar\@xs@StrLen@@\@xs@StrLen@} +\newcommand\@xs@StrLen@@[1]{% + \@xs@expand@and@detokenize{\xsarg@a}{#1}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrLen{\xsarg@a}}{}}% + \@call} +\newcommand\@xs@StrLen@[1]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrLen{#1}}{}}% + \@call} +% Macro qui compte le nombre de caractères de son argument #1 +\def\@xs@StrLen@i#1\@nil{% + \ifx\@empty#1\@empty% tant que #1 n'est pas vide ... + \else + \advance\Length@StrLen\@ne% ...on ajoute 1 à la longueur + \@xs@IfBeginWith{#1}{ }% et on recommence après avoir enlevé le 1er caractère (on distingue le cas où c'est un espace) + {\@xs@StrBehind[1]{#1}{ }[\@xs@result@StrLen]% + \expandafter\@xs@StrLen@i\@xs@result@StrLen\@nil}% + {\expandafter\@xs@StrLen@i\@xs@RemoveFirst@StrLen#1\@nil\@nil}% + \fi}% +% Macro qui enlève le 1er caractère de son argument +\def\@xs@RemoveFirst@StrLen#1#2\@nil{#2}% +% Macro principale +\def\@xs@StrLen#1[#2]{% +% Renvoie la longueur de la chaine #1 + \Length@StrLen\z@ + \@xs@StrLen@i#1\@nil% + \expandafter\@xs@ReturnResult\expandafter{\the\Length@StrLen}{#2}} + +\newcount\Position@StrMid +\newcommand\StrMid{\@ifstar\@xs@StrMid@@\@xs@StrMid@} +\newcommand\@xs@StrMid@@[3]{% + \edef\@StrMid@First{\@xs@expand#2}\edef\@StrMid@Last{\@xs@expand#3}% position début et fin + \ifnum#2>#3\@xs@BadNumArg\fi + \@xs@expand@and@detokenize{\xsarg@a}{#1}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrMid{\xsarg@a}}{}}% + \@call} +\newcommand\@xs@StrMid@[3]{% + \edef\@StrMid@First{\@xs@expand#2}\edef\@StrMid@Last{\@xs@expand#3}% position début et fin + \ifnum#2>#3\@xs@BadNumArg\fi + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrMid{#1}}{}}% + \@call} +% cette sous macro supprime le nombre de caractère nécessaires +% à la gauche de son argument, et renvoie le résultat dans \@result@Mid@Gobble +\def\@xs@Mid@Gobble#1\@nil{% enlève #2 caractères à gauche de ##1 + \advance\Position@StrMid\@ne + \ifnum\Position@StrMid=\@StrMid@First% si on a atteint la position + \edef\@result@Mid@Gobble{#1}% on renvoie ce qui reste + \else% sinon + \@xs@RemoveFirst{#1}[\@Mid@remain]% on enlève un caractère + \expandafter\@xs@Mid@Gobble\@Mid@remain\@nil% et on recommence + \fi}% +% cette sous macro prend le nombre de caractères nécessaires +% à la gauche de son argument, et renvoie le résultat dans \@final@Result +\def\@xs@Mid@Concat#1\@nil{% + \@xs@ReturnFirst{#1}[\@Char@to@add]% prend le 1er caractère + \edef\@final@Result{\@final@Result\@Char@to@add}% l'ajoute au résultat final + \@xs@RemoveFirst{#1}[\@remain@StrMid]% puis l'enlève de la chaine + \ifnum\Position@StrMid<\@StrMid@Last% si pas encore fini + \advance\Position@StrMid\@ne% on incrémente et + \expandafter\@xs@Mid@Concat\@remain@StrMid\@nil% on recommence + \fi}% +\def\@xs@StrMid#1[#2]{% +% renvoie la sous chaine de #1 comprise entre les positions \@StrMid@First et \@StrMid@Last + \@xs@StrLen{#1}[\@len@StrMid]% + \ifnum\@StrMid@First>\@StrMid@Last% mauvais ordre ? + \@xs@ReturnResult{}{#2}% on renvoie rien + \else + \ifnum\@StrMid@Last<\@ne% si position fin trop petite + \@xs@ReturnResult{}{#2}% on renvoie rien + \else + \ifnum\@StrMid@First<\@ne% 1ère position trop petite ? + \edef\@StrMid@First{1}% on limite à 1 + \@xs@BadNumArg% avertissement + \fi + \ifnum\@StrMid@Last>\@len@StrMid% dernière position trop grande ? + \edef\@StrMid@Last{\@len@StrMid}% on limite à la longueur de la chaine + \@xs@BadNumArg% avertissement + \fi + \Position@StrMid\z@ + \@xs@Mid@Gobble#1\@nil% on supprime ce qu'il faut à gauche + \edef\@final@Result{}% rien dans le résultat final pour l'instant + \expandafter\@xs@Mid@Concat\@result@Mid@Gobble\@nil% on prend les caractères qu'il faut à gauche + \expandafter\@xs@ReturnResult\expandafter{\@final@Result}{#2}% + \fi + \fi} + +\newcommand\StrGobbleLeft{\@ifstar\@xs@StrGobbleLeft@@\@xs@StrGobbleLeft@} +% supprime #2 caractères à gauche dans la chaine #1 +\newcommand\@xs@StrGobbleLeft@@[2]{% + \@xs@expand@and@detokenize{\xsarg@a}{#1}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrGobbleLeft{\xsarg@a}{\@xs@expand#2}}{}}% + \@call} +\newcommand\@xs@StrGobbleLeft@[2]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrGobbleLeft{#1}{#2}}{}}% + \@call} +\def\@xs@StrGobbleLeft#1#2[#3]{% + \edef\@StrMid@First{\numexpr#2+1}% + \@xs@StrLen{#1}[\@StrMid@Last]% + \@xs@StrMid{#1}[\@xs@result@StrGobbleLeft]% + \@xs@ReturnResult{\@xs@result@StrGobbleLeft}{#3}} + +% extrait de #1 la chaine à gauche de longueur #2 +\newcommand\StrLeft{\@ifstar\@xs@StrLeft@@\@xs@StrLeft@} +\newcommand\@xs@StrLeft@@[2]{% + \@xs@expand@and@detokenize{\xsarg@a}{#1}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrLeft{\xsarg@a}{\@xs@expand#2}}{}}% + \@call} +\newcommand\@xs@StrLeft@[2]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrLeft{#1}{#2}}{}}% + \@call} +\def\@xs@StrLeft#1#2[#3]{% + \edef\@StrMid@First{1}% + \ifnum#2<0\@xs@BadNumArg\fi% avertissement + \edef\@StrMid@Last{#2}% + \@xs@StrMid{#1}[\@xs@result@@StrLeft]% + \@xs@ReturnResult{\@xs@result@@StrLeft}{#3}} + +% supprime #2 caractères à droite dans la chaine #1 +\newcommand\StrGobbleRight{\@ifstar\@xs@StrGobbleRight@@\@xs@StrGobbleRight@} +\newcommand\@xs@StrGobbleRight@@[2]{% + \@xs@expand@and@detokenize{\xsarg@a}{#1}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrGobbleRight{\xsarg@a}{\@xs@expand#2}}{}}% + \@call} +\newcommand\@xs@StrGobbleRight@[2]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrGobbleRight{#1}{#2}}{}}% + \@call} +\def\@xs@StrGobbleRight#1#2[#3]{% + \@xs@StrLen{#1}[\@Result@Length]% + \ifnum#2>\@Result@Length\@xs@BadNumArg\fi% avertissement + \edef\@StrMid@First{1}% + \edef\@StrMid@Last{\numexpr\@Result@Length-#2}% + \@xs@StrMid{#1}[\@xs@result@StrGobbleRight]% + \@xs@ReturnResult{\@xs@result@StrGobbleRight}{#3}} + +% renvoie #2 caractères à la droite de la chaine #1 +\newcommand\StrRight{\@ifstar\@xs@StrRight@@\@xs@StrRight@} +\newcommand\@xs@StrRight@@[2]{% + \@xs@expand@and@detokenize{\xsarg@a}{#1}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrRight{\xsarg@a}{#2}}{}}% + \@call} +\newcommand\@xs@StrRight@[2]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrRight{#1}{#2}}{}}% + \@call} +\def\@xs@StrRight#1#2[#3]{% + \ifnum#2<0\@xs@BadNumArg\fi% avertissement + \@xs@StrLen{#1}[\@StrMid@Last]% + \edef\@StrMid@First{\numexpr\@StrMid@Last+1-#2}% + \@xs@StrMid{#1}[\@xs@result@StrMid]% + \@xs@ReturnResult{\@xs@result@StrMid}{#3}} + +\newcommand\StrChar{\@ifstar\@xs@StrChar@@\@xs@StrChar@} +\newcommand\@xs@StrChar@@[2]{% + \edef\@StrMid@First{\@xs@expand#2}\edef\@StrMid@Last{\@xs@expand#2}% + \@xs@expand@and@detokenize{\xsarg@a}{#1}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrMid{\xsarg@a}}{}}% + \@call} +\newcommand\@xs@StrChar@[2]{% + \edef\@StrMid@First{\@xs@expand#2}\edef\@StrMid@Last{\@xs@expand#2}% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrMid{#1}}{}}% + \@call}% + +\newcount\Occurrence@StrCount +% Combien de fois compte t-on #2 dans #1 ? +\newcommand\StrCount{\@ifstar\@xs@StrCount@@\@xs@StrCount@} +\newcommand\@xs@StrCount@@[2]{% + \@xs@expand@and@detokenize{\xsarg@a}{#1}% + \@xs@expand@and@detokenize{\xsarg@b}{#2}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrCount{\xsarg@a}{\xsarg@b}}{}}% + \@call} +\newcommand\@xs@StrCount@[2]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrCount{#1}{#2}}{}}% + \@call} +\def\@xs@StrCount#1#2[#3]{% + \Occurrence@StrCount\z@% on initialise à 0 + \def\@xs@StrCount@i{% + \advance\Occurrence@StrCount\@ne% occurrence := occurrence +1 + \@xs@StrPosition[\the\Occurrence@StrCount]{#1}{#2}[\@xs@Pos@StrCount]% position de l'occurrence ? + \ifnum\@xs@Pos@StrCount=\z@% si l'occurrence n'est pas trouvée + \advance\Occurrence@StrCount\m@ne% on enlève 1 au compteur + \@xs@ReturnResult{\the\Occurrence@StrCount}{#3}% et on renvoie ce résultat + \else + \@xs@StrCount@i% si l'occurrence est trouvée, on recommence + \fi}% + \@xs@StrCount@i} + +\newcount\Position@StrPosition +% renvoie la position de l'occurrence #1 de la sous chaine #3 dans la chaine #2 +\newcommand\StrPosition{\@ifstar\@xs@StrPosition@@\@xs@StrPosition@} +\newcommand\@xs@StrPosition@@[3][1]{% + \@xs@expand@and@detokenize{\xsarg@a}{#2}% + \@xs@expand@and@detokenize{\xsarg@b}{#3}% + \edef\@call{\noexpand\@testopt{\noexpand\@xs@StrPosition[\@xs@expand#1]{\xsarg@a}{\xsarg@b}}{}}% + \@call} +\newcommand\@xs@StrPosition@[3][1]{% + \@xs@def\@call{\@xs@expand\@testopt{\@xs@expand\@xs@StrPosition[#1]{#2}{#3}}{}}% + \@call} +\def\@xs@StrPosition[#1]#2#3[#4]{% + \Position@StrPosition\z@ + \ifx\@empty#3\@empty% + \else + \@xs@StrBefore[#1]{#2}{#3}[\@xs@result@StrPosition]% on extrait la chaine avant l'occurrence de #3 + \expandafter\@xs@StrLen\expandafter{\@xs@result@StrPosition}[\@xs@len@StrPosition]% + \Position@StrPosition\@xs@len@StrPosition% + \advance\Position@StrPosition\@ne% \@xs@len@StrPosition+1 est le résultat à priori... + \ifnum\@xs@len@StrPosition=\z@% ... mais si la position vaut 0, soit #3 est au début de #2, soit #3 n'est pas trouvé. On lève le doute ci dessous + \Position@StrPosition\z@% on considère que l'occurrence de #3 n'est pas trouvée, mais... + \ifnum#1=\@ne% si on teste la 1ère occurrence + \@xs@IfBeginWith{#2}{#3}% et que le #2 commence par #3, + {\Position@StrPosition\@ne}% c'est le seul cas où on renvoie 1 + {}% + \fi + \fi + \fi + \expandafter\@xs@ReturnResult\expandafter{\the\Position@StrPosition}{#4}} + +% Définit le délimiteur verb et le développement des arguments par défaut +\AtBeginDocument{\setverbdelim{|}\fullexpandarg} +\endinput +% +% Historique : +% +% 5/7/2008 : premiere sortie de ce package \ No newline at end of file diff --git a/templates/f-tex/zwischensumme.sty b/templates/f-tex/zwischensumme.sty new file mode 100644 index 000000000..043d94fbd --- /dev/null +++ b/templates/f-tex/zwischensumme.sty @@ -0,0 +1,228 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Makros zur Berechnung und Ausgabe einer Zwischensumme bei langen Tabellen +% Der Hack der longtable Ausgabe ist von Heiko Oberdiek, das Paket zref auch. +% ---<(kaimartin)>---(August, 2007) +% +% - Dezimaltrennzeichenn nur noch "." by scripts_at_gpl.coulmann.de 2010-12 +% (raw_numbers patch) +% - \Wert -> default Wert 0, by scripts_at_gpl.coulmann.de 2009-08 +% wenn kein Wert uebergebenn wird, dies +% ermoeglicht das Ausgeben von Tabellen ohne +% Preise (z.b. Lieferscheine) +% - keine Ausgabe der Zwischensumme, wenn 0 +% - neu: \brutto zur Ausgabe von Bruttopreisen by scripts_at_gpl.coulmann.de 2009-07 +% - Anpassungen fuer fancy LaTeX by scripts_at_gpl.coulmann.de 2009-03 +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Diese Datei steht unter der GPL-Lizenz, Version 3 +% siehe http://www.gnu.de/licenses/gpl-3.0.html +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\usepackage{etex} % Damit Marken verwendet werden koennen +\usepackage[savepos,user]{zref} % Um die jeweils aktuelle Position zu merken +\usepackage{fltpoint} % Rechnen mit Komma-Zahlen +\usepackage{numprint} % Zahlen formatiert ausgeben +\usepackage{eurosym} % Das Euro-Zeichen +\usepackage{calc} % Fuer das Makro \widthof{} + +% Vorlagen sind auf raw_num Patch ausgelegt daher nur noch . als Trennzeichen +\newcommand{\DecimalSign}{.} +\fpDecimalSign{\DecimalSign} + +% Globale Einstellungen fuer numprint +\npstylegerman % Deutsche Zahlenformatierung, in der Ausgabe +\nprounddigits{2} % Zwei Nachkommasstellen + +% \leer ist bereits in letter.tex definiert, wenn nicht muss es hier passieren +% \newcommand{\leer}{} + +%%%%%%%%%%%%%%Befehle zur Berechnung der Zwischensumme%%%%%%%%%%%%%%%%%%%%%%% +\newcommand*\laufsumme{0} +\newcommand*\resetlaufsumme{\global\def\laufsumme{0}} +\newcommand*\addlaufsumme[1]{\fpAdd{\laufsumme}{\laufsumme}{#1}% + \global\let\laufsumme\laufsumme} +\newcommand*\printwert[1]{ + \ifthenelse{\NoValue > 0}{ + }{ + \numprint{#1} + } +} + + +%%%%%%%%Plaintex-Hack fuer Positionierung der Zwischensummen%%%%%%%%%%%%%%%%%% + + +\makeatletter % Das at-Zeichen in Variablen zulassen + +% Variablen bereit stellen + \newdimen\drx + \newdimen\dry + + \newmarks\ltm@marks + \def\ltm@setmarks#1{% + \marks\ltm@marks{#1}% + } + \def\ltm@getmarks{% + \botmarks\ltm@marks + } + + +% Den aktuellen Wert der Laufsumme berechnen und merken +\newcommand*{\Wert}[1]{% + \ifthenelse{\equal{#1}{\leer}}{ + \addlaufsumme{0}% Den uebergebenen Wert zur Laufsumme addieren + \expandafter\ltm@setmarks\expandafter{\laufsumme}% Die Laufsumme merken + }{ + \printwert{#1}% Ausgabe des Werts vor Ort + \addlaufsumme{#1}% Den uebergebenen Wert zur Laufsumme addieren + \expandafter\ltm@setmarks\expandafter{\laufsumme}% Die Laufsumme merken + } +} + +% Merken der aktuellen Position +\newcommand*{\MarkZwsumPos}{% + \leavevmode + \zsavepos{zwsumpos\thepage}% + \zrefused{zwsumpos\thepage}% +} + + +% Ausgabe der Zwischensumme +\def\ltm@insertfoot#1{% + \vbox to\z@{% + \vss + \hb@xt@\z@{% + \color@begingroup + \zsavepos{tabende\thepage}% % Die aktuelle Position merken + \drx=0sp + \dry=0sp + % Die aktuelle Position abziehen und die gemerkte addieren + \advance \drx by -\zposx{tabende\thepage}sp + \advance \drx by \zposx{zwsumpos\thepage}sp + \advance \dry by -\zposy{tabende\thepage}sp + \advance \dry by \zposy{zwsumpos\thepage}sp + \smash{\kern\drx\raise\dry% + %\hbox{\makebox[\widthof{ \currency}][r]{\printwert{#1} \currency}}% % mit Waehrungszeichen + \hbox{\printwert{#1} }% % ohne Waehrungszeichen + }% end smash + \color@endgroup + }% + }% + \vspace{4mm} +} + +% Ausgabe des Uebertrags +% Wie die Ausgabe der Zwischensumme, nur ohne neu gemerkte Position +\def\ltm@inserthead#1{% + \vbox to\z@{% + \vss + \hb@xt@\z@{% + \color@begingroup + \drx=0sp + \dry=0sp + % Die Position des Tabellenendes abziehen und zur gemerkten gehen + \advance \drx by -\zposx{tabende\thepage}sp + \advance \drx by \zposx{zwsumpos\thepage}sp + \advance \dry by -\zposy{tabende\thepage}sp + \advance \dry by \zposy{zwsumpos\thepage}sp + \smash{\kern\drx\raise\dry% + % Die eigentliche Ausgabe. + % Rechtsbuendig und um die Breite der Währung verschoben. + %\hbox{\makebox[\widthof{ \currency}][r]{\printwert{#1} \currency}}% + \hbox{\printwert{#1}}% % ohne Waehrungszeichen + %\hbox{\makebox[\widthof{ \printwert{#1}}][r]{\printwert{#1}\rule{0mm}{10mm} }}% % ohne Waehrungszeichen + }% end smash + \color@endgroup + }% + }% + \vspace{1mm} +} + + +\def\ltm@lastfoot{\ltm@insertfoot\ltm@getmarks} +\def\ltm@foot{\ltm@insertfoot{\ltm@getmarks}} +\def\ltm@head{\ltm@inserthead{\ltm@getmarks}} + + +% Ueberschreiben der Output-Routine von longtable +\def\LT@output{% + \ifnum\outputpenalty <-\@Mi + \ifnum\outputpenalty > -\LT@end@pen + \LT@err{floats and marginpars % + not allowed in a longtable}\@ehc + \else + \setbox\z@\vbox{\unvbox\@cclv}% + \ifdim \ht\LT@lastfoot>\ht\LT@foot + \dimen@\pagegoal + \advance\dimen@-\ht\LT@lastfoot + \ifdim\dimen@<\ht\z@ + \setbox\@cclv\vbox{% + \unvbox\z@\copy\LT@foot\ltm@foot\vss + }% + \@makecol + \@outputpage + \setbox\z@\vbox{\box\LT@head}% + \fi + \fi + \global\@colroom\@colht + \global\vsize\@colht + \vbox{% + \unvbox\z@ + \box\ifvoid\LT@lastfoot + \LT@foot\ltm@foot + \else + \LT@lastfoot\ltm@lastfoot + \fi + }% + \fi + \else + \setbox\@cclv\vbox{% + \unvbox\@cclv\copy\LT@foot\ltm@foot\vss + }% + \@makecol + \@outputpage + \global\vsize\@colroom + \copy\LT@head\ltm@head + \fi +} + +\newcommand\BruttoSellPrice[2]{ + \fpAdd{\tax}{#2}{100} + \fpDiv{\taxF}{\tax}{100} + \fpMul{\result}{#1}{\taxF} + \numprint{\result} +} +\newcommand\BruttoWert[2]{ + \fpAdd{\tax}{#2}{100} + \fpDiv{\taxF}{\tax}{100} + \fpMul{\rawresult}{#1}{\taxF} + \Wert{\rawresult} +} + + +\newcommand\BruttoLineSum[4]{ + \fpAdd{\tax}{#4}{100} + \fpDiv{\taxF}{\tax}{100} + \fpMul{\result}{#1}{\taxF} + \fpMul{\result}{#2}{\result} + \fpSub{\rabatt}{100}{#3} + \fpDiv{\rabatt}{\rabatt}{100} + \fpMul{\result}{\result}{\rabatt} + \Wert{\result} +} + +% \ifthenelse{\equal{<%p_discount%>}{0}}{}{ -<%p_discount%>\%} & +% %<%sellprice%> +% \Wert{<%linetotal%>} % Zeilensumme + +% \fpMul{\result}{#1}{1.19} +% \fpMul{\resultt}{#2}{\result} +% \fpSub{\rabatt}{100}{#3} +% \fpDiv{\rabattt}{\rabatt}{100} +% \fpMul{\resulttt}{\resultt}{\rabattt} +% %\fpRound{\roundresult}{\result}{3} +% %\roundresult +% \resulttt + +\makeatother % Das at-Zeichen in Variablen wieder verbieten +%%%%%%%%%%%%%%%%%%%%Ende plaintex-Hack%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%