diff --git a/eu_einvoice/european_e_invoice/doctype/e_invoice_import/e_invoice_import.json b/eu_einvoice/european_e_invoice/doctype/e_invoice_import/e_invoice_import.json index e6fe3ab..94bd47c 100644 --- a/eu_einvoice/european_e_invoice/doctype/e_invoice_import/e_invoice_import.json +++ b/eu_einvoice/european_e_invoice/doctype/e_invoice_import/e_invoice_import.json @@ -38,7 +38,8 @@ "items", "settlement_section", "currency", - "taxes" + "taxes", + "payment_terms" ], "fields": [ { @@ -249,6 +250,12 @@ "fieldtype": "Table", "label": "Taxes", "options": "E Invoice Trade Tax" + }, + { + "fieldname": "payment_terms", + "fieldtype": "Table", + "label": "Payment Terms", + "options": "E Invoice Payment Term" } ], "index_web_pages_for_search": 1, @@ -259,7 +266,7 @@ "link_fieldname": "e_invoice_import" } ], - "modified": "2024-09-26 21:07:31.840574", + "modified": "2024-10-01 16:00:37.256519", "modified_by": "Administrator", "module": "European e-Invoice", "name": "E Invoice Import", diff --git a/eu_einvoice/european_e_invoice/doctype/e_invoice_import/e_invoice_import.py b/eu_einvoice/european_e_invoice/doctype/e_invoice_import/e_invoice_import.py index 05d42e5..7a3e7db 100644 --- a/eu_einvoice/european_e_invoice/doctype/e_invoice_import/e_invoice_import.py +++ b/eu_einvoice/european_e_invoice/doctype/e_invoice_import/e_invoice_import.py @@ -16,6 +16,7 @@ if TYPE_CHECKING: from drafthorse.models.accounting import ApplicableTradeTax from drafthorse.models.party import PostalTradeAddress, TradeParty + from drafthorse.models.payment import PaymentTerms from drafthorse.models.tradelines import LineItem from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import PurchaseInvoice @@ -30,6 +31,9 @@ class EInvoiceImport(Document): from frappe.types import DF from eu_einvoice.european_e_invoice.doctype.e_invoice_item.e_invoice_item import EInvoiceItem + from eu_einvoice.european_e_invoice.doctype.e_invoice_payment_term.e_invoice_payment_term import ( + EInvoicePaymentTerm, + ) from eu_einvoice.european_e_invoice.doctype.e_invoice_trade_tax.e_invoice_trade_tax import ( EInvoiceTradeTax, ) @@ -47,6 +51,7 @@ class EInvoiceImport(Document): id: DF.Data | None issue_date: DF.Date | None items: DF.Table[EInvoiceItem] + payment_terms: DF.Table[EInvoicePaymentTerm] purchase_order: DF.Link | None seller_address_line_1: DF.Data | None seller_address_line_2: DF.Data | None @@ -121,6 +126,10 @@ def read_values_from_einvoice(self) -> None: for tax in doc.trade.settlement.trade_tax.children: self.parse_tax(tax) + self.payment_terms = [] + for term in doc.trade.settlement.terms.children: + self.parse_payment_term(term) + def parse_seller(self, seller: "TradeParty"): self.seller_name = str(seller.name) self.seller_tax_id = ( @@ -165,15 +174,30 @@ def parse_line_item(self, li: "LineItem"): item.billed_quantity = float(li.delivery.billed_quantity._amount) item.unit_code = str(li.delivery.billed_quantity._unit_code) item.net_rate = rate - item.tax_rate = float(li.settlement.trade_tax.rate_applicable_percent._value) + if li.settlement.trade_tax.rate_applicable_percent._value: + item.tax_rate = float(li.settlement.trade_tax.rate_applicable_percent._value) item.total_amount = float(li.settlement.monetary_summation.total_amount._value) def parse_tax(self, tax: "ApplicableTradeTax"): t = self.append("taxes") - t.basis_amount = float(tax.basis_amount._value) + t.basis_amount = float(tax.basis_amount._value or 0) or None t.rate_applicable_percent = float(tax.rate_applicable_percent._value) t.calculated_amount = float(tax.calculated_amount._value) + def parse_payment_term(self, term: "PaymentTerms"): + t = self.append("payment_terms") + t.due = term.due._value + partial_amount = [row[0] for row in term.partial_amount.children if row[1] == self.currency][0] + t.partial_amount = float(partial_amount) + t.description = term.description + t.discount_basis_date = term.discount_terms.basis_date_time._value + + if term.discount_terms.calculation_percent._value: + t.discount_calculation_percent = float(term.discount_terms.calculation_percent._value) + + if term.discount_terms.actual_amount._value: + t.discount_actual_amount = float(term.discount_terms.actual_amount._value) + def guess_supplier(self): if self.supplier: return @@ -237,9 +261,17 @@ def create_purchase_invoice(source_name, target_doc=None): def post_process(source, target: "PurchaseInvoice"): target.set_missing_values() - def process_tax_row(source, target, source_parent): + def process_tax_row(source, target, source_parent) -> None: target.charge_type = "Actual" + def process_payment_term(source, target, source_parent): + if source.discount_calculation_percent: + target.discount_type = "Percentage" + target.discount = source.discount_calculation_percent + elif source.discount_actual_amount: + target.discount_type = "Amount" + target.discount = source.discount_actual_amount + return get_mapped_doc( "E Invoice Import", source_name, @@ -274,6 +306,16 @@ def process_tax_row(source, target, source_parent): }, "postprocess": process_tax_row, }, + "E Invoice Payment Term": { + "doctype": "Payment Schedule", + "field_map": { + "due": "due_date", + "partial_amount": "payment_amount", + "description": "description", + "discount_basis_date": "discount_date", + }, + "postprocess": process_payment_term, + }, }, target_doc, post_process, diff --git a/eu_einvoice/european_e_invoice/doctype/e_invoice_payment_term/__init__.py b/eu_einvoice/european_e_invoice/doctype/e_invoice_payment_term/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/eu_einvoice/european_e_invoice/doctype/e_invoice_payment_term/e_invoice_payment_term.json b/eu_einvoice/european_e_invoice/doctype/e_invoice_payment_term/e_invoice_payment_term.json new file mode 100644 index 0000000..77663d7 --- /dev/null +++ b/eu_einvoice/european_e_invoice/doctype/e_invoice_payment_term/e_invoice_payment_term.json @@ -0,0 +1,71 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2024-10-01 15:54:37.279431", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "due", + "partial_amount", + "section_break_mgef", + "discount_basis_date", + "discount_calculation_percent", + "discount_actual_amount" + ], + "fields": [ + { + "fieldname": "due", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Due", + "read_only": 1, + "reqd": 1 + }, + { + "fieldname": "partial_amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Partial Amount", + "options": "currency", + "read_only": 1, + "reqd": 1 + }, + { + "fieldname": "section_break_mgef", + "fieldtype": "Section Break", + "label": "Discount" + }, + { + "fieldname": "discount_basis_date", + "fieldtype": "Date", + "label": "Basis Date", + "read_only": 1 + }, + { + "fieldname": "discount_calculation_percent", + "fieldtype": "Percent", + "label": "Calculation Percent", + "read_only": 1 + }, + { + "fieldname": "discount_actual_amount", + "fieldtype": "Currency", + "label": "Actual Amount", + "options": "currency", + "read_only": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2024-10-01 16:25:06.974472", + "modified_by": "Administrator", + "module": "European e-Invoice", + "name": "E Invoice Payment Term", + "owner": "Administrator", + "permissions": [], + "sort_field": "creation", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/eu_einvoice/european_e_invoice/doctype/e_invoice_payment_term/e_invoice_payment_term.py b/eu_einvoice/european_e_invoice/doctype/e_invoice_payment_term/e_invoice_payment_term.py new file mode 100644 index 0000000..f694a49 --- /dev/null +++ b/eu_einvoice/european_e_invoice/doctype/e_invoice_payment_term/e_invoice_payment_term.py @@ -0,0 +1,27 @@ +# Copyright (c) 2024, ALYF GmbH and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class EInvoicePaymentTerm(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + discount_actual_amount: DF.Currency + discount_basis_date: DF.Date | None + discount_calculation_percent: DF.Percent + due: DF.Date + parent: DF.Data + parentfield: DF.Data + parenttype: DF.Data + partial_amount: DF.Currency + # end: auto-generated types + + pass