feat(pl): add PUT plan side contracts for contract completion
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
d1d7425eeb
commit
b984c8c857
2 files changed
+94
-1
No files matched your search
@@ -33,6 +33,7 @@ from app.schemas.pl.plan import (
|
||||
PlanArchiveBody,
|
||||
PlanArchiveBrandQtyItem,
|
||||
PlanContractGapListResponse,
|
||||
PlanContractGapRead,
|
||||
PlanCreate,
|
||||
PlanCreateFull,
|
||||
PlanDriverFeedbackUpdateBody,
|
||||
@@ -45,11 +46,12 @@ from app.schemas.pl.plan import (
|
||||
PlanProductCertsUpdate,
|
||||
PlanProductRead,
|
||||
PlanRead,
|
||||
PlanSideContractsUpdateBody,
|
||||
PlanSiteFeedbackUpdateBody,
|
||||
PlanUpdate,
|
||||
PlanWithProducts,
|
||||
)
|
||||
from app.services.pl_plan_contract_gap import list_plan_contract_gaps
|
||||
from app.services.pl_plan_contract_gap import list_plan_contract_gaps, update_plan_side_contracts
|
||||
from app.services.pl_brand_archive import load_brand_qtys_by_plan_product_ids
|
||||
from app.services.pl_product_display import (
|
||||
load_crm_product_alias_maps,
|
||||
@@ -551,6 +553,31 @@ def list_contract_gaps(
|
||||
return PlanContractGapListResponse(total=total, list=items)
|
||||
|
||||
|
||||
@router.put("/{id}/contracts/{side}", response_model=PlanContractGapRead)
|
||||
def put_plan_side_contracts(
|
||||
id: str,
|
||||
side: str,
|
||||
payload: PlanSideContractsUpdateBody,
|
||||
db: Session = Depends(get_db),
|
||||
user: DbUserContext = Depends(get_db_current_user),
|
||||
) -> PlanContractGapRead:
|
||||
"""单侧保存计划合同关联(合同补全)。"""
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
plan = _get_plan(db, tenant_no, id, user)
|
||||
result = update_plan_side_contracts(
|
||||
db,
|
||||
tenant_no=tenant_no,
|
||||
plan=plan,
|
||||
side=side,
|
||||
contracts=payload.contracts,
|
||||
user_id=user.id,
|
||||
dept_id=user.dept_id,
|
||||
)
|
||||
plan.update_by = user.id
|
||||
db.commit()
|
||||
return result
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 创建计划
|
||||
# =============================================================================
|
||||
|
||||
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
from datetime import date
|
||||
from typing import List, Optional, TYPE_CHECKING
|
||||
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy import and_, exists, func, or_, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -13,7 +14,10 @@ from app.services.pl_internal_customer import INTERNAL_CUSTOMER_NAMES, is_intern
|
||||
from app.services.pl_plan_service import (
|
||||
PLAN_CONTRACT_SIDE_DEMANDER,
|
||||
PLAN_CONTRACT_SIDE_SUPPLIER,
|
||||
_normalize_contract_links,
|
||||
assert_contract_selectable_for_plan,
|
||||
load_plan_contracts_grouped,
|
||||
replace_plan_contracts,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -193,3 +197,65 @@ def list_plan_contract_gaps(
|
||||
)
|
||||
)
|
||||
return total, items
|
||||
|
||||
|
||||
def update_plan_side_contracts(
|
||||
db: Session,
|
||||
*,
|
||||
tenant_no: str,
|
||||
plan: PlPlan,
|
||||
side: str,
|
||||
contracts: list[PlanContractLink],
|
||||
user_id: Optional[str],
|
||||
dept_id: Optional[str],
|
||||
) -> PlanContractGapRead:
|
||||
"""单侧保存计划合同关联;允许空列表,不强制非内置侧必须有合同。"""
|
||||
if plan.follow_status == "cancelled":
|
||||
raise HTTPException(status_code=400, detail="已作废的计划不能修改")
|
||||
if side not in (PLAN_CONTRACT_SIDE_SUPPLIER, PLAN_CONTRACT_SIDE_DEMANDER):
|
||||
raise HTTPException(status_code=422, detail="side 必须为 supplier 或 demander")
|
||||
|
||||
current_s, current_d = load_plan_contracts_grouped(db, tenant_no, [plan.id]).get(
|
||||
plan.id, ([], [])
|
||||
)
|
||||
links = _normalize_contract_links(contracts)
|
||||
expected_customer_id = (
|
||||
plan.supplier_id if side == PLAN_CONTRACT_SIDE_SUPPLIER else plan.customer_id
|
||||
)
|
||||
side_label = "供方合同" if side == PLAN_CONTRACT_SIDE_SUPPLIER else "需方合同"
|
||||
resolved: list[PlanContractLink] = []
|
||||
for link in links:
|
||||
contract = assert_contract_selectable_for_plan(
|
||||
db,
|
||||
link.contract_id,
|
||||
tenant_no,
|
||||
expected_customer_id=expected_customer_id,
|
||||
side_label=side_label,
|
||||
)
|
||||
resolved.append(
|
||||
PlanContractLink(
|
||||
contractId=contract.id,
|
||||
contractNo=contract.contract_no or link.contract_no,
|
||||
)
|
||||
)
|
||||
|
||||
supplier_links = resolved if side == PLAN_CONTRACT_SIDE_SUPPLIER else current_s
|
||||
demander_links = resolved if side == PLAN_CONTRACT_SIDE_DEMANDER else current_d
|
||||
replace_plan_contracts(
|
||||
db,
|
||||
tenant_no=tenant_no,
|
||||
plan_id=plan.id,
|
||||
supplier_contracts=supplier_links,
|
||||
demander_contracts=demander_links,
|
||||
user_id=user_id,
|
||||
dept_id=dept_id,
|
||||
)
|
||||
|
||||
supplier_contracts, demander_contracts = load_plan_contracts_grouped(
|
||||
db, tenant_no, [plan.id]
|
||||
).get(plan.id, ([], []))
|
||||
return build_plan_contract_gap_read(
|
||||
plan,
|
||||
supplier_contracts=supplier_contracts,
|
||||
demander_contracts=demander_contracts,
|
||||
)
|
||||
Reference in new issue
Block a user