diff --git a/hb_client/src/api/mtm.js b/hb_client/src/api/mtm.js
index 317cbcb..940a086 100644
--- a/hb_client/src/api/mtm.js
+++ b/hb_client/src/api/mtm.js
@@ -1,5 +1,6 @@
import request from '@/utils/request'
//物料
+
export function getMaterialList(query) {
return request({
url: '/mtm/material/',
@@ -34,6 +35,36 @@ export function deleteMaterial(id, data) {
data
})
}
+//产品分解
+export function getsubproducationList(query) {
+ return request({
+ url: '/mtm/subproducation/',
+ method: 'get',
+ params: query
+ })
+}
+export function createsubproducation(data) {
+ return request({
+ url: '/mtm/subproducation/',
+ method: 'post',
+ data
+ })
+}
+
+export function updatesubproducation(id, data) {
+ return request({
+ url: `/mtm/subproducation/${id}/`,
+ method: 'put',
+ data
+ })
+}
+export function deletesubproducation(id, data) {
+ return request({
+ url: `/mtm/subproducation/${id}/`,
+ method: 'delete',
+ data
+ })
+}
//工序
export function getProcessList(query) {
return request({
@@ -64,7 +95,16 @@ export function deleteProcess(id, data) {
})
}
//子工序
-export function getStepList(id) {
+export function getStepList(query) {
+ return request({
+ url: `/mtm/step/`,
+ method: 'get',
+ params: query
+ })
+}
+
+
+export function getStepLists(id) {
return request({
url: `/mtm/process/${id}/steps/`,
method: 'get'
diff --git a/hb_client/src/api/pm.js b/hb_client/src/api/pm.js
new file mode 100644
index 0000000..4f3365d
--- /dev/null
+++ b/hb_client/src/api/pm.js
@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+//生产排程
+export function getProductionplanList(query) {
+ return request({
+ url: 'pm/productionplan/',
+ method: 'get',
+ params: query
+ })
+}
+export function createProductionplan(data) {
+ return request({
+ url: 'pm/productionplan/',
+ method: 'post',
+ data
+ })
+}
+
diff --git a/hb_client/src/api/sam.js b/hb_client/src/api/sam.js
index 451942a..cc378cd 100644
--- a/hb_client/src/api/sam.js
+++ b/hb_client/src/api/sam.js
@@ -87,3 +87,10 @@ export function deleteOrder(id, data) {
data
})
}
+
+export function getordertoplan() {
+ return request({
+ url: '/sam/order/toplan/',
+ method: 'get',
+ })
+}
\ No newline at end of file
diff --git a/hb_client/src/router/index.js b/hb_client/src/router/index.js
index 7befda0..4b8ad23 100644
--- a/hb_client/src/router/index.js
+++ b/hb_client/src/router/index.js
@@ -130,6 +130,34 @@ export const asyncRoutes = [
meta: { title: '产品管理', icon: 'example', perms: ['vendor_manage'] }
},
]
+ }
+ ,
+ {
+ path: '/pm',
+ component: Layout,
+ redirect: '/pm/plan',
+ name: 'pm',
+ meta: { title: '生产管理', icon: 'example', perms: ['equipment_set'] },
+ children: [
+ {
+ path: 'plan',
+ name: 'plan',
+ component: () => import('@/views/pm/plan'),
+ meta: { title: '生产计划管理', icon: 'example', perms: ['index_manage'] }
+ },
+ {
+ path: 'resources',
+ name: 'resources',
+ component: () => import('@/views/pm/resources'),
+ meta: { title: '生产资源配置', icon: 'example', perms: ['index_manage'] }
+ },
+ {
+ path: 'testitem',
+ name: 'testitem',
+ component: () => import('@/views/pm/plan'),
+ meta: { title: '生产作业管理', icon: 'example', perms: ['index_manage'] }
+ }
+ ]
},
{
path: '/em',
@@ -233,6 +261,13 @@ export const asyncRoutes = [
name: 'warehouse',
component: () => import('@/views/inm/warehouse'),
meta: { title: '仓库', icon: 'example', perms: ['index_manage'] }
+ },
+ {
+ path: 'materialbatch/:id',
+ name: 'MaterialBatch',
+ component: () => import('@/views/inm/materialbatch'),
+ meta: { title: '仓库物料', perms: ['vendor_manage'] },
+ hidden: true
}
,
{
diff --git a/hb_client/src/views/inm/materialbatch.vue b/hb_client/src/views/inm/materialbatch.vue
new file mode 100644
index 0000000..939f3dc
--- /dev/null
+++ b/hb_client/src/views/inm/materialbatch.vue
@@ -0,0 +1,178 @@
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+
+ {{ scope.row.name }}
+
+
+
+ {{ scope.row.number }}
+
+
+ {{ scope.row.place }}
+
+
+ {{ scope.row.place }}
+
+
+ {{ scope.row.create_time }}
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
diff --git a/hb_client/src/views/inm/warehouse.vue b/hb_client/src/views/inm/warehouse.vue
index eb6e1e9..928ed5b 100644
--- a/hb_client/src/views/inm/warehouse.vue
+++ b/hb_client/src/views/inm/warehouse.vue
@@ -61,7 +61,11 @@
width="220px"
>
-
+ 查看物料
+
+
+
+
+
+ 过程记录表
+
+ 新增
+
+
+
+ {{ scope.row.name }}
+
+
+
+ 查看
+ 编辑
+ 删除
+
+
+
+
+
-
-
-
-
-
-
- 新增
-
-
-
-
- {{ scope.row.name }}
+
+
+
+
-
-
+
+ 取消
+ 确认
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 记录字段
+
+ 新增
+
+
+
+
+ {{ options_[scope.row.field_type] }}
+
+
+
+ {{ scope.row.field_name }}
+
+
+
+ {{ scope.row.field_key }}
+
+
+
+ {{ scope.row.field_choice }}
+
+
+
+
+
+
+ 编辑
-
-
- 编辑
- 删除
-
-
-
-
-
- 删除
+
+
-
-
-
-
-
-
-
-
-
- 取消
- 确认
-
-
-
-
-
-
-
- 新增
-
-
-
-
- {{ options_[scope.row.field_type] }}
-
-
-
- {{ scope.row.field_name }}
-
-
-
- {{ scope.row.field_key }}
-
-
- {{ scope.row.boolean_field_display }}
-
-
- {{ scope.row.field_choice }}
-
-
-
-
-
-
- 编辑
- 删除
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 取消
- 确认
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 添加
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 确认
+
+
+
+
+
-
-
\ No newline at end of file
diff --git a/hb_client/src/views/pm/resources.vue b/hb_client/src/views/pm/resources.vue
new file mode 100644
index 0000000..21af9ad
--- /dev/null
+++ b/hb_client/src/views/pm/resources.vue
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+ 合同订单列表
+
+
+
+
+
+
+ {{ scope.row.number }}
+
+
+ {{ scope.row.customer_.name }}
+
+
+ {{ scope.row.contract_.name }}
+
+
+ {{ scope.row.product_.name }}
+
+
+ {{ scope.row.product_.specification }}
+
+
+ {{ scope.row.count }}
+
+
+ {{ scope.row.planed_count }}
+
+
+
+ {{ scope.row.delivery_date }}
+
+
+ {{ scope.row.create_time }}
+
+
+
+
+ 排产
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 物料配置
+
+
+
+
+
+
+ {{ scope.row.number }}
+
+
+ {{ scope.row.customer_.name }}
+
+
+ {{ scope.row.contract_.name }}
+
+
+ {{ scope.row.product_.name }}
+
+
+ {{ scope.row.product_.specification }}
+
+
+ {{ scope.row.count }}
+
+
+ {{ scope.row.planed_count }}
+
+
+
+ {{ scope.row.delivery_date }}
+
+
+ {{ scope.row.create_time }}
+
+
+
+
+ 排产
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 设备配置
+
+
+
+
+
+
+ {{ scope.row.number }}
+
+
+ {{ scope.row.customer_.name }}
+
+
+ {{ scope.row.contract_.name }}
+
+
+ {{ scope.row.product_.name }}
+
+
+ {{ scope.row.product_.specification }}
+
+
+ {{ scope.row.count }}
+
+
+ {{ scope.row.planed_count }}
+
+
+
+ {{ scope.row.delivery_date }}
+
+
+ {{ scope.row.create_time }}
+
+
+
+
+ 排产
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hb_server/apps/mtm/migrations/0001_initial.py b/hb_server/apps/mtm/migrations/0001_initial.py
index d44f801..654ed11 100644
--- a/hb_server/apps/mtm/migrations/0001_initial.py
+++ b/hb_server/apps/mtm/migrations/0001_initial.py
@@ -94,24 +94,6 @@ class Migration(migrations.Migration):
'verbose_name_plural': '操作记录条目',
},
),
- migrations.CreateModel(
- name='ProductProcess',
- 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='删除标记')),
- ('sort', models.IntegerField(default=1, verbose_name='排序号')),
- ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='productprocess_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
- ('process', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.process', 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='productprocess_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
- ],
- options={
- 'verbose_name': '产品生产工序',
- 'verbose_name_plural': '产品生产工序',
- },
- ),
migrations.CreateModel(
name='OutputMaterial',
fields=[
diff --git a/hb_server/apps/mtm/migrations/0019_auto_20211012_0901.py b/hb_server/apps/mtm/migrations/0019_auto_20211012_0901.py
new file mode 100644
index 0000000..9cc24ed
--- /dev/null
+++ b/hb_server/apps/mtm/migrations/0019_auto_20211012_0901.py
@@ -0,0 +1,137 @@
+# Generated by Django 3.2.6 on 2021-10-12 01:01
+
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('mtm', '0018_material_count'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='SubProduction',
+ 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='删除标记')),
+ ('name', models.CharField(blank=True, max_length=50, null=True, verbose_name='命名')),
+ ('sort', models.IntegerField(default=1, verbose_name='排序号')),
+ ],
+ options={
+ 'verbose_name': '产品生产工序',
+ 'verbose_name_plural': '产品生产工序',
+ },
+ ),
+ migrations.RemoveField(
+ model_name='inputmaterial',
+ name='create_by',
+ ),
+ migrations.RemoveField(
+ model_name='inputmaterial',
+ name='process',
+ ),
+ migrations.RemoveField(
+ model_name='inputmaterial',
+ name='product',
+ ),
+ migrations.RemoveField(
+ model_name='inputmaterial',
+ name='update_by',
+ ),
+ migrations.RemoveField(
+ model_name='material',
+ name='processes',
+ ),
+ migrations.RemoveField(
+ model_name='outputmaterial',
+ name='create_by',
+ ),
+ migrations.RemoveField(
+ model_name='outputmaterial',
+ name='process',
+ ),
+ migrations.RemoveField(
+ model_name='outputmaterial',
+ name='product',
+ ),
+ migrations.RemoveField(
+ model_name='outputmaterial',
+ name='update_by',
+ ),
+ migrations.RemoveField(
+ model_name='techdoc',
+ name='create_by',
+ ),
+ migrations.RemoveField(
+ model_name='techdoc',
+ name='process',
+ ),
+ migrations.RemoveField(
+ model_name='techdoc',
+ name='product',
+ ),
+ migrations.RemoveField(
+ model_name='techdoc',
+ name='update_by',
+ ),
+ migrations.RemoveField(
+ model_name='usedstep',
+ name='create_by',
+ ),
+ migrations.RemoveField(
+ model_name='usedstep',
+ name='process',
+ ),
+ migrations.RemoveField(
+ model_name='usedstep',
+ name='product',
+ ),
+ migrations.RemoveField(
+ model_name='usedstep',
+ name='update_by',
+ ),
+ migrations.AddField(
+ model_name='usedstep',
+ name='remark',
+ field=models.TextField(blank=True, null=True, verbose_name='生产备注'),
+ ),
+ migrations.AlterField(
+ model_name='step',
+ name='process',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='step_process', to='mtm.process', verbose_name='所属工序'),
+ ),
+ migrations.AddField(
+ model_name='subproduction',
+ name='product',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='产品'),
+ ),
+ migrations.AddField(
+ model_name='inputmaterial',
+ name='subproduction',
+ field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='mtm.subproduction', verbose_name='关联生产分解'),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name='outputmaterial',
+ name='subproduction',
+ field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='mtm.subproduction', verbose_name='关联生产分解'),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name='techdoc',
+ name='subproduction',
+ field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='mtm.subproduction', verbose_name='关联生产分解'),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name='usedstep',
+ name='subproduction',
+ field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='mtm.subproduction', verbose_name='关联生产分解'),
+ preserve_default=False,
+ ),
+ ]
diff --git a/hb_server/apps/mtm/migrations/0020_auto_20211012_1657.py b/hb_server/apps/mtm/migrations/0020_auto_20211012_1657.py
new file mode 100644
index 0000000..2d80438
--- /dev/null
+++ b/hb_server/apps/mtm/migrations/0020_auto_20211012_1657.py
@@ -0,0 +1,26 @@
+# Generated by Django 3.2.6 on 2021-10-12 08:57
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('mtm', '0019_auto_20211012_0901'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='subproduction',
+ name='create_by',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='subproduction_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
+ ),
+ migrations.AddField(
+ model_name='subproduction',
+ name='update_by',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='subproduction_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
+ ),
+ ]
diff --git a/hb_server/apps/mtm/migrations/0021_auto_20211013_0856.py b/hb_server/apps/mtm/migrations/0021_auto_20211013_0856.py
new file mode 100644
index 0000000..21d8787
--- /dev/null
+++ b/hb_server/apps/mtm/migrations/0021_auto_20211013_0856.py
@@ -0,0 +1,56 @@
+# Generated by Django 3.2.6 on 2021-10-13 00:56
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('mtm', '0020_auto_20211012_1657'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='inputmaterial',
+ name='create_by',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='inputmaterial_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
+ ),
+ migrations.AddField(
+ model_name='inputmaterial',
+ name='update_by',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='inputmaterial_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
+ ),
+ migrations.AddField(
+ model_name='outputmaterial',
+ name='create_by',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='outputmaterial_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
+ ),
+ migrations.AddField(
+ model_name='outputmaterial',
+ name='update_by',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='outputmaterial_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
+ ),
+ migrations.AddField(
+ model_name='techdoc',
+ name='create_by',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='techdoc_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
+ ),
+ migrations.AddField(
+ model_name='techdoc',
+ name='update_by',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='techdoc_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
+ ),
+ migrations.AddField(
+ model_name='usedstep',
+ name='create_by',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='usedstep_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
+ ),
+ migrations.AddField(
+ model_name='usedstep',
+ name='update_by',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='usedstep_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
+ ),
+ ]
diff --git a/hb_server/apps/mtm/models.py b/hb_server/apps/mtm/models.py
index 36f2c04..82b39c7 100644
--- a/hb_server/apps/mtm/models.py
+++ b/hb_server/apps/mtm/models.py
@@ -16,9 +16,9 @@ class Material(CommonAModel):
(1, '成品'),
(2, '半成品'),
(3, '主要原料'),
- (4,'辅助原料') ,
+ (4, '辅助原料') ,
(5, '加工工具'),
- (6,'辅助工具')
+ (6, '辅助工具')
)
unit_choices =(
('块', '块'),
@@ -29,7 +29,6 @@ class Material(CommonAModel):
specification = models.CharField('型号', max_length=100, null=True, blank=True)
type = models.CharField('物料类型', choices= type_choices, max_length=20, default=1)
sort_str = models.CharField('排序字符', max_length=100, null=True, blank=True)
- processes = models.JSONField('工艺流程', default=list, blank=True, null=True)
unit = models.CharField('基准计量单位', choices=unit_choices, default='块', max_length=10)
count = models.IntegerField('物料总数', default=0)
class Meta:
@@ -60,7 +59,7 @@ class Step(CommonAModel):
"""
工序步骤
"""
- process = models.ForeignKey(Process, on_delete=models.CASCADE, verbose_name='所属工序')
+ process = models.ForeignKey(Process, on_delete=models.CASCADE, verbose_name='所属工序', related_name='step_process')
name = models.CharField('工序步骤名称', max_length=100)
number = models.CharField('步骤编号', max_length=100, null=True, blank=True)
instruction_content = models.TextField('相应操作指导', null=True, blank=True)
@@ -127,26 +126,28 @@ class RecordFormField(CommonAModel):
def __str__(self):
return self.field_key + '-' + self.field_name
-class ProductProcess(CommonAModel):
+
+
+class SubProduction(CommonAModel):
"""
- 产品生产工艺集
+ 产品生产分解
"""
+ name = models.CharField('命名', max_length=50, null=True, blank=True)
product = models.ForeignKey(Material, verbose_name='产品', on_delete=models.CASCADE)
- process = models.ForeignKey(Process, verbose_name='工序', on_delete=models.CASCADE)
sort = models.IntegerField('排序号', default=1)
class Meta:
verbose_name = '产品生产工序'
verbose_name_plural = verbose_name
+
class InputMaterial(CommonAModel):
"""
输入物料
"""
material = models.ForeignKey(Material, verbose_name='输入物料', on_delete=models.CASCADE, related_name='inputmaterial')
count = models.FloatField('消耗量', default=1)
- product = models.ForeignKey(Material, verbose_name='关联产品', on_delete=models.CASCADE, related_name='inputmaterial_product')
- process = models.ForeignKey(Process, verbose_name='关联工序', on_delete=models.CASCADE)
+ subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE)
sort = models.IntegerField('排序号', default=1)
class Meta:
@@ -161,8 +162,7 @@ class OutputMaterial(CommonAModel):
"""
material = models.ForeignKey(Material, verbose_name='输出物料', on_delete=models.CASCADE, related_name='outputmaterial')
count = models.FloatField('产出量', default=1)
- product = models.ForeignKey(Material, verbose_name='关联产品', on_delete=models.CASCADE, related_name='outputmaterial_product')
- process = models.ForeignKey(Process, verbose_name='关联工序', on_delete=models.CASCADE)
+ subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE)
sort = models.IntegerField('排序号', default=1)
class Meta:
@@ -171,11 +171,11 @@ class OutputMaterial(CommonAModel):
class UsedStep(CommonAModel):
"""
- 产品生产子工序
+ 涉及的生产子工序
"""
step = models.ForeignKey(Step, verbose_name='子工序', on_delete=models.CASCADE, related_name='usedsteps')
- product = models.ForeignKey(Material, verbose_name='关联产品', on_delete=models.CASCADE)
- process = models.ForeignKey(Process, verbose_name='关联工序', on_delete=models.CASCADE)
+ remark = models.TextField('生产备注', null=True, blank=True)
+ subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE)
class Meta:
verbose_name = '产品生产子工序'
@@ -188,8 +188,7 @@ class TechDoc(CommonAModel):
"""
name = models.CharField('名称', max_length=50)
file = models.ForeignKey(File, verbose_name='技术文件', on_delete=models.CASCADE)
- product = models.ForeignKey(Material, verbose_name='关联产品', on_delete=models.CASCADE)
- process = models.ForeignKey(Process, verbose_name='关联工序', on_delete=models.CASCADE)
+ subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE)
content = models.TextField('内容', null=True, blank=True)
class Meta:
diff --git a/hb_server/apps/mtm/serializers.py b/hb_server/apps/mtm/serializers.py
index 6a1dd98..7cd8fe5 100644
--- a/hb_server/apps/mtm/serializers.py
+++ b/hb_server/apps/mtm/serializers.py
@@ -1,12 +1,11 @@
from apps.em.serializers import EquipmentSimpleSerializer
from rest_framework import serializers
from rest_framework.exceptions import ParseError, ValidationError
-from .models import InputMaterial, Material, OutputMaterial, Process, ProductProcess, RecordForm, RecordFormField, Step, TechDoc, UsedStep
+from .models import InputMaterial, Material, OutputMaterial, Process, RecordForm, RecordFormField, Step, TechDoc, UsedStep, SubProduction
from apps.system.serializers import FileSimpleSerializer, OrganizationSimpleSerializer
class MaterialSerializer(serializers.ModelSerializer):
- processes = serializers.ListField(child=serializers.IntegerField(min_value=1))
class Meta:
model = Material
fields = '__all__'
@@ -18,7 +17,8 @@ class MaterialDetailSerializer(serializers.ModelSerializer):
fields = '__all__'
def get_processes_(self, obj):
- objs = Process.objects.filter(id__in=obj.processes).order_by('number')
+ steps = UsedStep.objects.filter(subproduction__product=obj).values_list('step', flat=True)
+ objs = Process.objects.filter(step_process__id__in=steps).distinct().order_by('number')
return ProcessSimpleSerializer(instance=objs, many=True).data
@@ -60,18 +60,11 @@ class StepDetailSerializer(serializers.ModelSerializer):
queryset = queryset.prefetch_related('equipments')
return queryset
-class ProductProcessListSerializer(serializers.ModelSerializer):
- process_ = ProcessSimpleSerializer(source='process', read_only=True)
- product_ = MaterialSimpleSerializer(source='product', read_only=True)
+class SubProductionSerializer(serializers.ModelSerializer):
class Meta:
- model = ProductProcess
+ model = SubProduction
fields = '__all__'
-class ProductProcessUpdateSerializer(serializers.ModelSerializer):
- class Meta:
- model = ProductProcess
- fields = ['sort']
-
class InputMaterialListSerializer(serializers.ModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
class Meta:
@@ -88,10 +81,10 @@ class OutputMaterialListSerializer(serializers.ModelSerializer):
class InputMaterialSerializer(serializers.ModelSerializer):
class Meta:
model = InputMaterial
- fields = ['count', 'sort', 'material', 'product', 'process']
+ fields = ['count', 'sort', 'material', 'subproduction']
def create(self, validated_data):
- if InputMaterial.objects.filter(material=validated_data['material'], product=validated_data['product'], process=validated_data['process'], is_deleted=False).exists():
+ if InputMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False).exists():
raise ValidationError('该物料已存在')
return super().create(validated_data)
@@ -103,10 +96,10 @@ class InputMaterialUpdateSerializer(serializers.ModelSerializer):
class OutputMaterialSerializer(serializers.ModelSerializer):
class Meta:
model = OutputMaterial
- fields = ['count', 'sort', 'material', 'product', 'process']
+ fields = ['count', 'sort', 'material', 'subproduction']
def create(self, validated_data):
- if OutputMaterial.objects.filter(material=validated_data['material'], product=validated_data['product'], process=validated_data['process'], is_deleted=False).exists():
+ if OutputMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False).exists():
raise ValidationError('该物料已存在')
return super().create(validated_data)
@@ -121,7 +114,15 @@ class UsedStepCreateSerializer(serializers.ModelSerializer):
"""
class Meta:
model = UsedStep
- fields = ['step', 'product', 'process']
+ fields = ['step', 'subproduction', 'remark']
+
+class UsedStepUpdateSerializer(serializers.ModelSerializer):
+ """
+ 产品生产子工序编辑
+ """
+ class Meta:
+ model = UsedStep
+ fields = ['remark']
class UsedStepListSerializer(serializers.ModelSerializer):
"""
@@ -198,7 +199,7 @@ class TechDocListSerializer(serializers.ModelSerializer):
class TechDocCreateSerializer(serializers.ModelSerializer):
class Meta:
model = TechDoc
- fields = ['file', 'product', 'process', 'name', 'content']
+ fields = ['file', 'subproduction', 'name', 'content']
class TechDocUpdateSerializer(serializers.ModelSerializer):
class Meta:
diff --git a/hb_server/apps/mtm/urls.py b/hb_server/apps/mtm/urls.py
index 7048bc5..5c18f0c 100644
--- a/hb_server/apps/mtm/urls.py
+++ b/hb_server/apps/mtm/urls.py
@@ -1,14 +1,14 @@
from django.db.models import base
from rest_framework import urlpatterns
-from apps.mtm.views import InputMaterialViewSet, MaterialViewSet, OutputMaterialViewSet, ProcessViewSet, RecordFormFieldViewSet, RecordFormViewSet, StepViewSet, TechDocViewSet, UsedStepViewSet
+from apps.mtm.views import InputMaterialViewSet, MaterialViewSet, OutputMaterialViewSet, ProcessViewSet, RecordFormFieldViewSet, RecordFormViewSet, StepViewSet, SubProductionViewSet, TechDocViewSet, UsedStepViewSet
from django.urls import path, include
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('material', MaterialViewSet, basename='material')
router.register('process', ProcessViewSet, basename='process')
-# router.register('productprocess', ProductProcessViewSet, basename='productprocess')
router.register('step', StepViewSet, basename='step')
+router.register('subproducation', SubProductionViewSet, basename='subproducation')
router.register('inputmaterial', InputMaterialViewSet, basename='inputmaterial')
router.register('outputmaterial', OutputMaterialViewSet, basename='outputmaterial')
router.register('usedstep', UsedStepViewSet, basename='usedstep')
diff --git a/hb_server/apps/mtm/views.py b/hb_server/apps/mtm/views.py
index 974bdba..0e1c44f 100644
--- a/hb_server/apps/mtm/views.py
+++ b/hb_server/apps/mtm/views.py
@@ -2,8 +2,8 @@ from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
-from apps.mtm.models import InputMaterial, Material, OutputMaterial, Process, ProductProcess, RecordForm, RecordFormField, Step, TechDoc, UsedStep
-from apps.mtm.serializers import InputMaterialListSerializer, InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OutputMaterialListSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProductProcessListSerializer, ProductProcessUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer
+from apps.mtm.models import InputMaterial, Material, OutputMaterial, Process, RecordForm, RecordFormField, Step, TechDoc, UsedStep, SubProduction
+from apps.mtm.serializers import InputMaterialListSerializer, InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OutputMaterialListSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, SubProductionSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer, UsedStepUpdateSerializer
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action
from rest_framework.response import Response
@@ -30,15 +30,6 @@ class MaterialViewSet(PageOrNot, CreateUpdateModelAMixin, ModelViewSet):
return MaterialDetailSerializer
return MaterialSerializer
- # @action(methods=['get'], detail=True, perms_map={'get':'*'}, pagination_class=None, serializer_class=MaterialSimpleSerializer)
- # def processes(self, request, pk=None):
- # """
- # 产品生产工艺流程
- # """
- # material = self.get_object()
- # serializer = self.serializer_class(instance=Process.objects.filter(id__in=material.processes), many=True)
- # return Response(serializer.data)
-
class ProcessViewSet(PageOrNot, CreateUpdateModelAMixin, ModelViewSet):
"""
@@ -62,11 +53,11 @@ class ProcessViewSet(PageOrNot, CreateUpdateModelAMixin, ModelViewSet):
serializer = self.serializer_class(instance=Step.objects.prefetch_related('equipments').filter(process=process, is_deleted=False), many=True)
return Response(serializer.data)
-class StepViewSet(OptimizationMixin, CreateUpdateModelAMixin, CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet):
+class StepViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet):
"""
子工序-增删改查
"""
- perms_map = {'*':'process_update'}
+ perms_map = {'*':'*'}
queryset = Step.objects.all()
serializer_class = StepSerializer
search_fields = ['name', 'number']
@@ -78,20 +69,16 @@ class StepViewSet(OptimizationMixin, CreateUpdateModelAMixin, CreateModelMixin,
return StepDetailSerializer
return StepSerializer
-# class ProductProcessViewSet(PageOrNot, CreateModelMixin, UpdateModelMixin, ListModelMixin, DestroyModelMixin, GenericViewSet):
-# """
-# 产品生产工艺流程增删改查
-# """
-# perms_map={'*':'*'}
-# queryset = ProductProcess.objects.select_related('process', 'product').all()
-# filterset_fields = ['process', 'product']
-# serializer_class = ProductProcessListSerializer
-# ordering = ['sort']
-
-# def get_serializer_class(self):
-# if self.action == 'update':
-# return ProductProcessUpdateSerializer
-# return super().get_serializer_class()
+class SubProductionViewSet(CreateUpdateModelAMixin, ModelViewSet):
+ """
+ 产品生产分解增删改查
+ """
+ perms_map={'*':'*'}
+ queryset = SubProduction.objects.all()
+ filterset_fields = ['product']
+ search_fields = ['name']
+ serializer_class = SubProductionSerializer
+ ordering = ['sort']
class InputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet):
"""
@@ -100,7 +87,7 @@ class InputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet):
perms_map = {'*':'*'}
queryset = InputMaterial.objects.select_related('material').all()
serializer_class = InputMaterialSerializer
- filterset_fields = ['process', 'product']
+ filterset_fields = ['subproduction']
ordering = ['sort', '-create_time']
def get_serializer_class(self):
@@ -117,7 +104,7 @@ class OutputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet):
perms_map = {'*':'*'}
queryset = OutputMaterial.objects.select_related('material').all()
serializer_class = OutputMaterialSerializer
- filterset_fields = ['process', 'product']
+ filterset_fields = ['subproduction']
ordering = ['sort', '-create_time']
def get_serializer_class(self):
@@ -127,18 +114,20 @@ class OutputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet):
return OutputMaterialUpdateSerializer
return OutputMaterialSerializer
-class UsedStepViewSet(OptimizationMixin, CreateUpdateModelAMixin, CreateModelMixin, DestroyModelMixin, ListModelMixin, GenericViewSet):
+class UsedStepViewSet(OptimizationMixin, CreateModelMixin, DestroyModelMixin, ListModelMixin, UpdateModelMixin, GenericViewSet):
"""
产品生产子工序表
"""
perms_map = {'*':'*'}
queryset = UsedStep.objects.all()
- filterset_fields = ['process', 'product', 'step']
+ filterset_fields = ['subproduction', 'step']
ordering = ['step__sort', '-step__create_time']
def get_serializer_class(self):
if self.action =='create':
return UsedStepCreateSerializer
+ elif self.action == 'update':
+ return UsedStepUpdateSerializer
return UsedStepListSerializer
class RecordFormViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet):
@@ -189,7 +178,7 @@ class TechDocViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet):
"""
perms_map = {'*':'*'}
queryset = TechDoc.objects.select_related('file').all()
- filterset_fields = ['process', 'product']
+ filterset_fields = ['subproduction']
search_fields = ['name']
ordering = ['-id']
diff --git a/hb_server/apps/pm/views.py b/hb_server/apps/pm/views.py
index 25509dc..a0d28fa 100644
--- a/hb_server/apps/pm/views.py
+++ b/hb_server/apps/pm/views.py
@@ -1,3 +1,4 @@
+from rest_framework.views import APIView
from apps.system.mixins import CreateUpdateModelAMixin
from apps.pm.serializers import ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer
from rest_framework.mixins import CreateModelMixin, ListModelMixin
@@ -49,4 +50,7 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
raise APIException('排产数量错误')
instance = serializer.save(create_by=request.user, product=order.product)
updateOrderPlanedCount(instance.order)
- return Response()
\ No newline at end of file
+ return Response()
+
+class ResourceCalculate(APIView):
+ pass
\ No newline at end of file
diff --git a/hb_server/apps/wf/migrations/0012_ticketflow_intervene_type.py b/hb_server/apps/wf/migrations/0012_ticketflow_intervene_type.py
new file mode 100644
index 0000000..c6c9534
--- /dev/null
+++ b/hb_server/apps/wf/migrations/0012_ticketflow_intervene_type.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.6 on 2021-10-12 08:23
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('wf', '0011_auto_20210930_0954'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='ticketflow',
+ name='intervene_type',
+ field=models.IntegerField(choices=[(0, '正常处理'), (1, '转交'), (2, '加签'), (3, '加签处理完成'), (4, '接单'), (5, '评论'), (6, '删除'), (7, '强制关闭'), (8, '强制修改状态'), (9, 'hook操作'), (10, '撤回')], default=0, help_text='流转类型', verbose_name='干预类型'),
+ ),
+ ]
diff --git a/hb_server/apps/wf/models.py b/hb_server/apps/wf/models.py
index 8328153..4878086 100644
--- a/hb_server/apps/wf/models.py
+++ b/hb_server/apps/wf/models.py
@@ -39,7 +39,7 @@ class State(CommonAModel):
PARTICIPANT_TYPE_ROBOT = 6
PARTICIPANT_TYPE_FIELD = 7
PARTICIPANT_TYPE_PARENT_FIELD = 8
- type2_choices = (
+ state_participanttype_choices = (
(0, '无处理人'),
(PARTICIPANT_TYPE_PERSONAL, '个人'),
(PARTICIPANT_TYPE_MULTI, '多人'),
@@ -70,7 +70,7 @@ class State(CommonAModel):
sort = models.IntegerField('状态顺序', default=0, help_text='用于工单步骤接口时,step上状态的顺序(因为存在网状情况,所以需要人为设定顺序),值越小越靠前')
type = models.IntegerField('状态类型', default=0, choices=type_choices, help_text='0.普通类型 1.初始状态(用于新建工单时,获取对应的字段必填及transition信息) 2.结束状态(此状态下的工单不得再处理,即没有对应的transition)')
enable_retreat = models.BooleanField('允许撤回', default=False, help_text='开启后允许工单创建人在此状态直接撤回工单到初始状态')
- participant_type = models.IntegerField('参与者类型', choices=type2_choices, default=1, blank=True, help_text='0.无处理人,1.个人,2.多人,3.部门,4.角色,5.变量(支持工单创建人,创建人的leader),6.脚本,7.工单的字段内容(如表单中的"测试负责人",需要为用户名或者逗号隔开的多个用户名),8.父工单的字段内容。 初始状态请选择类型5,参与人填create_by')
+ participant_type = models.IntegerField('参与者类型', choices=state_participanttype_choices, default=1, blank=True, help_text='0.无处理人,1.个人,2.多人,3.部门,4.角色,5.变量(支持工单创建人,创建人的leader),6.脚本,7.工单的字段内容(如表单中的"测试负责人",需要为用户名或者逗号隔开的多个用户名),8.父工单的字段内容。 初始状态请选择类型5,参与人填create_by')
participant = models.JSONField('参与者', default=list, blank=True, help_text='可以为空(无处理人的情况,如结束状态)、userid、userid列表\部门id\角色id\变量(create_by,create_by_tl)\脚本记录的id等,包含子工作流的需要设置处理人为loonrobot')
state_fields = models.JSONField('表单字段', default=dict, help_text='json格式字典存储,包括读写属性1:只读,2:必填,3:可选. 示例:{"create_time":1,"title":2, "sn":1}, 内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称),state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称') # json格式存储,包括读写属性1:只读,2:必填,3:可选,4:不显示, 字典的字典
distribute_type = models.IntegerField('分配方式', default=1, choices=state_distribute_choices, help_text='1.主动接单(如果当前处理人实际为多人的时候,需要先接单才能处理) 2.直接处理(即使当前处理人实际为多人,也可以直接处理) 3.随机分配(如果实际为多人,则系统会随机分配给其中一个人) 4.全部处理(要求所有参与人都要处理一遍,才能进入下一步)')
@@ -87,6 +87,31 @@ class Transition(CommonAModel):
(2, '拒绝'),
(3, '其他')
)
+ TRANSITION_INTERVENE_TYPE_DELIVER = 1 # 转交操作
+ TRANSITION_INTERVENE_TYPE_ADD_NODE = 2 # 加签操作
+ TRANSITION_INTERVENE_TYPE_ADD_NODE_END = 3 # 加签处理完成
+ TRANSITION_INTERVENE_TYPE_ACCEPT = 4 # 接单操作
+ TRANSITION_INTERVENE_TYPE_COMMENT = 5 # 评论操作
+ TRANSITION_INTERVENE_TYPE_DELETE = 6 # 删除操作
+ TRANSITION_INTERVENE_TYPE_CLOSE = 7 # 强制关闭操作
+ TRANSITION_INTERVENE_TYPE_ALTER_STATE = 8 # 强制修改状态操作
+ TRANSITION_INTERVENE_TYPE_HOOK = 9 # hook操作
+ TRANSITION_INTERVENE_TYPE_RETREAT = 10 # 撤回
+
+ intervene_type_choices = (
+ (0, '正常处理'),
+ (TRANSITION_INTERVENE_TYPE_DELIVER, '转交'),
+ (TRANSITION_INTERVENE_TYPE_ADD_NODE, '加签'),
+ (TRANSITION_INTERVENE_TYPE_ADD_NODE_END, '加签处理完成'),
+ (TRANSITION_INTERVENE_TYPE_ACCEPT, '接单'),
+ (TRANSITION_INTERVENE_TYPE_COMMENT, '评论'),
+ (TRANSITION_INTERVENE_TYPE_DELETE, '删除'),
+ (TRANSITION_INTERVENE_TYPE_CLOSE, '强制关闭'),
+ (TRANSITION_INTERVENE_TYPE_ALTER_STATE, '强制修改状态'),
+ (TRANSITION_INTERVENE_TYPE_HOOK, 'hook操作'),
+ (TRANSITION_INTERVENE_TYPE_RETREAT, '撤回')
+ )
+
name = models.CharField('操作', max_length=50)
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='所属工作流')
timer = models.IntegerField('定时器(单位秒)', default=0, help_text='单位秒。处于源状态X秒后如果状态都没有过变化则自动流转到目标状态。设置时间有效')
@@ -166,7 +191,7 @@ class Ticket(CommonAModel):
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='加签操作的人,工单当前处理人处理完成后会回到该处理人,当处于加签状态下才有效')
- participant_type = models.IntegerField('当前处理人类型', default=0, help_text='0.无处理人,1.个人,2.多人', choices=State.type2_choices)
+ participant_type = models.IntegerField('当前处理人类型', default=0, help_text='0.无处理人,1.个人,2.多人', choices=State.state_participanttype_choices)
participant = models.JSONField('当前处理人', default=list, blank=True, help_text='可以为空(无处理人的情况,如结束状态)、userid、userid列表')
act_state = models.IntegerField('进行状态', default=1, help_text='当前工单的进行状态', choices=act_state_choices)
multi_all_person = models.JSONField('全部处理的结果', default=dict, blank=True, help_text='需要当前状态处理人全部处理时实际的处理结果,json格式')
@@ -178,7 +203,8 @@ class TicketFlow(BaseModel):
ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE, verbose_name='关联工单', related_name='ticketflow_ticket')
transition = models.ForeignKey(Transition, verbose_name='流转id', help_text='与worklow.Transition关联, 为0时表示认为干预的操作', on_delete=models.CASCADE, null=True, blank=True)
suggestion = models.CharField('处理意见', max_length=10000, default='', blank=True)
- participant_type = models.IntegerField('处理人类型', default=0, help_text='0.无处理人,1.个人,2.多人', choices=State.type2_choices)
+ participant_type = models.IntegerField('处理人类型', default=0, help_text='0.无处理人,1.个人,2.多人', choices=State.state_participanttype_choices)
participant = models.ForeignKey(User, verbose_name='处理人', on_delete=models.SET_NULL, null=True, blank=True, related_name='ticketflow_participant')
state = models.ForeignKey(State, verbose_name='当前状态', default=0, blank=True, on_delete=models.CASCADE)
- ticket_data = models.JSONField('工单数据', default=dict, blank=True, help_text='可以用于记录当前表单数据,json格式')
\ No newline at end of file
+ ticket_data = models.JSONField('工单数据', default=dict, blank=True, help_text='可以用于记录当前表单数据,json格式')
+ intervene_type = models.IntegerField('干预类型', default=0, help_text='流转类型', choices=Transition.intervene_type_choices)
\ No newline at end of file
diff --git a/hb_server/apps/wf/serializers.py b/hb_server/apps/wf/serializers.py
index 697a96a..9075341 100644
--- a/hb_server/apps/wf/serializers.py
+++ b/hb_server/apps/wf/serializers.py
@@ -23,7 +23,7 @@ class WorkflowSimpleSerializer(serializers.ModelSerializer):
class StateSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = State
- fields = ['id', 'name', 'type', 'distribute_type']
+ fields = ['id', 'name', 'type', 'distribute_type', 'enable_retreat']
class TransitionSerializer(serializers.ModelSerializer):
source_state_ = StateSimpleSerializer(source='source_state', read_only=True)
@@ -77,7 +77,7 @@ class TicketListSerializer(serializers.ModelSerializer):
class Meta:
model = Ticket
- fields = ['id', 'title', 'sn', 'workflow', 'workflow_', 'state', 'state_', 'act_state', 'create_time', 'update_time', 'participant_type']
+ fields = ['id', 'title', 'sn', 'workflow', 'workflow_', 'state', 'state_', 'act_state', 'create_time', 'update_time', 'participant_type', 'create_by']
@staticmethod
def setup_eager_loading(queryset):
@@ -126,4 +126,7 @@ class TicketFlowSimpleSerializer(serializers.ModelSerializer):
class TicketHandleSerializer(serializers.Serializer):
transition = serializers.IntegerField(label="流转id")
ticket_data = serializers.JSONField(label="表单数据json")
- suggestion = serializers.CharField(label="处理意见", required = False)
\ No newline at end of file
+ suggestion = serializers.CharField(label="处理意见", required = False)
+
+class TicketRetreatSerializer(serializers.Serializer):
+ suggestion = serializers.CharField(label="撤回原因", required = False)
\ No newline at end of file
diff --git a/hb_server/apps/wf/views.py b/hb_server/apps/wf/views.py
index 187d70f..a1aab22 100644
--- a/hb_server/apps/wf/views.py
+++ b/hb_server/apps/wf/views.py
@@ -3,7 +3,7 @@ from django.core.exceptions import AppRegistryNotReady
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
-from apps.wf.serializers import CustomFieldSerializer, StateSerializer, TicketCreateSerializer, TicketFlowSerializer, TicketFlowSimpleSerializer, TicketHandleSerializer, TicketSerializer, TransitionSerializer, WorkflowSerializer, TicketListSerializer, TicketDetailSerializer
+from apps.wf.serializers import CustomFieldSerializer, StateSerializer, TicketCreateSerializer, TicketFlowSerializer, TicketFlowSimpleSerializer, TicketHandleSerializer, TicketRetreatSerializer, TicketSerializer, TransitionSerializer, WorkflowSerializer, TicketListSerializer, TicketDetailSerializer
from django.shortcuts import get_object_or_404, render
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from rest_framework.decorators import action, api_view
@@ -102,6 +102,8 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
return TicketCreateSerializer
elif self.action == 'handle':
return TicketHandleSerializer
+ elif self.action == 'retreat':
+ return TicketRetreatSerializer
elif self.action == 'list':
return TicketListSerializer
elif self.action == 'retrieve':
@@ -281,7 +283,7 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
# 接单日志
# 更新工单流转记录
TicketFlow.objects.create(ticket=ticket, state=ticket.state, ticket_data=WfService.get_ticket_all_field_value(ticket),
- suggestion='接单处理', participant_type=State.PARTICIPANT_TYPE_PERSONAL,
+ suggestion='', participant_type=State.PARTICIPANT_TYPE_PERSONAL, intervene_type=Transition.TRANSITION_ATTRIBUTE_TYPE_ACCEPT,
participant=request.user, transition=None)
return Response()
else:
@@ -292,7 +294,35 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
"""
撤回工单,允许创建人在指定状态撤回工单至初始状态,状态设置中开启允许撤回
"""
- pass
+ ticket = self.get_object()
+ if ticket.create_by != request.user:
+ raise APIException('非创建人不可撤回')
+ if not ticket.state.enable_retreat:
+ raise APIException('该状态不可撤回')
+ start_state = WfService.get_workflow_start_state(ticket.workflow)
+ ticket.state = start_state
+ ticket.participant_type = State.PARTICIPANT_TYPE_PERSONAL
+ ticket.participant = request.user.id
+ ticket.act_state = Ticket.TICKET_ACT_STATE_RETREAT
+ ticket.save()
+ # 更新流转记录
+ suggestion = request.data.get('suggestion', '') # 撤回原因
+ TicketFlow.objects.create(ticket=ticket, state=ticket.state, ticket_data=WfService.get_ticket_all_field_value(ticket),
+ suggestion=suggestion, participant_type=State.PARTICIPANT_TYPE_PERSONAL, intervene_type=Transition.TRANSITION_INTERVENE_TYPE_RETREAT,
+ participant=request.user, transition=None)
+ return Response()
+
+ @action(methods=['post'], detail=True, perms_map={'post':'*'})
+ def add_node(self, request, pk=None):
+ """
+ 加签
+ """
+
+ def close(self, request, pk=None):
+ """
+ 关闭工单(超级管理员或者创建人在初始状态)
+ """
+
class TicketFlowViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
"""