PayrollManagementSystem/backend/app/services/receipt_confirmation.py

57 lines
2.0 KiB
Python
Raw Normal View History

"""回款人工确认门槛;与生成凭证、保存资料和工资审核分别管理。"""
import hashlib
import json
from datetime import date
from decimal import Decimal
from sqlalchemy import select
from app.core.exceptions import BadRequestError
from app.models import Receipt
from app.services.param_service import resolve_snapshot
CONFIRMATION_PARAM = "receipt.confirmation.enabled"
def enabled(session) -> bool:
"""操作开关取当前生效值,不按历史到账日绕过本次人工确认门槛。"""
return resolve_snapshot(session, date.today()).boolean(CONFIRMATION_PARAM)
def revision(receipt) -> str:
"""只绑定经办人核对的业务内容;备注和同步时间不使确认无故失效。"""
values = [
receipt.id, receipt.business_id, receipt.shipment_id,
receipt.receipt_date.isoformat(), format(Decimal(receipt.amount).quantize(Decimal("0.01")), "f"),
receipt.is_barter, receipt.t_plus_id, receipt.source_no,
]
return hashlib.sha256(json.dumps(values, ensure_ascii=False).encode()).hexdigest()
def is_confirmed(receipt) -> bool:
return bool(
receipt.confirmation_status == 1
and receipt.confirmed_by
and receipt.confirmed_at
and receipt.confirmed_revision == revision(receipt)
)
def invalidate(receipt) -> None:
receipt.confirmation_status = 0
receipt.confirmed_by = receipt.confirmed_at = receipt.confirmed_revision = None
def ensure_confirmed(session, receipt_ids) -> None:
"""在原核算事务内锁定并核实回款;关闭只跳过人工门槛,不改变凭证资格。"""
ids = sorted(set(receipt_ids))
if not ids or not enabled(session):
return
rows = list(session.scalars(
select(Receipt).where(Receipt.id.in_(ids)).order_by(Receipt.id)
.with_for_update().execution_options(populate_existing=True)
))
if len(rows) != len(ids) or any(not is_confirmed(row) for row in rows):
raise BadRequestError("存在未人工确认或确认后内容已变化的回款,请先在回款管理逐笔确认")