feat: 调整

This commit is contained in:
Czw996 2022-04-02 23:06:18 +08:00
parent 2efdd5c038
commit 88007169df
62 changed files with 409 additions and 281 deletions

View file

@ -79,9 +79,9 @@
* 仓库 * 仓库
* 结算账户 * 结算账户
* 收支项目 * 收支项目
* 品管理 * 品管理
* 品分类 * 品分类
* 品信息 * 品信息
* 采购管理 * 采购管理
* 采购开单 * 采购开单
* 采购退货 * 采购退货
@ -111,7 +111,7 @@
### 界面截图 ### 界面截图
![首页](https://gitee.com/haioucloud/erp/raw/master/raw/%E9%A6%96%E9%A1%B5.png) ![首页](https://gitee.com/haioucloud/erp/raw/master/raw/%E9%A6%96%E9%A1%B5.png)
![报表](https://gitee.com/haioucloud/erp/raw/master/raw/%E6%8A%A5%E8%A1%A8.png) ![报表](https://gitee.com/haioucloud/erp/raw/master/raw/%E6%8A%A5%E8%A1%A8.png)
![品](https://gitee.com/haioucloud/erp/raw/master/raw/%E5%95%86%E5%93%81.png) ![品](https://gitee.com/haioucloud/erp/raw/master/raw/%E5%95%86%E5%93%81.png)
![采购](https://gitee.com/haioucloud/erp/raw/master/raw/%E9%87%87%E8%B4%AD.png) ![采购](https://gitee.com/haioucloud/erp/raw/master/raw/%E9%87%87%E8%B4%AD.png)
![库存](https://gitee.com/haioucloud/erp/raw/master/raw/%E5%BA%93%E5%AD%98.png) ![库存](https://gitee.com/haioucloud/erp/raw/master/raw/%E5%BA%93%E5%AD%98.png)
![财务](https://gitee.com/haioucloud/erp/raw/master/raw/%E8%B4%A2%E5%8A%A1.png) ![财务](https://gitee.com/haioucloud/erp/raw/master/raw/%E8%B4%A2%E5%8A%A1.png)

View file

@ -27,7 +27,7 @@ class InventoryFlow(Model):
VOID_STOCK_TRANSFER_IN = ('void_stock_transfer_in', '作废调拨转入') VOID_STOCK_TRANSFER_IN = ('void_stock_transfer_in', '作废调拨转入')
warehouse = ForeignKey('data.Warehouse', on_delete=PROTECT, related_name='inventory_flows', verbose_name='仓库') warehouse = ForeignKey('data.Warehouse', on_delete=PROTECT, related_name='inventory_flows', verbose_name='仓库')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, related_name='inventory_flows', verbose_name='') goods = ForeignKey('goods.Goods', on_delete=PROTECT, related_name='inventory_flows', verbose_name='')
type = CharField(max_length=32, choices=Type.choices, verbose_name='流水类型') type = CharField(max_length=32, choices=Type.choices, verbose_name='流水类型')
quantity_before = FloatField(verbose_name='变化之前数量') quantity_before = FloatField(verbose_name='变化之前数量')
quantity_change = FloatField(verbose_name='变化数量') quantity_change = FloatField(verbose_name='变化数量')

View file

@ -7,9 +7,9 @@ from apps.flow.models import *
class InventoryFlowSerializer(BaseSerializer): class InventoryFlowSerializer(BaseSerializer):
warehouse_number = CharField(source='warehouse.number', read_only=True, label='仓库编号') warehouse_number = CharField(source='warehouse.number', read_only=True, label='仓库编号')
warehouse_name = CharField(source='warehouse.name', read_only=True, label='仓库名称') warehouse_name = CharField(source='warehouse.name', read_only=True, label='仓库名称')
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
type_display = CharField(source='get_type_display', read_only=True, label='流水类型') type_display = CharField(source='get_type_display', read_only=True, label='流水类型')
purchase_order_number = CharField(source='purchase_order.number', read_only=True, label='采购单号') purchase_order_number = CharField(source='purchase_order.number', read_only=True, label='采购单号')

View file

@ -3,7 +3,7 @@ from extensions.models import *
class GoodsCategory(Model): class GoodsCategory(Model):
"""品分类""" """品分类"""
name = CharField(max_length=64, verbose_name='名称') name = CharField(max_length=64, verbose_name='名称')
remark = CharField(max_length=256, null=True, blank=True, verbose_name='备注') remark = CharField(max_length=256, null=True, blank=True, verbose_name='备注')
@ -14,7 +14,7 @@ class GoodsCategory(Model):
class GoodsUnit(Model): class GoodsUnit(Model):
"""品单位""" """品单位"""
name = CharField(max_length=64, verbose_name='名称') name = CharField(max_length=64, verbose_name='名称')
remark = CharField(max_length=256, null=True, blank=True, verbose_name='备注') remark = CharField(max_length=256, null=True, blank=True, verbose_name='备注')
@ -25,15 +25,15 @@ class GoodsUnit(Model):
class Goods(Model): class Goods(Model):
"""""" """"""
number = CharField(max_length=32, verbose_name='编号') number = CharField(max_length=32, verbose_name='编号')
name = CharField(max_length=64, verbose_name='名称') name = CharField(max_length=64, verbose_name='名称')
barcode = CharField(max_length=32, null=True, blank=True, verbose_name='条码') barcode = CharField(max_length=32, null=True, blank=True, verbose_name='条码')
category = ForeignKey('goods.GoodsCategory', on_delete=SET_NULL, null=True, category = ForeignKey('goods.GoodsCategory', on_delete=SET_NULL, null=True,
related_name='goods_set', verbose_name='品分类') related_name='goods_set', verbose_name='品分类')
unit = ForeignKey('goods.GoodsUnit', on_delete=SET_NULL, null=True, unit = ForeignKey('goods.GoodsUnit', on_delete=SET_NULL, null=True,
related_name='goods_set', verbose_name='品单位') related_name='goods_set', verbose_name='品单位')
spec = CharField(max_length=64, null=True, blank=True, verbose_name='规格') spec = CharField(max_length=64, null=True, blank=True, verbose_name='规格')
enable_batch_control = BooleanField(default=False, verbose_name='启用批次控制') enable_batch_control = BooleanField(default=False, verbose_name='启用批次控制')
shelf_life_days = IntegerField(null=True, verbose_name='保质期天数') shelf_life_days = IntegerField(null=True, verbose_name='保质期天数')
@ -76,10 +76,10 @@ class Goods(Model):
class GoodsImage(Model): class GoodsImage(Model):
"""品图片""" """品图片"""
goods = ForeignKey('goods.Goods', on_delete=SET_NULL, null=True, goods = ForeignKey('goods.Goods', on_delete=SET_NULL, null=True,
related_name='goods_images', verbose_name='') related_name='goods_images', verbose_name='')
file = ImageField(verbose_name='文件') file = ImageField(verbose_name='文件')
name = CharField(max_length=256, verbose_name='文件名称') name = CharField(max_length=256, verbose_name='文件名称')
team = ForeignKey('system.Team', on_delete=CASCADE, related_name='goods_images') team = ForeignKey('system.Team', on_delete=CASCADE, related_name='goods_images')
@ -91,7 +91,7 @@ class Batch(Model):
number = CharField(max_length=32, verbose_name='编号') number = CharField(max_length=32, verbose_name='编号')
inventory = ForeignKey('goods.Inventory', on_delete=CASCADE, related_name='batchs', verbose_name='库存') inventory = ForeignKey('goods.Inventory', on_delete=CASCADE, related_name='batchs', verbose_name='库存')
warehouse = ForeignKey('data.Warehouse', on_delete=CASCADE, related_name='batchs', verbose_name='仓库') warehouse = ForeignKey('data.Warehouse', on_delete=CASCADE, related_name='batchs', verbose_name='仓库')
goods = ForeignKey('goods.Goods', on_delete=CASCADE, related_name='batchs', verbose_name='') goods = ForeignKey('goods.Goods', on_delete=CASCADE, related_name='batchs', verbose_name='')
initial_quantity = FloatField(default=0, verbose_name='初始库存') initial_quantity = FloatField(default=0, verbose_name='初始库存')
total_quantity = FloatField(verbose_name='批次数量') total_quantity = FloatField(verbose_name='批次数量')
remain_quantity = FloatField(verbose_name='批次剩余数量') remain_quantity = FloatField(verbose_name='批次剩余数量')
@ -110,7 +110,7 @@ class Inventory(Model):
"""库存""" """库存"""
warehouse = ForeignKey('data.Warehouse', on_delete=CASCADE, related_name='inventories', verbose_name='仓库') warehouse = ForeignKey('data.Warehouse', on_delete=CASCADE, related_name='inventories', verbose_name='仓库')
goods = ForeignKey('goods.Goods', on_delete=CASCADE, related_name='inventories', verbose_name='') goods = ForeignKey('goods.Goods', on_delete=CASCADE, related_name='inventories', verbose_name='')
initial_quantity = FloatField(default=0, verbose_name='初始库存') initial_quantity = FloatField(default=0, verbose_name='初始库存')
total_quantity = FloatField(default=0, verbose_name='库存总数') total_quantity = FloatField(default=0, verbose_name='库存总数')
has_stock = BooleanField(default=False, verbose_name='库存状态') has_stock = BooleanField(default=False, verbose_name='库存状态')

View file

@ -93,7 +93,7 @@ class GoodsSerializer(BaseSerializer):
inventory_items = InventoryItemSerializer( inventory_items = InventoryItemSerializer(
source='inventories', required=False, many=True, label='库存Item') source='inventories', required=False, many=True, label='库存Item')
goods_image_items = GoodsImageItemSerializer( goods_image_items = GoodsImageItemSerializer(
source='goods_images', many=True, read_only=True, label='品图片Item') source='goods_images', many=True, read_only=True, label='品图片Item')
class Meta: class Meta:
model = Goods model = Goods
@ -110,20 +110,20 @@ class GoodsSerializer(BaseSerializer):
return value return value
def validate_category(self, instance): def validate_category(self, instance):
instance = self.validate_foreign_key(GoodsCategory, instance, message='品分类不存在') instance = self.validate_foreign_key(GoodsCategory, instance, message='品分类不存在')
return instance return instance
def validate_unit(self, instance): def validate_unit(self, instance):
instance = self.validate_foreign_key(GoodsUnit, instance, message='品单位不存在') instance = self.validate_foreign_key(GoodsUnit, instance, message='品单位不存在')
return instance return instance
def validate_enable_batch_control(self, value): def validate_enable_batch_control(self, value):
if value and (self.team.enable_auto_stock_in or self.team.enable_auto_stock_out): if value and (self.team.enable_auto_stock_in or self.team.enable_auto_stock_out):
raise ValidationError('只有同时关闭自动入库、自动出库, 才可以开启品的批次控制') raise ValidationError('只有同时关闭自动入库、自动出库, 才可以开启品的批次控制')
return value return value
def validate_goods_images(self, instances): def validate_goods_images(self, instances):
instances = self.validate_foreign_key_set(GoodsImage, instances, message='品图片不存在') instances = self.validate_foreign_key_set(GoodsImage, instances, message='品图片不存在')
return instances return instances
@transaction.atomic @transaction.atomic
@ -145,7 +145,7 @@ class GoodsSerializer(BaseSerializer):
total_initial_quantity = 0 total_initial_quantity = 0
# 品开启批次控制, 创建批次 # 品开启批次控制, 创建批次
batch_items = inventory_item.get('batchs') batch_items = inventory_item.get('batchs')
if goods.enable_batch_control and batch_items: if goods.enable_batch_control and batch_items:
for batch_item in batch_items: for batch_item in batch_items:
@ -171,7 +171,7 @@ class GoodsSerializer(BaseSerializer):
inventory.initial_quantity = total_initial_quantity inventory.initial_quantity = total_initial_quantity
inventory.total_quantity = total_initial_quantity inventory.total_quantity = total_initial_quantity
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['initial_quantity', 'total_quantity', 'has_stock']) inventory.save(update_fields=['initial_quantity', 'total_quantity', 'has_stock'])
break break
@ -265,7 +265,7 @@ class GoodsSerializer(BaseSerializer):
inventory.initial_quantity = total_initial_quantity inventory.initial_quantity = total_initial_quantity
inventory.total_quantity = NP.plus(inventory.total_quantity, inventory.initial_quantity) inventory.total_quantity = NP.plus(inventory.total_quantity, inventory.initial_quantity)
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['initial_quantity', 'total_quantity', 'has_stock']) inventory.save(update_fields=['initial_quantity', 'total_quantity', 'has_stock'])
else: else:
@ -273,7 +273,7 @@ class GoodsSerializer(BaseSerializer):
inventory.initial_quantity = inventory_initial_quantity inventory.initial_quantity = inventory_initial_quantity
inventory.total_quantity = NP.plus(inventory.total_quantity, inventory.initial_quantity) inventory.total_quantity = NP.plus(inventory.total_quantity, inventory.initial_quantity)
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['initial_quantity', 'total_quantity', 'has_stock']) inventory.save(update_fields=['initial_quantity', 'total_quantity', 'has_stock'])
@ -290,8 +290,8 @@ class GoodsSerializer(BaseSerializer):
class GoodsImportExportSerializer(BaseSerializer): class GoodsImportExportSerializer(BaseSerializer):
number = CharField(label='品编号(唯一必填)') number = CharField(label='品编号(唯一必填)')
name = CharField(label='品名称(必填)') name = CharField(label='品名称(必填)')
barcode = CharField(required=False, label='条码') barcode = CharField(required=False, label='条码')
category = CharField(source='category.name', required=False, label='分类') category = CharField(source='category.name', required=False, label='分类')
unit = CharField(source='unit.name', required=False, label='单位') unit = CharField(source='unit.name', required=False, label='单位')
@ -334,9 +334,9 @@ class GoodsImageSerializer(BaseSerializer):
class BatchSerializer(BaseSerializer): class BatchSerializer(BaseSerializer):
warehouse_number = CharField(source='warehouse.number', read_only=True, label='仓库编号') warehouse_number = CharField(source='warehouse.number', read_only=True, label='仓库编号')
warehouse_name = CharField(source='warehouse.name', read_only=True, label='仓库名称') warehouse_name = CharField(source='warehouse.name', read_only=True, label='仓库名称')
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
class Meta: class Meta:
@ -349,9 +349,9 @@ class BatchSerializer(BaseSerializer):
class InventorySerializer(BaseSerializer): class InventorySerializer(BaseSerializer):
warehouse_number = CharField(source='warehouse.number', read_only=True, label='仓库编号') warehouse_number = CharField(source='warehouse.number', read_only=True, label='仓库编号')
warehouse_name = CharField(source='warehouse.name', read_only=True, label='仓库名称') warehouse_name = CharField(source='warehouse.name', read_only=True, label='仓库名称')
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
class Meta: class Meta:

View file

@ -12,7 +12,7 @@ from apps.data.models import *
class GoodsCategoryViewSet(ModelViewSet, ExportMixin, ImportMixin): class GoodsCategoryViewSet(ModelViewSet, ExportMixin, ImportMixin):
"""品分类""" """品分类"""
serializer_class = GoodsCategorySerializer serializer_class = GoodsCategorySerializer
permission_classes = [IsAuthenticated, GoodsCategoryPermission] permission_classes = [IsAuthenticated, GoodsCategoryPermission]
@ -77,7 +77,7 @@ class GoodsCategoryViewSet(ModelViewSet, ExportMixin, ImportMixin):
class GoodsUnitViewSet(ModelViewSet, ExportMixin, ImportMixin): class GoodsUnitViewSet(ModelViewSet, ExportMixin, ImportMixin):
"""品单位""" """品单位"""
serializer_class = GoodsUnitSerializer serializer_class = GoodsUnitSerializer
permission_classes = [IsAuthenticated, GoodsUnitPermission] permission_classes = [IsAuthenticated, GoodsUnitPermission]
@ -142,7 +142,7 @@ class GoodsUnitViewSet(ModelViewSet, ExportMixin, ImportMixin):
class GoodsViewSet(ModelViewSet, ExportMixin, ImportMixin): class GoodsViewSet(ModelViewSet, ExportMixin, ImportMixin):
"""""" """"""
serializer_class = GoodsSerializer serializer_class = GoodsSerializer
permission_classes = [IsAuthenticated, GoodsPermission] permission_classes = [IsAuthenticated, GoodsPermission]
@ -250,7 +250,7 @@ class GoodsViewSet(ModelViewSet, ExportMixin, ImportMixin):
class GoodsImageViewSet(ModelViewSet): class GoodsImageViewSet(ModelViewSet):
"""品图片""" """品图片"""
serializer_class = GoodsImageSerializer serializer_class = GoodsImageSerializer
permission_classes = [IsAuthenticated, GoodsPermission] permission_classes = [IsAuthenticated, GoodsPermission]

View file

@ -2,10 +2,10 @@ from extensions.serializers import *
class InventoryWarningResponse(Serializer): class InventoryWarningResponse(Serializer):
goods = IntegerField(label='品ID') goods = IntegerField(label='品ID')
goods_number = CharField(label='品编号') goods_number = CharField(label='品编号')
goods_name = CharField(label='品名称') goods_name = CharField(label='品名称')
goods_barcode = CharField(label='品条码') goods_barcode = CharField(label='品条码')
unit_name = CharField(label='单位名称') unit_name = CharField(label='单位名称')
inventory_upper = FloatField(label='库存上限') inventory_upper = FloatField(label='库存上限')
inventory_lower = FloatField(label='库存下限') inventory_lower = FloatField(label='库存下限')

View file

@ -8,7 +8,7 @@ from apps.sales.models import *
# Goods # Goods
class BatchOptionFilter(FilterSet): class BatchOptionFilter(FilterSet):
warehouse = NumberFilter(field_name='warehouse', required=True, label='仓库') warehouse = NumberFilter(field_name='warehouse', required=True, label='仓库')
goods = NumberFilter(field_name='goods', required=True, label='') goods = NumberFilter(field_name='goods', required=True, label='')
class Meta: class Meta:
model = Batch model = Batch
@ -17,8 +17,8 @@ class BatchOptionFilter(FilterSet):
class InventoryOptionFilter(FilterSet): class InventoryOptionFilter(FilterSet):
warehouse = NumberFilter(field_name='warehouse', required=True, label='仓库') warehouse = NumberFilter(field_name='warehouse', required=True, label='仓库')
category = NumberFilter(field_name='goods__category', label='品分类') category = NumberFilter(field_name='goods__category', label='品分类')
is_active = BooleanFilter(field_name='goods__is_active', label='品激活状态') is_active = BooleanFilter(field_name='goods__is_active', label='品激活状态')
class Meta: class Meta:
model = Inventory model = Inventory

View file

@ -92,10 +92,10 @@ class BatchOptionSerializer(ModelSerializer):
class InventoryOptionSerializer(ModelSerializer): class InventoryOptionSerializer(ModelSerializer):
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
goods_spec = CharField(source='goods.spec', read_only=True, label='品规格') goods_spec = CharField(source='goods.spec', read_only=True, label='品规格')
purchase_price = FloatField(source='goods.purchase_price', read_only=True, label='采购价') purchase_price = FloatField(source='goods.purchase_price', read_only=True, label='采购价')
retail_price = FloatField(source='goods.retail_price', read_only=True, label='零售价') retail_price = FloatField(source='goods.retail_price', read_only=True, label='零售价')
level_price1 = FloatField(source='goods.level_price1', read_only=True, label='等级价一') level_price1 = FloatField(source='goods.level_price1', read_only=True, label='等级价一')
@ -116,9 +116,9 @@ class InventoryOptionSerializer(ModelSerializer):
class PurchaseOrderOptionSerializer(ModelSerializer): class PurchaseOrderOptionSerializer(ModelSerializer):
class PurchaseGoodsItemSerializer(ModelSerializer): class PurchaseGoodsItemSerializer(ModelSerializer):
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
class Meta: class Meta:
@ -141,7 +141,7 @@ class PurchaseOrderOptionSerializer(ModelSerializer):
handler_name = CharField(source='handler.name', read_only=True, label='经手人名称') handler_name = CharField(source='handler.name', read_only=True, label='经手人名称')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
purchase_goods_items = PurchaseGoodsItemSerializer( purchase_goods_items = PurchaseGoodsItemSerializer(
source='purchase_goods_set', many=True, label='采购品Item') source='purchase_goods_set', many=True, label='采购品Item')
purchase_account_items = PurchaseAccountItemSerializer( purchase_account_items = PurchaseAccountItemSerializer(
source='purchase_accounts', required=False, many=True, label='采购结算账户Item') source='purchase_accounts', required=False, many=True, label='采购结算账户Item')
@ -158,9 +158,9 @@ class PurchaseOrderOptionSerializer(ModelSerializer):
class SalesOrderOptionSerializer(ModelSerializer): class SalesOrderOptionSerializer(ModelSerializer):
class SalesGoodsItemSerializer(ModelSerializer): class SalesGoodsItemSerializer(ModelSerializer):
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
class Meta: class Meta:
@ -183,7 +183,7 @@ class SalesOrderOptionSerializer(ModelSerializer):
handler_name = CharField(source='handler.name', read_only=True, label='经手人名称') handler_name = CharField(source='handler.name', read_only=True, label='经手人名称')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
sales_goods_items = SalesGoodsItemSerializer( sales_goods_items = SalesGoodsItemSerializer(
source='sales_goods_set', many=True, label='采购品Item') source='sales_goods_set', many=True, label='采购品Item')
sales_account_items = SalesAccountItemSerializer( sales_account_items = SalesAccountItemSerializer(
source='sales_accounts', required=False, many=True, label='采购结算账户Item') source='sales_accounts', required=False, many=True, label='采购结算账户Item')

View file

3
apps/production/admin.py Normal file
View file

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
apps/production/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class ProductionConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.production'

View file

@ -0,0 +1,7 @@
from django_filters.rest_framework import FilterSet
from django_filters.filters import *
__all__ = [
]

View file

36
apps/production/models.py Normal file
View file

@ -0,0 +1,36 @@
from extensions.models import *
class ProductionOrder(Model):
"""生产单据"""
number = CharField(max_length=32, verbose_name='编号')
is_related = BooleanField()
sales_order = ForeignKey()
warehouse = ForeignKey('data.Warehouse', on_delete=PROTECT, related_name='sales_orders', verbose_name='仓库')
goods = ForeignKey()
total_quantity = FloatField()
start_time = DateTimeField()
end_time = DateTimeField()
creator = ForeignKey('system.User', on_delete=PROTECT,
related_name='created_sales_orders', verbose_name='创建人')
create_time = DateTimeField(auto_now_add=True, verbose_name='创建时间')
team = ForeignKey('system.Team', on_delete=CASCADE, related_name='sales_orders')
class ProductionRecord(Model):
"""生产记录"""
production_order = ForeignKey()
warehouse = ForeignKey('data.Warehouse', on_delete=PROTECT, related_name='sales_orders', verbose_name='仓库')
goods = ForeignKey()
production_quantity = FloatField()
creator = ForeignKey('system.User', on_delete=PROTECT,
related_name='created_sales_orders', verbose_name='创建人')
create_time = DateTimeField(auto_now_add=True, verbose_name='创建时间')
team = ForeignKey('system.Team', on_delete=CASCADE, related_name='sales_orders')
__all__ = [
'ProductionPlan', 'ProductionRecord',
]

View file

@ -0,0 +1,6 @@
from extensions.permissions import ModelPermission
__all__ = [
]

View file

@ -0,0 +1,6 @@
from extensions.serializers import *
__all__ = [
]

View file

@ -0,0 +1,8 @@
from extensions.common.base import *
from extensions.serializers import *
from extensions.exceptions import *
__all__ = [
]

3
apps/production/tests.py Normal file
View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

5
apps/production/urls.py Normal file
View file

@ -0,0 +1,5 @@
from extensions.routers import *
router = BaseRouter()
urlpatterns = router.urls

10
apps/production/views.py Normal file
View file

@ -0,0 +1,10 @@
from extensions.common.schema import *
from extensions.common.base import *
from extensions.permissions import *
from extensions.exceptions import *
from extensions.viewsets import *
__all__ = [
]

View file

@ -41,11 +41,11 @@ class PurchaseOrder(Model):
class PurchaseGoods(Model): class PurchaseGoods(Model):
"""采购""" """采购"""
purchase_order = ForeignKey('purchase.PurchaseOrder', on_delete=CASCADE, purchase_order = ForeignKey('purchase.PurchaseOrder', on_delete=CASCADE,
related_name='purchase_goods_set', verbose_name='采购单据') related_name='purchase_goods_set', verbose_name='采购单据')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, related_name='purchase_goods_set', verbose_name='') goods = ForeignKey('goods.Goods', on_delete=PROTECT, related_name='purchase_goods_set', verbose_name='')
purchase_quantity = FloatField(verbose_name='采购数量') purchase_quantity = FloatField(verbose_name='采购数量')
purchase_price = FloatField(verbose_name='采购单价') purchase_price = FloatField(verbose_name='采购单价')
total_amount = AmountField(verbose_name='总金额') total_amount = AmountField(verbose_name='总金额')
@ -110,14 +110,14 @@ class PurchaseReturnOrder(Model):
class PurchaseReturnGoods(Model): class PurchaseReturnGoods(Model):
"""采购退货""" """采购退货"""
purchase_return_order = ForeignKey('purchase.PurchaseReturnOrder', on_delete=CASCADE, purchase_return_order = ForeignKey('purchase.PurchaseReturnOrder', on_delete=CASCADE,
related_name='purchase_return_goods_set', verbose_name='采购退货单据') related_name='purchase_return_goods_set', verbose_name='采购退货单据')
purchase_goods = ForeignKey('purchase.PurchaseGoods', on_delete=CASCADE, null=True, purchase_goods = ForeignKey('purchase.PurchaseGoods', on_delete=CASCADE, null=True,
related_name='purchase_return_goods_set', verbose_name='采购') related_name='purchase_return_goods_set', verbose_name='采购')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, goods = ForeignKey('goods.Goods', on_delete=PROTECT,
related_name='purchase_return_goods_set', verbose_name='') related_name='purchase_return_goods_set', verbose_name='')
return_quantity = FloatField(verbose_name='退货数量') return_quantity = FloatField(verbose_name='退货数量')
return_price = FloatField(verbose_name='退货单价') return_price = FloatField(verbose_name='退货单价')
total_amount = AmountField(verbose_name='总金额') total_amount = AmountField(verbose_name='总金额')

