Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop

This commit is contained in:
shijing 2022-01-29 10:53:59 +08:00
commit d6915a9f19
33 changed files with 882 additions and 213 deletions

View File

@ -15,3 +15,12 @@ export function getProcessYield(data) {
data
})
}
//到岗统计
export function getatwork(data) {
return request({
url: '/srm/at_work/',
method: 'post',
data
})
}

View File

@ -418,12 +418,12 @@ export const asyncRoutes = [
meta: { title: '人员列表', icon: 'example', perms: ['user_manage'] }
},
{
path: 'personnel',
name: 'personnel',
component: () => import('@/views/personnel/user'),
meta: { title: '考勤列表', icon: 'example', perms: ['user_manage'] }
path: 'attendance',
name: 'attendance',
component: () => import('@/views/personnel/attendance'),
meta: { title: '考勤列表', icon: 'example', perms: ['attendance_manage'] }
} ,{
path: 'userupdate',
path: 'userupdate/:id',
name: 'userupdate',
component: () => import('@/views/personnel/userupdate'),
meta: { title: '人员信息详情', icon: 'employee', perms: ['employee_detail'] },

View File

@ -0,0 +1,182 @@
<template>
<div class="app-container">
<el-card>
<el-tabs type="border-card">
<el-tab-pane label="今日到岗">
<el-table
:data="userList.results"
style="width: 100%; margin-top: 6px"
highlight-current-row
row-key="id"
height="100"
stripe
border
v-el-height-adaptive-table="{ bottomOffset: 41 }"
>
<el-table-column type="index" width="50" label="序号" />
<el-table-column align="center" label="工号">
<template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column align="center" label="姓名">
<template slot-scope="scope">{{ scope.row.name }}</template>
</el-table-column>
<el-table-column align="center" label="到岗情况">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.is_atwork">在岗</el-tag>
<el-tag type="danger" v-else>离岗</el-tag>
</template>
</el-table-column>
<el-table-column align="header-center" label="部门">
<template v-if="scope.row.dept_" slot-scope="scope">{{
scope.row.dept_.name
}}</template>
</el-table-column>
</el-table>
<pagination
v-show="userList.count > 0"
:total="userList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/></el-tab-pane>
<el-tab-pane label="到岗统计">
<div class="container">
<span class="demonstration"></span>
<el-date-picker
v-model="value2"
type="month"
placeholder="选择年月">
</el-date-picker>
<el-button type="primary" @click="submit">主要按钮</el-button>
</div>
<el-table
:data="atworkList"
style="width: 100%; margin-top: 6px"
highlight-current-row
row-key="id"
height="680"
stripe
border
v-el-height-adaptive-table="{ bottomOffset: 41 }"
>
<el-table-column type="index" width="50" label="序号" />
<el-table-column align="center" label="工号">
<template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column align="center" label="姓名">
<template slot-scope="scope">{{ scope.row.name }}</template>
</el-table-column>
<el-table-column align="header-center" label="部门">
<template slot-scope="scope">{{ scope.row.dept_name }}</template>
</el-table-column>
<el-table-column align="center" label="出勤天数">
<template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</el-card>
</div>
</template>
<style>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
}
.avatar {
width: 100px;
height: 100px;
display: block;
}
</style>
<script>
import { getEmployeeList } from "@/api/employee";
import checkPermission from "@/utils/permission";
import {getatwork } from "@/api/srm";
import { upUrl, upHeaders } from "@/api/file";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
components: { Pagination, Treeselect },
data() {
return {
userList: { count: 0 },
atworkList: "",
value3:null,
value2:null,
listLoading: true,
listQuery: {
page: 1,
page_size: 20,
},
atworkDate:{year:null,month:null},
};
},
computed: {},
watch: {},
created() {
this.getList();
},
methods: {
checkPermission,
//今日到岗
getList() {
this.listQuery.fields='number,name,is_atwork,dept_';
getEmployeeList(this.listQuery).then((response) => {
if (response.data) {
this.userList = response.data;
}
});
},
//到岗统计
submit()
{
this.atworkDate.year=this.value2.getFullYear();
this.atworkDate.month=this.value2.getMonth()+1;
getatwork(this.atworkDate).then((response) => {
if (response.data) {
this.atworkList = response.data;
}
});
}
},
};
</script>

View File

