1
0
forked from erp-dev/erp

feat: big

This commit is contained in:
2026-07-01 11:51:13 +08:00
parent 7c9b77afb0
commit 5170700234
28 changed files with 933 additions and 37 deletions

View File

@@ -1,5 +1,6 @@
from datetime import date
from django.core.exceptions import ValidationError as DjangoValidationError
from django.shortcuts import get_object_or_404
from rest_framework import permissions, serializers, status
from rest_framework.parsers import FormParser, JSONParser, MultiPartParser
@@ -38,6 +39,9 @@ def _entry_payload(entry: cost_models.CostEntry) -> dict:
'category_id': entry.category_id,
'category_name': entry.category.name if entry.category_id else '',
'amount': str(entry.amount),
'unit_amount': str(entry.unit_amount) if entry.unit_amount is not None else None,
'quantity': str(entry.quantity) if entry.quantity is not None else None,
'unit_name': entry.unit_name or '',
'occurred_at': entry.occurred_at.isoformat(),
'operator_id': entry.operator_id,
'image1': _image_url(entry.image1),
@@ -81,7 +85,16 @@ class CategoryUpdateSerializer(serializers.Serializer):
class EntryWriteSerializer(serializers.Serializer):
category_id = serializers.IntegerField(min_value=1)
amount = serializers.DecimalField(max_digits=15, decimal_places=2, min_value=0)
amount = serializers.DecimalField(
required=False, allow_null=True, max_digits=15, decimal_places=2, min_value=0,
)
unit_amount = serializers.DecimalField(
required=False, allow_null=True, max_digits=15, decimal_places=4, min_value=0,
)
quantity = serializers.DecimalField(
required=False, allow_null=True, max_digits=12, decimal_places=4, min_value=0,
)
unit_name = serializers.CharField(required=False, allow_blank=True, max_length=20, default='')
occurred_at = serializers.DateField()
image1 = serializers.ImageField(required=False, allow_null=True)
image2 = serializers.ImageField(required=False, allow_null=True)
@@ -89,10 +102,30 @@ class EntryWriteSerializer(serializers.Serializer):
source_id = serializers.CharField(required=False, allow_blank=True, default='')
remarks = serializers.CharField(required=False, allow_blank=True, default='')
def validate(self, attrs):
unit_amount = attrs.get('unit_amount')
quantity = attrs.get('quantity')
has_unit_amount = unit_amount is not None
has_quantity = quantity is not None
if has_unit_amount != has_quantity:
raise serializers.ValidationError('unit_amount 和 quantity 必须同时填写或同时为空')
if not has_unit_amount and attrs.get('amount') is None:
raise serializers.ValidationError('普通支出必须填写 amount倍数型支出必须填写 unit_amount 和 quantity')
return attrs
class EntryUpdateSerializer(serializers.Serializer):
category_id = serializers.IntegerField(required=False, min_value=1)
amount = serializers.DecimalField(required=False, max_digits=15, decimal_places=2, min_value=0)
amount = serializers.DecimalField(
required=False, allow_null=True, max_digits=15, decimal_places=2, min_value=0,
)
unit_amount = serializers.DecimalField(
required=False, allow_null=True, max_digits=15, decimal_places=4, min_value=0,
)
quantity = serializers.DecimalField(
required=False, allow_null=True, max_digits=12, decimal_places=4, min_value=0,
)
unit_name = serializers.CharField(required=False, allow_blank=True, max_length=20)
occurred_at = serializers.DateField(required=False)
image1 = serializers.ImageField(required=False, allow_null=True)
image2 = serializers.ImageField(required=False, allow_null=True)
@@ -210,18 +243,24 @@ class CostEntryListCreateView(APIView):
merchant_id=employee.merchant_id,
)
entry = cost_models.CostEntry.objects.create(
merchant=employee.merchant,
category=category,
amount=data['amount'],
occurred_at=data['occurred_at'],
operator=employee,
image1=data.get('image1'),
image2=data.get('image2'),
source_module=data.get('source_module', ''),
source_id=data.get('source_id', ''),
remarks=data.get('remarks', ''),
)
try:
entry = cost_services.create_cost_entry(
merchant=employee.merchant,
category=category,
occurred_at=data['occurred_at'],
amount=data.get('amount'),
unit_amount=data.get('unit_amount'),
quantity=data.get('quantity'),
unit_name=data.get('unit_name', ''),
operator=employee,
image1=data.get('image1'),
image2=data.get('image2'),
source_module=data.get('source_module', ''),
source_id=data.get('source_id', ''),
remarks=data.get('remarks', ''),
)
except DjangoValidationError as exc:
raise serializers.ValidationError(exc.message_dict if hasattr(exc, 'message_dict') else exc.messages)
return Response(_entry_payload(entry), status=status.HTTP_201_CREATED)
@@ -261,7 +300,10 @@ class CostEntryDetailView(APIView):
setattr(entry, field, value)
update_fields.append(field)
if update_fields:
entry.save(update_fields=update_fields)
try:
entry.save(update_fields=update_fields)
except DjangoValidationError as exc:
raise serializers.ValidationError(exc.message_dict if hasattr(exc, 'message_dict') else exc.messages)
entry.refresh_from_db()
return Response(_entry_payload(entry))