diff --git a/server/vbv_lernwelt/shop/invoice/abacus.py b/server/vbv_lernwelt/shop/invoice/abacus.py
index 697f5b15..2725e8ee 100644
--- a/server/vbv_lernwelt/shop/invoice/abacus.py
+++ b/server/vbv_lernwelt/shop/invoice/abacus.py
@@ -1,5 +1,4 @@
import datetime
-from typing import List
from uuid import uuid4
from xml.dom import minidom
from xml.etree.ElementTree import Element, SubElement, tostring
@@ -44,120 +43,165 @@ class AbacusInvoiceCreator(InvoiceCreator):
self.repository.upload_invoice(invoice, filename)
- def create_invoice_xml(self, checkout_information: CheckoutInformation):
- pass
- @staticmethod
- def render_invoice_xml(
- abacus_debitor_number: int,
- abacus_order_id: int,
- datatrans_transaction_id: str,
- order_date: datetime.date,
- item_description: str,
- ) -> str:
- container = Element("AbaConnectContainer")
- task = SubElement(container, "Task")
- parameter = SubElement(task, "Parameter")
- SubElement(parameter, "Application").text = "ORDE"
- SubElement(parameter, "Id").text = "Verkaufsauftrag"
- SubElement(parameter, "MapId").text = "AbaDefault"
- SubElement(parameter, "Version").text = "2022.00"
+def create_invoice_xml(checkout_information: CheckoutInformation):
+ # set fill abacus numbers
+ checkout_information = checkout_information.set_increment_abacus_order_id()
+ customer = checkout_information.user.set_increment_abacus_debitor_number()
- transaction = SubElement(task, "Transaction")
- sales_order_header = SubElement(transaction, "SalesOrderHeader", mode="SAVE")
- sales_order_header_fields = SubElement(
- sales_order_header, "SalesOrderHeaderFields", mode="SAVE"
- )
+ invoice_xml_content = render_invoice_xml(
+ abacus_debitor_number=customer.abacus_debitor_number,
+ abacus_order_id=checkout_information.abacus_order_id,
+ datatrans_transaction_id=checkout_information.transaction_id,
+ order_date=checkout_information.created_at.date(),
+ # TODO was ist der korrekte text für die item_description?
+ item_description=f"{checkout_information.product_name} - {checkout_information.created_at.date().isoformat()} - {checkout_information.user.last_name} {checkout_information.user.first_name}",
+ )
- # Skender: Kundennummer, erste Ziffer abhängig von der Plattform (4 = LMS, 6 = myVBV, 7 = EduManager), Plattform führt ein eigenständiges hochzählendes Mapping.
- SubElement(sales_order_header_fields, "CustomerNumber").text = str(
- abacus_debitor_number
- )
+ # YYYYMMDDhhmmss
+ filename_datetime = checkout_information.created_at.strftime("%Y%m%d%H%M%S")
+ invoice_xml_filename = f"myVBV_orde_{customer.abacus_debitor_number}_{filename_datetime}_{checkout_information.abacus_order_id}.xml"
- # Skender: ePayment: Ablaufnr. für ePayment Rechnung in Abacus
- SubElement(sales_order_header_fields, "ProcessFlowNumber").text = "30"
+ return invoice_xml_filename, invoice_xml_content
- # Skender: ePayment: Zahlungskondition für ePaymente in Abacus 9999 Tage Mahnungsfrist, da schon bezahlt
- SubElement(sales_order_header_fields, "PaymentCode").text = "9999"
- # Skender: Bestellzeitpunkt
- SubElement(
- sales_order_header_fields, "PurchaseOrderDate"
- ).text = order_date.isoformat()
+def create_customer_xml(checkout_information: CheckoutInformation):
+ customer = checkout_information.user.set_increment_abacus_debitor_number()
- # Skender: ePayment: TRANSACTION-ID von Datatrans in Bestellreferenz
- SubElement(
- sales_order_header_fields, "ReferencePurchaseOrder"
- ).text = datatrans_transaction_id
+ customer_xml_content = render_customer_xml(
+ abacus_debitor_number=customer.abacus_debitor_number,
+ last_name=checkout_information.last_name,
+ first_name=checkout_information.first_name,
+ company_name=checkout_information.company_name,
+ street=(checkout_information.company_street or checkout_information.street),
+ house_number=(
+ checkout_information.company_street_number
+ or checkout_information.street_number
+ ),
+ zip_code=(
+ checkout_information.company_postal_code or checkout_information.postal_code
+ ),
+ city=(checkout_information.company_city or checkout_information.city),
+ country=(checkout_information.company_country or checkout_information.country),
+ language=customer.language,
+ email=customer.email,
+ )
- # Skender: ePayment: OrderID. max 10 Ziffern, erste Ziffer abhängig von der Plattform (4 = LMS, 6 = myVBV, 7 = EduManager)
- SubElement(sales_order_header_fields, "GroupingNumberAscii1").text = str(
- abacus_order_id
- )
+ customer_xml_filename = f"myVBV_debi_{customer.abacus_debitor_number}.xml"
- item_element = SubElement(sales_order_header, "Item", mode="SAVE")
- item_fields = SubElement(item_element, "ItemFields", mode="SAVE")
- SubElement(item_fields, "DeliveryDate").text = order_date.isoformat()
- SubElement(item_fields, "ItemNumber").text = "1"
- SubElement(item_fields, "ProductNumber").text = "30202"
- SubElement(item_fields, "QuantityOrdered").text = "1"
+ return customer_xml_filename, customer_xml_content
- item_text = SubElement(item_element, "ItemText", mode="SAVE")
- item_text_fields = SubElement(item_text, "ItemTextFields", mode="SAVE")
- SubElement(item_text_fields, "Text").text = item_description
- return AbacusInvoiceCreator.create_xml_string(container)
+def render_invoice_xml(
+ abacus_debitor_number: int,
+ abacus_order_id: int,
+ datatrans_transaction_id: str,
+ order_date: datetime.date,
+ item_description: str,
+) -> str:
+ container = Element("AbaConnectContainer")
+ task = SubElement(container, "Task")
+ parameter = SubElement(task, "Parameter")
+ SubElement(parameter, "Application").text = "ORDE"
+ SubElement(parameter, "Id").text = "Verkaufsauftrag"
+ SubElement(parameter, "MapId").text = "AbaDefault"
+ SubElement(parameter, "Version").text = "2022.00"
- @staticmethod
- def render_customer_xml(
- abacus_debitor_number: int,
- last_name: str,
- first_name: str,
- company_name: str,
- street: str,
- house_number: str,
- zip_code: str,
- city: str,
- country: str,
- language: str,
- email: str,
- ):
- container = Element("AbaConnectContainer")
- task = SubElement(container, "Task")
+ transaction = SubElement(task, "Transaction")
+ sales_order_header = SubElement(transaction, "SalesOrderHeader", mode="SAVE")
+ sales_order_header_fields = SubElement(
+ sales_order_header, "SalesOrderHeaderFields", mode="SAVE"
+ )
- parameter = SubElement(task, "Parameter")
- SubElement(parameter, "Application").text = "DEBI"
- SubElement(parameter, "ID").text = "Kunden"
- SubElement(parameter, "MapID").text = "AbaDefault"
- SubElement(parameter, "Version").text = "2022.00"
+ # Skender: Kundennummer, erste Ziffer abhängig von der Plattform (4 = LMS, 6 = myVBV, 7 = EduManager), Plattform führt ein eigenständiges hochzählendes Mapping.
+ SubElement(sales_order_header_fields, "CustomerNumber").text = str(
+ abacus_debitor_number
+ )
- transaction = SubElement(task, "Transaction")
- customer_element = SubElement(transaction, "Customer", mode="SAVE")
+ # Skender: ePayment: Ablaufnr. für ePayment Rechnung in Abacus
+ SubElement(sales_order_header_fields, "ProcessFlowNumber").text = "30"
- SubElement(customer_element, "CustomerNumber").text = str(abacus_debitor_number)
- SubElement(customer_element, "DefaultCurrency").text = "CHF"
- SubElement(customer_element, "PaymentTermNumber").text = "1"
- SubElement(customer_element, "ReminderProcedure").text = "NORM"
+ # Skender: ePayment: Zahlungskondition für ePaymente in Abacus 9999 Tage Mahnungsfrist, da schon bezahlt
+ SubElement(sales_order_header_fields, "PaymentCode").text = "9999"
- address_data = SubElement(customer_element, "AddressData", mode="SAVE")
- SubElement(address_data, "AddressNumber").text = str(abacus_debitor_number)
- SubElement(address_data, "Name").text = last_name
- SubElement(address_data, "FirstName").text = first_name
- SubElement(address_data, "Text").text = company_name
- SubElement(address_data, "Street").text = street
- SubElement(address_data, "HouseNumber").text = house_number
- SubElement(address_data, "ZIP").text = zip_code
- SubElement(address_data, "City").text = city
- SubElement(address_data, "Country").text = country
- SubElement(address_data, "Language").text = language
- SubElement(address_data, "Email").text = email
+ # Skender: Bestellzeitpunkt
+ SubElement(
+ sales_order_header_fields, "PurchaseOrderDate"
+ ).text = order_date.isoformat()
- return AbacusInvoiceCreator.create_xml_string(container)
+ # Skender: ePayment: TRANSACTION-ID von Datatrans in Bestellreferenz
+ SubElement(
+ sales_order_header_fields, "ReferencePurchaseOrder"
+ ).text = datatrans_transaction_id
- @staticmethod
- def create_xml_string(container: Element, encoding: str = "utf-8") -> str:
- xml_bytes = tostring(container, encoding)
- xml_pretty_str = minidom.parseString(xml_bytes).toprettyxml(
- indent=" ", encoding=encoding
- )
- return xml_pretty_str.decode(encoding)
+ # Skender: ePayment: OrderID. max 10 Ziffern, erste Ziffer abhängig von der Plattform (4 = LMS, 6 = myVBV, 7 = EduManager)
+ SubElement(sales_order_header_fields, "GroupingNumberAscii1").text = str(
+ abacus_order_id
+ )
+
+ item_element = SubElement(sales_order_header, "Item", mode="SAVE")
+ item_fields = SubElement(item_element, "ItemFields", mode="SAVE")
+ SubElement(item_fields, "DeliveryDate").text = order_date.isoformat()
+ SubElement(item_fields, "ItemNumber").text = "1"
+ SubElement(item_fields, "ProductNumber").text = "30202"
+ SubElement(item_fields, "QuantityOrdered").text = "1"
+
+ item_text = SubElement(item_element, "ItemText", mode="SAVE")
+ item_text_fields = SubElement(item_text, "ItemTextFields", mode="SAVE")
+ SubElement(item_text_fields, "Text").text = item_description
+
+ return create_xml_string(container)
+
+
+def render_customer_xml(
+ abacus_debitor_number: int,
+ last_name: str,
+ first_name: str,
+ company_name: str,
+ street: str,
+ house_number: str,
+ zip_code: str,
+ city: str,
+ country: str,
+ language: str,
+ email: str,
+):
+ container = Element("AbaConnectContainer")
+ task = SubElement(container, "Task")
+
+ parameter = SubElement(task, "Parameter")
+ SubElement(parameter, "Application").text = "DEBI"
+ SubElement(parameter, "ID").text = "Kunden"
+ SubElement(parameter, "MapID").text = "AbaDefault"
+ SubElement(parameter, "Version").text = "2022.00"
+
+ transaction = SubElement(task, "Transaction")
+ customer_element = SubElement(transaction, "Customer", mode="SAVE")
+
+ SubElement(customer_element, "CustomerNumber").text = str(abacus_debitor_number)
+ SubElement(customer_element, "DefaultCurrency").text = "CHF"
+ SubElement(customer_element, "PaymentTermNumber").text = "1"
+ SubElement(customer_element, "ReminderProcedure").text = "NORM"
+
+ address_data = SubElement(customer_element, "AddressData", mode="SAVE")
+ SubElement(address_data, "AddressNumber").text = str(abacus_debitor_number)
+ SubElement(address_data, "Name").text = last_name
+ SubElement(address_data, "FirstName").text = first_name
+ SubElement(address_data, "Text").text = company_name
+ SubElement(address_data, "Street").text = street
+ SubElement(address_data, "HouseNumber").text = house_number
+ SubElement(address_data, "ZIP").text = zip_code
+ SubElement(address_data, "City").text = city
+ SubElement(address_data, "Country").text = country
+ SubElement(address_data, "Language").text = language
+ SubElement(address_data, "Email").text = email
+
+ return create_xml_string(container)
+
+
+def create_xml_string(container: Element, encoding: str = "utf-8") -> str:
+ xml_bytes = tostring(container, encoding)
+ xml_pretty_str = minidom.parseString(xml_bytes).toprettyxml(
+ indent=" ", encoding=encoding
+ )
+ return xml_pretty_str.decode(encoding)
diff --git a/server/vbv_lernwelt/shop/tests/factories.py b/server/vbv_lernwelt/shop/tests/factories.py
index f8396de9..17869a68 100644
--- a/server/vbv_lernwelt/shop/tests/factories.py
+++ b/server/vbv_lernwelt/shop/tests/factories.py
@@ -11,3 +11,5 @@ class CheckoutInformationFactory(DjangoModelFactory):
product_sku = VV_DE_PRODUCT_SKU
product_price = 324_30
state = CheckoutState.PAID
+ product_name = "Versicherungsvermittler/-in VBV"
+ product_description = "Versicherungsvermittler/-in VBV DE"
diff --git a/server/vbv_lernwelt/shop/tests/test_invoice.py b/server/vbv_lernwelt/shop/tests/test_invoice.py
index 15c9c661..48ac5f4d 100644
--- a/server/vbv_lernwelt/shop/tests/test_invoice.py
+++ b/server/vbv_lernwelt/shop/tests/test_invoice.py
@@ -1,34 +1,74 @@
-from datetime import date
+from datetime import date, datetime
from unittest.mock import create_autospec
from django.test import TestCase
from vbv_lernwelt.core.admin import User
-from vbv_lernwelt.shop.invoice.abacus import AbacusInvoiceCreator
-from vbv_lernwelt.shop.invoice.creator import Item
+from vbv_lernwelt.core.create_default_users import create_default_users
+from vbv_lernwelt.shop.invoice.abacus import (
+ AbacusInvoiceCreator,
+ render_invoice_xml,
+ render_customer_xml,
+ create_invoice_xml,
+ create_customer_xml,
+)
from vbv_lernwelt.shop.invoice.repositories import InvoiceRepository
from vbv_lernwelt.shop.models import CheckoutInformation
+from vbv_lernwelt.shop.tests.factories import CheckoutInformationFactory
USER_USERNAME = "testuser"
USER_EMAIL = "test@example.com"
USER_PASSWORD = "testpassword"
-class InvoiceTestCase(TestCase):
- def setUp(self) -> None:
- self.user = User.objects.create_user(
- username=USER_USERNAME,
- email=USER_EMAIL,
- password=USER_PASSWORD,
- is_active=True,
+class AbacusInvoiceTestCase(TestCase):
+ def setUp(self):
+ create_default_users()
+
+ def test_create_invoice_xml(self):
+ # set abacus_number before
+ _pat = User.objects.get(username="patrizia.huggel@eiger-versicherungen.ch")
+ _pat.abacus_debitor_number = 60000011
+ _pat.save()
+ _ignore_checkout_information = CheckoutInformationFactory(
+ user=_pat, abacus_order_id=6_000_000_123
+ )
+
+ feuz = User.objects.get(username="andreas.feuz@eiger-versicherungen.ch")
+ feuz_checkout_info = CheckoutInformationFactory(
+ user=feuz,
+ transaction_id="24021508331287484",
+ )
+ feuz_checkout_info.created_at = datetime(2024, 2, 15, 8, 33, 12, 0)
+ invoice_xml_filename, invoice_xml_content = create_invoice_xml(
+ feuz_checkout_info
+ )
+
+ self.assertEqual(
+ invoice_xml_filename, "myVBV_orde_60000012_20240215083312_6000000124.xml"
+ )
+
+ # print(invoice_xml_content)
+ assert "60000012" in invoice_xml_content
+ assert (
+ "2024-02-15" in invoice_xml_content
+ )
+ assert (
+ "6000000124"
+ in invoice_xml_content
+ )
+ assert (
+ "24021508331287484"
+ in invoice_xml_content
+ )
+ assert "2024-02-15" in invoice_xml_content
+ assert (
+ "Versicherungsvermittler/-in VBV - 2024-02-15 - Feuz Andreas"
+ in invoice_xml_content
)
def test_render_invoice_xml(self):
- # GIVEN
- creator = AbacusInvoiceCreator(repository=create_autospec(InvoiceRepository))
-
- # WHEN
- invoice_xml = creator.render_invoice_xml(
+ invoice_xml = render_invoice_xml(
abacus_debitor_number=60000012,
abacus_order_id=6000000001,
order_date=date(2024, 2, 15),
@@ -75,17 +115,56 @@ class InvoiceTestCase(TestCase):
"""
- # THEN
self.maxDiff = None
self.assertXMLEqual(expected_xml, invoice_xml)
- def test_render_customer_xml(self):
- # GIVEN
- creator = AbacusInvoiceCreator(
- repository=create_autospec(InvoiceRepository))
+ def test_create_customer_xml_with_company_address(self):
+ _pat = User.objects.get(username="patrizia.huggel@eiger-versicherungen.ch")
+ _pat.abacus_debitor_number = 60000011
+ _pat.save()
+ _ignore_checkout_information = CheckoutInformationFactory(
+ user=_pat, abacus_order_id=6_000_000_123
+ )
- # WHEN
- customer_xml = creator.render_customer_xml(
+ feuz = User.objects.get(username="andreas.feuz@eiger-versicherungen.ch")
+ feuz_checkout_info = CheckoutInformationFactory(
+ user=feuz,
+ transaction_id="24021508331287484",
+ first_name="Andreas",
+ last_name="Feuz",
+ street="Eggersmatt",
+ street_number="32",
+ postal_code="1719",
+ city="Zumholz",
+ country="209",
+ company_name="VBV",
+ company_street="Laupenstrasse",
+ company_street_number="10",
+ company_postal_code="3000",
+ company_city="Bern",
+ company_country="209",
+ )
+ feuz_checkout_info.created_at = datetime(2024, 2, 15, 8, 33, 12, 0)
+
+ customer_xml_filename, customer_xml_content = create_customer_xml(
+ checkout_information=feuz_checkout_info
+ )
+ print(customer_xml_content)
+ print(customer_xml_filename)
+
+ self.assertEqual("myVBV_debi_60000012.xml", customer_xml_filename)
+ assert "60000012" in customer_xml_content
+ assert (
+ "andreas.feuz@eiger-versicherungen.ch"
+ in customer_xml_content
+ )
+ assert "VBV" in customer_xml_content
+
+ # FIXME refactor country
+ assert "209" in customer_xml_content
+
+ def test_render_customer_xml(self):
+ customer_xml = render_customer_xml(
abacus_debitor_number=60000012,
last_name="Gebhart-Krasniqi",
first_name="Skender",
@@ -96,11 +175,9 @@ class InvoiceTestCase(TestCase):
city="Bern",
country="CH",
language="de",
- email="skender.krasniqi@vbv-afa.ch"
+ email="skender.krasniqi@vbv-afa.ch",
)
- print(customer_xml)
-
# example from Skender
expected_xml = """
@@ -136,7 +213,6 @@ class InvoiceTestCase(TestCase):
"""
- # THEN
self.maxDiff = None
self.assertXMLEqual(expected_xml, customer_xml)