View file

@ -12,11 +12,11 @@ class PurchaseOrderSerializer(BaseSerializer):
"""采购单据""" """采购单据"""
class PurchaseGoodsItemSerializer(BaseSerializer): class PurchaseGoodsItemSerializer(BaseSerializer):
"""采购""" """采购"""
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
class Meta: class Meta:
@ -26,9 +26,9 @@ class PurchaseOrderSerializer(BaseSerializer):
fields = ['goods', 'purchase_quantity', 'purchase_price', *read_only_fields] fields = ['goods', 'purchase_quantity', 'purchase_price', *read_only_fields]
def validate_goods(self, instance): def validate_goods(self, instance):
instance = self.validate_foreign_key(Goods, instance, message='品不存在') instance = self.validate_foreign_key(Goods, instance, message='品不存在')
if not instance.is_active: if not instance.is_active:
raise ValidationError(f'品[{instance.name}]未激活') raise ValidationError(f'品[{instance.name}]未激活')
return instance return instance
def validate_purchase_quantity(self, value): def validate_purchase_quantity(self, value):
@ -70,7 +70,7 @@ class PurchaseOrderSerializer(BaseSerializer):
handler_name = CharField(source='handler.name', read_only=True, label='经手人名称') handler_name = CharField(source='handler.name', read_only=True, label='经手人名称')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
purchase_goods_items = PurchaseGoodsItemSerializer( purchase_goods_items = PurchaseGoodsItemSerializer(
source='purchase_goods_set', many=True, label='采购品Item') source='purchase_goods_set', many=True, label='采购品Item')
purchase_account_items = PurchaseAccountItemSerializer( purchase_account_items = PurchaseAccountItemSerializer(
source='purchase_accounts', required=False, many=True, label='采购结算账户Item') source='purchase_accounts', required=False, many=True, label='采购结算账户Item')
@ -123,7 +123,7 @@ class PurchaseOrderSerializer(BaseSerializer):
total_purchase_quantity = 0 total_purchase_quantity = 0
total_purchase_amount = 0 total_purchase_amount = 0
# 创建采购 # 创建采购
purchase_goods_set = [] purchase_goods_set = []
for purchase_goods_item in purchase_goods_items: for purchase_goods_item in purchase_goods_items:
purchase_quantity = purchase_goods_item['purchase_quantity'] purchase_quantity = purchase_goods_item['purchase_quantity']
@ -171,11 +171,11 @@ class PurchaseReturnOrderSerializer(BaseSerializer):
"""采购退货单据""" """采购退货单据"""
class PurchaseReturnGoodsItemSerializer(BaseSerializer): class PurchaseReturnGoodsItemSerializer(BaseSerializer):
"""采购退货""" """采购退货"""
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
class Meta: class Meta:
@ -185,13 +185,13 @@ class PurchaseReturnOrderSerializer(BaseSerializer):
fields = ['purchase_goods', 'goods', 'return_quantity', 'return_price', *read_only_fields] fields = ['purchase_goods', 'goods', 'return_quantity', 'return_price', *read_only_fields]
def validate_purchase_goods(self, instance): def validate_purchase_goods(self, instance):
instance = self.validate_foreign_key(PurchaseGoods, instance, message='采购品不存在') instance = self.validate_foreign_key(PurchaseGoods, instance, message='采购品不存在')
return instance return instance
def validate_goods(self, instance): def validate_goods(self, instance):
instance = self.validate_foreign_key(Goods, instance, message='品不存在') instance = self.validate_foreign_key(Goods, instance, message='品不存在')
if not instance.is_active: if not instance.is_active:
raise ValidationError(f'品[{instance.name}]未激活') raise ValidationError(f'品[{instance.name}]未激活')
return instance return instance
def validate_return_quantity(self, value): def validate_return_quantity(self, value):
@ -234,7 +234,7 @@ class PurchaseReturnOrderSerializer(BaseSerializer):
handler_name = CharField(source='handler.name', read_only=True, label='经手人名称') handler_name = CharField(source='handler.name', read_only=True, label='经手人名称')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
purchase_return_goods_items = PurchaseReturnGoodsItemSerializer( purchase_return_goods_items = PurchaseReturnGoodsItemSerializer(
source='purchase_return_goods_set', many=True, label='采购退货品Item') source='purchase_return_goods_set', many=True, label='采购退货品Item')
purchase_return_account_items = PurchaseReturnAccountItemSerializer( purchase_return_account_items = PurchaseReturnAccountItemSerializer(
source='purchase_return_accounts', required=False, many=True, label='采购退货结算账户Item') source='purchase_return_accounts', required=False, many=True, label='采购退货结算账户Item')
@ -299,7 +299,7 @@ class PurchaseReturnOrderSerializer(BaseSerializer):
total_return_quantity = 0 total_return_quantity = 0
total_return_amount = 0 total_return_amount = 0
# 创建采购退货 # 创建采购退货
purchase_return_goods_set = [] purchase_return_goods_set = []
for purchase_return_goods_item in purchase_return_goods_items: for purchase_return_goods_item in purchase_return_goods_items:
goods = purchase_return_goods_item['goods'] goods = purchase_return_goods_item['goods']
@ -308,13 +308,13 @@ class PurchaseReturnOrderSerializer(BaseSerializer):
purchase_goods = None purchase_goods = None
if purchase_order := purchase_return_order.purchase_order: if purchase_order := purchase_return_order.purchase_order:
if not (purchase_goods := purchase_return_goods_item.get('purchase_goods')): if not (purchase_goods := purchase_return_goods_item.get('purchase_goods')):
raise ValidationError(f'采购单据[{purchase_order.number}]不存在品[{goods.name}]') raise ValidationError(f'采购单据[{purchase_order.number}]不存在品[{goods.name}]')
purchase_goods.return_quantity = NP.plus(purchase_goods.return_quantity, return_quantity) purchase_goods.return_quantity = NP.plus(purchase_goods.return_quantity, return_quantity)
if purchase_goods.return_quantity > purchase_goods.purchase_quantity: if purchase_goods.return_quantity > purchase_goods.purchase_quantity:
raise ValidationError(f'退货品[{goods.name}]退货数量错误') raise ValidationError(f'退货品[{goods.name}]退货数量错误')
# 同步采购品退货数量 # 同步采购品退货数量
purchase_goods.save(update_fields=['return_quantity']) purchase_goods.save(update_fields=['return_quantity'])
return_price = purchase_return_goods_item['return_price'] return_price = purchase_return_goods_item['return_price']

