fix(quotes): derive decision.project_id from accept item_projects
Multi-project quotes: the manager picks one project per line item in the accept modal (item_projects), but accept_quote only auto-filled decision.project_id from existing line_item_projects (≤1). For items without a single existing line-project the decision stayed NULL, so / pm/on-the-way (filtered by ItemDecision.project_id) never showed those items to any project manager — they accumulated only in the global admin list. Now derivation order is: explicit decision.project_id → payload.item_projects (single) → existing line_item_projects (single) → NULL (office-only, never misattributed). Verified E2E: two items of one quote accepted to two projects appear in exactly their own PM's on-the-way.
This commit is contained in:
@@ -416,6 +416,9 @@ async def accept_quote(db: AsyncSession, quote_id: UUID, payload: AcceptQuoteIn,
|
||||
|
||||
# --- process item decisions (UPSERT) ---
|
||||
chosen_ts_ids: set[UUID] = set()
|
||||
# پروژههای ارسالی در payload.item_projects — منبع اصلی برای
|
||||
# decision.project_id (مدیر تدارکات برای هر قلم یک پروژه انتخاب میکند)
|
||||
proj_by_line: dict[UUID, list[UUID]] = {e.line_item_id: list(e.project_ids) for e in payload.item_projects}
|
||||
for decision_in in payload.item_decisions:
|
||||
decision = await db.scalar(
|
||||
select(ItemDecision).where(ItemDecision.line_item_id == decision_in.line_item_id).with_for_update()
|
||||
@@ -460,10 +463,19 @@ async def accept_quote(db: AsyncSession, quote_id: UUID, payload: AcceptQuoteIn,
|
||||
decision.adjusted_unit_price = decision_in.adjusted_unit_price
|
||||
decision.adjusted_notes = decision_in.adjusted_notes
|
||||
decision.decided_at = utcnow()
|
||||
# v2.6: the SINGLE purchased project (proc manager picks it;
|
||||
# auto-filled when the offer had exactly one project).
|
||||
# v2.6: the SINGLE purchased project (proc manager picks it).
|
||||
# Derivation order:
|
||||
# 1) explicit decision_in.project_id
|
||||
# 2) payload.item_projects for this line item (exactly one)
|
||||
# 3) existing line_item_projects (exactly one)
|
||||
# otherwise NULL — the item stays visible only to the office
|
||||
# until a project is assigned (never wrongly visible to a PM).
|
||||
if decision_in.project_id is not None:
|
||||
decision.project_id = decision_in.project_id
|
||||
else:
|
||||
accept_projs = proj_by_line.get(decision_in.line_item_id) or []
|
||||
if len(accept_projs) == 1:
|
||||
decision.project_id = accept_projs[0]
|
||||
else:
|
||||
line_projs = (
|
||||
(await db.execute(
|
||||
|
||||
Reference in New Issue
Block a user