@ -2,9 +2,7 @@
<div class="app-container">
<el-card>
<div slot="header" class="clearfix">
<span>用户</span>
</div>
<div>
<el-input
@ -39,7 +37,7 @@
height="100"
stripe
border
v-el-height-adaptive-table="{bottomOffset: 50}"
v-el-height-adaptive-table="{bottomOffset: 41}"
>
<el-table-column type="index" width="50" />
<el-table-column align="center" label="工号">
@ -179,8 +177,7 @@ export default {
},
created() {
this.getList();
this.getOrgAll();
this.getRoleAll();
},
methods: {
checkPermission,
@ -212,18 +209,7 @@ export default {
this.listLoading = false;
});
},
getOrgAll() {
this.treeLoding = true;
getOrgAll().then(response => {
this.orgData = genTree(response.data);
this.treeLoding = false;
});
},
getRoleAll() {
getRoleAll().then(response => {
this.roles = genTree(response.data);
});
},
resetFilter() {
this.listQuery = {
page: 1,

View File

@ -1,24 +1,56 @@
<template>
<div class="app-container">
<el-card>
<el-row>
<el-col :span="4">
<el-row :gutter="2">
<el-col :span="9" >
<el-card style="height:655px" >
<div>基础信息</div>
<el-form label-width="60px">
<el-form-item label="姓名">{{userDate.name}}</el-form-item>
<el-form-item label="账户">{{userDate.username}}</el-form-item>
<el-form-item label="角色">
<el-tag
v-for="(item, index) in userDate.roles_name"
:key="index"
style="margin:2px"
>{{item}}</el-tag>
<el-form ref="Form" :model="user" label-width="80px" label-position="right" :rules="rule1">
<el-form-item label="姓名" prop="name">
<el-input v-model="user.name" placeholder="姓名" />
</el-form-item>
<el-form-item label="账户" prop="username">
<el-input v-model="user.username" placeholder="账户" />
</el-form-item>
<el-form-item label="所属部门" prop="dept">
<el-cascader ref="cascader" :options="orgData" v-model="user.dept" :show-all-levels="false"></el-cascader>
</el-form-item>
<el-form-item label="角色" prop="roles">
<el-select v-model="user.roles" multiple placeholder="请选择" style="width:100%">
<el-option
v-for="item in roles"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="头像" prop="dept">
<el-upload
class="avatar-uploader"
:action="upUrl"
accept="image/jpeg, image/gif, image/png, image/bmp"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
:headers="upHeaders"
>
<img v-if="user.avatar" :src="user.avatar" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
</el-form-item>
<el-form-item size="large">
<el-button type="primary" @click="submitFormuser" >保存</el-button>
<el-button @click="goBack">返回</el-button>
</el-form-item>
<el-form-item label="手机">{{userDate.phone}}</el-form-item>
</el-form>
</el-card>
</el-col>
<el-col :span="20">
<el-col :span="15" >
<el-card style="height:655px" >
<div>详细信息</div>
<el-form ref="elForm" :model="formData" :rules="rules" size="medium" label-width="100px">
<el-row>
@ -31,6 +63,8 @@
:style="{width: '100%'}"
></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="学历" prop="qualification">
<el-input
v-model="formData.qualification"
@ -39,7 +73,7 @@
:style="{width: '100%'}"
></el-input>
</el-form-item>
</el-col>
@ -61,7 +95,8 @@
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="在职状态" prop="job_state">
<el-select
v-model="formData.job_state"
@ -77,6 +112,12 @@
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="出生年月" prop="birthday">
<el-date-picker
v-model="formData.birthday"
@ -87,12 +128,9 @@
>
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
</el-col>
<el-col :span="8">
<el-form-item label="身份证号" prop="id_number">
<el-input
v-model="formData.id_number"
@ -107,7 +145,7 @@
<el-row>
<el-col :span="6">
<el-col :span="8">
<el-form-item label="证件照" prop="photo">
<el-upload
:action="upUrl"
@ -123,9 +161,8 @@
</el-upload>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-col :span="8">
<el-form-item label="签名图片" prop="signature">
<el-upload :action="upUrl" :headers="upHeaders" accept=".png, .jpeg, .jpg" :before-upload="beforeUpload" class="avatar-uploader"
:show-file-list="false"
@ -139,9 +176,10 @@
<el-button @click="goBack">返回</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
</div>
</template>
<style>
@ -186,21 +224,27 @@
import { upUrl, upHeaders } from "@/api/file"
import { genSignature } from "@/api/util"
import { getUser } from "@/api/user";
import { getUser,updateUser } from "@/api/user";
import { genTree } from "@/utils"
import { getOrgAll } from "@/api/org"
import { getRoleAll } from "@/api/role"
import Treeselect from '@riophae/vue-treeselect'
import { getEmployee, updateEmployee } from "@/api/employee";
const defaultForm = {
user:{},
};
export default {
name: "Employeedetail",
components: {},
components: { Treeselect },
props: ["id"],
data() {
return {
upHeaders: upHeaders(),
upUrl: upUrl(),
formData: Object.assign({}, defaultForm),
userDate:[],
user:[],
orgData: [],
roles: [],
genderOptions: [
{ value: "", label: "" },
{ value: "", label: "" }
@ -209,6 +253,7 @@ export default {
{ value: 1, label: "在职" },
{ value: 2, label: "离职" }
],
deptvalue:null,
rules: {
ID_number: [
@ -226,7 +271,8 @@ export default {
created() {
this.formData.id = this.$route.params.id;
this.getDetail();
this.getOrgAll();
this.getRoleAll();
},
mounted() {},
methods: {
@ -235,13 +281,38 @@ export default {
this.formData = res.data;
getUser(res.data.user).then(Response => {
this.userDate=Response.data;
this.user=Response.data;
})
});
},
getOrgAll() {
getOrgAll().then(response => {
this.orgData = genTree(response.data);
});
},
getRoleAll() {
getRoleAll({page:0}).then(response => {
this.roles =response.data;
});
},
handleAvatarSuccess(res, file) {
this.user.avatar = res.data.path
},
beforeAvatarUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error("上传头像图片大小不能超过 2MB!");
}
return isLt2M;
},
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
beforeUpload(file) {
const isLt1M = file.size / 1024 / 1024 < 1;
if (!isLt1M) {
@ -277,6 +348,26 @@ export default {
},
goBack() {
this.$router.go(-1);
},
submitFormuser() {
this.$refs["Form"].validate(valid => {
if (!valid) return;
this.deptvalue= this.$refs['cascader'].getCheckedNodes();
if( this.deptvalue!="")
{
this.user.dept=this.deptvalue[0].value;
}
updateUser(this.user.id, this.user).then(res => {
this.$message({
message: "编辑成功",
type: "success",
});
});
});
}
}
};

View File

@ -88,9 +88,9 @@
</el-table-column>
<el-table-column align="header-center" label="部门">
<template
v-if="scope.row.dept_name != null"
v-if="scope.row.dept"
slot-scope="scope"
>{{ scope.row.dept_name }}</template>
>{{ scope.row.dept_.name }}</template>
</el-table-column>
<el-table-column label="创建日期">
<template slot-scope="scope">

View File

@ -2,7 +2,7 @@ from django.db.models import base
from rest_framework import urlpatterns
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from apps.develop.views import CleanDataView, UpdateCuttingView, UpdateEquipState, UpdateFIFOItem, UpdateLastTestResult, UpdateNeedToOrder, UpdateSpg
from apps.develop.views import CleanDataView, UpdateCuttingView, UpdateEquipState, UpdateFIFOItem, UpdateFIFONumber, UpdateLastTestResult, UpdateNeedToOrder, UpdateSpg
urlpatterns = [
path('cleandata/', CleanDataView.as_view()),
@ -12,6 +12,7 @@ urlpatterns = [
path('update_fifoitem/', UpdateFIFOItem.as_view()),
path('update_spg/', UpdateSpg.as_view()),
path('update_equip_state/', UpdateEquipState.as_view()),
path('update_need_to_order/', UpdateNeedToOrder.as_view())
path('update_need_to_order/', UpdateNeedToOrder.as_view()),
path('update_fifo_number/', UpdateFIFONumber.as_view())
]

View File

@ -105,4 +105,16 @@ class UpdateNeedToOrder(APIView):
permission_classes = [IsAdminUser]
def post(self, request):
WProduct.objects.exclude(to_order=None).update(need_to_order=True)
return Response()
class UpdateFIFONumber(APIView):
permission_classes = [IsAdminUser]
def post(self, request):
from utils.tools import ranstr
for i in FIFO.objects.all():
if i.type in [FIFO.FIFO_TYPE_DO_IN, FIFO.FIFO_TYPE_PUR_IN]:
i.number = 'RK'+ ranstr(7)
else:
i.number = 'CK' + ranstr(7)
i.save()
return Response()

View File

@ -10,6 +10,8 @@ from django.db.models.query import Prefetch
class EmployeeSerializer(DynamicFieldsSerializerMixin, ModelSerializer):
name = serializers.CharField(source='user.name', read_only=True)
dept_ = OrganizationSimpleSerializer(source='user.dept', read_only=True)
is_atwork = serializers.BooleanField(source='user.is_atwork', read_only=True)
last_check_time = serializers.DateTimeField(source='user.last_check_time', read_only=True)
class Meta:
model = Employee
exclude = ['face_data']

View File

@ -2,7 +2,4 @@ from django.apps import AppConfig
class InmConfig(AppConfig):
name = 'apps.inm'
verbose_name = '库存管理'
def ready(self):
import apps.inm.signals
verbose_name = '库存管理'

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.9 on 2022-01-27 07:47
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('pum', '0004_puorder_puorderitem'),
('inm', '0028_alter_fifoitem_files'),
]
operations = [
migrations.AddField(
model_name='fifo',
name='pu_order',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pum.puorder', verbose_name='关联采购订单'),
),
]

View File

@ -0,0 +1,31 @@
# Generated by Django 3.2.9 on 2022-01-28 01:43
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('pum', '0004_puorder_puorderitem'),
('inm', '0029_fifo_pu_order'),
]
operations = [
migrations.AddField(
model_name='fifo',
name='number',
field=models.CharField(default=1, max_length=100, verbose_name='记录编号'),
preserve_default=False,
),
migrations.AddField(
model_name='fifo',
name='vendor',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pum.vendor', verbose_name='供应商'),
),
migrations.AlterField(
model_name='fifoitemproduct',
name='fifoitem',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inm.fifoitem', verbose_name='关联出入库条目'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.9 on 2022-01-28 06:32
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('pum', '0004_puorder_puorderitem'),
('inm', '0030_auto_20220128_0943'),
]
operations = [
migrations.AddField(
model_name='fifoitem',
name='pu_order_item',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pum.puorderitem', verbose_name='关联采购订单条目'),
),
]

View File

@ -2,6 +2,7 @@ from django.db import models
from django.db.models.base import Model
import django.utils.timezone as timezone
from django.db.models.query import QuerySet
from apps.pum.models import PuOrder, PuOrderItem, Vendor
from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords
@ -72,12 +73,17 @@ class FIFO(CommonADModel):
(FIFO_TYPE_PUR_IN, '采购入库'),
(FIFO_TYPE_DO_IN, '生产入库')
)
number = models.CharField('记录编号', max_length=100)
type = models.IntegerField('出入库类型', default=1)
is_audited = models.BooleanField('是否审核', default=False)
auditor = models.ForeignKey(
User, verbose_name='审核人', on_delete=models.CASCADE, null=True, blank=True)
inout_date = models.DateField('出入库日期', null=True, blank=True)
remark = models.CharField('备注', max_length=1000, default='')
vendor = models.ForeignKey(Vendor, verbose_name='供应商',
on_delete=models.CASCADE, null=True, blank=True)
pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单',
null=True, blank=True, on_delete=models.CASCADE)
class FIFOItem(BaseModel):
@ -97,6 +103,8 @@ class FIFOItem(BaseModel):
subproduction_plan = models.ForeignKey(
SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, null=True, blank=True)
files = models.ManyToManyField(File, verbose_name='上传材料', blank=True)
pu_order_item = models.ForeignKey(PuOrderItem,
verbose_name='关联采购订单条目', null=True, blank=True, on_delete=models.CASCADE)
class IProduct(BaseModel):
@ -116,14 +124,17 @@ class IProduct(BaseModel):
class FIFOItemProduct(BaseModel):
"""
出入库产品
出入库记录具体产品
"""
fifoitem = models.ForeignKey(
FIFOItem, verbose_name='关联出入库具体产品', on_delete=models.CASCADE)
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True,
related_name='fifoitem_wproduct')
FIFOItem, verbose_name='关联出入库条目', on_delete=models.CASCADE)
wproduct = models.ForeignKey('wpm.wproduct',
on_delete=models.CASCADE, verbose_name='关联的动态产品',
db_constraint=False, null=True, blank=True,
related_name='fifoitem_wproduct')
number = models.CharField('物品编号', max_length=50)
material = models.ForeignKey(
Material, verbose_name='物料类型', on_delete=models.CASCADE)
iproduct = models.ForeignKey(
IProduct, verbose_name='关联库存产品', null=True, blank=True, on_delete=models.SET_NULL)
IProduct, verbose_name='关联库存产品',
null=True, blank=True, on_delete=models.SET_NULL)

View File

@ -2,6 +2,7 @@ from rest_framework import exceptions
from rest_framework import serializers
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse, Inventory
from apps.pum.models import PuOrder, Vendor
from apps.qm.models import TestRecord, TestRecordItem
from apps.sam.serializers import OrderSimpleSerializer
@ -10,6 +11,8 @@ from apps.system.serializers import FileSimpleSerializer, UserSimpleSerializer
from apps.mtm.serializers import MaterialSimpleSerializer
from django.db import transaction
from utils.mixins import DynamicFieldsSerializerMixin
from utils.tools import ranstr
from rest_framework.exceptions import ValidationError
@ -73,6 +76,28 @@ class FIFOListSerializer(serializers.ModelSerializer):
model = FIFO
fields = '__all__'
class FIFOItemCreateSerializer(serializers.ModelSerializer):
class Meta:
model = FIFOItem
fields = ['warehouse',
'material', 'batch', 'fifo', 'files', 'pu_order_item']
def create(self, validated_data):
fifo = validated_data['fifo']
pu_order_item = validated_data.get('pu_order_item', None)
if pu_order_item:
if fifo.pu_order != pu_order_item.pu_order:
raise ValidationError('项目与采购订单不一致')
validated_data['material']=pu_order_item.material
else:
if fifo.pu_order is not None:
raise ValidationError('非采购订单')
return super().create(validated_data)
class FIFOItemUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = FIFOItem
fields = ['warehouse', 'batch', 'files']
class FIFOItemSerializer(serializers.ModelSerializer):
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
@ -83,14 +108,14 @@ class FIFOItemSerializer(serializers.ModelSerializer):
fields = '__all__'
class IProductInPurSerializer(serializers.ModelSerializer):
class FIFOItemProductCreateSerializer(serializers.ModelSerializer):
class Meta:
model = IProduct
fields = ['number']
class FIFODetailInPurSerializer(serializers.ModelSerializer):
details = IProductInPurSerializer(many=True, required=False)
details = FIFOItemProductCreateSerializer(many=True, required=False)
class Meta:
model = FIFOItem
@ -101,41 +126,26 @@ class MaterialBatchQuerySerializer(serializers.Serializer):
warehouse = serializers.IntegerField(label="仓库ID", required=False)
materials = serializers.ListField(child=serializers.IntegerField(label="物料ID"), required=False)
class FIFOInPurSerializer(serializers.ModelSerializer):
class FIFOInOtherSerializer(serializers.ModelSerializer):
"""
采购入库序列化
其他入库序列化
"""
details = FIFODetailInPurSerializer(many=True)
details = FIFODetailInPurSerializer(many=True, required=False)
vendor = serializers.PrimaryKeyRelatedField(label='供应商ID',
queryset=Vendor.objects.all())
class Meta:
model = FIFO
fields = ['details']
fields = ['details', 'vendor']
def create(self, validated_data):
details = validated_data.pop('details')
if len(details) > 0:
pass
else:
raise serializers.ValidationError('没有入库内容')
# for i in details:
# # 校验批次
# try:
# if i['batch']:
# obj = MaterialBatch.objects.get(batch=i['batch'], material=i['material'])
# if obj.warehouse != validated_data['warehouse']:
# raise serializers.ValidationError('批次号{}在其他仓库已存在'.format(i['batch']))
# except:
# pass
# 创建采购入库
with transaction.atomic():
validated_data['type'] = FIFO.FIFO_TYPE_PUR_IN
obj = FIFO(**validated_data)
obj.save()
for i in details:
if 'details' in i:
i['number'] = 'RK' + ranstr(7)
p_details = i.pop('details')
if len(p_details) != i['count']:
raise serializers.ValidationError('数目对不上')
@ -148,19 +158,30 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
x['fifoitem'] = fifoitem
p_list0.append(FIFOItemProduct(**x))
FIFOItemProduct.objects.bulk_create(p_list0)
p_list = []
for x in p_details:
x['material'] = i['material']
x['warehouse'] = validated_data['warehouse']
x['batch'] = i['batch']
p_list.append(IProduct(**x))
IProduct.objects.bulk_create(p_list)
else:
i['fifo'] = obj
i['number'] = 'RK' + ranstr(7)
FIFOItem.objects.create(**i)
return obj
class FIFOInPurSerializer(serializers.ModelSerializer):
"""
采购入库序列化
"""
pu_order = serializers.PrimaryKeyRelatedField(label='采购订单ID',
queryset = PuOrder.objects.filter(is_audited=True))
class Meta:
model = FIFO
fields = ['pu_order']
def create(self, validated_data):
pu_order = validated_data['pu_order']
validated_data['vendor'] = pu_order.vendor
validated_data['number'] = 'RK' + ranstr(7)
obj = FIFO.objects.create(**validated_data)
return obj
class InmTestRecordItemCreateSerializer(serializers.ModelSerializer):
class Meta:

View File

@ -0,0 +1,75 @@
from rest_framework.exceptions import ValidationError
from apps.inm.models import FIFOItemProduct, IProduct, Inventory, MaterialBatch, FIFO, FIFOItem
class InmService:
@classmethod
def update_inm(cls, instance:FIFO, type:int=1):
"""
更新库存(正反)
"""
if instance.type in [FIFO.FIFO_TYPE_PUR_IN, FIFO.FIFO_TYPE_DO_IN]: # 采购入库, 生产入库
# 更新相关表
for i in FIFOItem.objects.filter(fifo=instance):
material = i.material
warehouse = i.warehouse
o1, _ = Inventory.objects.get_or_create(material=material, warehouse=warehouse, \
defaults={'material':material, 'warehouse':warehouse, 'count':0})
o1.count = o1.count + i.count
o1.save()
o2, _ = MaterialBatch.objects.get_or_create(material=material, warehouse=warehouse, batch=i.batch,\
defaults={'material':material, 'warehouse':warehouse, 'count':0, 'batch':i.batch})
o2.count = o2.count + i.count
o2.save()
material.count = material.count + i.count
material.save()
# 创建IProduct
ips2 = []
for m in FIFOItemProduct.objects.filter(fifoitem=i):
ip = {}
ip['warehouse'] = warehouse
ip['batch'] = i.batch
wp = m.wproduct
ip['wproduct'] = wp
ip['number'] = m.number
ip['material'] = m.material
ips2.append(IProduct(**ip))
IProduct.objects.bulk_create(ips2)
# 如果是采购入库更新采购订单表
if instance.type == FIFO.FIFO_TYPE_PUR_IN:
pur_order_item = i.pur_order_item
delivered_count = pur_order_item.delivered_count + i.count
if delivered_count > pur_order_item.count:
raise ValidationError('超出采购订单所需量')
pur_order_item.delivered_count = delivered_count
pur_order_item.save()
elif instance.type in [FIFO.FIFO_TYPE_DO_OUT, FIFO.FIFO_TYPE_SALE_OUT]: # 生产领料 销售出库
# 更新相关表
for i in FIFOItem.objects.filter(fifo=instance):
material = i.material
warehouse = i.warehouse
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
temp_count = o1.count - i.count
if temp_count < 0:
raise ValidationError('库存不足,操作失败')
o1.count = temp_count
o1.save()
o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=i.batch)
temp_count = o2.count - i.count
if temp_count < 0:
raise ValidationError('库存不足,操作失败')
o2.count = temp_count
o2.save()
temp_count = material.count - i.count
if temp_count < 0:
raise ValidationError('库存不足,操作失败')
material.count = temp_count
material.save()
# 删除IProduct
if instance.type == FIFO.FIFO_TYPE_DO_OUT:
# 生产领料的情况直接从IProduct中删除
numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True)
IProduct.objects.filter(number__in=numbers).delete()