View file

@ -51,7 +51,7 @@ class PurchaseOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Crea
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
else: else:
@ -67,7 +67,7 @@ class PurchaseOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Crea
creator=self.user, team=self.team creator=self.user, team=self.team
) )
# 创建入库 # 创建入库
stock_in_goods_set = [] stock_in_goods_set = []
for purchase_goods in purchase_order.purchase_goods_set.all(): for purchase_goods in purchase_order.purchase_goods_set.all():
stock_in_goods_set.append(StockInGoods( stock_in_goods_set.append(StockInGoods(
@ -125,7 +125,7 @@ class PurchaseOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Crea
if purchase_order.is_void: if purchase_order.is_void:
raise ValidationError(f'采购单据[{purchase_order.number}]已作废, 无法再次作废') raise ValidationError(f'采购单据[{purchase_order.number}]已作废, 无法再次作废')
# 同步采购单据, 采购 # 同步采购单据, 采购
purchase_order.is_void = True purchase_order.is_void = True
purchase_order.save(update_fields=['is_void']) purchase_order.save(update_fields=['is_void'])
@ -148,7 +148,7 @@ class PurchaseOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Crea
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
else: else:
@ -232,7 +232,7 @@ class PurchaseReturnOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
else: else:
@ -248,7 +248,7 @@ class PurchaseReturnOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin
creator=self.user, team=self.team creator=self.user, team=self.team
) )
# 创建出库 # 创建出库
stock_out_goods_set = [] stock_out_goods_set = []
for purchase_return_goods in purchase_return_order.purchase_return_goods_set.all(): for purchase_return_goods in purchase_return_order.purchase_return_goods_set.all():
stock_out_goods_set.append(StockOutGoods( stock_out_goods_set.append(StockOutGoods(
@ -305,7 +305,7 @@ class PurchaseReturnOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin
if purchase_return_order.is_void: if purchase_return_order.is_void:
raise ValidationError(f'采购退货单据[{purchase_return_order.number}]已作废, 无法再次作废') raise ValidationError(f'采购退货单据[{purchase_return_order.number}]已作废, 无法再次作废')
# 同步采购退货单据, 采购退货 # 同步采购退货单据, 采购退货
purchase_return_order.is_void = True purchase_return_order.is_void = True
purchase_return_order.save(update_fields=['is_void']) purchase_return_order.save(update_fields=['is_void'])
@ -328,11 +328,11 @@ class PurchaseReturnOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
# 同步采购品退货数量 # 同步采购品退货数量
if purchase_goods := purchase_return_goods.purchase_goods: if purchase_goods := purchase_return_goods.purchase_goods:
purchase_goods.return_quantity = NP.minus(purchase_goods.return_quantity, purchase_goods.return_quantity = NP.minus(purchase_goods.return_quantity,
purchase_return_goods.return_quantity) purchase_return_goods.return_quantity)

View file

@ -42,11 +42,11 @@ class SalesOrder(Model):
class SalesGoods(Model): class SalesGoods(Model):
"""销售""" """销售"""
sales_order = ForeignKey('sales.SalesOrder', on_delete=CASCADE, sales_order = ForeignKey('sales.SalesOrder', on_delete=CASCADE,
related_name='sales_goods_set', verbose_name='销售单据') related_name='sales_goods_set', verbose_name='销售单据')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, related_name='sales_goods_set', verbose_name='') goods = ForeignKey('goods.Goods', on_delete=PROTECT, related_name='sales_goods_set', verbose_name='')
sales_quantity = FloatField(verbose_name='销售数量') sales_quantity = FloatField(verbose_name='销售数量')
sales_price = FloatField(verbose_name='销售单价') sales_price = FloatField(verbose_name='销售单价')
total_amount = AmountField(verbose_name='总金额') total_amount = AmountField(verbose_name='总金额')
@ -111,13 +111,13 @@ class SalesReturnOrder(Model):
class SalesReturnGoods(Model): class SalesReturnGoods(Model):
"""销售退货""" """销售退货"""
sales_return_order = ForeignKey('sales.SalesReturnOrder', on_delete=CASCADE, sales_return_order = ForeignKey('sales.SalesReturnOrder', on_delete=CASCADE,
related_name='sales_return_goods_set', verbose_name='销售退货单据') related_name='sales_return_goods_set', verbose_name='销售退货单据')
sales_goods = ForeignKey('sales.SalesGoods', on_delete=CASCADE, null=True, sales_goods = ForeignKey('sales.SalesGoods', on_delete=CASCADE, null=True,
related_name='sales_return_goods_set', verbose_name='销售') related_name='sales_return_goods_set', verbose_name='销售')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, related_name='sales_return_goods_set', verbose_name='') goods = ForeignKey('goods.Goods', on_delete=PROTECT, related_name='sales_return_goods_set', verbose_name='')
return_quantity = FloatField(verbose_name='退货数量') return_quantity = FloatField(verbose_name='退货数量')
return_price = FloatField(verbose_name='退货单价') return_price = FloatField(verbose_name='退货单价')
total_amount = AmountField(verbose_name='总金额') total_amount = AmountField(verbose_name='总金额')

View file

@ -12,11 +12,11 @@ class SalesOrderSerializer(BaseSerializer):
"""销售单据""" """销售单据"""
class SalesGoodsItemSerializer(BaseSerializer): class SalesGoodsItemSerializer(BaseSerializer):
"""销售""" """销售"""
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
class Meta: class Meta:
@ -26,9 +26,9 @@ class SalesOrderSerializer(BaseSerializer):
fields = ['goods', 'sales_quantity', 'sales_price', *read_only_fields] fields = ['goods', 'sales_quantity', 'sales_price', *read_only_fields]
def validate_goods(self, instance): def validate_goods(self, instance):
instance = self.validate_foreign_key(Goods, instance, message='品不存在') instance = self.validate_foreign_key(Goods, instance, message='品不存在')
if not instance.is_active: if not instance.is_active:
raise ValidationError(f'品[{instance.name}]未激活') raise ValidationError(f'品[{instance.name}]未激活')
return instance return instance
def validate_sales_quantity(self, value): def validate_sales_quantity(self, value):
@ -70,7 +70,7 @@ class SalesOrderSerializer(BaseSerializer):
handler_name = CharField(source='handler.name', read_only=True, label='经手人名称') handler_name = CharField(source='handler.name', read_only=True, label='经手人名称')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
sales_goods_items = SalesGoodsItemSerializer( sales_goods_items = SalesGoodsItemSerializer(
source='sales_goods_set', many=True, label='销售品Item') source='sales_goods_set', many=True, label='销售品Item')
sales_account_items = SalesAccountItemSerializer( sales_account_items = SalesAccountItemSerializer(
source='sales_accounts', required=False, many=True, label='销售结算账户Item') source='sales_accounts', required=False, many=True, label='销售结算账户Item')
@ -128,7 +128,7 @@ class SalesOrderSerializer(BaseSerializer):
total_sales_quantity = 0 total_sales_quantity = 0
total_sales_amount = 0 total_sales_amount = 0
# 创建销售 # 创建销售
sales_goods_set = [] sales_goods_set = []
for sales_goods_item in sales_goods_items: for sales_goods_item in sales_goods_items:
sales_quantity = sales_goods_item['sales_quantity'] sales_quantity = sales_goods_item['sales_quantity']
@ -175,11 +175,11 @@ class SalesReturnOrderSerializer(BaseSerializer):
"""销售退货单据""" """销售退货单据"""
class SalesReturnGoodsItemSerializer(BaseSerializer): class SalesReturnGoodsItemSerializer(BaseSerializer):
"""销售退货""" """销售退货"""
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
class Meta: class Meta:
@ -189,13 +189,13 @@ class SalesReturnOrderSerializer(BaseSerializer):
fields = ['sales_goods', 'goods', 'return_quantity', 'return_price', *read_only_fields] fields = ['sales_goods', 'goods', 'return_quantity', 'return_price', *read_only_fields]
def validate_sales_goods(self, instance): def validate_sales_goods(self, instance):
instance = self.validate_foreign_key(SalesGoods, instance, message='销售品不存在') instance = self.validate_foreign_key(SalesGoods, instance, message='销售品不存在')
return instance return instance
def validate_goods(self, instance): def validate_goods(self, instance):
instance = self.validate_foreign_key(Goods, instance, message='品不存在') instance = self.validate_foreign_key(Goods, instance, message='品不存在')
if not instance.is_active: if not instance.is_active:
raise ValidationError(f'品[{instance.name}]未激活') raise ValidationError(f'品[{instance.name}]未激活')
return instance return instance
def validate_return_quantity(self, value): def validate_return_quantity(self, value):
@ -238,7 +238,7 @@ class SalesReturnOrderSerializer(BaseSerializer):
handler_name = CharField(source='handler.name', read_only=True, label='经手人名称') handler_name = CharField(source='handler.name', read_only=True, label='经手人名称')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
sales_return_goods_items = SalesReturnGoodsItemSerializer( sales_return_goods_items = SalesReturnGoodsItemSerializer(
source='sales_return_goods_set', many=True, label='销售退货') source='sales_return_goods_set', many=True, label='销售退货')
sales_return_account_items = SalesReturnAccountItemSerializer( sales_return_account_items = SalesReturnAccountItemSerializer(
source='sales_return_accounts', required=False, many=True, label='销售退货结算账户') source='sales_return_accounts', required=False, many=True, label='销售退货结算账户')
@ -308,7 +308,7 @@ class SalesReturnOrderSerializer(BaseSerializer):
total_return_quantity = 0 total_return_quantity = 0
total_return_amount = 0 total_return_amount = 0
# 创建销售退货 # 创建销售退货
sales_return_goods_set = [] sales_return_goods_set = []
for sales_return_goods_item in sales_return_goods_items: for sales_return_goods_item in sales_return_goods_items:
goods = sales_return_goods_item['goods'] goods = sales_return_goods_item['goods']
@ -317,13 +317,13 @@ class SalesReturnOrderSerializer(BaseSerializer):
sales_goods = None sales_goods = None
if sales_order := sales_return_order.sales_order: if sales_order := sales_return_order.sales_order:
if not (sales_goods := sales_return_goods_item.get('sales_goods')): if not (sales_goods := sales_return_goods_item.get('sales_goods')):
raise ValidationError(f'销售单据[{sales_order.number}]不存在品[{goods.name}]') raise ValidationError(f'销售单据[{sales_order.number}]不存在品[{goods.name}]')
sales_goods.return_quantity = NP.plus(sales_goods.return_quantity, return_quantity) sales_goods.return_quantity = NP.plus(sales_goods.return_quantity, return_quantity)
if sales_goods.return_quantity > sales_goods.sales_quantity: if sales_goods.return_quantity > sales_goods.sales_quantity:
raise ValidationError(f'退货品[{goods.name}]退货数量错误') raise ValidationError(f'退货品[{goods.name}]退货数量错误')
# 同步销售品退货数量 # 同步销售品退货数量
sales_goods.save(update_fields=['return_quantity']) sales_goods.save(update_fields=['return_quantity'])
return_price = sales_return_goods_item['return_price'] return_price = sales_return_goods_item['return_price']

View file

@ -51,7 +51,7 @@ class SalesOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, CreateM
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
else: else:
@ -67,7 +67,7 @@ class SalesOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, CreateM
creator=self.user, team=self.team creator=self.user, team=self.team
) )
# 创建出库 # 创建出库
stock_out_goods_set = [] stock_out_goods_set = []
for sales_goods in sales_order.sales_goods_set.all(): for sales_goods in sales_order.sales_goods_set.all():
stock_out_goods_set.append(StockOutGoods( stock_out_goods_set.append(StockOutGoods(
@ -125,7 +125,7 @@ class SalesOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, CreateM
if sales_order.is_void: if sales_order.is_void:
raise ValidationError(f'销售单据[{sales_order.number}]已作废, 无法再次作废') raise ValidationError(f'销售单据[{sales_order.number}]已作废, 无法再次作废')
# 同步销售单据, 销售 # 同步销售单据, 销售
sales_order.is_void = True sales_order.is_void = True
sales_order.save(update_fields=['is_void']) sales_order.save(update_fields=['is_void'])
@ -148,7 +148,7 @@ class SalesOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, CreateM
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
else: else:
@ -232,7 +232,7 @@ class SalesReturnOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, C
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
else: else:
@ -248,7 +248,7 @@ class SalesReturnOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, C
creator=self.user, team=self.team creator=self.user, team=self.team
) )
# 创建入库 # 创建入库
stock_in_goods_set = [] stock_in_goods_set = []
for sales_return_goods in sales_return_order.sales_return_goods_set.all(): for sales_return_goods in sales_return_order.sales_return_goods_set.all():
stock_in_goods_set.append(StockInGoods( stock_in_goods_set.append(StockInGoods(
@ -306,7 +306,7 @@ class SalesReturnOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, C
if sales_return_order.is_void: if sales_return_order.is_void:
raise ValidationError(f'销售退货单据[{sales_return_order.number}]已作废, 无法再次作废') raise ValidationError(f'销售退货单据[{sales_return_order.number}]已作废, 无法再次作废')
# 同步销售退货单据, 采购退货 # 同步销售退货单据, 采购退货
sales_return_order.is_void = True sales_return_order.is_void = True
sales_return_order.save(update_fields=['is_void']) sales_return_order.save(update_fields=['is_void'])
@ -329,11 +329,11 @@ class SalesReturnOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, C
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
# 同步采购品退货数量 # 同步采购品退货数量
if sales_goods := sales_return_goods.sales_goods: if sales_goods := sales_return_goods.sales_goods:
sales_goods.return_quantity = NP.minus(sales_goods.return_quantity, sales_goods.return_quantity = NP.minus(sales_goods.return_quantity,
sales_return_goods.return_quantity) sales_return_goods.return_quantity)

View file

@ -6,7 +6,7 @@ from apps.finance.models import *
class PurchaseReportFilter(FilterSet): class PurchaseReportFilter(FilterSet):
category = NumberFilter(field_name='goods__category', label='品分类') category = NumberFilter(field_name='goods__category', label='品分类')
creator = NumberFilter(field_name='sales_order__creator', label='创建人') creator = NumberFilter(field_name='sales_order__creator', label='创建人')
start_date = DateFilter(field_name='purchase_order__create_time', required=True, lookup_expr='gte', label='开始日期') start_date = DateFilter(field_name='purchase_order__create_time', required=True, lookup_expr='gte', label='开始日期')
end_date = DateFilter(field_name='purchase_order__create_time', required=True, lookup_expr='lt', label='结束日期') end_date = DateFilter(field_name='purchase_order__create_time', required=True, lookup_expr='lt', label='结束日期')
@ -17,7 +17,7 @@ class PurchaseReportFilter(FilterSet):
class SalesReportFilter(FilterSet): class SalesReportFilter(FilterSet):
category = NumberFilter(field_name='goods__category', label='品分类') category = NumberFilter(field_name='goods__category', label='品分类')
creator = NumberFilter(field_name='sales_order__creator', label='创建人') creator = NumberFilter(field_name='sales_order__creator', label='创建人')
start_date = DateFilter(field_name='sales_order__create_time', required=True, lookup_expr='gte', label='开始日期') start_date = DateFilter(field_name='sales_order__create_time', required=True, lookup_expr='gte', label='开始日期')
end_date = DateFilter(field_name='sales_order__create_time', required=True, lookup_expr='lt', label='结束日期') end_date = DateFilter(field_name='sales_order__create_time', required=True, lookup_expr='lt', label='结束日期')

View file

@ -5,7 +5,7 @@ from extensions.serializers import *
class PurchaseReportParameter(Serializer): class PurchaseReportParameter(Serializer):
start_date = DateField(required=True, label='开始日期') start_date = DateField(required=True, label='开始日期')
end_date = DateField(required=True, label='结束日期') end_date = DateField(required=True, label='结束日期')
category = IntegerField(required=False, label='品分类') category = IntegerField(required=False, label='品分类')
class PurchaseReportStatisticResponse(Serializer): class PurchaseReportStatisticResponse(Serializer):
@ -15,11 +15,11 @@ class PurchaseReportStatisticResponse(Serializer):
class PurchaseReportGroupByGoodsResponse(Serializer): class PurchaseReportGroupByGoodsResponse(Serializer):
goods = IntegerField(label='品ID') goods = IntegerField(label='品ID')
goods_number = CharField(label='品编号') goods_number = CharField(label='品编号')
goods_name = CharField(label='品名称') goods_name = CharField(label='品名称')
goods_barcode = CharField(label='品条码') goods_barcode = CharField(label='品条码')
goods_spec = CharField(label='品规格') goods_spec = CharField(label='品规格')
category_name = CharField(label='分类名称') category_name = CharField(label='分类名称')
unit_name = CharField(label='单位名称') unit_name = CharField(label='单位名称')
total_purchase_quantity = FloatField(label='采购总数量') total_purchase_quantity = FloatField(label='采购总数量')
@ -32,7 +32,7 @@ class PurchaseReportGroupByGoodsResponse(Serializer):
class SalesReportParameter(Serializer): class SalesReportParameter(Serializer):
start_date = DateField(required=True, label='开始日期') start_date = DateField(required=True, label='开始日期')
end_date = DateField(required=True, label='结束日期') end_date = DateField(required=True, label='结束日期')
category = IntegerField(required=False, label='品分类') category = IntegerField(required=False, label='品分类')
class SalesReportStatisticResponse(Serializer): class SalesReportStatisticResponse(Serializer):
@ -42,11 +42,11 @@ class SalesReportStatisticResponse(Serializer):
class SalesReportGroupByGoodsResponse(Serializer): class SalesReportGroupByGoodsResponse(Serializer):
goods = IntegerField(label='品ID') goods = IntegerField(label='品ID')
goods_number = CharField(label='品编号') goods_number = CharField(label='品编号')
goods_name = CharField(label='品名称') goods_name = CharField(label='品名称')
goods_barcode = CharField(label='品条码') goods_barcode = CharField(label='品条码')
goods_spec = CharField(label='品规格') goods_spec = CharField(label='品规格')
category_name = CharField(label='分类名称') category_name = CharField(label='分类名称')
unit_name = CharField(label='单位名称') unit_name = CharField(label='单位名称')
total_sales_quantity = FloatField(label='销售总数量') total_sales_quantity = FloatField(label='销售总数量')
@ -62,11 +62,11 @@ class SalesHotGoodsParameter(Serializer):
class SalesHotGoodsResponse(Serializer): class SalesHotGoodsResponse(Serializer):
goods = IntegerField(label='品ID') goods = IntegerField(label='品ID')
goods_number = CharField(label='品编号') goods_number = CharField(label='品编号')
goods_name = CharField(label='品名称') goods_name = CharField(label='品名称')
goods_barcode = CharField(label='品条码') goods_barcode = CharField(label='品条码')
goods_spec = CharField(label='品规格') goods_spec = CharField(label='品规格')
category_name = CharField(label='分类名称') category_name = CharField(label='分类名称')
unit_name = CharField(label='单位名称') unit_name = CharField(label='单位名称')
total_sales_quantity = FloatField(label='销售总数量') total_sales_quantity = FloatField(label='销售总数量')
@ -79,8 +79,8 @@ class SalesTrendParameter(Serializer):
class SalesTrendResponse(Serializer): class SalesTrendResponse(Serializer):
warehouse = IntegerField(label='仓库ID') warehouse = IntegerField(label='仓库ID')
warehouse_number = CharField(label='品编号') warehouse_number = CharField(label='品编号')
warehouse_name = CharField(label='品名称') warehouse_name = CharField(label='品名称')
total_sales_amount = AmountField(label='销售总金额') total_sales_amount = AmountField(label='销售总金额')
date = DateField(label='日期') date = DateField(label='日期')

View file

@ -9,10 +9,10 @@ from apps.finance.models import *
class PurchaseReportDetialSerializer(BaseSerializer): class PurchaseReportDetialSerializer(BaseSerializer):
"""采购明细""" """采购明细"""
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
goods_spec = CharField(source='goods.spec', read_only=True, label='品规格') goods_spec = CharField(source='goods.spec', read_only=True, label='品规格')
category_name = CharField(source='goods.category.name', read_only=True, label='分类名称') category_name = CharField(source='goods.category.name', read_only=True, label='分类名称')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
purchase_order_number = CharField(source='purchase_order.number', read_only=True, label='采购单号') purchase_order_number = CharField(source='purchase_order.number', read_only=True, label='采购单号')
@ -34,10 +34,10 @@ class PurchaseReportDetialSerializer(BaseSerializer):
class SalesReportDetialSerializer(BaseSerializer): class SalesReportDetialSerializer(BaseSerializer):
"""销售明细""" """销售明细"""
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
goods_spec = CharField(source='goods.spec', read_only=True, label='品规格') goods_spec = CharField(source='goods.spec', read_only=True, label='品规格')
category_name = CharField(source='goods.category.name', read_only=True, label='分类名称') category_name = CharField(source='goods.category.name', read_only=True, label='分类名称')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
sales_order_number = CharField(source='sales_order.number', read_only=True, label='采购单号') sales_order_number = CharField(source='sales_order.number', read_only=True, label='采购单号')

View file

@ -60,7 +60,7 @@ class PurchaseReportViewSet(BaseViewSet):
responses={200: PurchaseReportGroupByGoodsResponse}) responses={200: PurchaseReportGroupByGoodsResponse})
@action(detail=False, methods=['get']) @action(detail=False, methods=['get'])
def group_by_goods(self, request, *args, **kwargs): def group_by_goods(self, request, *args, **kwargs):
"""品汇总""" """品汇总"""
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset())
queryset = queryset.select_related('goods', 'goods__category', 'goods__unit') queryset = queryset.select_related('goods', 'goods__category', 'goods__unit')
@ -124,7 +124,7 @@ class SalesReportViewSet(BaseViewSet):
responses={200: SalesReportGroupByGoodsResponse}) responses={200: SalesReportGroupByGoodsResponse})
@action(detail=False, methods=['get']) @action(detail=False, methods=['get'])
def group_by_goods(self, request, *args, **kwargs): def group_by_goods(self, request, *args, **kwargs):
"""品汇总""" """品汇总"""
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset())
queryset = queryset.select_related('goods', 'goods__category', 'goods__unit') queryset = queryset.select_related('goods', 'goods__category', 'goods__unit')
@ -143,7 +143,7 @@ class SalesReportViewSet(BaseViewSet):
class SalesHotGoodsViewSet(BaseViewSet, ListModelMixin): class SalesHotGoodsViewSet(BaseViewSet, ListModelMixin):
"""销售前十""" """销售前十"""
permission_classes = [IsAuthenticated, SalesHotGoodsPermission] permission_classes = [IsAuthenticated, SalesHotGoodsPermission]
pagination_class = None pagination_class = None

View file

@ -48,7 +48,7 @@ class StockCheckOrder(Model):
class StockCheckGoods(Model): class StockCheckGoods(Model):
"""盘点""" """盘点"""
class Status(TextChoices): class Status(TextChoices):
"""盘点状态""" """盘点状态"""
@ -60,7 +60,7 @@ class StockCheckGoods(Model):
stock_check_order = ForeignKey('stock_check.StockCheckOrder', on_delete=CASCADE, stock_check_order = ForeignKey('stock_check.StockCheckOrder', on_delete=CASCADE,
related_name='stock_check_goods_set', verbose_name='盘点单据') related_name='stock_check_goods_set', verbose_name='盘点单据')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, goods = ForeignKey('goods.Goods', on_delete=PROTECT,
related_name='stock_check_goods_set', verbose_name='') related_name='stock_check_goods_set', verbose_name='')
book_quantity = FloatField(verbose_name='账面数量') book_quantity = FloatField(verbose_name='账面数量')
actual_quantity = FloatField(verbose_name='实际数量') actual_quantity = FloatField(verbose_name='实际数量')
surplus_quantity = FloatField(verbose_name='盘盈数量') surplus_quantity = FloatField(verbose_name='盘盈数量')
@ -86,11 +86,11 @@ class StockCheckBatch(Model):
stock_check_order = ForeignKey('stock_check.StockCheckOrder', on_delete=CASCADE, stock_check_order = ForeignKey('stock_check.StockCheckOrder', on_delete=CASCADE,
related_name='stock_check_batchs', verbose_name='盘点单据') related_name='stock_check_batchs', verbose_name='盘点单据')
stock_check_goods = ForeignKey('stock_check.StockCheckGoods', on_delete=CASCADE, stock_check_goods = ForeignKey('stock_check.StockCheckGoods', on_delete=CASCADE,
related_name='stock_check_batchs', verbose_name='盘点') related_name='stock_check_batchs', verbose_name='盘点')
batch_number = CharField(max_length=32, verbose_name='批次编号') batch_number = CharField(max_length=32, verbose_name='批次编号')
production_date = DateField(null=True, verbose_name='生产日期') production_date = DateField(null=True, verbose_name='生产日期')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, goods = ForeignKey('goods.Goods', on_delete=PROTECT,
related_name='stock_check_batchs', verbose_name='') related_name='stock_check_batchs', verbose_name='')
book_quantity = FloatField(verbose_name='账面数量') book_quantity = FloatField(verbose_name='账面数量')
actual_quantity = FloatField(verbose_name='实际数量') actual_quantity = FloatField(verbose_name='实际数量')
surplus_quantity = FloatField(verbose_name='盘盈数量') surplus_quantity = FloatField(verbose_name='盘盈数量')

