forked from erp-dev/erp
344 lines
14 KiB
Python
344 lines
14 KiB
Python
from django.test import TestCase
|
|
from django.utils import timezone
|
|
|
|
from basic_info import models as basic_models
|
|
from business import models as business_models, services
|
|
from stock import models as stock_models
|
|
|
|
from .fixtures import create_basic_fixtures, create_sales_fixtures
|
|
|
|
|
|
class BusinessServiceEdgeCaseTestCase(TestCase):
|
|
def _disable_auto_stock_tasks(self, merchant):
|
|
basic_models.MerchantSetting.objects.filter(
|
|
merchant=merchant,
|
|
key=basic_models.MerchantSettingKeyEnum.AUTO_CREATE_STOCK_CHANGE_TASKS,
|
|
).update(val_bool=False)
|
|
|
|
def test_sales_order_kind_and_date_validation_errors(self):
|
|
merchant, customer, _, warehouse, _, product, operator = create_sales_fixtures()
|
|
with self.assertRaises(ValueError):
|
|
services.create_sales_order(
|
|
merchant=merchant,
|
|
customer=customer,
|
|
order_date=timezone.now().date(),
|
|
warehouse=warehouse,
|
|
operator=operator,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
kind='invalid',
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.create_sales_order(
|
|
merchant=merchant,
|
|
customer=customer,
|
|
order_date=timezone.now().date(),
|
|
warehouse=warehouse,
|
|
operator=operator,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
kind=999,
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.create_sales_order(
|
|
merchant=merchant,
|
|
customer=customer,
|
|
order_date='not-a-date',
|
|
warehouse=warehouse,
|
|
operator=operator,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.create_sales_order(
|
|
merchant=merchant,
|
|
customer=customer,
|
|
order_date=object(),
|
|
warehouse=warehouse,
|
|
operator=operator,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
|
|
def test_return_order_source_validation_errors(self):
|
|
merchant, supplier, _, warehouse, product, operator = create_basic_fixtures()
|
|
other_supplier = basic_models.Supplier.objects.create(merchant=merchant, name='其他供应商')
|
|
purchase_order = services.create_purchase_order(
|
|
merchant=merchant,
|
|
supplier=supplier,
|
|
order_date=timezone.now().date(),
|
|
warehouse=warehouse,
|
|
operator=operator,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.create_purchase_return_order(
|
|
merchant=merchant,
|
|
supplier=supplier,
|
|
return_date=timezone.now().date(),
|
|
warehouse=warehouse,
|
|
operator=operator,
|
|
purchase_order_id=999999,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.create_purchase_return_order(
|
|
merchant=merchant,
|
|
supplier=other_supplier,
|
|
return_date=timezone.now().date(),
|
|
warehouse=warehouse,
|
|
operator=operator,
|
|
purchase_order=purchase_order,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
|
|
sales_merchant, customer, _, sales_warehouse, _, sales_product, sales_operator = create_sales_fixtures()
|
|
other_customer = basic_models.Customer.objects.create(merchant=sales_merchant, name='其他客户')
|
|
sales_order = services.create_sales_order(
|
|
merchant=sales_merchant,
|
|
customer=customer,
|
|
order_date=timezone.now().date(),
|
|
warehouse=sales_warehouse,
|
|
operator=sales_operator,
|
|
items=[{'product_id': sales_product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.create_sales_return_order(
|
|
merchant=sales_merchant,
|
|
customer=customer,
|
|
return_date=timezone.now().date(),
|
|
warehouse=sales_warehouse,
|
|
operator=sales_operator,
|
|
sales_order_id=999999,
|
|
items=[{'product_id': sales_product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.create_sales_return_order(
|
|
merchant=sales_merchant,
|
|
customer=other_customer,
|
|
return_date=timezone.now().date(),
|
|
warehouse=sales_warehouse,
|
|
operator=sales_operator,
|
|
sales_order=sales_order,
|
|
items=[{'product_id': sales_product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
|
|
def test_empty_items_and_update_source_validation_errors(self):
|
|
merchant, supplier, _, warehouse, product, operator = create_basic_fixtures()
|
|
purchase_order = services.create_purchase_order(
|
|
merchant=merchant,
|
|
supplier=supplier,
|
|
order_date=timezone.now().date(),
|
|
warehouse=warehouse,
|
|
operator=operator,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.update_purchase_order(purchase_order=purchase_order, items=[])
|
|
updated = services.update_purchase_order(
|
|
purchase_order=purchase_order,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
from_pre_purchase_order_id=123,
|
|
)
|
|
self.assertEqual(updated.from_pre_purchase_order_id, 123)
|
|
sales_merchant, customer, _, sales_warehouse, _, sales_product, sales_operator = create_sales_fixtures()
|
|
with self.assertRaises(ValueError):
|
|
services.create_sales_order(
|
|
merchant=sales_merchant,
|
|
customer=customer,
|
|
order_date=timezone.now().date(),
|
|
warehouse=sales_warehouse,
|
|
operator=sales_operator,
|
|
items=[],
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.create_purchase_return_order(
|
|
merchant=merchant,
|
|
supplier=supplier,
|
|
return_date=timezone.now().date(),
|
|
warehouse=warehouse,
|
|
operator=operator,
|
|
items=[],
|
|
)
|
|
|
|
return_order = services.create_purchase_return_order(
|
|
merchant=merchant,
|
|
supplier=supplier,
|
|
return_date=timezone.now().date(),
|
|
warehouse=warehouse,
|
|
operator=operator,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
return_order.purchase_order = None
|
|
return_order.save(update_fields=['purchase_order'])
|
|
with self.assertRaises(ValueError):
|
|
services.update_purchase_return_order(
|
|
purchase_return_order=return_order,
|
|
purchase_order_id=999999,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
|
|
with self.assertRaises(ValueError):
|
|
services.create_sales_return_order(
|
|
merchant=sales_merchant,
|
|
customer=customer,
|
|
return_date=timezone.now().date(),
|
|
warehouse=sales_warehouse,
|
|
operator=sales_operator,
|
|
items=[],
|
|
)
|
|
|
|
def test_review_invalid_targets_and_cancelled_reapprove_errors(self):
|
|
merchant, supplier, _, warehouse, product, operator = create_basic_fixtures()
|
|
purchase_order = services.create_purchase_order(
|
|
merchant=merchant,
|
|
supplier=supplier,
|
|
order_date=timezone.now().date(),
|
|
warehouse=warehouse,
|
|
operator=operator,
|
|
items=[{'product_id': product.id, 'quantity': 1, 'num_of_rolls': 1, 'price': '1'}],
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.review_purchase_order(purchase_order=purchase_order, target_status=999)
|
|
services.review_purchase_order(
|
|
purchase_order=purchase_order,
|
|
target_status=business_models.PurchaseOrderStatusEnum.CANCELLED,
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.review_purchase_order(
|
|
purchase_order=purchase_order,
|
|
target_status=business_models.PurchaseOrderStatusEnum.APPROVED,
|
|
)
|
|
|
|
payment = services.create_payment_order(
|
|
merchant=merchant,
|
|
supplier=supplier,
|
|
payment_date=timezone.now().date(),
|
|
amount='1',
|
|
operator=operator,
|
|
)
|
|
services.review_payment_order(payment_order=payment, target_status=business_models.PaymentOrderStatusEnum.CANCELLED)
|
|
with self.assertRaises(ValueError):
|
|
services.review_payment_order(payment_order=payment, target_status=business_models.PaymentOrderStatusEnum.APPROVED)
|
|
|
|
def test_resolve_helpers_require_instance_or_id(self):
|
|
with self.assertRaises(ValueError):
|
|
services._resolve_purchase_order_instance(None, None)
|
|
with self.assertRaises(ValueError):
|
|
services._resolve_sales_order_instance(None, None)
|
|
with self.assertRaises(ValueError):
|
|
services._resolve_purchase_return_order_instance(None, None)
|
|
with self.assertRaises(ValueError):
|
|
services._resolve_sales_return_order_instance(None, None)
|
|
with self.assertRaises(ValueError):
|
|
services._resolve_payment_order_instance(None, None)
|
|
with self.assertRaises(ValueError):
|
|
services._resolve_receipt_order_instance(None, None)
|
|
|
|
def test_stock_entry_sync_not_found_payloads(self):
|
|
self.assertEqual(
|
|
services.create_purchase_order_stock_entries_sync(
|
|
purchase_order_id=999999,
|
|
warehouse_id=1,
|
|
items=[],
|
|
)['error'],
|
|
'purchase_order_not_found',
|
|
)
|
|
self.assertEqual(
|
|
services.create_sales_order_stock_entries_sync(
|
|
sales_order_id=999999,
|
|
warehouse_id=1,
|
|
items=[],
|
|
)['error'],
|
|
'sales_order_not_found',
|
|
)
|
|
self.assertEqual(
|
|
services.create_purchase_return_order_stock_entries_sync(
|
|
purchase_return_order_id=999999,
|
|
warehouse_id=1,
|
|
items=[],
|
|
)['error'],
|
|
'purchase_return_order_not_found',
|
|
)
|
|
self.assertEqual(
|
|
services.create_sales_return_order_stock_entries_sync(
|
|
sales_return_order_id=999999,
|
|
warehouse_id=1,
|
|
items=[],
|
|
)['error'],
|
|
'sales_return_order_not_found',
|
|
)
|
|
|
|
def test_build_stock_flow_items_error_branches(self):
|
|
merchant, supplier, warehouse_strict, _, product, operator = create_basic_fixtures()
|
|
order = services.create_purchase_order(
|
|
merchant=merchant,
|
|
supplier=supplier,
|
|
order_date=timezone.now().date(),
|
|
warehouse=warehouse_strict,
|
|
operator=operator,
|
|
items=[{'product_id': product.id, 'numbers': [1], 'price': '1'}],
|
|
)
|
|
order.items.all().delete()
|
|
with self.assertRaises(ValueError):
|
|
services._build_stock_flow_items_from_order(order)
|
|
|
|
order = services.create_purchase_order(
|
|
merchant=merchant,
|
|
supplier=supplier,
|
|
order_date=timezone.now().date(),
|
|
warehouse=warehouse_strict,
|
|
operator=operator,
|
|
items=[{'product_id': product.id, 'numbers': [1], 'price': '1'}],
|
|
)
|
|
item = order.items.first()
|
|
item.quantity_of_rolls = ''
|
|
item.save(update_fields=['quantity_of_rolls'])
|
|
with self.assertRaises(ValueError):
|
|
services._build_stock_flow_items_from_order(order)
|
|
|
|
def test_bind_purchase_order_stock_change_record_error_branches(self):
|
|
merchant, supplier, warehouse_strict, warehouse_relaxed, product, operator = create_basic_fixtures()
|
|
self._disable_auto_stock_tasks(merchant)
|
|
order = services.create_purchase_order(
|
|
merchant=merchant,
|
|
supplier=supplier,
|
|
order_date=timezone.now().date(),
|
|
warehouse=warehouse_strict,
|
|
operator=operator,
|
|
items=[{'product_id': product.id, 'numbers': [1], 'price': '1'}],
|
|
)
|
|
|
|
bound_record = stock_models.StockChangeRecord.objects.create(
|
|
merchant=merchant,
|
|
type=stock_models.StockChangeTypeEnum.ADD,
|
|
warehouse=warehouse_strict,
|
|
source_type=stock_models.StockChangeSourceEnum.PURCHASE,
|
|
source_id=123,
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.bind_purchase_order_stock_change_record(
|
|
purchase_order_id=order.id,
|
|
stock_change_record_id=bound_record.id,
|
|
)
|
|
|
|
wrong_warehouse_record = stock_models.StockChangeRecord.objects.create(
|
|
merchant=merchant,
|
|
type=stock_models.StockChangeTypeEnum.ADD,
|
|
warehouse=warehouse_relaxed,
|
|
source_type=stock_models.StockChangeSourceEnum.PURCHASE,
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.bind_purchase_order_stock_change_record(
|
|
purchase_order_id=order.id,
|
|
stock_change_record_id=wrong_warehouse_record.id,
|
|
)
|
|
|
|
sales_source_record = stock_models.StockChangeRecord.objects.create(
|
|
merchant=merchant,
|
|
type=stock_models.StockChangeTypeEnum.ADD,
|
|
warehouse=warehouse_strict,
|
|
source_type=stock_models.StockChangeSourceEnum.SALES_RETURN,
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
services.bind_purchase_order_stock_change_record(
|
|
purchase_order_id=order.id,
|
|
stock_change_record_id=sales_source_record.id,
|
|
)
|