forked from erp-dev/erp
fix: order_quantity
This commit is contained in:
@@ -507,6 +507,18 @@ class SalesOrderAPITestCase(TestCase):
|
|||||||
expected_human_id = f"XS{order.created_at.strftime('%Y%m%d')}{order.id:06d}"
|
expected_human_id = f"XS{order.created_at.strftime('%Y%m%d')}{order.id:06d}"
|
||||||
self.assertEqual(response.data['human_id'], expected_human_id)
|
self.assertEqual(response.data['human_id'], expected_human_id)
|
||||||
|
|
||||||
|
def test_get_sales_order_detail_includes_order_quantity_on_items(self):
|
||||||
|
payload = copy.deepcopy(self.strict_in_payload)
|
||||||
|
payload['items'][0]['order_quantity'] = 88
|
||||||
|
order_id = self._create_sales_order(payload)
|
||||||
|
|
||||||
|
response = self.client.get(f'/api/v1/sales-orders/{order_id}/')
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertIn('items', response.data)
|
||||||
|
self.assertEqual(len(response.data['items']), 1)
|
||||||
|
self.assertIn('order_quantity', response.data['items'][0])
|
||||||
|
self.assertEqual(response.data['items'][0]['order_quantity'], 88)
|
||||||
|
|
||||||
def test_update_sales_order_rejects_non_pending(self):
|
def test_update_sales_order_rejects_non_pending(self):
|
||||||
order_id = self._create_sales_order(self.strict_in_payload)
|
order_id = self._create_sales_order(self.strict_in_payload)
|
||||||
self.client.post(
|
self.client.post(
|
||||||
|
|||||||
@@ -169,6 +169,33 @@ class PrintingOrderAPITestCase(TestCase):
|
|||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
# 分页响应格式
|
# 分页响应格式
|
||||||
self.assertEqual(response.data['count'], 2)
|
self.assertEqual(response.data['count'], 2)
|
||||||
|
|
||||||
|
def test_list_printing_orders_default_excludes_invalid(self):
|
||||||
|
"""默认不返回作废订单;显式传 is_invalid=true 时可查询作废订单"""
|
||||||
|
printing_models.PrintingOrder.objects.create(
|
||||||
|
merchant=self.merchant,
|
||||||
|
customer=self.customer,
|
||||||
|
fabric='正常订单',
|
||||||
|
width='150cm',
|
||||||
|
is_invalid=False,
|
||||||
|
)
|
||||||
|
printing_models.PrintingOrder.objects.create(
|
||||||
|
merchant=self.merchant,
|
||||||
|
customer=self.customer,
|
||||||
|
fabric='作废订单',
|
||||||
|
width='150cm',
|
||||||
|
is_invalid=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.client.get('/api/v1/printing-orders/')
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(response.data['count'], 1)
|
||||||
|
self.assertEqual(response.data['results'][0]['is_invalid'], False)
|
||||||
|
|
||||||
|
response = self.client.get('/api/v1/printing-orders/?is_invalid=true')
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(response.data['count'], 1)
|
||||||
|
self.assertEqual(response.data['results'][0]['is_invalid'], True)
|
||||||
|
|
||||||
def test_retrieve_printing_order(self):
|
def test_retrieve_printing_order(self):
|
||||||
"""测试获取订单详情"""
|
"""测试获取订单详情"""
|
||||||
|
|||||||
@@ -540,6 +540,15 @@ class PlateOrderAPITestCase(TestCase):
|
|||||||
else:
|
else:
|
||||||
self.assertEqual(len(response.data), 1)
|
self.assertEqual(len(response.data), 1)
|
||||||
self.assertEqual(response.data[0]['is_invalid'], False)
|
self.assertEqual(response.data[0]['is_invalid'], False)
|
||||||
|
|
||||||
|
response = self.client.get('/api/v1/plate-orders/?is_invalid=true')
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
if isinstance(response.data, dict):
|
||||||
|
self.assertEqual(response.data['count'], 1)
|
||||||
|
self.assertEqual(response.data['results'][0]['is_invalid'], True)
|
||||||
|
else:
|
||||||
|
self.assertEqual(len(response.data), 1)
|
||||||
|
self.assertEqual(response.data[0]['is_invalid'], True)
|
||||||
|
|
||||||
def test_filter_by_plate_at_from(self):
|
def test_filter_by_plate_at_from(self):
|
||||||
"""测试按开版时间起始筛选(带时分秒)"""
|
"""测试按开版时间起始筛选(带时分秒)"""
|
||||||
|
|||||||
@@ -224,6 +224,12 @@ class PrintingOrderViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
"""优化查询"""
|
"""优化查询"""
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
|
|
||||||
|
# 默认不返回作废订单(仅 list);如显式传入 is_invalid 参数,则交由 FilterSet 处理
|
||||||
|
# 注意:不能影响 activate/invalidate 等 action,否则会因 get_object() 被过滤而 404。
|
||||||
|
if self.action == 'list' and self.request and 'is_invalid' not in self.request.query_params:
|
||||||
|
queryset = queryset.filter(is_invalid=False)
|
||||||
|
|
||||||
if self.action in ['list', 'retrieve']:
|
if self.action in ['list', 'retrieve']:
|
||||||
queryset = queryset.select_related('customer')
|
queryset = queryset.select_related('customer')
|
||||||
# 预取 printing_jobs 及其 business_object,用于状态汇总统计
|
# 预取 printing_jobs 及其 business_object,用于状态汇总统计
|
||||||
@@ -798,6 +804,12 @@ class PlateOrderViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
"""优化查询"""
|
"""优化查询"""
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
|
|
||||||
|
# 默认不返回作废订单(仅 list);如显式传入 is_invalid 参数,则交由 FilterSet 处理
|
||||||
|
# 注意:不能影响 activate/invalidate 等 action,否则会因 get_object() 被过滤而 404。
|
||||||
|
if self.action == 'list' and self.request and 'is_invalid' not in self.request.query_params:
|
||||||
|
queryset = queryset.filter(is_invalid=False)
|
||||||
|
|
||||||
if self.action in ['list', 'retrieve']:
|
if self.action in ['list', 'retrieve']:
|
||||||
queryset = queryset.select_related('customer', 'salesperson', 'merchandiser', 'business_object')
|
queryset = queryset.select_related('customer', 'salesperson', 'merchandiser', 'business_object')
|
||||||
# 为搜索提供 design_code 的兜底(为空时使用主键字符串)
|
# 为搜索提供 design_code 的兜底(为空时使用主键字符串)
|
||||||
|
|||||||
@@ -349,6 +349,7 @@ def create_sales_order(
|
|||||||
num_of_rolls=item_data['num_of_rolls'],
|
num_of_rolls=item_data['num_of_rolls'],
|
||||||
consume_detail_ids=item_data.get('consume_detail_ids'),
|
consume_detail_ids=item_data.get('consume_detail_ids'),
|
||||||
batch_number=item_data.get('batch_number'),
|
batch_number=item_data.get('batch_number'),
|
||||||
|
order_quantity=item_data.get('order_quantity'),
|
||||||
remarks=item_data.get('remarks'),
|
remarks=item_data.get('remarks'),
|
||||||
printing_job=item_data.get('printing_job'),
|
printing_job=item_data.get('printing_job'),
|
||||||
)
|
)
|
||||||
@@ -418,6 +419,7 @@ def update_sales_order(
|
|||||||
num_of_rolls=item_data['num_of_rolls'],
|
num_of_rolls=item_data['num_of_rolls'],
|
||||||
consume_detail_ids=item_data.get('consume_detail_ids'),
|
consume_detail_ids=item_data.get('consume_detail_ids'),
|
||||||
batch_number=item_data.get('batch_number'),
|
batch_number=item_data.get('batch_number'),
|
||||||
|
order_quantity=item_data.get('order_quantity'),
|
||||||
remarks=item_data.get('remarks'),
|
remarks=item_data.get('remarks'),
|
||||||
printing_job=item_data.get('printing_job'),
|
printing_job=item_data.get('printing_job'),
|
||||||
)
|
)
|
||||||
@@ -1059,6 +1061,10 @@ def _normalize_order_items(
|
|||||||
batch_number = raw_item.get('batch_number')
|
batch_number = raw_item.get('batch_number')
|
||||||
remarks = raw_item.get('remarks')
|
remarks = raw_item.get('remarks')
|
||||||
spec = raw_item.get('spec')
|
spec = raw_item.get('spec')
|
||||||
|
order_quantity = _to_non_negative_int_or_none(
|
||||||
|
raw_item.get('order_quantity'),
|
||||||
|
f'items[{index}].order_quantity',
|
||||||
|
)
|
||||||
unit = raw_item.get('unit') or product.get_unit_display() or '米'
|
unit = raw_item.get('unit') or product.get_unit_display() or '米'
|
||||||
printing_job = None
|
printing_job = None
|
||||||
raw_printing_job_id = raw_item.get('printing_job') or raw_item.get('printing_job_id')
|
raw_printing_job_id = raw_item.get('printing_job') or raw_item.get('printing_job_id')
|
||||||
@@ -1154,6 +1160,7 @@ def _normalize_order_items(
|
|||||||
'batch_number': batch_number,
|
'batch_number': batch_number,
|
||||||
'remarks': remarks,
|
'remarks': remarks,
|
||||||
'spec': spec,
|
'spec': spec,
|
||||||
|
'order_quantity': order_quantity,
|
||||||
'consume_detail_ids': consume_detail_ids_str,
|
'consume_detail_ids': consume_detail_ids_str,
|
||||||
'printing_job': printing_job,
|
'printing_job': printing_job,
|
||||||
})
|
})
|
||||||
@@ -1755,6 +1762,17 @@ def _to_positive_int(value, field_name: str) -> int:
|
|||||||
return int(decimal_value)
|
return int(decimal_value)
|
||||||
|
|
||||||
|
|
||||||
|
def _to_non_negative_int_or_none(value, field_name: str) -> int | None:
|
||||||
|
if value in (None, ''):
|
||||||
|
return None
|
||||||
|
decimal_value = _to_decimal(value, field_name)
|
||||||
|
if decimal_value < 0:
|
||||||
|
raise ValueError(f'{field_name} 不能小于 0')
|
||||||
|
if decimal_value != decimal_value.to_integral_value():
|
||||||
|
raise ValueError(f'{field_name} 必须为整数')
|
||||||
|
return int(decimal_value)
|
||||||
|
|
||||||
|
|
||||||
# ==================== Statement Builders ====================
|
# ==================== Statement Builders ====================
|
||||||
|
|
||||||
_STATEMENT_TWO_PLACES = Decimal('0.01')
|
_STATEMENT_TWO_PLACES = Decimal('0.01')
|
||||||
|
|||||||
Reference in New Issue
Block a user