forked from erp-dev/erp
fix: frozen excluded from stock api
This commit is contained in:
@@ -314,6 +314,8 @@ class ListStockChangeDetailsView(StockChangeViewMixin, views.APIView):
|
|||||||
stock_change_record__type=change_type,
|
stock_change_record__type=change_type,
|
||||||
product_id=product_id,
|
product_id=product_id,
|
||||||
consumed_by_detail__isnull=True # 仅查询未被消耗的明细
|
consumed_by_detail__isnull=True # 仅查询未被消耗的明细
|
||||||
|
).exclude(
|
||||||
|
stock_freezes__status=stock_models.StockFreezeStatusEnum.FROZEN
|
||||||
).select_related(
|
).select_related(
|
||||||
'stock_change_record',
|
'stock_change_record',
|
||||||
'product'
|
'product'
|
||||||
|
|||||||
@@ -511,6 +511,29 @@ class ListStockChangeDetailsAPITestCase(TestCase):
|
|||||||
dates = [result['record_created_at'] for result in response.data['results']]
|
dates = [result['record_created_at'] for result in response.data['results']]
|
||||||
self.assertEqual(dates, sorted(dates, reverse=True))
|
self.assertEqual(dates, sorted(dates, reverse=True))
|
||||||
|
|
||||||
|
def test_list_stock_change_details_excludes_frozen(self):
|
||||||
|
"""库存明细列表应过滤已冻结明细"""
|
||||||
|
frozen_detail = self.details1[0]
|
||||||
|
stock_models.StockFreeze.objects.create(
|
||||||
|
merchant=self.merchant,
|
||||||
|
product=frozen_detail.product,
|
||||||
|
warehouse=self.warehouse,
|
||||||
|
stock_detail=frozen_detail,
|
||||||
|
quantity=frozen_detail.quantity,
|
||||||
|
unit=frozen_detail.unit,
|
||||||
|
status=stock_models.StockFreezeStatusEnum.FROZEN,
|
||||||
|
frozen_by=self.user,
|
||||||
|
frozen_with=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.client.get(
|
||||||
|
f'/api/v1/stock-change-details/?warehouse_id={self.warehouse.id}&product_id={self.product.id}'
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
returned_ids = [item['id'] for item in response.data['results']]
|
||||||
|
self.assertNotIn(frozen_detail.id, returned_ids)
|
||||||
|
self.assertEqual(response.data['count'], 1)
|
||||||
|
|
||||||
def test_list_stock_change_details_missing_warehouse_id(self):
|
def test_list_stock_change_details_missing_warehouse_id(self):
|
||||||
"""测试缺少warehouse_id参数"""
|
"""测试缺少warehouse_id参数"""
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from typing import Any, Dict, Iterable, List, Tuple, Optional
|
|||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from basic_info import models as basic_info_models
|
from basic_info import models as basic_info_models
|
||||||
from stock import models as stock_models
|
from stock import models as stock_models
|
||||||
@@ -1273,6 +1274,28 @@ def _approve_sales_order(
|
|||||||
source_id=locked_order.id,
|
source_id=locked_order.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
consume_detail_ids: List[int] = []
|
||||||
|
for item in locked_order.items.all():
|
||||||
|
raw_ids = (item.consume_detail_ids or '').strip()
|
||||||
|
if not raw_ids:
|
||||||
|
continue
|
||||||
|
consume_detail_ids.extend(
|
||||||
|
int(value)
|
||||||
|
for value in raw_ids.split(',')
|
||||||
|
if value.strip()
|
||||||
|
)
|
||||||
|
if consume_detail_ids:
|
||||||
|
stock_models.StockFreeze.objects.filter(
|
||||||
|
merchant=locked_order.merchant,
|
||||||
|
stock_detail_id__in=consume_detail_ids,
|
||||||
|
status=stock_models.StockFreezeStatusEnum.FROZEN,
|
||||||
|
).update(
|
||||||
|
status=stock_models.StockFreezeStatusEnum.COMPLETED,
|
||||||
|
completed_by=reviewed_by,
|
||||||
|
completed_at=timezone.now(),
|
||||||
|
completed_with=locked_order.id,
|
||||||
|
)
|
||||||
|
|
||||||
created_by_id = getattr(reviewed_by, 'id', None)
|
created_by_id = getattr(reviewed_by, 'id', None)
|
||||||
if _auto_stock_task_enabled(locked_order.merchant):
|
if _auto_stock_task_enabled(locked_order.merchant):
|
||||||
logger.info('审批通过销售单 %s,触发出库任务', locked_order.id)
|
logger.info('审批通过销售单 %s,触发出库任务', locked_order.id)
|
||||||
|
|||||||
@@ -194,6 +194,88 @@ class SalesOrderServiceTestCase(TestCase):
|
|||||||
self.assertEqual(item.consume_detail_ids, ','.join(consume_ids))
|
self.assertEqual(item.consume_detail_ids, ','.join(consume_ids))
|
||||||
self.assertEqual(item.quantity_of_rolls, '6,4')
|
self.assertEqual(item.quantity_of_rolls, '6,4')
|
||||||
|
|
||||||
|
def test_review_sales_order_unfreezes_consumed_stock(self):
|
||||||
|
stock_record = stock_models.StockChangeRecord.objects.create(
|
||||||
|
merchant=self.merchant,
|
||||||
|
type=stock_models.StockChangeTypeEnum.ADD,
|
||||||
|
warehouse=self.warehouse_strict_out,
|
||||||
|
source_type=stock_models.StockChangeSourceEnum.PURCHASE,
|
||||||
|
created_by=self.user,
|
||||||
|
)
|
||||||
|
detail_1 = stock_models.StockChangeDetail.objects.create(
|
||||||
|
merchant=self.merchant,
|
||||||
|
product=self.product,
|
||||||
|
unit=self.product.unit,
|
||||||
|
stock_change_record=stock_record,
|
||||||
|
quantity='6',
|
||||||
|
)
|
||||||
|
detail_2 = stock_models.StockChangeDetail.objects.create(
|
||||||
|
merchant=self.merchant,
|
||||||
|
product=self.product,
|
||||||
|
unit=self.product.unit,
|
||||||
|
stock_change_record=stock_record,
|
||||||
|
quantity='4',
|
||||||
|
)
|
||||||
|
stock_models.StockFreeze.objects.create(
|
||||||
|
merchant=self.merchant,
|
||||||
|
product=self.product,
|
||||||
|
warehouse=self.warehouse_strict_out,
|
||||||
|
stock_detail=detail_1,
|
||||||
|
quantity=detail_1.quantity,
|
||||||
|
unit=detail_1.unit,
|
||||||
|
status=stock_models.StockFreezeStatusEnum.FROZEN,
|
||||||
|
frozen_by=self.user,
|
||||||
|
frozen_with=1,
|
||||||
|
)
|
||||||
|
stock_models.StockFreeze.objects.create(
|
||||||
|
merchant=self.merchant,
|
||||||
|
product=self.product,
|
||||||
|
warehouse=self.warehouse_strict_out,
|
||||||
|
stock_detail=detail_2,
|
||||||
|
quantity=detail_2.quantity,
|
||||||
|
unit=detail_2.unit,
|
||||||
|
status=stock_models.StockFreezeStatusEnum.FROZEN,
|
||||||
|
frozen_by=self.user,
|
||||||
|
frozen_with=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
sales_order = services.create_sales_order(
|
||||||
|
merchant=self.merchant,
|
||||||
|
customer=self.customer,
|
||||||
|
order_date=timezone.now().date(),
|
||||||
|
warehouse=self.warehouse_strict_out,
|
||||||
|
operator=self.operator,
|
||||||
|
items=[
|
||||||
|
{
|
||||||
|
'product_id': self.product.id,
|
||||||
|
'consume_detail_ids': [detail_1.id, detail_2.id],
|
||||||
|
'quantity': 10,
|
||||||
|
'price': '32.0',
|
||||||
|
'unit': '米',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
created_by=self.user,
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch('business.services.create_sales_order_stock_entries.delay') as mock_delay:
|
||||||
|
reviewed = services.review_sales_order(
|
||||||
|
sales_order=sales_order,
|
||||||
|
target_status=business_models.SalesOrderStatusEnum.APPROVED,
|
||||||
|
reviewed_by=self.user,
|
||||||
|
)
|
||||||
|
self.assertEqual(reviewed.status, business_models.SalesOrderStatusEnum.APPROVED)
|
||||||
|
mock_delay.assert_called_once()
|
||||||
|
|
||||||
|
statuses = list(
|
||||||
|
stock_models.StockFreeze.objects.filter(
|
||||||
|
stock_detail_id__in=[detail_1.id, detail_2.id]
|
||||||
|
).values_list('status', flat=True)
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
set(statuses),
|
||||||
|
{stock_models.StockFreezeStatusEnum.COMPLETED},
|
||||||
|
)
|
||||||
|
|
||||||
def test_sales_order_outgoing_missing_consume_ids_raises(self):
|
def test_sales_order_outgoing_missing_consume_ids_raises(self):
|
||||||
payload = [
|
payload = [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user