Bernd Bleßmann [Mon, 14 Dec 2020 16:28:32 +0000 (17:28 +0100)]
Menü Produktivität: Zugriffsrechte nicht am Haupteintrag fest machen …
und eigene Zugriffssregel für E-Mail-Journal.
So kann z.B. das Recht, E-Mail-Journal ansehen, getrennt von der
Produktivität gesetzt werden.
Ein Hauptmenüpunkt wird nicht angezeigt, wenn keiner seiner Kinder
(z.B. wg. fehlender Rechte) angezeigt wird - wenn also keines der Rechte
vorhanden ist, so wird, wie vorher auch, der Haupteintrag auch nicht
gezeigt.
Jan Büren [Mon, 28 Sep 2020 15:24:57 +0000 (17:24 +0200)]
Dialogbuchungen um Boolean imported erweitert.
Buchungen mit diesem Boolean können beim DATEV-Export
gefiltert werden. Anwendungsfall sind bspw. in DATEV
erstellte Lohnbuchungen, die dann in kivi importiert werden
Jan Büren [Mon, 14 Dec 2020 08:31:32 +0000 (09:31 +0100)]
GLTransaction:: add_chart_booking um get_active_taxkey erweitert
Der Aufruf von add_chart_booking muss sich nicht mehr
darum kümmern welcher Steuerschlüssel gesetzt sein muss, wenn
er einfach nur den vorkonfigurierten Steuerschlüssel setzen will.
Dementsprechend ist param{tax_id} kein Pflichtparameter mehr.
POD ergänzt und mit Testfällen abgesichert (19% / 16% Fall).
Moritz Bunkus [Fri, 11 Dec 2020 10:07:47 +0000 (11:07 +0100)]
Artikelstammdaten: in Übersetzungen Zeilenumbrüche verwenden können
Das Eingabefeld für die Beschreibung im Basisdaten-Tab erlaubt die
Eingabe von Zeilenumbrüchen. Daher muss das auch für die übersetzen
Beschreibungen gehen.
Jan Büren [Wed, 9 Dec 2020 10:35:59 +0000 (11:35 +0100)]
Kontoauszug verbuchen: Vorschlagsliste verbessern
- Kommentar stimmt nicht mit dem Code überein.
- Die Prüfung verhindert das Banktransaktionen mit einer Summe größer der
Rechnungssumme als Vorschlag zugewiesen werden. Das war wichtig,
weil der Payment-Helper zu Beginn immer die komplette Bankbewegung auf
einen Beleg gebucht hat. Das ist mittlerweile besser gelöst.
Moritz Bunkus [Thu, 3 Dec 2020 10:08:08 +0000 (11:08 +0100)]
display_row: ship_$row nicht formatiert ausgeben
Im ganzen Programm wird angenommen, dass `$::form->{ship_$row}`
unformatiert ist, nur an dieser Stelle wird es formatiert
ausgegeben. Das war nicht mal ein Problem, weil es in `update` via
`_update_ship()` komplett neu berechnet wird, ohne auf den aktuellen
Wert in `$::form->{ship_$row}` zurückzugreifen. Trotzdem ist es der
Konsistenz halber wichtig, den Wert auch hier unformatiert auszugeben.
Moritz Bunkus [Thu, 3 Dec 2020 10:05:10 +0000 (11:05 +0100)]
Order-Controller: Umwandlung: Berechnung bereits gelieferter/abgerechneter Mengen gefixt
In $::form steht der Wert für die gelieferte Menge in
`ship_$row`. Dieser Wert wird überall im Programm als unformatiert
angenommen, nur bisher in der Methode nicht, die berechnet, wie viel
von jeder Position bereits abgerechnet/geliefert war. Ergebnis war,
dass ein unformatierter Wert noch mal durch `$::form->parse_amount`
gejagt wurde.
Für einen Wert mit Nachkommaanteil ist das dann problematisch. Wurden
bereits z.B. 123,45 geliefert, so steht in `$::form->{ship_1}` der
Wert `123.45`, einmal durch `parse_amount` ergibt `12345`, was um
einen Faktor 100 zu viel ist.
Inventory Helper: Bessere Fehlermeldung bei fehlenden Parametern
Alle Fehler im allocate() des Inventory-Helpers werden nun per
SL::X::Inventory::Allocation Fehlermethode erzeugt,
damit es eine einheitliche Prüfung geben kann.
Bei der Fehlermeldung wird das falsche Lager angezeigt.
Bisher wurde das Lager mit vorhandener Menge angezeigt, das nicht der Einschränkung entspricht.
Es muss aber entweder kein Lager oder ein Lager angezeigt werden, das den Einschränkungen entspricht
aber zuwenig Menge hat.
Nun werden an die Exception noch zwei weitere Parameter zur Auswertung übergeben:
- accessor: Bei wem tritt der Fehler auf
- allocations: Parameter die zu diesem Fehler geführt haben
Sollen beim Produzieren/Abfüllen für die notwendigen Artikel auch
Dokumente angegeben werden, so müssen diese extra in die Allocation
Struktur eingebracht werden.
Automatischer Test angepasst: Inventoryhelper nun mit Parameter oe_id
Moritz Bunkus [Fri, 27 Nov 2020 09:44:56 +0000 (10:44 +0100)]
HTTP-Header: Lebenszeit für Session-ID-Cookie setzen
Wenn ein Cookie kein Ablaufdatum gesetzt hat, so soll der Browser das
Cookie beim Beenden löschen. Damit ist es de facto unmöglich, ein
Session-Timeout anzugeben, das groß genug ist, damit man auch am
folgenden Arbeitstag noch eingeloggt ist (z.B. 24 Stunden).
`SL::Auth` berücksichtigt die Session-ID-Gültigkeit natürlich selber
schon, ist also die maßgebliche Instanz bzgl. der Gültigkeit, egal wie
lange der Browser das Cookie nun mitschickt. Aber wenn der Browser das
Cookie gar nicht mehr schickt, weil er zwischendurch geschlossen
wurde, kann `SL::Auth` auch nichts mehr machen.
Moritz Bunkus [Thu, 26 Nov 2020 13:04:32 +0000 (14:04 +0100)]
Factur-X/ZUGFeRD: in »Factur-X/ZUGFeRD« umbenannt
Mit ZUGFeRD-Standard Version 2.1.1 ist der offizielle Name des
EU-Standards schlicht Factur-X. ZUGFeRD ist nur noch der tolerierte
alte Name.
In der Oberfläche ist nun überall von »Factur-X/ZUGFeRD« die Rede.
Im Quellcode heißen die Module hingegen weiterhin `SL::…::ZUGFeRD`,
weil die Umstellung ansonsten zu groß und irgendwo auch nicht so nötig
ist.
Es ändern sich auch die ganzen Namen in den Metadaten des PDFs und der
XML-Datei:
• Namensraum in der für Factur-X/ZUGFeRD relevanten XML-Elemente in
den XMP-Metadaten im PDF
• Name des Dateianhangs der Rechnungs-XML im PDF (»factur-x.xml«)
• Standard-Identifier in der Rechnungs-XML
Moritz Bunkus [Thu, 26 Nov 2020 10:03:15 +0000 (11:03 +0100)]
Factur-X/ZUGFeRD: Verkäufernamen aus Employee-Objekt nehmen
Wichtig für Personen, die inzwischen aus der Auth-Datenbank gelöscht
wurden. Für die existiert der Employee-Eintrag weiterhin, und von dort
kann man den Namen beziehen.
Moritz Bunkus [Tue, 24 Nov 2020 12:26:22 +0000 (13:26 +0100)]
SL::DB::Object: Methode update_collections für One-To-Many-Relationships
Der große Nachteil einer direkten Zuweisung wie
z.B. `$customer->shiptos($::form->{shiptos} // [])` ist, dass Rose
erst mal alle Objekte der Relationship löscht (auch wenn die neuen
Werte Primärschlüsselattribute enthalten) und anschließend neu
INSERTed, was nicht nur deutlich zu aufwändig ist, sondern auch mal
nicht funktionieren kann, wenn es da noch weitere Objekte mit
Fremdschlüsseln auf die zu aktualisierenden Objekte verweisen.
Daher muss man die Behandlung (neu hinzuzufügende, zu löschende & zu
aktualisierende Objekte) selber vornehmen. Das macht nun diese
Methode.
Die Methode gleicht eine Liste von existierenden Objekten einer
One-To-Many-Relationship (z.B. Kunde zu Lieferadressen) mit einer
neuen Liste von Hashrefs ab, die z.B. aus `$::form` stammen können.
Für alle Einträge aus der neuen Liste, die kein Attribut für den
Primärschlüssel enthalten, werden neue Einträge in der Datenbank
angelegt.
Für alle Einträge aus der neuen Liste mit Primärschlüsselattribut wird
das korrespondierende Objekt mit den Werten aus `$::form`
aktualisiert.
Alle existierenden Objekte in `$self->$attribute`, für die es keinen
korrespondierenden Eintrag in der neuen Liste mehr gibt, werden
gelöscht.
Moritz Bunkus [Tue, 24 Nov 2020 11:10:33 +0000 (12:10 +0100)]
AttrDuration für minutes: _in_hours und _in_hours_as_number
Generierte Helfer-Methoden für Attribute, die normalerweise Minuten
speichern. Die Funktion `attribute_in_hours` rechnet die Minuten in
Stunden um (beim Lesen) und umgekehrt (beim Schreiben).
`attribute_in_hours_as_number` formatiert zusätzlich den Wert in
Stunden zusätzlich in das Zahlenformat der Anwender*in bzw. parst
dieses Format beim Schreiben.
Bernd Bleßmann [Fri, 20 Nov 2020 19:32:48 +0000 (20:32 +0100)]
CSV-Import Waren: bestehende Makemodels als Array, nicht als Array-Ref
makdemodels verhält sich als makemodels_sorted: Die von Rose erzeugte Methode
berücksichtig offenbar den Kontext - makemodels_sorted gibt immer ein array-ref
Bernd Bleßmann [Fri, 20 Nov 2020 16:02:32 +0000 (17:02 +0100)]
Massenerstellen von RG aus LS: geschlossene LS nicht (erneut) verarbeiten
Geschlossene Lieferscheine werden nicht zum Umwandeln in der Liste angezeigt,
das war auch bisher so. Aber weenn man nach dem Erzeuigen der Rechnungen von
der Folgeseite den Browser-Zurück-Knopf drückt, konnten aus den selben
Lieferscheine durchaus nochmal Rechnungen erzeugt werden. Das wird nun
abgefangen.
Bernd Bleßmann [Fri, 20 Nov 2020 15:34:16 +0000 (16:34 +0100)]
Massenerstellen von Rechnungen aus LS: Aktion nur einmal ausführen
Dafür den Action-Parameter only_once verwenden.
Damit das aber klappt, muss die Prüfung, ob etwas angehakt ist, auch als check
an die Action gehängt werden. Denn sonst wird der Knopf abgeschaltet, auch wenn
nur die Prüfung fehlschlägt, weil man nix angehakt hat.
Moritz Bunkus [Mon, 16 Nov 2020 16:02:38 +0000 (17:02 +0100)]
CSS/JS: Git-Revision von HEAD als GET-Parameter verwenden
Webbrowser cachen CSS & JS sehr aggressiv. Das ist während der
Entwicklung störend, weshalb es bereits seit langem die
Konfigurationsoption `auto_reload_resources` gibt. Ist diese an, so
wird an alle CSS- und JS-URLs ein GET-Parameter `?rand=<Zufallswert>`
angehängt wird, um das Cachen auszuhebeln.
Dieser Commit führt etwas Ähnliches ein, das für den Produktivbetrieb
ohne `auto_reload_resources` gedacht ist. Wenn kivitendo erkennt, dass
es aus git heraus läuft (also ein `.git`-Verzeichnis existiert), so
parset es die Revision von `HEAD` und nimmt das als GET-Parameter
`?rand=<Revision>`. Der Vorteil ist, dass nach Updates einer
Produktivinstallation die Webbrowser der Anwender*innen genau einmal
alle Ressourcen neu laden, weil sich ja die Git-Revisionsnummer
geändert hat. Anschließend können sie die Ressourcen aber wieder
normal cachen, bis das nächste Update kommt.
Es wird hierfür übrigens kein installiertes git-Executable benötigt;
die Infos werden zwecks Performance direkt aus den Dateien gelesen,
anstatt bei jedem Request ein Programm auszuführen.
Zukünftig könnte man ein analoges Verfahren anwenden, wenn es kein
`.git`-Verzeichnis gibt, und dann zumindest die
kivitendo-Versionsnummer verwenden.
Moritz Bunkus [Mon, 16 Nov 2020 14:16:19 +0000 (15:16 +0100)]
L/P.select_tag: Unterstützung für Text-Filter
Gedacht für Selects mit size="123"-Attribut, die also als Liste und
nicht als Combobox gerendert werden.
Es wird direkt oberhalb der Select eine Text-Eingabezeile angezeigt,
die als dynamischer Filter für die Optionen verwendet wird. Bei jeder
Änderung (keyup) werden nur noch diejenigen Einträge in der Select
angezeigt, in deren Text der Suchfilter-Begriff irgendwo
vorkommt (ohne Berücksichtigung von Groß-/Kleinschreibung).
• with_filter=1 schaltet den Filter an
• filter_placeholder=LxERP.t8("Placeholder text") gibt einen
Platzhalter-Text an
Moritz Bunkus [Mon, 16 Nov 2020 16:15:41 +0000 (17:15 +0100)]
L/P.select_tag: Collection, die aus einem leeren Wert besteht, ignorieren
Unter Umständen kann es durch wantarray & Durchschieben in Templates
passieren, dass der $collection-Parameter nicht leer ist (obwohl er
leer sein sollte), und statt dessen ein leerer String ist. Bisher
wurde daraus eine Liste mit einem leeren Eintrag, auch wenn
`with_empty` nicht angegeben war.
Ab sofort solche Einträge einfach als leere Liste werten.