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
|