Files

274 lines
9.7 KiB
Python
Raw Permalink Normal View History

2026-02-25 10:24:12 +01:00
from invoice_base import *
class Invoice(BaseInvoice):
def __str__(self):
taxestotal = ''
for x in self.taxes:
taxestotal += str(x)
allarticles = ''
for a in self.articles:
allarticles += str(a)
alltenders = ''
for t in self.tenders:
alltenders += str(t)
xml = f'''<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>{self.nr}</cbc:ID>
<cbc:IssueDate>{self.receipt.year}-{self.receipt.month}-{self.receipt.day}</cbc:IssueDate>
<cbc:DueDate>{self.receipt.year}-{self.receipt.month}-{self.receipt.day}</cbc:DueDate>
<cbc:InvoiceTypeCode>388</cbc:InvoiceTypeCode> <!-- invoice for tax purposes -->
<cbc:DocumentCurrencyCode>{self.currency()}</cbc:DocumentCurrencyCode>
<!--cbc:AccountingCost>4025:123:4343</cbc:AccountingCost-->
<cbc:BuyerReference>{self.receipt.store}{self.receipt.year}{self.receipt.month}{self.receipt.day}{self.receipt.till}{self.receipt.seq.zfill(6)}</cbc:BuyerReference>
{self.seller}
{self.buyer}
{alltenders}
<cac:PaymentTerms>
<cbc:Note>{self.receipt.year}-{self.receipt.month}-{self.receipt.day}</cbc:Note>
</cac:PaymentTerms>
{self.totals}
<cac:TaxTotal>
<cbc:TaxAmount currencyID="{self.currency()}">{self.total_taxes():.2f}</cbc:TaxAmount>
{taxestotal}
</cac:TaxTotal>
{allarticles}
</Invoice>
'''
result = ""
result += xml
# if self.seller:
# result += str(self.seller)
# else:
# result += "[ == no country / PVH-ofice found ==]\n"
# if self.buyer:
# result += str(self.buyer)
# for a in self.articles:
# result += str(a)
# for t in self.tenders:
# result += str(t)
return result
class Discount(BaseDiscount):
def __str__(self):
return f'''
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>95</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>{self.promotionID}</cbc:AllowanceChargeReason>
<cbc:Amount currencyID="{self.currency()}">{self.net_amount():.2f}</cbc:Amount>
</cac:AllowanceCharge>
'''
class Tax(BaseTax):
spaces = 'tax'
#### TODO translation pls note self.country is always XX
def translated_group(self):
result = 'S' # peppol: S: standard
p = float(self.percentage)
if p < 18.0:
result = 'AA' # lower rate
if p <0.01:
result = 'E' # zero rate
return result
def __str__(self):
return f"{self.spaces},{self.typesubtype},{self.code},{self.amount},{self.percentage}%,{self.translated_group()},{self.taxableamount}\n"
class TotalTax(Tax):
def __str__(self):
return f'''
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="{self.currency()}">{self.taxableamount:.2f}</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="{self.currency()}">{self.amount:.2f}</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>{self.translated_group()}</cbc:ID>
<cbc:Percent>{self.percentage}</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
'''
class Header(BaseHeader):
pass
class Totals(BaseTotals):
def __str__(self):
return f'''
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="{self.currency()}">{self.netAmount:.2f}</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="{self.currency()}">{self.netAmount:.2f}</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="{self.currency()}">{self.grandAmount:.2f}</cbc:TaxInclusiveAmount>
<!--cbc:ChargeTotalAmount currencyID="{self.currency()}">0</cbc:ChargeTotalAmount-->
<cbc:PayableAmount currencyID="{self.currency()}">{self.grandAmount:.2f}</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
'''
class Receipt(BaseReceipt):
pass
class Buyer(BaseBuyer):
def __str__(self):
return f'''
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="{self.scheme}">{self.orgid}</cbc:EndpointID>
<!--cac:PartyIdentification>
<cbc:ID schemeID="0002">FR23342</cbc:ID>
</cac:PartyIdentification-->
<cac:PartyName>
<cbc:Name>{self.name}</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>{self.street1}</cbc:StreetName>
<cbc:AdditionalStreetName>{self.street2}</cbc:AdditionalStreetName>
<cbc:CityName>{self.city}</cbc:CityName>
<cbc:PostalZone>{self.zip}</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>{self.country}</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>{self.taxID}</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>tax</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>{self.name}</cbc:RegistrationName>
<cbc:CompanyID schemeID="0183">{self.orgid}</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>{self.name}</cbc:Name>
<cbc:Telephone>{self.phone}</cbc:Telephone>
<cbc:ElectronicMail>{self.email}</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingCustomerParty>
'''
class Delivery():
pass
class Seller(BaseSeller):
def __str__(self):
return f'''
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="{self.scheme}">{self.orgid}</cbc:EndpointID>
<!--cac:PartyIdentification>
<cbc:ID>99887766</cbc:ID>
</cac:PartyIdentification-->
<cac:PartyName>
<cbc:Name>{self.name}</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>{self.street1}</cbc:StreetName>
<cbc:AdditionalStreetName>{self.street2}</cbc:AdditionalStreetName>
<cbc:CityName>{self.city}</cbc:CityName>
<cbc:PostalZone>{self.zip}</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>{self.country}</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>{self.taxID}</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>tax</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>{self.name}</cbc:RegistrationName>
<cbc:CompanyID>{self.orgid}</cbc:CompanyID>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingSupplierParty>
'''
class Tender(BaseTender):
def translate(self, code):
return '54' # credit card
def __str__(self):
return f'''
<cac:PaymentMeans>
<cbc:PaymentMeansCode name="{self.description}">{self.type}</cbc:PaymentMeansCode>
<!--cbc:PaymentID></cbc:PaymentID>
<cac:PayeeFinancialAccount>
<cbc:ID></cbc:ID>
<cbc:Name></cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID></cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount-->
</cac:PaymentMeans>
'''
class Article(BaseArticle):
def __str__(self):
discounts = ''
for d in self.discounts:
discounts += str(d)
return f'''
<cac:InvoiceLine>
<cbc:ID>{self.sequence}</cbc:ID>
<cbc:InvoicedQuantity unitCode="H87">{'-' if self.returnflag else ''}{self.quantity}</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="{self.currency()}">{'-' if self.returnflag else ''}{self.netSalesPrice():.2f}</cbc:LineExtensionAmount>
<!--cbc:AccountingCost>Konteringsstreng</cbc:AccountingCost-->
<!--cac:OrderLineReference>
<cbc:LineID>123</cbc:LineID>
</cac:OrderLineReference -->
{discounts}
<cac:Item>
<cbc:Description>{self.description}</cbc:Description>
<cbc:Name>{self.description}</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>{self.itemid}</cbc:ID>
</cac:SellersItemIdentification>
<!-- cac:StandardItemIdentification>
<cbc:ID schemeID="0088">21382183120983</cbc:ID>
</cac:StandardItemIdentification -->
<!-- cac:OriginCountry>
<cbc:IdentificationCode>NO</cbc:IdentificationCode>
</cac:OriginCountry -->
<cac:CommodityClassification>
<cbc:ItemClassificationCode listID="AL">{self.upc}</cbc:ItemClassificationCode>
</cac:CommodityClassification>
<cac:ClassifiedTaxCategory>
<cbc:ID>{self.tax.translated_group()}</cbc:ID>
<cbc:Percent>{self.tax.percentage}</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="{self.currency()}">{self.netBasePrice():.2f}</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
'''