View file

@ -11,7 +11,7 @@ class StockCheckOrderSerializer(BaseSerializer):
"""盘点单据""" """盘点单据"""
class StockCheckGoodsItemSerializer(BaseSerializer): class StockCheckGoodsItemSerializer(BaseSerializer):
"""盘点""" """盘点"""
class StockCheckBatchItemSerializer(BaseSerializer): class StockCheckBatchItemSerializer(BaseSerializer):
"""盘点批次""" """盘点批次"""
@ -28,9 +28,9 @@ class StockCheckOrderSerializer(BaseSerializer):
raise ValidationError('盘点数量小于零') raise ValidationError('盘点数量小于零')
return value return value
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
enable_batch_control = BooleanField(source='goods.enable_batch_control', enable_batch_control = BooleanField(source='goods.enable_batch_control',
read_only=True, label='启用批次控制') read_only=True, label='启用批次控制')
@ -46,9 +46,9 @@ class StockCheckOrderSerializer(BaseSerializer):
fields = ['goods', 'actual_quantity', 'stock_check_batch_items', *read_only_fields] fields = ['goods', 'actual_quantity', 'stock_check_batch_items', *read_only_fields]
def validate_goods(self, instance): def validate_goods(self, instance):
instance = self.validate_foreign_key(Goods, instance, message='品不存在') instance = self.validate_foreign_key(Goods, instance, message='品不存在')
if not instance.is_active: if not instance.is_active:
raise ValidationError(f'品[{instance.name}]未激活') raise ValidationError(f'品[{instance.name}]未激活')
return instance return instance
def validate_actual_quantity(self, value): def validate_actual_quantity(self, value):
@ -60,13 +60,13 @@ class StockCheckOrderSerializer(BaseSerializer):
goods = attrs['goods'] goods = attrs['goods']
if goods.enable_batch_control: if goods.enable_batch_control:
if not (stock_check_batch_items := attrs.get('stock_check_batchs')): if not (stock_check_batch_items := attrs.get('stock_check_batchs')):
raise ValidationError(f'品[{goods.name}]批次为空') raise ValidationError(f'品[{goods.name}]批次为空')
total_actual_quantity = reduce(lambda total, item: NP.plus(total, item['actual_quantity']), total_actual_quantity = reduce(lambda total, item: NP.plus(total, item['actual_quantity']),
stock_check_batch_items, 0) stock_check_batch_items, 0)
if total_actual_quantity != attrs['actual_quantity']: if total_actual_quantity != attrs['actual_quantity']:
raise ValidationError(f'品[{goods.name}]盘点数量错误') raise ValidationError(f'品[{goods.name}]盘点数量错误')
return super().validate(attrs) return super().validate(attrs)
@ -76,7 +76,7 @@ class StockCheckOrderSerializer(BaseSerializer):
status_display = CharField(source='get_status_display', read_only=True, label='盘点状态') status_display = CharField(source='get_status_display', read_only=True, label='盘点状态')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
stock_check_goods_Items = StockCheckGoodsItemSerializer( stock_check_goods_Items = StockCheckGoodsItemSerializer(
source='stock_check_goods_set', many=True, label='盘点') source='stock_check_goods_set', many=True, label='盘点')
class Meta: class Meta:
model = StockCheckOrder model = StockCheckOrder
@ -116,7 +116,7 @@ class StockCheckOrderSerializer(BaseSerializer):
total_actual_quantity = 0 total_actual_quantity = 0
total_surplus_amount = 0 total_surplus_amount = 0
# 创建盘点 # 创建盘点
stock_check_batchs = [] stock_check_batchs = []
for stock_check_goods_item in stock_check_goods_items: for stock_check_goods_item in stock_check_goods_items:
goods = stock_check_goods_item['goods'] goods = stock_check_goods_item['goods']

