diff --git a/hb_client/src/api/wpm.js b/hb_client/src/api/wpm.js
index 7e3462d..b274167 100644
--- a/hb_client/src/api/wpm.js
+++ b/hb_client/src/api/wpm.js
@@ -58,14 +58,6 @@ export function wproductTest(data) {
data
})
}
-//半成品复检
-export function wproductRetest(data) {
- return request({
- url: '/wpm/wproduct/retest/',
- method: 'post',
- data
- })
-}
//半成品入库
@@ -261,4 +253,14 @@ export function createTool(data) {
})
}
+//检验合格的半成品批量入库
+export function createputins(data) {
+ return request({
+ url: '/wpm/wproduct/putins/',
+ method: 'post',
+ data
+ })
+}
+
+
diff --git a/hb_client/src/router/index.js b/hb_client/src/router/index.js
index b739f6c..2aa5dcb 100644
--- a/hb_client/src/router/index.js
+++ b/hb_client/src/router/index.js
@@ -112,6 +112,14 @@ export const asyncRoutes = [
component: () => import('@/views/mtm/materialdo.vue'),
meta: { title: '绑定检查表', perms: ['vendor_manage'] },
hidden: true
+ }
+ ,
+ {
+ path: 'materialDetail/:id',
+ name: 'MaterialDetail',
+ component: () => import('@/views/mtm/materialDetail.vue'),
+ meta: { title: '物料详情', perms: ['vendor_manage'] },
+ hidden: true
},
{
path: 'process',
@@ -201,11 +209,19 @@ export const asyncRoutes = [
hidden: true
},
{
- path: 'need/:id',
+ path: 'need',
name: 'need',
component: () => import('@/views/wpm/need'),
meta: { title: '半成品检验', icon: 'example', perms: ['index_manage'] }
}
+ ,
+ {
+ path: 'productjy',
+ name: 'productjy',
+ component: () => import('@/views/wpm/productjy'),
+ meta: { title: '成品检验', icon: 'example', perms: ['index_manage'] }
+ }
+
]
},
{
diff --git a/hb_client/src/views/mtm/material.vue b/hb_client/src/views/mtm/material.vue
index afaf129..8d1677a 100644
--- a/hb_client/src/views/mtm/material.vue
+++ b/hb_client/src/views/mtm/material.vue
@@ -92,10 +92,16 @@
@click="handlebind(scope)"
>检查表
+
编辑
+ 详情
diff --git a/hb_client/src/views/mtm/productprocess.vue b/hb_client/src/views/mtm/productprocess.vue
index f874189..7dd2203 100644
--- a/hb_client/src/views/mtm/productprocess.vue
+++ b/hb_client/src/views/mtm/productprocess.vue
@@ -46,14 +46,14 @@
-
+
产品名称
{{products.name}}
-
+
产品编号
{{products.number}}
diff --git a/hb_client/src/views/wpm/need.vue b/hb_client/src/views/wpm/need.vue
index c0764b2..b5f6bf7 100644
--- a/hb_client/src/views/wpm/need.vue
+++ b/hb_client/src/views/wpm/need.vue
@@ -78,42 +78,49 @@
{{ scope.row.step_.name }}
+
+
+ 检验
+
+
+
+
+
+
+
+
+ 批量入库
+
-
- 检验
-
-
-
-
-
-
-
-
-
-
-
-
- {{ scope.row.material_.name }}
-
+ >
+
+
+
+
+ {{ scope.row.material_.name }}
+
{{ scope.row.number }}
@@ -183,250 +190,308 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hb_client/src/views/wpm/operationdo.vue b/hb_client/src/views/wpm/operationdo.vue
index fd974e0..30526a8 100644
--- a/hb_client/src/views/wpm/operationdo.vue
+++ b/hb_client/src/views/wpm/operationdo.vue
@@ -813,6 +813,7 @@ export default {
handlesubmit() {
submitOperation(this.id).then((res) => {
if (res.code >= 200) {
+ this.$router.push({name: "operation" })
this.$message.success("操作提交成功!");
}
});
diff --git a/hb_client/src/views/wpm/productjy.vue b/hb_client/src/views/wpm/productjy.vue
new file mode 100644
index 0000000..37fd54b
--- /dev/null
+++ b/hb_client/src/views/wpm/productjy.vue
@@ -0,0 +1,542 @@
+
+
+
+
+
+
+
+
+ {{ scope.row.material_.name }}
+
+
+
+ {{ scope.row.number }}
+
+
+
+ {{ actstate_[scope.row.act_state] }}
+
+
+
+
+ {{ scope.row.step_.name }}
+
+
+
+
+ 检验
+
+
+
+
+
+
+
+
+
+ 批量入库
+
+
+
+
+
+ {{ scope.row.material_.name }}
+
+
+
+ {{ scope.row.number }}
+
+
+
+ {{ actstate_[scope.row.act_state] }}
+
+
+
+
+ {{ scope.row.step_.name }}
+
+
+
+
+ 入库
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 检查合格
+ 检查不合格
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hb_client/src/views/wpm/worktask.vue b/hb_client/src/views/wpm/worktask.vue
index 598af64..12da811 100644
--- a/hb_client/src/views/wpm/worktask.vue
+++ b/hb_client/src/views/wpm/worktask.vue
@@ -162,17 +162,12 @@
scope.row.step_.name
}}
-
+
{{
actstate_[scope.row.act_state]
}}
-
-
- 已执行
- 待执行
-
-
+
{{
@@ -701,12 +696,13 @@ export default {
showPrise1: false,
actstate_: {
6: "待复检",
- 10: "生产中",
+ 10: "操作进行中",
20: "待检验",
30: "已合格",
40: "库存中",
50: "不合格",
60: "待成品检验",
+ 8:"操作准备中",
},
state_: {
0: "制定中",
diff --git a/hb_server/apps/inm/filters.py b/hb_server/apps/inm/filters.py
index c71c4fb..3f550a3 100644
--- a/hb_server/apps/inm/filters.py
+++ b/hb_server/apps/inm/filters.py
@@ -1,9 +1,17 @@
from django_filters import rest_framework as filters
from apps.mtm.models import Material
-from .models import MaterialBatch
+from .models import IProduct, MaterialBatch
class MbFilterSet(filters.FilterSet):
material = filters.ModelMultipleChoiceFilter(field_name="material", queryset=Material.objects.all())
class Meta:
model = MaterialBatch
- fields = ['material', 'warehouse']
\ No newline at end of file
+ fields = ['material', 'warehouse']
+
+
+class IProductFilterSet(filters.FilterSet):
+
+ order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order")
+ class Meta:
+ model = IProduct
+ fields = ['material', 'warehouse', 'batch', 'order']
\ No newline at end of file
diff --git a/hb_server/apps/inm/migrations/0020_iproduct_is_saled.py b/hb_server/apps/inm/migrations/0020_iproduct_is_saled.py
new file mode 100644
index 0000000..5ca02e7
--- /dev/null
+++ b/hb_server/apps/inm/migrations/0020_iproduct_is_saled.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.9 on 2021-12-06 01:58
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('inm', '0019_auto_20211201_1011'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='iproduct',
+ name='is_saled',
+ field=models.BooleanField(default=False, verbose_name='是否售出'),
+ ),
+ ]
diff --git a/hb_server/apps/inm/models.py b/hb_server/apps/inm/models.py
index 20d87dd..5c485d0 100644
--- a/hb_server/apps/inm/models.py
+++ b/hb_server/apps/inm/models.py
@@ -102,5 +102,6 @@ class IProduct(BaseModel):
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
batch = models.CharField('所属批次号', max_length=100, default='')
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True)
+ is_saled = models.BooleanField('是否售出', default=False)
diff --git a/hb_server/apps/inm/serializers.py b/hb_server/apps/inm/serializers.py
index 7f050fc..0a44f79 100644
--- a/hb_server/apps/inm/serializers.py
+++ b/hb_server/apps/inm/serializers.py
@@ -2,6 +2,7 @@ from rest_framework import serializers
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse,Inventory
from apps.qm.models import TestRecord, TestRecordItem
+from apps.sam.serializers import OrderSimpleSerializer
from apps.system.serializers import UserSimpleSerializer
from apps.mtm.serializers import MaterialSimpleSerializer
@@ -40,10 +41,18 @@ class MaterialBatchSerializer(serializers. ModelSerializer):
class IProductListSerializer(serializers.ModelSerializer):
material_= MaterialSimpleSerializer(source='material', read_only=True)
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
+ order_ = serializers.SerializerMethodField()
class Meta:
model = IProduct
fields = '__all__'
+ def get_order_(self, obj):
+ if obj.wproduct:
+ order = obj.wproduct.subproduction_plan.production_plan.order
+ if order:
+ return OrderSimpleSerializer(instance=order).data
+ return None
+
class FIFOListSerializer(serializers.ModelSerializer):
auditor_ = UserSimpleSerializer(source='auditor', read_only=True)
diff --git a/hb_server/apps/inm/views.py b/hb_server/apps/inm/views.py
index 6454c40..8f455e0 100644
--- a/hb_server/apps/inm/views.py
+++ b/hb_server/apps/inm/views.py
@@ -3,7 +3,7 @@ from rest_framework import serializers
from rest_framework.exceptions import APIException
from rest_framework.mixins import DestroyModelMixin, ListModelMixin, RetrieveModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet
-from apps.inm.filters import MbFilterSet
+from apps.inm.filters import IProductFilterSet, MbFilterSet
from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory
from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, IProductListSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
@@ -167,9 +167,9 @@ class IProductViewSet(ListModelMixin, GenericViewSet):
半成品库存表
"""
perms_map = {'*': '*'}
- queryset = IProduct.objects.select_related('material', 'warehouse').all()
+ queryset = IProduct.objects.select_related('material', 'warehouse', 'wproduct__subproduction_plan__production_plan__order').filter(is_saled=False)
serializer_class = IProductListSerializer
- filterset_fields = ['material', 'warehouse', 'batch']
+ filterset_class = IProductFilterSet
search_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']
\ No newline at end of file
diff --git a/hb_server/apps/sam/migrations/0005_auto_20211203_1501.py b/hb_server/apps/sam/migrations/0005_auto_20211203_1501.py
new file mode 100644
index 0000000..c819554
--- /dev/null
+++ b/hb_server/apps/sam/migrations/0005_auto_20211203_1501.py
@@ -0,0 +1,28 @@
+# Generated by Django 3.2.9 on 2021-12-03 07:01
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('sam', '0004_order_planed_count'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='order',
+ name='delivered_count',
+ field=models.PositiveIntegerField(default=0, verbose_name='交货数量'),
+ ),
+ migrations.AlterField(
+ model_name='order',
+ name='count',
+ field=models.PositiveIntegerField(default=0, verbose_name='所需数量'),
+ ),
+ migrations.AlterField(
+ model_name='order',
+ name='planed_count',
+ field=models.PositiveIntegerField(default=0, verbose_name='已排数量'),
+ ),
+ ]
diff --git a/hb_server/apps/sam/migrations/0006_auto_20211206_0958.py b/hb_server/apps/sam/migrations/0006_auto_20211206_0958.py
new file mode 100644
index 0000000..9b99454
--- /dev/null
+++ b/hb_server/apps/sam/migrations/0006_auto_20211206_0958.py
@@ -0,0 +1,65 @@
+# Generated by Django 3.2.9 on 2021-12-06 01:58
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('inm', '0020_iproduct_is_saled'),
+ ('mtm', '0041_alter_material_type'),
+ ('sam', '0005_auto_20211203_1501'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='order',
+ name='delivered_count',
+ field=models.PositiveIntegerField(default=0, verbose_name='已交货数量'),
+ ),
+ migrations.AlterField(
+ model_name='order',
+ name='number',
+ field=models.CharField(max_length=100, unique=True, verbose_name='订单编号'),
+ ),
+ migrations.CreateModel(
+ name='Sale',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
+ ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
+ ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
+ ('count', models.PositiveIntegerField(default=0, verbose_name='交货数量')),
+ ('is_audited', models.BooleanField(default=False, verbose_name='是否审核')),
+ ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sale_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
+ ('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sam.customer', verbose_name='客户')),
+ ('order', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sam.order', verbose_name='关联订单')),
+ ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='所需产品')),
+ ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sale_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
+ ],
+ options={
+ 'abstract': False,
+ },
+ ),
+ migrations.CreateModel(
+ name='SaleProduct',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
+ ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
+ ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
+ ('number', models.CharField(max_length=50, unique=True, verbose_name='物品编号')),
+ ('is_mtested', models.BooleanField(default=False, verbose_name='是否军检')),
+ ('is_mtestok', models.BooleanField(default=True, verbose_name='是否军检合格')),
+ ('iproduct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sale_iproduct', to='inm.iproduct', verbose_name='关联库存产品')),
+ ('sale', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sam.sale', verbose_name='关联销售记录')),
+ ],
+ options={
+ 'unique_together': {('sale', 'iproduct')},
+ },
+ ),
+ ]
diff --git a/hb_server/apps/sam/models.py b/hb_server/apps/sam/models.py
index 583fe87..631a472 100644
--- a/hb_server/apps/sam/models.py
+++ b/hb_server/apps/sam/models.py
@@ -1,4 +1,4 @@
-from apps.system.models import CommonAModel
+from apps.system.models import CommonADModel, CommonAModel
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.db.models.base import Model
@@ -58,16 +58,47 @@ class Order(CommonAModel):
"""
订单信息
"""
- number = models.CharField('订单编号', max_length=100)
+ number = models.CharField('订单编号', max_length=100, unique=True)
customer = models.ForeignKey(Customer, verbose_name='客户', on_delete=models.CASCADE)
contract = models.ForeignKey(Contract, verbose_name='所属合同', null=True, blank=True, on_delete=models.SET_NULL)
product = models.ForeignKey(Material, verbose_name='所需产品', on_delete=models.CASCADE)
- count = models.IntegerField('所需数量', default=0)
- planed_count = models.IntegerField('已排数量', default=0)
+ count = models.PositiveIntegerField('所需数量', default=0)
+ planed_count = models.PositiveIntegerField('已排数量', default=0)
+ delivered_count = models.PositiveIntegerField('已交货数量', default=0)
delivery_date = models.DateField('交货日期')
class Meta:
verbose_name = '订单信息'
verbose_name_plural = verbose_name
def __str__(self):
- return self.name
\ No newline at end of file
+ return self.name
+
+
+class Sale(CommonADModel):
+ """
+ 销售记录
+ """
+ customer = models.ForeignKey(Customer, verbose_name='客户', on_delete=models.CASCADE)
+ order = models.ForeignKey(Order, verbose_name='关联订单', on_delete=models.CASCADE, null=True, blank=True)
+ product = models.ForeignKey(Material, verbose_name='所需产品', on_delete=models.CASCADE)
+ count = models.PositiveIntegerField('交货数量', default=0)
+ is_audited = models.BooleanField('是否审核', default=False)
+
+
+class SaleProduct(BaseModel):
+ """
+ 具体产品
+ """
+ sale = models.ForeignKey(Sale, verbose_name='关联销售记录', on_delete=models.CASCADE)
+ number = models.CharField('物品编号', unique=True, max_length=50)
+ iproduct = models.ForeignKey('inm.iproduct', verbose_name='关联库存产品', on_delete=models.CASCADE, related_name='sale_iproduct')
+ is_mtested = models.BooleanField('是否军检', default=False)
+ is_mtestok = models.BooleanField('是否军检合格', default=True)
+
+ class Meta:
+ unique_together = (
+ ('sale','iproduct'), # 联合唯一
+ )
+
+
+
diff --git a/hb_server/apps/sam/serializers.py b/hb_server/apps/sam/serializers.py
index a4ed099..e4ce902 100644
--- a/hb_server/apps/sam/serializers.py
+++ b/hb_server/apps/sam/serializers.py
@@ -1,6 +1,9 @@
+from django.db import transaction
from rest_framework import serializers
-from .models import Contract, Customer, Order
+from apps.inm.models import IProduct
+
+from .models import Contract, Customer, Order, Sale, SaleProduct
from apps.mtm.serializers import MaterialSimpleSerializer
@@ -54,3 +57,40 @@ class OrderSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = '__all__'
+
+class SaleCreateSerializer(serializers.ModelSerializer):
+ iproducts = serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), many=True)
+ class Meta:
+ model = Sale
+ fields = ['customer', 'order', 'product', 'iproducts']
+
+ def validate(self, attrs):
+ order = attrs.get('order', None)
+ if order:
+ if order.customer:
+ attrs['customer'] = order.customer
+ attrs['product'] = order.product
+ return super().validate(attrs)
+
+ @transaction.atomic
+ def create(self, validated_data):
+ iproducts = validated_data.pop('iproducts')
+ validated_data['count'] = len(iproducts)
+ sale = Sale.objects.create(**validated_data)
+ i_l = []
+ for i in iproducts:
+ i_d ={}
+ i_d['sale'] = sale
+ i_d['number'] = i.number
+ i_d['iproduct'] = i
+ i_l.append(SaleProduct(**i_d))
+ SaleProduct.objects.bulk_create(i_l)
+ return sale
+
+class SaleListSerializer(serializers.ModelSerializer):
+ customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
+ order_ = OrderSimpleSerializer(source='order', read_only=True)
+ product_ = MaterialSimpleSerializer(source='product', read_only=True)
+ class Meta:
+ model = Sale
+ fields = '__all__'
diff --git a/hb_server/apps/sam/urls.py b/hb_server/apps/sam/urls.py
index 4aa607f..2418046 100644
--- a/hb_server/apps/sam/urls.py
+++ b/hb_server/apps/sam/urls.py
@@ -1,6 +1,6 @@
from django.db.models import base
from rest_framework import urlpatterns
-from apps.sam.views import CustomerViewSet,ContractViewSet,OrderViewSet
+from apps.sam.views import CustomerViewSet,ContractViewSet,OrderViewSet, SaleViewSet
from django.urls import path, include
from rest_framework.routers import DefaultRouter
@@ -8,6 +8,7 @@ router = DefaultRouter()
router.register('customer', CustomerViewSet, basename='customer')
router.register('contract', ContractViewSet, basename='contract')
router.register('order', OrderViewSet, basename='order')
+router.register('sale', SaleViewSet, basename='sale')
urlpatterns = [
path('', include(router.urls)),
diff --git a/hb_server/apps/sam/views.py b/hb_server/apps/sam/views.py
index 441e7fa..98bced6 100644
--- a/hb_server/apps/sam/views.py
+++ b/hb_server/apps/sam/views.py
@@ -1,6 +1,7 @@
-from apps.sam.serializers import ContractCreateUpdateSerializer, ContractSerializer, CustomerCreateUpdateSerializer, CustomerSerializer, OrderCreateUpdateSerializer, OrderSerializer
-from apps.sam.models import Contract, Customer, Order
-from rest_framework.viewsets import ModelViewSet
+from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin
+from apps.sam.serializers import ContractCreateUpdateSerializer, ContractSerializer, CustomerCreateUpdateSerializer, CustomerSerializer, OrderCreateUpdateSerializer, OrderSerializer, SaleCreateSerializer, SaleListSerializer
+from apps.sam.models import Contract, Customer, Order, Sale
+from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.system.mixins import CreateUpdateCustomMixin
from django.shortcuts import render
from rest_framework.decorators import action
@@ -57,7 +58,7 @@ class OrderViewSet(CreateUpdateCustomMixin, ModelViewSet):
def get_serializer_class(self):
if self.action in ['create', 'update']:
return OrderCreateUpdateSerializer
- return OrderSerializer
+ return super().get_serializer_class()
@action(methods=['get'], detail=False, perms_map={'get':'*'})
def toplan(self, request, pk=None):
@@ -67,4 +68,24 @@ class OrderViewSet(CreateUpdateCustomMixin, ModelViewSet):
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
- return Response(serializer.data)
\ No newline at end of file
+ return Response(serializer.data)
+
+
+class SaleViewSet(CreateUpdateCustomMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, GenericViewSet):
+ """
+ 销售记录
+ """
+ perms_map = {'*': '*'}
+ queryset = Sale.objects.select_related('customer', 'order', 'product').all()
+ serializer_class = SaleListSerializer
+ search_fields = ['customer__name', 'order__number']
+ filterset_fields = ['product', 'order', 'customer']
+ ordering_fields = ['create_time']
+ ordering = ['-create_time']
+
+ def get_serializer_class(self):
+ if self.action == 'create':
+ return SaleCreateSerializer
+ elif self.action == 'retrieve':
+ return SaleListSerializer
+ return super().get_serializer_class()
\ No newline at end of file
diff --git a/hb_server/apps/wf/migrations/0017_auto_20211203_1501.py b/hb_server/apps/wf/migrations/0017_auto_20211203_1501.py
new file mode 100644
index 0000000..f5b3766
--- /dev/null
+++ b/hb_server/apps/wf/migrations/0017_auto_20211203_1501.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.2.9 on 2021-12-03 07:01
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('wf', '0016_auto_20211024_2349'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='customfield',
+ name='field_type',
+ field=models.CharField(choices=[('string', '字符串'), ('int', '整型'), ('float', '浮点'), ('boolean', '布尔'), ('date', '日期'), ('datetime', '日期时间'), ('radio', '单选'), ('checkbox', '多选'), ('select', '单选下拉'), ('selects', '多选下拉'), ('textarea', '文本域'), ('selectuser', '单选用户'), ('selectusers', '多选用户'), ('file', '附件'), ('draw', '绘图')], help_text='5.字符串,10.整形,15.浮点型,20.布尔,25.日期,30.日期时间,35.单选框,40.多选框,45.下拉列表,50.多选下拉列表,55.文本域,60.用户名, 70.多选的用户名, 80.附件(只保存路径,多个使用逗号隔开)', max_length=50, verbose_name='类型'),
+ ),
+ migrations.AlterField(
+ model_name='ticket',
+ name='ticket_data',
+ field=models.JSONField(default=dict, help_text='工单自定义字段内容', verbose_name='工单数据'),
+ ),
+ ]
diff --git a/hb_server/apps/wf/models.py b/hb_server/apps/wf/models.py
index 4bc7d75..bc1597c 100644
--- a/hb_server/apps/wf/models.py
+++ b/hb_server/apps/wf/models.py
@@ -152,7 +152,8 @@ class CustomField(CommonAModel):
('textarea', '文本域'),
('selectuser', '单选用户'),
('selectusers', '多选用户'),
- ('file', '附件')
+ ('file', '附件'),
+ ('draw', '绘图')
)
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='所属工作流')
field_type = models.CharField('类型', max_length=50, choices=field_type_choices, help_text='5.字符串,10.整形,15.浮点型,20.布尔,25.日期,30.日期时间,35.单选框,40.多选框,45.下拉列表,50.多选下拉列表,55.文本域,60.用户名, 70.多选的用户名, 80.附件(只保存路径,多个使用逗号隔开)')
@@ -201,7 +202,7 @@ class Ticket(CommonBModel):
state = models.ForeignKey(State, on_delete=models.CASCADE, verbose_name='当前状态', related_name='ticket_state')
parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE, verbose_name='父工单')
parent_state = models.ForeignKey(State, null=True, blank=True, on_delete=models.CASCADE, verbose_name='父工单状态', related_name='ticket_parent_state')
- ticket_data = models.JSONField('工单数据', default=dict, help_text='工单所有字段内容')
+ ticket_data = models.JSONField('工单数据', default=dict, help_text='工单自定义字段内容')
in_add_node = models.BooleanField('加签状态中', default=False, help_text='是否处于加签状态下')
add_node_man = models.ForeignKey(User, verbose_name='加签人', on_delete=models.SET_NULL, null=True, blank=True, help_text='加签操作的人,工单当前处理人处理完成后会回到该处理人,当处于加签状态下才有效')
@@ -210,6 +211,19 @@ class Ticket(CommonBModel):
act_state = models.IntegerField('进行状态', default=1, help_text='当前工单的进行状态', choices=act_state_choices)
multi_all_person = models.JSONField('全部处理的结果', default=dict, blank=True, help_text='需要当前状态处理人全部处理时实际的处理结果,json格式')
+
+# class TicketCustomField(BaseModel):
+# """
+# 工单数据,自定义字段值
+# """
+# ticket = models.ForeignKey(Ticket, verbose_name='关联工单', on_delete=models.CASCADE)
+# form_field = models.ForeignKey(CustomField, verbose_name='关联字段', on_delete=models.SET_NULL, db_constraint=False, null=True, blank=True)
+# field_name = models.CharField('字段名', max_length=50)
+# field_key = models.CharField('字段标识', max_length=50)
+# field_type = models.CharField('字段类型', choices=CustomField.field_type_choices, max_length=50)
+# field_value = models.JSONField('录入值', default=dict, blank=True)
+# sort = models.IntegerField('排序号', default=1)
+
class TicketFlow(BaseModel):
"""
工单流转日志
diff --git a/hb_server/apps/wf/serializers.py b/hb_server/apps/wf/serializers.py
index 45369a5..e79f121 100644
--- a/hb_server/apps/wf/serializers.py
+++ b/hb_server/apps/wf/serializers.py
@@ -52,7 +52,7 @@ class TicketCreateSerializer(serializers.ModelSerializer):
transition = serializers.IntegerField(label='流转ID')
class Meta:
model=Ticket
- fields=['title','workflow','ticket_data', 'transition']
+ fields=['title','workflow', 'ticket_data', 'transition']
def create(self, validated_data):
validated_data.pop('transition')
diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py
index f7591de..b689a84 100644
--- a/hb_server/apps/wpm/serializers.py
+++ b/hb_server/apps/wpm/serializers.py
@@ -18,16 +18,17 @@ from django.db import transaction
class PickHalfSerializer(serializers.Serializer):
id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID')
- wproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID'),
- required=False) # 从半成品表里直接修改状态
+ wproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all())
+ , label='半成品ID', required=False) # 从半成品表里直接修改状态
+class PickHalfsSerializer(serializers.ListSerializer):
+ child = PickHalfSerializer()
class PickDetailSerializer(serializers.Serializer):
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
batch = serializers.CharField(label='物料批次', allow_blank=True)
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
pick_count = serializers.IntegerField(label="领料数量", required=False)
- iproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID'),
- required=False)
+ iproducts = serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID',required=False, many=True)
class PickSerializer(serializers.Serializer):
subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
@@ -172,8 +173,7 @@ class OperationCreateSerializer(serializers.Serializer):
"""
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
# subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
- wproducts = serializers.ListField(child=
- serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
+ wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label="半成品ID列表", required=False, many=True)
def validate(self, data):
# subproduction_plan = data['subproduction_plan']
@@ -209,8 +209,7 @@ class OperationUpdateSerializer(serializers.ModelSerializer):
class OperationInitSerializer(serializers.Serializer):
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
- wproducts = serializers.ListField(child=
- serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
+ wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label="半成品ID列表", required=False, many=True)
def validate(self, data):
# subproduction_plan = data['subproduction_plan']
@@ -273,8 +272,7 @@ class OperationWproductListSerializer(serializers.ModelSerializer):
class OperationSubmitSerializer(serializers.Serializer):
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
- wproducts = serializers.ListField(child=
- serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
+ wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label="半成品ID列表", required=False, many=True)
input = DoInputSerializer(many=True, required=False)
output = DoOutputSerializer(many=True, required=False)
forms = OperationRecordSerializer(many=True, required=False)
@@ -294,11 +292,6 @@ class WpmTestRecordCreateSerializer(serializers.ModelSerializer):
model = TestRecord
fields = ['form', 'record_data', 'is_testok', 'wproduct']
-class WproductPutInSerializer(serializers.Serializer):
- """
- 半成品入库序列化
- """
-
class WplanPutInSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
remark = serializers.CharField(label="入库备注", required =False)
@@ -307,6 +300,12 @@ class WproductPutInSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
remark = serializers.CharField(label="入库备注", required =False)
+class WproductPutInsSerializer(serializers.Serializer):
+ warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
+ wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID', many=True)
+ remark = serializers.CharField(label="入库备注", required =False)
+
+
class OperationEquipListSerializer(serializers.Serializer):
equip_ = EquipmentSimpleSerializer(source='equip', read_only=True)
class Meta:
diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py
index 39a7b08..9d3b427 100644
--- a/hb_server/apps/wpm/views.py
+++ b/hb_server/apps/wpm/views.py
@@ -18,7 +18,7 @@ from rest_framework.decorators import action
from apps.wpm.filters import WMaterialFilterSet
from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
-from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer
+from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickHalfsSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer, WproductPutInsSerializer
from rest_framework.response import Response
from django.db import transaction
from rest_framework import exceptions, serializers
@@ -27,6 +27,7 @@ from apps.wpm.services import WpmServies
from django.utils import timezone
from utils.tools import ranstr
from rest_framework import status
+from django.db.models import Count
# Create your views here.
class WPlanViewSet(ListModelMixin, GenericViewSet):
"""
@@ -40,7 +41,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
ordering_fields = []
ordering = ['-update_time']
- @action(methods=['post', 'get'], detail=True, perms_map={'post':'*', 'get':'*'}, serializer_class=PickHalfSerializer)
+ @action(methods=['post', 'get'], detail=True, perms_map={'post':'*', 'get':'*'}, serializer_class=PickHalfsSerializer)
@transaction.atomic
def pick_half(self, request, pk=None):
"""
@@ -55,7 +56,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
material__type=Material.MA_TYPE_HALFGOOD, subproduction_plan=sp).select_related('material')
return Response(SubProductionProgressSerializer(instance=spps, many=True).data)
elif request.method=='POST':
- serializer= PickHalfSerializer(data=request.data, many=True)
+ serializer= PickHalfsSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.data
first_step = Step.objects.get(pk=sp.steps[0]['id'])
@@ -84,8 +85,6 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
pw.material = i.material
pw.subproduction_plan = i.suproduction_plan
pw.save()
- else:
- raise exceptions.APIException('未选择任何玻璃')
sp.is_picked = True
sp.save()
@@ -245,49 +244,57 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
wproduct.save()
return Response()
+
+ @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WproductPutInsSerializer)
+ @transaction.atomic
+ def putins(self, request, pk=None):
+ """
+ 半成品批量入库
+ """
+ serializer= WproductPutInsSerializer(data=request.data)
+ serializer.is_valid(raise_exception=True)
+ vdata = serializer.data
+ wproducts = WProduct.objects.filter(pk__in=[x for x in vdata['wproducts']])
+ warehouse = WareHouse.objects.get(id=vdata['warehouse'])
+ for i in wproducts:
+ if i.act_state is not WProduct.WPR_ACT_STATE_OK:
+ raise exceptions.APIException('存在不可入库半成品')
+ # 聚合一下
+ wproducts_a = wproducts.values('subproduction_plan', 'material', 'subproduction_plan__number').annotate(total=Count('id'))
+ # 创建入库记录
+ remark = vdata.get('remark', '')
+ fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN,
+ is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark)
+ # 创建入库明细
+ for i in wproducts_a:
+ spi = SubProductionPlan.objects.get(pk=i['subproduction_plan'])
+ fifoitem = FIFOItem()
+ fifoitem.is_tested = True
+ fifoitem.is_testok = True
+ fifoitem.warehouse = warehouse
+ fifoitem.material = Material.objects.get(pk=i['material'])
+ fifoitem.count = i['total']
+ fifoitem.batch = spi.number
+ fifoitem.fifo = fifo
+ fifoitem.subproduction_plan = spi
+ fifoitem.save()
+
+ wproducts_items = wproducts.filter(subproduction_plan=i['subproduction_plan'], material=i['material'])
+ ips = []
+ for i in wproducts_items:
+ # 创建入库明细半成品
+ ip = {}
+ ip['fifoitem'] = fifoitem
+ ip['wproduct'] = i
+ ip['number'] = i.number
+ ip['material'] = i.material
+ ips.append(FIFOItemProduct(**ip))
+ FIFOItemProduct.objects.bulk_create(ips)
+ # 更新库存并修改半成品进行状态
+ update_inm(fifo)
+ wproducts.update(act_state=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user)
+ return Response()
- # @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestRecordCreateSerializer)
- # @transaction.atomic
- # def retest(self, request, pk=None):
- # """
- # 复检
- # """
- # serializer = WpmTestRecordCreateSerializer(data=request.data)
- # serializer.is_valid(raise_exception=True)
- # vdata = serializer.validated_data
- # record_data = vdata.pop('record_data')
- # wproduct = vdata['wproduct']
- # if wproduct.act_state != WProduct.WPR_ACT_STATE_TORETEST:
- # raise exceptions.APIException('该产品当前状态不可检验')
- # if 'is_testok' not in vdata:
- # raise exceptions.APIException('未填写检测结论')
-
- # obj = serializer.save(create_by = self.request.user,
- # material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan)
- # tris = []
- # for m in record_data: # 保存记录详情
- # form_field = m['form_field']
- # m['field_name'] = form_field.field_name
- # m['field_key'] = form_field.field_key
- # m['field_type'] = form_field.field_type
- # m['field_value'] = m['field_value']
- # m['sort'] = form_field.sort
- # m['need_judge'] = form_field.need_judge
- # m['is_testok'] = m['is_testok'] if 'is_testok' in m else None
- # m['test_record'] = obj
- # tris.append(TestRecordItem(**m))
- # TestRecordItem.objects.bulk_create(tris)
-
- # # 如果检测合格, 变更动态产品进行状态
-
- # if obj.is_testok:
- # wproduct.act_state = WProduct.WProduct.WPR_ACT_STATE_DOWAIT
- # wproduct.save()
- # else:# 如果不合格
- # wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK
- # wproduct.save()
- # return Response()
-
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer)
@transaction.atomic
def putin(self, request, pk=None):