1
0
forked from erp-dev/erp

feat: statement for supplier and customer

This commit is contained in:
2025-12-01 22:55:52 +08:00
parent fae33809ac
commit d522c0a9b0
15 changed files with 1085 additions and 52 deletions

View File

@@ -125,6 +125,68 @@ class SalesReturnOrderItemAdmin(admin.ModelAdmin):
return obj.total_amount()
@admin.register(models.SalesOrder)
class SalesOrderAdmin(admin.ModelAdmin):
list_display = ('id', 'customer', 'sales_date', 'operator', 'status', '_total_amount', '_diff_quantity', '_total_quantity', 'created_at')
search_fields = ('customer__name',)
list_filter = ('operator', 'warehouse', 'status', 'created_at')
ordering = ('-created_at',)
@admin.display(description='总价')
def _total_amount(self, obj: models.SalesOrder):
return obj.get_total_amount()
@admin.display(description='差异数量')
def _diff_quantity(self, obj: models.SalesOrder):
return obj.get_total_diff_quantity()
@admin.display(description='总数量')
def _total_quantity(self, obj: models.SalesOrder):
return obj.get_total_quantity()
@admin.register(models.SalesOrderItem)
class SalesOrderItemAdmin(admin.ModelAdmin):
list_display = (
'id', 'sales_order', 'product',
'quantity', 'unit', 'price', 'batch_number',
'_total_amount', 'empty_diff_percent',
'_real_quantity', '_diff_quantity',
'num_of_rolls',
)
search_fields = ('sales_order__id', 'product__name')
list_filter = ('sales_order__operator', 'sales_order__warehouse', 'created_at')
ordering = ('-created_at',)
@admin.display(description='实际数量')
def _real_quantity(self, obj: models.SalesOrderItem):
return obj.real_quantity()
@admin.display(description='差异数量')
def _diff_quantity(self, obj: models.SalesOrderItem):
return obj.diff_quantity()
@admin.display(description='总金额')
def _total_amount(self, obj: models.SalesOrderItem):
return obj.total_amount()
@admin.register(models.PaymentOrder)
class PaymentOrderAdmin(admin.ModelAdmin):
list_display = ('id', 'supplier', 'payment_date', 'amount', 'operator', 'status', 'created_at')
search_fields = ('supplier__name',)
list_filter = ('operator', 'status', 'created_at')
ordering = ('-created_at',)
@admin.register(models.ReceiptOrder)
class ReceiptOrderAdmin(admin.ModelAdmin):
list_display = ('id', 'customer', 'receipt_date', 'amount', 'operator', 'status', 'created_at')
search_fields = ('customer__name',)
list_filter = ('operator', 'status', 'created_at')
ordering = ('-created_at',)
@admin.register(models.CustomerBalance)
class CustomerBalancemAdmin(admin.ModelAdmin):
list_display = ('id', 'customer', 'balance', 'created_at')
@@ -132,6 +194,13 @@ class CustomerBalancemAdmin(admin.ModelAdmin):
ordering = ('-created_at',)
@admin.register(models.SupplierBalance)
class SupplierBalanceAdmin(admin.ModelAdmin):
list_display = ('id', 'supplier', 'balance', 'created_at')
search_fields = ('supplier__name',)
ordering = ('-created_at',)
@admin.register(models.BalanceChangeRecord)
class BalanceChangeRecordAdmin(admin.ModelAdmin):
list_display = ('id', 'merchant', 'target_type', 'source_type', 'source_id', 'delta', 'balance_before', 'balance_after', 'direction', 'created_at')

View File

@@ -1246,7 +1246,7 @@ def _build_stock_flow_items_from_order(order) -> List[Dict[str, Any]]:
items_payload.append({
'product_id': item.product_id,
'value': str(item.quantity),
'num_of_rolls': item.num_of_rolls,
'num_of_rolls': item.num_of_rolls or 1,
})
return items_payload

View File

@@ -276,6 +276,27 @@ class PurchaseOrderServiceTestCase(TestCase):
created_by_id=self.user.id,
)
def test_purchase_order_relaxed_mode_even_split(self):
purchase_order = services.create_purchase_order(
merchant=self.merchant,
supplier=self.supplier,
order_date=timezone.now().date(),
warehouse=self.warehouse_relaxed,
operator=self.operator,
items=[{'product_id': self.product.id, 'quantity': 99, 'num_of_rolls': 2, 'price': '10.0', 'unit': ''}],
created_by=self.user,
)
stock_flow_items = services._build_stock_flow_items_from_order(purchase_order)
payload = services.create_purchase_order_stock_entries_sync(
purchase_order_id=purchase_order.id,
warehouse_id=self.warehouse_relaxed.id,
items=stock_flow_items,
created_by_id=self.user.id,
)
record = stock_models.StockChangeRecord.objects.get(id=payload['stock_change_record_id'])
quantities = sorted([detail.quantity for detail in record.details.order_by('id')], reverse=True)
self.assertEqual(quantities, [Decimal('49.50'), Decimal('49.50')])
class SalesOrderServiceTestCase(TestCase):
def setUp(self):
@@ -633,6 +654,40 @@ class SalesReturnServiceTestCase(TestCase):
target_status=business_models.SalesReturnStatusEnum.CANCELLED,
)
def test_sales_return_relaxed_mode_stock_payload_preserves_rolls(self):
order = services.create_sales_return_order(
merchant=self.merchant,
customer=self.customer,
return_date=timezone.now().date(),
warehouse=self.warehouse_relaxed,
operator=self.operator,
items=[{'product_id': self.product.id, 'quantity': 100, 'num_of_rolls': 1, 'price': '22.0'}],
)
stock_flow_items = services._build_stock_flow_items_from_order(order)
self.assertEqual(len(stock_flow_items), 1)
self.assertEqual(stock_flow_items[0]['num_of_rolls'], 1)
def test_sales_return_relaxed_mode_even_split(self):
order = services.create_sales_return_order(
merchant=self.merchant,
customer=self.customer,
return_date=timezone.now().date(),
warehouse=self.warehouse_relaxed,
operator=self.operator,
items=[{'product_id': self.product.id, 'quantity': 100, 'num_of_rolls': 3, 'price': '22.0'}],
created_by=self.user,
)
stock_flow_items = services._build_stock_flow_items_from_order(order)
payload = services.create_sales_return_order_stock_entries_sync(
sales_return_order_id=order.id,
warehouse_id=self.warehouse_relaxed.id,
items=stock_flow_items,
created_by_id=self.user.id,
)
record = stock_models.StockChangeRecord.objects.get(id=payload['stock_change_record_id'])
quantities = sorted([detail.quantity for detail in record.details.order_by('id')], reverse=True)
self.assertEqual(quantities, [Decimal('33.34'), Decimal('33.33'), Decimal('33.33')])
class PaymentReceiptServiceTestCase(TestCase):
def setUp(self):
(