164 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			164 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Python
		
	
	
	
| from apps.mtm.models import Goal, Mgroup, RoutePack, Route
 | ||
| from django.core.cache import cache
 | ||
| from django.db.models import Q
 | ||
| from apps.mtm.models import Material, Process
 | ||
| from rest_framework.exceptions import ParseError
 | ||
| from apps.utils.tools import ranstr
 | ||
| from datetime import datetime
 | ||
| from apps.wf.models import Ticket
 | ||
| from django.db.models import Sum
 | ||
| from typing import List
 | ||
| 
 | ||
| def cal_material_count(materialId_list: List[str]=None):
 | ||
|     """
 | ||
|     计算物料总数量
 | ||
|     """
 | ||
|     from apps.inm.models import MaterialBatch
 | ||
|     from apps.wpm.models import WMaterial
 | ||
|     if materialId_list is None:
 | ||
|         materialId_list = []
 | ||
|     if materialId_list:
 | ||
|         objs = Material.objects.filter(id__in=set(materialId_list))
 | ||
|     else:
 | ||
|         objs = Material.objects.all()
 | ||
|     for material in objs:
 | ||
|         mb_count = MaterialBatch.objects.filter(material=material).aggregate(total=Sum("count"))["total"] or 0
 | ||
|         wm_count = WMaterial.objects.filter(material=material).aggregate(total=Sum("count"))["total"] or 0
 | ||
|         if mb_count is None:
 | ||
|             mb_count = 0
 | ||
|         if wm_count is None:
 | ||
|             wm_count = 0
 | ||
|         Material.objects.filter(id=material.id).update(
 | ||
|             count_wm=wm_count,
 | ||
|             count_mb=mb_count,
 | ||
|             count=mb_count + wm_count)
 | ||
| 
 | ||
| def get_mgroup_goals(mgroupId, year, reload=False):
 | ||
|     """
 | ||
|     获取工段某年的全部目标值, 以字典形式返回, 带缓存
 | ||
|     """
 | ||
|     goals = Goal.objects.filter(
 | ||
|         Q(mgroup__id=mgroupId) | Q(mgroup__name=mgroupId), year=year)
 | ||
|     key = f'mgroup_{mgroupId}_goals'
 | ||
|     if reload is False:
 | ||
|         mgroup_goals = cache.get(key, None)
 | ||
|         if mgroup_goals is not None:
 | ||
|             return mgroup_goals
 | ||
|     mgroup_goals = {}
 | ||
|     for goal in goals:
 | ||
|         mgroup_goals[f'{goal.goal_cate.code}_year'] = goal.goal_val
 | ||
|         for i in range(12):
 | ||
|             mgroup_goals[f'{goal.goal_cate.code}_{i+1}'] = getattr(
 | ||
|                 goal, f'goal_val_{i+1}')
 | ||
|     cache.set(key, mgroup_goals, 10)
 | ||
|     return mgroup_goals
 | ||
| 
 | ||
| 
 | ||
| def daoru_material(path: str):
 | ||
|     """
 | ||
|     导入物料信息
 | ||
|     """
 | ||
|     type_dict = {'主要原料': 30, '半成品': 20, '成品': 10,
 | ||
|                  '辅助材料': 40, '加工工具': 50, '辅助工装': 60, '办公用品': 70}
 | ||
|     from apps.utils.snowflake import idWorker
 | ||
|     from openpyxl import load_workbook
 | ||
|     wb = load_workbook(path)
 | ||
|     sheet = wb.get_sheet_by_name('物料')
 | ||
|     process_l = Process.objects.all()
 | ||
|     process_d = {p.name: p for p in process_l}
 | ||
|     i = 3
 | ||
|     while sheet[f'a{i}'].value is not None:
 | ||
|         type_str = sheet[f'a{i}'].value.replace(' ', '')
 | ||
|         try:
 | ||
|             type = type_dict[type_str]
 | ||
|             name = sheet[f'b{i}'].value.replace(' ', '')
 | ||
|             specification = sheet[f'c{i}'].value.replace(
 | ||
|                 '×', '*').replace(' ', '')
 | ||
|             model = sheet[f'd{i}'].value.replace(' ', '')
 | ||
|             unit = sheet[f'e{i}'].value.replace(' ', '')
 | ||
|             count_safe = sheet[f'g{i}'].value
 | ||
|             unit_price = sheet[f'h{i}'].value
 | ||
|         except Exception as e:
 | ||
|             raise ParseError(f'{i}行物料信息错误: {str(e)}')
 | ||
|         if type in [20, 30]:
 | ||
|             try:
 | ||
|                 process = process_d[sheet[f'f{i}'].value.replace(' ', '')]
 | ||
|             except Exception as e:
 | ||
|                 raise ParseError(f'{i}行物料信息错误: {str(e)}')
 | ||
|         try:
 | ||
