from decimal import Decimal from django.test import TestCase, override_settings from django.utils import timezone from basic_info import models as basic_models from business import services from business.amounts import calculate_line_amount, normalize_money_amount from .fixtures import create_basic_fixtures class BusinessAmountRulesTestCase(TestCase): def setUp(self): ( self.merchant, self.supplier, self.warehouse_strict, self.warehouse_relaxed, self.product, self.operator, ) = create_basic_fixtures() def test_line_amount_rounds_half_up_to_integer(self): self.assertEqual(calculate_line_amount(quantity='1', price='1.49'), Decimal('1')) self.assertEqual(calculate_line_amount(quantity='1', price='1.50'), Decimal('2')) self.assertEqual(calculate_line_amount(quantity='1.5', price='1.5'), Decimal('2')) self.assertEqual(calculate_line_amount(quantity='1', price='2.5'), Decimal('3')) def test_order_total_sums_rounded_line_amounts(self): 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': '1', 'num_of_rolls': 1, 'price': '1.5', 'unit': '米'}, {'product_id': self.product.id, 'quantity': '1', 'num_of_rolls': 1, 'price': '1.5', 'unit': '米'}, ], ) self.assertEqual([item.total_amount() for item in order.items.order_by('id')], [Decimal('2'), Decimal('2')]) self.assertEqual(order.get_total_amount(), Decimal('4')) def test_payment_and_receipt_amounts_are_normalized_on_create(self): payment = services.create_payment_order( merchant=self.merchant, supplier=self.supplier, payment_date=timezone.now().date(), amount='120.50', discount_amount='20.49', operator=self.operator, ) self.assertEqual(payment.amount, Decimal('121')) self.assertEqual(payment.discount_amount, Decimal('20')) self.assertEqual(payment.settlement_amount, Decimal('141')) customer = basic_models.Customer.objects.create( merchant=self.merchant, name='金额测试客户', created_by=None, ) receipt = services.create_receipt_order( merchant=self.merchant, customer=customer, receipt_date=timezone.now().date(), amount='80.49', discount_amount='5.50', operator=self.operator, ) self.assertEqual(receipt.amount, Decimal('80')) self.assertEqual(receipt.discount_amount, Decimal('6')) self.assertEqual(receipt.settlement_amount, Decimal('86')) def test_normalize_money_amount_rounds_negative_half_away_from_zero(self): self.assertEqual(normalize_money_amount('-25.50'), Decimal('-26')) @override_settings(BUSINESS_AMOUNT_MODE='standard_decimal_2') def test_standard_decimal_mode_preserves_original_precision(self): self.assertEqual( calculate_line_amount(quantity='10', standard_quantity='9.50', price='12.345'), Decimal('117.28'), ) payment = services.create_payment_order( merchant=self.merchant, supplier=self.supplier, payment_date=timezone.now().date(), amount='120.50', discount_amount='20.49', operator=self.operator, ) self.assertEqual(payment.amount, Decimal('120.50')) self.assertEqual(payment.discount_amount, Decimal('20.49')) self.assertEqual(payment.settlement_amount, Decimal('140.99')) @override_settings(BUSINESS_AMOUNT_MODE='unknown_mode') def test_invalid_amount_mode_fails_fast(self): with self.assertRaisesMessage(ValueError, 'BUSINESS_AMOUNT_MODE 不合法'): calculate_line_amount(quantity='1', price='1')