Files
Fuchs_Intranet/Fuchs/js/intranet/modules/fis.inv_txt_de.js
T
StefanandClaude Sonnet 5 ecc74cf3c6
Playwright Tests / test (push) Canceled after 0s
Add user-defined invoice set structure dialog (ADR 0016)
Lets a back-office user correct/define which invoice line belongs to
which "set" and how deep it is nested, instead of relying only on the
implicit "everything after a Set header until the next Set" grouping
fds__prepInvoice derives. Sets may contain sets; every change applies
immediately to the cached draft session and is reflected in the editor
and PDF (ADR 0006/0008).

Backend:
- InvoiceSetStructure: pure parent-link forest (assign, change level,
  create, place/move-sibling, depth-first linearise + level recompute).
- InvoiceDraftSetStructureDeltas: new inv/dpatch targets set.assign,
  set.level, set.create, set.move.
- InvoiceSetPricing.Build is now order-preserving and nesting-aware
  (governed by the nearest converted ancestor); the set-item switch
  sums a header's transitive descendants so nested conversions never
  double-count.
- FuchsPdf indents nested set members per level, mirroring the editor.

Frontend:
- New fis.inv_sets.js: "Set-Struktur bearbeiten" dialog — per-block
  table of all lines with drag & drop reorder (before/after/into),
  ▲▼ order and ◀▶ level buttons, fold/unfold per set (view-only), and
  a create bar for new Set/Text lines. Posts one delta per action; the
  dialog is a pure view of the server state (ADR 0006).
- _Layout.cshtml / fis_main.js: cache-bust the dynamically imported
  per-module bundles (web/fis.<mdl>.<locale>.js/.css) with an asset
  version derived from the newest bundle write time, so a gulp rebuild
  is picked up without a stale cached module.

Docs: ADR 0016, live-draft-editing concept, INVOICE_SET_PRICING.md,
USER_GUIDE.md, ARCHITECTURE.md updated. Tests: InvoiceSetStructureTests
(new) + additions to InvoiceDraftServiceTests/InvoiceSetPricingTests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 08:55:05 +02:00

