"""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 )