Start abacus upload manually from admin interface
This commit is contained in:
parent
516079ba10
commit
f4729cb4c8
|
|
@ -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";
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
|
||||||
|
|
@ -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():
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue