forked from erp-dev/erp
feat: settlement first api beta
This commit is contained in:
510
settlement/test_services.py
Normal file
510
settlement/test_services.py
Normal file
@@ -0,0 +1,510 @@
|
||||
"""Settlement Service 测试"""
|
||||
from datetime import date, datetime
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
|
||||
from basic_info import models as basic_models
|
||||
from printing import models as printing_models
|
||||
from settlement import services
|
||||
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class SettlementServiceTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.merchant = basic_models.Merchant.objects.create(
|
||||
name='测试商户',
|
||||
type=basic_models.MerchantTypeEnum.FACTORY
|
||||
)
|
||||
|
||||
self.user = User.objects.create_user(
|
||||
username='test-user',
|
||||
password='pass123'
|
||||
)
|
||||
self.employee = basic_models.Employee.objects.create(
|
||||
sys_user=self.user,
|
||||
merchant=self.merchant,
|
||||
name='测试员工'
|
||||
)
|
||||
|
||||
self.customer1 = basic_models.Customer.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='客户A',
|
||||
created_by=self.employee
|
||||
)
|
||||
self.customer2 = basic_models.Customer.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='客户B',
|
||||
created_by=self.employee
|
||||
)
|
||||
|
||||
self.settlement_date = date(2026, 2, 8)
|
||||
|
||||
|
||||
class GetPlateOrderQuerySetTestCase(SettlementServiceTestCase):
|
||||
def test_filters_by_merchant(self):
|
||||
other_merchant = basic_models.Merchant.objects.create(
|
||||
name='其他商户',
|
||||
type=basic_models.MerchantTypeEnum.FACTORY
|
||||
)
|
||||
other_customer = basic_models.Customer.objects.create(
|
||||
merchant=other_merchant,
|
||||
name='其他客户'
|
||||
)
|
||||
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method='定位'
|
||||
)
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=other_merchant,
|
||||
customer=other_customer,
|
||||
plate_type='首版',
|
||||
production_method='定位'
|
||||
)
|
||||
|
||||
queryset = services._get_plate_order_queryset(
|
||||
self.merchant.id,
|
||||
self.user
|
||||
)
|
||||
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertEqual(queryset.first().customer.name, '客户A')
|
||||
|
||||
def test_filters_by_plate_type_not_null(self):
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method='定位'
|
||||
)
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type=None,
|
||||
production_method='定位'
|
||||
)
|
||||
|
||||
queryset = services._get_plate_order_queryset(
|
||||
self.merchant.id,
|
||||
self.user
|
||||
)
|
||||
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertIsNotNone(queryset.first().plate_type)
|
||||
|
||||
def test_applies_customer_visibility_filter(self):
|
||||
other_employee = basic_models.Employee.objects.create(
|
||||
sys_user=User.objects.create_user('other', 'pass123'),
|
||||
merchant=self.merchant,
|
||||
name='其他员工'
|
||||
)
|
||||
|
||||
customer_visible = basic_models.Customer.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='可见客户',
|
||||
created_by=other_employee
|
||||
)
|
||||
customer_visible.visible_employees.set([self.employee])
|
||||
customer_invisible = basic_models.Customer.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='不可见客户',
|
||||
created_by=other_employee
|
||||
)
|
||||
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=customer_visible,
|
||||
plate_type='首版',
|
||||
production_method='定位'
|
||||
)
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=customer_invisible,
|
||||
plate_type='首版',
|
||||
production_method='定位'
|
||||
)
|
||||
|
||||
queryset = services._get_plate_order_queryset(
|
||||
self.merchant.id,
|
||||
self.user
|
||||
)
|
||||
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertEqual(queryset.first().customer.name, '可见客户')
|
||||
|
||||
def test_superuser_sees_all_customers(self):
|
||||
self.user.is_superuser = True
|
||||
self.user.save()
|
||||
|
||||
other_employee = basic_models.Employee.objects.create(
|
||||
sys_user=User.objects.create_user('other', 'pass123'),
|
||||
merchant=self.merchant,
|
||||
name='其他员工'
|
||||
)
|
||||
customer_invisible = basic_models.Customer.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='不可见客户',
|
||||
created_by=other_employee
|
||||
)
|
||||
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=customer_invisible,
|
||||
plate_type='首版',
|
||||
production_method='定位'
|
||||
)
|
||||
|
||||
queryset = services._get_plate_order_queryset(
|
||||
self.merchant.id,
|
||||
self.user
|
||||
)
|
||||
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
|
||||
|
||||
class GetMonthDateRangeTestCase(TestCase):
|
||||
def test_returns_month_start_and_settlement_date(self):
|
||||
settlement_date = date(2026, 2, 8)
|
||||
month_start, end_date = services._get_month_date_range(settlement_date)
|
||||
|
||||
self.assertEqual(month_start, date(2026, 2, 1))
|
||||
self.assertEqual(end_date, date(2026, 2, 8))
|
||||
|
||||
def test_handles_month_start(self):
|
||||
settlement_date = date(2026, 2, 1)
|
||||
month_start, end_date = services._get_month_date_range(settlement_date)
|
||||
|
||||
self.assertEqual(month_start, date(2026, 2, 1))
|
||||
self.assertEqual(end_date, date(2026, 2, 1))
|
||||
|
||||
def test_handles_month_end(self):
|
||||
settlement_date = date(2026, 2, 28)
|
||||
month_start, end_date = services._get_month_date_range(settlement_date)
|
||||
|
||||
self.assertEqual(month_start, date(2026, 2, 1))
|
||||
self.assertEqual(end_date, date(2026, 2, 28))
|
||||
|
||||
def test_handles_different_months(self):
|
||||
settlement_date = date(2026, 3, 15)
|
||||
month_start, end_date = services._get_month_date_range(settlement_date)
|
||||
|
||||
self.assertEqual(month_start, date(2026, 3, 1))
|
||||
self.assertEqual(end_date, date(2026, 3, 15))
|
||||
|
||||
|
||||
class AggregatePlateOrdersByCustomerAndTypeTestCase(SettlementServiceTestCase):
|
||||
def test_aggregates_by_customer_and_type(self):
|
||||
today = self.settlement_date
|
||||
yesterday = date(2026, 2, 7)
|
||||
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method='定位',
|
||||
plate_date=timezone.make_aware(datetime.combine(today, datetime.min.time()))
|
||||
)
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='修改',
|
||||
production_method='定位',
|
||||
plate_date=timezone.make_aware(datetime.combine(yesterday, datetime.min.time()))
|
||||
)
|
||||
|
||||
queryset = services._get_plate_order_queryset(
|
||||
self.merchant.id,
|
||||
self.user
|
||||
)
|
||||
aggregated = services._aggregate_plate_orders_by_customer_and_type(
|
||||
queryset, self.settlement_date
|
||||
)
|
||||
|
||||
self.assertEqual(len(aggregated), 2)
|
||||
|
||||
def test_calculates_today_count(self):
|
||||
today = self.settlement_date
|
||||
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method='定位',
|
||||
plate_date=timezone.make_aware(datetime.combine(today, datetime.min.time()))
|
||||
)
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method='定位',
|
||||
plate_date=timezone.make_aware(datetime.combine(date(2026, 2, 7), datetime.min.time()))
|
||||
)
|
||||
|
||||
queryset = services._get_plate_order_queryset(
|
||||
self.merchant.id,
|
||||
self.user
|
||||
)
|
||||
aggregated = services._aggregate_plate_orders_by_customer_and_type(
|
||||
queryset, self.settlement_date
|
||||
)
|
||||
|
||||
today_item = [item for item in aggregated if item['type'] == '首版-定位'][0]
|
||||
self.assertEqual(today_item['today'], 1)
|
||||
|
||||
def test_calculates_current_month_count(self):
|
||||
today = self.settlement_date
|
||||
month_start = date(2026, 2, 1)
|
||||
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method='定位',
|
||||
plate_date=timezone.make_aware(datetime.combine(today, datetime.min.time()))
|
||||
)
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method='定位',
|
||||
plate_date=timezone.make_aware(datetime.combine(month_start, datetime.min.time()))
|
||||
)
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method='定位',
|
||||
plate_date=timezone.make_aware(datetime.combine(date(2026, 1, 31), datetime.min.time()))
|
||||
)
|
||||
|
||||
queryset = services._get_plate_order_queryset(
|
||||
self.merchant.id,
|
||||
self.user
|
||||
)
|
||||
aggregated = services._aggregate_plate_orders_by_customer_and_type(
|
||||
queryset, self.settlement_date
|
||||
)
|
||||
|
||||
today_item = [item for item in aggregated if item['type'] == '首版-定位'][0]
|
||||
self.assertEqual(today_item['current_month'], 2)
|
||||
|
||||
def test_filters_null_production_method(self):
|
||||
today = self.settlement_date
|
||||
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method='定位',
|
||||
plate_date=timezone.make_aware(datetime.combine(today, datetime.min.time()))
|
||||
)
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method=None,
|
||||
plate_date=timezone.make_aware(datetime.combine(today, datetime.min.time()))
|
||||
)
|
||||
|
||||
queryset = services._get_plate_order_queryset(
|
||||
self.merchant.id,
|
||||
self.user
|
||||
)
|
||||
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertEqual(queryset.first().production_method, '定位')
|
||||
|
||||
|
||||
class FilterZeroDataTestCase(SettlementServiceTestCase):
|
||||
def test_filters_all_zero_data(self):
|
||||
data = [
|
||||
{'type': '首版-定位', 'today': 0, 'current_month': 0},
|
||||
{'type': '修改-定位', 'today': 0, 'current_month': 0}
|
||||
]
|
||||
|
||||
result = services._filter_zero_data(data)
|
||||
|
||||
self.assertEqual(len(result), 0)
|
||||
|
||||
def test_keeps_non_zero_today(self):
|
||||
data = [
|
||||
{'type': '首版-定位', 'today': 1, 'current_month': 0},
|
||||
{'type': '修改-定位', 'today': 0, 'current_month': 0}
|
||||
]
|
||||
|
||||
result = services._filter_zero_data(data)
|
||||
|
||||
self.assertEqual(len(result), 1)
|
||||
self.assertEqual(result[0]['type'], '首版-定位')
|
||||
|
||||
def test_keeps_non_zero_current_month(self):
|
||||
data = [
|
||||
{'type': '首版-定位', 'today': 0, 'current_month': 5},
|
||||
{'type': '修改-定位', 'today': 0, 'current_month': 0}
|
||||
]
|
||||
|
||||
result = services._filter_zero_data(data)
|
||||
|
||||
self.assertEqual(len(result), 1)
|
||||
self.assertEqual(result[0]['type'], '首版-定位')
|
||||
|
||||
|
||||
class FormatPlateOrderSummaryTestCase(SettlementServiceTestCase):
|
||||
def test_formats_aggregated_data(self):
|
||||
aggregated = [
|
||||
{
|
||||
'customer__id': self.customer1.id,
|
||||
'customer__name': '客户A',
|
||||
'type': '首版-定位',
|
||||
'today': 5,
|
||||
'current_month': 10
|
||||
},
|
||||
{
|
||||
'customer__id': self.customer1.id,
|
||||
'customer__name': '客户A',
|
||||
'type': '修改-定位',
|
||||
'today': 2,
|
||||
'current_month': 3
|
||||
}
|
||||
]
|
||||
|
||||
result = services._format_plate_order_summary(aggregated)
|
||||
|
||||
self.assertEqual(len(result), 1)
|
||||
self.assertEqual(result[0]['client_id'], self.customer1.id)
|
||||
self.assertEqual(result[0]['client_name'], '客户A')
|
||||
self.assertEqual(len(result[0]['plate_order_count']), 2)
|
||||
|
||||
def test_filters_customers_with_zero_data(self):
|
||||
aggregated = [
|
||||
{
|
||||
'customer__id': self.customer1.id,
|
||||
'customer__name': '客户A',
|
||||
'type': '首版-定位',
|
||||
'today': 0,
|
||||
'current_month': 0
|
||||
}
|
||||
]
|
||||
|
||||
result = services._format_plate_order_summary(aggregated)
|
||||
|
||||
self.assertEqual(len(result), 0)
|
||||
|
||||
def test_groups_by_customer(self):
|
||||
aggregated = [
|
||||
{
|
||||
'customer__id': self.customer1.id,
|
||||
'customer__name': '客户A',
|
||||
'type': '首版-定位',
|
||||
'today': 5,
|
||||
'current_month': 10
|
||||
},
|
||||
{
|
||||
'customer__id': self.customer2.id,
|
||||
'customer__name': '客户B',
|
||||
'type': '首版-定位',
|
||||
'today': 3,
|
||||
'current_month': 6
|
||||
}
|
||||
]
|
||||
|
||||
result = services._format_plate_order_summary(aggregated)
|
||||
|
||||
self.assertEqual(len(result), 2)
|
||||
self.assertEqual(result[0]['client_id'], self.customer1.id)
|
||||
self.assertEqual(result[0]['client_name'], '客户A')
|
||||
self.assertEqual(result[1]['client_id'], self.customer2.id)
|
||||
self.assertEqual(result[1]['client_name'], '客户B')
|
||||
|
||||
def test_groups_same_name_customers_by_customer_id(self):
|
||||
aggregated = [
|
||||
{
|
||||
'customer__id': self.customer1.id,
|
||||
'customer__name': '同名客户',
|
||||
'type': '首版-定位',
|
||||
'today': 1,
|
||||
'current_month': 2
|
||||
},
|
||||
{
|
||||
'customer__id': self.customer2.id,
|
||||
'customer__name': '同名客户',
|
||||
'type': '修改-定位',
|
||||
'today': 3,
|
||||
'current_month': 4
|
||||
}
|
||||
]
|
||||
|
||||
result = services._format_plate_order_summary(aggregated)
|
||||
|
||||
self.assertEqual(len(result), 2)
|
||||
self.assertNotEqual(result[0]['client_id'], result[1]['client_id'])
|
||||
|
||||
|
||||
class GetPlateOrderSummaryByCustomerTestCase(SettlementServiceTestCase):
|
||||
def test_returns_summary_for_multiple_customers(self):
|
||||
today = self.settlement_date
|
||||
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method='定位',
|
||||
plate_date=timezone.make_aware(datetime.combine(today, datetime.min.time()))
|
||||
)
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer2,
|
||||
plate_type='首版',
|
||||
production_method='匹布',
|
||||
plate_date=timezone.make_aware(datetime.combine(today, datetime.min.time()))
|
||||
)
|
||||
|
||||
result = services.get_plate_order_summary_by_customer(
|
||||
self.merchant.id,
|
||||
self.settlement_date,
|
||||
self.user
|
||||
)
|
||||
|
||||
self.assertEqual(len(result), 2)
|
||||
self.assertIn('client_id', result[0])
|
||||
|
||||
def test_filters_zero_data(self):
|
||||
today = self.settlement_date
|
||||
|
||||
printing_models.PlateOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer1,
|
||||
plate_type='首版',
|
||||
production_method='定位',
|
||||
plate_date=timezone.make_aware(datetime.combine(date(2026, 1, 1), datetime.min.time()))
|
||||
)
|
||||
|
||||
result = services.get_plate_order_summary_by_customer(
|
||||
self.merchant.id,
|
||||
self.settlement_date,
|
||||
self.user
|
||||
)
|
||||
|
||||
self.assertEqual(len(result), 0)
|
||||
|
||||
def test_raises_for_invalid_merchant_id(self):
|
||||
with self.assertRaises(ValueError):
|
||||
services.get_plate_order_summary_by_customer(
|
||||
merchant_id=0,
|
||||
settlement_date=self.settlement_date,
|
||||
user=self.user
|
||||
)
|
||||
|
||||
def test_raises_for_invalid_settlement_date(self):
|
||||
with self.assertRaises(ValueError):
|
||||
services.get_plate_order_summary_by_customer(
|
||||
merchant_id=self.merchant.id,
|
||||
settlement_date='2026-02-08',
|
||||
user=self.user
|
||||
)
|
||||
Reference in New Issue
Block a user