Start abacus upload manually from admin interface

This commit is contained in:
Daniel Egger 2024-05-31 18:57:52 +02:00
parent 516079ba10
commit f4729cb4c8
7 changed files with 94 additions and 39 deletions

View File

@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import WizardPage from "@/components/onboarding/WizardPage.vue"; import WizardPage from "@/components/onboarding/WizardPage.vue";
import type { Ref } from "vue"; import { computed, ref } from "vue";
import { computed, ref, watch } from "vue";
import { type User, useUserStore } from "@/stores/user"; import { type User, useUserStore } from "@/stores/user";
import PersonalAddress from "@/components/onboarding/PersonalAddress.vue"; import PersonalAddress from "@/components/onboarding/PersonalAddress.vue";
import OrganisationAddress from "@/components/onboarding/OrganisationAddress.vue"; import OrganisationAddress from "@/components/onboarding/OrganisationAddress.vue";

View File

@ -1,5 +1,6 @@
encrypted: env_secrets/caprover_myvbv-prod.env encrypted: env_secrets/caprover_myvbv-prod.env
encrypted: env_secrets/caprover_myvbv-stage.env encrypted: env_secrets/caprover_myvbv-stage.env
encrypted: env_secrets/caprover_vbv-develop.env
encrypted: env_secrets/local_chrigu.env encrypted: env_secrets/local_chrigu.env
encrypted: env_secrets/local_daniel.env encrypted: env_secrets/local_daniel.env
encrypted: env_secrets/local_elia.env encrypted: env_secrets/local_elia.env

View File

@ -108,7 +108,10 @@ class AbacusInvoiceUploadTestCase(BaseAbacusSftpServerTestCase):
self.assertTrue(os.path.exists(order_filepath)) self.assertTrue(os.path.exists(order_filepath))
with open(order_filepath) as order_file: with open(order_filepath) as order_file:
order_content = order_file.read() order_content = order_file.read()
assert "<ReferencePurchaseOrder>24021508331287484</ReferencePurchaseOrder>" in order_content assert (
"<ReferencePurchaseOrder>24021508331287484</ReferencePurchaseOrder>"
in order_content
)
assert "<CustomerNumber>60000012</CustomerNumber>" in order_content assert "<CustomerNumber>60000012</CustomerNumber>" in order_content
feuz_checkout_info.refresh_from_db() feuz_checkout_info.refresh_from_db()

View File

@ -1,14 +1,10 @@
from django.contrib import admin from django.contrib import admin
from vbv_lernwelt.shop.invoice.abacus import abacus_ssh_upload
from vbv_lernwelt.shop.models import CheckoutInformation, Product from vbv_lernwelt.shop.models import CheckoutInformation, Product
from vbv_lernwelt.shop.services import get_transaction_state from vbv_lernwelt.shop.services import get_transaction_state
@admin.action(description="ABACUS: Create invoices")
def generate_invoice(modeladmin, request, queryset):
pass
@admin.action(description="DATATRANS: Sync transaction states") @admin.action(description="DATATRANS: Sync transaction states")
def sync_transaction_state(modeladmin, request, queryset): def sync_transaction_state(modeladmin, request, queryset):
for checkout in queryset: for checkout in queryset:
@ -23,18 +19,60 @@ def sync_transaction_state(modeladmin, request, queryset):
@admin.register(CheckoutInformation) @admin.register(CheckoutInformation)
class CheckoutInformationAdmin(admin.ModelAdmin): class CheckoutInformationAdmin(admin.ModelAdmin):
@admin.action(description="ABACUS: Upload invoice to SFTP server")
def abacus_upload_order(self, request, queryset):
success = True
for ci in queryset:
if not abacus_ssh_upload(ci):
success = False
if not success:
self.message_user(
request, f"Beim SFTP upload ist ein Fehler aufgetreten", level="error"
)
@staticmethod
def customer(obj):
return f"{obj.user.first_name} {obj.user.last_name} ({obj.user.email})"
@staticmethod
def debitor_number(obj):
return obj.user.abacus_debitor_number
def has_delete_permission(self, request, obj=None):
# Disable delete
return False
list_display = ( list_display = (
"product_sku", "product_sku",
"user", customer,
"product_name", "product_name",
"product_price", "product_price",
"updated_at", "created_at",
"state", "state",
"invoice_transmitted_at", "invoice_transmitted_at",
"abacus_order_id",
debitor_number,
"abacus_ssh_upload_done",
) )
search_fields = ["user__email"] search_fields = [
list_filter = ("state", "product_name") "user__email",
actions = [generate_invoice, sync_transaction_state] "user__first_name",
"user__last_name",
"user__username",
"transaction_id",
"abacus_order_id",
"user__abacus_debitor_number",
]
list_filter = ("state", "product_name", "product_sku", "abacus_ssh_upload_done")
date_hierarchy = "created_at"
actions = [abacus_upload_order, sync_transaction_state]
readonly_fields = [
"user",
"transaction_id",
"state",
"product_price",
"webhook_history",
]
@admin.register(Product) @admin.register(Product)

