218 lines
7.7 KiB
Python
218 lines
7.7 KiB
Python
# barbacompta - invoicing for dummies
|
|
# Copyright (C) 2010-2020 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import datetime
|
|
import io
|
|
import xml.etree.ElementTree as ET
|
|
|
|
import facturx
|
|
import pytest
|
|
|
|
from eo_gestion.eo_facture.facturx import add_facturx_from_bytes, to_pdfa
|
|
|
|
|
|
@pytest.fixture
|
|
def fake_invoice_bytes():
|
|
with open('tests/fake-invoice.pdf', 'rb') as fd:
|
|
return fd.read()
|
|
|
|
|
|
def test_to_pdfa(fake_invoice_bytes):
|
|
to_pdfa(fake_invoice_bytes)
|
|
|
|
|
|
def test_add_facturx_from_bytes(fake_invoice_bytes):
|
|
facturx_ctx = {
|
|
'numero_de_facture': 'F20190001',
|
|
'type_facture': '380',
|
|
'date_emission': datetime.date(2019, 1, 1),
|
|
'chorus_service_code': 'service-code',
|
|
'vendeur': 'Entr\'ouvert',
|
|
'vendeur_siret': '44317013900036',
|
|
'vendeur_tvai': 'FR09491081899',
|
|
'client_siret': '1234',
|
|
'client_name': 'RGFIPD',
|
|
'numero_engagement': '5678',
|
|
'numero_marche': 'ABCD',
|
|
'montant_ht': '10',
|
|
'montant_ttc': '12',
|
|
'montant_tva': '2',
|
|
'taux_tva': 20.0,
|
|
}
|
|
facturx_bytes = add_facturx_from_bytes(fake_invoice_bytes, facturx_ctx)
|
|
_, xml_str = facturx.get_facturx_xml_from_pdf(io.BytesIO(facturx_bytes))
|
|
root = ET.fromstring(xml_str)
|
|
|
|
def helper(root):
|
|
tag = root.tag.split('}')[-1]
|
|
if len(root) == 0:
|
|
return [tag, root.text or '']
|
|
else:
|
|
return [tag] + [helper(node) for node in root]
|
|
|
|
assert helper(root) == [
|
|
'CrossIndustryInvoice',
|
|
[
|
|
'ExchangedDocumentContext',
|
|
['BusinessProcessSpecifiedDocumentContextParameter', ['ID', 'A1']],
|
|
['GuidelineSpecifiedDocumentContextParameter', ['ID', 'urn:factur-x.eu:1p0:basicwl']],
|
|
],
|
|
[
|
|
'ExchangedDocument',
|
|
['ID', 'F20190001'],
|
|
['TypeCode', '380'],
|
|
['IssueDateTime', ['DateTimeString', '20190101']],
|
|
],
|
|
[
|
|
'SupplyChainTradeTransaction',
|
|
[
|
|
'ApplicableHeaderTradeAgreement',
|
|
['BuyerReference', 'service-code'],
|
|
[
|
|
'SellerTradeParty',
|
|
['Name', "Entr'ouvert"],
|
|
['SpecifiedLegalOrganization', ['ID', '44317013900036']],
|
|
['PostalTradeAddress', ['CountryID', 'FR']],
|
|
['SpecifiedTaxRegistration', ['ID', 'FR09491081899']],
|
|
],
|
|
[
|
|
'BuyerTradeParty',
|
|
['Name', 'RGFIPD'],
|
|
[
|
|
'SpecifiedLegalOrganization',
|
|
['ID', '1234'],
|
|
],
|
|
],
|
|
['BuyerOrderReferencedDocument', ['IssuerAssignedID', '5678']],
|
|
['ContractReferencedDocument', ['IssuerAssignedID', 'ABCD']],
|
|
],
|
|
['ApplicableHeaderTradeDelivery', ''],
|
|
[
|
|
'ApplicableHeaderTradeSettlement',
|
|
['InvoiceCurrencyCode', 'EUR'],
|
|
[
|
|
'ApplicableTradeTax',
|
|
['CalculatedAmount', '2'],
|
|
['TypeCode', 'VAT'],
|
|
['BasisAmount', '10'],
|
|
['CategoryCode', 'S'],
|
|
['RateApplicablePercent', '20.0'],
|
|
],
|
|
[
|
|
'SpecifiedTradeSettlementHeaderMonetarySummation',
|
|
['LineTotalAmount', '10'],
|
|
['TaxBasisTotalAmount', '10'],
|
|
['TaxTotalAmount', '2'],
|
|
['GrandTotalAmount', '12'],
|
|
['DuePayableAmount', '12'],
|
|
],
|
|
],
|
|
],
|
|
]
|
|
|
|
|
|
def test_add_facturx_from_bytes_facture_avoir(fake_invoice_bytes):
|
|
facturx_ctx = {
|
|
'numero_de_facture': 'F20190002',
|
|
'type_facture': '381',
|
|
'date_emission': datetime.date(2019, 1, 1),
|
|
'chorus_service_code': 'service-code',
|
|
'vendeur': 'Entr\'ouvert',
|
|
'vendeur_siret': '44317013900036',
|
|
'vendeur_tvai': 'FR09491081899',
|
|
'client_siret': '1234',
|
|
'client_name': 'RGFIPD',
|
|
'numero_engagement': '5678',
|
|
'numero_marche': 'ABCD',
|
|
'montant_ht': '10',
|
|
'montant_ttc': '12',
|
|
'montant_tva': '2',
|
|
'taux_tva': 20.0,
|
|
'annulation_code': 'F20190001',
|
|
}
|
|
facturx_bytes = add_facturx_from_bytes(fake_invoice_bytes, facturx_ctx)
|
|
_, xml_str = facturx.get_facturx_xml_from_pdf(io.BytesIO(facturx_bytes))
|
|
root = ET.fromstring(xml_str)
|
|
|
|
def helper(root):
|
|
tag = root.tag.split('}')[-1]
|
|
if len(root) == 0:
|
|
return [tag, root.text or '']
|
|
else:
|
|
return [tag] + [helper(node) for node in root]
|
|
|
|
assert helper(root) == [
|
|
'CrossIndustryInvoice',
|
|
[
|
|
'ExchangedDocumentContext',
|
|
['BusinessProcessSpecifiedDocumentContextParameter', ['ID', 'A1']],
|
|
['GuidelineSpecifiedDocumentContextParameter', ['ID', 'urn:factur-x.eu:1p0:basicwl']],
|
|
],
|
|
[
|
|
'ExchangedDocument',
|
|
['ID', 'F20190002'],
|
|
['TypeCode', '381'],
|
|
['IssueDateTime', ['DateTimeString', '20190101']],
|
|
],
|
|
[
|
|
'SupplyChainTradeTransaction',
|
|
[
|
|
'ApplicableHeaderTradeAgreement',
|
|
['BuyerReference', 'service-code'],
|
|
[
|
|
'SellerTradeParty',
|
|
['Name', "Entr'ouvert"],
|
|
['SpecifiedLegalOrganization', ['ID', '44317013900036']],
|
|
['PostalTradeAddress', ['CountryID', 'FR']],
|
|
['SpecifiedTaxRegistration', ['ID', 'FR09491081899']],
|
|
],
|
|
[
|
|
'BuyerTradeParty',
|
|
['Name', 'RGFIPD'],
|
|
[
|
|
'SpecifiedLegalOrganization',
|
|
['ID', '1234'],
|
|
],
|
|
],
|
|
['BuyerOrderReferencedDocument', ['IssuerAssignedID', '5678']],
|
|
['ContractReferencedDocument', ['IssuerAssignedID', 'ABCD']],
|
|
],
|
|
['ApplicableHeaderTradeDelivery', ''],
|
|
[
|
|
'ApplicableHeaderTradeSettlement',
|
|
['InvoiceCurrencyCode', 'EUR'],
|
|
['SpecifiedTradeSettlementPaymentMeans', ['TypeCode', '97']],
|
|
[
|
|
'ApplicableTradeTax',
|
|
['CalculatedAmount', '2'],
|
|
['TypeCode', 'VAT'],
|
|
['BasisAmount', '10'],
|
|
['CategoryCode', 'S'],
|
|
['RateApplicablePercent', '20.0'],
|
|
],
|
|
[
|
|
'SpecifiedTradeSettlementHeaderMonetarySummation',
|
|
['LineTotalAmount', '10'],
|
|
['TaxBasisTotalAmount', '10'],
|
|
['TaxTotalAmount', '2'],
|
|
['GrandTotalAmount', '12'],
|
|
['DuePayableAmount', '12'],
|
|
],
|
|
['InvoiceReferencedDocument', ['IssuerAssignedID', 'F20190001']],
|
|
],
|
|
],
|
|
]
|