179 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			179 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Python
		
	
	
	
| from apps.inm.models import MIO, MIOItem, MaterialBatch, MaterialBatchA, MIOItemA, WareHouse
 | ||
| from rest_framework.exceptions import ValidationError, ParseError
 | ||
| from django.db.models.aggregates import Sum
 | ||
| from django.db.models import F
 | ||
| from apps.wpm.services import do_out, do_in
 | ||
| from apps.mtm.models import Material, Process
 | ||
| from apps.utils.tools import ranstr
 | ||
| from apps.system.models import Dept
 | ||
| 
 | ||
| 
 | ||
| class InmService:
 | ||
|     @classmethod
 | ||
|     def update_inm(cls, instance: MIO, is_reverse: bool = False):
 | ||
|         """
 | ||
|         更新库存, 支持反向操作
 | ||
|         """
 | ||
|         if instance.type in [MIO.MIO_TYPE_PUR_IN, MIO.MIO_TYPE_DO_IN, MIO.MIO_TYPE_OTHER_IN]:  # 采购入库, 生产入库, 其他入库
 | ||
|             in_or_out = 1
 | ||
|             if is_reverse:
 | ||
|                 in_or_out = -1
 | ||
|             cls.update_mb(instance, in_or_out)
 | ||
|             if instance.type == MIO.MIO_TYPE_PUR_IN:  # 需要更新订单
 | ||
|                 from apps.pum.services import PumService
 | ||
| 
 | ||
|                 PumService.mio_purin(instance, is_reverse)
 | ||
|             elif instance.type == MIO.MIO_TYPE_DO_IN:
 | ||
|                 if is_reverse:
 | ||
|                     do_out(instance)
 | ||
|                 else:
 | ||
|                     do_in(instance)
 | ||
|         elif instance.type in [MIO.MIO_TYPE_DO_OUT, MIO.MIO_TYPE_SALE_OUT, MIO.MIO_TYPE_OTHER_OUT]:  # 生产领料 销售出库
 | ||
|             in_or_out = -1
 | ||
|             if is_reverse:
 | ||
|                 in_or_out = 1
 | ||
|             cls.update_mb(instance, in_or_out)
 | ||
|             if instance.type == MIO.MIO_TYPE_SALE_OUT:
 | ||
|                 from apps.sam.services import SamService
 | ||
| 
 | ||
|                 SamService.mio_saleout(instance, is_reverse)
 | ||
|             elif instance.type == MIO.MIO_TYPE_DO_OUT:
 | ||
|                 if is_reverse:
 | ||
|                     do_in(instance)
 | ||
|                 else:
 | ||
|                     do_out(instance)
 | ||
| 
 | ||
|     @classmethod
 | ||
|     def cal_mat_count(cls, material: Material):
 | ||
|         mb_count = MaterialBatch.objects.filter(material=material).aggregate(total=Sum("count"))["total"]
 | ||
|         from apps.wpm.models import WMaterial
 | ||
|         wm_count = WMaterial.objects.filter(material=material).aggregate(total=Sum("count"))["total"]
 | ||
|         if mb_count is None:
 | ||
|             mb_count = 0
 | ||
|         if wm_count is None:
 | ||
|             wm_count = 0
 | ||
|         Material.objects.filter(id=material.id).update(
 | ||
|             count_mb=mb_count,
 | ||
|             count=mb_count + wm_count)
 | ||
| 
 | ||
|     @classmethod
 | ||
|     def update_mb(cls, instance: MIO, in_or_out: int = 1):
 | ||
|         """
 | ||
|         更新物料批次
 | ||
|         in = 1
 | ||
|         out = -1
 | ||
|         """
 | ||
|         mioitems = MIOItem.objects.filter(mio=instance)
 | ||
|         if not mioitems.exists():
 | ||
|             raise ParseError("未填写物料明细")
 | ||
|         type = instance.type
 | ||
|         belong_dept = instance.belong_dept
 | ||
|         for i in MIOItem.objects.filter(mio=instance):
 | ||
|            cls.update_mb_item(i,  in_or_out, 'count', type, belong_dept)
 | ||
| 
 | ||
|     @classmethod
 | ||
|     def update_mb_item(cls, i: MIOItem, in_or_out: int = 1, field:str='count', type: str =None, belong_dept: Dept=None):
 | ||
|         """
 | ||
|         更新物料批次(根据明细)
 | ||
|         in = 1
 | ||
|         out = -1
 | ||
|         默认使用count字段做加减
 | ||
|         """
 | ||
|         if type is None or belong_dept is None:
 | ||
|             mio = i.mio
 | ||
|             type = mio.type
 | ||
|             belong_dept = mio.belong_dept
 | ||
|         material = i.material
 | ||
|         warehouse = i.warehouse
 | ||
|         mb, is_created = MaterialBatch.objects.get_or_create(
 | ||
|             material=material, warehouse=warehouse, batch=i.batch, defaults={"material": material, "warehouse": warehouse, "count": 0, "batch": i.batch}
 | ||
|         )
 | ||
|         if in_or_out == 1:
 | ||
|             mb.count = mb.count + getattr(i, field)
 | ||
