flower_bs před 2 dny
rodič
revize
94d5bf769f

+ 3 - 3
bound/serializers.py

@@ -90,8 +90,8 @@ class BoundBatchPostSerializer(serializers.ModelSerializer):
     bound_month = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
     bound_batch_order = serializers.IntegerField(read_only=False, required=False, validators=[datasolve.data_validate])
 
-    warehouse_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
-    warehouse_name = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
+    warehouse_code = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
+    warehouse_name = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
     goods_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
     goods_desc = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
     goods_std =  serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
@@ -103,7 +103,7 @@ class BoundBatchPostSerializer(serializers.ModelSerializer):
 
     goods_total_weight = serializers.FloatField(read_only=False, required=False, validators=[datasolve.data_validate])
     openid = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
-    creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
+    creater = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
     is_delete = serializers.BooleanField(read_only=False, required=False)
 
     class Meta:

+ 29 - 0
erp/serializers.py

@@ -98,6 +98,35 @@ class MaterialDetailSerializer(serializers.ModelSerializer):
         """
         return f"{obj.bound_billId.number}"
 
+class MaterialDetailPOSTSerializer(serializers.ModelSerializer):
+    """
+    物料明细序列化器
+    """
+    
+    class Meta:
+        model = MaterialDetail
+        fields = [ 'production_batch', 'goods_code', 'goods_name', 'goods_std', 'goods_weight', 'plan_qty', 'goods_total_weight', 'goods_unit', 'note','is_delete']
+
+class InboundApplyPOSTSerializer(serializers.ModelSerializer):
+    """
+    生产入库申请序列化器
+    """
+    class Meta:
+        model = InboundBill
+        # fields = ['billId', 'number', 'type', 'date', 'department', 'warehouse', 'creater', 'note', 'totalCount','is_delete','audit_status']
+        fields = ['bound_status']
+    
+
+class OutboundApplyPOSTSerializer(serializers.ModelSerializer):
+    """
+    生产出库申请序列化器
+    """
+    class Meta:
+        model = OutboundBill
+        # fields = ['billId', 'number', 'type', 'date', 'department', 'warehouse', 'creater', 'note', 'totalCount','is_delete','audit_status']
+        fields = ['bound_status']
+ 
+
 class OutMaterialDetailSerializer(serializers.ModelSerializer):
     """
     物料明细序列化器

+ 4 - 0
erp/urls.py

@@ -25,18 +25,22 @@ urlpatterns = [
     path('inboundBills/', views.InboundBills.as_view({"get": "list"}),name="inboundBills"),
     re_path(r'^inboundBills/(?P<pk>\d+)/$', views.InboundBills.as_view({
         'get': 'retrieve',
+        'put': 'update_inbound',
         'delete': 'destroy',
     }), name="inboundBills_1"),
 
     path('outboundBills/', views.OutboundBills.as_view({"get": "list"}),name="outboutBills"),
     re_path(r'^outboundBills/(?P<pk>\d+)/$', views.OutboundBills.as_view({
         'get': 'retrieve',
+        'put': 'update_outbound',
+
         'delete': 'destroy',
     }), name="outboundBills_1"),
 
     path('materials/', views.Materials.as_view({"get": "list"}),name="Materials"),
     re_path(r'^materials/(?P<pk>\d+)/$', views.Materials.as_view({
         'get': 'retrieve',
+        'put': 'update_material',
 
     }), name="Materials_1"),
     path('materials/check/', views.Materials.as_view({

+ 52 - 1
erp/views.py

@@ -1974,6 +1974,22 @@ class InboundBills(viewsets.ModelViewSet):
         # qs.number = f"deleted_{qs.number}_{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}"
         # qs.save()
         return Response({'message': '删除成功'}, status=status.HTTP_200_OK)
+    
+    def update_inbound(self, request, *args, **kwargs):
+        id = self.get_project()
+        if id is None:
+            return Response({'message': '没找到数据', 'data': None, 'code': 400}, status=status.HTTP_200_OK)
+        else:
+            bill_obj = InboundBill.objects.filter(billId=id).first()
+            if bill_obj:
+                serializer = InboundApplyPOSTSerializer(bill_obj, data=request.data)
+                if serializer.is_valid():
+                    serializer.save()
+                    return Response({'message': '操作成功', 'data': serializer.data, 'code': 200}, status=status.HTTP_200_OK)
+                else:
+                    return Response({'message': '上传参数错误', 'data': None, 'code': 400}, status=status.HTTP_200_OK)
+            else:
+                return Response({'message': '数据不存在', 'data': None, 'code': 400}, status=status.HTTP_200_OK)
 
         
     
@@ -2045,6 +2061,23 @@ class OutboundBills(viewsets.ModelViewSet):
         # qs.number = f"deleted_{qs.number}_{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}"
         # qs.save()
         return Response({'message': '删除成功'}, status=status.HTTP_200_OK)
+    
+    def update_outbound(self, request, *args, **kwargs):
+        id = self.get_project()
+        if id is None:
+            return Response({'message': '没找到数据', 'data': None, 'code': 400}, status=status.HTTP_200_OK)
+        else:
+            bill_obj = OutboundBill.objects.filter(billId=id).first()
+            if bill_obj:
+                serializer = OutboundApplyPOSTSerializer(bill_obj, data=request.data)
+                if serializer.is_valid():
+                    serializer.save()
+                    return Response({'message': '操作成功', 'data': serializer.data, 'code': 200}, status=status.HTTP_200_OK)
+                else:
+                    return Response({'message': '上传参数错误', 'data': None, 'code': 400}, status=status.HTTP_200_OK)
+            else:
+                return Response({'message': '数据不存在', 'data': None, 'code': 400}, status=status.HTTP_200_OK)
+
         
 class Materials(viewsets.ModelViewSet):
     """
@@ -2080,11 +2113,29 @@ class Materials(viewsets.ModelViewSet):
             return MaterialDetail.objects.none()
 
     def get_serializer_class(self):
-        if self.action in ['retrieve', 'list']:
+        if self.action in ['retrieve', 'list','update']:
             return MaterialDetailSerializer
         else:
             return self.http_method_not_allowed(request=self.request)   
 
+    def update_material(self, request, *args, **kwargs):
+        id = request.data.get('id', None)
+        if id is None:
+            return Response({'message': '参数错误', 'data': None, 'code': 400}, status=status.HTTP_200_OK)
+        else:
+            material_obj = MaterialDetail.objects.filter(id=id).first()
+            if material_obj:
+                serializer = MaterialDetailPOSTSerializer(material_obj, data=request.data)
+                if serializer.is_valid():
+                    serializer.save()
+                    return Response({'message': '操作成功', 'data': serializer.data, 'code': 200}, status=status.HTTP_200_OK)
+                else:
+                    return Response({'message': '参数错误', 'data': None, 'code': 400}, status=status.HTTP_200_OK)
+            else:
+                return Response({'message': '数据不存在', 'data': None, 'code': 400}, status=status.HTTP_200_OK)        
+
+        
+
     def _check_status_operation(self, material_obj):
         return_data = {}
         return_data['status'] = material_obj.status

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
templates/dist/spa/css/15.3c7078c1.css


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 1
templates/dist/spa/css/15.65fea8cc.css


+ 1 - 0
templates/dist/spa/css/17.710ed6db.css

@@ -0,0 +1 @@
+.q-date__calendar-item--selected[data-v-63b04511]{transition:all 0.3s ease;background-color:#1976d2!important}.q-date__range[data-v-63b04511]{background-color:rgba(25,118,210,0.1)}.custom-title[data-v-63b04511]{font-size:0.9rem;font-weight:500}.custom-timeline[data-v-63b04511]{--q-timeline-color:#e0e0e0}.custom-node .q-timeline__dot[data-v-63b04511]{background:#485573!important;border:2px solid #5c6b8c!important}.custom-node .q-timeline__content[data-v-63b04511]{color:#485573}

+ 0 - 1
templates/dist/spa/css/17.865457f7.css

@@ -1 +0,0 @@
-.q-date__calendar-item--selected[data-v-ea0acd5e]{transition:all 0.3s ease;background-color:#1976d2!important}.q-date__range[data-v-ea0acd5e]{background-color:rgba(25,118,210,0.1)}.custom-title[data-v-ea0acd5e]{font-size:0.9rem;font-weight:500}.custom-timeline[data-v-ea0acd5e]{--q-timeline-color:#e0e0e0}.custom-node .q-timeline__dot[data-v-ea0acd5e]{background:#485573!important;border:2px solid #5c6b8c!important}.custom-node .q-timeline__content[data-v-ea0acd5e]{color:#485573}

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 1
templates/dist/spa/css/18.476963a1.css


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
templates/dist/spa/css/18.712d6cf2.css


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
templates/dist/spa/index.html


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 1
templates/dist/spa/js/15.0995ef23.js


binární
templates/dist/spa/js/15.0995ef23.js.gz


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
templates/dist/spa/js/15.12d0592b.js


binární
templates/dist/spa/js/15.12d0592b.js.gz


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
templates/dist/spa/js/17.a57993e2.js


binární
templates/dist/spa/js/17.a57993e2.js.gz


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 1
templates/dist/spa/js/17.f437c689.js


binární
templates/dist/spa/js/17.f437c689.js.gz


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 1
templates/dist/spa/js/18.48a2ffbb.js


binární
templates/dist/spa/js/18.48a2ffbb.js.gz


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
templates/dist/spa/js/18.d4d9a033.js


binární
templates/dist/spa/js/18.d4d9a033.js.gz


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
templates/dist/spa/js/app.432f6d7c.js


binární
templates/dist/spa/js/app.432f6d7c.js.gz


+ 52 - 10
templates/src/pages/erp/erpasn.vue

@@ -245,16 +245,36 @@
                 {{
                   formatStatusType(props.row.bound_status) ||
                   props.row.bound_status
-                }}</q-td
-              >
+                }}
+              </q-td>
             </template>
             <template v-else-if="props.row.id !== editid">
               <q-td key="bound_status" :props="props">
-                {{
-                  formatStatusType(props.row.bound_status) ||
-                  props.row.bound_status
-                }}</q-td
-              >
+                <div class="row justify-center items-center">
+                  <span>{{
+                    formatStatusType(props.row.bound_status) ||
+                    props.row.bound_status
+                  }}</span>
+                  <q-btn
+                    v-if="props.row.bound_status === 0"
+                    round
+                    flat
+                    push
+                    color="primary"
+                    icon="check"
+                    size="sm"
+                    @click="auditRow(props.row)"
+                    class="q-ml-sm"
+                  >
+                    <q-tooltip
+                      content-class="bg-amber text-black shadow-4"
+                      :offset="[10, 10]"
+                    >
+                      审核通过
+                    </q-tooltip>
+                  </q-btn>
+                </div>
+              </q-td>
             </template>
 
             <template v-if="!editMode">
@@ -623,7 +643,7 @@
 <router-view />
 
 <script>
-import { getauth, postauth, deleteauth } from 'boot/axios_request'
+import { getauth, putauth, postauth, deleteauth } from 'boot/axios_request'
 import moment from 'moment'
 import { date, exportFile, LocalStorage } from 'quasar'
 
@@ -849,6 +869,28 @@ export default {
     }
   },
   methods: {
+    // 新增审核行方法
+    auditRow (row) {
+      const _this = this
+      // 调用API更新审核状态
+      putauth(`wms/inboundBills/${row.billId}/`, {
+        bound_status: 1 // 设置为已审核状态
+      })
+        .then(res => {
+          _this.$q.notify({
+            message: '审核状态已更新',
+            color: 'positive'
+          })
+          // 刷新数据
+          _this.getSearchList()
+        })
+        .catch(err => {
+          _this.$q.notify({
+            message: err.detail || '更新审核状态失败',
+            color: 'negative'
+          })
+        })
+    },
     // 检查阶段处理
     // 获取过滤选项
     getFilterOptions (columnName) {
@@ -1322,8 +1364,8 @@ export default {
       this.getList({
         number__icontains: this.filter,
         document_date__range: this.date_range,
-        ...filterParams ,// 添加过滤条件
-        ...this.filterdata, // 添加其他过滤条件
+        ...filterParams, // 添加过滤条件
+        ...this.filterdata // 添加其他过滤条件
       })
     },
     getfileList () {

+ 94 - 28
templates/src/pages/erp/erpasnmaterial.vue

@@ -251,44 +251,44 @@
             <div class="row q-col-gutter-md">
               <q-input
                 class="col-6"
-                v-model="editForm.bound_number"
-                label="管理批次"
+                v-model="editForm.bound_billId_code"
+                label="主单号"
                 dense
                 outlined
                 readonly
               />
               <q-input
                 class="col-6"
-                v-model="editForm.goods_code"
-                label="存货编码"
+                v-model="editForm.production_batch"
+                label="erp批次"
                 dense
                 outlined
               />
               <q-input
                 class="col-6"
-                v-model="editForm.goods_desc"
-                label="存货名称"
+                v-model="editForm.goods_code"
+                label="存货编码"
                 dense
                 outlined
               />
               <q-input
                 class="col-6"
-                v-model="editForm.goods_unit"
-                label="单位"
+                v-model="editForm.goods_name"
+                label="存货名称"
                 dense
                 outlined
               />
               <q-input
                 class="col-6"
-                v-model="editForm.goods_qty"
+                v-model="editForm.plan_qty"
                 label="计划数目"
                 dense
                 outlined
               />
               <q-input
                 class="col-6"
-                v-model="editForm.goods_package"
-                label="包装"
+                v-model="editForm.goods_unit"
+                label="存货单位"
                 dense
                 outlined
               />
@@ -345,20 +345,20 @@
 
           <!-- 出入库信息组(只读) -->
           <q-card-section class="q-pa-none">
-            <div class="text-subtitle1 q-mb-md">出入库信息</div>
+            <div class="text-subtitle1 q-mb-md">ERP出入库信息</div>
             <div class="row q-col-gutter-md">
               <q-input
                 class="col-6"
-                v-model="editForm.goods_in_qty"
-                label="已入库/组盘数目"
+                v-model="editForm.bound_billId"
+                label="主单ID"
                 dense
                 outlined
                 readonly
               />
               <q-input
                 class="col-6"
-                v-model="editForm.goods_out_qty"
-                label="已出库/预定数目"
+                v-model="editForm.entryIds"
+                label="明细ID"
                 dense
                 outlined
                 readonly
@@ -376,8 +376,10 @@
         </q-card-section>
 
         <q-card-actions align="right">
-          <q-btn flat label="取消" color="primary" v-close-popup />
-          <q-btn flat label="保存" color="primary" @click="saveEditRow" />
+          <q-btn flat icon="delete" label="删除" color="negative" @click="deleteRow" />
+
+          <q-btn flat icon="cancel" label="取消"  v-close-popup />
+          <q-btn flat icon= "save" label="保存" color="primary" @click="saveEditRow" />
         </q-card-actions>
       </q-card>
     </q-dialog>
@@ -548,18 +550,23 @@ export default {
       },
       editForm: {
         id: '',
-        bound_number: '',
+        bound_billId_code: '',
+        bound_billId: '',
+        entryIds: '',
+        production_batch: '',
+        material_goods_code: '',
+        material_batch_order: '',
         goods_code: '',
-        goods_desc: '',
-        goods_qty: '',
-        goods_unit: '',
-        goods_package: '',
+        goods_name: '',
         goods_in_qty: '',
         goods_out_qty: '',
         goods_std: '',
-        status: '',
-        check_user: '',
-        create_time: '',
+        goods_weight: '',
+        plan_qty: '',
+        goods_total_weight: '',
+        goods_unit: '',
+        status: 0,
+        is_delete: 0,
         note: ''
       },
       activeSearchField: '',
@@ -577,6 +584,66 @@ export default {
     }
   },
   methods: {
+    // 新增删除行数据方法
+    deleteRow () {
+      const _this = this
+      // 确认删除操作
+      this.$q.dialog({
+        title: '确认删除',
+        message: `确定要删除批次 ${this.editForm.bound_billId_code} 吗?`,
+        cancel: true,
+        persistent: true
+      }).onOk(() => {
+        // 标记删除状态
+        _this.editForm.is_delete = 1
+
+        putauth(`wms/materials/${_this.editForm.id}/`, _this.editForm)
+          .then((res) => {
+            if (res.status_code !== 400) {
+              _this.$q.notify({
+                message: '删除成功',
+                color: 'positive',
+                icon: 'check_circle'
+              })
+              _this.editDialog = false
+              _this.getSearchList() // 刷新列表
+            } else {
+              _this.handleApiError(res, '删除')
+            }
+          })
+          .catch((error) => {
+            console.error('删除失败', error)
+            _this.$q.notify({
+              message: '删除失败:' + (error.response?.data?.detail || '服务器错误'),
+              color: 'negative',
+              icon: 'error'
+            })
+          })
+      })
+    },
+
+    // 提取的错误处理函数
+    handleApiError (res, action) {
+      const errorFieldMap = {
+        note: '备注',
+        check_user: '质检人'
+      }
+
+      let errorMessage = `${action}失败`
+      for (const key in res) {
+        if (Array.isArray(res[key]) && res[key].length > 0) {
+          const fieldLabel = errorFieldMap[key] || key
+          errorMessage = `${fieldLabel}: ${res[key].join(' ')}`
+          break
+        }
+      }
+
+      this.$q.notify({
+        message: errorMessage,
+        color: 'negative',
+        icon: 'warning'
+      })
+    },
     handleEditRow (row) {
       this.editForm = { ...row } // 复制当前行的数据到表单
       console.log(this.editForm)
@@ -584,7 +651,7 @@ export default {
     },
     saveEditRow () {
       const _this = this
-      putauth(`bound/batch/${_this.editForm.id}/`, _this.editForm) // 假设修改API是这样的
+      putauth(`wms/materials/${_this.editForm.id}/`, _this.editForm) // 假设修改API是这样的
         .then((res) => {
           _this.editDialog = false // 关闭对话框
 
@@ -764,7 +831,6 @@ export default {
         .then((res) => {
           if (res.code === 200) {
             this.$q.notify({ message: res.data.message, color: 'positive' })
-           
           } else {
             this.$q.notify({ message: res.data.message, color: 'negative' })
           }

+ 58 - 16
templates/src/pages/erp/erpdn.vue

@@ -240,21 +240,41 @@
               <q-td key="creater" :props="props">{{ props.row.creater }}</q-td>
             </template>
 
-            <template v-if="props.row.id === editid">
+<template v-if="props.row.id === editid">
               <q-td key="bound_status" :props="props">
                 {{
                   formatStatusType(props.row.bound_status) ||
                   props.row.bound_status
-                }}</q-td
-              >
+                }}
+              </q-td>
             </template>
             <template v-else-if="props.row.id !== editid">
               <q-td key="bound_status" :props="props">
-                {{
-                  formatStatusType(props.row.bound_status) ||
-                  props.row.bound_status
-                }}</q-td
-              >
+                <div class="row justify-center items-center">
+                  <span>{{
+                    formatStatusType(props.row.bound_status) ||
+                    props.row.bound_status
+                  }}</span>
+                  <q-btn
+                    v-if="props.row.bound_status === 0"
+                    round
+                    flat
+                    push
+                    color="primary"
+                    icon="check"
+                    size="sm"
+                    @click="auditRow(props.row)"
+                    class="q-ml-sm"
+                  >
+                    <q-tooltip
+                      content-class="bg-amber text-black shadow-4"
+                      :offset="[10, 10]"
+                    >
+                      审核通过
+                    </q-tooltip>
+                  </q-btn>
+                </div>
+              </q-td>
             </template>
 
             <template v-if="!editMode">
@@ -623,7 +643,7 @@
 <router-view />
 
 <script>
-import { getauth, postauth, deleteauth } from 'boot/axios_request'
+import { getauth, putauth, postauth, deleteauth } from 'boot/axios_request'
 import moment from 'moment'
 import { date, exportFile, LocalStorage } from 'quasar'
 
@@ -842,6 +862,28 @@ export default {
     }
   },
   methods: {
+     // 新增审核行方法
+    auditRow (row) {
+      const _this = this
+      // 调用API更新审核状态
+      putauth(`wms/outboundBills/${row.billId}/`, {
+        bound_status: 1 // 设置为已审核状态
+      })
+        .then(res => {
+          _this.$q.notify({
+            message: '审核状态已更新',
+            color: 'positive'
+          })
+          // 刷新数据
+          _this.getSearchList()
+        })
+        .catch(err => {
+          _this.$q.notify({
+            message: err.detail || '更新审核状态失败',
+            color: 'negative'
+          })
+        })
+    },
     // 检查阶段处理
     // 获取过滤选项
     getFilterOptions (columnName) {
@@ -1004,11 +1046,11 @@ export default {
           // }
           {
             type: 3,
-            icon: "save",
-            color: "green",
-            timestamp: "出库保存",
-            title: "销售出库",
-          },
+            icon: 'save',
+            color: 'green',
+            timestamp: '出库保存',
+            title: '销售出库'
+          }
         ],
         2: [
           // 生产领料申请 (类型2)
@@ -1025,7 +1067,7 @@ export default {
             color: 'orange',
             timestamp: '领料审核',
             title: '领料审核'
-          },
+          }
           // {
           //   type: 3,
           //   icon: 'save',
@@ -1049,7 +1091,7 @@ export default {
             color: 'orange',
             timestamp: '出库审核',
             title: '出库审核'
-          },
+          }
           // {
           //   type: 3,
           //   icon: "save",