This commit is contained in:
zlwu committed 2026-05-24 23:04:33 +08:00
1 parent 13e4c9530a
commit 575e63e7e8
62 files changed
+28759 -9636

No files matched your search

+625
View File
@@ -1544,6 +1544,631 @@ async def delete_checkup_institution_project(
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 7. 渠道服务购买订单
# ---------------------------------------------------------------------------
class ServiceOrderProductItem(BaseModel):
model_config = ConfigDict(populate_by_name=True)
project_code: Optional[str] = Field(None, alias="projectCode")
project_name: Optional[str] = Field(None, alias="projectName")
cell_type: Optional[str] = Field(None, alias="cellType")
spec_text: Optional[str] = Field(None, alias="specText")
agreement_unit_price: Optional[float] = Field(None, alias="agreementUnitPrice")
buy_qty: Optional[float] = Field(None, alias="buyQty")
buy_amount: Optional[float] = Field(None, alias="buyAmount")
class ServiceOrderCreateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
channel_id: str = Field(..., alias="channelId")
order_type: str = Field(..., alias="orderType") # yfk / gmcp
dept_name: Optional[str] = Field(None, alias="deptName")
prepay_amount: Optional[float] = Field(None, alias="prepayAmount")
channel_agreement_id: Optional[str] = Field(None, alias="channelAgreementId")
products: Optional[List[ServiceOrderProductItem]] = None
remark: Optional[str] = None
class ServiceOrderUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
dept_name: Optional[str] = Field(None, alias="deptName")
remark: Optional[str] = None
prepay_amount: Optional[float] = Field(None, alias="prepayAmount")
channel_agreement_id: Optional[str] = Field(None, alias="channelAgreementId")
products: Optional[List[ServiceOrderProductItem]] = None
class FinanceSubmitBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
finance_submit_remark: Optional[str] = Field(None, alias="financeSubmitRemark")
finance_submit_attachments: Optional[str] = Field(None, alias="financeSubmitAttachments")
class FinanceConfirmBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
finance_remark: Optional[str] = Field(None, alias="financeRemark")
finance_confirm_attachments: Optional[str] = Field(None, alias="financeConfirmAttachments")
class RefundSubmitBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
refund_amount: Optional[float] = Field(None, alias="refundAmount")
refund_remark: Optional[str] = Field(None, alias="refundRemark")
refund_attachments: Optional[str] = Field(None, alias="refundAttachments")
class RefundConfirmBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
refund_finance_remark: Optional[str] = Field(None, alias="refundFinanceRemark")
refund_finance_confirm_attachments: Optional[str] = Field(
None, alias="refundFinanceConfirmAttachments"
)
class TxnRechargeBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
amount: float = Field(..., gt=0, alias="amount")
remark: Optional[str] = Field(None, alias="remark")
class TxnRefundBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
amount: float = Field(..., gt=0, alias="amount")
remark: Optional[str] = Field(None, alias="remark")
class TxnProductItem(BaseModel):
model_config = ConfigDict(populate_by_name=True)
project_code: Optional[str] = Field(None, alias="projectCode")
project_name: Optional[str] = Field(None, alias="projectName")
cell_type: Optional[str] = Field(None, alias="cellType")
spec_text: Optional[str] = Field(None, alias="specText")
agreement_unit_price: Optional[float] = Field(None, alias="agreementUnitPrice")
qty: Optional[float] = Field(None, alias="qty")
amount: Optional[float] = Field(None, alias="amount")
class TxnPurchaseBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
products: List[TxnProductItem] = Field(..., alias="products")
remark: Optional[str] = Field(None, alias="remark")
class TxnUnsubscribeBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
products: List[TxnProductItem] = Field(..., alias="products")
remark: Optional[str] = Field(None, alias="remark")
class TxnFinanceSubmitBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
finance_submit_remark: Optional[str] = Field(None, alias="financeSubmitRemark")
finance_submit_attachments: Optional[str] = Field(None, alias="financeSubmitAttachments")
class TxnFinanceConfirmBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
finance_remark: Optional[str] = Field(None, alias="financeRemark")
finance_confirm_attachments: Optional[str] = Field(None, alias="financeConfirmAttachments")
@router.get("/channel-service-orders")
async def list_channel_service_orders(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
orderType: Optional[str] = Query(None, alias="orderType"),
orderStatus: Optional[str] = Query(None, alias="orderStatus"),
channelId: Optional[str] = Query(None, alias="channelId"),
keyword: Optional[str] = None,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
items, total = ps_svc.list_channel_service_orders(
db,
page=page,
page_size=pageSize,
order_type=orderType,
order_status=orderStatus,
channel_id=channelId,
keyword=keyword,
tenant_no=tenant_no,
user_info=user,
)
tp = ps_svc.total_pages(total, pageSize)
return success_response(
{"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp}
)
@router.get("/channel-service-orders/{order_id}")
async def get_channel_service_order_detail(
order_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
order = ps_svc.get_service_order(db, order_id, tenant_no=tenant_no)
if not order:
return error_response(404, "订单不存在")
order_dict = ps_svc._row_to_dict_service_order(order, db, tenant_no)
user_ids = [x for x in (order.create_by, order.finance_submit_by) if x]
name_map = ps_svc._user_nick_name_map(db, user_ids)
order_dict["createByName"] = name_map.get(order.create_by or "", "") or (order.create_by or "")
order_dict["financeSubmitByName"] = name_map.get(order.finance_submit_by or "", "") or (
order.finance_submit_by or ""
)
products = ps_svc.get_service_order_products(db, order_id, tenant_no=tenant_no)
order_dict["products"] = products
txns, _ = ps_svc.list_service_order_txns(db, service_order_id=order_id, tenant_no=tenant_no, page_size=200)
order_dict["transactions"] = txns
return success_response(order_dict)
except ValueError as e:
return error_response(400, str(e))
@router.post("/channel-service-orders")
async def create_channel_service_order(
body: ServiceOrderCreateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
products_data = None
if body.products:
products_data = [p.model_dump(by_alias=False) for p in body.products]
order = ps_svc.create_channel_service_order(
db,
channel_id=body.channel_id,
order_type=body.order_type,
dept_name=body.dept_name,
prepay_amount=body.prepay_amount,
channel_agreement_id=body.channel_agreement_id,
products=products_data,
tenant_no=tenant_no,
remark=body.remark,
user_id=user.get("user_id"),
)
order_dict = ps_svc._row_to_dict_service_order(order, db, tenant_no)
order_dict["products"] = ps_svc.get_service_order_products(db, order.id, tenant_no=tenant_no)
return success_response(order_dict, message="创建成功")
except ValueError as e:
return error_response(400, str(e))
@router.put("/channel-service-orders/{order_id}")
async def update_channel_service_order(
order_id: str,
body: ServiceOrderUpdateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
payload: dict[str, Any] = body.model_dump(exclude_unset=True, by_alias=False)
products_data = None
if "products" in payload:
products_data = payload.pop("products")
if products_data is not None:
products_data = [
p.model_dump(by_alias=False) if hasattr(p, "model_dump") else p
for p in (body.products or [])
]
obj = ps_svc.update_channel_service_order(
db,
order_id,
tenant_no=tenant_no,
user_id=user.get("user_id"),
products=products_data,
**payload,
)
return success_response(
ps_svc._row_to_dict_service_order(obj, db, tenant_no), message="更新成功"
)
except ValueError as e:
return error_response(400, str(e))
@router.delete("/channel-service-orders/{order_id}")
async def delete_channel_service_order(
order_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
ps_svc.soft_delete_service_order(db, order_id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
@router.post("/channel-service-orders/{order_id}/submit-finance-confirm")
async def submit_service_order_finance_confirm(
order_id: str,
body: FinanceSubmitBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = ps_svc.submit_finance_confirm(
db,
order_id,
finance_submit_remark=body.finance_submit_remark,
finance_submit_attachments=body.finance_submit_attachments,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order(obj, db, tenant_no), message="已发起财务确认"
)
except ValueError as e:
return error_response(400, str(e))
@router.post("/channel-service-orders/{order_id}/confirm-receipt")
async def confirm_service_order_receipt(
order_id: str,
body: FinanceConfirmBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = ps_svc.confirm_receipt(
db,
order_id,
finance_remark=body.finance_remark,
finance_confirm_attachments=body.finance_confirm_attachments,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order(obj, db, tenant_no), message="确认收款成功"
)
except ValueError as e:
return error_response(400, str(e))
@router.post("/channel-service-orders/{order_id}/submit-refund")
async def submit_service_order_refund(
order_id: str,
body: RefundSubmitBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = ps_svc.submit_refund(
db,
order_id,
refund_amount=body.refund_amount,
refund_remark=body.refund_remark,
refund_attachments=body.refund_attachments,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order(obj, db, tenant_no), message="提交退款成功"
)
except ValueError as e:
return error_response(400, str(e))
@router.post("/channel-service-orders/{order_id}/confirm-refund")
async def confirm_service_order_refund(
order_id: str,
body: RefundConfirmBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = ps_svc.confirm_refund(
db,
order_id,
refund_finance_remark=body.refund_finance_remark,
refund_finance_confirm_attachments=body.refund_finance_confirm_attachments,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order(obj, db, tenant_no), message="确认退款成功"
)
except ValueError as e:
return error_response(400, str(e))
@router.put("/channel-service-orders/{order_id}/void")
async def void_channel_service_order(
order_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = ps_svc.void_service_order(
db,
order_id,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order(obj, db, tenant_no), message="作废成功"
)
except ValueError as e:
return error_response(400, str(e))
@router.get("/channel-service-order-txns")
async def list_service_order_txns(
page: int = Query(1, ge=1),
pageSize: int = Query(20, ge=1, le=100, alias="pageSize"),
serviceOrderId: Optional[str] = Query(None, alias="serviceOrderId"),
txnStatus: Optional[str] = Query(None, alias="txnStatus"),
txnType: Optional[str] = Query(None, alias="txnType"),
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
items, total = ps_svc.list_service_order_txns(
db,
service_order_id=serviceOrderId,
txn_status=txnStatus,
txn_type=txnType,
page=page,
page_size=pageSize,
tenant_no=tenant_no,
)
tp = ps_svc.total_pages(total, pageSize)
return success_response(
{"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp}
)
@router.get("/channel-service-order-txns/{txn_id}")
async def get_service_order_txn_detail(
txn_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
txn = ps_svc.get_service_order_txn(db, txn_id, tenant_no=tenant_no)
if not txn:
return error_response(404, "流水不存在")
txn_dict = ps_svc._row_to_dict_service_order_txn(txn, db, tenant_no)
order = ps_svc.get_service_order(db, txn.service_order_id, tenant_no=tenant_no)
if order:
txn_dict["channelName"] = order.channel_name or ""
txn_dict["orderType"] = order.order_type or ""
user_ids = [x for x in (txn.create_by, txn.finance_submit_by) if x]
name_map = ps_svc._user_nick_name_map(db, user_ids)
txn_dict["createByName"] = name_map.get(txn.create_by or "", "") or (txn.create_by or "")
txn_dict["financeSubmitByName"] = name_map.get(txn.finance_submit_by or "", "") or (
txn.finance_submit_by or ""
)
return success_response(txn_dict)
except ValueError as e:
return error_response(400, str(e))
@router.post("/channel-service-orders/{order_id}/recharge")
async def create_recharge_txn(
order_id: str,
body: TxnRechargeBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
txn = ps_svc.create_recharge_txn(
db,
order_id,
amount=body.amount,
remark=body.remark,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order_txn(txn, db, tenant_no), message="充值流水创建成功"
)
except ValueError as e:
return error_response(400, str(e))
@router.post("/channel-service-orders/{order_id}/refund")
async def create_refund_txn(
order_id: str,
body: TxnRefundBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
txn = ps_svc.create_refund_txn(
db,
order_id,
amount=body.amount,
remark=body.remark,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order_txn(txn, db, tenant_no), message="退款流水创建成功"
)
except ValueError as e:
return error_response(400, str(e))
@router.post("/channel-service-orders/{order_id}/purchase")
async def create_purchase_txn(
order_id: str,
body: TxnPurchaseBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
products_data = [p.model_dump(by_alias=False) for p in body.products]
txn = ps_svc.create_purchase_txn(
db,
order_id,
products=products_data,
remark=body.remark,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order_txn(txn, db, tenant_no), message="购买产品流水创建成功"
)
except ValueError as e:
return error_response(400, str(e))
@router.post("/channel-service-orders/{order_id}/unsubscribe")
async def create_unsubscribe_txn(
order_id: str,
body: TxnUnsubscribeBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
products_data = [p.model_dump(by_alias=False) for p in body.products]
txn = ps_svc.create_unsubscribe_txn(
db,
order_id,
products=products_data,
remark=body.remark,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order_txn(txn, db, tenant_no), message="退订产品流水创建成功"
)
except ValueError as e:
return error_response(400, str(e))
@router.post("/channel-service-order-txns/{txn_id}/submit-finance")
async def submit_txn_finance(
txn_id: str,
body: TxnFinanceSubmitBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
txn = ps_svc.submit_txn_finance(
db,
txn_id,
finance_submit_remark=body.finance_submit_remark,
finance_submit_attachments=body.finance_submit_attachments,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order_txn(txn, db, tenant_no), message="已发起财务确认"
)
except ValueError as e:
return error_response(400, str(e))
@router.post("/channel-service-order-txns/{txn_id}/confirm")
async def confirm_txn(
txn_id: str,
body: TxnFinanceConfirmBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
txn = ps_svc.confirm_txn(
db,
txn_id,
finance_remark=body.finance_remark,
finance_confirm_attachments=body.finance_confirm_attachments,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order_txn(txn, db, tenant_no), message="财务确认成功"
)
except ValueError as e:
return error_response(400, str(e))
@router.put("/channel-service-order-txns/{txn_id}/void")
async def void_txn(
txn_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
txn = ps_svc.void_txn(
db,
txn_id,
tenant_no=tenant_no,
user_id=user.get("user_id"),
)
return success_response(
ps_svc._row_to_dict_service_order_txn(txn, db, tenant_no), message="作废成功"
)
except ValueError as e:
return error_response(400, str(e))
@router.get("/channels/{channel_id}/account")
async def get_channel_account_info(
channel_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
account = ps_svc.get_channel_account(db, channel_id, tenant_no=tenant_no)
if not account:
return success_response({"channelId": channel_id, "balanceAmount": 0.0})
return success_response(ps_svc._row_to_dict_channel_account(account))
except ValueError as e:
return error_response(400, str(e))
@router.get("/channels/{channel_id}/product-quotas")
async def list_channel_product_quotas(
channel_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
items = ps_svc.list_channel_product_quotas(db, channel_id, tenant_no=tenant_no)
return success_response(items)
except ValueError as e:
return error_response(400, str(e))
# --- 体检机构项目套餐 ---