187 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			187 lines
		
	
	
		
			8.0 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
 | ||
| 
 | ||
| 
 | ||
| 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):
 | ||
|         material_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 material_count is None:
 | ||
|             material_count = 0
 | ||
|         if wm_count is None:
 | ||
|             wm_count = 0
 | ||
|         Material.objects.filter(id=material.id).update(
 | ||
|             count=material_count+wm_count)
 | ||
|         
 | ||
|     @classmethod
 | ||
|     def update_mb(cls, instance: MIO, in_or_out: int = 1):
 | ||
|         """
 | ||
|         更新物料批次
 | ||
|         in = 1
 | ||
|         out = -1
 | ||
|         """
 | ||
|         belong_dept = instance.belong_dept
 | ||
|         mioitems = MIOItem.objects.filter(mio=instance)
 | ||
|         if not mioitems.exists():
 | ||
|             raise ParseError('未填写物料明细')
 | ||
|         for i in MIOItem.objects.filter(mio=instance):
 | ||
|             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 + i.count
 | ||
|                 # if mb.expiration_date is None:
 | ||
|                 #     mb.expiration_date = i.expiration_date
 | ||
|                 if instance.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 - i.count
 | ||
|                 if mb.count < 0:
 | ||
|                     raise ParseError('批次库存不足,操作失败')
 | ||
|                 elif mb.count == 0:
 | ||
|                     mb.delete()
 | ||
|                 else:
 | ||
|                     mb.save()
 | ||
|             else:
 | ||
|                 raise ParseError('不支持的操作')
 | ||
|             cls.cal_mat_count(material)
 | ||
| 
 | ||
|     @classmethod
 | ||
|     def update_mb_after_test(cls, ins: MIOItem):
 | ||
|         count_notok = ins.count_notok
 | ||
|         batch = ins.batch
 | ||
|         material = ins.material
 | ||
|         warehouse = ins.warehouse
 | ||
|         try:
 | ||
|             mb = MaterialBatch.objects.get(
 | ||
|                 material=material, batch=batch, warehouse=warehouse)
 | ||
|             count_new = mb.count - count_notok
 | ||
|             if count_new < 0:
 | ||
|                 raise ParseError('库存扣减失败,请确认!')
 | ||
|             mb.count = count_new
 | ||
|             mb.save()
 | ||
|         except MaterialBatch.DoesNotExist:
 | ||
|             # 库存不存在已被消耗了
 | ||
|             if count_notok != 0:
 | ||
|                 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(
 | ||
|                     ' ', '') + '|' + 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()
 | ||
|                 })
 | ||
|             # if not is_created:
 | ||
|             #     mb.count += count
 | ||
|             #     mb.save()
 | ||
|             print(f'第{i}行数据导入成功')
 | ||
|             i = i + 1
 |