forked from erp-dev/erp
feat: balance api
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
from typing import List, Dict, Any
|
||||
from decimal import Decimal
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test import TestCase, TransactionTestCase, override_settings
|
||||
from django.db import connections
|
||||
from django.utils import timezone
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
@@ -171,6 +174,11 @@ class PurchaseOrderServiceTestCase(TestCase):
|
||||
items=[{'product_id': self.product.id, 'quantities': ['10', '5']}],
|
||||
created_by_id=self.user.id,
|
||||
)
|
||||
balance = business_models.SupplierBalance.objects.get(
|
||||
merchant=self.merchant,
|
||||
supplier=self.supplier,
|
||||
)
|
||||
self.assertEqual(balance.balance, purchase_order.get_total_amount())
|
||||
|
||||
def test_create_purchase_order_without_items_raises(self):
|
||||
with self.assertRaises(ValueError):
|
||||
@@ -324,6 +332,11 @@ class SalesOrderServiceTestCase(TestCase):
|
||||
items=[{'product_id': self.product.id, 'quantities': ['6', '4']}],
|
||||
created_by_id=self.user.id,
|
||||
)
|
||||
balance = business_models.CustomerBalance.objects.get(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer,
|
||||
)
|
||||
self.assertEqual(balance.balance, sales_order.get_total_amount())
|
||||
|
||||
def test_sales_order_cancel_blocked_after_stock_created(self):
|
||||
sales_order = services.create_sales_order(
|
||||
@@ -392,7 +405,6 @@ class SalesOrderServiceTestCase(TestCase):
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
|
||||
class PaymentReceiptServiceTestCase(TestCase):
|
||||
def setUp(self):
|
||||
(
|
||||
@@ -426,6 +438,17 @@ class PaymentReceiptServiceTestCase(TestCase):
|
||||
reviewed_by=self.operator,
|
||||
)
|
||||
self.assertEqual(reviewed.status, business_models.PaymentOrderStatusEnum.APPROVED)
|
||||
balance = business_models.SupplierBalance.objects.get(
|
||||
merchant=self.merchant,
|
||||
supplier=self.supplier,
|
||||
)
|
||||
self.assertEqual(balance.balance, Decimal('-120.50'))
|
||||
with self.assertRaises(ValueError):
|
||||
services.review_payment_order(
|
||||
payment_order=order,
|
||||
target_status=business_models.PaymentOrderStatusEnum.CANCELLED,
|
||||
reviewed_by=self.operator,
|
||||
)
|
||||
|
||||
def test_create_receipt_order_and_cancel(self):
|
||||
order = services.create_receipt_order(
|
||||
@@ -472,6 +495,11 @@ class PaymentReceiptServiceTestCase(TestCase):
|
||||
reviewed_by=self.operator,
|
||||
)
|
||||
self.assertEqual(reviewed_again.status, business_models.ReceiptOrderStatusEnum.APPROVED)
|
||||
balance = business_models.CustomerBalance.objects.get(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer,
|
||||
)
|
||||
self.assertEqual(balance.balance, Decimal('-10'))
|
||||
|
||||
|
||||
class PurchaseOrderStockServiceTestCase(TestCase):
|
||||
@@ -593,6 +621,58 @@ class SalesOrderStockServiceTestCase(TestCase):
|
||||
self.assertEqual(payload['stock_change_record_id'], 987)
|
||||
|
||||
|
||||
class SalesOrderConcurrencyTestCase(TransactionTestCase):
|
||||
reset_sequences = True
|
||||
|
||||
def setUp(self):
|
||||
(
|
||||
self.merchant,
|
||||
self.customer,
|
||||
self.warehouse_strict,
|
||||
self.warehouse_relaxed,
|
||||
self.warehouse_strict_out,
|
||||
self.product,
|
||||
self.operator,
|
||||
) = create_sales_fixtures()
|
||||
basic_models.MerchantSetting.objects.filter(
|
||||
merchant=self.merchant,
|
||||
key=basic_models.MerchantSettingKeyEnum.AUTO_CREATE_STOCK_CHANGE_TASKS,
|
||||
).update(val_bool=False)
|
||||
User = get_user_model()
|
||||
self.user = User.objects.create_user(username='concurrent', password='pass123')
|
||||
self.sales_order = services.create_sales_order(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer,
|
||||
order_date=timezone.now().date(),
|
||||
warehouse=self.warehouse_strict,
|
||||
operator=self.operator,
|
||||
items=[{'product_id': self.product.id, 'numbers': [5], 'price': '12', 'unit': '米'}],
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
def test_concurrent_sales_order_approval_updates_balance_once(self):
|
||||
def approve():
|
||||
services.review_sales_order(
|
||||
sales_order_id=self.sales_order.id,
|
||||
target_status=business_models.SalesOrderStatusEnum.APPROVED,
|
||||
reviewed_by=self.user,
|
||||
)
|
||||
|
||||
with ThreadPoolExecutor(max_workers=2) as executor:
|
||||
futures = [executor.submit(approve) for _ in range(2)]
|
||||
for future in futures:
|
||||
future.result()
|
||||
|
||||
balance = business_models.CustomerBalance.objects.get(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer,
|
||||
)
|
||||
self.assertEqual(balance.balance, self.sales_order.get_total_amount())
|
||||
|
||||
def tearDown(self):
|
||||
connections.close_all()
|
||||
|
||||
|
||||
@override_settings(
|
||||
CELERY_TASK_ALWAYS_EAGER=True,
|
||||
CELERY_TASK_EAGER_PROPAGATES=True,
|
||||
|
||||
Reference in New Issue
Block a user