View File

@ -1,58 +0,0 @@
from django.db.models.signals import post_save
from django.dispatch import receiver
from apps.inm.models import FIFOItemProduct, IProduct, Inventory, MaterialBatch, FIFO, FIFOItem
def update_inm(instance:FIFO, type:int=1):
"""
更新库存(正反)
"""
if instance.type in [FIFO.FIFO_TYPE_PUR_IN, FIFO.FIFO_TYPE_DO_IN]: # 采购入库, 生产入库
# 更新相关表
for i in FIFOItem.objects.filter(fifo=instance):
material = i.material
warehouse = i.warehouse
o1, _ = Inventory.objects.get_or_create(material=material, warehouse=warehouse, \
defaults={'material':material, 'warehouse':warehouse, 'count':0})
o1.count = o1.count + i.count
o1.save()
o2, _ = MaterialBatch.objects.get_or_create(material=material, warehouse=warehouse, batch=i.batch,\
defaults={'material':material, 'warehouse':warehouse, 'count':0, 'batch':i.batch})
o2.count = o2.count + i.count
o2.save()
material.count = material.count + i.count
material.save()
# 创建IProduct
ips2 = []
for m in FIFOItemProduct.objects.filter(fifoitem=i):
ip = {}
ip['warehouse'] = warehouse
ip['batch'] = i.batch
wp = m.wproduct
ip['wproduct'] = wp
ip['number'] = m.number
ip['material'] = m.material
ips2.append(IProduct(**ip))
IProduct.objects.bulk_create(ips2)
elif instance.type in [FIFO.FIFO_TYPE_DO_OUT, FIFO.FIFO_TYPE_SALE_OUT]: # 生产领料 销售出库
# 更新相关表
for i in FIFOItem.objects.filter(fifo=instance):
material = i.material
warehouse = i.warehouse
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
o1.count = o1.count - i.count
o1.save()
o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=i.batch)
o2.count = o2.count - i.count
o2.save()
material.count = material.count - i.count
material.save()
# 删除IProduct
if instance.type == FIFO.FIFO_TYPE_DO_OUT:
numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True)
IProduct.objects.filter(number__in=numbers).delete()