View file

@ -53,7 +53,7 @@ class StockCheckOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Cr
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
update_inventories.append(inventory) update_inventories.append(inventory)
@ -113,7 +113,7 @@ class StockCheckOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Cr
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
update_inventories.append(inventory) update_inventories.append(inventory)

View file

@ -53,12 +53,12 @@ class StockInOrder(Model):
class StockInGoods(Model): class StockInGoods(Model):
"""入库""" """入库"""
stock_in_order = ForeignKey('stock_in.StockInOrder', on_delete=CASCADE, stock_in_order = ForeignKey('stock_in.StockInOrder', on_delete=CASCADE,
related_name='stock_in_goods_set', verbose_name='入库单据') related_name='stock_in_goods_set', verbose_name='入库单据')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, goods = ForeignKey('goods.Goods', on_delete=PROTECT,
related_name='stock_in_goods_set', verbose_name='') related_name='stock_in_goods_set', verbose_name='')
stock_in_quantity = FloatField(verbose_name='入库总数') stock_in_quantity = FloatField(verbose_name='入库总数')
remain_quantity = FloatField(default=0, verbose_name='入库剩余数量') remain_quantity = FloatField(default=0, verbose_name='入库剩余数量')
is_completed = BooleanField(default=False, verbose_name='完成状态') is_completed = BooleanField(default=False, verbose_name='完成状态')
@ -88,14 +88,14 @@ class StockInRecord(Model):
class StockInRecordGoods(Model): class StockInRecordGoods(Model):
"""入库记录""" """入库记录"""
stock_in_record = ForeignKey('stock_in.StockInRecord', on_delete=CASCADE, stock_in_record = ForeignKey('stock_in.StockInRecord', on_delete=CASCADE,
related_name='stock_in_record_goods_set', verbose_name='入库记录') related_name='stock_in_record_goods_set', verbose_name='入库记录')
stock_in_goods = ForeignKey('stock_in.StockInGoods', on_delete=CASCADE, stock_in_goods = ForeignKey('stock_in.StockInGoods', on_delete=CASCADE,
related_name='stock_in_record_goods_set', verbose_name='入库') related_name='stock_in_record_goods_set', verbose_name='入库')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, goods = ForeignKey('goods.Goods', on_delete=PROTECT,
related_name='stock_in_record_goods_set', verbose_name='') related_name='stock_in_record_goods_set', verbose_name='')
stock_in_quantity = FloatField(verbose_name='入库数量') stock_in_quantity = FloatField(verbose_name='入库数量')
batch = ForeignKey('goods.Batch', on_delete=CASCADE, null=True, batch = ForeignKey('goods.Batch', on_delete=CASCADE, null=True,
related_name='stock_in_record_goods_set', verbose_name='批次') related_name='stock_in_record_goods_set', verbose_name='批次')

