315 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			315 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Python
		
	
	
	
import datetime
 | 
						|
 | 
						|
from django.core.cache import cache
 | 
						|
from django.db.models import Sum
 | 
						|
from django.utils import timezone
 | 
						|
from typing import Union
 | 
						|
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
 | 
						|
 | 
						|
from rest_framework.exceptions import ParseError
 | 
						|
 | 
						|
from apps.system.models import User
 | 
						|
from apps.inm.models import MIO, MIOItem, MIOItemA
 | 
						|
from apps.pm.models import Mtask
 | 
						|
from apps.mtm.models import Mgroup, Shift, Material, Route
 | 
						|
 | 
						|
from .models import SfLog, SfLogExp, WMaterial, Mlog, Mlogb, Handover
 | 
						|
 | 
						|
 | 
						|
def get_sflog(mgroup: Mgroup, happen_time: datetime):
 | 
						|
    sflog = SfLog.objects.filter(
 | 
						|
        start_time__lt=happen_time, end_time__gte=happen_time, mgroup=mgroup).first()
 | 
						|
    if sflog is None:  # 需要创建值班记录
 | 
						|
        make_sflogs(mgroup=mgroup, start_date=(
 | 
						|
            happen_time-datetime.timedelta(days=1)).date(), end_date=happen_time.date())
 | 
						|
        sflog = SfLog.objects.filter(
 | 
						|
            start_time__lt=happen_time, end_time__gte=happen_time, mgroup=mgroup).order_by('-start_time').first()
 | 
						|
    return sflog
 | 
						|
 | 
						|
 | 
						|
def make_sflogs(mgroup: Mgroup, start_date: datetime.date, end_date: datetime.date, create_by=None):
 | 
						|
    shift_rule = mgroup.shift_rule
 | 
						|
    shifts = Shift.objects.filter(rule=shift_rule)  # 根据排班规则制定排班记录
 | 
						|
    for shift in shifts:
 | 
						|
        start_time_o = shift.start_time_o
 | 
						|
        end_time_o = shift.end_time_o
 | 
						|
        current_date = start_date
 | 
						|
        while current_date <= end_date:
 | 
						|
            start_time = datetime.datetime.combine(current_date, start_time_o)
 | 
						|
            end_time = datetime.datetime.combine(current_date, end_time_o)
 | 
						|
            if start_time > end_time:
 | 
						|
                start_time -= datetime.timedelta(days=1)
 | 
						|
            duration = end_time - start_time
 | 
						|
            total_hour = duration.total_seconds() / 3600
 | 
						|
            SfLog.objects.get_or_create(mgroup=mgroup, shift=shift, start_time=start_time, defaults={
 | 
						|
                "mgroup": mgroup,
 | 
						|
                "shift": shift,
 | 
						|
                "work_date": current_date,
 | 
						|
                "start_time": start_time,
 | 
						|
                "end_time": end_time,
 | 
						|
                "total_hour_now": total_hour,
 | 
						|
                "total_hour": total_hour,
 | 
						|
                "create_by": create_by
 | 
						|
            })
 | 
						|
            current_date = current_date + datetime.timedelta(days=1)
 | 
						|
 | 
						|
 | 
						|
def get_pcoal_heat(year_s: int, month_s: int, day_s: int):
 | 
						|
    """
 | 
						|
    获取煤粉热值
 | 
						|
    只有回转窑需要录入煤粉热值
 | 
						|
    """
 | 
						|
    key = f'pgoal_val_{year_s}_{month_s}_{day_s}'
 | 
						|
    pcoal_heat = cache.get(key, None)
 | 
						|
    if pcoal_heat is not None:
 | 
						|
        return pcoal_heat
 | 
						|
    else:
 | 
						|
        try:
 | 
						|
            qs = SfLog.objects.get(end_time__year=year_s, end_time__month=month_s, end_time__day=day_s,
 | 
						|
                                   mgroup__name='回转窑', shift__name='白班')
 | 
						|
            if qs.pcoal_heat is None:
 | 
						|
                qs.pcoal_heat = 0
 | 
						|
                qs.save()
 | 
						|
            cache.set(f'pgoal_val_{year_s}_{month_s}_{day_s}', qs.pcoal_heat)
 | 
						|
            return qs.pcoal_heat
 | 
						|
        except Exception:
 | 
						|
            return 0
 | 
						|
 | 
						|
 | 
						|
