forked from erp-dev/erp
feat: running on docker fully, and added rabbitmq/worker container
This commit is contained in:
202
stock/tests.py
202
stock/tests.py
@@ -6,6 +6,7 @@ from unittest.mock import patch, MagicMock
|
||||
import logging
|
||||
|
||||
from basic_info.models import Product, WareHouse, Supplier, ProductUnitEnum, ProductCategory, Merchant, MerchantTypeEnum, WareHouseModeEnum
|
||||
from business.models import PurchaseOrder
|
||||
from . import models, services
|
||||
|
||||
|
||||
@@ -83,7 +84,7 @@ class StockServicesTestCase(TestCase):
|
||||
def setUp(self):
|
||||
"""每个测试方法执行前的设置"""
|
||||
# 创建采购单
|
||||
self.purchase_order = models.PurchaseOrder.objects.create(
|
||||
self.purchase_order = PurchaseOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
supplier=self.supplier,
|
||||
order_date=timezone.now().date(),
|
||||
@@ -456,23 +457,129 @@ class CreateStockChangeRecordWithDetailsTestCase(StockServicesTestCase):
|
||||
|
||||
self.assertIn('宽进宽出', str(ctx.exception))
|
||||
|
||||
def test_strict_mode_not_implemented_for_restrict_in_out(self):
|
||||
"""严进严出模式暂不支持"""
|
||||
def test_restrict_in_out_incoming_behaves_like_strict(self):
|
||||
"""严进严出模式的入库沿用严谨逻辑"""
|
||||
self.warehouse_main.mode = WareHouseModeEnum.RESTRICT_IN_OUT
|
||||
self.warehouse_main.save()
|
||||
|
||||
with self.assertRaises(ValueError) as ctx:
|
||||
record, details, created_count = 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('5.00'), Decimal('6.00')]}],
|
||||
)
|
||||
|
||||
self.assertEqual(created_count, 2)
|
||||
self.assertEqual(record.details.count(), 2)
|
||||
|
||||
def test_restrict_in_out_outgoing_consumes_detail(self):
|
||||
"""严进严出模式的出库需要消耗入库明细"""
|
||||
self.warehouse_main.mode = WareHouseModeEnum.RESTRICT_IN_OUT
|
||||
self.warehouse_main.save()
|
||||
|
||||
products = [{
|
||||
'product': self.product_fabric_a.id,
|
||||
'consume_with': [self.stock_detail_in.id],
|
||||
}]
|
||||
|
||||
record, details, created_count = services.create_stock_change_record_with_details(
|
||||
merchant=self.merchant,
|
||||
created_by=None,
|
||||
type=models.StockChangeTypeEnum.REMOVE,
|
||||
warehouse_id=self.warehouse_main.id,
|
||||
source_type=models.StockChangeSourceEnum.SALES,
|
||||
source_id=123,
|
||||
products=products,
|
||||
)
|
||||
|
||||
self.assertEqual(created_count, 1)
|
||||
detail = details[0]
|
||||
self.stock_detail_in.refresh_from_db()
|
||||
self.assertTrue(self.stock_detail_in.is_consumed)
|
||||
self.assertEqual(detail.consume_with_id, self.stock_detail_in.id)
|
||||
self.assertEqual(detail.quantity, self.stock_detail_in.quantity)
|
||||
|
||||
def test_restrict_in_out_outgoing_requires_consume_ids(self):
|
||||
self.warehouse_main.mode = WareHouseModeEnum.RESTRICT_IN_OUT
|
||||
self.warehouse_main.save()
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
services.create_stock_change_record_with_details(
|
||||
merchant=self.merchant,
|
||||
created_by=None,
|
||||
type=models.StockChangeTypeEnum.ADD,
|
||||
type=models.StockChangeTypeEnum.REMOVE,
|
||||
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')]}],
|
||||
source_type=models.StockChangeSourceEnum.SALES,
|
||||
source_id=123,
|
||||
products=[{'product': self.product_fabric_a.id}],
|
||||
)
|
||||
|
||||
self.assertIn('严进严出', str(ctx.exception))
|
||||
def test_restrict_in_out_outgoing_rejects_consumed_detail(self):
|
||||
self.warehouse_main.mode = WareHouseModeEnum.RESTRICT_IN_OUT
|
||||
self.warehouse_main.save()
|
||||
|
||||
products = [{
|
||||
'product': self.product_fabric_a.id,
|
||||
'consume_with': [self.stock_detail_in.id],
|
||||
}]
|
||||
|
||||
services.create_stock_change_record_with_details(
|
||||
merchant=self.merchant,
|
||||
created_by=None,
|
||||
type=models.StockChangeTypeEnum.REMOVE,
|
||||
warehouse_id=self.warehouse_main.id,
|
||||
source_type=models.StockChangeSourceEnum.SALES,
|
||||
source_id=123,
|
||||
products=products,
|
||||
)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
services.create_stock_change_record_with_details(
|
||||
merchant=self.merchant,
|
||||
created_by=None,
|
||||
type=models.StockChangeTypeEnum.REMOVE,
|
||||
warehouse_id=self.warehouse_main.id,
|
||||
source_type=models.StockChangeSourceEnum.SALES,
|
||||
source_id=124,
|
||||
products=products,
|
||||
)
|
||||
|
||||
def test_restrict_in_out_outgoing_rejects_other_warehouse_detail(self):
|
||||
self.warehouse_main.mode = WareHouseModeEnum.RESTRICT_IN_OUT
|
||||
self.warehouse_main.save()
|
||||
|
||||
other_record = models.StockChangeRecord.objects.create(
|
||||
merchant=self.merchant,
|
||||
type=models.StockChangeTypeEnum.ADD,
|
||||
source_type=models.StockChangeSourceEnum.PURCHASE,
|
||||
warehouse=self.warehouse_backup,
|
||||
)
|
||||
other_detail = models.StockChangeDetail.objects.create(
|
||||
merchant=self.merchant,
|
||||
stock_change_record=other_record,
|
||||
product=self.product_fabric_a,
|
||||
quantity=Decimal('8.00'),
|
||||
unit=self.unit_meter,
|
||||
)
|
||||
|
||||
products = [{
|
||||
'product': self.product_fabric_a.id,
|
||||
'consume_with': [other_detail.id],
|
||||
}]
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
services.create_stock_change_record_with_details(
|
||||
merchant=self.merchant,
|
||||
created_by=None,
|
||||
type=models.StockChangeTypeEnum.REMOVE,
|
||||
warehouse_id=self.warehouse_main.id,
|
||||
source_type=models.StockChangeSourceEnum.SALES,
|
||||
source_id=125,
|
||||
products=products,
|
||||
)
|
||||
|
||||
|
||||
class CreateStockChangeRecordRelaxedTestCase(StockServicesTestCase):
|
||||
@@ -748,5 +855,82 @@ class StockServicesIntegrationTestCase(StockServicesTestCase):
|
||||
self.assertEqual(out_snapshot.quantity_after, 50)
|
||||
|
||||
|
||||
class StockFlowServiceTestCase(TestCase):
|
||||
"""StockFlowService 统一出入库服务测试"""
|
||||
|
||||
def setUp(self):
|
||||
self.merchant = Merchant.objects.create(
|
||||
name='统一服务商户',
|
||||
type=MerchantTypeEnum.FACTORY,
|
||||
)
|
||||
self.category = ProductCategory.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='面料',
|
||||
product_prefix='FAB',
|
||||
)
|
||||
self.product = Product.objects.create(
|
||||
merchant=self.merchant,
|
||||
category=self.category,
|
||||
name='测试面料',
|
||||
human_id='FAB-0001',
|
||||
unit=ProductUnitEnum.METER,
|
||||
)
|
||||
self.strict_warehouse = WareHouse.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='严谨仓',
|
||||
mode=WareHouseModeEnum.RESTRICT_IN,
|
||||
)
|
||||
self.relaxed_warehouse = WareHouse.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='宽松仓',
|
||||
mode=WareHouseModeEnum.UNRESTRICTED,
|
||||
)
|
||||
self.restrict_in_out = WareHouse.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='严进严出仓',
|
||||
mode=WareHouseModeEnum.RESTRICT_IN_OUT,
|
||||
)
|
||||
self.service = services.StockFlowService(merchant=self.merchant, created_by=None)
|
||||
|
||||
def test_stock_in_strict_mode_uses_quantities(self):
|
||||
record, details, count = self.service.stock_in(
|
||||
warehouse_id=self.strict_warehouse.id,
|
||||
source_type=models.StockChangeSourceEnum.PURCHASE,
|
||||
source_id=10,
|
||||
items=[{'product_id': self.product.id, 'quantities': ['5', '3']}],
|
||||
)
|
||||
self.assertEqual(count, 2)
|
||||
self.assertEqual(record.warehouse_id, self.strict_warehouse.id)
|
||||
self.assertEqual(len(details), 2)
|
||||
|
||||
def test_stock_in_relaxed_mode_splits_value(self):
|
||||
_, details, count = self.service.stock_in(
|
||||
warehouse_id=self.relaxed_warehouse.id,
|
||||
source_type=models.StockChangeSourceEnum.PURCHASE,
|
||||
source_id=11,
|
||||
items=[{'product_id': self.product.id, 'value': '9', 'num_of_rolls': 4}],
|
||||
)
|
||||
self.assertEqual(count, 3) # 4 + 4 + 1
|
||||
self.assertEqual(len(details), 3)
|
||||
|
||||
def test_stock_out_restrict_mode_consumes_details(self):
|
||||
_, inbound_details, _ = self.service.stock_in(
|
||||
warehouse_id=self.restrict_in_out.id,
|
||||
source_type=models.StockChangeSourceEnum.PURCHASE,
|
||||
source_id=12,
|
||||
items=[{'product_id': self.product.id, 'quantities': ['6']}],
|
||||
)
|
||||
detail_id = inbound_details[0].id
|
||||
_, outbound_details, _ = self.service.stock_out(
|
||||
warehouse_id=self.restrict_in_out.id,
|
||||
source_type=models.StockChangeSourceEnum.SALES,
|
||||
source_id=13,
|
||||
items=[{'product_id': self.product.id, 'consume_detail_ids': [detail_id]}],
|
||||
)
|
||||
inbound_details[0].refresh_from_db()
|
||||
self.assertTrue(inbound_details[0].is_consumed)
|
||||
self.assertEqual(outbound_details[0].consume_with_id, detail_id)
|
||||
|
||||
|
||||
# 禁用测试期间的日志输出
|
||||
logging.disable(logging.CRITICAL)
|
||||
|
||||
Reference in New Issue
Block a user