146 lines
8.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
let $ict = {
mdl: 'Rechnungen',
iov: {
all: 'Rechnungen (alle)', '': 'Rechnungen (nur fertige)', '#d': 'Rechnungen (nur Entwürfe)', '#u': 'Rechnungen (nur unbezahlt)', '#r': 'Rechnungen (nur angemahnt)', '#a': 'Rechnungen (nur Akonto)', '#c': 'Rechnungen (nur Storno)', '#ru': 'Rechnungen (nur angemahnt + unbez.)'
},
uba: ', gesamter Zeitraum)',
req: 'Auftrag',
inv: 'Rechnung',
rem: 'Mahnung',
in: 'Rechnungsnummer',
cc: 'Kunde',
wk: 'Woche',
nd: 'Keine Daten gefunden.',
dl: 'Herunterladen',
ed: 'Bearbeiten',
ced: 'Bearbeitung fortsetzen',
sItm: 'Einzelheiten anzeigen',
sPay: 'Zahlungen anzeigen',
cdI: 'Entwurf der Rechnung löschen?',
rel: 'Neu Laden',
relm: 'Bitte laden Sie Liste manuell neu, um die Änderungen zu sehen.',
dsp: 'Rechnung anzeigen',
storno: 'Storno-Rechnung erstellen',
credit: 'Gutschrift erstellen',
remd: 'Mahnung erstellen',
remdt: 'Mahnung erstellen zur Rechnung {0}',
remlst: 'Mahnungen anzeigen',
remdsp: 'Mahnung anzeigen',
remres: 'Mahnung erneut senden',
remresc: 'Mahnung {0} wirklich erneut senden?',
remresr: 'Mahnung {0} wurde erfolgreich versandt.',
setpyd: 'Bezahlt markieren',
cpyd: 'Rechnung wirklich als bezahlt markieren?',
setupd: 'Bezahlt-Markierung aufheben',
cupd: 'Bezahlt-Markierung wirklich aufheben?',
ivE: 'Die Email-Adresse ist vermutlich nicht gültig.',
ivEc: '\nMöchten Sie fortfahren?',
pna: 'Diese Seite ist in der Vorschau nicht verfügbar',
tpe: 'Die Anzahl von {0} Seiten wird aktuell nicht unterstützt',
eis: 'Der Rechnungsentwurf konnte nicht gespeichert werden.',
iss: 'Zwischenstand speichern.',
p13b: 'USt -> §13b',
setm: 'Set-Preisanzeige',
setmo: {
setprice: 'Set mit Preis – Positionen ohne Preis',
setonly: 'Nur Set mit Preis – Positionen ausgeblendet'
},
/* user-defined set structure dialog (ADR 0016) */
setst: 'Set-Struktur bearbeiten',
setsHint: 'Reihenfolge: Zeile per Drag & Drop an den oberen/unteren Rand einer anderen Zeile ziehen (davor/danach) oder ▲▼ nutzen. Zuordnung: Zeile auf die Mitte eines Sets ziehen (hinein) bzw. auf die Auftragszeile oder "oberste Ebene" (aus dem Set lösen); ◀▶ ändert die Ebene. Sets lassen sich über das Dreieck zu-/aufklappen und auch zugeklappt verschieben – ihre Positionen wandern mit. Änderungen werden sofort übernommen.',
setsUp: 'Nach oben (innerhalb der Ebene)',
setsDown: 'Nach unten (innerhalb der Ebene)',
setsCollapse: 'Set zuklappen',
setsExpand: 'Set aufklappen',
setsHR: ['', 'Pos.', 'Typ', 'Menge', 'Bezeichnung', 'Reihenfolge / Ebene'],
setsRoot: 'Hierher ziehen = aus dem Set lösen (oberste Ebene)',
setsOut: 'Eine Ebene höher (aus dem Set lösen)',
setsIn: 'Eine Ebene tiefer (dem vorangehenden Set zuordnen)',
setsNew: 'Neu:',
setsInto: 'in',
setsTop: 'oberste Ebene',
setsTitle: 'Bezeichnung',
setsAdd: 'Hinzufügen',
setsNoTitle: '(ohne Bezeichnung)',
settyp: { set: 'Set', text: 'Text', title: 'Text', material: 'Material', service: 'Arbeitsleistung', equipment: 'Ausrüstung', other: 'Position', osum: 'Zusammenfassung', intinvoiceallocation: 'Abschlag', intinvoiceallocationdiff: 'Abschlag (offen)' },
ctp: 'Ansprechpartner festlegen',
mfr: 'Von MFR neu abrufen',
rq1: 'Auftragsdaten werden von MFR abgerufen.\nDer Vorgang kann bis zu 90Sek dauern.',
rq2: 'Auftragsdaten werden geladen',
iq1: 'Rechnungsdaten werden von MFR abgerufen.\nDer Vorgang kann bis zu 90Sek dauern.',
iq2: 'Rechnungsdaten werden geladen',
sis: 'Rechnung als versandt markieren',
srs: 'Mahnung als versandt markieren',
sisc: 'Rechnung wirklich als versandt markieren?',
srsc: 'Mahnung wirklich als versandt markieren?',
iSt: {dft: 'Entwurf', uns: 'nicht versandt', pyd: 'bezahlt', cc: 'storniert', op: 'offen', due: 'fällig', ovd: 'überfällig', rem: 'angemahnt' },
rSt: ['', 'Überfällig', '2. Mahnung', '3. Stufe'],
pSt: { 'a': 'Vollst.', 'p': 'Teilz.' },
ivT: { i: 'AbschlagsR.', f: 'SchlussR', r: 'Rechnung', c: 'StornoR.' },
rovlh: 'Übersicht der bisherigen Mahnungen',
rovl: ['Betreff', 'Betrag', 'Betrag gezahlt', 'fertiggestellt am'],
remHR: ['Rechnung', 'vom', 'Rechnungsbetrag', 'bereits bezahlt', 'noch offen'],
// Reminder intro/closing notice texts are backend-authoritative (see FuchsPdf.BuildReminderNotes /
// $inv.rd.notes) — no client-side copies here.
translatePaymentTerm: (pt) => (pt || '').replace('wd', ' Werktagen').replace('d', ' Tagen').replace('wk', ' Wochen') || '10 Tagen'
, payi: { account: 'Konto', name: 'Zahler', text: 'Verw.Zweck', InvoiceID: 'Rechnung', amount: 'Betrag', date: 'Datum', manual: 'Typ'}
}, $invcol = {
datev: new fields_definition('Rechnung', 'Rechnungen', [
{ name: 'Umsatz (ohne Soll/Haben-Kz)', label: 'Umsatz (ohne Soll/Haben-Kz)', type: 'string' },
/*{ name: 'EINZELPOS_brutto', label: 'EINZELPOS_brutto', type: 'string' },
{ name: 'EINZELPOS_netto', label: 'EINZELPOS_netto', type: 'string' },*/
{ name: 'vf', label: 'vf', type: 'string' },
{ name: 'Soll/Haben-Kennzeichen', label: 'Soll/Haben-Kennzeichen', type: 'string' },
{ name: 'Konto', label: 'Konto', type: 'string' },
{ name: 'Gegenkonto', label: 'Gegenkonto', type: 'string' },
{ name: 'BU-Schlüssel', label: 'BU-Schlüssel', type: 'string' },
{ name: 'Belegdatum', label: 'Belegdatum', type: 'string' },
{ name: 'Belegfeld 1', label: 'Belegfeld 1', type: 'string' },
{ name: 'Belegfeld 2', label: 'Belegfeld 2', type: 'string' },
{ name: 'Buchungstext', label: 'Buchungstext', type: 'string' }
])
, inv: new fields_definition('Rechnung', 'Rechnungen', [
{ name: 'invstatus', label: 'Status', type: 'select', url: $ict.iSt },
{ name: 'balance', label: 'Umsatz', type: 'string', dtype: 'currency' },
{ name: 'CustomerName', label: 'Kunde', type: 'string' },
{ name: 'InvoiceId', label: 'RNummer', type: 'string' },
{ name: 'InvoiceType', label: 'Typ', type: 'select', url: $ict.ivT },
//{ name: 'requestcount', label: 'Anz. Aufträge', type: 'string', dtype: 'num' },
{ name: 'request', label: 'Auftrag', type: 'string', dtype: 'num' },
/*{ name: 'EINZELPOS_brutto', label: 'EINZELPOS_brutto', type: 'string', dtype: 'currency' },
{ name: 'EINZELPOS_netto', label: 'EINZELPOS_netto', type: 'string', dtype: 'currency' },*/
{ name: 'vat', label: 'MwSt', type: 'string', dtype: 'num' },
{ name: 'deb_cred', label: 'Soll/Haben', type: 'string' },
{ name: 'customer', label: 'Konto', type: 'string', dtype: 'num' },
{ name: 'contra_account', label: 'Gegenkonto', type: 'string', dtype: 'num' },
{ name: 'Belegdatum', label: 'Belegdatum', type: 'date' },
{ name: 'reminderstatus', label: 'MahnStatus', type: 'select', url: $ict.rSt },
{ name: 'reminder', label: '# Mahnungen', type: 'integer' },
{ name: 'Buchungstext', label: 'Buchungstext', type: 'string' },
{ name: 'Payment', label: 'Zahlung', type: 'string' }
/*{ name: 'PaymentStatus', label: 'Zahlungsstatus', type: 'select', url: $ict.pSt}*/
])
, rem: new fields_definition('Zahlungserinnerung', 'Zahlungserinnerung', [
{ name: 'amount', label: 'Rechnungsbetrag', type: 'number', precision: '0.01', value: 1 },
{ name: 'amount_payed', label: 'bereits bezahlt', type: 'number', precision: '0.01', value: 1 }
])
, rem2: new fields_definition('Zahlungserinnerung', 'Zahlungserinnerung', [
{ name: 'DocumentName', label: 'Name', type: 'string' },
{ name: 'subject', label: 'Betreff', type: 'string' },
{ name: 'DateSent', label: 'Versanddatum', type: 'date' },
{ name: 'status', label: 'Status', type: 'string' },
//{ name: 'IsDraft', label: 'Entwurf', type: 'boolean' },
{ name: 'amount_open', label: 'offener Betrag', type: 'number', precision: '0.01' },
{ name: 'InvoiceId', label: 'RNummer', type: 'string' },
//{ name: 'InvoiceDocumentName', label: 'RechnungName', type: 'string' }
])
, rid: new fields_definition('Zahlungserinnerung', 'Zahlungserinnerung', [
{ name: 'type', label: 'Typ', type: 'select', url: [['f', 'einfache Zahlungserinnerung'],[ 'm', 'Mahnung'],[ 'l', 'letzte Mahnung']], required: true},
{ name: 'level', label: 'Stufe', type: 'select', url: [['1', 'Stufe 1'], ['2', 'Stufe 2'], ['3', 'Stufe 3'], ['4', 'Stufe 4'], ['5', 'Stufe 5'], ['6', 'Stufe 6']], required: true }
])
, ctp: new fields_definition('Ansprechpartner', 'Ansprechpartner', [
{ name: 'name', label: 'Name', type: 'string' },
{ name: 'email', label: 'Email', type: 'string' }
])
};