def do_out(mio: MIO):
 | 
						|
    """
 | 
						|
    生产领料到车间
 | 
						|
    """
 | 
						|
    belong_dept = mio.belong_dept
 | 
						|
    do_user = mio.do_user
 | 
						|
    mioitems = MIOItem.objects.filter(mio=mio)
 | 
						|
    for item in mioitems:
 | 
						|
        action_list = []
 | 
						|
        mias = MIOItemA.objects.filter(mioitem=item)
 | 
						|
        if mias.exists():  # 组合件入库
 | 
						|
            mias_list = list(mias.values_list('material', 'batch', 'rate'))
 | 
						|
            for i in range(len(mias_list)):
 | 
						|
                material, batch, rate = mias_list[i]
 | 
						|
                new_count = rate * item.count  # 假设 item.count 存在
 | 
						|
                action_list.append([material, batch, new_count])
 | 
						|
        else:
 | 
						|
            action_list = [[item.material, item.batch, item.count]]
 | 
						|
        for al in action_list:
 | 
						|
            xmaterial, xbatch, xcount = al
 | 
						|
            wm, new_create = WMaterial.objects.get_or_create(batch=xbatch, material=xmaterial,
 | 
						|
                                                             belong_dept=belong_dept, defaults={
 | 
						|
                                                                 "batch": xbatch,
 | 
						|
                                                                 "material": xmaterial,
 | 
						|
                                                                 "count": xcount,
 | 
						|
                                                                 "create_by": do_user,
 | 
						|
                                                                 "belong_dept": belong_dept
 | 
						|
                                                             })
 | 
						|
            if not new_create:
 | 
						|
                wm.count = wm.count + item.count
 | 
						|
                wm.update_by = do_user
 | 
						|
                wm.save()
 | 
						|
 | 
						|
 | 
						|
def do_in(mio: MIO):
 | 
						|
    """
 | 
						|
    生产入库后更新车间物料
 | 
						|
    """
 | 
						|
    belong_dept = mio.belong_dept
 | 
						|
    do_user = mio.do_user
 | 
						|
    mioitems = MIOItem.objects.filter(mio=mio)
 | 
						|
    for item in mioitems:
 | 
						|
        action_list = []
 | 
						|
        mias = MIOItemA.objects.filter(mioitem=item)
 | 
						|
        if mias.exists():  # 组合件入库
 | 
						|
            mias_list = list(mias.values_list('material', 'batch', 'rate'))
 | 
						|
            for i in range(len(mias_list)):
 | 
						|
                material, batch, rate = mias_list[i]
 | 
						|
                new_count = rate * item.count  # 假设 item.count 存在
 | 
						|
                action_list.append([material, batch, new_count])
 | 
						|
        else:
 | 
						|
            action_list = [[item.material, item.batch, item.count]]
 | 
						|
        for al in action_list:
 | 
						|
            xmaterial, xbatch, xcount = al
 | 
						|
            try:
 | 
						|
                wm = WMaterial.objects.get(
 | 
						|
                    batch=xbatch, material=xmaterial, belong_dept=belong_dept)
 | 
						|
            except ObjectDoesNotExist:
 | 
						|
                raise ParseError(f'{str(xmaterial)}-{xbatch}车间物料不存在!')
 | 
						|
            except MultipleObjectsReturned:
 | 
						|
                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()
 | 
						|
            elif new_count == 0:
 | 
						|
                wm.delete()
 | 
						|
            else:
 | 
						|
                raise ParseError(f'{str(xmaterial)}-{xbatch}车间物料不足')
 | 
						|
 | 
						|
 | 
						|
