from apps.inm.models import MIO, MIOItem, MaterialBatch, MaterialBatchA, MIOItemA, WareHouse from rest_framework.exceptions import ParseError from apps.mtm.models import Material, Process from apps.utils.tools import ranstr from apps.utils.thread import MyThread from apps.mtm.services import cal_material_count from apps.wpm.models import WMaterial def do_out(item: MIOItem): """ 生产领料到车间 """ from apps.inm.models import MaterialBatch mio:MIO = item.mio belong_dept = mio.belong_dept mgroup = mio.mgroup do_user = mio.do_user material = item.material if material.into_wm is False: # 用于混料的原料不与车间库存交互, 这个是配置项目 return action_list = [] mias = MIOItemA.objects.filter(mioitem=item) is_zhj = False # 是否组合件领料 if mias.exists(): is_zhj = True 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]] if is_zhj: try: mb = MaterialBatch.objects.get( material=item.material, warehouse=item.warehouse, batch=item.batch ) except (MaterialBatch.DoesNotExist, MaterialBatch.MultipleObjectsReturned) as e: raise ParseError(f"组合件批次错误!{e}") mb.count = mb.count - item.count if mb.count < 0: raise ParseError("组合件批次库存不足,操作失败") else: mb.save() for al in action_list: xmaterial:Material = al[0] xbatch:str = al[1] xcount:str = al[2] mb = None if not is_zhj: try: mb = MaterialBatch.objects.get( material=xmaterial, warehouse=item.warehouse, batch=xbatch ) except (MaterialBatch.DoesNotExist, MaterialBatch.MultipleObjectsReturned) as e: raise ParseError(f"批次错误!{e}") mb.count = mb.count - xcount if mb.count < 0: raise ParseError("批次库存不足,操作失败") else: mb.save() # 领到车间库存(或工段) wm, new_create = WMaterial.objects.get_or_create(batch=xbatch, material=xmaterial, belong_dept=belong_dept, mgroup=mgroup, state=WMaterial.WM_OK) if new_create: wm.create_by = do_user wm.batch_ofrom = mb.batch if mb else None wm.material_ofrom = mb.material if mb else None wm.count = wm.count + item.count wm.update_by = do_user wm.save() def do_in(item: MIOItem): """ 生产入库后更新车间物料 """ mio = item.mio belong_dept = mio.belong_dept mgroup = mio.mgroup do_user = mio.do_user material = item.material if material.into_wm is False: return action_list = [] mias = MIOItemA.objects.filter(mioitem=item) is_zhj = False # 是否组合件入仓库 if mias.exists(): is_zhj = True 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]] production_dept = None for al in action_list: xmaterial, xbatch, xcount = al # 扣减车间库存 wm_qs = WMaterial.objects.filter( batch=xbatch, material=xmaterial, belong_dept=belong_dept, mgroup=mgroup, state=WMaterial.WM_OK) count_x = wm_qs.count() if count_x == 1: wm = wm_qs.first() elif count_x == 0: raise ParseError( f'{str(xmaterial)}-{xbatch}-批次库存不存在!') else: 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() else: raise ParseError(f'{str(xmaterial)}-{xbatch}车间物料不足') wm_production_dept = wm.mgroup.belong_dept if wm.mgroup else None if production_dept is None: production_dept = wm_production_dept elif wm_production_dept and production_dept != wm_production_dept: raise ParseError(f'{str(xmaterial)}-{xbatch}车间物料不属于同一车间') # 增加mb if not is_zhj: mb, _ = MaterialBatch.objects.get_or_create( material=xmaterial, warehouse=item.warehouse, batch=xbatch, defaults={ "count": 0, "batch_ofrom": wm.batch_ofrom, "material_ofrom": wm.material_ofrom, "production_dept": production_dept } ) mb.count = mb.count + xcount mb.save() if is_zhj: # 组合件单独处理 mb, is_created = MaterialBatch.objects.get_or_create( material=item.material, warehouse=item.warehouse, batch=item.batch, defaults={"count": 0, "production_dept": production_dept} ) if not is_created: raise ParseError("该批次组合件已存在") for mia in mias: MaterialBatchA.objects.create(mb=mb, material=mia.material, batch=mia.batch, rate=mia.rate) class InmService: @classmethod def update_material_count(cls, instance: MIO): """ 更新物料数量 """ # 统计物料数量 m_ids = MIOItem.objects.filter(mio=instance).values_list('material_id', flat=True) MyThread(target=cal_material_count, args=(m_ids, ), daemon=True).start() @classmethod def update_inm(cls, instance: MIO, is_reverse: bool = False): """ 更新库存, 支持反向操作 """ in_or_out = 1 if is_reverse: in_or_out = -1 if instance.type == MIO.MIO_TYPE_PUR_IN: # 需要更新订单 from apps.pum.services import PumService cls.update_mb(instance, in_or_out) PumService.mio_purin(instance, is_reverse) elif instance.type == MIO.MIO_TYPE_OTHER_IN: cls.update_mb(instance, in_or_out) elif instance.type == MIO.MIO_TYPE_DO_IN: mioitems = MIOItem.objects.filter(mio=instance) if is_reverse: for item in mioitems: do_out(item) else: for item in mioitems: do_in(item) elif instance.type == MIO.MIO_TYPE_SALE_OUT: from apps.sam.services import SamService cls.update_mb(instance, in_or_out) SamService.mio_saleout(instance, is_reverse) elif instance.type == MIO.MIO_TYPE_OTHER_OUT: cls.update_mb(instance, in_or_out) elif instance.type == MIO.MIO_TYPE_DO_OUT: mioitems = MIOItem.objects.filter(mio=instance) if is_reverse: for item in mioitems: do_in(item) else: for item in mioitems: do_out(item) else: raise ParseError('不支持该出入库操作') @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("未填写物料明细") for i in mioitems: cls.update_mb_item(i, in_or_out, 'count') @classmethod def update_mb_item(cls, i: MIOItem, in_or_out: int = 1, field:str='count'): """ 更新物料批次(根据明细) in = 1 out = -1 默认使用count字段做加减 """ material = i.material warehouse = i.warehouse ddict = {"count": 0, "supplier": i.mio.supplier} if i.material.type in [Material.MA_TYPE_MAINSO]: ddict["batch_ofrom"] = i.batch ddict["material_ofrom"] = i.material mb, _ = MaterialBatch.objects.get_or_create( material=material, warehouse=warehouse, batch=i.batch, defaults=ddict ) if in_or_out == 1: mb.count = mb.count + getattr(i, field) mb.save() elif in_or_out == -1: mb.count = mb.count - getattr(i, field) if mb.count < 0: raise ParseError("批次库存不足,操作失败") else: mb.save() else: raise ParseError("不支持的操作") 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()}, ) MaterialBatch.objects.get_or_create( material=material, batch=batch, warehouse=warehouse, defaults={"material": material, "batch": batch, "warehouse": warehouse, "count": count, "id": idWorker.get_id()} ) cal_material_count([material.id]) # if not is_created: # mb.count += count # mb.save() print(f"第{i}行数据导入成功") i = i + 1