Compare commits
42 Commits
2.8.202510
...
master
Author | SHA1 | Date |
---|---|---|
|
388e225108 | |
|
25ee92602b | |
|
241df0beca | |
|
5ea7980a1b | |
|
a3416cfc0d | |
|
2ca47b8949 | |
|
10792d090c | |
|
bfc8454ac7 | |
|
02b14ec2c6 | |
|
acb4c802e4 | |
|
260c9893eb | |
|
666a9c169c | |
|
b869521221 | |
|
99d8144bdf | |
|
8a87ba356e | |
|
830bf18132 | |
|
b52e90a11f | |
|
ee67e6896a | |
|
54f8b82c98 | |
|
6125139fbf | |
|
2169bbea68 | |
|
6dfab46b4d | |
|
477976f86c | |
|
c37ff77eda | |
|
1aa7d51769 | |
|
e06cc8c38e | |
|
b93024ca44 | |
|
7d87c79dd1 | |
|
9f030ece6d | |
|
67f9cbb700 | |
|
8fe2b8ca48 | |
|
7732ddc88e | |
|
6713693c6c | |
|
20604ef7cb | |
|
eb2deb02c2 | |
|
f5f6c136d9 | |
|
8eee09678a | |
|
efd40d1d32 | |
|
3ab9682b07 | |
|
1983f7b121 | |
|
cec6837d00 | |
|
e214c6115a |
|
@ -62,7 +62,7 @@ class Mpoint(CommonBModel):
|
||||||
cal_coefficient = models.FloatField("计算系数", null=True, blank=True)
|
cal_coefficient = models.FloatField("计算系数", null=True, blank=True)
|
||||||
|
|
||||||
mpoint_from = models.ForeignKey("self", verbose_name="来源自采测点", related_name="mp_mpoint_from", on_delete=models.SET_NULL, null=True, blank=True)
|
mpoint_from = models.ForeignKey("self", verbose_name="来源自采测点", related_name="mp_mpoint_from", on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
cal_related_mgroup_running = models.PositiveSmallIntegerField("与工段运行状态的关联", default=10, choices=[(10, "运行时统计")], null=True, blank=True)
|
cal_related_mgroup_running = models.PositiveSmallIntegerField("与工段运行状态的关联", default=10, choices=[(10, "不涉及"), (20, "运行时统计")], null=True, blank=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def cache_key(cls, code: str):
|
def cache_key(cls, code: str):
|
||||||
|
|
|
@ -167,11 +167,11 @@ def get_first_stlog_time_from_duration(mgroup:Mgroup, dt_start:datetime, dt_end:
|
||||||
if st:
|
if st:
|
||||||
|
|
||||||
return st, "ending"
|
return st, "ending"
|
||||||
st = st_qs.filter(start_time__gte=dt_start, start_time__lte=dt_end, duration_sec__lte=600).order_by("start_time").last()
|
st = st_qs.filter(start_time__gte=dt_start, start_time__lte=dt_end, duration_sec__gte=600).order_by("start_time").last()
|
||||||
if st:
|
if st:
|
||||||
|
|
||||||
return st, "start"
|
return st, "start"
|
||||||
st = st_qs.filter(end_time__gte=dt_start, end_time__lte=dt_end, duration_sec__lte=600).order_by("end_time").first()
|
st = st_qs.filter(end_time__gte=dt_start, end_time__lte=dt_end, duration_sec__gte=600).order_by("end_time").first()
|
||||||
if st:
|
if st:
|
||||||
|
|
||||||
return st, "end"
|
return st, "end"
|
||||||
|
@ -213,7 +213,7 @@ def cal_mpointstat_hour(mpointId: str, year: int, month: int, day: int, hour: in
|
||||||
val = abs(first_val - last_val)
|
val = abs(first_val - last_val)
|
||||||
else:
|
else:
|
||||||
xtype = "normal"
|
xtype = "normal"
|
||||||
if mpointfrom and mpoint.cal_related_mgroup_running == 10:
|
if mpointfrom and mpoint.cal_related_mgroup_running == 20:
|
||||||
|
|
||||||
stlog, xtype = get_first_stlog_time_from_duration(mpoint.mgroup, dt, dt_hour_n)
|
stlog, xtype = get_first_stlog_time_from_duration(mpoint.mgroup, dt, dt_hour_n)
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,9 @@ class MioFilter(filters.FilterSet):
|
||||||
"item_mio__test_user": ["isnull"],
|
"item_mio__test_user": ["isnull"],
|
||||||
"item_mio__w_mioitem__number": ["exact"],
|
"item_mio__w_mioitem__number": ["exact"],
|
||||||
"mgroup": ["exact"],
|
"mgroup": ["exact"],
|
||||||
"item_mio__batch": ["exact"]
|
"item_mio__batch": ["exact"],
|
||||||
|
"inout_date": ["gte", "lte", "exact"],
|
||||||
|
"belong_dept": ["exact"]
|
||||||
}
|
}
|
||||||
|
|
||||||
def filter_materials__type(self, queryset, name, value):
|
def filter_materials__type(self, queryset, name, value):
|
||||||
|
|
|
@ -10,7 +10,7 @@ from apps.wpmw.models import Wpr
|
||||||
from apps.qm.models import Ftest, Defect
|
from apps.qm.models import Ftest, Defect
|
||||||
from django.db.models import Count, Q
|
from django.db.models import Count, Q
|
||||||
|
|
||||||
def do_out(item: MIOItem):
|
def do_out(item: MIOItem, is_reverse: bool = False):
|
||||||
"""
|
"""
|
||||||
生产领料到车间
|
生产领料到车间
|
||||||
"""
|
"""
|
||||||
|
@ -23,8 +23,6 @@ def do_out(item: MIOItem):
|
||||||
mgroup = mio.mgroup
|
mgroup = mio.mgroup
|
||||||
do_user = mio.do_user
|
do_user = mio.do_user
|
||||||
material:Material = item.material
|
material:Material = item.material
|
||||||
if material.into_wm is False: # 用于混料的原料不与车间库存交互, 这个是配置项目
|
|
||||||
return
|
|
||||||
|
|
||||||
# 获取defect
|
# 获取defect
|
||||||
defect:Defect = None
|
defect:Defect = None
|
||||||
|
@ -98,22 +96,24 @@ def do_out(item: MIOItem):
|
||||||
else:
|
else:
|
||||||
mb.save()
|
mb.save()
|
||||||
|
|
||||||
|
if material.into_wm:
|
||||||
# 领到车间库存(或工段)
|
# 领到车间库存(或工段)
|
||||||
wm, new_create = WMaterial.objects.get_or_create(
|
wm, new_create = WMaterial.objects.get_or_create(
|
||||||
batch=xbatch, material=xmaterial,
|
batch=xbatch, material=xmaterial,
|
||||||
belong_dept=belong_dept, mgroup=mgroup,
|
belong_dept=belong_dept, mgroup=mgroup,
|
||||||
state=WMaterial.WM_OK, defect=defect)
|
state=WMaterial.WM_OK, defect=defect)
|
||||||
if new_create:
|
if new_create:
|
||||||
wm.create_by = do_user
|
wm.create_by = do_user
|
||||||
wm.batch_ofrom = mb.batch if mb else None
|
wm.batch_ofrom = mb.batch if mb else None
|
||||||
wm.material_ofrom = mb.material if mb else None
|
wm.material_ofrom = mb.material if mb else None
|
||||||
wm.count = wm.count + item.count
|
wm.count = wm.count + item.count
|
||||||
wm.update_by = do_user
|
wm.update_by = do_user
|
||||||
wm.save()
|
wm.save()
|
||||||
|
|
||||||
# 开始变动wpr
|
# 开始变动wpr
|
||||||
if xmaterial.tracking == Material.MA_TRACKING_SINGLE:
|
if xmaterial.tracking == Material.MA_TRACKING_SINGLE:
|
||||||
|
if material.into_wm is False:
|
||||||
|
raise ParseError("追踪单个物料不支持不进行车间库存的操作")
|
||||||
mioitemws = MIOItemw.objects.filter(mioitem=item)
|
mioitemws = MIOItemw.objects.filter(mioitem=item)
|
||||||
if mioitemws.count() != item.count:
|
if mioitemws.count() != item.count:
|
||||||
raise ParseError("出入库与明细数量不一致,操作失败")
|
raise ParseError("出入库与明细数量不一致,操作失败")
|
||||||
|
@ -141,8 +141,7 @@ def do_in(item: MIOItem):
|
||||||
mgroup = mio.mgroup
|
mgroup = mio.mgroup
|
||||||
do_user = mio.do_user
|
do_user = mio.do_user
|
||||||
material = item.material
|
material = item.material
|
||||||
if material.into_wm is False: # 根据配置不进行入车间库存的处理
|
|
||||||
return
|
|
||||||
action_list = []
|
action_list = []
|
||||||
mias = MIOItemA.objects.filter(mioitem=item)
|
mias = MIOItemA.objects.filter(mioitem=item)
|
||||||
is_zhj = False # 是否组合件入仓库
|
is_zhj = False # 是否组合件入仓库
|
||||||
|
@ -177,38 +176,39 @@ def do_in(item: MIOItem):
|
||||||
raise ParseError("存在非正数!")
|
raise ParseError("存在非正数!")
|
||||||
|
|
||||||
xbatchs.append(xbatch)
|
xbatchs.append(xbatch)
|
||||||
|
if material.into_wm:
|
||||||
wm_qs = WMaterial.objects.filter(
|
wm_qs = WMaterial.objects.filter(
|
||||||
batch=xbatch,
|
batch=xbatch,
|
||||||
material=xmaterial,
|
material=xmaterial,
|
||||||
belong_dept=belong_dept,
|
belong_dept=belong_dept,
|
||||||
mgroup=mgroup,
|
mgroup=mgroup,
|
||||||
defect=defect,
|
defect=defect,
|
||||||
state=WMaterial.WM_OK)
|
state=WMaterial.WM_OK)
|
||||||
count_x = wm_qs.count()
|
count_x = wm_qs.count()
|
||||||
if count_x == 1:
|
if count_x == 1:
|
||||||
wm = wm_qs.first()
|
wm = wm_qs.first()
|
||||||
elif count_x == 0:
|
elif count_x == 0:
|
||||||
raise ParseError(
|
raise ParseError(
|
||||||
f'{str(xmaterial)}-{xbatch}-批次库存不存在!')
|
f'{str(xmaterial)}-{xbatch}-批次库存不存在!')
|
||||||
else:
|
else:
|
||||||
raise ParseError(
|
raise ParseError(
|
||||||
f'{str(xmaterial)}-{xbatch}-存在多个相同批次!')
|
f'{str(xmaterial)}-{xbatch}-存在多个相同批次!')
|
||||||
|
|
||||||
|
# 扣减车间库存
|
||||||
|
new_count = wm.count - xcount
|
||||||
|
if new_count >= 0:
|
||||||
|
wm.count = new_count
|
||||||
|
wm.update_by = do_user
|
||||||
|
wm.save()
|
||||||
|
else:
|
||||||
|
raise ParseError(f'{str(xmaterial)}-{xbatch}车间物料不足')
|
||||||
|
|
||||||
|
wm_production_dept = wm.mgroup.belong_dept if wm.mgroup else wm.belong_dept
|
||||||
|
if production_dept is None:
|
||||||
|
production_dept = wm_production_dept
|
||||||
|
elif wm_production_dept and production_dept != wm_production_dept:
|
||||||
|
raise ParseError(f'{str(xmaterial)}-{xbatch}车间物料不属于同一车间')
|
||||||
|
|
||||||
# 扣减车间库存
|
|
||||||
new_count = wm.count - xcount
|
|
||||||
if new_count >= 0:
|
|
||||||
wm.count = new_count
|
|
||||||
wm.update_by = do_user
|
|
||||||
wm.save()
|
|
||||||
else:
|
|
||||||
raise ParseError(f'{str(xmaterial)}-{xbatch}车间物料不足')
|
|
||||||
|
|
||||||
wm_production_dept = wm.mgroup.belong_dept if wm.mgroup else wm.belong_dept
|
|
||||||
if production_dept is None:
|
|
||||||
production_dept = wm_production_dept
|
|
||||||
elif wm_production_dept and production_dept != wm_production_dept:
|
|
||||||
raise ParseError(f'{str(xmaterial)}-{xbatch}车间物料不属于同一车间')
|
|
||||||
# 增加mb
|
# 增加mb
|
||||||
if not is_zhj:
|
if not is_zhj:
|
||||||
mb, _ = MaterialBatch.objects.get_or_create(
|
mb, _ = MaterialBatch.objects.get_or_create(
|
||||||
|
@ -231,6 +231,8 @@ def do_in(item: MIOItem):
|
||||||
|
|
||||||
# 开始变动wpr
|
# 开始变动wpr
|
||||||
if xmaterial.tracking == Material.MA_TRACKING_SINGLE:
|
if xmaterial.tracking == Material.MA_TRACKING_SINGLE:
|
||||||
|
if material.into_wm is False:
|
||||||
|
raise ParseError("追踪单个物料不支持不进行车间库存的操作")
|
||||||
mioitemws = MIOItemw.objects.filter(mioitem=item)
|
mioitemws = MIOItemw.objects.filter(mioitem=item)
|
||||||
if mioitemws.count() != item.count:
|
if mioitemws.count() != item.count:
|
||||||
raise ParseError("出入库与明细数量不一致,操作失败")
|
raise ParseError("出入库与明细数量不一致,操作失败")
|
||||||
|
|
|
@ -39,7 +39,7 @@ class MaterialViewSet(CustomModelViewSet):
|
||||||
ordering = ['name', 'model', 'specification',
|
ordering = ['name', 'model', 'specification',
|
||||||
'type', 'process', 'process__sort', 'sort', 'id', 'number']
|
'type', 'process', 'process__sort', 'sort', 'id', 'number']
|
||||||
ordering_fields = ['name', 'model', 'specification',
|
ordering_fields = ['name', 'model', 'specification',
|
||||||
'type', 'process', 'process__sort', 'sort', 'id', 'number']
|
'type', 'process', 'process__sort', 'sort', 'id', 'number', 'create_time']
|
||||||
|
|
||||||
def perform_destroy(self, instance):
|
def perform_destroy(self, instance):
|
||||||
from apps.inm.models import MaterialBatch
|
from apps.inm.models import MaterialBatch
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-10-10 08:31
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ofm', '0016_auto_20250929_1551'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='secret_period',
|
||||||
|
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='秘密期限'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='level',
|
||||||
|
field=models.JSONField(default=list, help_text=['重要', '一般', '非涉密'], verbose_name='涉密等级'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-10-11 01:22
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ofm', '0017_auto_20251010_1631'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='dept_opinion',
|
||||||
|
field=models.JSONField(blank=True, default=list, help_text=['同意', '不同意'], null=True, verbose_name='部门负责人意见'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='number',
|
||||||
|
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='记录编号'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='publicity_opinion',
|
||||||
|
field=models.JSONField(blank=True, default=list, help_text=['同意公开宣传报道', '不同意任何渠道的宣传报道'], null=True, verbose_name='宣传统战部审查意见'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='review',
|
||||||
|
field=models.JSONField(blank=True, default=list, help_text=['内容不涉及国家秘密和商业秘密,申请公开', '内容涉及国家秘密,申请按涉密渠道发布'], null=True, verbose_name='第一撰稿人自审'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-10-11 03:28
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ofm', '0018_auto_20251011_0922'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='dept_opinion',
|
||||||
|
field=models.JSONField(default=list, help_text=['同意', '不同意'], verbose_name='部门负责人意见'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='publicity_opinion',
|
||||||
|
field=models.JSONField(blank=True, default=list, help_text=['同意公开宣传报道', '不同意任何渠道的宣传报道'], verbose_name='宣传统战部审查意见'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='review',
|
||||||
|
field=models.JSONField(blank=True, default=list, help_text=['内容不涉及国家秘密和商业秘密,申请公开', '内容涉及国家秘密,申请按涉密渠道发布'], verbose_name='第一撰稿人自审'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-10-11 06:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ofm', '0019_auto_20251011_1128'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='dept_opinion',
|
||||||
|
field=models.JSONField(blank=True, default=list, help_text=['同意', '不同意'], null=True, verbose_name='部门负责人意见'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='publicity_opinion',
|
||||||
|
field=models.JSONField(blank=True, default=list, help_text=['同意公开宣传报道', '不同意任何渠道的宣传报道'], null=True, verbose_name='宣传统战部审查意见'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='review',
|
||||||
|
field=models.JSONField(blank=True, default=list, help_text=['内容不涉及国家秘密和商业秘密,申请公开', '内容涉及国家秘密,申请按涉密渠道发布'], null=True, verbose_name='第一撰稿人自审'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-10-13 01:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ofm', '0020_auto_20251011_1427'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='publicity',
|
||||||
|
name='publicity_opinion',
|
||||||
|
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='宣传报道意见'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-10-17 06:50
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ofm', '0021_alter_publicity_publicity_opinion'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='mroomslot',
|
||||||
|
unique_together=set(),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-10-21 06:08
|
||||||
|
|
||||||
|
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 = [
|
||||||
|
('wf', '0004_workflow_view_path2'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('system', '0006_auto_20241213_1249'),
|
||||||
|
('ofm', '0022_alter_mroomslot_unique_together'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='PatentInfo',
|
||||||
|
fields=[
|
||||||
|
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, 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(max_length=100, verbose_name='拟申请专利名称')),
|
||||||
|
('author', models.CharField(max_length=100, verbose_name='发明人(设计人)')),
|
||||||
|
('type', models.CharField(choices=[('invention', '发明专利'), ('utility', '实用新型专利'), ('design', '外观设计专利')], default='invention', max_length=50, verbose_name='专利类型')),
|
||||||
|
('is_public', models.BooleanField(default=False, verbose_name='是否公开')),
|
||||||
|
('area', models.CharField(choices=[('Domestic', '国内申请'), ('Foreign', '国外申请'), (' PCT', 'PCT申请')], default='Domestic', max_length=50, verbose_name='拟申请地域')),
|
||||||
|
('identified', models.BooleanField(default=False, verbose_name='是否进行过科技成果鉴定')),
|
||||||
|
('published_article', models.BooleanField(default=False, verbose_name='是否发表过文章')),
|
||||||
|
('exhibited', models.BooleanField(default=False, verbose_name='是否参与过展会展出')),
|
||||||
|
('applied_to_production', models.BooleanField(default=False, verbose_name='是否参与应用于生产/销售')),
|
||||||
|
('participated_in_exchange', models.BooleanField(default=False, verbose_name='是否参与过技术交流')),
|
||||||
|
('tech_background_pages', models.PositiveIntegerField(blank=True, null=True, verbose_name='技术背景材料页数')),
|
||||||
|
('tech_disclosure_pages', models.PositiveIntegerField(blank=True, null=True, verbose_name='技术交底材料页数')),
|
||||||
|
('novelty_report_pages', models.PositiveIntegerField(blank=True, null=True, verbose_name='查新检索报告页数')),
|
||||||
|
('diagrams_or_photos_pages', models.PositiveIntegerField(blank=True, null=True, verbose_name='图/照片页数或张数')),
|
||||||
|
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='patentinfo_belong_dept', to='system.dept', verbose_name='所属部门')),
|
||||||
|
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='patentinfo_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||||
|
('ticket', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='patentInfo_ticket', to='wf.ticket', verbose_name='关联工单')),
|
||||||
|
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='patentinfo_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -44,9 +44,6 @@ class MroomSlot(BaseModel):
|
||||||
mdate = models.DateField('会议日期', db_index=True)
|
mdate = models.DateField('会议日期', db_index=True)
|
||||||
slot = models.PositiveIntegerField('时段', help_text='0-47')
|
slot = models.PositiveIntegerField('时段', help_text='0-47')
|
||||||
is_inuse = models.BooleanField('是否占用', default=True)
|
is_inuse = models.BooleanField('是否占用', default=True)
|
||||||
|
|
||||||
class Meta:
|
|
||||||
unique_together = ('mroom', 'mdate', 'slot', 'is_inuse')
|
|
||||||
|
|
||||||
|
|
||||||
# class Seal(BaseModel):
|
# class Seal(BaseModel):
|
||||||
|
@ -122,12 +119,12 @@ class BorrowRecord(CommonBDModel):
|
||||||
|
|
||||||
class Publicity(CommonBDModel):
|
class Publicity(CommonBDModel):
|
||||||
"""TN: 公示栏"""
|
"""TN: 公示栏"""
|
||||||
number = models.CharField('记录编号', max_length=50)
|
number = models.CharField('记录编号', max_length=50, blank=True, null=True)
|
||||||
title = models.CharField('送审稿件标题', max_length=100)
|
title = models.CharField('送审稿件标题', max_length=100)
|
||||||
participants = models.CharField('所有撰稿人', max_length=50)
|
participants = models.CharField('所有撰稿人', max_length=50)
|
||||||
pub_dept = models.CharField('部室/研究院', null=True, blank=True, max_length=50)
|
pub_dept = models.CharField('部室/研究院', null=True, blank=True, max_length=50)
|
||||||
pfile = models.CharField('稿件路径', null=True, blank=True, max_length=100)
|
pfile = models.CharField('稿件路径', null=True, blank=True, max_length=100)
|
||||||
level = models.JSONField('用途', default=list, help_text=['重要', '一般', '非涉密'])
|
level = models.JSONField('涉密等级', default=list, help_text=['重要', '一般', '非涉密'])
|
||||||
content = models.JSONField('稿件内容涉及', default=list, help_text=[
|
content = models.JSONField('稿件内容涉及', default=list, help_text=[
|
||||||
"武器装备科研生产综合事项",
|
"武器装备科研生产综合事项",
|
||||||
"其它"
|
"其它"
|
||||||
|
@ -137,59 +134,58 @@ class Publicity(CommonBDModel):
|
||||||
channel = models.JSONField('发布渠道', default=list, help_text=['互联网', '信息平台', '官微', '公开发行物', '其它'])
|
channel = models.JSONField('发布渠道', default=list, help_text=['互联网', '信息平台', '官微', '公开发行物', '其它'])
|
||||||
other_channel = models.CharField('其它渠道', max_length=50, blank=True, null=True)
|
other_channel = models.CharField('其它渠道', max_length=50, blank=True, null=True)
|
||||||
report_name = models.CharField('报道名称', max_length=50, blank=True, null=True)
|
report_name = models.CharField('报道名称', max_length=50, blank=True, null=True)
|
||||||
review = models.JSONField('第一撰稿人自审', default=list, help_text=['内容不涉及国家秘密和商业秘密,申请公开', '内容涉及国家秘密,申请按涉密渠道发布'])
|
review = models.JSONField('第一撰稿人自审', default=list, help_text=['内容不涉及国家秘密和商业秘密,申请公开', '内容涉及国家秘密,申请按涉密渠道发布'], null=True,blank=True)
|
||||||
dept_opinion = models.JSONField('部门负责人意见', default=list, help_text=['同意', '不同意'])
|
dept_opinion = models.JSONField('部门负责人意见', default=list, help_text=['同意', '不同意'], null=True, blank=True)
|
||||||
|
secret_period = models.CharField('秘密期限', max_length=50, blank=True, null=True)
|
||||||
dept_opinion_review = models.CharField('部门审查意见', max_length=100, blank=True, null=True)
|
dept_opinion_review = models.CharField('部门审查意见', max_length=100, blank=True, null=True)
|
||||||
publicity_opinion = models.JSONField('宣传统战部审查意见', default=list, help_text=['同意公开宣传报道', '不同意任何渠道的宣传报道'])
|
publicity_opinion = models.CharField('宣传报道意见', max_length=100, blank=True, null=True)
|
||||||
ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单',
|
ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单',
|
||||||
on_delete=models.SET_NULL, related_name='publicity_ticket', null=True, blank=True, db_constraint=False)
|
on_delete=models.SET_NULL, related_name='publicity_ticket', null=True, blank=True, db_constraint=False)
|
||||||
|
|
||||||
# 记录编号自动生成
|
# 记录编号自动生成
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.number:
|
if not self.number:
|
||||||
with transaction.atomic():
|
last_number = self.__class__.objects.filter(number__startswith=f"GXKG-{datetime.now().year}-").order_by('-number').first()
|
||||||
# 加行锁,防止并发取到相同 last_number
|
if last_number:
|
||||||
last_number = self.__class__.objects.select_for_update(skip_locked=True).order_by('-id').first() # skip_locked 锁定行,避免并发冲突
|
try:
|
||||||
if last_number:
|
last_num = int(last_number.number.split('-')[-1])
|
||||||
try:
|
except ValueError:
|
||||||
last_num = int(last_number.number.split('-')[-1])
|
last_num = 0
|
||||||
except ValueError:
|
else:
|
||||||
last_num = 0
|
last_num =0
|
||||||
new_num= last_num + 1
|
# 格式化编号,带补零
|
||||||
else:
|
self.number = f"GXKG-{datetime.now().year}-{last_num+1:02d}"
|
||||||
new_num = 1
|
|
||||||
# 格式化编号,带补零
|
|
||||||
self.number = f"(GXKG-{datetime.now().year}-{new_num:02d})"
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
# class PatentInfo(CommonBDModel):
|
class PatentInfo(CommonBDModel):
|
||||||
# """TN: 专利申密审批表单样式"""
|
"""TN: 专利申密审批表单样式"""
|
||||||
# PATENT_TYPE_CHOICES = (
|
PATENT_TYPE_CHOICES = (
|
||||||
# ('invention', '发明专利'),
|
('invention', '发明专利'),
|
||||||
# ('utility', '实用新型专利'),
|
('utility', '实用新型专利'),
|
||||||
# ('design', '外观设计专利'),
|
('design', '外观设计专利'),
|
||||||
# )
|
)
|
||||||
# APPLY_AREAS = (
|
APPLY_AREAS = (
|
||||||
# ('Domestic', '国内申请'),
|
('Domestic', '国内申请'),
|
||||||
# ('Foreign', '国外申请'),
|
('Foreign', '国外申请'),
|
||||||
# (' PCT', 'PCT申请'),
|
(' PCT', 'PCT申请'),
|
||||||
# )
|
)
|
||||||
# name = models.CharField('拟申请专利名称', max_length=100)
|
name = models.CharField('拟申请专利名称', max_length=100)
|
||||||
# author = models.CharField('发明人(设计人)', max_length=100)
|
author = models.CharField('发明人(设计人)', max_length=100)
|
||||||
# type = models.CharField('专利类型', max_length=50, choices=PATENT_TYPE_CHOICES, default='invention')
|
type = models.CharField('专利类型', max_length=50, choices=PATENT_TYPE_CHOICES, default='invention')
|
||||||
# is_public = models.BooleanField('是否公开', default=False)
|
is_public = models.BooleanField('是否公开', default=False)
|
||||||
# area = models.CharField('拟申请地域', max_length=50, choices=APPLY_AREAS, default='Domestic')
|
area = models.CharField('拟申请地域', max_length=50, choices=APPLY_AREAS, default='Domestic')
|
||||||
# identified = models.BooleanField('是否进行过科技成果鉴定', default=False)
|
identified = models.BooleanField('是否进行过科技成果鉴定', default=False)
|
||||||
# published_article = models.BooleanField('是否发表过文章', default=False)
|
published_article = models.BooleanField('是否发表过文章', default=False)
|
||||||
# exhibited = models.BooleanField('是否参与过展会展出', default=False)
|
exhibited = models.BooleanField('是否参与过展会展出', default=False)
|
||||||
# applied_to_production = models.BooleanField('是否参与应用于生产/销售', default=False)
|
applied_to_production = models.BooleanField('是否参与应用于生产/销售', default=False)
|
||||||
# participated_in_exchange = models.BooleanField('是否参与过技术交流', default=False)
|
participated_in_exchange = models.BooleanField('是否参与过技术交流', default=False)
|
||||||
# tech_background_pages = models.PositiveIntegerField('技术背景材料页数', null=True, blank=True)
|
tech_background_pages = models.PositiveIntegerField('技术背景材料页数', null=True, blank=True)
|
||||||
# tech_disclosure_pages = models.PositiveIntegerField('技术交底材料页数', null=True, blank=True)
|
tech_disclosure_pages = models.PositiveIntegerField('技术交底材料页数', null=True, blank=True)
|
||||||
# novelty_report_pages = models.PositiveIntegerField('查新检索报告页数', null=True, blank=True)
|
novelty_report_pages = models.PositiveIntegerField('查新检索报告页数', null=True, blank=True)
|
||||||
# diagrams_or_photos_pages = models.PositiveIntegerField('图/照片页数或张数', null=True, blank=True)
|
diagrams_or_photos_pages = models.PositiveIntegerField('图/照片页数或张数', null=True, blank=True)
|
||||||
|
ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单',
|
||||||
|
on_delete=models.SET_NULL, related_name='patentInfo_ticket', null=True, blank=True, db_constraint=False)
|
||||||
|
|
||||||
# class PaperOfm(CommonADModel):
|
# class PaperOfm(CommonADModel):
|
||||||
# """TN: 论文申密审批表单"""
|
# """TN: 论文申密审批表单"""
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from .models import (Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity)
|
from .models import (Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity, PatentInfo)
|
||||||
# Publicity, PatentInfo, PaperOfm, Platform, Project, PatentRecord, PaperRecord, ProjectApproval, ProjectInfo)
|
# Publicity, PatetInfo, PaperOfm, Platform, Project, PatentRecord, PaperRecord, ProjectApproval, ProjectInfo)
|
||||||
from apps.utils.serializers import CustomModelSerializer
|
from apps.utils.serializers import CustomModelSerializer
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
@ -37,10 +37,10 @@ class MroomBookingSerializer(CustomModelSerializer):
|
||||||
for slot in slots:
|
for slot in slots:
|
||||||
if slot < 0 or slot > 47:
|
if slot < 0 or slot > 47:
|
||||||
raise ParseError("时段索引超出范围")
|
raise ParseError("时段索引超出范围")
|
||||||
try:
|
ms_exists = MroomSlot.objects.filter(mroom=mroom, mdate=mdate, slot=slot, is_inuse=True).exists()
|
||||||
MroomSlot.objects.create(booking=booking, slot=slot, mdate=mdate, mroom=mroom, is_inuse=True)
|
if ms_exists:
|
||||||
except Exception as e:
|
raise ParseError("时段已预订,请刷新重选")
|
||||||
raise ParseError(f"时段已预订,请刷新重选-{e}")
|
MroomSlot.objects.create(booking=booking, slot=slot, mdate=mdate, mroom=mroom, is_inuse=True)
|
||||||
return booking
|
return booking
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
|
@ -52,10 +52,10 @@ class MroomBookingSerializer(CustomModelSerializer):
|
||||||
for slot in slots:
|
for slot in slots:
|
||||||
if slot < 0 or slot > 47:
|
if slot < 0 or slot > 47:
|
||||||
raise ParseError("时段索引超出范围")
|
raise ParseError("时段索引超出范围")
|
||||||
try:
|
ms_exists = MroomSlot.objects.filter(mroom=mroom, mdate=mdate, slot=slot, is_inuse=True).exists()
|
||||||
MroomSlot.objects.create(booking=booking, slot=slot, mdate=mdate, mroom=mroom, is_inuse=True)
|
if ms_exists:
|
||||||
except Exception as e:
|
raise ParseError("时段已预订,请刷新重选")
|
||||||
raise ParseError(f"时段已预订,请刷新重选-{e}")
|
MroomSlot.objects.create(booking=booking, slot=slot, mdate=mdate, mroom=mroom, is_inuse=True)
|
||||||
return booking
|
return booking
|
||||||
|
|
||||||
|
|
||||||
|
@ -122,11 +122,11 @@ class PublicitySerializer(CustomModelSerializer):
|
||||||
read_only_fields = EXCLUDE_FIELDS
|
read_only_fields = EXCLUDE_FIELDS
|
||||||
|
|
||||||
|
|
||||||
# class PatentInfoSerializer(CustomModelSerializer):
|
class PatentInfoSerializer(CustomModelSerializer):
|
||||||
# class Meta:
|
class Meta:
|
||||||
# model = PatentInfo
|
model = PatentInfo
|
||||||
# fields = '__all__'
|
fields = '__all__'
|
||||||
# read_only_fields = EXCLUDE_FIELDS
|
read_only_fields = EXCLUDE_FIELDS
|
||||||
|
|
||||||
|
|
||||||
# class PaperSerializer(CustomModelSerializer):
|
# class PaperSerializer(CustomModelSerializer):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
from apps.wf.models import Ticket
|
from apps.wf.models import Ticket
|
||||||
# TicketFlow, Transition, Workflow, CustomField, State,
|
# TicketFlow, Transition, Workflow, CustomField, State,
|
||||||
from apps.ofm.models import LendingSeal, Vehicle, BorrowRecord, Publicity, MroomBooking, MroomSlot
|
from apps.ofm.models import LendingSeal, Vehicle, BorrowRecord, Publicity, MroomBooking, MroomSlot, PatentInfo
|
||||||
from rest_framework.exceptions import ParseError
|
from rest_framework.exceptions import ParseError
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ def mroombooking_reject(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
|
|
||||||
def bind_lendingseal(ticket: Ticket, transition, new_ticket_data: dict):
|
def bind_lendingseal(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
ins = LendingSeal.objects.get(id=new_ticket_data['t_id'])
|
ins = LendingSeal.objects.get(id=new_ticket_data['t_id'])
|
||||||
|
ins.actual_return_date = None
|
||||||
ticket_data = ticket.ticket_data
|
ticket_data = ticket.ticket_data
|
||||||
ticket_data.update({
|
ticket_data.update({
|
||||||
't_model': 'LendingSeal',
|
't_model': 'LendingSeal',
|
||||||
|
@ -42,6 +43,19 @@ def bind_lendingseal(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
if ins.ticket is None:
|
if ins.ticket is None:
|
||||||
ins.ticket = ticket
|
ins.ticket = ticket
|
||||||
ins.save()
|
ins.save()
|
||||||
|
# 如果驳回到开始状态
|
||||||
|
|
||||||
|
def lending_save_ticket_data(ticket: Ticket, new_ticket_data: dict, **kwargs):
|
||||||
|
try:
|
||||||
|
obj = LendingSeal.objects.get(id=new_ticket_data['t_id'])
|
||||||
|
except LendingSeal.DoesNotExist:
|
||||||
|
raise ParseError("Publicity t_id 不存在")
|
||||||
|
data_save = {k: v for k, v in new_ticket_data.items() if k not in ['t_model', 't_id']}
|
||||||
|
|
||||||
|
for k, v in data_save.items():
|
||||||
|
setattr(obj, k, v)
|
||||||
|
obj.save()
|
||||||
|
|
||||||
|
|
||||||
def bind_vehicle(ticket: Ticket, transition, new_ticket_data: dict):
|
def bind_vehicle(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
ins = Vehicle.objects.get(id=new_ticket_data['t_id'])
|
ins = Vehicle.objects.get(id=new_ticket_data['t_id'])
|
||||||
|
@ -50,6 +64,8 @@ def bind_vehicle(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
't_model': 'Vehicle',
|
't_model': 'Vehicle',
|
||||||
't_id': ins.id,
|
't_id': ins.id,
|
||||||
})
|
})
|
||||||
|
ins.actual_km = None
|
||||||
|
ins.end_time = None
|
||||||
ticket.ticket_data = ticket_data
|
ticket.ticket_data = ticket_data
|
||||||
ticket.create_by = ins.create_by
|
ticket.create_by = ins.create_by
|
||||||
ticket.save()
|
ticket.save()
|
||||||
|
@ -57,11 +73,16 @@ def bind_vehicle(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
ins.ticket = ticket
|
ins.ticket = ticket
|
||||||
ins.save()
|
ins.save()
|
||||||
|
|
||||||
|
def vehicle_save_ticket_data(ticket: Ticket, new_ticket_data: dict, **kwargs):
|
||||||
|
try:
|
||||||
|
obj = Vehicle.objects.get(id=new_ticket_data['t_id'])
|
||||||
|
except Vehicle.DoesNotExist:
|
||||||
|
raise ParseError("Publicity t_id 不存在")
|
||||||
|
data_save = {k: v for k, v in new_ticket_data.items() if k not in ['t_model', 't_id']}
|
||||||
|
|
||||||
# def update_vehicle_endkm(ticket: Ticket, transition, new_ticket_data: dict):
|
for k, v in data_save.items():
|
||||||
# ins = Vehicle.objects.get(id=new_ticket_data['t_id'])
|
setattr(obj, k, v)
|
||||||
# ins.end_km = new_ticket_data['end_km']
|
obj.save()
|
||||||
# ins.save()
|
|
||||||
|
|
||||||
def bind_file(ticket: Ticket, transition, new_ticket_data: dict):
|
def bind_file(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
ins = BorrowRecord.objects.get(id=new_ticket_data['t_id'])
|
ins = BorrowRecord.objects.get(id=new_ticket_data['t_id'])
|
||||||
|
@ -70,13 +91,24 @@ def bind_file(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
't_model': 'BorrowRecord',
|
't_model': 'BorrowRecord',
|
||||||
't_id': ins.id,
|
't_id': ins.id,
|
||||||
})
|
})
|
||||||
|
ins.return_date = None
|
||||||
ticket.ticket_data = ticket_data
|
ticket.ticket_data = ticket_data
|
||||||
ticket.create_by = ins.create_by
|
ticket.create_by = ins.create_by
|
||||||
ticket.save()
|
ticket.save()
|
||||||
if ins.ticket is None:
|
if ins.ticket is None:
|
||||||
ins.ticket = ticket
|
ins.ticket = ticket
|
||||||
ins.save()
|
ins.save()
|
||||||
|
|
||||||
|
def file_save_ticket_data(ticket: Ticket, new_ticket_data: dict, **kwargs):
|
||||||
|
try:
|
||||||
|
obj = BorrowRecord.objects.get(id=new_ticket_data['t_id'])
|
||||||
|
except BorrowRecord.DoesNotExist:
|
||||||
|
raise ParseError("Publicity t_id 不存在")
|
||||||
|
data_save = {k: v for k, v in new_ticket_data.items() if k not in ['t_model', 't_id']}
|
||||||
|
|
||||||
|
for k, v in data_save.items():
|
||||||
|
setattr(obj, k, v)
|
||||||
|
obj.save()
|
||||||
|
|
||||||
def bind_publicity(ticket: Ticket, transition, new_ticket_data: dict):
|
def bind_publicity(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
ins = Publicity.objects.get(id=new_ticket_data['t_id'])
|
ins = Publicity.objects.get(id=new_ticket_data['t_id'])
|
||||||
|
@ -85,6 +117,36 @@ def bind_publicity(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
't_model': 'publicity',
|
't_model': 'publicity',
|
||||||
't_id': ins.id,
|
't_id': ins.id,
|
||||||
})
|
})
|
||||||
|
ins.dept_opinion = None
|
||||||
|
ins.secret_period = None
|
||||||
|
ins.dept_opinion_review = None
|
||||||
|
ins.publicity_opinion = None
|
||||||
|
ticket.ticket_data = ticket_data
|
||||||
|
ticket.create_by = ins.create_by
|
||||||
|
ticket.save()
|
||||||
|
if ins.ticket is None:
|
||||||
|
ins.ticket = ticket
|
||||||
|
ins.save()
|
||||||
|
|
||||||
|
def save_ticket_data(ticket: Ticket, new_ticket_data: dict, **kwargs):
|
||||||
|
try:
|
||||||
|
obj = Publicity.objects.get(id=new_ticket_data['t_id'])
|
||||||
|
except Publicity.DoesNotExist:
|
||||||
|
raise ParseError("Publicity t_id 不存在")
|
||||||
|
data_save = {k: v for k, v in new_ticket_data.items() if k not in ['t_model', 't_id']}
|
||||||
|
|
||||||
|
for k, v in data_save.items():
|
||||||
|
setattr(obj, k, v)
|
||||||
|
obj.save()
|
||||||
|
|
||||||
|
|
||||||
|
def bind_patent(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
|
ins = PatentInfo.objects.get(id=new_ticket_data['t_id'])
|
||||||
|
ticket_data = ticket.ticket_data
|
||||||
|
ticket_data.update({
|
||||||
|
't_model': 'patent',
|
||||||
|
't_id': ins.id,
|
||||||
|
})
|
||||||
ticket.ticket_data = ticket_data
|
ticket.ticket_data = ticket_data
|
||||||
ticket.create_by = ins.create_by
|
ticket.create_by = ins.create_by
|
||||||
ticket.save()
|
ticket.save()
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
from apps.ofm.views import (MroomViewSet, MroomBookingViewSet, MroomSlotViewSet,LendingSealViewSet, VehicleViewSet, FilerecordViewSet, FileborrowViewSet, PublicityViewSet)
|
from apps.ofm.views import (MroomViewSet, MroomBookingViewSet, MroomSlotViewSet,LendingSealViewSet, VehicleViewSet, FilerecordViewSet,
|
||||||
|
FileborrowViewSet, PublicityViewSet, PatentInfoViewSet)
|
||||||
# SealModelViewSet,
|
# SealModelViewSet,
|
||||||
# , PublicityViewSet, PatentInfoViewSet, PaperViewSet, PlatformViewSet,
|
# , PublicityViewSet, , PaperViewSet, PlatformViewSet,
|
||||||
# ProjectViewSet, PatentRecordViewSet, PaperRecordViewSet, ProjectApprovalViewSet, ProjectInfoViewSet)
|
# ProjectViewSet, PatentRecordViewSet, PaperRecordViewSet, ProjectApprovalViewSet, ProjectInfoViewSet)
|
||||||
|
|
||||||
API_BASE_URL = 'api/ofm/'
|
API_BASE_URL = 'api/ofm/'
|
||||||
|
@ -18,7 +19,7 @@ router.register('vehicle', VehicleViewSet, basename='vehicle')
|
||||||
router.register('filerecord', FilerecordViewSet, basename='filerecord')
|
router.register('filerecord', FilerecordViewSet, basename='filerecord')
|
||||||
router.register('fileborrow', FileborrowViewSet, basename='fileborrow')
|
router.register('fileborrow', FileborrowViewSet, basename='fileborrow')
|
||||||
router.register('publicity', PublicityViewSet, basename='publicity')
|
router.register('publicity', PublicityViewSet, basename='publicity')
|
||||||
# router.register('patentinfo', PatentInfoViewSet, basename='patentinfo')
|
router.register('patentinfo', PatentInfoViewSet, basename='patentinfo')
|
||||||
# router.register('paper', PaperViewSet, basename='paper')
|
# router.register('paper', PaperViewSet, basename='paper')
|
||||||
# router.register('platform', PlatformViewSet, basename='platform')
|
# router.register('platform', PlatformViewSet, basename='platform')
|
||||||
# router.register('project', ProjectViewSet, basename='project')
|
# router.register('project', ProjectViewSet, basename='project')
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from apps.utils.viewsets import CustomModelViewSet, CustomGenericViewSet
|
from apps.utils.viewsets import CustomModelViewSet, CustomGenericViewSet
|
||||||
from .models import Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity
|
from .models import Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity, PatentInfo
|
||||||
# Publicity, PatentInfo, PaperOfm, Platform, Project, PatentRecord, PaperRecord, ProjectApproval, ProjectInfo)
|
# Publicity, , PaperOfm, Platform, Project, PatentRecord, PaperRecord, ProjectApproval, ProjectInfo)
|
||||||
from .serializers import (MroomSerializer, MroomBookingSerializer, MroomSlotSerializer, LendingSealSerializer, VehicleSerializer, FileRecordSerializer, BorrowRecordSerializer, PublicitySerializer,)
|
from .serializers import (MroomSerializer, MroomBookingSerializer, MroomSlotSerializer, LendingSealSerializer,
|
||||||
|
VehicleSerializer, FileRecordSerializer, BorrowRecordSerializer, PublicitySerializer, PatentInfoSerializer)
|
||||||
# ,SealSerializer,
|
# ,SealSerializer,
|
||||||
# LendingSealSerializer, FileRecordSerializer, BorrowRecordSerializer, PublicitySerializer,
|
# LendingSealSerializer, FileRecordSerializer, BorrowRecordSerializer, PublicitySerializer,
|
||||||
# PatentInfoSerializer, PaperSerializer, PlatformSerializer, ProjectSerializer, ProjectMemberSerializer, PaperRecordSerializer, ProjectApprovalSerializer, ProjectInfoSerializer)
|
# PatentInfoSerializer, PaperSerializer, PlatformSerializer, ProjectSerializer, ProjectMemberSerializer, PaperRecordSerializer, ProjectApprovalSerializer, ProjectInfoSerializer)
|
||||||
|
@ -123,7 +124,7 @@ class LendingSealViewSet(CustomModelViewSet):
|
||||||
queryset = LendingSeal.objects.all()
|
queryset = LendingSeal.objects.all()
|
||||||
serializer_class = LendingSealSerializer
|
serializer_class = LendingSealSerializer
|
||||||
filterset_class = SealFilter
|
filterset_class = SealFilter
|
||||||
ordering = ["create_time"]
|
ordering = ["-create_time"]
|
||||||
data_filter = True
|
data_filter = True
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,7 +135,7 @@ class VehicleViewSet(CustomModelViewSet):
|
||||||
"""
|
"""
|
||||||
queryset = Vehicle.objects.all()
|
queryset = Vehicle.objects.all()
|
||||||
serializer_class = VehicleSerializer
|
serializer_class = VehicleSerializer
|
||||||
ordering = ["create_time"]
|
ordering = ["-create_time"]
|
||||||
|
|
||||||
|
|
||||||
class FilerecordViewSet(CustomModelViewSet):
|
class FilerecordViewSet(CustomModelViewSet):
|
||||||
|
@ -145,7 +146,7 @@ class FilerecordViewSet(CustomModelViewSet):
|
||||||
queryset = FileRecord.objects.all()
|
queryset = FileRecord.objects.all()
|
||||||
serializer_class = FileRecordSerializer
|
serializer_class = FileRecordSerializer
|
||||||
filterset_fields = [ "name", "number"]
|
filterset_fields = [ "name", "number"]
|
||||||
ordering = ["create_time", "number", "name"]
|
ordering = ["-create_time", "number", "name"]
|
||||||
|
|
||||||
|
|
||||||
class FileborrowViewSet(CustomModelViewSet):
|
class FileborrowViewSet(CustomModelViewSet):
|
||||||
|
@ -156,7 +157,7 @@ class FileborrowViewSet(CustomModelViewSet):
|
||||||
queryset = BorrowRecord.objects.all()
|
queryset = BorrowRecord.objects.all()
|
||||||
serializer_class = BorrowRecordSerializer
|
serializer_class = BorrowRecordSerializer
|
||||||
filterset_class = BorrowRecordFilter
|
filterset_class = BorrowRecordFilter
|
||||||
ordering = ["create_time"]
|
ordering = ["-create_time"]
|
||||||
|
|
||||||
|
|
||||||
class PublicityViewSet(CustomModelViewSet):
|
class PublicityViewSet(CustomModelViewSet):
|
||||||
|
@ -167,18 +168,18 @@ class PublicityViewSet(CustomModelViewSet):
|
||||||
queryset = Publicity.objects.all()
|
queryset = Publicity.objects.all()
|
||||||
serializer_class = PublicitySerializer
|
serializer_class = PublicitySerializer
|
||||||
filterset_fields = ["title","number"]
|
filterset_fields = ["title","number"]
|
||||||
ordering = ["create_time", "number"]
|
ordering = ["-create_time", "number"]
|
||||||
|
|
||||||
|
|
||||||
# class PatentInfoViewSet(CustomModelViewSet):
|
class PatentInfoViewSet(CustomModelViewSet):
|
||||||
# """list: 专利
|
"""list: 专利
|
||||||
|
|
||||||
# 专利
|
专利
|
||||||
# """
|
"""
|
||||||
# queryset = PatentInfo.objects.all()
|
queryset = PatentInfo.objects.all()
|
||||||
# serializer_class = PatentInfoSerializer
|
serializer_class = PatentInfoSerializer
|
||||||
# filterset_fields = ["name", "author", "type"]
|
filterset_fields = ["name", "author", "type"]
|
||||||
# ordering = ["create_time", "name", "author", "type"]
|
ordering = ["-create_time", "name", "author", "type"]
|
||||||
|
|
||||||
|
|
||||||
# class PaperViewSet(CustomModelViewSet):
|
# class PaperViewSet(CustomModelViewSet):
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-10-16 08:29
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('wf', '0003_workflow_view_path'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='workflow',
|
||||||
|
name='view_path2',
|
||||||
|
field=models.TextField(blank=True, null=True, verbose_name='前端自定义页面路径2'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -22,6 +22,7 @@ class Workflow(CommonAModel):
|
||||||
content_template = models.CharField(
|
content_template = models.CharField(
|
||||||
'内容模板', max_length=1000, default='标题:{title}, 创建时间:{create_time}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:标题:{title}, 创建时间:{create_time}')
|
'内容模板', max_length=1000, default='标题:{title}, 创建时间:{create_time}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:标题:{title}, 创建时间:{create_time}')
|
||||||
view_path = models.TextField('前端自定义页面路径', null=True, blank=True)
|
view_path = models.TextField('前端自定义页面路径', null=True, blank=True)
|
||||||
|
view_path2 = models.TextField('前端自定义页面路径2', null=True, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '工作流'
|
verbose_name = '工作流'
|
||||||
|
|
|
@ -77,7 +77,7 @@ class WfService(object):
|
||||||
"""
|
"""
|
||||||
获取状态可执行的操作
|
获取状态可执行的操作
|
||||||
"""
|
"""
|
||||||
return Transition.objects.filter(is_deleted=False, source_state=state).all()
|
return Transition.objects.filter(is_deleted=False, source_state=state).all().order_by("-attribute_type", "-id")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_ticket_steps(cls, ticket: Ticket):
|
def get_ticket_steps(cls, ticket: Ticket):
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-10-20 02:09
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('em', '0022_equipment_cd_req_addr'),
|
||||||
|
('wpm', '0123_mlogbdefect_count_has'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='mloguser',
|
||||||
|
name='equipment',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mloguser_equipment', to='em.equipment', verbose_name='生产设备'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='mloguser',
|
||||||
|
name='work_start_time',
|
||||||
|
field=models.DateTimeField(blank=True, null=True, verbose_name='生产开始时间'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -368,6 +368,9 @@ class MlogUser(BaseModel):
|
||||||
mlog = models.ForeignKey(Mlog, verbose_name='关联日志', on_delete=models.CASCADE)
|
mlog = models.ForeignKey(Mlog, verbose_name='关联日志', on_delete=models.CASCADE)
|
||||||
handle_user = models.ForeignKey(User, verbose_name='操作人', on_delete=models.CASCADE)
|
handle_user = models.ForeignKey(User, verbose_name='操作人', on_delete=models.CASCADE)
|
||||||
process = models.ForeignKey(Process, verbose_name='子工序', on_delete=models.CASCADE)
|
process = models.ForeignKey(Process, verbose_name='子工序', on_delete=models.CASCADE)
|
||||||
|
work_start_time = models.DateTimeField('生产开始时间', null=True, blank=True)
|
||||||
|
equipment = models.ForeignKey(
|
||||||
|
Equipment, verbose_name='生产设备', on_delete=models.CASCADE, null=True, blank=True, related_name='mloguser_equipment')
|
||||||
shift = models.ForeignKey(Shift, verbose_name='关联班次', on_delete=models.CASCADE)
|
shift = models.ForeignKey(Shift, verbose_name='关联班次', on_delete=models.CASCADE)
|
||||||
handle_date = models.DateField('操作日期')
|
handle_date = models.DateField('操作日期')
|
||||||
|
|
||||||
|
|
|
@ -355,12 +355,12 @@ class MlogSerializer(CustomModelSerializer):
|
||||||
model = Mlog
|
model = Mlog
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
read_only_fields = EXCLUDE_FIELDS + \
|
read_only_fields = EXCLUDE_FIELDS + \
|
||||||
['submit_time', 'submit_user', 'material_outs', "handle_date", "shift"]
|
['submit_time', 'submit_user', 'material_outs']
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
"batch": {"required": True},
|
"batch": {"required": True},
|
||||||
"shift": {"required": False},
|
"shift": {"required": False},
|
||||||
"material_out": {"required": True},
|
"material_out": {"required": True},
|
||||||
"work_start_time": {"required": True}
|
"work_start_time": {"required": False}
|
||||||
}
|
}
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
|
@ -634,14 +634,20 @@ class MlogSerializer(CustomModelSerializer):
|
||||||
|
|
||||||
# 时间
|
# 时间
|
||||||
mgroup:Mgroup = attrs['mgroup']
|
mgroup:Mgroup = attrs['mgroup']
|
||||||
work_start_time:datetime = attrs['work_start_time']
|
work_start_time:datetime = attrs.get('work_start_time', None)
|
||||||
handle_date, attrs["shift"] = mgroup.get_shift(work_start_time)
|
if work_start_time:
|
||||||
if mtask and mtask.start_date == mtask.end_date:
|
attrs['handle_date'], attrs["shift"] = mgroup.get_shift(work_start_time)
|
||||||
attrs['handle_date'] = mtask.end_date
|
|
||||||
if attrs['handle_date'] != handle_date:
|
|
||||||
raise ParseError('任务日期与生产日期不一致')
|
|
||||||
else:
|
else:
|
||||||
attrs['handle_date'] = handle_date
|
if "handle_date" in attrs and attrs["handle_date"]:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise ParseError('缺少生产日期')
|
||||||
|
if mtask and mtask.start_date == mtask.end_date:
|
||||||
|
if attrs['handle_date'] != mtask.end_date:
|
||||||
|
if work_start_time:
|
||||||
|
raise ParseError('任务日期与生产日期不一致')
|
||||||
|
else:
|
||||||
|
attrs['handle_date'] = mtask.end_date
|
||||||
|
|
||||||
handle_user = attrs.get('handle_user', None)
|
handle_user = attrs.get('handle_user', None)
|
||||||
if handle_user is None and hasattr(self, "request"):
|
if handle_user is None and hasattr(self, "request"):
|
||||||
|
@ -1486,10 +1492,17 @@ class MlogUserSerializer(CustomModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = MlogUser
|
model = MlogUser
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = EXCLUDE_FIELDS_BASE
|
read_only_fields = EXCLUDE_FIELDS_BASE + ["shift", "handle_date"]
|
||||||
|
extra_kwargs = {
|
||||||
|
"work_start_time": {"required": True}
|
||||||
|
}
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
mlog:Mlog = validated_data["mlog"]
|
mlog:Mlog = validated_data["mlog"]
|
||||||
|
work_start_time:datetime = validated_data["work_start_time"]
|
||||||
|
if mlog.work_start_time < mlog.work_start_time:
|
||||||
|
raise ParseError("操作时间不能早于日志开始时间")
|
||||||
|
validated_data["handle_date"], validated_data["shift"] = mlog.mgroup.get_shift(work_start_time)
|
||||||
if mlog.submit_time is not None:
|
if mlog.submit_time is not None:
|
||||||
raise ParseError("该日志已提交")
|
raise ParseError("该日志已提交")
|
||||||
process:Process = validated_data["process"]
|
process:Process = validated_data["process"]
|
||||||
|
|
|
@ -11,7 +11,7 @@ from apps.system.models import User
|
||||||
from apps.pm.models import Mtask
|
from apps.pm.models import Mtask
|
||||||
from apps.mtm.models import Mgroup, Shift, Material, Route, RoutePack, Team, Srule
|
from apps.mtm.models import Mgroup, Shift, Material, Route, RoutePack, Team, Srule
|
||||||
|
|
||||||
from .models import SfLog, WMaterial, Mlog, Mlogb, Mlogbw, Handover, Handoverb, Handoverbw, MlogbDefect, BatchLog, BatchSt
|
from .models import SfLog, WMaterial, Mlog, Mlogb, Mlogbw, Handover, Handoverb, Handoverbw, MlogbDefect, BatchLog, BatchSt, MlogUser
|
||||||
from apps.mtm.services_2 import cal_material_count
|
from apps.mtm.services_2 import cal_material_count
|
||||||
from apps.wf.models import Ticket
|
from apps.wf.models import Ticket
|
||||||
from apps.wf.services import WfService
|
from apps.wf.services import WfService
|
||||||
|
@ -152,7 +152,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
||||||
"""
|
"""
|
||||||
生产日志提交后需要执行的操作
|
生产日志提交后需要执行的操作
|
||||||
"""
|
"""
|
||||||
if mlog.work_start_time > timezone.now():
|
if mlog.work_start_time and mlog.work_start_time > timezone.now():
|
||||||
raise ParseError('操作开始时间不能晚于当前时间')
|
raise ParseError('操作开始时间不能晚于当前时间')
|
||||||
if mlog.work_start_time and mlog.work_end_time and mlog.work_end_time < mlog.work_start_time:
|
if mlog.work_start_time and mlog.work_end_time and mlog.work_end_time < mlog.work_start_time:
|
||||||
raise ParseError('操作结束时间不能早于操作开始时间')
|
raise ParseError('操作结束时间不能早于操作开始时间')
|
||||||
|
@ -385,7 +385,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
||||||
mlog.submit_user = user
|
mlog.submit_user = user
|
||||||
mlog.stored_notok = stored_notok
|
mlog.stored_notok = stored_notok
|
||||||
mlog.stored_mgroup = stored_mgroup
|
mlog.stored_mgroup = stored_mgroup
|
||||||
if mlog.work_end_time is None:
|
if mlog.work_end_time is None and mlog.work_start_time is not None:
|
||||||
mlog.work_end_time = now
|
mlog.work_end_time = now
|
||||||
mlog.save()
|
mlog.save()
|
||||||
|
|
||||||
|
@ -1026,6 +1026,10 @@ def mlog_submit_validate(ins: Mlog):
|
||||||
raise ParseError('该日志未指定消耗!')
|
raise ParseError('该日志未指定消耗!')
|
||||||
if Mlogb.objects.filter(material_out__isnull=False, count_real=0, mlog=ins).exists():
|
if Mlogb.objects.filter(material_out__isnull=False, count_real=0, mlog=ins).exists():
|
||||||
raise ParseError('产出数量不能为0!')
|
raise ParseError('产出数量不能为0!')
|
||||||
|
if ins.is_fix is False and ins.route:
|
||||||
|
process = ins.route.process
|
||||||
|
if Process.objects.filter(parent=process).exists() and not MlogUser.objects.filter(mlog=ins).exists():
|
||||||
|
raise ParseError('该日志子工序信息未完善!')
|
||||||
|
|
||||||
def bind_mlog(ticket: Ticket, transition, new_ticket_data: dict):
|
def bind_mlog(ticket: Ticket, transition, new_ticket_data: dict):
|
||||||
ins = Mlog.objects.get(id=new_ticket_data['t_id'])
|
ins = Mlog.objects.get(id=new_ticket_data['t_id'])
|
||||||
|
|
Loading…
Reference in New Issue