forked from erp-dev/erp
192 lines
6.9 KiB
Python
192 lines
6.9 KiB
Python
from decimal import Decimal
|
|
|
|
from django.contrib.auth import get_user_model
|
|
from django.test import TestCase, override_settings
|
|
|
|
from basic_info.models import (
|
|
Merchant,
|
|
MerchantTypeEnum,
|
|
Customer,
|
|
WareHouse,
|
|
WareHouseModeEnum,
|
|
ProductCategory,
|
|
Product,
|
|
ProductUnitEnum,
|
|
Employee,
|
|
EmployeeStatusEnum,
|
|
)
|
|
from business import models as business_models
|
|
from business import allocation_services
|
|
from stock import models as stock_models
|
|
|
|
|
|
@override_settings(
|
|
CELERY_TASK_ALWAYS_EAGER=True,
|
|
CELERY_TASK_EAGER_PROPAGATES=True,
|
|
)
|
|
class AllocationServicesTestCase(TestCase):
|
|
def setUp(self):
|
|
self.merchant = Merchant.objects.create(name='配货商户', type=MerchantTypeEnum.FACTORY)
|
|
self.customer = Customer.objects.create(
|
|
merchant=self.merchant,
|
|
name='配货客户',
|
|
created_by=None,
|
|
)
|
|
self.warehouse = WareHouse.objects.create(
|
|
merchant=self.merchant,
|
|
name='配货仓库',
|
|
mode=WareHouseModeEnum.UNRESTRICTED,
|
|
)
|
|
category = ProductCategory.objects.create(
|
|
merchant=self.merchant,
|
|
name='配货品类',
|
|
product_prefix='ALC',
|
|
)
|
|
self.product = Product.objects.create(
|
|
merchant=self.merchant,
|
|
category=category,
|
|
name='配货产品',
|
|
human_id='ALC-001',
|
|
unit=ProductUnitEnum.METER,
|
|
)
|
|
self.other_product = Product.objects.create(
|
|
merchant=self.merchant,
|
|
category=category,
|
|
name='其他产品',
|
|
human_id='ALC-002',
|
|
unit=ProductUnitEnum.METER,
|
|
)
|
|
|
|
User = get_user_model()
|
|
self.user = User.objects.create_user(username='allocation_user', password='pass123')
|
|
self.employee = Employee.objects.create(
|
|
merchant=self.merchant,
|
|
sys_user=self.user,
|
|
name='配货员',
|
|
status=EmployeeStatusEnum.ACTIVE,
|
|
)
|
|
|
|
self.pre_sales_order = business_models.PreSalesOrder.objects.create(
|
|
merchant=self.merchant,
|
|
customer=self.customer,
|
|
warehouse=self.warehouse,
|
|
created_by=self.user,
|
|
operator=self.employee,
|
|
kind=business_models.SalesOrderKindEnum.WHOLESALE,
|
|
remarks='预销售单备注',
|
|
)
|
|
self.item = business_models.PreSalesOrderItem.objects.create(
|
|
pre_sales_order=self.pre_sales_order,
|
|
product_id=self.product.id,
|
|
product_name=self.product.name,
|
|
quantity=Decimal('12.5'),
|
|
unit='米',
|
|
remarks='明细备注',
|
|
)
|
|
|
|
self.stock_record = stock_models.StockChangeRecord.objects.create(
|
|
merchant=self.merchant,
|
|
type=stock_models.StockChangeTypeEnum.ADD,
|
|
warehouse=self.warehouse,
|
|
source_type=stock_models.StockChangeSourceEnum.PURCHASE,
|
|
created_by=self.user,
|
|
)
|
|
self.stock_detail = stock_models.StockChangeDetail.objects.create(
|
|
merchant=self.merchant,
|
|
product=self.product,
|
|
unit=ProductUnitEnum.METER,
|
|
stock_change_record=self.stock_record,
|
|
quantity='12.5',
|
|
)
|
|
|
|
def test_validate_stock_details_missing(self):
|
|
with self.assertRaises(ValueError) as ctx:
|
|
allocation_services.validate_stock_details(
|
|
merchant=self.merchant,
|
|
stock_ids=[999999],
|
|
)
|
|
self.assertIn('库存明细不存在', str(ctx.exception))
|
|
|
|
def test_validate_stock_details_consumed(self):
|
|
self.stock_detail.is_consumed = True
|
|
self.stock_detail.save(update_fields=['is_consumed'])
|
|
|
|
with self.assertRaises(ValueError) as ctx:
|
|
allocation_services.validate_stock_details(
|
|
merchant=self.merchant,
|
|
stock_ids=[self.stock_detail.id],
|
|
)
|
|
self.assertIn('库存明细已被消费', str(ctx.exception))
|
|
|
|
def test_validate_stock_details_frozen(self):
|
|
stock_models.StockFreeze.objects.create(
|
|
merchant=self.merchant,
|
|
product=self.product,
|
|
warehouse=self.warehouse,
|
|
stock_detail=self.stock_detail,
|
|
quantity=Decimal('1'),
|
|
unit=ProductUnitEnum.METER,
|
|
status=stock_models.StockFreezeStatusEnum.FROZEN,
|
|
frozen_by=self.user,
|
|
)
|
|
|
|
with self.assertRaises(ValueError) as ctx:
|
|
allocation_services.validate_stock_details(
|
|
merchant=self.merchant,
|
|
stock_ids=[self.stock_detail.id],
|
|
)
|
|
self.assertIn('库存明细已被冻结', str(ctx.exception))
|
|
|
|
def test_create_allocation_record_product_mismatch(self):
|
|
other_detail = stock_models.StockChangeDetail.objects.create(
|
|
merchant=self.merchant,
|
|
product=self.other_product,
|
|
unit=ProductUnitEnum.METER,
|
|
stock_change_record=self.stock_record,
|
|
quantity='3.0',
|
|
)
|
|
|
|
with self.assertRaises(ValueError) as ctx:
|
|
allocation_services.create_allocation_record(
|
|
item=self.item,
|
|
stock_ids=[other_detail.id],
|
|
quantity='3.0',
|
|
unit='米',
|
|
scanned_by=self.employee,
|
|
)
|
|
self.assertIn('库存明细产品不匹配', str(ctx.exception))
|
|
|
|
def test_create_allocation_record_success(self):
|
|
record = allocation_services.create_allocation_record(
|
|
item=self.item,
|
|
stock_ids=[self.stock_detail.id],
|
|
quantity='5.5',
|
|
unit='米',
|
|
scanned_by=self.employee,
|
|
remarks='扫码录入',
|
|
)
|
|
self.assertEqual(record.pre_sales_order_item_id, self.item.id)
|
|
self.assertEqual(record.stock_ids, str(self.stock_detail.id))
|
|
self.assertEqual(record.stock_id_list, [self.stock_detail.id])
|
|
self.assertEqual(record.status, business_models.AllocationRecordStatusEnum.ACTIVE)
|
|
freeze_qs = stock_models.StockFreeze.objects.filter(stock_detail=self.stock_detail)
|
|
self.assertEqual(freeze_qs.count(), 1)
|
|
self.assertEqual(freeze_qs.first().status, stock_models.StockFreezeStatusEnum.FROZEN)
|
|
|
|
def test_cancel_allocation_record(self):
|
|
record = allocation_services.create_allocation_record(
|
|
item=self.item,
|
|
stock_ids=[self.stock_detail.id],
|
|
quantity='2.0',
|
|
unit='米',
|
|
scanned_by=self.employee,
|
|
)
|
|
updated = allocation_services.cancel_allocation_record_with_unfreeze(
|
|
record=record,
|
|
cancelled_by=self.user,
|
|
reason='测试撤销',
|
|
)
|
|
self.assertEqual(updated.status, business_models.AllocationRecordStatusEnum.CANCELLED)
|
|
freeze = stock_models.StockFreeze.objects.get(stock_detail=self.stock_detail)
|
|
self.assertEqual(freeze.status, stock_models.StockFreezeStatusEnum.CANCELLED)
|