View File

@ -1,15 +1,15 @@
from rest_framework import serializers
from rest_framework import exceptions
from rest_framework.exceptions import APIException
from rest_framework.mixins import DestroyModelMixin, ListModelMixin, UpdateModelMixin
from rest_framework.exceptions import APIException, ValidationError
from rest_framework.mixins import DestroyModelMixin, ListModelMixin, UpdateModelMixin, CreateModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet
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, FIFOItemUpdateSerializer, FIFOListSerializer, IProductListSerializer, \
from apps.inm.serializers import FIFOInOtherSerializer, FIFOItemCreateSerializer, FIFOItemSerializer, FIFOInPurSerializer, FIFOItemUpdateSerializer, FIFOListSerializer, IProductListSerializer, \
InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, \
WareHouseCreateUpdateSerializer, InventorySerializer
from apps.inm.signals import update_inm
from apps.inm.services import InmService
from apps.qm.models import TestRecordItem
from apps.system.mixins import CreateUpdateModelAMixin
from rest_framework.decorators import action
@ -77,7 +77,7 @@ class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
return Response(MaterialBatchSerializer(instance=queryset, many=True).data)
class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet):
class FIFOItemViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet):
"""
出入库记录详情表
"""
@ -93,12 +93,27 @@ class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, Gener
def get_serializer_class(self):
if self.action == 'update':
return FIFOItemUpdateSerializer
elif self.action == 'create':
return FIFOItemCreateSerializer
return super().get_serializer_class()
def perform_destroy(self, instance):
if instance.fifo.is_audited:
raise APIException('该出入库记录已通过审核, 无法删除')
return super().perform_destroy(instance)
def create(self, request, *args, **kwargs):
obj = self.get_object()
if obj.fifo.is_audited:
raise ValidationError('该出入库记录已审核')
return super().create(request, *args, **kwargs)
def update(self, request, *args, **kwargs):
obj = self.get_object()
if obj.fifo.is_audited:
raise ValidationError('该出入库记录已审核')
return super().update(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
if obj.fifo.is_audited:
raise ValidationError('该出入库记录已审核')
return super().destroy(request, *args, **kwargs)
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=InmTestRecordCreateSerializer)
def test(self, request, pk=None):
@ -160,6 +175,17 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
serializer.is_valid(raise_exception=True)
serializer.save(create_by=request.user)
return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'},
serializer_class=FIFOInOtherSerializer)
def in_other(self, request, pk=None):
"""
其他入库
"""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save(create_by=request.user)
return Response()
@action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=serializers.Serializer)
def audit(self, request, pk=None):
@ -167,6 +193,8 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
审核通过
"""
obj = self.get_object()
if not FIFOItem.objects.filter(fifo=obj).exists():
raise ValidationError('出入库条目为空')
for i in FIFOItem.objects.filter(fifo=obj, need_test=True):
if not i.is_testok:
raise APIException('未检验通过, 不可审核')
@ -177,7 +205,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
obj.auditor = request.user
obj.inout_date = timezone.now() # 也是审核日期
obj.save()
update_inm(obj) # 更新库存
InmService.update_inm(obj) # 更新库存
return Response()

View File

@ -0,0 +1,53 @@
# Generated by Django 3.2.9 on 2022-01-27 07:47
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),
('mtm', '0044_subproduction_need_combtest'),
('pum', '0003_remove_vendor_material'),
]
operations = [
migrations.CreateModel(
name='PuOrder',
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=100, unique=True, 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='puorder_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='puorder_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
('vendor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pum.vendor', verbose_name='供应商')),
],
options={
'verbose_name': '采购订单',
'verbose_name_plural': '采购订单',
},
),
migrations.CreateModel(
name='PuOrderItem',
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='所需数量')),
('delivered_count', models.PositiveIntegerField(default=0, verbose_name='已到货数量')),
('delivery_date', models.DateField(verbose_name='截止到货日期')),
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='采购材料')),
('pu_order', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='item_pu_order', to='pum.puorder', verbose_name='关联采购订单')),
],
options={
'abstract': False,
},
),
]

View File

@ -5,7 +5,7 @@ from django.db.models.query import QuerySet
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords
from apps.mtm.models import Material
class Vendor(CommonAModel):
@ -23,4 +23,26 @@ class Vendor(CommonAModel):
verbose_name_plural = verbose_name
def __str__(self):
return self.name
return self.name
class PuOrder(CommonAModel):
"""
采购订单信息
"""
number = models.CharField('订单编号', max_length=100, unique=True)
vendor = models.ForeignKey(Vendor, verbose_name='供应商', on_delete=models.CASCADE)
is_audited = models.BooleanField('是否审核', default=False)
class Meta:
verbose_name = '采购订单'
verbose_name_plural = verbose_name
class PuOrderItem(BaseModel):
"""
采购具体项目
"""
material = models.ForeignKey(Material, verbose_name='采购材料', on_delete=models.CASCADE)
count = models.PositiveIntegerField('所需数量', default=0)
delivered_count = models.PositiveIntegerField('已到货数量', default=0)
delivery_date = models.DateField('截止到货日期')
pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单',
on_delete=models.CASCADE, null=True, blank=True, related_name='item_pu_order')

View File

@ -1,9 +1,47 @@
from rest_framework.serializers import ModelSerializer
from .models import Vendor
from rest_framework.serializers import ModelSerializer, ValidationError
from apps.mtm.serializers import MaterialSimpleSerializer
from .models import PuOrder, PuOrderItem, Vendor
class VendorSerializer(ModelSerializer):
class Meta:
model = Vendor
fields = '__all__'
class VendorSimpleSerializer(ModelSerializer):
class Meta:
model = Vendor
fields = ['id', 'name']
class PuOrderItemSerializer(ModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
class Meta:
model = PuOrderItem
fields = '__all__'
class PuOrderItemCreateSerializer(ModelSerializer):
class Meta:
model = PuOrderItem
fields = ['count', 'delivery_date', 'pu_order', 'material']
def validate(self, attrs):
pu_order = attrs['pu_order']
if pu_order.is_audited:
raise ValidationError('采购订单已审核')
return super().validate(attrs)
class PuOrderItemUpdateSerializer(ModelSerializer):
class Meta:
model = PuOrderItem
fields = ['count', 'delivery_date']
class PuOrderSerializer(ModelSerializer):
vendor_ = VendorSimpleSerializer(source='vendor', read_only=True)
items = PuOrderItemSerializer(source='item_pu_order', many=True, read_only=True)
class Meta:
model = PuOrder
fields = '__all__'
class PuOrderCreateUpdateSerializer(ModelSerializer):
class Meta:
model = PuOrder
fields = ['number', 'vendor']

View File

@ -1,11 +1,13 @@
from django.db.models import base
from rest_framework import urlpatterns
from apps.pum.views import VendorViewSet
from apps.pum.views import PuOrderItemViewSet, PuOrderViewSet, VendorViewSet
from django.urls import path, include
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('vendor', VendorViewSet, basename='vendor')
router.register('pu_order', PuOrderViewSet, basename='pu_order')
router.register('pu_order_item', PuOrderItemViewSet, basename='pu_order_item')
urlpatterns = [
path('', include(router.urls)),
]

View File

@ -1,11 +1,17 @@
from django.shortcuts import render
from numpy import delete
from rest_framework.viewsets import ModelViewSet
from apps.pum.models import Vendor
from apps.pum.serializers import VendorSerializer
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin
from rest_framework.viewsets import GenericViewSet
from apps.pum.models import PuOrder, PuOrderItem, Vendor
from apps.pum.serializers import PuOrderCreateUpdateSerializer, PuOrderItemCreateSerializer, PuOrderItemSerializer, PuOrderItemUpdateSerializer, PuOrderSerializer, VendorSerializer
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.exceptions import APIException, ValidationError
from rest_framework.decorators import action
from rest_framework import serializers
from rest_framework.response import Response
from rest_framework import status
# Create your views here.
class VendorViewSet(CreateUpdateModelAMixin, ModelViewSet):
"""
@ -19,3 +25,69 @@ class VendorViewSet(CreateUpdateModelAMixin, ModelViewSet):
filterset_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']
class PuOrderViewSet(CreateUpdateModelAMixin, ModelViewSet):
"""
采购订单-增删改查
"""
perms_map = {'get': '*', 'post': '*',
'put': '*', 'delete': '*'}
queryset = PuOrder.objects.select_related('vendor').\
prefetch_related('item_pu_order').all()
serializer_class = PuOrderSerializer
search_fields = ['number', 'vendor__name']
filterset_fields = ['vendor']
ordering = ['-create_time']
def get_serializer_class(self):
if self.action in ['create', 'update']:
return PuOrderCreateUpdateSerializer
return super().get_serializer_class()
def update(self, request, *args, **kwargs):
obj = self.get_object()
if obj.is_audited:
raise ValidationError('该采购订单已审核')
return super().update(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
if obj.is_audited:
raise ValidationError('该采购订单已审核')
return super().destroy(request, *args, **kwargs)
@action(methods=['post'], detail=True, perms_map={'post':'*'},
serializer_class=serializers.Serializer)
def audit(self, request, pk=None):
obj = self.get_object()
if obj.item_pu_order.exists() and not obj.is_audited:
obj.is_audited = True
obj.update_by = request.user
obj.save()
return Response()
return Response('订单状态有误', status=status.HTTP_400_BAD_REQUEST)
class PuOrderItemViewSet(CreateModelMixin, ListModelMixin, DestroyModelMixin, GenericViewSet):
"""
采购订单条目
"""
perms_map = {'get': '*', 'post': '*',
'put': '*', 'delete': '*'}
queryset = PuOrderItem.objects.select_related('material').all()
serializer_class = PuOrderItemSerializer
filterset_fields = ['pu_order', 'material']
ordering = ['-create_time']
def get_serializer_class(self):
if self.action == 'create':
return PuOrderItemCreateSerializer
elif self.action == 'update':
return PuOrderItemUpdateSerializer
return super().get_serializer_class()
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
if obj.pu_order.is_audited:
raise ValidationError('所属采购已审核')
return super().destroy(request, *args, **kwargs)

View File

@ -73,7 +73,7 @@ class TestRecord(CommonADModel):
remark = models.TextField('备注', default='')
class TestRecordItem(BaseModel):
class TestRecordItem(CommonADModel):
"""
记录表格字段值
"""

View File

@ -124,13 +124,17 @@ class TestRecordUpdateSerializer(serializers.ModelSerializer):
fields = ['is_testok', 'record_data']
def update(self, instance, validated_data):
# 获取更新人
update_by = self.context['request'].user
record_data = validated_data.pop('record_data')
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
instance.save(update_by=update_by)
for i in record_data:
tri = i['id']
tri.field_value = i['field_value']
if i['field_value'] != tri.field_value:
tri.field_value = i['field_value']
tri.update_by = update_by
tri.is_testok = i['is_testok']
tri.is_hidden = i['is_hidden']
tri.save()

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2022-01-27 07:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sam', '0011_order_need_mtest'),
]
operations = [
migrations.AlterField(
model_name='order',
name='delivery_date',
field=models.DateField(verbose_name='截止交货日期'),
),
]

