feat: 增加utask
This commit is contained in:
parent
53d2276998
commit
3d407795a9
|
@ -22,7 +22,6 @@ class MtaskFilter(filters.FilterSet):
|
||||||
"material_out__type": ["exact"],
|
"material_out__type": ["exact"],
|
||||||
"material_out__is_hidden": ["exact"],
|
"material_out__is_hidden": ["exact"],
|
||||||
"mgroup__belong_dept__name": ["exact"],
|
"mgroup__belong_dept__name": ["exact"],
|
||||||
"parent": ["exact", "isnull"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def filter_tag(self, queryset, name, value):
|
def filter_tag(self, queryset, name, value):
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
# Generated by Django 3.2.12 on 2023-10-19 10:12
|
||||||
|
|
||||||
|
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 = [
|
||||||
|
('mtm', '0017_auto_20231018_1033'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('pm', '0006_auto_20231016_1648'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='mtask',
|
||||||
|
name='parent',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='mtask',
|
||||||
|
name='state',
|
||||||
|
field=models.PositiveIntegerField(choices=[(10, '创建中'), (20, '已下达'), (30, '生产中'), (40, '已提交')], default=10, help_text="((10, '创建中'), (20, '已下达'), (30, '生产中'), (40, '已提交'))", verbose_name='状态'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Utask',
|
||||||
|
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='删除标记')),
|
||||||
|
('state', models.PositiveIntegerField(choices=[(10, '创建中'), (20, '已下达'), (30, '生产中'), (40, '已提交')], default=10, help_text="((10, '创建中'), (20, '已下达'), (30, '生产中'), (40, '已提交'))", verbose_name='状态')),
|
||||||
|
('number', models.CharField(max_length=50, unique=True, verbose_name='编号')),
|
||||||
|
('count', models.PositiveIntegerField(default=1, verbose_name='任务数')),
|
||||||
|
('count_real', models.PositiveIntegerField(default=0, verbose_name='实际生产数')),
|
||||||
|
('count_ok', models.PositiveIntegerField(default=0, verbose_name='合格数')),
|
||||||
|
('count_notok', models.PositiveIntegerField(default=0, verbose_name='不合格数')),
|
||||||
|
('start_date', models.DateField(verbose_name='计划开工日期')),
|
||||||
|
('end_date', models.DateField(verbose_name='计划完工日期')),
|
||||||
|
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='utask_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||||
|
('material', 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='utask_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='mtask',
|
||||||
|
name='utask',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pm.utask', verbose_name='关联大任务'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -5,6 +5,33 @@ from apps.mtm.models import Material, Mgroup
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
||||||
|
|
||||||
|
class Utask(CommonADModel):
|
||||||
|
"""
|
||||||
|
生产大任务
|
||||||
|
"""
|
||||||
|
UTASK_CREATED = 10
|
||||||
|
UTASK_ASSGINED = 20
|
||||||
|
UTASK_WORKING = 30
|
||||||
|
UTASK_DONE = 40
|
||||||
|
UTASK_STATES = (
|
||||||
|
(UTASK_CREATED, '创建中'),
|
||||||
|
(UTASK_ASSGINED, '已下达'),
|
||||||
|
(UTASK_WORKING, '生产中'),
|
||||||
|
(UTASK_DONE, '已提交')
|
||||||
|
)
|
||||||
|
state = models.PositiveIntegerField(
|
||||||
|
'状态', choices=UTASK_STATES, default=UTASK_CREATED, help_text=str(UTASK_STATES))
|
||||||
|
number = models.CharField('编号', max_length=50, unique=True)
|
||||||
|
material = models.ForeignKey(
|
||||||
|
Material, verbose_name='产品', on_delete=models.CASCADE)
|
||||||
|
count = models.PositiveIntegerField('任务数', default=1)
|
||||||
|
count_real = models.PositiveIntegerField('实际生产数', default=0)
|
||||||
|
count_ok = models.PositiveIntegerField('合格数', default=0)
|
||||||
|
count_notok = models.PositiveIntegerField('不合格数', default=0)
|
||||||
|
start_date = models.DateField('计划开工日期')
|
||||||
|
end_date = models.DateField('计划完工日期')
|
||||||
|
|
||||||
|
|
||||||
class Mtask(CommonADModel):
|
class Mtask(CommonADModel):
|
||||||
"""
|
"""
|
||||||
生产任务
|
生产任务
|
||||||
|
@ -16,7 +43,7 @@ class Mtask(CommonADModel):
|
||||||
MTASK_STATES = (
|
MTASK_STATES = (
|
||||||
(MTASK_CREATED, '创建中'),
|
(MTASK_CREATED, '创建中'),
|
||||||
(MTASK_ASSGINED, '已下达'),
|
(MTASK_ASSGINED, '已下达'),
|
||||||
# (MTASK_WORKING, '生产中'),
|
(MTASK_WORKING, '生产中'),
|
||||||
(MTASK_DONE, '已提交')
|
(MTASK_DONE, '已提交')
|
||||||
)
|
)
|
||||||
state = models.PositiveIntegerField(
|
state = models.PositiveIntegerField(
|
||||||
|
@ -34,5 +61,5 @@ class Mtask(CommonADModel):
|
||||||
count_notok = models.PositiveIntegerField('不合格数', default=0)
|
count_notok = models.PositiveIntegerField('不合格数', default=0)
|
||||||
start_date = models.DateField('计划开工日期')
|
start_date = models.DateField('计划开工日期')
|
||||||
end_date = models.DateField('计划完工日期')
|
end_date = models.DateField('计划完工日期')
|
||||||
parent = models.ForeignKey(
|
utask = models.ForeignKey(
|
||||||
'self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='父任务')
|
Utask, verbose_name='关联大任务', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
|
|
@ -2,17 +2,16 @@ from rest_framework import serializers
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
|
|
||||||
from apps.mtm.serializers import MaterialSerializer
|
from apps.mtm.serializers import MaterialSerializer
|
||||||
from apps.pm.models import Mtask
|
from apps.pm.models import Mtask, Utask
|
||||||
from apps.sam.models import OrderItem
|
from apps.sam.models import OrderItem
|
||||||
from apps.utils.serializers import CustomModelSerializer
|
from apps.utils.serializers import CustomModelSerializer
|
||||||
|
|
||||||
|
|
||||||
class MtaskSerializer(CustomModelSerializer):
|
class UtaskSerializer(CustomModelSerializer):
|
||||||
material_ = MaterialSerializer(source='material', read_only=True)
|
material_ = MaterialSerializer(source='material', read_only=True)
|
||||||
mgroup_name = serializers.CharField(source='mgroup.name', read_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Mtask
|
model = Utask
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
|
@ -23,9 +22,28 @@ class MtaskSerializer(CustomModelSerializer):
|
||||||
return super().update(instance, new_data)
|
return super().update(instance, new_data)
|
||||||
|
|
||||||
|
|
||||||
|
class MtaskSerializer(CustomModelSerializer):
|
||||||
|
material_ = MaterialSerializer(source='material', read_only=True)
|
||||||
|
mgroup_name = serializers.CharField(source='mgroup.name', read_only=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Mtask
|
||||||
|
fields = '__all__'
|
||||||
|
read_only_fields = ['utask']
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
if instance.state != Mtask.MTASK_CREATED:
|
||||||
|
raise ValidationError('任务非创建中不可编辑')
|
||||||
|
if instance.utask is not None:
|
||||||
|
new_data = {'count': validated_data['count']}
|
||||||
|
else:
|
||||||
|
new_data = {key: validated_data[key] for key in [
|
||||||
|
'number', 'count', 'start_date', 'end_date']}
|
||||||
|
return super().update(instance, new_data)
|
||||||
|
|
||||||
|
|
||||||
class SchedueSerializer(serializers.Serializer):
|
class SchedueSerializer(serializers.Serializer):
|
||||||
orderitems = serializers.PrimaryKeyRelatedField(
|
orderitems = serializers.PrimaryKeyRelatedField(
|
||||||
label='orderitem的ID列表', queryset=OrderItem.objects.all(), many=True)
|
label='orderitem的ID列表', queryset=OrderItem.objects.all(), many=True)
|
||||||
start_date = serializers.DateField(label='计划开工日期')
|
start_date = serializers.DateField(label='计划开工日期')
|
||||||
end_date = serializers.DateField(
|
end_date = serializers.DateField(label='计划完工日期')
|
||||||
label='计划完工日期', allow_null=True, required=False)
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from apps.sam.models import OrderItem
|
from apps.sam.models import OrderItem
|
||||||
from apps.mtm.models import Route, Material, Mgroup
|
from apps.mtm.models import Route, Material, Mgroup
|
||||||
from rest_framework.exceptions import ParseError
|
from rest_framework.exceptions import ParseError
|
||||||
from apps.pm.models import Mtask
|
from apps.pm.models import Mtask, Utask
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from datetime import date, timedelta
|
from datetime import date, timedelta
|
||||||
import math
|
import math
|
||||||
|
@ -10,9 +10,103 @@ from typing import List
|
||||||
|
|
||||||
class PmService:
|
class PmService:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def make_utasks_from_orderitems(cls, user, orderitemIds: List[str], start_date: date, end_date: date):
|
||||||
|
start_date_str = start_date.strftime('%Y%m%d')
|
||||||
|
if start_date >= end_date:
|
||||||
|
raise ParseError('开始时间不可大于结束时间')
|
||||||
|
orderitems = OrderItem.objects.filter(pk__in=orderitemIds)
|
||||||
|
if orderitems.exclude(utask=None).exists():
|
||||||
|
raise ParseError('存在订单项已排任务!')
|
||||||
|
rdict = {}
|
||||||
|
for item in orderitems:
|
||||||
|
productId = item.material.id
|
||||||
|
if productId not in rdict:
|
||||||
|
rdict[productId] = [item.material, item.count, [item.id]]
|
||||||
|
else:
|
||||||
|
rdict[productId][1] = rdict[productId][1] + item.count
|
||||||
|
rdict[productId][2].append(item.id)
|
||||||
|
# 生成大任务
|
||||||
|
make_list = []
|
||||||
|
for k, v in rdict.items():
|
||||||
|
xproduct, xcount, orderitemsId = v
|
||||||
|
if xproduct.is_assemb:
|
||||||
|
for key in xproduct.components:
|
||||||
|
make_list.append([Material.objects.get(
|
||||||
|
id=key), xcount*xproduct.components[key], orderitemsId])
|
||||||
|
else:
|
||||||
|
make_list = [[xproduct, xcount, orderitemsId]]
|
||||||
|
for i in make_list:
|
||||||
|
material, count, orderitemsId = i
|
||||||
|
utask = Utask.objects.create(
|
||||||
|
number=f'{material.number}_{start_date_str}',
|
||||||
|
material=material,
|
||||||
|
count=count,
|
||||||
|
start_date=start_date,
|
||||||
|
end_date=end_date,
|
||||||
|
create_by=user,
|
||||||
|
update_by=user
|
||||||
|
)
|
||||||
|
OrderItem.objects.filter(id__in=orderitemIds).update(utask=utask)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def schedue_mtasks(cls, user, utask: Utask):
|
||||||
|
"""
|
||||||
|
从大任务自动排产出小任务
|
||||||
|
"""
|
||||||
|
number, product, count, start_date, end_date = utask.number, utask.material, utask.count, utask.start_date, utask.end_date
|
||||||
|
# 计算相差天数
|
||||||
|
rela_days = (end_date - start_date).days + 1
|
||||||
|
# 获取每个产品的加工路线
|
||||||
|
rqs = Route.get_routes(product)
|
||||||
|
# 创建小任务
|
||||||
|
for ind, val in enumerate(rqs):
|
||||||
|
if val.material_out:
|
||||||
|
halfgood = val.material_out
|
||||||
|
else:
|
||||||
|
raise ParseError(f'第{ind+1}步-无输出物料')
|
||||||
|
if val.material_in:
|
||||||
|
material_in = val.material_in
|
||||||
|
elif ind > 0:
|
||||||
|
material_in = rqs[ind-1].material_out
|
||||||
|
if val.is_autotask:
|
||||||
|
# 找到工段
|
||||||
|
mgroups = Mgroup.objects.filter(process=val.process)
|
||||||
|
mgroups_count = mgroups.count()
|
||||||
|
if mgroups_count == 1:
|
||||||
|
mgroup = mgroups.first()
|
||||||
|
elif mgroups_count == 0:
|
||||||
|
raise ParseError(f'第{ind+1}步-工段不存在!')
|
||||||
|
else: # 后面可能会指定车间
|
||||||
|
raise ParseError(f'第{ind+1}步-工段存在多个!')
|
||||||
|
task_count = count
|
||||||
|
if val.out_rate:
|
||||||
|
if val.out_rate > 1:
|
||||||
|
task_count = math.ceil(
|
||||||
|
count / (val.out_rate/100))
|
||||||
|
else:
|
||||||
|
task_count = math.ceil(count / val.out_rate)
|
||||||
|
task_count_day = math.ceil(task_count/rela_days)
|
||||||
|
if rela_days > 1:
|
||||||
|
for i in range(rela_days):
|
||||||
|
task_date = start_date + timedelta(days=i)
|
||||||
|
Mtask.objects.create(**{
|
||||||
|
'number': f'{number}_r{ind+1}_{i+1}',
|
||||||
|
'material_out': halfgood,
|
||||||
|
'material_in': material_in,
|
||||||
|
'mgroup': mgroup,
|
||||||
|
'count': task_count_day,
|
||||||
|
'start_date': task_date,
|
||||||
|
'end_date': task_date,
|
||||||
|
'utask': utask,
|
||||||
|
'create_by': user,
|
||||||
|
'update_by': user
|
||||||
|
})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def check_orderitems(cls, orderitems: QuerySet[OrderItem]):
|
def check_orderitems(cls, orderitems: QuerySet[OrderItem]):
|
||||||
"""
|
"""
|
||||||
|
废弃
|
||||||
校验orderitems并返回整合后的字典以productId为key, [product, count, end_date, orderitems] 为value
|
校验orderitems并返回整合后的字典以productId为key, [product, count, end_date, orderitems] 为value
|
||||||
"""
|
"""
|
||||||
rdict = {}
|
rdict = {}
|
||||||
|
@ -34,6 +128,7 @@ class PmService:
|
||||||
@classmethod
|
@classmethod
|
||||||
def schedue_from_orderitems(cls, user, orderitemIds: List[str], start_date: date, end_date: date = None):
|
def schedue_from_orderitems(cls, user, orderitemIds: List[str], start_date: date, end_date: date = None):
|
||||||
"""
|
"""
|
||||||
|
废弃
|
||||||
从多个订单明细自动排产
|
从多个订单明细自动排产
|
||||||
"""
|
"""
|
||||||
orderitems = OrderItem.objects.filter(pk__in=orderitemIds)
|
orderitems = OrderItem.objects.filter(pk__in=orderitemIds)
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
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.pm.views import (MtaskViewSet)
|
from apps.pm.views import (MtaskViewSet, UtaskViewSet)
|
||||||
|
|
||||||
API_BASE_URL = 'api/pm/'
|
API_BASE_URL = 'api/pm/'
|
||||||
HTML_BASE_URL = 'pm/'
|
HTML_BASE_URL = 'pm/'
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register('mtask', MtaskViewSet, basename='mtask')
|
router.register('mtask', MtaskViewSet, basename='mtask')
|
||||||
|
router.register('utask', UtaskViewSet, basename='utask')
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path(API_BASE_URL, include(router.urls)),
|
path(API_BASE_URL, include(router.urls)),
|
||||||
]
|
]
|
||||||
|
|
106
apps/pm/views.py
106
apps/pm/views.py
|
@ -7,13 +7,77 @@ from apps.utils.serializers import PkSerializer
|
||||||
from apps.utils.viewsets import CustomModelViewSet
|
from apps.utils.viewsets import CustomModelViewSet
|
||||||
|
|
||||||
from .filters import MtaskFilter
|
from .filters import MtaskFilter
|
||||||
from .models import Mtask
|
from .models import Mtask, Utask
|
||||||
from .serializers import MtaskSerializer, SchedueSerializer
|
from .serializers import MtaskSerializer, SchedueSerializer, UtaskSerializer
|
||||||
from .services import PmService
|
from .services import PmService
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
|
|
||||||
|
class UtaskViewSet(CustomModelViewSet):
|
||||||
|
"""
|
||||||
|
list: 生产大任务
|
||||||
|
|
||||||
|
生产大任务
|
||||||
|
"""
|
||||||
|
queryset = Utask.objects.all()
|
||||||
|
serializer_class = UtaskSerializer
|
||||||
|
filterset_fields = ['material', 'state']
|
||||||
|
select_related_fields = ['material']
|
||||||
|
ordering = ['-start_date']
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=False, perms_map={'post': 'utask.schedue'}, serializer_class=SchedueSerializer)
|
||||||
|
@transaction.atomic
|
||||||
|
def schedue_utasks(self, request, *args, **kwargs):
|
||||||
|
"""从多个订单明细生成大任务
|
||||||
|
|
||||||
|
从多个订单明细生成大任务
|
||||||
|
"""
|
||||||
|
sr = SchedueSerializer(data=request.data)
|
||||||
|
sr.is_valid(raise_exception=True)
|
||||||
|
vdata = sr.validated_data
|
||||||
|
PmService.make_utasks_from_orderitems(request.user,
|
||||||
|
request.data['orderitems'], vdata['start_date'], vdata['end_date'])
|
||||||
|
return Response()
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=False, perms_map={'post': 'utask.schedue'}, serializer_class=PkSerializer)
|
||||||
|
@transaction.atomic
|
||||||
|
def schedue_mtasks(self, request, *args, **kwargs):
|
||||||
|
"""大任务自动排产为小任务
|
||||||
|
|
||||||
|
大任务自动排产为小任务
|
||||||
|
"""
|
||||||
|
sr = PkSerializer(data=request.data)
|
||||||
|
sr.is_valid(raise_exception=True)
|
||||||
|
vdata = sr.validated_data
|
||||||
|
utasks = Utask.objects.filter(
|
||||||
|
id__in=vdata['ids'], state=Utask.UTASK_CREATED)
|
||||||
|
for i in utasks:
|
||||||
|
PmService.schedue_mtasks(request.user, i)
|
||||||
|
return Response()
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=False, perms_map={'post': 'utask.assgin'}, serializer_class=PkSerializer)
|
||||||
|
@transaction.atomic
|
||||||
|
def assgin(self, request):
|
||||||
|
"""下达任务
|
||||||
|
|
||||||
|
下达任务
|
||||||
|
"""
|
||||||
|
ids = request.data.get('ids', [])
|
||||||
|
utasks = Utask.objects.filter(id__in=ids)
|
||||||
|
Mtask.objects.filter(utask__in=utasks, state=Mtask.MTASK_CREATED).update(
|
||||||
|
state=Mtask.MTASK_ASSGINED)
|
||||||
|
utasks.filter(state=Utask.UTASK_CREATED).update(
|
||||||
|
state=Utask.UTASK_ASSGINED)
|
||||||
|
# 此处要更新订单状态
|
||||||
|
from apps.sam.models import OrderItem, Order
|
||||||
|
orderIds = OrderItem.objects.filter(
|
||||||
|
utask__in=utasks).values_list('order', flat=True).distinct()
|
||||||
|
Order.objects.filter(id__in=orderIds, state=Order.ORDER_SUBMITED).update(
|
||||||
|
state=Order.ORDER_DOING)
|
||||||
|
return Response()
|
||||||
|
|
||||||
|
|
||||||
class MtaskViewSet(CustomModelViewSet):
|
class MtaskViewSet(CustomModelViewSet):
|
||||||
"""
|
"""
|
||||||
list: 生产任务
|
list: 生产任务
|
||||||
|
@ -27,39 +91,25 @@ class MtaskViewSet(CustomModelViewSet):
|
||||||
ordering_fields = ['start_date', 'mgroup__process__sort']
|
ordering_fields = ['start_date', 'mgroup__process__sort']
|
||||||
ordering = ['-start_date', 'mgroup__process__sort', '-create_time']
|
ordering = ['-start_date', 'mgroup__process__sort', '-create_time']
|
||||||
|
|
||||||
@action(methods=['post'], detail=False, perms_map={'post': 'mtask.schedue'}, serializer_class=SchedueSerializer)
|
# @action(methods=['post'], detail=False, perms_map={'post': 'mtask.schedue'}, serializer_class=SchedueSerializer)
|
||||||
@transaction.atomic
|
# @transaction.atomic
|
||||||
def schedue_from_orderitems(self, request, *args, **kwargs):
|
# def schedue_from_orderitems(self, request, *args, **kwargs):
|
||||||
"""从多个订单明细自动排产
|
# """从多个订单明细自动排产
|
||||||
|
|
||||||
从多个订单明细自动排产
|
# 从多个订单明细自动排产
|
||||||
"""
|
# """
|
||||||
sr = SchedueSerializer(data=request.data)
|
# sr = SchedueSerializer(data=request.data)
|
||||||
sr.is_valid(raise_exception=True)
|
# sr.is_valid(raise_exception=True)
|
||||||
vdata = sr.validated_data
|
# vdata = sr.validated_data
|
||||||
PmService.schedue_from_orderitems(request.user,
|
# PmService.schedue_from_orderitems(request.user,
|
||||||
request.data['orderitems'], vdata['start_date'], vdata.get('end_date', None))
|
# request.data['orderitems'], vdata['start_date'], vdata.get('end_date', None))
|
||||||
return Response()
|
# return Response()
|
||||||
|
|
||||||
def perform_destroy(self, instance):
|
def perform_destroy(self, instance):
|
||||||
if instance.state != Mtask.MTASK_CREATED:
|
if instance.state != Mtask.MTASK_CREATED:
|
||||||
raise ParseError('该任务非创建中不可删除')
|
raise ParseError('该任务非创建中不可删除')
|
||||||
return super().perform_destroy(instance)
|
return super().perform_destroy(instance)
|
||||||
|
|
||||||
@action(methods=['post'], detail=False, perms_map={'post': 'mtask.assgin'}, serializer_class=PkSerializer)
|
|
||||||
@transaction.atomic
|
|
||||||
def assgin(self, request):
|
|
||||||
"""下达任务
|
|
||||||
|
|
||||||
下达任务
|
|
||||||
"""
|
|
||||||
ids = request.data.get('ids', [])
|
|
||||||
mtasks = Mtask.objects.filter(
|
|
||||||
id__in=ids, parent=None, state=Mtask.MTASK_CREATED)
|
|
||||||
mtasks = mtasks | Mtask.objects.filter(parent__in=mtasks)
|
|
||||||
mtasks.update(state=Mtask.MTASK_ASSGINED)
|
|
||||||
return Response()
|
|
||||||
|
|
||||||
@action(methods=['post'], detail=False, perms_map={'post': 'mtask.submit'}, serializer_class=PkSerializer)
|
@action(methods=['post'], detail=False, perms_map={'post': 'mtask.submit'}, serializer_class=PkSerializer)
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def submit(self, request):
|
def submit(self, request):
|
||||||
|
|
|
@ -9,5 +9,5 @@ class OrderItemFilter(filters.FilterSet):
|
||||||
fields = {
|
fields = {
|
||||||
"order": ["exact", "in"],
|
"order": ["exact", "in"],
|
||||||
"order__state": ["exact", "in"],
|
"order__state": ["exact", "in"],
|
||||||
"mtask": ["exact", "isnull"]
|
"utask": ["exact", "isnull"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Generated by Django 3.2.12 on 2023-10-19 10:12
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pm', '0007_auto_20231019_1812'),
|
||||||
|
('sam', '0004_alter_order_state'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='orderitem',
|
||||||
|
name='mtask',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='orderitem',
|
||||||
|
name='utask',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pm.utask', verbose_name='关联生产大任务'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -50,15 +50,13 @@ class Order(CommonBModel):
|
||||||
"""
|
"""
|
||||||
ORDER_CREATE = 10
|
ORDER_CREATE = 10
|
||||||
ORDER_SUBMITED = 20
|
ORDER_SUBMITED = 20
|
||||||
ORDER_PLANING = 30
|
ORDER_DOING = 30
|
||||||
ORDER_PLANED = 40
|
ORDER_DELIVERED = 40
|
||||||
ORDER_DELIVERED = 50
|
|
||||||
ORDER_STATES = (
|
ORDER_STATES = (
|
||||||
(10, '创建中'),
|
(10, '创建中'),
|
||||||
(20, '已提交'),
|
(20, '已提交'),
|
||||||
(30, '排产中'),
|
(30, '进行中'),
|
||||||
(40, '排产完成'),
|
(40, '已交付')
|
||||||
(50, '已交付')
|
|
||||||
)
|
)
|
||||||
state = models.PositiveSmallIntegerField(
|
state = models.PositiveSmallIntegerField(
|
||||||
'订单状态', default=ORDER_CREATE, choices=ORDER_STATES, help_text=str(ORDER_STATES))
|
'订单状态', default=ORDER_CREATE, choices=ORDER_STATES, help_text=str(ORDER_STATES))
|
||||||
|
@ -87,5 +85,5 @@ class OrderItem(BaseModel):
|
||||||
Material, verbose_name='所需产品', on_delete=models.CASCADE)
|
Material, verbose_name='所需产品', on_delete=models.CASCADE)
|
||||||
count = models.PositiveIntegerField('所需数量', default=1)
|
count = models.PositiveIntegerField('所需数量', default=1)
|
||||||
delivered_count = models.PositiveIntegerField('已交货数量', default=0)
|
delivered_count = models.PositiveIntegerField('已交货数量', default=0)
|
||||||
mtask = models.ForeignKey('pm.mtask', verbose_name='关联生产任务',
|
utask = models.ForeignKey('pm.utask', verbose_name='关联生产大任务',
|
||||||
on_delete=models.SET_NULL, null=True, blank=True)
|
on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
|
|
|
@ -3,6 +3,7 @@ from rest_framework.exceptions import ValidationError
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
from apps.inm.models import MIO, MIOItem
|
from apps.inm.models import MIO, MIOItem
|
||||||
|
|
||||||
|
|
||||||
class SamService:
|
class SamService:
|
||||||
|
|
||||||
def mio_saleout(mio: MIO):
|
def mio_saleout(mio: MIO):
|
||||||
|
@ -18,9 +19,10 @@ class SamService:
|
||||||
orderitem.delivered_count = delivered_count
|
orderitem.delivered_count = delivered_count
|
||||||
orderitem.save()
|
orderitem.save()
|
||||||
# 更新order的状态
|
# 更新order的状态
|
||||||
qs = OrderItem.objects.filter(order=order, count__lte=F('delivered_count'))
|
qs = OrderItem.objects.filter(
|
||||||
|
order=order, count__lte=F('delivered_count'))
|
||||||
if qs.exists():
|
if qs.exists():
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
order.state = Order.ORDER_DELIVERED
|
order.state = Order.ORDER_DELIVERED
|
||||||
order.save()
|
order.save()
|
||||||
|
|
|
@ -5,18 +5,18 @@ from celery import shared_task
|
||||||
from .models import Order, OrderItem
|
from .models import Order, OrderItem
|
||||||
|
|
||||||
|
|
||||||
@shared_task(base=CustomTask)
|
# @shared_task(base=CustomTask)
|
||||||
def change_order_state_when_schedue(orderitemIds):
|
# def change_order_state_when_schedue(orderitemIds):
|
||||||
"""排产后更新orderstate
|
# """排产后更新orderstate
|
||||||
"""
|
# """
|
||||||
orderIds = list(OrderItem.objects.filter(
|
# orderIds = list(OrderItem.objects.filter(
|
||||||
id__in=orderitemIds).values_list('order__id', flat=True).distinct())
|
# id__in=orderitemIds).values_list('order__id', flat=True).distinct())
|
||||||
for i in orderIds:
|
# for i in orderIds:
|
||||||
order = Order.objects.get(id=i)
|
# order = Order.objects.get(id=i)
|
||||||
state = Order.ORDER_PLANED
|
# state = Order.ORDER_PLANED
|
||||||
orderitems = OrderItem.objects.filter(order__id=i)
|
# orderitems = OrderItem.objects.filter(order__id=i)
|
||||||
for item in orderitems:
|
# for item in orderitems:
|
||||||
if item.mtask is None:
|
# if item.mtask is None:
|
||||||
state = Order.ORDER_PLANING
|
# state = Order.ORDER_PLANING
|
||||||
order.state = state
|
# order.state = state
|
||||||
order.save()
|
# order.save()
|
||||||
|
|
|
@ -137,20 +137,23 @@ def mlog_confirm(mlog: Mlog):
|
||||||
|
|
||||||
|
|
||||||
def update_mtask(mtask: Mtask):
|
def update_mtask(mtask: Mtask):
|
||||||
|
from apps.pm.models import Utask
|
||||||
res = Mlog.objects.filter(mtask=mtask).aggregate(sum_count_real=Sum(
|
res = Mlog.objects.filter(mtask=mtask).aggregate(sum_count_real=Sum(
|
||||||
'count_real'), sum_count_ok=Sum('count_ok'), sum_count_notok=Sum('count_notok'))
|
'count_real'), sum_count_ok=Sum('count_ok'), sum_count_notok=Sum('count_notok'))
|
||||||
mtask.count_real = res['sum_count_real'] if res['sum_count_real'] else 0
|
mtask.count_real = res['sum_count_real'] if res['sum_count_real'] else 0
|
||||||
mtask.count_ok = res['sum_count_ok'] if res['sum_count_ok'] else 0
|
mtask.count_ok = res['sum_count_ok'] if res['sum_count_ok'] else 0
|
||||||
mtask.count_notok = res['sum_count_notok'] if res['sum_count_notok'] else 0
|
mtask.count_notok = res['sum_count_notok'] if res['sum_count_notok'] else 0
|
||||||
mtask.save()
|
mtask.save()
|
||||||
if mtask.parent:
|
utask = mtask
|
||||||
fmtask = mtask.parent
|
if utask and mtask.material_out == utask.material:
|
||||||
res2 = Mtask.objects.filter(parent=fmtask).aggregate(sum_count_real=Sum(
|
res2 = Mtask.objects.filter(utask=utask, material_out=utask.material_out).aggregate(sum_count_real=Sum(
|
||||||
'count_real'), sum_count_ok=Sum('count_ok'), sum_count_notok=Sum('count_notok'))
|
'count_real'), sum_count_ok=Sum('count_ok'), sum_count_notok=Sum('count_notok'))
|
||||||
fmtask.count_real = res2['sum_count_real'] if res2['sum_count_real'] else 0
|
utask.count_real = res2['sum_count_real'] if res2['sum_count_real'] else 0
|
||||||
fmtask.count_ok = res2['sum_count_ok'] if res2['sum_count_ok'] else 0
|
utask.count_ok = res2['sum_count_ok'] if res2['sum_count_ok'] else 0
|
||||||
fmtask.count_notok = res2['sum_count_notok'] if res2['sum_count_notok'] else 0
|
utask.count_notok = res2['sum_count_notok'] if res2['sum_count_notok'] else 0
|
||||||
fmtask.save()
|
if utask.count_ok > 0 and utask.state == Utask.UTASK_ASSGINED:
|
||||||
if Mtask.objects.filter(parent=fmtask).exclude(state=Mtask.MTASK_DONE).count() == 0:
|
utask.state = Utask.UTASK_WORKING
|
||||||
fmtask.state = Mtask.MTASK_DONE
|
utask.save()
|
||||||
fmtask.save()
|
if Mtask.objects.filter(utask=utask).exclude(state=Mtask.MTASK_DONE).count() == 0:
|
||||||
|
utask.state = Mtask.MTASK_DONE
|
||||||
|
utask.save()
|
||||||
|
|
Loading…
Reference in New Issue