en16931 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68e50271df60f58d073c6fa0d95500a97b97619c524e7d678d44f2e3fb4860ac
4
- data.tar.gz: dee874aede98b65b9a4e9e99ed4c63a2e4a62978260bd469d41aea340621c7a5
3
+ metadata.gz: 82694745f476c409a9426718145ecf0a20ea7df0b43887c15367a6fee0ddb1a6
4
+ data.tar.gz: 7f5e45615e2cceaa50ea3533cd57a78bf844f78995ffeb04e20f1c3c01a9a296
5
5
  SHA512:
6
- metadata.gz: aee3a214e1ee51743bd4783c3021dd5fc0fcf6c7e68162dfcbaa5a61be926f93294e8b98b67ba10cb2b8130bc1e384de244edc4421bf148b5c50c70fbe1314cf
7
- data.tar.gz: 938665eec90c4c06e64f999b830b659669af1c9f68168cc45ecb6d96bb9968b78e9f3ab078a8f697b7fb099d896cfad79e0224e39d9c95c3b0f5e15c2db24766
6
+ metadata.gz: 2b46c041335e5ceb2d1085c3c5f4ad38973ad04ac0867085a48a3b36777fcd26cd749dee7e90a893dbabfc8734cb7d8864307b85dd9b842a754069bf2d61b68f
7
+ data.tar.gz: e7bf88692a48caa4c9d55baaf3f2b48f61bacd5561b14b5791708eb821f2f268771c2544be6b8d7b6df01b57c8164929d1ddcec5227cac3de9fb4a81702d8b56
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.2] - 2026-10-21
4
+
5
+ - Long payment terms no longer run under the GiroCode; beside it the payment block is narrower.
6
+
7
+ ## [0.1.1] - 2026-10-21
8
+
9
+ - The reference layout speaks 18 languages: German and English plus Czech, Danish, Spanish, Estonian, Finnish, French, Italian, Latvian, Dutch, Polish, Portuguese, Romanian, Russian, Swedish, Turkish and Chinese, each with its own number and date format.
10
+ - `PDF.render` no longer raises a `KeyError` for a locale the layout does not know; it falls back to German like the renderer does. Locales may be given as strings.
11
+ - Glyphs a branding font lacks are drawn with DejaVu Sans instead of the `.notdef` glyph, which PDF/A forbids.
12
+
3
13
  ## [0.1.0] - 2026-10-20
4
14
 
5
15
  - Invoice model with parties, lines, allowances and charges, payment details, periods and corrections.
data/README.md CHANGED
@@ -80,6 +80,8 @@ branding = EN16931::Branding.new(
80
80
  pdf = EN16931::PDF.render(invoice, branding:, locale: :de)
81
81
  ```
82
82
 
83
+ `locale:` sets the labels, number and date formats of the layout: `:de`, `:en`, `:cs`, `:da`, `:es`, `:et`, `:fi`, `:fr`, `:it`, `:lv`, `:nl`, `:pl`, `:pt`, `:ro`, `:ru`, `:sv`, `:tr` or `:zh` (a string works too; anything else falls back to German). DejaVu Sans covers every one of them but Chinese: for `:zh` pass a TrueType font with CJK glyphs as the branding font. Glyphs a branding font lacks, such as `€` in a subset, are taken from DejaVu Sans.
84
+
83
85
  `Branding.new` rejects what would break PDF/A at construction time: CMYK JPEGs, interlaced PNGs, unknown image data. The GiroCode is drawn as vectors, so it adds no raster image; it carries the holder, IBAN, BIC, the amount due and the payment reference (or the invoice title) and is left out when the invoice is not in euro, has no IBAN or nothing is due.
84
86
 
85
87
  ### Your own layout
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EN16931
4
+ module PDF
5
+ class Renderer
6
+ UNIT_CODES = %w[C62 HUR DAY MON LS E48].freeze
7
+
8
+ # The texts of the reference layout, one entry per locale. Keys are the
9
+ # same everywhere; units follow UNIT_CODES.
10
+ LABELS = {
11
+ de: { invoice: "Rechnung", credit_note: "Gutschrift", corrected: "Rechnungskorrektur", self_billed: "Gutschrift (Abrechnung durch den Leistungsempfänger)",
12
+ partial: "Teilrechnung", prepayment: "Anzahlungsrechnung",
13
+ number: "Rechnungsnummer", date: "Rechnungsdatum", due: "Fällig am", delivery: "Leistungsdatum", period: "Leistungszeitraum",
14
+ reference: "Ihre Referenz", preceding: "Zur Rechnung", pos: "Pos.", description: "Beschreibung", qty: "Menge", unit_price: "Einzelpreis",
15
+ net: "Netto", sum_net: "Summe netto", vat: "Umsatzsteuer", allowance: "Nachlass", charge: "Zuschlag", prepaid: "Bereits gezahlt",
16
+ gross: "Gesamtbetrag", payable: "Zahlbetrag", payment: "Zahlung", iban: "IBAN", bic: "BIC", holder: "Kontoinhaber",
17
+ reference_line: "Verwendungszweck", vat_id: "USt-IdNr.", tax_number: "Steuernummer", contact: "Kontakt",
18
+ giro_code: "GiroCode", units: %w[Stk. Std. Tage Monate pauschal Leistung] },
19
+ en: { invoice: "Invoice", credit_note: "Credit note", corrected: "Corrected invoice", self_billed: "Self-billed invoice",
20
+ partial: "Partial invoice", prepayment: "Prepayment invoice",
21
+ number: "Invoice number", date: "Invoice date", due: "Due date", delivery: "Delivery date", period: "Service period",
22
+ reference: "Your reference", preceding: "Refers to invoice", pos: "No.", description: "Description", qty: "Quantity", unit_price: "Unit price",
23
+ net: "Net", sum_net: "Total net", vat: "VAT", allowance: "Discount", charge: "Charge", prepaid: "Prepaid",
24
+ gross: "Total", payable: "Amount due", payment: "Payment", iban: "IBAN", bic: "BIC", holder: "Account holder",
25
+ reference_line: "Payment reference", vat_id: "VAT id", tax_number: "Tax number", contact: "Contact",
26
+ giro_code: "Scan to pay", units: ["pcs", "h", "days", "months", "lump sum", "service"] },
27
+ cs: { invoice: "Faktura", credit_note: "Dobropis", corrected: "Opravná faktura", self_billed: "Faktura vystavená odběratelem",
28
+ partial: "Dílčí faktura", prepayment: "Zálohová faktura",
29
+ number: "Číslo faktury", date: "Datum vystavení", due: "Datum splatnosti", delivery: "Datum plnění", period: "Období plnění",
30
+ reference: "Vaše reference", preceding: "K faktuře", pos: "Č.", description: "Popis", qty: "Množství", unit_price: "Jedn. cena",
31
+ net: "Bez DPH", sum_net: "Celkem bez DPH", vat: "DPH", allowance: "Sleva", charge: "Příplatek", prepaid: "Již zaplaceno",
32
+ gross: "Celkem", payable: "K úhradě", payment: "Platba", iban: "IBAN", bic: "BIC", holder: "Majitel účtu",
33
+ reference_line: "Účel platby", vat_id: "DIČ", tax_number: "Daňové číslo", contact: "Kontakt",
34
+ giro_code: "Naskenujte a zaplaťte", units: ["ks", "hod.", "dny", "měsíce", "paušál", "služba"] },
35
+ da: { invoice: "Faktura", credit_note: "Kreditnota", corrected: "Korrigeret faktura", self_billed: "Selvfakturering",
36
+ partial: "Delfaktura", prepayment: "Forudbetalingsfaktura",
37
+ number: "Fakturanummer", date: "Fakturadato", due: "Forfaldsdato", delivery: "Leveringsdato", period: "Leveringsperiode",
38
+ reference: "Jeres reference", preceding: "Vedrører faktura", pos: "Nr.", description: "Beskrivelse", qty: "Antal", unit_price: "Enhedspris",
39
+ net: "Netto", sum_net: "I alt netto", vat: "Moms", allowance: "Rabat", charge: "Tillæg", prepaid: "Allerede betalt",
40
+ gross: "I alt", payable: "Beløb til betaling", payment: "Betaling", iban: "IBAN", bic: "BIC", holder: "Kontohaver",
41
+ reference_line: "Betalingsreference", vat_id: "Momsnr.", tax_number: "Skattenummer", contact: "Kontakt",
42
+ giro_code: "Scan for at betale", units: ["stk.", "t.", "dage", "måneder", "samlet", "ydelse"] },
43
+ es: { invoice: "Factura", credit_note: "Nota de abono", corrected: "Factura rectificativa", self_billed: "Autofactura",
44
+ partial: "Factura parcial", prepayment: "Factura de anticipo",
45
+ number: "Número de factura", date: "Fecha de factura", due: "Fecha de vencimiento", delivery: "Fecha de entrega", period: "Período de servicio",
46
+ reference: "Su referencia", preceding: "Referente a la factura", pos: "N.º", description: "Descripción", qty: "Cantidad", unit_price: "Precio unitario",
47
+ net: "Neto", sum_net: "Total neto", vat: "IVA", allowance: "Descuento", charge: "Recargo", prepaid: "Ya pagado",
48
+ gross: "Total", payable: "Importe a pagar", payment: "Pago", iban: "IBAN", bic: "BIC", holder: "Titular de la cuenta",
49
+ reference_line: "Concepto", vat_id: "NIF-IVA", tax_number: "Número fiscal", contact: "Contacto",
50
+ giro_code: "Escanear para pagar", units: ["uds.", "h", "días", "meses", "global", "servicio"] },
51
+ et: { invoice: "Arve", credit_note: "Kreeditarve", corrected: "Parandatud arve", self_billed: "Ostja koostatud arve",
52
+ partial: "Osaarve", prepayment: "Ettemaksuarve",
53
+ number: "Arve number", date: "Arve kuupäev", due: "Maksetähtaeg", delivery: "Tarnekuupäev", period: "Teenuse periood",
54
+ reference: "Teie viide", preceding: "Seotud arvega", pos: "Nr", description: "Kirjeldus", qty: "Kogus", unit_price: "Ühikuhind",
55
+ net: "Neto", sum_net: "Kokku neto", vat: "Käibemaks", allowance: "Allahindlus", charge: "Lisatasu", prepaid: "Juba makstud",
56
+ gross: "Kokku", payable: "Tasumisele kuulub", payment: "Makse", iban: "IBAN", bic: "BIC", holder: "Konto omanik",
57
+ reference_line: "Selgitus", vat_id: "KMKR nr", tax_number: "Maksunumber", contact: "Kontakt",
58
+ giro_code: "Skanni ja maksa", units: %w[tk h päeva kuud ühekordne teenus] },
59
+ fi: { invoice: "Lasku", credit_note: "Hyvityslasku", corrected: "Korjattu lasku", self_billed: "Itselaskutus",
60
+ partial: "Osalasku", prepayment: "Ennakkolasku",
61
+ number: "Laskun numero", date: "Laskun päivämäärä", due: "Eräpäivä", delivery: "Toimituspäivä", period: "Suoritusjakso",
62
+ reference: "Viitteenne", preceding: "Koskee laskua", pos: "Nro", description: "Kuvaus", qty: "Määrä", unit_price: "Yksikköhinta",
63
+ net: "Netto", sum_net: "Yhteensä netto", vat: "ALV", allowance: "Alennus", charge: "Lisämaksu", prepaid: "Jo maksettu",
64
+ gross: "Yhteensä", payable: "Maksettava", payment: "Maksu", iban: "IBAN", bic: "BIC", holder: "Tilinhaltija",
65
+ reference_line: "Viesti", vat_id: "ALV-tunniste", tax_number: "Verotunniste", contact: "Yhteystiedot",
66
+ giro_code: "Skannaa ja maksa", units: %w[kpl h päivää kuukautta kertaerä palvelu] },
67
+ fr: { invoice: "Facture", credit_note: "Avoir", corrected: "Facture rectificative", self_billed: "Autofacturation",
68
+ partial: "Facture partielle", prepayment: "Facture d'acompte",
69
+ number: "Numéro de facture", date: "Date de facture", due: "Date d'échéance", delivery: "Date de livraison", period: "Période de prestation",
70
+ reference: "Votre référence", preceding: "Se rapporte à la facture", pos: "N°", description: "Désignation", qty: "Quantité", unit_price: "Prix unitaire",
71
+ net: "Net HT", sum_net: "Total HT", vat: "TVA", allowance: "Remise", charge: "Supplément", prepaid: "Déjà payé",
72
+ gross: "Total TTC", payable: "Montant à payer", payment: "Paiement", iban: "IBAN", bic: "BIC", holder: "Titulaire du compte",
73
+ reference_line: "Référence de paiement", vat_id: "N° TVA", tax_number: "N° fiscal", contact: "Contact",
74
+ giro_code: "Scanner pour payer", units: %w[pce h jours mois forfait prestation] },
75
+ it: { invoice: "Fattura", credit_note: "Nota di credito", corrected: "Fattura rettificativa", self_billed: "Autofattura",
76
+ partial: "Fattura parziale", prepayment: "Fattura di acconto",
77
+ number: "Numero fattura", date: "Data fattura", due: "Scadenza", delivery: "Data di consegna", period: "Periodo di prestazione",
78
+ reference: "Vostro riferimento", preceding: "Riferita alla fattura", pos: "N.", description: "Descrizione", qty: "Quantità", unit_price: "Prezzo unitario",
79
+ net: "Netto", sum_net: "Totale imponibile", vat: "IVA", allowance: "Sconto", charge: "Maggiorazione", prepaid: "Già pagato",
80
+ gross: "Totale", payable: "Importo da pagare", payment: "Pagamento", iban: "IBAN", bic: "BIC", holder: "Intestatario del conto",
81
+ reference_line: "Causale", vat_id: "Partita IVA", tax_number: "Codice fiscale", contact: "Contatto",
82
+ giro_code: "Scansiona per pagare", units: %w[pz h giorni mesi forfait prestazione] },
83
+ lv: { invoice: "Rēķins", credit_note: "Kredītrēķins", corrected: "Labots rēķins", self_billed: "Pircēja sagatavots rēķins",
84
+ partial: "Daļējs rēķins", prepayment: "Avansa rēķins",
85
+ number: "Rēķina numurs", date: "Rēķina datums", due: "Apmaksas termiņš", delivery: "Piegādes datums", period: "Pakalpojuma periods",
86
+ reference: "Jūsu atsauce", preceding: "Attiecas uz rēķinu", pos: "Nr.", description: "Apraksts", qty: "Daudzums", unit_price: "Vienības cena",
87
+ net: "Neto", sum_net: "Kopā neto", vat: "PVN", allowance: "Atlaide", charge: "Piemaksa", prepaid: "Jau samaksāts",
88
+ gross: "Kopā", payable: "Apmaksājamā summa", payment: "Maksājums", iban: "IBAN", bic: "BIC", holder: "Konta turētājs",
89
+ reference_line: "Maksājuma mērķis", vat_id: "PVN reģ. nr.", tax_number: "Nodokļu maksātāja nr.", contact: "Kontakti",
90
+ giro_code: "Skenējiet, lai samaksātu", units: ["gab.", "h", "dienas", "mēneši", "kopsumma", "pakalpojums"] },
91
+ nl: { invoice: "Factuur", credit_note: "Creditnota", corrected: "Gecorrigeerde factuur", self_billed: "Factuur opgemaakt door afnemer",
92
+ partial: "Deelfactuur", prepayment: "Voorschotfactuur",
93
+ number: "Factuurnummer", date: "Factuurdatum", due: "Vervaldatum", delivery: "Leverdatum", period: "Prestatieperiode",
94
+ reference: "Uw referentie", preceding: "Betreft factuur", pos: "Nr.", description: "Omschrijving", qty: "Aantal", unit_price: "Stukprijs",
95
+ net: "Netto", sum_net: "Totaal netto", vat: "Btw", allowance: "Korting", charge: "Toeslag", prepaid: "Reeds betaald",
96
+ gross: "Totaal", payable: "Te betalen", payment: "Betaling", iban: "IBAN", bic: "BIC", holder: "Rekeninghouder",
97
+ reference_line: "Betalingskenmerk", vat_id: "Btw-nr.", tax_number: "Fiscaal nummer", contact: "Contact",
98
+ giro_code: "Scan om te betalen", units: ["st.", "u", "dagen", "maanden", "forfaitair", "dienst"] },
99
+ pl: { invoice: "Faktura", credit_note: "Nota uznaniowa", corrected: "Faktura korygująca", self_billed: "Samofakturowanie",
100
+ partial: "Faktura częściowa", prepayment: "Faktura zaliczkowa",
101
+ number: "Numer faktury", date: "Data wystawienia", due: "Termin płatności", delivery: "Data dostawy", period: "Okres świadczenia",
102
+ reference: "Państwa referencja", preceding: "Dotyczy faktury", pos: "Lp.", description: "Opis", qty: "Ilość", unit_price: "Cena jedn.",
103
+ net: "Netto", sum_net: "Razem netto", vat: "VAT", allowance: "Rabat", charge: "Dopłata", prepaid: "Już zapłacono",
104
+ gross: "Razem", payable: "Do zapłaty", payment: "Płatność", iban: "IBAN", bic: "BIC", holder: "Właściciel rachunku",
105
+ reference_line: "Tytuł przelewu", vat_id: "Nr VAT", tax_number: "Numer podatkowy", contact: "Kontakt",
106
+ giro_code: "Zeskanuj, aby zapłacić", units: ["szt.", "godz.", "dni", "mies.", "ryczałt", "usługa"] },
107
+ pt: { invoice: "Fatura", credit_note: "Nota de crédito", corrected: "Fatura retificativa", self_billed: "Autofaturação",
108
+ partial: "Fatura parcial", prepayment: "Fatura de adiantamento",
109
+ number: "Número da fatura", date: "Data da fatura", due: "Data de vencimento", delivery: "Data de entrega", period: "Período de prestação",
110
+ reference: "A sua referência", preceding: "Referente à fatura", pos: "N.º", description: "Descrição", qty: "Quantidade", unit_price: "Preço unitário",
111
+ net: "Líquido", sum_net: "Total líquido", vat: "IVA", allowance: "Desconto", charge: "Acréscimo", prepaid: "Já pago",
112
+ gross: "Total", payable: "Valor a pagar", payment: "Pagamento", iban: "IBAN", bic: "BIC", holder: "Titular da conta",
113
+ reference_line: "Referência de pagamento", vat_id: "N.º IVA", tax_number: "Número fiscal", contact: "Contacto",
114
+ giro_code: "Digitalize para pagar", units: ["un.", "h", "dias", "meses", "valor global", "serviço"] },
115
+ ro: { invoice: "Factură", credit_note: "Notă de credit", corrected: "Factură de corecție", self_billed: "Autofactură",
116
+ partial: "Factură parțială", prepayment: "Factură de avans",
117
+ number: "Număr factură", date: "Data facturii", due: "Scadență", delivery: "Data livrării", period: "Perioada prestării",
118
+ reference: "Referința dvs.", preceding: "Se referă la factura", pos: "Nr.", description: "Descriere", qty: "Cantitate", unit_price: "Preț unitar",
119
+ net: "Net", sum_net: "Total net", vat: "TVA", allowance: "Reducere", charge: "Supliment", prepaid: "Deja plătit",
120
+ gross: "Total", payable: "De plată", payment: "Plată", iban: "IBAN", bic: "BIC", holder: "Titular cont",
121
+ reference_line: "Referință plată", vat_id: "Cod TVA", tax_number: "Cod fiscal", contact: "Contact",
122
+ giro_code: "Scanați pentru a plăti", units: ["buc.", "h", "zile", "luni", "forfetar", "serviciu"] },
123
+ ru: { invoice: "Счёт", credit_note: "Кредит-нота", corrected: "Исправленный счёт", self_billed: "Счёт, выставленный покупателем",
124
+ partial: "Частичный счёт", prepayment: "Счёт на предоплату",
125
+ number: "Номер счёта", date: "Дата счёта", due: "Срок оплаты", delivery: "Дата поставки", period: "Период оказания услуг",
126
+ reference: "Ваш референс", preceding: "К счёту", pos: "№", description: "Описание", qty: "Кол-во", unit_price: "Цена за ед.",
127
+ net: "Нетто", sum_net: "Итого нетто", vat: "НДС", allowance: "Скидка", charge: "Надбавка", prepaid: "Уже оплачено",
128
+ gross: "Итого", payable: "К оплате", payment: "Оплата", iban: "IBAN", bic: "BIC", holder: "Владелец счёта",
129
+ reference_line: "Назначение платежа", vat_id: "Номер НДС", tax_number: "Налоговый номер", contact: "Контакт",
130
+ giro_code: "Отсканируйте для оплаты", units: ["шт.", "ч", "дн.", "мес.", "паушально", "услуга"] },
131
+ sv: { invoice: "Faktura", credit_note: "Kreditfaktura", corrected: "Rättad faktura", self_billed: "Självfaktura",
132
+ partial: "Delfaktura", prepayment: "Förskottsfaktura",
133
+ number: "Fakturanummer", date: "Fakturadatum", due: "Förfallodatum", delivery: "Leveransdatum", period: "Leveransperiod",
134
+ reference: "Er referens", preceding: "Avser faktura", pos: "Nr", description: "Beskrivning", qty: "Antal", unit_price: "À-pris",
135
+ net: "Netto", sum_net: "Summa netto", vat: "Moms", allowance: "Rabatt", charge: "Tillägg", prepaid: "Redan betalt",
136
+ gross: "Totalt", payable: "Att betala", payment: "Betalning", iban: "IBAN", bic: "BIC", holder: "Kontoinnehavare",
137
+ reference_line: "Betalningsreferens", vat_id: "Momsreg.nr", tax_number: "Skattenummer", contact: "Kontakt",
138
+ giro_code: "Skanna för att betala", units: ["st", "tim", "dagar", "månader", "fast pris", "tjänst"] },
139
+ tr: { invoice: "Fatura", credit_note: "Alacak dekontu", corrected: "Düzeltilmiş fatura", self_billed: "Alıcı tarafından düzenlenen fatura",
140
+ partial: "Kısmi fatura", prepayment: "Ön ödeme faturası",
141
+ number: "Fatura numarası", date: "Fatura tarihi", due: "Son ödeme tarihi", delivery: "Teslim tarihi", period: "Hizmet dönemi",
142
+ reference: "Referansınız", preceding: "İlgili fatura", pos: "No", description: "Açıklama", qty: "Miktar", unit_price: "Birim fiyat",
143
+ net: "Net", sum_net: "Net toplam", vat: "KDV", allowance: "İndirim", charge: "Ek ücret", prepaid: "Ödenmiş",
144
+ gross: "Toplam", payable: "Ödenecek tutar", payment: "Ödeme", iban: "IBAN", bic: "BIC", holder: "Hesap sahibi",
145
+ reference_line: "Ödeme açıklaması", vat_id: "KDV no", tax_number: "Vergi numarası", contact: "İletişim",
146
+ giro_code: "Ödemek için tarayın", units: %w[adet sa gün ay götürü hizmet] },
147
+ # Chinese needs a font with CJK glyphs; pass one through Branding#font.
148
+ zh: { invoice: "发票", credit_note: "贷记单", corrected: "更正发票", self_billed: "买方自开发票",
149
+ partial: "部分发票", prepayment: "预付款发票",
150
+ number: "发票编号", date: "开票日期", due: "到期日", delivery: "交付日期", period: "服务期间",
151
+ reference: "您的参考号", preceding: "关联发票", pos: "序号", description: "描述", qty: "数量", unit_price: "单价",
152
+ net: "净额", sum_net: "净额合计", vat: "增值税", allowance: "折扣", charge: "附加费", prepaid: "已付款",
153
+ gross: "总计", payable: "应付金额", payment: "付款", iban: "IBAN", bic: "BIC", holder: "账户持有人",
154
+ reference_line: "付款附言", vat_id: "增值税号", tax_number: "税号", contact: "联系方式",
155
+ giro_code: "扫码付款", units: %w[件 小时 天 个月 一次性 服务] }
156
+ }.transform_values { |labels| labels.merge(units: UNIT_CODES.zip(labels[:units]).to_h).freeze }.freeze
157
+
158
+ # Thousands separator, decimal separator and date format per locale.
159
+ FORMATS = {
160
+ de: [".", ",", "%d.%m.%Y"], en: [",", ".", "%Y-%m-%d"], cs: [" ", ",", "%d.%m.%Y"], da: [".", ",", "%d.%m.%Y"],
161
+ es: [".", ",", "%d/%m/%Y"], et: [" ", ",", "%d.%m.%Y"], fi: [" ", ",", "%d.%m.%Y"], fr: [" ", ",", "%d/%m/%Y"],
162
+ it: [".", ",", "%d/%m/%Y"], lv: [" ", ",", "%d.%m.%Y"], nl: [".", ",", "%d-%m-%Y"], pl: [" ", ",", "%d.%m.%Y"],
163
+ pt: [".", ",", "%d/%m/%Y"], ro: [".", ",", "%d.%m.%Y"], ru: [" ", ",", "%d.%m.%Y"], sv: [" ", ",", "%Y-%m-%d"],
164
+ tr: [".", ",", "%d.%m.%Y"], zh: [",", ".", "%Y-%m-%d"]
165
+ }.freeze
166
+
167
+ # A supported locale as a symbol; anything unknown falls back to German.
168
+ def self.locale(value) = LABELS.key?(value&.to_sym) ? value.to_sym : :de
169
+ end
170
+ end
171
+ end
@@ -12,32 +12,14 @@ module EN16931
12
12
  # The recipient block starts 45 mm below the page top (DIN 5008 window), unless the letterhead runs deeper.
13
13
  ADDRESS_TOP = 45 * 72 / 25.4
14
14
  GIRO_CODE_SIZE = 68
15
- LABELS = {
16
- de: { invoice: "Rechnung", credit_note: "Gutschrift", corrected: "Rechnungskorrektur", self_billed: "Gutschrift (Abrechnung durch den Leistungsempfänger)",
17
- partial: "Teilrechnung", prepayment: "Anzahlungsrechnung",
18
- number: "Rechnungsnummer", date: "Rechnungsdatum", due: "Fällig am", delivery: "Leistungsdatum", period: "Leistungszeitraum",
19
- reference: "Ihre Referenz", preceding: "Zur Rechnung", pos: "Pos.", description: "Beschreibung", qty: "Menge", unit_price: "Einzelpreis",
20
- net: "Netto", sum_net: "Summe netto", vat: "Umsatzsteuer", allowance: "Nachlass", charge: "Zuschlag", prepaid: "Bereits gezahlt",
21
- gross: "Gesamtbetrag", payable: "Zahlbetrag", payment: "Zahlung", iban: "IBAN", bic: "BIC", holder: "Kontoinhaber",
22
- reference_line: "Verwendungszweck", vat_id: "USt-IdNr.", tax_number: "Steuernummer", contact: "Kontakt",
23
- giro_code: "GiroCode", units: { "C62" => "Stk.", "HUR" => "Std.", "DAY" => "Tage", "MON" => "Monate", "LS" => "pauschal", "E48" => "Leistung" } },
24
- en: { invoice: "Invoice", credit_note: "Credit note", corrected: "Corrected invoice", self_billed: "Self-billed invoice",
25
- partial: "Partial invoice", prepayment: "Prepayment invoice",
26
- number: "Invoice number", date: "Invoice date", due: "Due date", delivery: "Delivery date", period: "Service period",
27
- reference: "Your reference", preceding: "Refers to invoice", pos: "No.", description: "Description", qty: "Quantity", unit_price: "Unit price",
28
- net: "Net", sum_net: "Total net", vat: "VAT", allowance: "Discount", charge: "Charge", prepaid: "Prepaid",
29
- gross: "Total", payable: "Amount due", payment: "Payment", iban: "IBAN", bic: "BIC", holder: "Account holder",
30
- reference_line: "Payment reference", vat_id: "VAT id", tax_number: "Tax number", contact: "Contact",
31
- giro_code: "Scan to pay", units: { "C62" => "pcs", "HUR" => "h", "DAY" => "days", "MON" => "months", "LS" => "lump sum", "E48" => "service" } }
32
- }.freeze
33
15
 
34
16
  attr_reader :invoice, :locale, :branding
35
17
 
36
- def self.title(invoice, locale) = "#{LABELS.fetch(locale)[invoice.type]} #{invoice.number}"
18
+ def self.title(invoice, locale) = "#{LABELS.fetch(self.locale(locale))[invoice.type]} #{invoice.number}"
37
19
 
38
20
  def initialize(invoice, locale: :de, branding: Branding.new)
39
21
  @invoice = invoice
40
- @locale = LABELS.key?(locale) ? locale : :de
22
+ @locale = Renderer.locale(locale)
41
23
  @branding = branding
42
24
  @accent = branding.accent
43
25
  end
@@ -48,7 +30,11 @@ module EN16931
48
30
  def document
49
31
  @document ||= Prawn::Document.new(page_size: "A4", margin: [56, 50, 56, 50], compress: true, info: {}).tap do |pdf|
50
32
  pdf.font_families.update(FONT => { normal: EN16931.font_path("DejaVuSans.ttf"), bold: EN16931.font_path("DejaVuSans-Bold.ttf") })
51
- pdf.font_families.update(BRAND_FONT => branding.font) if branding.font
33
+ if branding.font
34
+ pdf.font_families.update(BRAND_FONT => branding.font)
35
+ # Glyphs the brand font lacks (often € in a subset) come from DejaVu, never as .notdef.
36
+ pdf.fallback_fonts([FONT])
37
+ end
52
38
  pdf.font(branding.font ? BRAND_FONT : FONT, size: 9.5)
53
39
  draw(pdf)
54
40
  end
@@ -184,20 +170,28 @@ module EN16931
184
170
  return if payment.nil?
185
171
 
186
172
  code_bottom = giro_code(pdf)
187
- pdf.text t(:payment), style: :bold
188
- pdf.move_down 3
189
- pdf.text payment.terms, size: 9 if payment.terms
173
+ # Beside the GiroCode the text keeps clear of it.
174
+ width = code_bottom ? pdf.bounds.width - GIRO_CODE_SIZE - 12 : pdf.bounds.width
175
+ pdf.bounding_box([pdf.bounds.left, pdf.cursor], width: width) do
176
+ pdf.text t(:payment), style: :bold
177
+ pdf.move_down 3
178
+ pdf.text payment.terms, size: 9 if payment.terms
179
+ payment_details(pdf, payment)
180
+ end
181
+ pdf.move_cursor_to [pdf.cursor, code_bottom].min if code_bottom
182
+ end
183
+
184
+ def payment_details(pdf, payment)
190
185
  rows = []
191
186
  rows << [t(:holder), payment.holder] if payment.holder
192
187
  rows << [t(:iban), payment.iban.scan(/.{1,4}/).join(" ")] if payment.iban
193
188
  rows << [t(:bic), payment.bic] if payment.bic
194
189
  rows << [t(:reference_line), payment.reference] if payment.reference
195
- unless rows.empty?
196
- pdf.table(rows, cell_style: { borders: [], padding: [2, 0], size: 9.5 }, column_widths: [130, 280]) do
197
- column(0).text_color = "666666"
198
- end
190
+ return if rows.empty?
191
+
192
+ pdf.table(rows, cell_style: { borders: [], padding: [2, 0], size: 9.5 }, column_widths: [130, 280]) do
193
+ column(0).text_color = "666666"
199
194
  end
200
- pdf.move_cursor_to [pdf.cursor, code_bottom].min if code_bottom
201
195
  end
202
196
 
203
197
  # The GiroCode floats at the right of the payment details and reports
@@ -249,12 +243,12 @@ module EN16931
249
243
  int, frac = text.split(".")
250
244
  frac = frac&.sub(/0+\z/, "") if decimals.min < decimals.max
251
245
  frac = nil if frac && frac.empty?
252
- sep = locale == :de ? [".", ","] : [",", "."]
246
+ sep = FORMATS.fetch(locale)
253
247
  int = int.reverse.scan(/\d{1,3}/).join(sep[0]).reverse
254
248
  [int, frac].compact.join(sep[1])
255
249
  end
256
250
 
257
- def date(d) = locale == :de ? d.strftime("%d.%m.%Y") : d.strftime("%Y-%m-%d")
251
+ def date(d) = d.strftime(FORMATS.fetch(locale)[2])
258
252
  def unit(code) = LABELS.fetch(locale)[:units].fetch(code, code)
259
253
 
260
254
  def country_name(code)
data/lib/en16931/pdf.rb CHANGED
@@ -6,6 +6,7 @@ require "prawn/table"
6
6
  require_relative "pdf/xmp"
7
7
  require_relative "pdf/giro_code"
8
8
  require_relative "pdf/a3"
9
+ require_relative "pdf/labels"
9
10
  require_relative "pdf/renderer"
10
11
 
11
12
  module EN16931
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EN16931
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: en16931
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schwed
@@ -108,6 +108,7 @@ files:
108
108
  - lib/en16931/pdf.rb
109
109
  - lib/en16931/pdf/a3.rb
110
110
  - lib/en16931/pdf/giro_code.rb
111
+ - lib/en16931/pdf/labels.rb
111
112
  - lib/en16931/pdf/renderer.rb
112
113
  - lib/en16931/pdf/xmp.rb
113
114
  - lib/en16931/tax.rb