91 lines
4.6 KiB
Python
91 lines
4.6 KiB
Python
import base64
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from exceptions.exception import ServiceException
|
|
from module_admin.entity.vo.user_vo import CurrentUserModel
|
|
from module_business.dao.master_dao import MasterDao
|
|
from module_business.dao.operation_dao import OperationDao
|
|
from module_business.dao.shipment_label_dao import ShipmentLabelDao
|
|
from module_business.domain.enums import DocumentStatus
|
|
from module_business.domain.test_batch_scope import TestBatchScope, assert_record_in_scope
|
|
from module_business.entity.vo.shipment_label_vo import ShipmentLabelModel
|
|
from module_business.service.pallet_service import PalletService
|
|
from module_business.service.shipment_service import ShipmentService
|
|
|
|
|
|
class ShipmentLabelService:
|
|
"""复用发货双数据范围读取原始物料资料,不改变托盘、批号或库存。"""
|
|
|
|
@staticmethod
|
|
async def get_labels_services(
|
|
query_db: AsyncSession,
|
|
shipment_id: int,
|
|
current_user: CurrentUserModel,
|
|
test_scope: TestBatchScope,
|
|
) -> list[ShipmentLabelModel]:
|
|
warehouse_ids, site_ids = await ShipmentService._scopes(query_db, current_user)
|
|
shipment = await OperationDao.get_shipment_by_id(
|
|
query_db, shipment_id, test_scope, warehouse_ids=warehouse_ids, site_ids=site_ids,
|
|
)
|
|
if shipment is None:
|
|
ShipmentService._raise_shipment_not_accessible(current_user)
|
|
assert_record_in_scope(shipment, test_scope, '发货单')
|
|
if shipment.status not in (DocumentStatus.DRAFT.value, DocumentStatus.CONFIRMED.value):
|
|
raise ServiceException(message='当前发货单状态不支持打印标签')
|
|
if not shipment.items:
|
|
raise ServiceException(message='发货单没有可打印的托盘')
|
|
for item in shipment.items:
|
|
assert_record_in_scope(item, test_scope, '发货明细')
|
|
|
|
# 先授权单据,再读取其目标现场与所属客户,避免通过标签枚举跨范围资料。
|
|
site = await MasterDao.get_site(query_db, shipment.target_site_id, test_scope)
|
|
assert_record_in_scope(site, test_scope, '发货现场')
|
|
customer = await MasterDao.get_customer(query_db, site.customer_id, test_scope)
|
|
assert_record_in_scope(customer, test_scope, '发货客户')
|
|
rows = await ShipmentLabelDao.get_label_sources(query_db, shipment, test_scope)
|
|
if (
|
|
len(rows) != len(shipment.items)
|
|
or {row[0].shipment_item_id for row in rows} != {item.shipment_item_id for item in shipment.items}
|
|
):
|
|
raise ServiceException(message='发货明细已变化,请刷新后重新打印')
|
|
|
|
draft = shipment.status == DocumentStatus.DRAFT.value
|
|
# 整单全部验证后才生成任何二维码,缺少关联资料时不得输出部分标签。
|
|
for item, pallet, filling, quantity in rows:
|
|
for record, name in ((item, '发货明细'), (pallet, '托盘'), (filling, '装填记录')):
|
|
assert_record_in_scope(record, test_scope, name)
|
|
if (
|
|
item.shipment_id != shipment.shipment_id
|
|
or item.pallet_id != pallet.pallet_id
|
|
or filling.pallet_id != pallet.pallet_id
|
|
or type(quantity) is not int
|
|
or quantity <= 0
|
|
or not pallet.qr_token
|
|
):
|
|
raise ServiceException(message='发货标签资料不完整,请核对托盘与装填记录')
|
|
if draft:
|
|
if pallet.asset_status != '0' or filling.active_slot != 'ACTIVE' or quantity > pallet.capacity_packages:
|
|
raise ServiceException(message='草稿托盘已不满足发货条件,请刷新后重新打印')
|
|
elif item.active_filling_id != filling.filling_id or quantity != item.package_qty:
|
|
raise ServiceException(message='发货快照不完整,无法打印标签')
|
|
|
|
return [
|
|
ShipmentLabelModel(
|
|
shipment_no=shipment.shipment_no,
|
|
shipment_status=shipment.status,
|
|
pallet_code=pallet.pallet_code,
|
|
customer_name=customer.customer_name,
|
|
site_name=site.site_name,
|
|
strain_name=filling.strain_name_snapshot,
|
|
batch_no=filling.batch_no,
|
|
production_date=filling.production_date,
|
|
expiry_date=filling.expiry_date,
|
|
package_qty=quantity,
|
|
qr_code_data_url='data:image/png;base64,' + base64.b64encode(
|
|
PalletService.render_qr_png(pallet.qr_token),
|
|
).decode('ascii'),
|
|
)
|
|
for item, pallet, filling, quantity in rows
|
|
]
|