forked from erp-dev/erp
fix: added new field into purchase and stock cancelled or red flush
This commit is contained in:
@@ -121,7 +121,8 @@ class StockChangeRecordResponseSerializer(serializers.ModelSerializer):
|
||||
model = stock_models.StockChangeRecord
|
||||
fields = [
|
||||
'id', 'type', 'warehouse', 'source_type', 'source_id',
|
||||
'is_finished', 'finished_at', 'created_at', 'updated_at'
|
||||
'is_finished', 'finished_at', 'cancelled', 'is_offset', 'is_reversed',
|
||||
'created_at', 'updated_at'
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@ class StockChangeViewMixin:
|
||||
'source_id': record.source_id,
|
||||
'is_finished': record.is_finished,
|
||||
'finished_at': record.finished_at,
|
||||
'cancelled': record.cancelled,
|
||||
'is_offset': record.is_offset,
|
||||
'is_reversed': record.is_reversed,
|
||||
'created_at': record.created_at,
|
||||
'created_by': record.created_by.username if record.created_by else None,
|
||||
'remarks': record.remarks,
|
||||
|
||||
@@ -4,6 +4,7 @@ import logging
|
||||
import unittest
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.utils import timezone
|
||||
from django.test import TestCase
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
@@ -139,6 +140,7 @@ class CreateStockChangeAPITestCase(TestCase):
|
||||
|
||||
logging.disable(logging.NOTSET)
|
||||
self.addCleanup(logging.disable, logging.CRITICAL)
|
||||
|
||||
with self.assertLogs('api_v1.views.stock_change_views.mixins', level='ERROR') as cm:
|
||||
response = self.client.post('/api/v1/stock-change/', payload, format='json')
|
||||
|
||||
@@ -146,6 +148,70 @@ class CreateStockChangeAPITestCase(TestCase):
|
||||
self.assertEqual(response.data['error'], '无权限访问')
|
||||
self.assertTrue(any('无员工信息' in msg for msg in cm.output))
|
||||
|
||||
def test_get_stock_change_includes_offset_status_fields(self):
|
||||
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,
|
||||
)
|
||||
detail = stock_models.StockChangeDetail.objects.create(
|
||||
merchant=self.merchant,
|
||||
stock_change_record=record,
|
||||
product=self.product,
|
||||
quantity='10',
|
||||
unit=self.product.unit,
|
||||
)
|
||||
snapshot = stock_models.StockSnapshot.objects.create(
|
||||
merchant=self.merchant,
|
||||
product=self.product,
|
||||
warehouse=self.warehouse,
|
||||
delta='10',
|
||||
quantity_before='0',
|
||||
quantity_after='10',
|
||||
stock_change_record=record,
|
||||
unit=self.product.unit,
|
||||
num_of_rolls=1,
|
||||
cancelled=True,
|
||||
cancelled_at=timezone.now(),
|
||||
offset_id=1,
|
||||
)
|
||||
|
||||
offset_record = stock_models.StockChangeRecord.objects.create(
|
||||
merchant=self.merchant,
|
||||
type=stock_models.StockChangeTypeEnum.ADD,
|
||||
warehouse=self.warehouse,
|
||||
source_type=stock_models.StockChangeSourceEnum.OFFSET,
|
||||
created_by=self.user,
|
||||
)
|
||||
stock_models.StockSnapshot.objects.create(
|
||||
merchant=self.merchant,
|
||||
product=self.product,
|
||||
warehouse=self.warehouse,
|
||||
delta='-10',
|
||||
quantity_before='10',
|
||||
quantity_after='0',
|
||||
stock_change_record=offset_record,
|
||||
unit=self.product.unit,
|
||||
num_of_rolls=1,
|
||||
offset_to=snapshot.id,
|
||||
offset_at=timezone.now(),
|
||||
)
|
||||
|
||||
response = self.client.get(f'/api/v1/stock-change/{record.id}/')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
record_data = response.data['stock_change_record']
|
||||
self.assertTrue(record_data['cancelled'])
|
||||
self.assertTrue(record_data['is_reversed'])
|
||||
self.assertFalse(record_data['is_offset'])
|
||||
|
||||
offset_response = self.client.get(f'/api/v1/stock-change/{offset_record.id}/')
|
||||
self.assertEqual(offset_response.status_code, status.HTTP_200_OK)
|
||||
offset_data = offset_response.data['stock_change_record']
|
||||
self.assertTrue(offset_data['is_offset'])
|
||||
self.assertFalse(offset_data['is_reversed'])
|
||||
|
||||
|
||||
class CreateStockChangeRelaxedAPITestCase(TestCase):
|
||||
"""测试宽松模式库存变动创建 API"""
|
||||
|
||||
@@ -100,3 +100,15 @@
|
||||
|
||||
通过以上步骤,审批流程与红冲机制可以衔接:审批负责“正向入库”与任务分发,红冲负责在业务需要时生成配对的反向库存记录,保持库存账实一致,同时具备可回溯、可审计的业务闭环。
|
||||
|
||||
---
|
||||
|
||||
## 8. 库存记录红冲标识字段
|
||||
|
||||
库存变动记录的 API 响应新增以下字段,用于前端识别红冲关系:
|
||||
|
||||
- `cancelled`:是否已被红冲(等价于 `is_reversed`)
|
||||
- `is_reversed`:当前记录是否已被红冲
|
||||
- `is_offset`:当前记录是否为红冲记录(用于冲抵其他记录)
|
||||
|
||||
说明:红冲关系来源于库存快照的 `offset_to/offset_id/cancelled` 字段,记录本身不落库状态字段。
|
||||
|
||||
|
||||
@@ -133,6 +133,21 @@ class StockChangeRecord(ModelBase):
|
||||
self.details.count()
|
||||
return self.details.count()
|
||||
|
||||
@property
|
||||
def is_offset(self) -> bool:
|
||||
"""是否为红冲记录(用于冲抵其他记录)"""
|
||||
return self.stock_snapshots.filter(offset_to__isnull=False).exists()
|
||||
|
||||
@property
|
||||
def is_reversed(self) -> bool:
|
||||
"""是否已被红冲"""
|
||||
return self.stock_snapshots.filter(cancelled=True).exists()
|
||||
|
||||
@property
|
||||
def cancelled(self) -> bool:
|
||||
"""兼容字段:是否已被红冲"""
|
||||
return self.is_reversed
|
||||
|
||||
@property
|
||||
def delta_num_of_rolls(self) -> int:
|
||||
"""计算库存变动的匹数增减"""
|
||||
|
||||
Reference in New Issue
Block a user