def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
 | 
						|
    """
 | 
						|
    生产日志提交后需要执行的操作
 | 
						|
    """
 | 
						|
    if mlog.submit_time is not None:
 | 
						|
        return
 | 
						|
    if now is None:
 | 
						|
        now = timezone.now()
 | 
						|
    if now.date() < mlog.handle_date:
 | 
						|
        raise ParseError('不可提交未来的日志')
 | 
						|
    belong_dept = mlog.mgroup.belong_dept
 | 
						|
    material_out = mlog.material_out
 | 
						|
    material_in = mlog.material_in
 | 
						|
    if material_in:  # 需要进行车间库存管理
 | 
						|
        # 需要判断领用数是否合理
 | 
						|
        material_has_qs = WMaterial.objects.filter(
 | 
						|
            batch=mlog.batch, material=material_in, belong_dept=belong_dept)
 | 
						|
        count_x = material_has_qs.count()
 | 
						|
        if count_x == 1:
 | 
						|
            material_has = material_has_qs.first()
 | 
						|
        elif count_x == 0:
 | 
						|
            raise ParseError(
 | 
						|
                f'{str(material_in)}-{mlog.batch}-批次库存不存在!')
 | 
						|
        else:
 | 
						|
            raise ParseError(
 | 
						|
                f'{str(material_in)}-{mlog.batch}-存在多个相同批次!')
 | 
						|
        if mlog.count_use > material_has.count:
 | 
						|
            raise ParseError(
 | 
						|
                f'{str(material_in)}-{mlog.batch}-该批次车间库存不足!')
 | 
						|
        else:
 | 
						|
            material_has.count = material_has.count - mlog.count_use
 | 
						|
            if material_has.count == 0:
 | 
						|
                material_has.delete()
 | 
						|
            else:
 | 
						|
                material_has.save()
 | 
						|
    if material_out:  # 需要入车间库存
 | 
						|
        # 有多个产物的情况
 | 
						|
        if material_out.brothers and Mlogb.objects.filter(mlog=mlog).exists():
 | 
						|
            for item in Mlogb.objects.filter(mlog=mlog):
 | 
						|
                wmaterial, _ = WMaterial.objects.get_or_create(batch=mlog.batch, material=item.material_out, belong_dept=belong_dept, defaults={
 | 
						|
                    'batch': mlog.batch, 'material': item.material_out, 'belong_dept': belong_dept
 | 
						|
                })
 | 
						|
                wmaterial.count = wmaterial.count + item.count_ok
 | 
						|
                if hasattr(item, 'count_real_eweight'):
 | 
						|
                    wmaterial.count_eweight = item.count_real_eweight
 | 
						|
                wmaterial.save()
 | 
						|
        else:
 | 
						|
            wmaterial, _ = WMaterial.objects.get_or_create(batch=mlog.batch, material=material_out, belong_dept=belong_dept, defaults={
 | 
						|
                'batch': mlog.batch, 'material': material_out, 'belong_dept': belong_dept
 | 
						|
            })
 | 
						|
            wmaterial.count = wmaterial.count + mlog.count_ok
 | 
						|
            wmaterial.count_eweight = mlog.count_real_eweight
 | 
						|
            wmaterial.save()
 | 
						|
    mlog.submit_time = now
 | 
						|
    mlog.submit_user = user
 | 
						|
    mlog.save()
 | 
						|
 | 
						|
 | 
						|
def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
 | 
						|
    """日志撤回
 | 
						|
    """
 | 
						|
    if mlog.submit_time is None:
 | 
						|
        return
 | 
						|
    if now is None:
 | 
						|
        now = timezone.now()
 | 
						|
    belong_dept = mlog.mgroup.belong_dept
 | 
						|
    material_out = mlog.material_out
 | 
						|
    material_in = mlog.material_in
 | 
						|
    if material_in:
 | 
						|
        # 领用数退回
 | 
						|
        wmaterial, _ = WMaterial.objects.get_or_create(batch=mlog.batch, material=material_in, belong_dept=belong_dept, defaults={
 | 
						|
            'batch': mlog.batch, 'material': material_in, 'belong_dept': belong_dept})
 | 
						|
        wmaterial.count = wmaterial.count + mlog.count_use
 | 
						|
        wmaterial.save()
 | 
						|
    if material_out:  # 产物退回
 | 
						|
        # 有多个产物的情况
 | 
						|
        if material_out.brothers and Mlogb.objects.filter(mlog=mlog).exists():
 | 
						|
            for item in Mlogb.objects.filter(mlog=mlog):
 | 
						|
                wmaterial, _ = WMaterial.objects.get_or_create(batch=mlog.batch, material=item.material_out, belong_dept=belong_dept, defaults={
 | 
						|
                    'batch': mlog.batch, 'material': item.material_out, 'belong_dept': belong_dept
 | 
						|
                })
 | 
						|
                wmaterial.count = wmaterial.count - item.count_ok
 | 
						|
                if wmaterial.count < 0:
 | 
						|
                    raise ParseError('车间库存不足, 产物无法回退')
 | 
						|
                elif wmaterial.count == 0:
 | 
						|
                    wmaterial.delete()
 | 
						|
                else:
 | 
						|
                    wmaterial.save()
 | 
						|
        else:
 | 
						|
            wmaterial, _ = WMaterial.objects.get_or_create(batch=mlog.batch, material=material_out, belong_dept=belong_dept, defaults={
 | 
						|
                'batch': mlog.batch, 'material': material_out, 'belong_dept': belong_dept
 | 
						|
            })
 | 
						|
            wmaterial.count = wmaterial.count - mlog.count_ok
 | 
						|
            if wmaterial.count < 0:
 | 
						|
                raise ParseError('车间库存不足, 产物无法回退')
 | 
						|
            elif wmaterial.count == 0:
 | 
						|
                wmaterial.delete()
 | 
						|
            else:
 | 
						|
                wmaterial.save()
 | 
						|
    mlog.submit_time = None
 | 
						|
    mlog.submit_user = None
 | 
						|
    mlog.save()
 | 
						|
 | 
						|
 | 
						|
