from django.utils import timezone from rest_framework import decorators, mixins, response, viewsets from apps.core.errors import ApiError from apps.integrations.odoo.services import OdooInvoiceService from apps.invoicing.models import Invoice from apps.invoicing.serializers import InvoiceSerializer from apps.rbac.permissions import ActionPermission class InvoiceViewSet( mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet ): serializer_class = InvoiceSerializer permission_classes = [ActionPermission] code_map = { "list": "invoice.view", "retrieve": "invoice.view", "create": "invoice.create", "sync": "invoice.create", } def get_queryset(self): user = self.request.user qs = Invoice.objects.select_related("order").all() if user.is_superuser: return qs return qs.filter(order__customer__user=user) def perform_create(self, serializer): order = serializer.validated_data["order"] total = (order.price_snapshot or {}).get("total") if not total: raise ApiError("NO_PRICE_SNAPSHOT", "Order has no price snapshot.") serializer.save(number=f"INV-{order.order_number}", amount=total, currency=order.currency) @decorators.action(detail=True, methods=["post"]) def sync(self, request, pk=None): invoice = self.get_object() invoice.sync_state = Invoice.SyncState.PROCESSING invoice.save(update_fields=["sync_state"]) try: result = OdooInvoiceService().sync_invoice(invoice) invoice.odoo_invoice_id = result.get("id", "") invoice.sync_state = Invoice.SyncState.SYNCHRONIZED invoice.synced_at = timezone.now() invoice.save(update_fields=["odoo_invoice_id", "sync_state", "synced_at"]) except Exception as exc: invoice.sync_state = Invoice.SyncState.FAILED invoice.last_error = str(exc) invoice.save(update_fields=["sync_state", "last_error"]) return response.Response(InvoiceSerializer(invoice).data)