mirror of
https://github.com/kbenestad/invoice.git
synced 2026-06-18 08:04:32 +00:00
Build invoicing app: app/index.html and app/config.yml
Static single-page invoice app per spec. Features: - Multilingual UI (EN/DE/FR/NO) loaded from config.yml; form always prints in the default language - Sender fields + invoice details (date, project code, invoice no.) persisted in localStorage; invoice number auto-increments after each generation - Predefined charge-to recipients selectable from config, or manual entry - Dynamic invoice line items: predefined products with UOM/price pre-fill, free-text fallback, foreign-currency sub-row with exchange-rate and per-item price that calculates back to local currency - Subtotal / tax (configurable rates) / paid / to-pay calculated live - "Generate Invoice" renders a clean A4-formatted preview overlay; "Print / Save as PDF" triggers browser print-to-PDF https://claude.ai/code/session_015iyCBgoTXNNqaErR287U1u
This commit is contained in:
parent
c5d3019e3f
commit
8bac41fe77
2 changed files with 1649 additions and 0 deletions
416
app/config.yml
Normal file
416
app/config.yml
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
# Invoice App Configuration
|
||||
# (C) 2026 Kristian Benestad. Licensed under the Apache 2 license.
|
||||
|
||||
# ── Default language ───────────────────────────────────────────────────────────
|
||||
default-code: en
|
||||
default-name: English
|
||||
default-direction: ltr
|
||||
|
||||
# ── Available languages ────────────────────────────────────────────────────────
|
||||
languages:
|
||||
- code: en
|
||||
name: English
|
||||
direction: ltr
|
||||
- code: de
|
||||
name: Deutsch
|
||||
direction: ltr
|
||||
- code: fr
|
||||
name: Français
|
||||
direction: ltr
|
||||
- code: "no"
|
||||
name: Norsk
|
||||
direction: ltr
|
||||
|
||||
# ── Tax / VAT options ──────────────────────────────────────────────────────────
|
||||
tax-rates:
|
||||
- label-en: "No Tax (0%)"
|
||||
label-de: "Keine Steuer (0%)"
|
||||
label-fr: "Sans taxe (0%)"
|
||||
label-no: "Ingen mva (0%)"
|
||||
rate: 0
|
||||
- label-en: "VAT 5%"
|
||||
label-de: "MwSt. 5%"
|
||||
label-fr: "TVA 5%"
|
||||
label-no: "Mva 5%"
|
||||
rate: 5
|
||||
- label-en: "VAT 10%"
|
||||
label-de: "MwSt. 10%"
|
||||
label-fr: "TVA 10%"
|
||||
label-no: "Mva 10%"
|
||||
rate: 10
|
||||
- label-en: "VAT 20%"
|
||||
label-de: "MwSt. 20%"
|
||||
label-fr: "TVA 20%"
|
||||
label-no: "Mva 20%"
|
||||
rate: 20
|
||||
- label-en: "VAT 25%"
|
||||
label-de: "MwSt. 25%"
|
||||
label-fr: "TVA 25%"
|
||||
label-no: "Mva 25%"
|
||||
rate: 25
|
||||
|
||||
# ── Units of measure ──────────────────────────────────────────────────────────
|
||||
uom:
|
||||
- code: EA
|
||||
labels:
|
||||
en: Each
|
||||
de: Stück
|
||||
fr: Pièce
|
||||
"no": Stykk
|
||||
- code: HR
|
||||
labels:
|
||||
en: Hour
|
||||
de: Stunde
|
||||
fr: Heure
|
||||
"no": Time
|
||||
- code: DY
|
||||
labels:
|
||||
en: Day
|
||||
de: Tag
|
||||
fr: Jour
|
||||
"no": Dag
|
||||
- code: WK
|
||||
labels:
|
||||
en: Week
|
||||
de: Woche
|
||||
fr: Semaine
|
||||
"no": Uke
|
||||
- code: MO
|
||||
labels:
|
||||
en: Month
|
||||
de: Monat
|
||||
fr: Mois
|
||||
"no": Måned
|
||||
- code: LS
|
||||
labels:
|
||||
en: Lump Sum
|
||||
de: Pauschale
|
||||
fr: Forfait
|
||||
"no": Engangsbeløp
|
||||
|
||||
# ── Predefined recipients (charge-to) ─────────────────────────────────────────
|
||||
charge-to:
|
||||
- display: Acme Corporation
|
||||
name: Acme Corporation Ltd.
|
||||
address1: 123 Business Avenue
|
||||
address2: Suite 400
|
||||
address3: New York, NY 10001
|
||||
address4: ""
|
||||
country: US
|
||||
phone: "+1-212-555-0100"
|
||||
email: accounts@acmecorp.example
|
||||
vat-id: "US-EIN-12-3456789"
|
||||
- display: Example NGO
|
||||
name: Example Non-Profit Organisation
|
||||
address1: 45 Charity Lane
|
||||
address2: London EC1A 1BB
|
||||
address3: ""
|
||||
address4: ""
|
||||
country: GB
|
||||
phone: "+44 20 7123 4567"
|
||||
email: finance@examplengo.example
|
||||
vat-id: "GB123456789"
|
||||
|
||||
# ── Project codes ──────────────────────────────────────────────────────────────
|
||||
project-codes:
|
||||
- Project 100
|
||||
- Project 110
|
||||
- Project 230
|
||||
|
||||
# ── Predefined products / services ────────────────────────────────────────────
|
||||
products:
|
||||
- code: CONSULTING
|
||||
description:
|
||||
en: Consulting Services
|
||||
de: Beratungsleistungen
|
||||
fr: Services de conseil
|
||||
"no": Konsulenttjenester
|
||||
uom: HR
|
||||
price: 100.00
|
||||
- code: TRAINING
|
||||
description:
|
||||
en: Training
|
||||
de: Schulung
|
||||
fr: Formation
|
||||
"no": Opplæring
|
||||
uom: DY
|
||||
price: 800.00
|
||||
- code: REPORT
|
||||
description:
|
||||
en: Written Report
|
||||
de: Schriftlicher Bericht
|
||||
fr: Rapport écrit
|
||||
"no": Skriftlig rapport
|
||||
uom: EA
|
||||
price: 500.00
|
||||
- code: REVIEW
|
||||
description:
|
||||
en: Review & Feedback
|
||||
de: Überprüfung & Feedback
|
||||
fr: Révision et retours
|
||||
"no": Gjennomgang og tilbakemelding
|
||||
uom: HR
|
||||
price: 120.00
|
||||
|
||||
# ── Foreign currency options ───────────────────────────────────────────────────
|
||||
currencies:
|
||||
- USD
|
||||
- EUR
|
||||
- GBP
|
||||
- JPY
|
||||
- CHF
|
||||
- CAD
|
||||
- AUD
|
||||
- NOK
|
||||
- SEK
|
||||
- DKK
|
||||
- THB
|
||||
- SGD
|
||||
- HKD
|
||||
- INR
|
||||
- MXN
|
||||
- BRL
|
||||
- ZAR
|
||||
|
||||
# ── UI label translations ──────────────────────────────────────────────────────
|
||||
translations:
|
||||
language:
|
||||
en: Language
|
||||
de: Sprache
|
||||
fr: Langue
|
||||
"no": Språk
|
||||
invoice:
|
||||
en: INVOICE
|
||||
de: RECHNUNG
|
||||
fr: FACTURE
|
||||
"no": FAKTURA
|
||||
sender-name:
|
||||
en: Your Name / Organisation
|
||||
de: Ihr Name / Organisation
|
||||
fr: Votre nom / Organisation
|
||||
"no": Ditt navn / Organisasjon
|
||||
sender-address1:
|
||||
en: Address Line 1
|
||||
de: Adresszeile 1
|
||||
fr: "Ligne d'adresse 1"
|
||||
"no": Adresselinje 1
|
||||
sender-address2:
|
||||
en: Address Line 2
|
||||
de: Adresszeile 2
|
||||
fr: "Ligne d'adresse 2"
|
||||
"no": Adresselinje 2
|
||||
sender-address3:
|
||||
en: Address Line 3
|
||||
de: Adresszeile 3
|
||||
fr: "Ligne d'adresse 3"
|
||||
"no": Adresselinje 3
|
||||
sender-address4:
|
||||
en: Address Line 4
|
||||
de: Adresszeile 4
|
||||
fr: "Ligne d'adresse 4"
|
||||
"no": Adresselinje 4
|
||||
sender-country:
|
||||
en: Country
|
||||
de: Land
|
||||
fr: Pays
|
||||
"no": Land
|
||||
sender-phone:
|
||||
en: Phone
|
||||
de: Telefon
|
||||
fr: Téléphone
|
||||
"no": Telefon
|
||||
sender-email:
|
||||
en: Email
|
||||
de: E-Mail
|
||||
fr: "E-mail"
|
||||
"no": E-post
|
||||
charge-to:
|
||||
en: "Charge to"
|
||||
de: "In Rechnung an"
|
||||
fr: "Facturer à"
|
||||
"no": "Faktureres til"
|
||||
charge-to-name:
|
||||
en: Organisation / Name
|
||||
de: Organisation / Name
|
||||
fr: Organisation / Nom
|
||||
"no": Organisasjon / Navn
|
||||
charge-to-address1:
|
||||
en: Address Line 1
|
||||
de: Adresszeile 1
|
||||
fr: "Ligne d'adresse 1"
|
||||
"no": Adresselinje 1
|
||||
charge-to-address2:
|
||||
en: Address Line 2
|
||||
de: Adresszeile 2
|
||||
fr: "Ligne d'adresse 2"
|
||||
"no": Adresselinje 2
|
||||
charge-to-address3:
|
||||
en: Address Line 3
|
||||
de: Adresszeile 3
|
||||
fr: "Ligne d'adresse 3"
|
||||
"no": Adresselinje 3
|
||||
charge-to-address4:
|
||||
en: Address Line 4
|
||||
de: Adresszeile 4
|
||||
fr: "Ligne d'adresse 4"
|
||||
"no": Adresselinje 4
|
||||
charge-to-country:
|
||||
en: Country
|
||||
de: Land
|
||||
fr: Pays
|
||||
"no": Land
|
||||
charge-to-phone:
|
||||
en: Phone
|
||||
de: Telefon
|
||||
fr: Téléphone
|
||||
"no": Telefon
|
||||
charge-to-email:
|
||||
en: Email
|
||||
de: E-Mail
|
||||
fr: "E-mail"
|
||||
"no": E-post
|
||||
vat-id:
|
||||
en: VAT / Tax ID
|
||||
de: USt-IdNr.
|
||||
fr: "N° TVA / ID fiscal"
|
||||
"no": MVA-nummer
|
||||
invoice-date:
|
||||
en: Invoice date
|
||||
de: Rechnungsdatum
|
||||
fr: Date de facture
|
||||
"no": Fakturadato
|
||||
project-code:
|
||||
en: Project code
|
||||
de: Projektnummer
|
||||
fr: Code projet
|
||||
"no": Prosjektkode
|
||||
invoice-no:
|
||||
en: "Invoice no."
|
||||
de: "Rechnungsnr."
|
||||
fr: "N° de facture"
|
||||
"no": "Fakturanr."
|
||||
qty:
|
||||
en: QTY
|
||||
de: Menge
|
||||
fr: Qté
|
||||
"no": Ant.
|
||||
uom:
|
||||
en: UOM
|
||||
de: Einh.
|
||||
fr: UM
|
||||
"no": Enh.
|
||||
description:
|
||||
en: Description
|
||||
de: Beschreibung
|
||||
fr: Description
|
||||
"no": Beskrivelse
|
||||
price:
|
||||
en: Unit Price
|
||||
de: Einzelpreis
|
||||
fr: Prix unitaire
|
||||
"no": Enhetspris
|
||||
line-total:
|
||||
en: Line Total
|
||||
de: Betrag
|
||||
fr: Total ligne
|
||||
"no": Linjebeløp
|
||||
foreign-currency:
|
||||
en: Foreign currency
|
||||
de: Fremdwährung
|
||||
fr: Devise étrangère
|
||||
"no": Utenlandsk valuta
|
||||
currency-code:
|
||||
en: Currency code
|
||||
de: Währungscode
|
||||
fr: Code devise
|
||||
"no": Valutakode
|
||||
exchange-rate:
|
||||
en: "Exchange rate (1 foreign = X local)"
|
||||
de: "Wechselkurs (1 Fremd = X Inland)"
|
||||
fr: "Taux de change (1 étranger = X local)"
|
||||
"no": "Valutakurs (1 utenlandsk = X lokal)"
|
||||
per-item:
|
||||
en: Price per item (foreign currency)
|
||||
de: Preis je Einheit (Fremdwährung)
|
||||
fr: Prix par unité (devise étrangère)
|
||||
"no": Pris per enhet (utenlandsk valuta)
|
||||
total-local:
|
||||
en: Line total (local currency)
|
||||
de: Zeilenbetrag (Landeswährung)
|
||||
fr: Total ligne (devise locale)
|
||||
"no": Linjebeløp (lokal valuta)
|
||||
add-line:
|
||||
en: "+ Add new line"
|
||||
de: "+ Neue Zeile hinzufügen"
|
||||
fr: "+ Ajouter une ligne"
|
||||
"no": "+ Legg til ny linje"
|
||||
subtotal:
|
||||
en: Subtotal
|
||||
de: Zwischensumme
|
||||
fr: Sous-total
|
||||
"no": Delsum
|
||||
tax:
|
||||
en: Tax
|
||||
de: Steuer
|
||||
fr: Taxe
|
||||
"no": Mva
|
||||
paid:
|
||||
en: Paid
|
||||
de: Bezahlt
|
||||
fr: Payé
|
||||
"no": Betalt
|
||||
to-pay:
|
||||
en: To Pay
|
||||
de: Zu zahlen
|
||||
fr: À payer
|
||||
"no": Å betale
|
||||
generate-invoice:
|
||||
en: Generate Invoice
|
||||
de: Rechnung erstellen
|
||||
fr: Générer la facture
|
||||
"no": Generer faktura
|
||||
other:
|
||||
en: Other
|
||||
de: Andere
|
||||
fr: Autre
|
||||
"no": Annet
|
||||
select:
|
||||
en: "— Select —"
|
||||
de: "— Auswählen —"
|
||||
fr: "— Sélectionner —"
|
||||
"no": "— Velg —"
|
||||
yes:
|
||||
en: "Yes"
|
||||
de: "Ja"
|
||||
fr: "Oui"
|
||||
"no": "Ja"
|
||||
no-option:
|
||||
en: "No"
|
||||
de: "Nein"
|
||||
fr: "Non"
|
||||
"no": "Nei"
|
||||
print-invoice:
|
||||
en: "Print / Save as PDF"
|
||||
de: "Drucken / Als PDF speichern"
|
||||
fr: "Imprimer / Enregistrer en PDF"
|
||||
"no": "Skriv ut / Lagre som PDF"
|
||||
close:
|
||||
en: Close
|
||||
de: Schließen
|
||||
fr: Fermer
|
||||
"no": Lukk
|
||||
invoice-lines:
|
||||
en: Invoice Lines
|
||||
de: Rechnungspositionen
|
||||
fr: Lignes de facture
|
||||
"no": Fakturalinjer
|
||||
sender-section:
|
||||
en: From
|
||||
de: Von
|
||||
fr: De
|
||||
"no": Fra
|
||||
invoice-details-section:
|
||||
en: Invoice Details
|
||||
de: Rechnungsdetails
|
||||
fr: Détails de la facture
|
||||
"no": Fakturaopplysninger
|
||||
1233
app/index.html
Normal file
1233
app/index.html
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue