Bernd Wurst commited on 2025-03-12 11:43:24
Zeige 3 geänderte Dateien mit 28 Einfügungen und 14 Löschungen.
| ... | ... |
@@ -47,8 +47,8 @@ class InvoiceTable(object): |
| 47 | 47 |
'count': e['count'], |
| 48 | 48 |
'unit': e['unit'], |
| 49 | 49 |
'subject': e['subject'], |
| 50 |
- 'price': Decimal(e['price']), |
|
| 51 |
- 'total': Decimal(e['price'] * e['count']), |
|
| 50 |
+ 'price': e['price'], |
|
| 51 |
+ 'total': e['price'] * e['count'], |
|
| 52 | 52 |
'vat': Decimal(e['vat']), |
| 53 | 53 |
'tender': False, |
| 54 | 54 |
'print_date': True, |
| ... | ... |
@@ -149,9 +149,14 @@ def InvoiceToXML(invoice): |
| 149 | 149 |
|
| 150 | 150 |
# Line Items |
| 151 | 151 |
summe_netto = Decimal('0.0')
|
| 152 |
+ summe_brutto_rechnerisch = Decimal('0.0')
|
|
| 152 | 153 |
summe_brutto = Decimal('0.0')
|
| 153 | 154 |
summe_bezahlt = Decimal('0.0')
|
| 154 | 155 |
summe_ust = Decimal('0.0')
|
| 156 |
+ summe_rundung = Decimal('0.0')
|
|
| 157 |
+ # Problem: Die Rechnung muss netto gestellt werden. Wenn wir die Rechnungsposten brutto erfassen, ergibt sich ein Rundungsfehler. |
|
| 158 |
+ # Daher konvertieren wir die Line-Items in stimmige Netto-Items und erfassen für jeden Posten einen Rundungsbetrag, |
|
| 159 |
+ # um den wir abgewichen sind. |
|
| 155 | 160 |
line_id_count = 0 |
| 156 | 161 |
textparts = [] |
| 157 | 162 |
for part in invoice.parts: |
| ... | ... |
@@ -160,6 +165,9 @@ def InvoiceToXML(invoice): |
| 160 | 165 |
if isinstance(part, InvoiceTable): |
| 161 | 166 |
last_title = None |
| 162 | 167 |
for el in part.entries: |
| 168 |
+ from pprint import pprint |
|
| 169 |
+ pprint(el) |
|
| 170 |
+ |
|
| 163 | 171 |
if el['type'] == 'title': |
| 164 | 172 |
# Diese Information ist im XML nicht auf diese Weise darstellbar |
| 165 | 173 |
last_title = el['title'] |
| ... | ... |
@@ -186,7 +194,7 @@ def InvoiceToXML(invoice): |
| 186 | 194 |
for key, value in UNITS.items(): |
| 187 | 195 |
if el['unit'] in value: |
| 188 | 196 |
unit = key |
| 189 |
- li.delivery.billed_quantity = (Decimal(el['count']), unit) |
|
| 197 |
+ li.delivery.billed_quantity = (Decimal(f"{el['count']:.4f}"), unit)
|
|
| 190 | 198 |
# C62 = ohne Einheit |
| 191 | 199 |
# H87 = Stück |
| 192 | 200 |
# MON = Month, SEC = second, MIN = minute, HUR = hour, DAY = day, WEE = week, ANN = year |
| ... | ... |
@@ -211,23 +219,25 @@ def InvoiceToXML(invoice): |
| 211 | 219 |
# K = Intra-Community supply (specific reverse charge) |
| 212 | 220 |
# G = Exempt VAT for Export outside EU |
| 213 | 221 |
# O = Outside VAT scope |
| 214 |
- li.settlement.trade_tax.rate_applicable_percent = Decimal(f"{el['vat'] * 100:.1f}")
|
|
| 222 |
+ li.settlement.trade_tax.rate_applicable_percent = Decimal(f"{el['vat'] * 100:.2f}")
|
|
| 215 | 223 |
|
| 216 | 224 |
nettopreis = el['price'] |
| 217 | 225 |
if part.vatType == 'gross': |
| 218 |
- nettopreis = el['price'] / (1 + el['vat']) |
|
| 219 |
- li.agreement.net.amount = Decimal(f"{nettopreis:.2f}")
|
|
| 226 |
+ nettopreis = el['price'] / (el['vat'] + 1) |
|
| 227 |
+ nettopreis = round(nettopreis, 2) |
|
| 228 |
+ li.agreement.net.amount = nettopreis |
|
| 220 | 229 |
|
| 221 |
- nettosumme = el['total'] |
|
| 222 |
- if part.vatType == 'gross': |
|
| 223 |
- nettosumme = el['total'] / (1 + el['vat']) |
|
| 230 |
+ nettosumme = nettopreis * el['count'] |
|
| 224 | 231 |
li.settlement.monetary_summation.total_amount = Decimal(f"{nettosumme:.2f}")
|
| 225 | 232 |
|
| 233 |
+ brutto_rechnerisch = round(nettosumme * (el['vat'] + 1), 2) |
|
| 226 | 234 |
summe_netto += nettosumme |
| 227 | 235 |
if part.vatType == 'net': |
| 228 |
- summe_brutto += el['total'] * (1 + el['vat']) |
|
| 236 |
+ summe_brutto += el['total'] * (el['vat'] + 1) |
|
| 229 | 237 |
else: |
| 230 | 238 |
summe_brutto += el['total'] |
| 239 |
+ summe_brutto_rechnerisch += brutto_rechnerisch |
|
| 240 |
+ summe_rundung += (el['total'] - brutto_rechnerisch) |
|
| 231 | 241 |
doc.trade.items.add(li) |
| 232 | 242 |
|
| 233 | 243 |
for pay in part.payments: |
| ... | ... |
@@ -265,7 +275,6 @@ def InvoiceToXML(invoice): |
| 265 | 275 |
note.content.add(paragraph) |
| 266 | 276 |
doc.header.notes.add(note) |
| 267 | 277 |
|
| 268 |
- rest = summe_brutto - summe_bezahlt |
|
| 269 | 278 |
|
| 270 | 279 |
if invoice.creditor_reference_id: |
| 271 | 280 |
# Gläubiger-ID für SEPA |
| ... | ... |
@@ -298,13 +307,18 @@ def InvoiceToXML(invoice): |
| 298 | 307 |
terms.description = 'Wir buchen von Ihrem Konto ab.' |
| 299 | 308 |
doc.trade.settlement.terms.add(terms) |
| 300 | 309 |
|
| 310 |
+ summe_brutto = round(summe_brutto, 2) |
|
| 311 |
+ rest = summe_brutto - summe_bezahlt |
|
| 312 |
+ summe_netto = round(summe_netto, 2) |
|
| 313 |
+ summe_ust = round(summe_ust, 2) |
|
| 301 | 314 |
doc.trade.settlement.monetary_summation.line_total = Decimal(f"{summe_netto:.2f}")
|
| 302 | 315 |
doc.trade.settlement.monetary_summation.charge_total = Decimal("0.00")
|
| 303 | 316 |
doc.trade.settlement.monetary_summation.allowance_total = Decimal("0.00")
|
| 304 | 317 |
doc.trade.settlement.monetary_summation.tax_basis_total = Decimal(f"{summe_netto:.2f}")
|
| 305 | 318 |
doc.trade.settlement.monetary_summation.tax_total = (Decimal(f"{summe_ust:.2f}"), "EUR")
|
| 319 |
+ doc.trade.settlement.monetary_summation.grand_total = Decimal(f"{summe_brutto_rechnerisch:.2f}")
|
|
| 306 | 320 |
doc.trade.settlement.monetary_summation.prepaid_total = Decimal(f"{summe_bezahlt:.2f}")
|
| 307 |
- doc.trade.settlement.monetary_summation.grand_total = Decimal(f"{summe_brutto:.2f}")
|
|
| 321 |
+ doc.trade.settlement.monetary_summation.rounding_amount = summe_rundung |
|
| 308 | 322 |
doc.trade.settlement.monetary_summation.due_amount = Decimal(f"{rest:.2f}")
|
| 309 | 323 |
|
| 310 | 324 |
# Generate XML file |
| ... | ... |
@@ -94,8 +94,8 @@ if __name__ == '__main__': |
| 94 | 94 |
tab.addTitle("Zwischenüberschrift in der Tabelle")
|
| 95 | 95 |
for item in data: |
| 96 | 96 |
# Der Betrag muss immer positiv sein, bei Gutschriften wird nur die Anzahl negativ. |
| 97 |
- count = float(item['anzahl']) |
|
| 98 |
- price = float(item['betrag']) |
|
| 97 |
+ count = item['anzahl'] |
|
| 98 |
+ price = item['betrag'] |
|
| 99 | 99 |
if price < 0: |
| 100 | 100 |
count = -count |
| 101 | 101 |
price = abs(price) |
| 102 | 102 |