def update_mtask(mtask: Mtask):
 | 
						|
    from apps.pm.models import Utask
 | 
						|
    res = Mlog.objects.filter(mtask=mtask).exclude(submit_time=None).aggregate(sum_count_real=Sum(
 | 
						|
        '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_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.save()
 | 
						|
    utask = mtask.utask
 | 
						|
    if utask and mtask.is_count_utask:
 | 
						|
        res2 = Mtask.objects.filter(utask=utask, mgroup=mtask.mgroup).aggregate(sum_count_real=Sum(
 | 
						|
            'count_real'), sum_count_ok=Sum('count_ok'), sum_count_notok=Sum('count_notok'))
 | 
						|
        utask.count_real = res2['sum_count_real'] if res2['sum_count_real'] else 0
 | 
						|
        utask.count_ok = res2['sum_count_ok'] if res2['sum_count_ok'] else 0
 | 
						|
        utask.count_notok = res2['sum_count_notok'] if res2['sum_count_notok'] else 0
 | 
						|
        if utask.count_ok > 0 and utask.state == Utask.UTASK_ASSGINED:
 | 
						|
            utask.state = Utask.UTASK_WORKING
 | 
						|
        if Mtask.objects.filter(utask=utask).exclude(state=Mtask.MTASK_SUBMIT).count() == 0:
 | 
						|
            utask.state = Utask.UTASK_SUBMIT
 | 
						|
        utask.save()
 | 
						|
 | 
						|
 | 
						|
def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime, None]):
 | 
						|
    """
 | 
						|
    交接提交后需要执行的操作
 | 
						|
    """
 | 
						|
    if handover.submit_time is not None:
 | 
						|
        return
 | 
						|
    now = timezone.now()
 | 
						|
    need_add = True
 | 
						|
    wm_from_need_delete = False
 | 
						|
    material = handover.material
 | 
						|
    batch = handover.batch
 | 
						|
    try:
 | 
						|
        wm_from = WMaterial.objects.get(
 | 
						|
            material=material, batch=batch, belong_dept=handover.send_dept)
 | 
						|
    except Exception as e:
 | 
						|
        raise ParseError(f'找不到车间库存:{e}')
 | 
						|
    if '混料' in material.name:  # hard code
 | 
						|
        need_add = False
 | 
						|
    count_x = wm_from.count - handover.count
 | 
						|
    if count_x < 0:
 | 
						|
        raise ParseError('车间库存不足!')
 | 
						|
    elif count_x == 0:
 | 
						|
        wm_from_need_delete = True
 | 
						|
    else:
 | 
						|
        wm_from.count = count_x
 | 
						|
        wm_from.save()
 | 
						|
    if need_add:
 | 
						|
        wm_to, _ = WMaterial.objects.get_or_create(batch=batch, material=material, belong_dept=handover.recive_dept, defaults={
 | 
						|
            'batch': batch, 'material': material, 'belong_dept': handover.recive_dept
 | 
						|
        })
 | 
						|
        wm_to.count = wm_to.count + handover.count
 | 
						|
        wm_to.count_eweight = handover.count_eweight
 | 
						|
        wm_to.save()
 | 
						|
    handover.submit_user = user
 | 
						|
    handover.submit_time = now
 | 
						|
    handover.save()
 | 
						|
    if wm_from_need_delete:
 | 
						|
        wm_from.delete()
 |