View file

@ -10,11 +10,11 @@ class StockInOrderSerializer(BaseSerializer):
"""入库单据""" """入库单据"""
class StockInGoodsItemSerializer(BaseSerializer): class StockInGoodsItemSerializer(BaseSerializer):
"""入库""" """入库"""
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
enable_batch_control = BooleanField(source='goods.enable_batch_control', enable_batch_control = BooleanField(source='goods.enable_batch_control',
read_only=True, label='启用批次控制') read_only=True, label='启用批次控制')
@ -36,7 +36,7 @@ class StockInOrderSerializer(BaseSerializer):
read_only=True, label='调拨单据编号') read_only=True, label='调拨单据编号')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
stock_in_goods_items = StockInGoodsItemSerializer( stock_in_goods_items = StockInGoodsItemSerializer(
source='stock_in_goods_set', many=True, label='入库品Item') source='stock_in_goods_set', many=True, label='入库品Item')
class Meta: class Meta:
model = StockInOrder model = StockInOrder
@ -51,11 +51,11 @@ class StockInRecordSerializer(BaseSerializer):
"""入库记录""" """入库记录"""
class StockInRecordGoodsItemSerializer(BaseSerializer): class StockInRecordGoodsItemSerializer(BaseSerializer):
"""入库记录""" """入库记录"""
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
enable_batch_control = BooleanField(source='goods.enable_batch_control', enable_batch_control = BooleanField(source='goods.enable_batch_control',
read_only=True, label='启用批次控制') read_only=True, label='启用批次控制')
@ -72,9 +72,9 @@ class StockInRecordSerializer(BaseSerializer):
*read_only_fields] *read_only_fields]
def validate_stock_in_goods(self, instance): def validate_stock_in_goods(self, instance):
instance = self.validate_foreign_key(StockInGoods, instance, message='入库品不存在') instance = self.validate_foreign_key(StockInGoods, instance, message='入库品不存在')
if instance.is_completed: if instance.is_completed:
raise ValidationError(f'入库品[{instance.goods.name}]已完成') raise ValidationError(f'入库品[{instance.goods.name}]已完成')
return instance return instance
def validate_stock_in_quantity(self, value): def validate_stock_in_quantity(self, value):
@ -87,11 +87,11 @@ class StockInRecordSerializer(BaseSerializer):
goods = stock_in_goods.goods goods = stock_in_goods.goods
if stock_in_goods.remain_quantity < attrs['stock_in_quantity']: if stock_in_goods.remain_quantity < attrs['stock_in_quantity']:
raise ValidationError(f'品[{goods.name}]入库数量错误') raise ValidationError(f'品[{goods.name}]入库数量错误')
if goods.enable_batch_control: if goods.enable_batch_control:
if not (attrs.get('batch') or attrs['batch'].get('number')): if not (attrs.get('batch') or attrs['batch'].get('number')):
raise ValidationError(f'品[{goods.name}]批次编号为空') raise ValidationError(f'品[{goods.name}]批次编号为空')
return super().validate(attrs) return super().validate(attrs)
stock_in_order_number = CharField(source='stock_in_order.number', read_only=True, label='入库单据编号') stock_in_order_number = CharField(source='stock_in_order.number', read_only=True, label='入库单据编号')
@ -100,7 +100,7 @@ class StockInRecordSerializer(BaseSerializer):
handler_name = CharField(source='handler.name', read_only=True, label='经手人名称') handler_name = CharField(source='handler.name', read_only=True, label='经手人名称')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
stock_in_record_goods_items = StockInRecordGoodsItemSerializer( stock_in_record_goods_items = StockInRecordGoodsItemSerializer(
source='stock_in_record_goods_set', many=True, label='入库记录') source='stock_in_record_goods_set', many=True, label='入库记录')
class Meta: class Meta:
model = StockInRecord model = StockInRecord
@ -136,12 +136,12 @@ class StockInRecordSerializer(BaseSerializer):
total_stock_in_quantity = 0 total_stock_in_quantity = 0
# 创建入库记录 # 创建入库记录
stock_in_record_goods_set = [] stock_in_record_goods_set = []
for stock_in_record_goods_item in stock_in_record_goods_items: for stock_in_record_goods_item in stock_in_record_goods_items:
stock_in_goods = stock_in_record_goods_item['stock_in_goods'] stock_in_goods = stock_in_record_goods_item['stock_in_goods']
if stock_in_goods.stock_in_order != stock_in_order: if stock_in_goods.stock_in_order != stock_in_order:
raise ValidationError('入库品错误') raise ValidationError('入库品错误')
stock_in_quantity = stock_in_record_goods_item['stock_in_quantity'] stock_in_quantity = stock_in_record_goods_item['stock_in_quantity']
goods = stock_in_goods.goods goods = stock_in_goods.goods

View file

@ -63,11 +63,11 @@ class StockInRecordViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Crea
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
# 同步入库 # 同步入库
stock_in_goods = stock_in_record_goods.stock_in_goods stock_in_goods = stock_in_record_goods.stock_in_goods
stock_in_goods.remain_quantity = NP.minus(stock_in_goods.remain_quantity, quantity_change) stock_in_goods.remain_quantity = NP.minus(stock_in_goods.remain_quantity, quantity_change)
stock_in_goods.save(update_fields=['remain_quantity']) stock_in_goods.save(update_fields=['remain_quantity'])
@ -89,7 +89,7 @@ class StockInRecordViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Crea
if stock_in_record.is_void: if stock_in_record.is_void:
raise ValidationError(f'入库记录已作废, 无法再次作废') raise ValidationError(f'入库记录已作废, 无法再次作废')
# 同步入库记录, 入库记录 # 同步入库记录, 入库记录
stock_in_record.is_void = True stock_in_record.is_void = True
stock_in_record.save(update_fields=['is_void']) stock_in_record.save(update_fields=['is_void'])
@ -111,7 +111,7 @@ class StockInRecordViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Crea
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
@ -122,7 +122,7 @@ class StockInRecordViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Crea
batch.has_stock = batch.remain_quantity > 0 batch.has_stock = batch.remain_quantity > 0
batch.save(update_fields=['total_quantity', 'remain_quantity', 'has_stock']) batch.save(update_fields=['total_quantity', 'remain_quantity', 'has_stock'])
# 同步入库 # 同步入库
stock_in_goods = stock_in_record_goods.stock_in_goods stock_in_goods = stock_in_record_goods.stock_in_goods
stock_in_goods.remain_quantity = NP.plus(stock_in_goods.remain_quantity, quantity_change) stock_in_goods.remain_quantity = NP.plus(stock_in_goods.remain_quantity, quantity_change)
stock_in_goods.save(update_fields=['remain_quantity']) stock_in_goods.save(update_fields=['remain_quantity'])

View file

@ -49,12 +49,12 @@ class StockOutOrder(Model):
class StockOutGoods(Model): class StockOutGoods(Model):
"""出库""" """出库"""
stock_out_order = ForeignKey('stock_out.StockOutOrder', on_delete=CASCADE, stock_out_order = ForeignKey('stock_out.StockOutOrder', on_delete=CASCADE,
related_name='stock_out_goods_set', verbose_name='出库单据') related_name='stock_out_goods_set', verbose_name='出库单据')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, goods = ForeignKey('goods.Goods', on_delete=PROTECT,
related_name='stock_out_goods_set', verbose_name='') related_name='stock_out_goods_set', verbose_name='')
stock_out_quantity = FloatField(verbose_name='出库总数') stock_out_quantity = FloatField(verbose_name='出库总数')
remain_quantity = FloatField(default=0, verbose_name='出库剩余数量') remain_quantity = FloatField(default=0, verbose_name='出库剩余数量')
is_completed = BooleanField(default=False, verbose_name='完成状态') is_completed = BooleanField(default=False, verbose_name='完成状态')
@ -84,14 +84,14 @@ class StockOutRecord(Model):
class StockOutRecordGoods(Model): class StockOutRecordGoods(Model):
"""出库记录""" """出库记录"""
stock_out_record = ForeignKey('stock_out.StockOutRecord', on_delete=CASCADE, stock_out_record = ForeignKey('stock_out.StockOutRecord', on_delete=CASCADE,
related_name='stock_out_record_goods_set', verbose_name='出库记录') related_name='stock_out_record_goods_set', verbose_name='出库记录')
stock_out_goods = ForeignKey('stock_out.StockOutGoods', on_delete=CASCADE, stock_out_goods = ForeignKey('stock_out.StockOutGoods', on_delete=CASCADE,
related_name='stock_out_record_goods_set', verbose_name='出库') related_name='stock_out_record_goods_set', verbose_name='出库')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, goods = ForeignKey('goods.Goods', on_delete=PROTECT,
related_name='stock_out_record_goods_set', verbose_name='') related_name='stock_out_record_goods_set', verbose_name='')
stock_out_quantity = FloatField(verbose_name='出库数量') stock_out_quantity = FloatField(verbose_name='出库数量')
batch = ForeignKey('goods.Batch', on_delete=CASCADE, null=True, batch = ForeignKey('goods.Batch', on_delete=CASCADE, null=True,
related_name='stock_out_record_goods_set', verbose_name='批次') related_name='stock_out_record_goods_set', verbose_name='批次')

View file

