diff --git a/server/vbv_lernwelt/shop/invoice/abacus.py b/server/vbv_lernwelt/shop/invoice/abacus.py
index 059c6e3b..a92b1056 100644
--- a/server/vbv_lernwelt/shop/invoice/abacus.py
+++ b/server/vbv_lernwelt/shop/invoice/abacus.py
@@ -6,6 +6,7 @@ from xml.etree.ElementTree import Element, SubElement, tostring
from vbv_lernwelt.shop.invoice.creator import InvoiceCreator, Item
from vbv_lernwelt.shop.invoice.repositories import InvoiceRepository
+from vbv_lernwelt.shop.models import CheckoutInformation
class AbacusInvoiceCreator(InvoiceCreator):
@@ -14,18 +15,25 @@ class AbacusInvoiceCreator(InvoiceCreator):
def create_invoice(
self,
- customer_number: str,
- purchase_order_date: datetime.date,
- delivery_date: datetime.date,
- reference_purchase_order: str,
- unic_id: str,
- items: List[Item],
+ checkout_information: CheckoutInformation,
filename: str = None,
):
- invoice = self.render_invoice(
+ customer_number = checkout_information.transaction_id
+ order_date = checkout_information.created_at.date()
+ reference_purchase_order = str(checkout_information.id)
+ unic_id = checkout_information.transaction_id
+
+ items = [
+ Item(
+ product_number=checkout_information.product_sku,
+ quantity=1,
+ description=checkout_information.product_description,
+ )
+ ]
+
+ invoice = self.invoice_xml(
customer_number,
- purchase_order_date,
- delivery_date,
+ order_date,
reference_purchase_order,
unic_id,
items,
@@ -37,10 +45,9 @@ class AbacusInvoiceCreator(InvoiceCreator):
self.repository.upload_invoice(invoice, filename)
@staticmethod
- def render_invoice(
+ def invoice_xml(
customer_number: str,
- purchase_order_date: datetime.date,
- delivery_date: datetime.date,
+ order_date: datetime.date,
reference_purchase_order: str,
unic_id: str,
items: List[Item],
@@ -62,10 +69,10 @@ class AbacusInvoiceCreator(InvoiceCreator):
SubElement(sales_order_header_fields, "CustomerNumber").text = customer_number
SubElement(
sales_order_header_fields, "PurchaseOrderDate"
- ).text = purchase_order_date.isoformat()
+ ).text = order_date.isoformat()
SubElement(
sales_order_header_fields, "DeliveryDate"
- ).text = delivery_date.isoformat()
+ ).text = order_date.isoformat()
SubElement(
sales_order_header_fields, "ReferencePurchaseOrder"
).text = reference_purchase_order
@@ -76,7 +83,7 @@ class AbacusInvoiceCreator(InvoiceCreator):
item_fields = SubElement(item_element, "ItemFields", mode="SAVE")
SubElement(item_fields, "ItemNumber").text = str(index)
SubElement(item_fields, "ProductNumber").text = item.product_number
- SubElement(item_fields, "QuantityOrdered").text = item.quantity
+ SubElement(item_fields, "QuantityOrdered").text = str(item.quantity)
item_text = SubElement(item_element, "ItemText", mode="SAVE")
item_text_fields = SubElement(item_text, "ItemTextFields", mode="SAVE")
@@ -84,6 +91,52 @@ class AbacusInvoiceCreator(InvoiceCreator):
return AbacusInvoiceCreator.create_xml_string(container)
+ @staticmethod
+ def customer_xml(
+ customer_number: str,
+ name: str,
+ first_name: str,
+ address_text: 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 = customer_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 = customer_number
+ SubElement(address_data, "Name").text = name
+ SubElement(address_data, "FirstName").text = first_name
+ SubElement(address_data, "Text").text = address_text
+ 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 AbacusInvoiceCreator.create_xml_string(container)
+
@staticmethod
def create_xml_string(container: Element, encoding: str = "UTF-8") -> str:
xml_bytes = tostring(container, encoding)
diff --git a/server/vbv_lernwelt/shop/invoice/creator.py b/server/vbv_lernwelt/shop/invoice/creator.py
index c8758e91..85c08475 100644
--- a/server/vbv_lernwelt/shop/invoice/creator.py
+++ b/server/vbv_lernwelt/shop/invoice/creator.py
@@ -1,13 +1,13 @@
-import datetime
from abc import ABC, abstractmethod
from dataclasses import dataclass
-from typing import List
+
+from vbv_lernwelt.shop.models import CheckoutInformation
@dataclass
class Item:
product_number: str
- quantity: str
+ quantity: int
description: str
@@ -15,11 +15,7 @@ class InvoiceCreator(ABC):
@abstractmethod
def create_invoice(
self,
- customer_number: str,
- purchase_order_date: datetime.date,
- delivery_date: datetime.date,
- reference_purchase_order: str,
- unic_id: str,
- items: List[Item],
+ checkout_information: CheckoutInformation,
+ filename: str = None,
):
pass
diff --git a/server/vbv_lernwelt/shop/invoice/repositories.py b/server/vbv_lernwelt/shop/invoice/repositories.py
index 5f599b22..df231324 100644
--- a/server/vbv_lernwelt/shop/invoice/repositories.py
+++ b/server/vbv_lernwelt/shop/invoice/repositories.py
@@ -1,5 +1,9 @@
from abc import ABC, abstractmethod
+import structlog
+
+logger = structlog.get_logger(__name__)
+
class InvoiceRepository(ABC):
@abstractmethod
@@ -35,6 +39,6 @@ class SFTPInvoiceRepository(InvoiceRepository):
sftp_client.putfo(invoice_io, f"uploads/{filename}")
except Exception as e:
- print(f"An error occurred: {e}")
+ logger.error("Could not upload invoice", exc_info=e)
finally:
ssh_client.close()
diff --git a/server/vbv_lernwelt/shop/tests/test_invoice.py b/server/vbv_lernwelt/shop/tests/test_invoice.py
index ffc4936f..538aeaf3 100644
--- a/server/vbv_lernwelt/shop/tests/test_invoice.py
+++ b/server/vbv_lernwelt/shop/tests/test_invoice.py
@@ -1,71 +1,86 @@
from datetime import date
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.shop.invoice.repositories import InvoiceRepository
+from vbv_lernwelt.shop.models import CheckoutInformation
+
+USER_USERNAME = "testuser"
+USER_EMAIL = "test@example.com"
+USER_PASSWORD = "testpassword"
-def test_render_invoice():
- # GIVEN
- creator = AbacusInvoiceCreator(repository=create_autospec(InvoiceRepository))
- items = [Item(product_number="001", quantity="10", description="Test Item")]
- customer_number = "12345"
- purchase_order_date = date(2023, 1, 1)
- delivery_date = date(2023, 1, 10)
- reference_purchase_order = "PO12345678"
- unic_id = "UNIC001"
+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,
+ )
- # WHEN
- invoice_xml = creator.render_invoice(
- customer_number,
- purchase_order_date,
- delivery_date,
- reference_purchase_order,
- unic_id,
- items,
- )
+ def test_render_invoice(self):
+ # GIVEN
+ creator = AbacusInvoiceCreator(repository=create_autospec(InvoiceRepository))
+ items = [Item(product_number="001", quantity=1, description="Test Item")]
+ customer_number = "12345"
+ order_date = date(2023, 1, 1)
+ reference_purchase_order = "PO12345678"
+ unic_id = "UNIC001"
- # THEN
- assert "12345" in invoice_xml
- assert "1" in invoice_xml
- assert "001" in invoice_xml
- assert "10" in invoice_xml
- assert "Test Item" in invoice_xml
+ # WHEN
+ invoice_xml = creator.invoice_xml(
+ customer_number,
+ order_date,
+ reference_purchase_order,
+ unic_id,
+ items,
+ )
+ # THEN
+ assert "12345" in invoice_xml
+ assert "1" in invoice_xml
+ assert "001" in invoice_xml
+ assert "1" in invoice_xml
+ assert "Test Item" in invoice_xml
-def test_create_invoice_calls_upload():
- # GIVEN
- repository_mock = create_autospec(InvoiceRepository)
+ def test_create_invoice_calls_upload(self):
+ # GIVEN
+ repository_mock = create_autospec(InvoiceRepository)
- creator = AbacusInvoiceCreator(repository=repository_mock)
- items = [Item(product_number="001", quantity="10", description="Test Item")]
- customer_number = "12345"
- purchase_order_date = date(2023, 1, 1)
- delivery_date = date(2023, 1, 10)
- reference_purchase_order = "PO12345678"
- unic_id = "UNIC001"
+ creator = AbacusInvoiceCreator(repository=repository_mock)
- expected_filename = "test.xml"
+ expected_filename = "test.xml"
- # WHEN
- creator.create_invoice(
- customer_number,
- purchase_order_date,
- delivery_date,
- reference_purchase_order,
- unic_id,
- items,
- filename=expected_filename,
- )
+ checkout_information = CheckoutInformation.objects.create(
+ user=self.user,
+ transaction_id="12345",
+ product_sku="001",
+ product_name="Test Product",
+ product_description="Test Product Description",
+ product_price=1000,
+ state="initialized",
+ )
- # THEN
- repository_mock.upload_invoice.assert_called_once()
- uploaded_invoice, uploaded_filename = repository_mock.upload_invoice.call_args[0]
+ # WHEN
+ creator.create_invoice(
+ checkout_information=checkout_information,
+ filename=expected_filename,
+ )
- assert uploaded_filename == expected_filename
- assert "12345" in uploaded_invoice
- assert "1" in uploaded_invoice
- assert "001" in uploaded_invoice
- assert "10" in uploaded_invoice
- assert "Test Item" in uploaded_invoice
+ # THEN
+ repository_mock.upload_invoice.assert_called_once()
+ uploaded_invoice, uploaded_filename = repository_mock.upload_invoice.call_args[
+ 0
+ ]
+
+ assert uploaded_filename == expected_filename
+ assert "12345" in uploaded_invoice
+ assert "1" in uploaded_invoice
+ assert "001" in uploaded_invoice
+ assert "1" in uploaded_invoice
+ assert "Test Product Description" in uploaded_invoice