View File

@ -6,25 +6,44 @@ from xml.etree.ElementTree import Element, SubElement, tostring
import structlog import structlog
from vbv_lernwelt.shop.invoice.abacus_sftp_client import AbacusSftpClient from vbv_lernwelt.shop.invoice.abacus_sftp_client import AbacusSftpClient
from vbv_lernwelt.shop.models import CheckoutInformation from vbv_lernwelt.shop.models import CheckoutInformation, CheckoutState
logger = structlog.get_logger(__name__) logger = structlog.get_logger(__name__)
def abacus_ssh_upload(checkout_information: CheckoutInformation): def abacus_ssh_upload(checkout_information: CheckoutInformation):
invoice_xml_filename, invoice_xml_content = create_invoice_xml(checkout_information) if checkout_information.state != CheckoutState.PAID:
customer_xml_filename, customer_xml_content = create_customer_xml( # only upload invoice if checkout is paid
checkout_information return True
)
abacus_ssh_upload_invoice( try:
customer_xml_filename, customer_xml_content, folder="debitor" invoice_xml_filename, invoice_xml_content = create_invoice_xml(
) checkout_information
)
customer_xml_filename, customer_xml_content = create_customer_xml(
checkout_information
)
if not checkout_information.abacus_ssh_upload_done: abacus_ssh_upload_invoice(
abacus_ssh_upload_invoice(invoice_xml_filename, invoice_xml_content, folder="order") customer_xml_filename, customer_xml_content, folder="debitor"
checkout_information.abacus_ssh_upload_done = True )
checkout_information.save()
if not checkout_information.abacus_ssh_upload_done:
abacus_ssh_upload_invoice(
invoice_xml_filename, invoice_xml_content, folder="order"
)
checkout_information.abacus_ssh_upload_done = True
checkout_information.invoice_transmitted_at = datetime.datetime.now()
checkout_information.save()
return True
except Exception as e:
logger.warning(
"Error uploading invoice to Abacus SFTP",
checkout_information_id=checkout_information.id,
exception=str(e),
)
return False
def create_invoice_xml(checkout_information: CheckoutInformation): def create_invoice_xml(checkout_information: CheckoutInformation):
@ -212,13 +231,9 @@ def abacus_ssh_upload_invoice(
filename: str, content_xml: str, folder: str = "" filename: str, content_xml: str, folder: str = ""
) -> None: ) -> None:
invoice_io = BytesIO(content_xml.encode("utf-8")) invoice_io = BytesIO(content_xml.encode("utf-8"))
try: with AbacusSftpClient() as sftp_client:
with AbacusSftpClient() as sftp_client: path = filename
path = filename if folder:
if folder: path = f"{folder}/{filename}"
path = f"{folder}/{filename}"
sftp_client.putfo(invoice_io, path) sftp_client.putfo(invoice_io, path)
except Exception as e:
logger.error("Could not upload invoice", exc_info=e)

View File

@ -1,5 +1,5 @@
from django.conf import settings from django.conf import settings
from paramiko.client import SSHClient, AutoAddPolicy from paramiko.client import AutoAddPolicy, SSHClient
def _create_abacus_sftp_client(): def _create_abacus_sftp_client():

View File

@ -4,15 +4,14 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('shop', '0013_checkoutinformation_abacus_order_id'), ("shop", "0013_checkoutinformation_abacus_order_id"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='checkoutinformation', model_name="checkoutinformation",
name='abacus_ssh_upload_done', name="abacus_ssh_upload_done",
field=models.BooleanField(default=False), field=models.BooleanField(default=False),
), ),
] ]