@ -10,11 +10,11 @@ class StockOutOrderSerializer(BaseSerializer):
"""出库单据""" """出库单据"""
class StockOutGoodsItemSerializer(BaseSerializer): class StockOutGoodsItemSerializer(BaseSerializer):
"""出库""" """出库"""
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
enable_batch_control = BooleanField(source='goods.enable_batch_control', enable_batch_control = BooleanField(source='goods.enable_batch_control',
read_only=True, label='启用批次控制') read_only=True, label='启用批次控制')
@ -34,7 +34,7 @@ class StockOutOrderSerializer(BaseSerializer):
read_only=True, label='调拨单据编号') read_only=True, label='调拨单据编号')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
stock_out_goods_items = StockOutGoodsItemSerializer( stock_out_goods_items = StockOutGoodsItemSerializer(
source='stock_out_goods_set', many=True, label='出库') source='stock_out_goods_set', many=True, label='出库')
class Meta: class Meta:
model = StockOutOrder model = StockOutOrder
@ -49,11 +49,11 @@ class StockOutRecordSerializer(BaseSerializer):
"""出库记录""" """出库记录"""
class StockOutRecordGoodsSerializer(BaseSerializer): class StockOutRecordGoodsSerializer(BaseSerializer):
"""出库记录""" """出库记录"""
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
enable_batch_control = BooleanField(source='goods.enable_batch_control', enable_batch_control = BooleanField(source='goods.enable_batch_control',
read_only=True, label='启用批次控制') read_only=True, label='启用批次控制')
@ -66,9 +66,9 @@ class StockOutRecordSerializer(BaseSerializer):
fields = ['stock_out_goods', 'stock_out_quantity', 'batch', *read_only_fields] fields = ['stock_out_goods', 'stock_out_quantity', 'batch', *read_only_fields]
def validate_stock_out_goods(self, instance): def validate_stock_out_goods(self, instance):
instance = self.validate_foreign_key(StockOutGoods, instance, message='出库品不存在') instance = self.validate_foreign_key(StockOutGoods, instance, message='出库品不存在')
if instance.is_completed: if instance.is_completed:
raise ValidationError(f'出库品[{instance.goods.name}]已完成') raise ValidationError(f'出库品[{instance.goods.name}]已完成')
return instance return instance
def validate_stock_out_quantity(self, value): def validate_stock_out_quantity(self, value):
@ -87,11 +87,11 @@ class StockOutRecordSerializer(BaseSerializer):
goods = stock_out_goods.goods goods = stock_out_goods.goods
if stock_out_goods.remain_quantity < attrs['stock_out_quantity']: if stock_out_goods.remain_quantity < attrs['stock_out_quantity']:
raise ValidationError(f'品[{goods.name}]出库数量错误') raise ValidationError(f'品[{goods.name}]出库数量错误')
if goods.enable_batch_control: if goods.enable_batch_control:
if not (batch := attrs.get('batch')): if not (batch := attrs.get('batch')):
raise ValidationError(f'品[{goods.name}]未选择批次') raise ValidationError(f'品[{goods.name}]未选择批次')
if batch.goods != attrs['stock_out_goods'].goods: if batch.goods != attrs['stock_out_goods'].goods:
raise ValidationError(f'批次[{batch.number}]选择错误') raise ValidationError(f'批次[{batch.number}]选择错误')
@ -107,7 +107,7 @@ class StockOutRecordSerializer(BaseSerializer):
handler_name = CharField(source='handler.name', read_only=True, label='经手人名称') handler_name = CharField(source='handler.name', read_only=True, label='经手人名称')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
stock_out_record_goods_items = StockOutRecordGoodsSerializer(source='stock_out_record_goods_set', stock_out_record_goods_items = StockOutRecordGoodsSerializer(source='stock_out_record_goods_set',
many=True, label='出库记录') many=True, label='出库记录')
class Meta: class Meta:
model = StockOutRecord model = StockOutRecord
@ -143,12 +143,12 @@ class StockOutRecordSerializer(BaseSerializer):
total_stock_out_quantity = 0 total_stock_out_quantity = 0
# 创建出库记录 # 创建出库记录
stock_out_record_goods_set = [] stock_out_record_goods_set = []
for stock_out_record_goods_item in stock_out_record_goods_items: for stock_out_record_goods_item in stock_out_record_goods_items:
stock_out_goods = stock_out_record_goods_item['stock_out_goods'] stock_out_goods = stock_out_record_goods_item['stock_out_goods']
if stock_out_goods.stock_out_order != stock_out_order: if stock_out_goods.stock_out_order != stock_out_order:
raise ValidationError('出库品错误') raise ValidationError('出库品错误')
stock_out_quantity = stock_out_record_goods_item['stock_out_quantity'] stock_out_quantity = stock_out_record_goods_item['stock_out_quantity']
batch = stock_out_record_goods_item.get('batch') batch = stock_out_record_goods_item.get('batch')

View file

@ -63,7 +63,7 @@ class StockOutRecordViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Cre
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
@ -73,7 +73,7 @@ class StockOutRecordViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Cre
batch.has_stock = batch.remain_quantity > 0 batch.has_stock = batch.remain_quantity > 0
batch.save(update_fields=['remain_quantity', 'has_stock']) batch.save(update_fields=['remain_quantity', 'has_stock'])
# 同步出库 # 同步出库
stock_out_goods = stock_out_record_goods.stock_out_goods stock_out_goods = stock_out_record_goods.stock_out_goods
stock_out_goods.remain_quantity = NP.minus(stock_out_goods.remain_quantity, quantity_change) stock_out_goods.remain_quantity = NP.minus(stock_out_goods.remain_quantity, quantity_change)
stock_out_goods.save(update_fields=['remain_quantity']) stock_out_goods.save(update_fields=['remain_quantity'])
@ -95,7 +95,7 @@ class StockOutRecordViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Cre
if stock_out_record.is_void: if stock_out_record.is_void:
raise ValidationError(f'出库记录已作废, 无法再次作废') raise ValidationError(f'出库记录已作废, 无法再次作废')
# 同步出库记录, 出库记录 # 同步出库记录, 出库记录
stock_out_record.is_void = True stock_out_record.is_void = True
stock_out_record.save(update_fields=['is_void']) stock_out_record.save(update_fields=['is_void'])
@ -117,7 +117,7 @@ class StockOutRecordViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Cre
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
@ -128,7 +128,7 @@ class StockOutRecordViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Cre
batch.has_stock = batch.remain_quantity > 0 batch.has_stock = batch.remain_quantity > 0
batch.save(update_fields=['total_quantity', 'remain_quantity', 'has_stock']) batch.save(update_fields=['total_quantity', 'remain_quantity', 'has_stock'])
# 同步出库 # 同步出库
stock_out_goods = stock_out_record_goods.stock_out_goods stock_out_goods = stock_out_record_goods.stock_out_goods
stock_out_goods.remain_quantity = NP.plus(stock_out_goods.remain_quantity, quantity_change) stock_out_goods.remain_quantity = NP.plus(stock_out_goods.remain_quantity, quantity_change)
stock_out_goods.save(update_fields=['remain_quantity']) stock_out_goods.save(update_fields=['remain_quantity'])

View file

@ -41,12 +41,12 @@ class StockTransferOrder(Model):
class StockTransferGoods(Model): class StockTransferGoods(Model):
"""调拨""" """调拨"""
stock_transfer_order = ForeignKey('stock_transfer.StockTransferOrder', on_delete=CASCADE, stock_transfer_order = ForeignKey('stock_transfer.StockTransferOrder', on_delete=CASCADE,
related_name='stock_transfer_goods_set', verbose_name='采购单据') related_name='stock_transfer_goods_set', verbose_name='采购单据')
goods = ForeignKey('goods.Goods', on_delete=PROTECT, goods = ForeignKey('goods.Goods', on_delete=PROTECT,
related_name='stock_transfer_goods_set', verbose_name='') related_name='stock_transfer_goods_set', verbose_name='')
stock_transfer_quantity = FloatField(verbose_name='调拨数量') stock_transfer_quantity = FloatField(verbose_name='调拨数量')
team = ForeignKey('system.Team', on_delete=CASCADE, related_name='stock_transfer_goods_set') team = ForeignKey('system.Team', on_delete=CASCADE, related_name='stock_transfer_goods_set')

View file

@ -11,11 +11,11 @@ class StockTransferOrderSerializer(BaseSerializer):
"""调拨单据""" """调拨单据"""
class StockTransferGoodsItemSerializer(BaseSerializer): class StockTransferGoodsItemSerializer(BaseSerializer):
"""调拨""" """调拨"""
goods_number = CharField(source='goods.number', read_only=True, label='品编号') goods_number = CharField(source='goods.number', read_only=True, label='品编号')
goods_name = CharField(source='goods.name', read_only=True, label='品名称') goods_name = CharField(source='goods.name', read_only=True, label='品名称')
goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码') goods_barcode = CharField(source='goods.barcode', read_only=True, label='品条码')
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称') unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
class Meta: class Meta:
@ -24,9 +24,9 @@ class StockTransferOrderSerializer(BaseSerializer):
fields = ['goods', 'stock_transfer_quantity', *read_only_fields] fields = ['goods', 'stock_transfer_quantity', *read_only_fields]
def validate_goods(self, instance): def validate_goods(self, instance):
instance = self.validate_foreign_key(Goods, instance, message='品不存在') instance = self.validate_foreign_key(Goods, instance, message='品不存在')
if not instance.is_active: if not instance.is_active:
raise ValidationError(f'入库品[{instance.goods.name}]已作废') raise ValidationError(f'入库品[{instance.goods.name}]已作废')
return instance return instance
def validate_stock_transfer_quantity(self, value): def validate_stock_transfer_quantity(self, value):
@ -41,7 +41,7 @@ class StockTransferOrderSerializer(BaseSerializer):
handler_name = CharField(source='handler.name', read_only=True, label='经手人名称') handler_name = CharField(source='handler.name', read_only=True, label='经手人名称')
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称') creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
stock_transfer_goods_items = StockTransferGoodsItemSerializer( stock_transfer_goods_items = StockTransferGoodsItemSerializer(
source='stock_transfer_goods_set', many=True, label='调拨') source='stock_transfer_goods_set', many=True, label='调拨')
class Meta: class Meta:
model = StockTransferOrder model = StockTransferOrder
@ -92,7 +92,7 @@ class StockTransferOrderSerializer(BaseSerializer):
total_stock_transfer_quantity = 0 total_stock_transfer_quantity = 0
# 创建调拨 # 创建调拨
stock_transfer_goods_set = [] stock_transfer_goods_set = []
for stock_transfer_goods_item in stock_transfer_goods_items: for stock_transfer_goods_item in stock_transfer_goods_items:
goods = stock_transfer_goods_item['goods'] goods = stock_transfer_goods_item['goods']

View file