|             filters = {'type': type, 'name': name, 'specification': specification,
 | ||
|                        'model': model, 'unit__iexact': unit}
 | ||
|             if type in [20, 30]:
 | ||
|                 filters['process'] = process
 | ||
|             default = {'type': type, 'name': name, 'specification': specification,
 | ||
|                        'model': model, 'unit': unit, 'number': f'm{type}_{ranstr(6)}', 'id': idWorker.get_id(), 
 | ||
|                        'count_safe': count_safe, 'unit_price': unit_price}
 | ||
|             material, is_created = Material.objects.get_or_create(
 | ||
|                 **filters, defaults=default)
 | ||
|             if not is_created:
 | ||
|                 material.count_safe = count_safe
 | ||
|                 material.save()
 | ||
|         except Exception as e:
 | ||
|             raise ParseError(f'{i}行物料有误, 导入失败--{e}')
 | ||
|         i = i + 1
 | ||
|         print(type, name, specification, model, unit, '导入成功')
 | ||
| 
 | ||
| 
 | ||
| def mgroup_run_change(mgroup: Mgroup, new_run: bool, last_timex: datetime):
 | ||
|     """
 | ||
|     调用工段运行变动
 | ||
|     """
 | ||
|     from apps.wpm.services import get_sflog
 | ||
|     from apps.wpm.tasks import cal_exp_duration_sec
 | ||
|     from apps.wpm.models import StLog
 | ||
|     mgroup.is_running = new_run
 | ||
|     mgroup.save(update_fields=["is_running"])
 | ||
| 
 | ||
|     last_stlog = StLog.objects.filter(mgroup=mgroup, is_shutdown=True).order_by("-start_time").first()  # 找到最后一次停机记录
 | ||
| 
 | ||
|     if last_stlog:
 | ||
|         if last_timex >= last_stlog.start_time:  # 认为是有效信号
 | ||
|             if last_stlog.end_time is None and new_run:  # 从停到开
 | ||
|                 last_stlog.end_time = last_timex
 | ||
|                 last_stlog.duration_sec = (last_stlog.end_time - last_stlog.start_time).total_seconds()
 | ||
|                 last_stlog.save()
 | ||
|                 cal_exp_duration_sec(last_stlog.id)  # 触发时间分配
 | ||
|             elif last_stlog.end_time and new_run is False and last_timex > last_stlog.end_time:  # 从开到停
 | ||
|                 has_same_stlog =StLog.objects.filter(mgroup=mgroup, is_shutdown=True, start_time=last_timex).exists()
 | ||
|                 if not has_same_stlog:
 | ||
|                     StLog.objects.create(title="停机", is_shutdown=True, mgroup=mgroup, end_time=None, start_time=last_timex, sflog=get_sflog(mgroup, last_timex))
 | ||
|     elif new_run is False:
 | ||
|         StLog.objects.create(title="停机", is_shutdown=True, mgroup=mgroup, end_time=None, start_time=last_timex, sflog=get_sflog(mgroup, last_timex))
 | ||
|         mgroup.is_running = False
 | ||
|         mgroup.save()
 | ||
| 
 | ||
| def bind_routepack(ticket: Ticket, transition, new_ticket_data: dict):
 | ||
|     routepack = RoutePack.objects.get(id=new_ticket_data['t_id'])
 | ||
|     if routepack.ticket and routepack.ticket.id!=ticket.id:
 | ||
|         raise ParseError('重复创建工单')
 | ||
|     if not Route.objects.filter(routepack=routepack).exists():
 | ||
|         raise ParseError('缺少步骤')
 | ||
|     ticket_data = ticket.ticket_data
 | ||
|     ticket_data.update({
 | ||
|         't_model': 'routepack',
 | ||
|         't_id': routepack.id,
 | ||
|     })
 | ||
|     ticket.ticket_data = ticket_data
 | ||
|     ticket.create_by = routepack.create_by
 | ||
|     ticket.save()
 | ||
|     if routepack.ticket is None:
 | ||
|         routepack.ticket = ticket
 | ||
|         routepack.state = RoutePack.RP_S_AUDIT
 | ||
|         routepack.save()
 | ||
| 
 | ||
| 
 | ||
| def routepack_audit_end(ticket: Ticket):
 | ||
|     routepack = RoutePack.objects.get(id=ticket.ticket_data['t_id'])
 | ||
|     routepack.state = RoutePack.RP_S_CONFIRM
 | ||
|     routepack.save()
 | ||
| 
 | ||
| def routepack_ticket_change(ticket: Ticket):
 | ||
|     routepack = RoutePack.objects.get(id=ticket.ticket_data['t_id'])
 | ||
|     if ticket.act_state == Ticket.TICKET_ACT_STATE_DRAFT:
 | ||
|         routepack.state = RoutePack.RP_S_CREATE
 | ||
|         routepack.save() |