Files
shanxia2.0/backend/app/services/pl_legal_use_document.py
T

121 lines
6.2 KiB
Python

"""合法使用证明独立资料维护;不改变运输、额度、归档或库存。"""
from fastapi import HTTPException
from pydantic import BaseModel
from app.models.pl_models import PlPlan, PlPlanProduct, PlPlanLoad, PlPlanLoadProduct, PlPlanDelivery, PlPlanDeliveryProduct
from app.schemas.pl.legal_use_document import LegalDocumentsBody
from app.services.pl_data_scope import apply_pl_scope, assert_pl_row_in_scope
from app.services.pl_plan_cert_perm import user_can_upload_plan_cert
from app.services.pl_quota_attachments import authorize_attachment, storage_base_url
def _plan(db, user, plan_id, lock=False):
query = db.query(PlPlan).filter_by(id=plan_id, tenant_no=user.tenant_no, del_flag=0)
if lock:
query = query.with_for_update().populate_existing()
row = query.first()
if row is None:
raise HTTPException(404, '计划不存在')
assert_pl_row_in_scope(db, row, PlPlan, user, user.tenant_no)
return row
def _products(db, user, plan_id, lock=False):
query = db.query(PlPlanProduct).filter_by(plan_id=plan_id, tenant_no=user.tenant_no, del_flag=0)
if lock:
query = query.with_for_update().populate_existing()
return query.order_by(PlPlanProduct.create_time.desc(), PlPlanProduct.id).all()
def _contexts(db, user, plan_id):
from app.services.pl_quota_contract_service import _contract
result, contracts = {}, {}
for side, model, parent, parent_field in (
('load', PlPlanLoadProduct, PlPlanLoad, 'load_id'),
('delivery', PlPlanDeliveryProduct, PlPlanDelivery, 'delivery_id'),
):
rows = db.query(model, parent).join(parent, getattr(model, parent_field) == parent.id).filter(
model.tenant_no == user.tenant_no, parent.tenant_no == user.tenant_no,
model.plan_id == plan_id, parent.plan_id == plan_id, model.del_flag == 0, parent.del_flag == 0,
).order_by(model.create_time.desc(), model.id).all()
for item, stop in rows:
if item.contract_id and item.contract_id not in contracts:
try:
contracts[item.contract_id] = _contract(db, user, item.contract_id).contract_no
except HTTPException as error:
if error.status_code not in (403, 404):
raise
contracts[item.contract_id] = None
result.setdefault(item.plan_product_id, []).append({
'stopType': side, 'stopProductId': item.id, 'partyName': stop.customer_name,
'address': stop.address, 'contractId': item.contract_id,
'contractNo': contracts.get(item.contract_id), 'contractProductId': item.contract_product_id})
return result
def get_documents(db, user, plan_id):
plan = _plan(db, user, plan_id)
contexts = _contexts(db, user, plan_id)
return {'id': plan.id, 'planNo': plan.plan_no, 'archiveStatus': plan.archive_status,
'transportStatus': plan.transport_status, 'products': [
{'id': r.id, 'productId': r.product_id, 'productName': r.product_name,
'model': r.model, 'contexts': contexts.get(r.id, []), 'legalUseCertUrl': r.legal_use_cert_url,
'documentStatus': 'uploaded' if r.legal_use_cert_url else 'pending'}
for r in _products(db, user, plan_id) if r.is_explosive == 1]}
def list_documents(db, user, keyword=None, status=None):
if status not in (None, 'pending', 'uploaded'):
raise HTTPException(400, '未知资料状态')
products = db.query(PlPlanProduct.plan_id).filter_by(tenant_no=user.tenant_no, del_flag=0, is_explosive=1)
if status == 'pending':
products = products.filter((PlPlanProduct.legal_use_cert_url.is_(None)) | (PlPlanProduct.legal_use_cert_url == ''))
elif status == 'uploaded':
products = products.filter(PlPlanProduct.legal_use_cert_url.isnot(None), PlPlanProduct.legal_use_cert_url != '')
query = db.query(PlPlan).filter(PlPlan.tenant_no == user.tenant_no, PlPlan.del_flag == 0, PlPlan.id.in_(products))
query = apply_pl_scope(query, PlPlan, user, db, user.tenant_no)
if keyword:
query = query.filter(PlPlan.plan_no.contains(keyword))
return [get_documents(db, user, r.id) for r in query.order_by(PlPlan.create_time.desc()).all()]
def save_documents(db, user, plan_id, data):
if not user_can_upload_plan_cert(db, user):
raise HTTPException(403, '无权维护合法使用证明')
payload = data.model_dump(exclude_unset=True) if isinstance(data, BaseModel) else data
body = LegalDocumentsBody(**payload)
_plan(db, user, plan_id, lock=True)
if 'products' not in body.model_fields_set:
return get_documents(db, user, plan_id)
if body.products is None:
raise HTTPException(400, '产品集合不可为null')
rows = {r.id: r for r in _products(db, user, plan_id, lock=True)}
seen, changes = set(), []
for item in body.products:
if item.id in seen or item.id not in rows:
raise HTTPException(400, '产品明细ID重复或不属于当前计划')
seen.add(item.id)
row = rows[item.id]
if row.is_explosive != 1:
raise HTTPException(400, '该产品不适用合法使用证明')
if 'legal_use_cert_url' not in item.model_fields_set:
continue
urls = list(dict.fromkeys(v.strip() for v in (item.legal_use_cert_url or '').split(',') if v.strip()))
old = {v.strip() for v in (row.legal_use_cert_url or '').split(',') if v.strip()}
for value in urls:
if value not in old:
authorize_attachment(db, user, value, storage_base_url())
normalized = ','.join(urls)
if normalized != (row.legal_use_cert_url or ''):
changes.append((row, normalized))
for row, value in changes:
row.legal_use_cert_url = value
row.update_by = user.id
if changes:
from app.services.pl_plan_service import record_plan_change
record_plan_change(db, tenant_no=user.tenant_no, plan_id=plan_id, change_type='legal_use_document',
change_content='维护合法使用证明:' + '、'.join(r.id for r, _ in changes),
user_id=user.id, user_name=getattr(user, 'name', None), dept_id=user.dept_id or '')
db.flush()
return get_documents(db, user, plan_id)