@ -75,11 +75,11 @@ class StockTransferOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin,
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
else: else:
# 创建出库 # 创建出库
stock_out_goods_set.append(StockOutGoods( stock_out_goods_set.append(StockOutGoods(
stock_out_order=stock_out_order, goods=stock_transfer_goods.goods, stock_out_order=stock_out_order, goods=stock_transfer_goods.goods,
stock_out_quantity=stock_transfer_goods.stock_transfer_quantity, stock_out_quantity=stock_transfer_goods.stock_transfer_quantity,
@ -103,11 +103,11 @@ class StockTransferOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin,
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
else: else:
# 创建入库 # 创建入库
stock_in_goods_set.append(StockInGoods( stock_in_goods_set.append(StockInGoods(
stock_in_order=stock_in_order, goods=stock_transfer_goods.goods, stock_in_order=stock_in_order, goods=stock_transfer_goods.goods,
stock_in_quantity=stock_transfer_goods.stock_transfer_quantity, stock_in_quantity=stock_transfer_goods.stock_transfer_quantity,
@ -136,7 +136,7 @@ class StockTransferOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin,
if stock_transfer_order.is_void: if stock_transfer_order.is_void:
raise ValidationError(f'调拨单据[{stock_transfer_order.number}]已作废, 无法再次作废') raise ValidationError(f'调拨单据[{stock_transfer_order.number}]已作废, 无法再次作废')
# 同步调拨单据, 调拨 # 同步调拨单据, 调拨
stock_transfer_order.is_void = True stock_transfer_order.is_void = True
stock_transfer_order.save(update_fields=['is_void']) stock_transfer_order.save(update_fields=['is_void'])
@ -159,7 +159,7 @@ class StockTransferOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin,
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
else: else:
@ -190,7 +190,7 @@ class StockTransferOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin,
inventory.total_quantity = quantity_after inventory.total_quantity = quantity_after
if inventory.total_quantity < 0: if inventory.total_quantity < 0:
raise ValidationError(f'品[{inventory.goods.name}]库存不足') raise ValidationError(f'品[{inventory.goods.name}]库存不足')
inventory.has_stock = inventory.total_quantity > 0 inventory.has_stock = inventory.total_quantity > 0
inventory.save(update_fields=['total_quantity', 'has_stock']) inventory.save(update_fields=['total_quantity', 'has_stock'])
else: else:

View file

@ -29,13 +29,13 @@ class SystemConfigSerializer(BaseSerializer):
def validate_enable_batch_control(self, value): def validate_enable_batch_control(self, value):
if value and (self.team.enable_auto_stock_in or self.team.enable_auto_stock_out): if value and (self.team.enable_auto_stock_in or self.team.enable_auto_stock_out):
raise ValidationError('只有同时关闭自动入库、自动出库, 才可以开启品的批次控制') raise ValidationError('只有同时关闭自动入库、自动出库, 才可以开启品的批次控制')
return value return value
def validate(self, attrs): def validate(self, attrs):
if attrs['enable_auto_stock_in'] or attrs['enable_auto_stock_out']: if attrs['enable_auto_stock_in'] or attrs['enable_auto_stock_out']:
if goods := Goods.objects.filter(enable_batch_control=True, team=self.team).first(): if goods := Goods.objects.filter(enable_batch_control=True, team=self.team).first():
raise ValidationError(f'品[{goods.name}]已开启批次控制, 无法开启自动出/入库') raise ValidationError(f'品[{goods.name}]已开启批次控制, 无法开启自动出/入库')
return super().validate(attrs) return super().validate(attrs)

View file

@ -1,15 +1,15 @@
# 品信息 # 品信息
## 功能 ## 功能
- 查询/创建品: - 查询/创建品:
[/api/goods/] [/api/goods/]
- 编辑/删除品: - 编辑/删除品:
[/api/goods/{id}/] [/api/goods/{id}/]
- 获取品编号: - 获取品编号:
[/api/goods/number/] [/api/goods/number/]
- 导出 - 导出
@ -24,13 +24,13 @@
## 其他接口 ## 其他接口
- 品分类选项: - 品分类选项:
[/api/goods_categories/options/] [/api/goods_categories/options/]
- 品单位选项: - 品单位选项:
[/api/goods_units/options/] [/api/goods_units/options/]
- 上传品图片: - 上传品图片:
[/api/goods_images/] [/api/goods_images/]
- 仓库选项: - 仓库选项:

View file

@ -1,12 +1,12 @@
# 品分类 # 品分类
## 功能 ## 功能
- 查询/创建品分类: - 查询/创建品分类:
[/api/goods_categories/] [/api/goods_categories/]
- 编辑/删除品分类: - 编辑/删除品分类:
[/api/goods_categories/{id}/] [/api/goods_categories/{id}/]
- 导出 - 导出

View file

@ -1,12 +1,12 @@
# 品单位 # 品单位
## 功能 ## 功能
- 查询/创建品单位: - 查询/创建品单位:
[/api/goods_units/] [/api/goods_units/]
- 编辑/删除品单位: - 编辑/删除品单位:
[/api/goods_units/{id}/] [/api/goods_units/{id}/]
- 导出 - 导出

View file

@ -24,4 +24,4 @@
## 补充说明 ## 补充说明
- 如果入库品开启批次控制, 则需要额外输入批次编号 - 如果入库品开启批次控制, 则需要额外输入批次编号

View file

@ -21,7 +21,7 @@
- 经手人选项: - 经手人选项:
[/api/users/options/]{is_active: true} [/api/users/options/]{is_active: true}
- 品选项: - 品选项:
[/api/inventories/options/]{page, warehouse, is_active: true} [/api/inventories/options/]{page, warehouse, is_active: true}
- 批次选项: - 批次选项:
@ -30,4 +30,4 @@
## 补充说明 ## 补充说明
- 如果盘点商品开启批次控制, 则需要额外输入该商品的批次信息 - 如果盘点产品开启批次控制, 则需要额外输入该产品的批次信息

View file

@ -21,7 +21,7 @@
- 经手人选项: - 经手人选项:
[/api/users/options/]{is_active: true} [/api/users/options/]{is_active: true}
- 品选项: - 品选项:
[/api/inventories/options/]{page, warehouse, is_active: true} [/api/inventories/options/]{page, warehouse, is_active: true}
- 批次选项: - 批次选项:

View file

@ -9,7 +9,7 @@
- 采购报表明细: - 采购报表明细:
[/api/purchase_reports/detials/] [/api/purchase_reports/detials/]
- 采购报表按品汇总: - 采购报表按品汇总:
[/api/purchase_reports/group_by_goods/] [/api/purchase_reports/group_by_goods/]

View file

@ -9,7 +9,7 @@
- 销售报表明细: - 销售报表明细:
[/api/sales_reports/detials/] [/api/sales_reports/detials/]
- 销售报表按品汇总: - 销售报表按品汇总:
[/api/sales_reports/group_by_goods/] [/api/sales_reports/group_by_goods/]

View file

@ -14,10 +14,10 @@
- 仓库 - 仓库
- 结算账户 - 结算账户
- 收支项目 - 收支项目
- 品管理 - 品管理
- 品分类 - 品分类
- 品单位 - 品单位
- 品信息 - 品信息
- 采购管理 - 采购管理
- 采购开单 - 采购开单
- 采购记录 - 采购记录

View file

@ -21,7 +21,7 @@
- 经手人选项: - 经手人选项:
[/api/users/options/]{is_active: true} [/api/users/options/]{is_active: true}
- 品选项: - 品选项:
[/api/inventories/options/]{page, warehouse, is_active: true} [/api/inventories/options/]{page, warehouse, is_active: true}
- 结算账户选项: - 结算账户选项:

View file

@ -24,7 +24,7 @@
- 经手人选项: - 经手人选项:
[/api/users/options/]{is_active: true} [/api/users/options/]{is_active: true}
- 品选项: - 品选项:
[/api/inventories/options/]{page, warehouse, is_active: true} [/api/inventories/options/]{page, warehouse, is_active: true}
- 结算账户选项: - 结算账户选项:

View file

@ -15,7 +15,7 @@
- 仓库选项: - 仓库选项:
[/api/warehouses/options/]{is_active: true} [/api/warehouses/options/]{is_active: true}
- 品选项: - 品选项:
[/api/goods/options/]{page, is_active: true} [/api/goods/options/]{page, is_active: true}
- 销售员选项: - 销售员选项:

View file

@ -21,7 +21,7 @@
- 经手人选项: - 经手人选项:
[/api/users/options/]{is_active: true} [/api/users/options/]{is_active: true}
- 品选项: - 品选项:
[/api/inventories/options/]{page, warehouse, is_active: true} [/api/inventories/options/]{page, warehouse, is_active: true}
- 结算账户选项: - 结算账户选项:

View file

@ -24,7 +24,7 @@
- 经手人选项: - 经手人选项:
[/api/users/options/]{is_active: true} [/api/users/options/]{is_active: true}
- 品选项: - 品选项:
[/api/inventories/options/]{page, warehouse, is_active: true} [/api/inventories/options/]{page, warehouse, is_active: true}
- 结算账户选项: - 结算账户选项:

View file

@ -15,7 +15,7 @@
- 出库任务提醒 - 出库任务提醒
[/api/stock_out_order_reminders/] [/api/stock_out_order_reminders/]
- 销售前十 - 销售前十
[/api/sales_hot_goods/]{start_date, end_date} [/api/sales_hot_goods/]{start_date, end_date}
- 销售走势 - 销售走势

View file

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<a-modal v-model="visible" :confirmLoading="loading" :maskClosable="false" @cancel="cancel" @ok="confirm"> <a-modal v-model="visible" :width="560" :confirmLoading="loading" :maskClosable="false" @cancel="cancel" @ok="confirm">
<div slot="title">{{form.id ? '编辑角色' : '新增角色' }}</div> <div slot="title">{{form.id ? '编辑角色' : '新增角色' }}</div>
<div> <div>
<a-form-model ref="form" :model="form" :rules="rules" :label-col="{ span: 4 }" :wrapper-col="{ span: 16 }"> <a-form-model ref="form" :model="form" :rules="rules" :label-col="{ span: 4 }" :wrapper-col="{ span: 16 }">
@ -11,7 +11,7 @@
<a-input v-model="form.remark" allowClear /> <a-input v-model="form.remark" allowClear />
</a-form-model-item> </a-form-model-item>
<a-checkbox-group v-model="form.permissions"> <!-- <a-checkbox-group v-model="form.permissions">
<a-descriptions size="small" title="权限" bordered> <a-descriptions size="small" title="权限" bordered>
<a-descriptions-item v-for="permissionTypeItem in $parent.permissionItems" :key="permissionTypeItem.id" :label="permissionTypeItem.name" :span="3"> <a-descriptions-item v-for="permissionTypeItem in $parent.permissionItems" :key="permissionTypeItem.id" :label="permissionTypeItem.name" :span="3">
<a-row> <a-row>
@ -21,6 +21,28 @@
</a-row> </a-row>
</a-descriptions-item> </a-descriptions-item>
</a-descriptions> </a-descriptions>
</a-checkbox-group> -->
<a-checkbox-group v-model="form.permissions">
<a-descriptions size="small" title="权限" bordered>
<a-descriptions-item
v-for="permissionTypeItem in $parent.permissionItems"
:key="permissionTypeItem.id"
:span="3"
>
<div slot="label" style="width: 90px">
<a-checkbox :value="permissionTypeItem.name" @change="checkAll">{{
permissionTypeItem.name
}}</a-checkbox>
</div>
<a-row>
<a-col v-for="item in permissionTypeItem.permission_items" :key="item.id" :span="8">
<a-checkbox :value="item.id">{{ item.name }}</a-checkbox>
</a-col>
</a-row>
</a-descriptions-item>
</a-descriptions>
</a-checkbox-group> </a-checkbox-group>
<!-- <a-form-model-item prop="permissions" label="角色权限"> <!-- <a-form-model-item prop="permissions" label="角色权限">
@ -70,6 +92,22 @@
this.$emit('cancel', false); this.$emit('cancel', false);
this.$refs.form.resetFields(); this.$refs.form.resetFields();
}, },
checkAll(event) {
for (let item of this.$parent.permissionItems) {
if (item.name == event.target.value) {
for (let permissionItem of item.permission_items) {
let index = this.form.permissions.indexOf(permissionItem.id);
if (event.target.checked && index == -1) {
this.form.permissions.push(permissionItem.id);
} else if (!event.target.checked && index != -1) {
this.form.permissions.splice(index, 1);
}
}
break;
}
}
},
}, },
} }
</script> </script>

View file

@ -12,6 +12,6 @@ def run(*args):
Supplier.objects.create(number='S001', name='默认供应商', team=team) Supplier.objects.create(number='S001', name='默认供应商', team=team)
warehouse = Warehouse.objects.create(number='W001', name='默认仓库', team=team) warehouse = Warehouse.objects.create(number='W001', name='默认仓库', team=team)
goods = Goods.objects.create(number='G001', name='品A', purchase_price=10, retail_price=20, goods = Goods.objects.create(number='G001', name='品A', purchase_price=10, retail_price=20,
level_price1=20, level_price2=20, level_price3=20, team=team) level_price1=20, level_price2=20, level_price3=20, team=team)
Inventory.objects.create(warehouse=warehouse, goods=goods, team=team) Inventory.objects.create(warehouse=warehouse, goods=goods, team=team)

View file

@ -6,7 +6,7 @@ PERMISSIONS = [
'name': '首页', 'name': '首页',
'permissions': [ 'permissions': [
{'name': '销售走势', 'code': 'sales_trend'}, {'name': '销售走势', 'code': 'sales_trend'},
{'name': '销售前十', 'code': 'sales_hot_goods'}, {'name': '销售前十', 'code': 'sales_hot_goods'},
{'name': '入库任务提醒', 'code': 'stock_in_reminder'}, {'name': '入库任务提醒', 'code': 'stock_in_reminder'},
{'name': '出库任务提醒', 'code': 'stock_out_reminder'}, {'name': '出库任务提醒', 'code': 'stock_out_reminder'},
{'name': '库存预警', 'code': 'inventory_warning'}, {'name': '库存预警', 'code': 'inventory_warning'},
@ -33,11 +33,11 @@ PERMISSIONS = [
], ],
}, },
{ {
'name': '品管理', 'name': '品管理',
'permissions': [ 'permissions': [
{'name': '品分类', 'code': 'goods_category'}, {'name': '品分类', 'code': 'goods_category'},
{'name': '品单位', 'code': 'goods_unit'}, {'name': '品单位', 'code': 'goods_unit'},
{'name': '品信息', 'code': 'goods'}, {'name': '品信息', 'code': 'goods'},
], ],
}, },
{ {