1
0
forked from erp-dev/erp

feat: relaxed in restrict out

This commit is contained in:
2025-11-24 15:57:19 +08:00
parent 113818f73d
commit cd6a2370fc
11 changed files with 840 additions and 5 deletions

View File

@@ -5,7 +5,7 @@ from decimal import Decimal
from unittest.mock import patch, MagicMock
import logging
from basic_info.models import Product, WareHouse, Supplier, ProductUnitEnum, ProductCategory, Merchant, MerchantTypeEnum
from basic_info.models import Product, WareHouse, Supplier, ProductUnitEnum, ProductCategory, Merchant, MerchantTypeEnum, WareHouseModeEnum
from . import models, services
@@ -437,6 +437,191 @@ class CreateStockChangeRecordWithDetailsTestCase(StockServicesTestCase):
source_id=self.purchase_order.id,
products=products,
)
def test_strict_mode_requires_restrict_in(self):
"""严谨模式仅允许在严进宽出仓库中使用"""
self.warehouse_main.mode = WareHouseModeEnum.UNRESTRICTED
self.warehouse_main.save()
with self.assertRaises(ValueError) as ctx:
services.create_stock_change_record_with_details(
merchant=self.merchant,
created_by=None,
type=models.StockChangeTypeEnum.ADD,
warehouse_id=self.warehouse_main.id,
source_type=models.StockChangeSourceEnum.PURCHASE,
source_id=self.purchase_order.id,
products=[{'product': self.product_fabric_a.id, 'quantity': [Decimal('10.00')]}],
)
self.assertIn('宽进宽出', str(ctx.exception))
def test_strict_mode_not_implemented_for_restrict_in_out(self):
"""严进严出模式暂不支持"""
self.warehouse_main.mode = WareHouseModeEnum.RESTRICT_IN_OUT
self.warehouse_main.save()
with self.assertRaises(ValueError) as ctx:
services.create_stock_change_record_with_details(
merchant=self.merchant,
created_by=None,
type=models.StockChangeTypeEnum.ADD,
warehouse_id=self.warehouse_main.id,
source_type=models.StockChangeSourceEnum.PURCHASE,
source_id=self.purchase_order.id,
products=[{'product': self.product_fabric_a.id, 'quantity': [Decimal('10.00')]}],
)
self.assertIn('严进严出', str(ctx.exception))
class CreateStockChangeRecordRelaxedTestCase(StockServicesTestCase):
"""测试宽松模式的库存变动创建"""
def setUp(self):
super().setUp()
self.warehouse_main.mode = WareHouseModeEnum.UNRESTRICTED
self.warehouse_main.save()
def test_relaxed_even_split(self):
products = [
{
'product': self.product_fabric_a.id,
'quantity': {'value': Decimal('100.00'), 'unit_count': Decimal('25.00')},
}
]
record, details, created_count = services.create_stock_change_record_relaxed(
merchant=self.merchant,
created_by=None,
type=models.StockChangeTypeEnum.ADD,
warehouse_id=self.warehouse_main.id,
source_type=models.StockChangeSourceEnum.PURCHASE,
source_id=self.purchase_order.id,
products=products,
)
self.assertEqual(created_count, 4)
self.assertEqual(record.details.count(), 4)
self.assertListEqual(
[detail.quantity for detail in details],
[Decimal('25.00')] * 4,
)
def test_relaxed_with_remainder(self):
products = [
{
'product': self.product_fabric_a.id,
'quantity': {'value': Decimal('105.00'), 'unit_count': Decimal('30.00')},
}
]
_, details, created_count = services.create_stock_change_record_relaxed(
merchant=self.merchant,
created_by=None,
type=models.StockChangeTypeEnum.ADD,
warehouse_id=self.warehouse_main.id,
source_type=models.StockChangeSourceEnum.PURCHASE,
source_id=self.purchase_order.id,
products=products,
)
self.assertEqual(created_count, 4)
self.assertListEqual(
[detail.quantity for detail in details],
[Decimal('30.00'), Decimal('30.00'), Decimal('30.00'), Decimal('15.00')],
)
def test_relaxed_invalid_unit_count(self):
products = [
{
'product': self.product_fabric_a.id,
'quantity': {'value': Decimal('50.00'), 'unit_count': Decimal('0')},
}
]
with self.assertRaises(ValueError):
services.create_stock_change_record_relaxed(
merchant=self.merchant,
created_by=None,
type=models.StockChangeTypeEnum.ADD,
warehouse_id=self.warehouse_main.id,
source_type=models.StockChangeSourceEnum.PURCHASE,
source_id=self.purchase_order.id,
products=products,
)
def test_relaxed_auto_complete_triggers_completion(self):
self.merchant.auto_complete_stock_change = True
self.merchant.save()
products = [
{
'product': self.product_fabric_a.id,
'quantity': {'value': Decimal('10.00'), 'unit_count': Decimal('2.00')},
}
]
with patch('stock.services.make_stock_change_completed') as mock_complete:
services.create_stock_change_record_relaxed(
merchant=self.merchant,
created_by=None,
type=models.StockChangeTypeEnum.ADD,
warehouse_id=self.warehouse_main.id,
source_type=models.StockChangeSourceEnum.PURCHASE,
source_id=self.purchase_order.id,
products=products,
)
mock_complete.assert_called_once()
def test_relaxed_mode_requires_unrestricted(self):
self.warehouse_main.mode = WareHouseModeEnum.RESTRICT_IN
self.warehouse_main.save()
products = [
{
'product': self.product_fabric_a.id,
'quantity': {'value': Decimal('10.00'), 'unit_count': Decimal('2.00')},
}
]
with self.assertRaises(ValueError) as ctx:
services.create_stock_change_record_relaxed(
merchant=self.merchant,
created_by=None,
type=models.StockChangeTypeEnum.ADD,
warehouse_id=self.warehouse_main.id,
source_type=models.StockChangeSourceEnum.PURCHASE,
source_id=self.purchase_order.id,
products=products,
)
self.assertIn('严进宽出', str(ctx.exception))
def test_relaxed_mode_not_implemented_for_restrict_in_out(self):
self.warehouse_main.mode = WareHouseModeEnum.RESTRICT_IN_OUT
self.warehouse_main.save()
products = [
{
'product': self.product_fabric_a.id,
'quantity': {'value': Decimal('10.00'), 'unit_count': Decimal('2.00')},
}
]
with self.assertRaises(ValueError) as ctx:
services.create_stock_change_record_relaxed(
merchant=self.merchant,
created_by=None,
type=models.StockChangeTypeEnum.ADD,
warehouse_id=self.warehouse_main.id,
source_type=models.StockChangeSourceEnum.PURCHASE,
source_id=self.purchase_order.id,
products=products,
)
self.assertIn('严进严出', str(ctx.exception))
def test_complete_outbound_record(self):
"""测试完成出库记录"""