1
0
forked from erp-dev/erp

feat: payment order and receipt order

This commit is contained in:
2025-11-30 21:52:36 +08:00
parent ce1954ad58
commit 9006a530d1
12 changed files with 900 additions and 12 deletions

View File

@@ -161,6 +161,62 @@ def create_sales_order(
return sales_order
def create_payment_order(
*,
merchant: basic_info_models.Merchant,
supplier: basic_info_models.Supplier,
payment_date,
amount,
operator: basic_info_models.Employee,
remarks: str | None = '',
) -> models.PaymentOrder:
"""
创建付款单(资金流出)。
"""
normalized_date = _normalize_order_date(payment_date)
normalized_amount = _ensure_positive_amount(amount, 'amount')
with transaction.atomic():
payment_order = models.PaymentOrder.objects.create(
merchant=merchant,
supplier=supplier,
payment_date=normalized_date,
amount=normalized_amount,
operator=operator,
remarks=remarks,
)
payment_order.refresh_from_db()
return payment_order
def create_receipt_order(
*,
merchant: basic_info_models.Merchant,
customer: basic_info_models.Customer,
receipt_date,
amount,
operator: basic_info_models.Employee,
remarks: str | None = '',
) -> models.ReceiptOrder:
"""
创建收款单(资金流入)。
"""
normalized_date = _normalize_order_date(receipt_date)
normalized_amount = _ensure_positive_amount(amount, 'amount')
with transaction.atomic():
receipt_order = models.ReceiptOrder.objects.create(
merchant=merchant,
customer=customer,
receipt_date=normalized_date,
amount=normalized_amount,
operator=operator,
remarks=remarks,
)
receipt_order.refresh_from_db()
return receipt_order
def review_purchase_order(
*,
purchase_order: models.PurchaseOrder | None = None,
@@ -222,6 +278,58 @@ def review_sales_order(
return _cancel_sales_order(order)
def review_payment_order(
*,
payment_order: models.PaymentOrder | None = None,
payment_order_id: int | None = None,
target_status: models.PaymentOrderStatusEnum,
reviewed_by=None,
) -> models.PaymentOrder:
order = _resolve_payment_order_instance(payment_order, payment_order_id)
if target_status not in {
models.PaymentOrderStatusEnum.APPROVED,
models.PaymentOrderStatusEnum.CANCELLED,
}:
raise ValueError('target_status 只能是 APPROVED 或 CANCELLED')
if order.status == target_status:
return order
with transaction.atomic():
order.status = target_status
order.save(update_fields=['status', 'updated_at'])
order.refresh_from_db(fields=['status', 'updated_at'])
return order
def review_receipt_order(
*,
receipt_order: models.ReceiptOrder | None = None,
receipt_order_id: int | None = None,
target_status: models.ReceiptOrderStatusEnum,
reviewed_by=None,
) -> models.ReceiptOrder:
order = _resolve_receipt_order_instance(receipt_order, receipt_order_id)
if target_status not in {
models.ReceiptOrderStatusEnum.APPROVED,
models.ReceiptOrderStatusEnum.CANCELLED,
}:
raise ValueError('target_status 只能是 APPROVED 或 CANCELLED')
if order.status == target_status:
return order
with transaction.atomic():
order.status = target_status
order.save(update_fields=['status', 'updated_at'])
order.refresh_from_db(fields=['status', 'updated_at'])
return order
def _normalize_order_items(
*,
merchant: basic_info_models.Merchant,
@@ -596,6 +704,28 @@ def _resolve_sales_order_instance(
)
def _resolve_payment_order_instance(
payment_order: models.PaymentOrder | None,
payment_order_id: int | None,
) -> models.PaymentOrder:
if payment_order is None and payment_order_id is None:
raise ValueError('必须提供 payment_order 或 payment_order_id')
if payment_order is not None:
payment_order_id = payment_order.id
return models.PaymentOrder.objects.select_related('merchant', 'supplier').get(id=payment_order_id)
def _resolve_receipt_order_instance(
receipt_order: models.ReceiptOrder | None,
receipt_order_id: int | None,
) -> models.ReceiptOrder:
if receipt_order is None and receipt_order_id is None:
raise ValueError('必须提供 receipt_order 或 receipt_order_id')
if receipt_order is not None:
receipt_order_id = receipt_order.id
return models.ReceiptOrder.objects.select_related('merchant', 'customer').get(id=receipt_order_id)
def _to_decimal(value, field_name: str) -> Decimal:
try:
return Decimal(str(value))
@@ -603,6 +733,13 @@ def _to_decimal(value, field_name: str) -> Decimal:
raise ValueError(f'{field_name} 必须是合法数值') from exc
def _ensure_positive_amount(value, field_name: str) -> Decimal:
amount = _to_decimal(value, field_name)
if amount <= 0:
raise ValueError(f'{field_name} 必须大于 0')
return amount
def _to_positive_int(value, field_name: str) -> int:
if value is None:
raise ValueError(f'{field_name} 不能为空')