factory/apps/inm/services.py

193 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
from apps.utils.thread import MyThread
def cal_material_count(materialId_list: list = []):
"""
计算物料总数量
"""
from apps.inm.models import MaterialBatch
from apps.wpm.models import WMaterial
if materialId_list:
objs = Material.objects.filter(id__in=set(materialId_list))
else:
objs = Material.objects.all()
for material in objs:
mb_count = MaterialBatch.objects.filter(material=material).aggregate(total=Sum("count"))["total"]
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_wm=wm_count,
count_mb=mb_count,
count=mb_count + wm_count)
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)
else:
raise ParseError('不支持该出入库操作')
# 统计物料数量
m_ids = MIOItem.objects.filter(mio=instance).values_list('material_id', flat=True)
MyThread(target=cal_material_count, args=(m_ids, ), daemon=True, log_err=True).start()
@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 mioitems:
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("不支持的操作")
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