329 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			329 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
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}车间物料不足')
 | 
						||
        
 | 
						||
        if production_dept is None:
 | 
						||
            production_dept = wm.mgroup.belong_dept
 | 
						||
        elif production_dept != wm.mgroup.belong_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
 |