diff --git a/kmuhelper/migrations/0113_customer_woocommerce_deleted_and_more.py b/kmuhelper/migrations/0113_customer_woocommerce_deleted_and_more.py
new file mode 100644
index 0000000..3fd19e2
--- /dev/null
+++ b/kmuhelper/migrations/0113_customer_woocommerce_deleted_and_more.py
@@ -0,0 +1,40 @@
+# Generated by Django 5.0.4 on 2024-04-09 14:22
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("kmuhelper", "0112_product_parent"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="customer",
+ name="woocommerce_deleted",
+ field=models.BooleanField(
+ blank=True, default=False, verbose_name="Deleted in WooCommerce?"
+ ),
+ ),
+ migrations.AddField(
+ model_name="order",
+ name="woocommerce_deleted",
+ field=models.BooleanField(
+ blank=True, default=False, verbose_name="Deleted in WooCommerce?"
+ ),
+ ),
+ migrations.AddField(
+ model_name="product",
+ name="woocommerce_deleted",
+ field=models.BooleanField(
+ blank=True, default=False, verbose_name="Deleted in WooCommerce?"
+ ),
+ ),
+ migrations.AddField(
+ model_name="productcategory",
+ name="woocommerce_deleted",
+ field=models.BooleanField(
+ blank=True, default=False, verbose_name="Deleted in WooCommerce?"
+ ),
+ ),
+ ]
diff --git a/kmuhelper/modules/integrations/woocommerce/api/_base.py b/kmuhelper/modules/integrations/woocommerce/api/_base.py
index 6c233a1..5c2503b 100644
--- a/kmuhelper/modules/integrations/woocommerce/api/_base.py
+++ b/kmuhelper/modules/integrations/woocommerce/api/_base.py
@@ -72,6 +72,7 @@ def update_object_from_api(self, db_object) -> bool:
str(db_object),
)
db_object.woocommerceid = 0
+ db_object.woocommerce_deleted = True
db_object.save()
else:
self.log(wc_obj)
diff --git a/kmuhelper/modules/integrations/woocommerce/filters.py b/kmuhelper/modules/integrations/woocommerce/filters.py
new file mode 100644
index 0000000..19e569d
--- /dev/null
+++ b/kmuhelper/modules/integrations/woocommerce/filters.py
@@ -0,0 +1,71 @@
+from django.contrib import admin
+from django.utils.translation import gettext_lazy as _
+
+from kmuhelper.modules.integrations.woocommerce.utils import is_connected
+
+
+class WooCommerceStateFilter(admin.SimpleListFilter):
+ """Filter that filters views based on WooCommerce state."""
+
+ # Human-readable title which will be displayed in the
+ # right admin sidebar just above the filter options.
+ title = _("WooCommerce State")
+
+ # Parameter for the filter that will be used in the URL query.
+ parameter_name = "wc_state"
+
+ def __init__(self, request, params, model, model_admin):
+ super(WooCommerceStateFilter, self).__init__(
+ request, params, model, model_admin
+ )
+
+ def lookups(self, request, model_admin):
+ return [
+ ("all", _("All")),
+ ("linked", _("Linked")),
+ ("not_linked", _("Not linked")),
+ ("deleted", _("Deleted")),
+ ("not_deleted", _("Not deleted")),
+ ]
+
+ def queryset(self, request, queryset):
+ """
+ Returns the filtered queryset based on the value
+ provided in the query string and retrievable via
+ `self.value()`.
+ """
+
+ if self.value() is None:
+ # default option
+ self.used_parameters[self.parameter_name] = "not_deleted"
+
+ if self.value() == "linked":
+ return queryset.exclude(woocommerceid=0)
+ if self.value() == "not_linked":
+ return queryset.filter(woocommerceid=0)
+ if self.value() == "deleted":
+ return queryset.filter(woocommerce_deleted=True)
+ if self.value() == "not_deleted":
+ return queryset.exclude(woocommerce_deleted=True)
+
+ return queryset
+
+ def choices(self, changelist):
+ add_facets = changelist.add_facets
+ facet_counts = self.get_facet_queryset(changelist) if add_facets else None
+ for i, (lookup, title) in enumerate(self.lookup_choices):
+ if add_facets:
+ if (count := facet_counts.get(f"{i}__c", -1)) != -1:
+ title = f"{title} ({count})"
+ else:
+ title = f"{title} (-)"
+ yield {
+ "selected": self.value() == str(lookup),
+ "query_string": changelist.get_query_string(
+ {self.parameter_name: lookup}
+ ),
+ "display": title,
+ }
+
+ def has_output(self):
+ return is_connected() and super().has_output()
diff --git a/kmuhelper/modules/integrations/woocommerce/mixins.py b/kmuhelper/modules/integrations/woocommerce/mixins.py
index dbc4c2b..d0b7655 100644
--- a/kmuhelper/modules/integrations/woocommerce/mixins.py
+++ b/kmuhelper/modules/integrations/woocommerce/mixins.py
@@ -4,9 +4,11 @@
from django.utils.translation import gettext_lazy as _
from kmuhelper import settings
-WC_ID_PRESENT_DESCRIPTION = format_html(
- '',
- _("Mit WooCommerce-Objekt verknüpft?"),
+WC_STATE_DESCRIPTION = format_html(
+ '',
+ _(
+ "WooCommerce-Status (grün = verknüpft, rot = verknüpft, aber auf WooCommerce gelöscht, grau = nicht verknüpft)"
+ ),
)
@@ -18,6 +20,13 @@ class WooCommerceModelMixin(models.Model):
default=0,
)
+ woocommerce_deleted = models.BooleanField(
+ verbose_name=_("Deleted in WooCommerce?"),
+ default=False,
+ blank=True,
+ null=False,
+ )
+
def get_woocommerce_url(self):
return self.WOOCOMMERCE_URL_FORMAT.format(
settings.get_secret_db_setting("wc-url"), self.woocommerceid
@@ -33,16 +42,21 @@ def display_woocommerce_id(self):
link = self.get_woocommerce_url()
return format_html(
- '#{}',
+ '#{} {}',
link,
str(self.woocommerceid),
+ _("(Deleted)") if self.woocommerce_deleted else "",
)
@admin.display(
- description=WC_ID_PRESENT_DESCRIPTION, ordering="woocommerceid", boolean=True
+ description=WC_STATE_DESCRIPTION,
+ ordering="woocommerceid",
+ boolean=True,
)
- def display_woocommerce_id_present(self):
- return bool(self.woocommerceid)
+ def display_woocommerce_state(self):
+ if not self.woocommerceid:
+ return None
+ return not self.woocommerce_deleted
class Meta:
abstract = True
diff --git a/kmuhelper/modules/integrations/woocommerce/views.py b/kmuhelper/modules/integrations/woocommerce/views.py
index 8327ebd..0b4a535 100644
--- a/kmuhelper/modules/integrations/woocommerce/views.py
+++ b/kmuhelper/modules/integrations/woocommerce/views.py
@@ -350,53 +350,56 @@ def wc_webhooks(request):
log("WooCommerce Webhook is being processed...")
+ delivery_id = request.headers["x-wc-webhook-delivery-id"]
topic = request.headers["x-wc-webhook-topic"]
wc_obj = json.loads(request.body)
+ log("Delivery ID: ", delivery_id)
log("Topic: ", topic)
- log("ID: ", wc_obj.get("id"))
-
- if topic in ("product.updated", "product.created"):
- if Product.objects.filter(woocommerceid=wc_obj["id"]).exists():
- WCProductsAPI().update_object_from_data(
- Product.objects.get(woocommerceid=wc_obj["id"]), wc_obj
- )
- else:
- WCProductsAPI().create_object_from_data(wc_obj)
- elif topic == "product.deleted":
- if Product.objects.filter(woocommerceid=wc_obj["id"]).exists():
- product = Product.objects.get(woocommerceid=wc_obj["id"])
- product.woocommerceid = 0
- product.save()
- elif topic in ("customer.updated", "customer.created"):
- if Customer.objects.filter(woocommerceid=wc_obj["id"]).exists():
- WCCustomersAPI().update_object_from_data(
- Customer.objects.get(woocommerceid=wc_obj["id"]), wc_obj
- )
- else:
- WCCustomersAPI().create_object_from_data(wc_obj)
- elif topic == "customer.deleted":
- if Customer.objects.filter(woocommerceid=wc_obj["id"]).exists():
- customer = Customer.objects.get(woocommerceid=wc_obj["id"])
- customer.woocommerceid = 0
- customer.save()
- elif topic in ("order.updated", "order.created"):
- if Order.objects.filter(woocommerceid=wc_obj["id"]).exists():
- WCOrdersAPI().update_object_from_data(
- Order.objects.get(woocommerceid=wc_obj["id"]), wc_obj
+ log("Object ID: ", wc_obj.get("id"))
+
+ match topic:
+ case "product.updated" | "product.created" | "product.restored":
+ if Product.objects.filter(woocommerceid=wc_obj["id"]).exists():
+ product = Product.objects.get(woocommerceid=wc_obj["id"])
+ product.woocommerce_deleted = False
+ WCProductsAPI().update_object_from_data(product, wc_obj)
+ else:
+ WCProductsAPI().create_object_from_data(wc_obj)
+ case "product.deleted":
+ if Product.objects.filter(woocommerceid=wc_obj["id"]).exists():
+ product = Product.objects.get(woocommerceid=wc_obj["id"])
+ product.woocommerce_deleted = True
+ product.save()
+ case "customer.updated" | "customer.created" | "customer.restored":
+ if Customer.objects.filter(woocommerceid=wc_obj["id"]).exists():
+ customer = Customer.objects.get(woocommerceid=wc_obj["id"])
+ customer.woocommerce_deleted = False
+ WCCustomersAPI().update_object_from_data(customer, wc_obj)
+ else:
+ WCCustomersAPI().create_object_from_data(wc_obj)
+ case "customer.deleted":
+ if Customer.objects.filter(woocommerceid=wc_obj["id"]).exists():
+ customer = Customer.objects.get(woocommerceid=wc_obj["id"])
+ customer.woocommerce_deleted = True
+ customer.save()
+ case "order.updated" | "order.created" | "order.restored":
+ if Order.objects.filter(woocommerceid=wc_obj["id"]).exists():
+ order = Order.objects.get(woocommerceid=wc_obj["id"])
+ order.woocommerce_deleted = False
+ WCOrdersAPI().update_object_from_data(order, wc_obj)
+ else:
+ WCOrdersAPI().create_object_from_data(wc_obj)
+ case "order.deleted":
+ if Order.objects.filter(woocommerceid=wc_obj["id"]).exists():
+ order = Order.objects.get(woocommerceid=wc_obj["id"])
+ order.woocommerce_deleted = True
+ order.save()
+ case _:
+ log(f"[orange_red1]Unknown topic: '{topic}'")
+ return JsonResponse(
+ {"accepted": False, "message": "Topic not supported!"}, status=400
)
- else:
- WCOrdersAPI().create_object_from_data(wc_obj)
- elif topic == "order.deleted":
- if Order.objects.filter(woocommerceid=wc_obj["id"]).exists():
- order = Order.objects.get(woocommerceid=wc_obj["id"])
- order.woocommerceid = 0
- order.save()
- else:
- log(f"[orange_red1]Unknown topic: '{topic}'")
- return JsonResponse(
- {"accepted": False, "message": "Topic not supported!"}, status=400
- )
return JsonResponse({"accepted": True})
diff --git a/kmuhelper/modules/main/admin.py b/kmuhelper/modules/main/admin.py
index 0aed571..21cb439 100644
--- a/kmuhelper/modules/main/admin.py
+++ b/kmuhelper/modules/main/admin.py
@@ -11,6 +11,7 @@
WCProductsAPI,
WCProductCategoriesAPI,
)
+from kmuhelper.modules.integrations.woocommerce.filters import WooCommerceStateFilter
from kmuhelper.modules.integrations.woocommerce.utils import is_connected
from kmuhelper.modules.main import views
from kmuhelper.modules.main.models import (
@@ -266,6 +267,7 @@ class OrderAdmin(CustomModelAdmin):
"status",
"is_paid",
"is_shipped",
+ WooCommerceStateFilter,
"payment_method",
"payment_receiver",
"contact_person",
@@ -300,7 +302,7 @@ class OrderAdmin(CustomModelAdmin):
def get_list_display(self, request):
if is_connected():
ls = self.list_display.copy()
- ls.insert(1, "display_woocommerce_id_present")
+ ls.insert(1, "display_woocommerce_state")
return ls
return self.list_display
@@ -613,6 +615,8 @@ class CustomerAdmin(CustomModelAdmin):
readonly_fields = ["linked_note_html", "display_woocommerce_id"]
+ list_filter = [WooCommerceStateFilter]
+
list_select_related = ["linked_note"]
autocomplete_fields = ["combine_with"]
@@ -624,7 +628,7 @@ class CustomerAdmin(CustomModelAdmin):
def get_list_display(self, request):
if is_connected():
ls = self.list_display.copy()
- ls.insert(1, "display_woocommerce_id_present")
+ ls.insert(1, "display_woocommerce_state")
return ls
return self.list_display
@@ -1081,7 +1085,7 @@ class ProductAdmin(CustomModelAdmin):
ordering = ("article_number", "name")
- list_filter = ("supplier", "categories", "stock_current")
+ list_filter = ("supplier", WooCommerceStateFilter, "categories")
search_fields = [
"pk",
"article_number",
@@ -1106,7 +1110,7 @@ class ProductAdmin(CustomModelAdmin):
def get_list_display(self, request):
if is_connected():
ls = self.list_display.copy()
- ls.insert(1, "display_woocommerce_id_present")
+ ls.insert(1, "display_woocommerce_state")
return ls
return self.list_display
@@ -1296,7 +1300,7 @@ class ProductCategoryAdmin(CustomModelAdmin):
def get_list_display(self, request):
if is_connected():
ls = self.list_display.copy()
- ls.insert(1, "display_woocommerce_id_present")
+ ls.insert(1, "display_woocommerce_state")
return ls
return self.list_display
diff --git a/kmuhelper/static/admin/kmuhelper/css/style.css b/kmuhelper/static/admin/kmuhelper/css/style.css
index ec304e0..a234679 100644
--- a/kmuhelper/static/admin/kmuhelper/css/style.css
+++ b/kmuhelper/static/admin/kmuhelper/css/style.css
@@ -79,7 +79,7 @@ form .wide textarea + div.help {
/* Icon columns width fix for boolean columns */
.column-pkfill,
-.column-display_woocommerce_id_present,
+.column-display_woocommerce_state,
.column-display_is_paid,
.column-display_is_shipped {
width: 1px;