View File

@ -58,7 +58,7 @@ class Order(CommonAModel):
count = models.PositiveIntegerField('所需数量', default=0)
planed_count = models.PositiveIntegerField('已排数量', default=0)
delivered_count = models.PositiveIntegerField('已交货数量', default=0)
delivery_date = models.DateField('交货日期')
delivery_date = models.DateField('截止交货日期')
need_mtest = models.BooleanField('是否需要军检', default=False)
class Meta:
verbose_name = '订单信息'

View File

@ -2,6 +2,7 @@ from rest_framework.mixins import ListModelMixin, DestroyModelMixin, CreateModel
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
from apps.inm.services import InmService
from apps.mtm.models import Material
from apps.sam.models import Sale, SaleProduct
from apps.sam.serializers_sale import SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer
@ -11,10 +12,11 @@ from rest_framework.decorators import action
from django.utils import timezone
from apps.system.mixins import CreateUpdateModelAMixin
from apps.inm.signals import update_inm
from rest_framework import serializers
from django.db.models import Count
from utils.tools import ranstr
class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
"""
销售记录
@ -71,6 +73,7 @@ class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, C
fifo.auditor = request.user
fifo.inout_date = timezone.now()
fifo.create_by = request.user
fifo.number = 'CK' + ranstr(7)
fifo.save()
# 创建出库条目
ips = IProduct.objects.filter(sale_iproduct__sale=obj)
@ -104,7 +107,7 @@ class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, C
WProduct.objects.filter(iproduct_wproduct__sale_iproduct__sale=obj).update(
act_state=WProduct.WPR_ACT_STATE_SELLED)
# 更新库存
update_inm(fifo)
InmService.update_inm(fifo)
# 变更审核状态
obj.is_audited = True
obj.save()

View File

@ -1,5 +1,6 @@
from django.shortcuts import render
from numpy import number
from rest_framework import serializers
from rest_framework.generics import ListAPIView, CreateAPIView
from rest_framework.views import APIView
@ -78,10 +79,11 @@ class AtWorkCountView(CreateAPIView):
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
ret = ClockRecord.objects.filter(
create_time__year = vdata['year'],
create_time__month = vdata['month']
update_time__year = vdata['year'],
update_time__month = vdata['month']
).values(
user_id = F('create_by'),
number = F('create_by__employee_user__number'),
username = F('create_by__username'),
name = F('create_by__name'),
dept_name = F('create_by__dept__name')).annotate(

View File

@ -4,8 +4,8 @@ from rest_framework.serializers import ModelSerializer
from apps.em.models import Equipment
from apps.em.serializers import EquipmentSimpleSerializer
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse
from apps.inm.signals import update_inm
from apps.inm.serializers import WareHouseSimpleSerializer
from apps.inm.services import InmService
from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer, RecordFormSimpleSerializer, StepSimpleSerializer
@ -21,6 +21,7 @@ from apps.wpm.models import Operation, OperationEquip, OperationMaterial, Operat
from django.db import transaction
from apps.sam.models import Order
from utils.mixins import DynamicFieldsSerializerMixin
from utils.tools import ranstr
class PickHalfSerializer(serializers.Serializer):
id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID')
@ -29,12 +30,14 @@ class PickHalfSerializer(serializers.Serializer):
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.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID',required=False, many=True)
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")
@ -58,7 +61,9 @@ class PickSerializer(serializers.Serializer):
# 创建出库记录
with transaction.atomic():
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT, inout_date=timezone.now(), create_by=self.context['request'].user)
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT,
inout_date=timezone.now(), create_by=self.context['request'].user,
number = 'CK' + ranstr(7))
for i in picks:
isLowLevel = False
# 更新出库详情
@ -123,7 +128,7 @@ class PickSerializer(serializers.Serializer):
# 更新库存
fifo.is_audited = True
fifo.save()
update_inm(fifo)
InmService.update_inm(fifo)
return fifo
class WMaterialListSerializer(serializers.ModelSerializer):

View File

@ -3,7 +3,7 @@ from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, \
ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from rest_framework.viewsets import GenericViewSet
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct
from apps.inm.signals import update_inm
from apps.inm.services import InmService
from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc
from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer
from apps.pm.models import SubProductionPlan, SubProductionProgress
@ -37,6 +37,8 @@ from django.utils import timezone
from rest_framework import status
from django.db.models import Count
from utils.tools import ranstr
# Create your views here.
@ -188,7 +190,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
raise exceptions.APIException('该产品当前状态不可检验')
savedict = dict(
create_by=self.request.user,
create_by=request.user,
wproduct=wproduct,
material=wproduct.material,
number=wproduct.number,
@ -219,6 +221,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
tri.test_record = tr
tri.form_field = i
tri.is_hidden = i.is_hidden
tri.create_by = request.user
tri.save()
return Response(TestRecordDetailSerializer(instance=tr).data)
@ -242,9 +245,10 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
'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)
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, number='RK'+ranstr(7))
# 创建入库明细
for i in wproducts_a:
spi = SubProductionPlan.objects.get(pk=i['subproduction_plan'])
@ -270,7 +274,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
ips.append(FIFOItemProduct(**ip))
FIFOItemProduct.objects.bulk_create(ips)
# 更新库存并修改半成品进行状态
update_inm(fifo)
InmService.update_inm(fifo)
for i in wproducts:
i.act_state = WProduct.WPR_ACT_STATE_INM
i.warehouse = warehouse
@ -320,7 +324,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
ips.append(FIFOItemProduct(**ip))
FIFOItemProduct.objects.bulk_create(ips)
# 更新库存并修改半成品进行状态
update_inm(fifo)
InmService.update_inm(fifo)
wproduct.act_state = WProduct.WPR_ACT_STATE_INM
wproduct.warehouse = warehouse
wproduct.save()

View File

@ -11,3 +11,4 @@ psutil==5.8.0
pillow==8.3.1
opencv-python==4.5.3.56
django-celery-results==2.2.0
numpy==1.21.2

View File

@ -1,3 +1,4 @@
import os
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser
@ -6,10 +7,9 @@ from PIL import Image
from django.conf import settings
from rest_framework import status
from datetime import datetime
import os
import uuid
import cv2
from server.settings import BASE_DIR
import numpy as np
# class UploadFileView(APIView):
# permission_classes = [IsAuthenticated]
@ -39,16 +39,33 @@ class GenSignature(APIView):
def post(self, request, *args, **kwargs):
path = (BASE_DIR + request.data['path']).replace('\\', '/')
image = cv2.imread(path, cv2.IMREAD_UNCHANGED)
size = image.shape
for i in range(size[0]):
for j in range(size[1]):
if image[i][j][0]>100 and image[i][j][1]>100 and image[i][j][2]>100:
image[i][j][3] = 0
else:
image[i][j][0],image[i][j][1],image[i][j][2] = 0,0,0
cv2.imwrite(path,image)
return Response(request.data, status=status.HTTP_200_OK)
try:
image = cv2.imread(path, cv2.IMREAD_UNCHANGED)
size = image.shape
width = size[0] # 宽度
height = size[1] # 高度
if size[2] != 4: # 判断
background = np.zeros((size[0], size[1], 4))
for yh in range(height):
for xw in range(width):
background[xw, yh, :3] = image[xw, yh]
background[xw, yh, 3] = 255
image = background
size = image.shape
for i in range(size[0]):
for j in range(size[1]):
if image[i][j][0]>100 and image[i][j][1]>100 and image[i][j][2]>100:
image[i][j][3] = 0
else:
image[i][j][0],image[i][j][1],image[i][j][2] = 0,0,0
ext = os.path.splitext(path)
new_path = ext[0] + '.png'
cv2.imwrite(new_path, image)
return Response({'path':new_path.replace(BASE_DIR, '')}, status=status.HTTP_200_OK)
except:
return Response('签名照处理失败,请重新上传',
status=status.HTTP_400_BAD_REQUEST)
import time
class UpdateDevelop(APIView):