|             if type == MIO.MIO_TYPE_DO_IN:  # 生产入库需要记录production_dept字段
 | ||
|                 if mb.production_dept is None or mb.production_dept == belong_dept:
 | ||
|                     mb.production_dept = belong_dept
 | ||
|                 else:
 | ||
|                     raise ParseError("同种物料不同生产车间应该有不同批次号!")
 | ||
|             mb.save()
 | ||
|             mias = MIOItemA.objects.filter(mioitem=i)
 | ||
|             if mias.exists():  # 组合件入库
 | ||
|                 if not is_created:
 | ||
|                     raise ParseError("该批次组合件已存在")
 | ||
|                 for mia in mias:
 | ||
|                     MaterialBatchA.objects.create(mb=mb, material=mia.material, batch=mia.batch)
 | ||
|         elif in_or_out == -1:
 | ||
|             mb.count = mb.count - getattr(i, field)
 | ||
|             if mb.count < 0:
 | ||
|                 raise ParseError("批次库存不足,操作失败")
 | ||
|             elif mb.count == 0:
 | ||
|                 mb.delete()
 | ||
|             else:
 | ||
|                 mb.save()
 | ||
|         else:
 | ||
|             raise ParseError("不支持的操作")
 | ||
|         cls.cal_mat_count(material)
 | ||
|     
 | ||
| 
 | ||
| def daoru_mb(path: str):
 | ||
|     """
 | ||
|     导入物料批次(如没有物料自动创建)
 | ||
|     """
 | ||
|     # 注释的是初次导入时做的数据矫正
 | ||
|     # objs1 = Material.objects.filter(specification__contains=' ')
 | ||
|     # for i in objs1:
 | ||
|     #     i.specification = i.specification.replace(' ', '')
 | ||
|     #     i.save()
 | ||
|     # objs2 = Material.objects.filter(specification__contains='×')
 | ||
|     # for i in objs2:
 | ||
|     #     i.specification = i.specification.replace('×', '*')
 | ||
|     #     i.save()
 | ||
|     # objs3 = (Material.objects.filter(
 | ||
|     #     specification__contains='优级') | Material.objects.filter(specification__contains='一级')).exclude(specification__contains='|')
 | ||
|     # for i in objs3:
 | ||
|     #     i.specification = i.specification.replace(
 | ||
|     #         '优级', '|优级').replace('一级', '|一级')
 | ||
|     #     i.save()
 | ||
|     type_dict = {"主要原料": 30, "半成品": 20, "成品": 10, "辅助材料": 40, "加工工具": 50, "辅助工装": 60, "办公用品": 70}
 | ||
|     from apps.utils.snowflake import idWorker
 | ||
|     from openpyxl import load_workbook
 | ||
| 
 | ||
|     wb = load_workbook(path)
 | ||
|     process_l = Process.objects.all()
 | ||
|     process_d = {p.name: p for p in process_l}
 | ||
|     warehouse_l = WareHouse.objects.all()
 | ||
|     warehouse_d = {w.name: w for w in warehouse_l}
 | ||
|     for sheet in wb.worksheets:
 | ||
|         i = 3
 | ||
|         while sheet[f"a{i}"].value:
 | ||
|             try:
 | ||
|                 type = type_dict[sheet[f"a{i}"].value.replace(" ", "")]
 | ||
|                 name = sheet[f"b{i}"].value.replace(" ", "")
 | ||
|                 specification = sheet[f"c{i}"].value.replace(" ", "")
 | ||
|                 if sheet[f"d{i}"].value and sheet[f"d{i}"].value.replace(" ", ""):
 | ||
|                     specification = specification + "|" + sheet[f"d{i}"].value.replace(" ", "")
 | ||
|                 model = sheet[f"e{i}"].value.replace(" ", "")
 | ||
|                 process = process_d[sheet[f"f{i}"].value.replace(" ", "")]
 | ||
|                 batch = sheet[f"g{i}"].value.replace(" ", "")
 | ||
|                 count = int(sheet[f"h{i}"].value)
 | ||
|                 warehouse = warehouse_d[sheet[f"i{i}"].value.replace(" ", "")]
 | ||
|             except KeyError as e:
 | ||
|                 raise ParseError(f"第{i}行数据有误:{str(e)}")
 | ||
|             material, _ = Material.objects.get_or_create(
 | ||
|                 type=type,
 | ||
|                 name=name,
 | ||
|                 specification=specification,
 | ||
|                 model=model,
 | ||
|                 process=process,
 | ||
|                 defaults={"type": type, "name": name, "specification": specification, "model": model, "process": process, "number": ranstr(6), "id": idWorker.get_id()},
 | ||
|             )
 | ||
|             mb, is_created = MaterialBatch.objects.get_or_create(
 | ||
|                 material=material, batch=batch, warehouse=warehouse, defaults={"material": material, "batch": batch, "warehouse": warehouse, "count": count, "id": idWorker.get_id()}
 | ||
|             )
 | ||
|             InmService.cal_mat_count(material)
 | ||
|             # if not is_created:
 | ||
|             #     mb.count += count
 | ||
|             #     mb.save()
 | ||
|             print(f"第{i}行数据导入成功")
 | ||
|             i = i + 1
 |