""" Commission rules engine. Reads all configuration from the database and computes the summary table output. v2.1 changes: - Bell ringer offering removed (no thresholds, no bell_ringer key in output). - CCP rendered before CE in year tables and participants list. - 'House Standard Agreement' is its own type (house_processor=True): no P1 field, House Account row deducted by CE/CCP layers, Bella Santana added automatically as approval processor. - 'Life Origination Fee Agreement' transitions to House Account in Year 2+ via CommissionTier.use_house_account. """ from typing import Optional from sqlalchemy.orm import Session from app.models import ( CommissionAgreement, CommissionTier, FixedConstant, Producer, ClientExecutive, ) # Fixed-code agreements (P1 auto-filled, locked) FIXED_CODE_AGREEMENTS = { "Gebhardt Agreement": {"name": "Steve Gebhardt", "code": "GEBST2", "suffix": 2}, "Beacham Agreement": {"name": "Wade Beacham", "code": "BEAWA2", "suffix": 2}, } # Fixed-PAIR agreements (BOTH P1 and P2 auto-filled & locked) that — unlike the # locked-pair Mentor/Bond agreements below — KEEP the CE/CCP layers available. # Round 5: Fitch Irick (Wayne Dean + John Streer). Internal TypeCode FITC-IRICK. FIXED_PAIR_AGREEMENTS = { "Fitch Irick Agreement": { "p1": {"name": "Wayne Dean", "code": "DEAWA2", "suffix": 2}, "p2": {"name": "John Streer", "code": "STRJO2", "suffix": 2}, }, } # Referral / Origination-style agreements: P1 + a separate "Originating Producer" # slot (sourced from the P2 tiers). Round 5 added the EMB variant alongside the # original (now displayed as "- Middle Market"). Internal names are the keys. REFERRAL_ORIG_AGREEMENTS = { "Referral / Origination Fee Agreement", # display: "... - Middle Market" "Referral / Origination Fee Agreement - EMB", } # Round 6: detection is no longer tied to the exact internal `name`. The admin tier # editor can rename an agreement's internal name, which used to silently strip the # Originating-Producer slot off the renamed row. We now also match on the display # name / a stable prefix, so renamed or admin-created referral variants keep working. REFERRAL_PREFIX = "Referral / Origination Fee Agreement" def _is_referral_orig(name: Optional[str], display_name: Optional[str]) -> bool: if name in REFERRAL_ORIG_AGREEMENTS: return True return ((name or "").startswith(REFERRAL_PREFIX) or (display_name or "").startswith(REFERRAL_PREFIX)) # Agreements where CE/CCP layers deduct ONLY from P1 (not split across all producers) P1_ONLY_DEDUCTION_AGREEMENTS = { "Closer Agreement", } | REFERRAL_ORIG_AGREEMENTS # Documentation-only CE placeholder (Round 5). Carries 0% commission / 0% credit, # never deducts from producers, and is excluded from the approval-email workflow. NO_CE_CODE = "NOCEA1" # Bella Santana is the standing approval processor for House Standard agreements HOUSE_STANDARD_PROCESSOR = { "name": "Bella Santana", "code": "SANBE1", "email": "bsantana@snellingswalters.com", } # Round 4 — locked-pair agreements: both P1 and P2 forced to specific producers, # no CE/CCP/Originator. Mentor agreements also surface a separate "Mentor Code" # row (MENTO3-6). Round 8 — in Unvalidated Years that row is the ONLY producer row # displayed (20% commission / 100% production credit); the Mentee/Mentor rows are # suppressed from the table but remain full approvers. LOCKED_PAIR_AGREEMENTS = { "Renno Mentor Agreement (MENTO3)": { "mentor_code": "MENTO3", "p1": {"name": "David Roos", "code": "ROODA2", "prefix": "ROODA", "suffix": 2}, "p2": {"name": "Chip Renno", "code": "RENCH2", "prefix": "RENCH", "suffix": 2}, }, "Harmon Mentor Agreement (MENTO4)": { "mentor_code": "MENTO4", "p1": {"name": "Brady Niblock", "code": "NIBBR2", "prefix": "NIBBR", "suffix": 2}, "p2": {"name": "Steve Harmon", "code": "HARST2", "prefix": "HARST", "suffix": 2}, }, "Levine Mentor Agreement (MENTO5)": { "mentor_code": "MENTO5", "p1": {"name": "Harrison O'Neal", "code": "ONEHA2", "prefix": "ONEHA", "suffix": 2}, "p2": {"name": "Eric Levine", "code": "LEVER2", "prefix": "LEVER", "suffix": 2}, }, "Byrd Mentor Agreement (MENTO6)": { "mentor_code": "MENTO6", "p1": {"name": "Matthew Downing", "code": "DOWMA2", "prefix": "DOWMA", "suffix": 2}, "p2": {"name": "Tara Byrd", "code": "BYRTA2", "prefix": "BYRTA", "suffix": 2}, }, "Bond Partner Agreement (Webb/Herron)": { "mentor_code": None, "p1": {"name": "Allan Webb", "code": "WEBAL2", "prefix": "WEBAL", "suffix": 2}, "p2": {"name": "Frank Herron", "code": "HERFR2", "prefix": "HERFR", "suffix": 2}, }, } def get_constant(db: Session, key: str) -> float: c = db.query(FixedConstant).filter(FixedConstant.key == key).first() return c.value if c else 0 def get_all_constants(db: Session) -> dict: return {c.key: c.value for c in db.query(FixedConstant).all()} def get_agreement_with_tiers(db: Session, agreement_id: int) -> Optional[dict]: agr = db.query(CommissionAgreement).filter( CommissionAgreement.id == agreement_id ).first() if not agr: return None p1_tiers = [t for t in agr.tiers if t.producer_role == "P1"] p2_tiers = [t for t in agr.tiers if t.producer_role == "P2"] return { "id": agr.id, "name": agr.name, "display_name": getattr(agr, "display_name", None) or agr.name, "p1_suffix": agr.p1_suffix, "p2_suffix": agr.p2_suffix, "ce_as_producer": agr.ce_as_producer, "house_processor": bool(agr.house_processor), "locked_pair": bool(getattr(agr, "locked_pair", False)), "P1": [_tier_to_dict(t) for t in p1_tiers] or None, "P2": [_tier_to_dict(t) for t in p2_tiers] or None, } def _tier_to_dict(t: CommissionTier) -> dict: return { "years": t.years_label, "commission": t.commission, "credit": t.credit, "agreement": t.agreement_label, "note": t.note, "flag": t.flag, "use_house_account": bool(t.use_house_account), } def _abe_status(suffix) -> str: if suffix == 1: return "ABE" if suffix == 2: return "Non-ABE" return "—" def _ce_code_base(code: str) -> Optional[str]: """'BRAJO1' -> 'BRAJO'. None when the code has no re-suffixable form: the NOCEA1 documentation placeholder (approval_routes.py matches that literal string, so it must never be rewritten) or any code not ending in a digit.""" if not code or code == NO_CE_CODE or not code[-1].isdigit(): return None return code[:-1] def ce_code_variants(code: str) -> set: """Both Epic suffix forms of a CE code (…1 ABE / …2 Non-ABE), for callers that must match approvals recorded under either — see the CE delete guard in admin_routes. Single-element for NOCEA1 / non-numeric codes.""" base = _ce_code_base(code) if base is None: return {code} if code else set() return {code, f"{base}1", f"{base}2"} def _apply_ce_suffix(db: Session, code: str, suffix) -> str: """The CE list stores ONE canonical code per person (seeded as the ABE '…1' form). Epic gives each CE both an ABE (…1) and a Non-ABE (…2) code, and CE_SUFFIX / CE_PROD_SUFFIX decides which one an agreement uses — so re-suffix the stored code rather than printing it verbatim. Returns the code unchanged when there is nothing safe to rewrite: - no re-suffixable base (NOCEA1, or a code not ending in a digit); - a suffix outside (1, 2), e.g. an admin typing 1.5 into the constant; - the derived code already belongs to a DIFFERENT ClientExecutive. Two CEs sharing a name-base get …1 and …2 from _gen_ce_code, and admins can type codes freely, so without this guard a re-suffix could stamp one person's Epic code onto another's agreement and approval record. NOTE: the stored ClientExecutive.code is never modified — saved drafts and the form's CE picker key on it (see compute_summary's ce_record lookup).""" base = _ce_code_base(code) if base is None or suffix not in (1, 2): return code derived = f"{base}{suffix}" if derived == code: return code clash = db.query(ClientExecutive).filter(ClientExecutive.code == derived).first() return code if clash else derived def _get_tier_at_index(tiers, index): if not tiers or index >= len(tiers): return None return tiers[index] def compute_summary(db: Session, form_data: dict) -> dict: agr_id = form_data.get("agreement_id") if not agr_id: return {"error": "No agreement selected", "year_tables": [], "participants": [], "warnings": []} R = get_agreement_with_tiers(db, agr_id) if not R: return {"error": "Agreement not found", "year_tables": [], "participants": [], "warnings": []} consts = get_all_constants(db) p1pfx = form_data.get("producer1_prefix") p2pfx = form_data.get("producer2_prefix") is_locked_pair = bool(R.get("locked_pair")) or R["name"] in LOCKED_PAIR_AGREEMENTS locked_pair = LOCKED_PAIR_AGREEMENTS.get(R["name"]) if is_locked_pair else None # Fitch Irick-style fixed PAIR: both producers locked, but CE/CCP stay available. is_fixed_pair = R["name"] in FIXED_PAIR_AGREEMENTS fixed_pair = FIXED_PAIR_AGREEMENTS.get(R["name"]) if is_fixed_pair else None if is_locked_pair and locked_pair: # Force P1/P2 prefixes from the locked-pair dict; engine ignores form payload # for these fields so a tampered request can't substitute different producers. p1pfx = locked_pair["p1"]["prefix"] p2pfx = locked_pair["p2"]["prefix"] elif is_fixed_pair and fixed_pair: # Fitch Irick-style: both producers forced from the dict (codes overridden # below). Use code-minus-suffix as the prefix so P2 renders + validation passes. p1pfx = fixed_pair["p1"]["code"][:-1] p2pfx = fixed_pair["p2"]["code"][:-1] # Round 7: locked-pair agreements (Mentor 3-6 + Bond Partner) now carry the CE # layer too — the form sends the mandatory "No Client Executive" (NOCEA1) dropdown # default, and a real CE deducts the standard 2% (split across producers). CCP # stays disabled for locked pairs (see below). include_ce = form_data.get("include_ce", False) # CE selector value is now a ClientExecutive code (key 'ce_code'); fall back # to the legacy 'ce_prefix' so older saved drafts still resolve. cepfx = (form_data.get("ce_code") or form_data.get("ce_prefix")) if include_ce else None # NOCEA1 is a documentation-only placeholder: 0% / 0%, no deduction, no approval email. is_nocea = (cepfx == NO_CE_CODE) include_ccp = form_data.get("include_ccp", False) and not is_locked_pair ccp_selection = form_data.get("ccp_selection") if not is_locked_pair else None has_cc = include_ccp and ccp_selection is_ce = R["ce_as_producer"] is_house_processor = R["house_processor"] is_referral_orig = _is_referral_orig(R["name"], R["display_name"]) and not is_locked_pair is_fixed_code = R["name"] in FIXED_CODE_AGREEMENTS # P1-only deduction == Closer Agreement plus every referral/origination variant # (kept in sync with REFERRAL detection so renamed referral rows deduct correctly). is_p1_only_deduction = (R["name"] == "Closer Agreement") or is_referral_orig if is_referral_orig: has_p2 = False orig_tiers = R["P2"] else: has_p2 = R["P2"] is not None orig_tiers = None warnings = [] participants = [] def _lookup_name(prefix): if not prefix: return "" p = db.query(Producer).filter(Producer.prefix == prefix).first() return p.name if p else "" # Resolve the CE from the standalone ClientExecutive list first; if the # selector value isn't a known CE code, fall back to the legacy Producer # path below so existing workflows/drafts behave exactly as before. ce_record = ( db.query(ClientExecutive).filter(ClientExecutive.code == cepfx).first() if cepfx else None ) ce_email = ce_record.email if ce_record else None p1name = _lookup_name(p1pfx) if not is_house_processor else "" p2name = _lookup_name(p2pfx) cename = ce_record.name if ce_record else _lookup_name(cepfx) p1suf = R["p1_suffix"] p2suf = R["p2_suffix"] ce_suf = int(consts.get("CE_PROD_SUFFIX", 2)) if is_ce else int(consts.get("CE_SUFFIX", 1)) if is_locked_pair and locked_pair: # Locked pair wins over every other code resolution path p1code = locked_pair["p1"]["code"] p1name = locked_pair["p1"]["name"] p1suf = locked_pair["p1"]["suffix"] p2code = locked_pair["p2"]["code"] p2name = locked_pair["p2"]["name"] p2suf = locked_pair["p2"]["suffix"] elif is_fixed_pair and fixed_pair: # Both producers hardcoded (Fitch Irick). CE/CCP layers stay active. p1code = fixed_pair["p1"]["code"] p1name = fixed_pair["p1"]["name"] p1suf = fixed_pair["p1"]["suffix"] p2code = fixed_pair["p2"]["code"] p2name = fixed_pair["p2"]["name"] p2suf = fixed_pair["p2"]["suffix"] elif is_fixed_code: fixed = FIXED_CODE_AGREEMENTS[R["name"]] p1code = fixed["code"] p1name = fixed["name"] p1suf = fixed["suffix"] p2code = f"{p2pfx}{p2suf}" if (has_p2 and p2pfx and p2suf) else "—" elif is_house_processor: p1code = "—" p2code = f"{p2pfx}{p2suf}" if (has_p2 and p2pfx and p2suf) else "—" else: p1code = f"{p1pfx}{p1suf}" if (p1pfx and p1suf) else "—" p2code = f"{p2pfx}{p2suf}" if (has_p2 and p2pfx and p2suf) else "—" # The CE list stores one canonical code per person (all seeded as '…1'), so the # stored code alone can never reflect CE_SUFFIX / CE_PROD_SUFFIX — re-suffix it # here so the Code column and the ABE Status column below are driven by the same # ce_suf. Legacy (non-CE-list) path keeps building prefix+suffix as before. cecode = (_apply_ce_suffix(db, ce_record.code, ce_suf) if ce_record else (f"{cepfx}{ce_suf}" if cepfx else "—")) has_orig_employee = form_data.get("employee_as_originator", False) and is_referral_orig has_orig_producer = (not has_orig_employee and form_data.get("orig_producer_prefix") and is_referral_orig) has_orig = has_orig_producer or has_orig_employee if has_orig_producer: opfx = form_data["orig_producer_prefix"] ocode = f"{opfx}{p2suf}" if p2suf else f"{opfx}2" oname = _lookup_name(opfx) elif has_orig_employee: ocode = "EMPOR2" oname = form_data.get("orig_employee_name", "") else: ocode = "—" oname = "" CE_COMM = consts.get("CE_COMM", 2) CC_COMM = consts.get("CC_COMM", 5) total_deduction = 0 # NOCEA1 is a 0% documentation placeholder — it never deducts from producers. if cepfx and not is_ce and not is_nocea: total_deduction += CE_COMM if has_cc: total_deduction += CC_COMM # Validation if (not p1pfx and not is_ce and not is_fixed_code and not is_house_processor and not is_locked_pair and R["name"] != "Ceded Accounts - CE as Producer"): warnings.append("Producer 1 (Lead) is required but not selected.") if has_p2 and not p2pfx and not is_locked_pair: warnings.append(f"{R['name']} uses two producers — select Producer 2.") if is_ce and not cepfx: warnings.append("This agreement needs a Client Executive as producer — select one above.") if is_referral_orig and not has_orig: warnings.append("Referral / Origination Fee Agreement requires an Originating Producer — select one.") is_bond = "bond" in R["name"].lower() if has_cc and is_bond: warnings.append("Complex Claims Practice (CCP) is not eligible for Bond Agreement.") # Build per-year tables year_labels = [] for src in ([R["P1"]] + ([orig_tiers] if is_referral_orig and orig_tiers else [R["P2"]] if has_p2 and R["P2"] else [])): if src: for t in src: if t["years"] not in year_labels: year_labels.append(t["years"]) if not year_labels: year_labels = ["All Years"] year_tables = [] for yi, year_label in enumerate(year_labels): year_rows = [] p1_tier = _get_tier_at_index(R["P1"], yi) if R["P1"] else None p2_tier = None orig_tier_data = None if is_referral_orig and orig_tiers: orig_tier_data = _get_tier_at_index(orig_tiers, yi) elif has_p2 and R["P2"]: p2_tier = _get_tier_at_index(R["P2"], yi) # Are we rendering a House-Account row in lieu of P1 for this year? # Two trigger conditions: # 1. Agreement has house_processor=True (House Standard). # 2. The P1 tier itself flags use_house_account=True (Life Y2+). p1_uses_house = bool( is_house_processor or (p1_tier and p1_tier.get("use_house_account")) ) active_producers = 0 if p1_tier and p1_tier["commission"] is not None and not is_ce and not p1_uses_house: active_producers += 1 if p2_tier and p2_tier["commission"] is not None: active_producers += 1 if orig_tier_data and orig_tier_data["commission"] is not None: active_producers += 1 if is_p1_only_deduction: p1_ded, p2_ded, orig_ded = total_deduction, 0, 0 else: pp = total_deduction / active_producers if active_producers > 0 else 0 p1_ded = p2_ded = orig_ded = pp if p1_uses_house and p1_tier: # House Account row — deducts CE/CCP from base 100% (or whatever tier defines). base = p1_tier["commission"] if p1_tier["commission"] is not None else 100.0 house_comm = base if cepfx and not is_ce and not is_nocea: house_comm -= CE_COMM if has_cc and not is_bond: house_comm -= CC_COMM year_rows.append({ "role": "House Account", "agreement_type": p1_tier["agreement"] or "House Standard Agreement", "commission_pct": round(max(house_comm, 0), 1), "production_pct": p1_tier.get("credit") if p1_tier.get("credit") is not None else 100.0, "abe_status": "Non-ABE", "code": "ACCHO1", "name": "House Account", }) else: # Round 8 — Mentor agreements (MENTO3-6) collapse the Mentee (P1) and # Mentor (P2) rows into the single MENTO code row during Unvalidated # Years. DISPLAY ONLY: the tiers, producer codes, participants list and # approval routing are untouched, so both producers still receive their # approval email and still block finalization. mentor_code = locked_pair.get("mentor_code") if (is_locked_pair and locked_pair) else None mentor_rollup = bool(mentor_code) and year_label == "Unvalidated Years" if not is_ce and p1_tier and p1_tier["commission"] is not None and not mentor_rollup: # Mentor agreements transition the former Mentee from Non-ABE Code 2 # to ABE Code 1 in the Validated Years tier. p1_row_code = p1code p1_row_abe = _abe_status(p1suf) p1_row_role = "Producer 1" if is_locked_pair and locked_pair and locked_pair.get("mentor_code"): if p1_tier["agreement"] == "Standard Agreement": p1_row_code = f"{locked_pair['p1']['prefix']}1" p1_row_abe = "ABE" else: p1_row_role = "Mentee (P1)" year_rows.append({"role": p1_row_role, "agreement_type": p1_tier["agreement"], "commission_pct": round(max(p1_tier["commission"] - p1_ded, 0), 1), "production_pct": p1_tier["credit"], "abe_status": p1_row_abe, "code": p1_row_code, "name": p1name}) if (not is_referral_orig and p2_tier and p2_tier["commission"] is not None and p2pfx and not mentor_rollup): p2_row_role = "Producer 2" if is_locked_pair and locked_pair and locked_pair.get("mentor_code"): p2_row_role = "Mentor (P2)" year_rows.append({"role": p2_row_role, "agreement_type": p2_tier["agreement"], "commission_pct": round(max(p2_tier["commission"] - p2_ded, 0), 1), "production_pct": p2_tier["credit"], "abe_status": _abe_status(p2suf), "code": p2code, "name": p2name}) if is_referral_orig and has_orig and orig_tier_data and orig_tier_data["commission"] is not None: year_rows.append({"role": "Originating Producer", "agreement_type": orig_tier_data["agreement"], "commission_pct": round(max(orig_tier_data["commission"] - orig_ded, 0), 1), "production_pct": orig_tier_data["credit"], "abe_status": "Non-ABE" if has_orig_employee else _abe_status(p2suf), "code": ocode, "name": oname}) # Mentor agreements only: add the MENTO code row in Unvalidated Years # (mechanically derived, not stored as a producer tier). Round 8 — this # row now carries the commission that used to sit on the suppressed # Mentee/Mentor rows. Read the rate off the tier rather than hardcoding # 20 so admin edits in the panel flow through; the p2_tier fallback # covers an admin edit that dropped the P1 tier (cf. the Fitch Irick # repair in start.py). Being the only commission-bearing producer row # left, it absorbs the FULL CE/CCP deduction rather than a per-producer # share — so 20% with NOCEA1, 18% with a real CE (18 + 2 = 20). if mentor_rollup: base_tier = p1_tier if (p1_tier and p1_tier["commission"] is not None) else p2_tier base = base_tier["commission"] if (base_tier and base_tier["commission"] is not None) else 0 mento_comm = round(max(base - total_deduction, 0), 1) # Keep this row's integer style ("20%", not "20.0%") — the generators # print the raw value and this row has always shown whole numbers. if mento_comm == int(mento_comm): mento_comm = int(mento_comm) year_rows.append({"role": "Mentor Code", "agreement_type": "Mentor Code", "commission_pct": mento_comm, "production_pct": 100, "abe_status": "Non-ABE", "code": mentor_code, "name": mentor_code}) # CCP row appears BEFORE CE row (v2.1) if has_cc and not is_bond: ccp_name = "Mike Parsa" if ccp_selection == "mike_parsa" else "House Account" ccp_code = "PARMI2" if ccp_selection == "mike_parsa" else "ACCHO1" year_rows.append({"role": "CCP Layer", "agreement_type": "Complex Claims Practice", "commission_pct": CC_COMM, "production_pct": consts.get("CC_CREDIT", 0), "abe_status": _abe_status(2), "code": ccp_code, "name": ccp_name}) if cepfx and not is_ce: # NOCEA1 placeholder → 0% / 0% and a documentation label; real CE → standard 2%. year_rows.append({ "role": "CE Layer", "agreement_type": "No Client Executive" if is_nocea else "Client Executive Agreement", "commission_pct": 0 if is_nocea else CE_COMM, "production_pct": 0 if is_nocea else consts.get("CE_CREDIT", 0), "abe_status": "Non-ABE" if is_nocea else _abe_status(ce_suf), "code": cecode, "name": cename}) elif is_ce and cepfx: ce_prod_comm = consts.get("CE_PROD_COMM", 10) if has_cc and not is_bond: ce_prod_comm = max(ce_prod_comm - CC_COMM, 0) year_rows.append({"role": "Client Executive", "agreement_type": "Ceded Accounts — CE as Producer", "commission_pct": ce_prod_comm, "production_pct": consts.get("CE_PROD_CREDIT", 100), # ce_suf IS CE_PROD_SUFFIX on this branch (is_ce) — read it # rather than the constant again, so this label and the # code above provably come from one value. "abe_status": _abe_status(ce_suf), "code": cecode, "name": cename}) if year_rows: year_tables.append({"year_label": year_label, "rows": year_rows}) # Participants list — order: P1, P2, Originator, House Standard processor, CCP, CE, CCP-Mike fallback seen_codes = set() def _add_participant(role, code, name, email=None, no_approval=False): if not code or code == "—" or code in seen_codes: return entry = {"role": role, "code": code, "name": name} if email: entry["email"] = email if no_approval: # Visible in tracking + PDF, but auto-satisfied: no approval email, # never blocks finalization (NOCEA1 documentation placeholder). entry["no_approval"] = True participants.append(entry) seen_codes.add(code) if is_house_processor: # Bella Santana is the standing processor _add_participant("Approval Processor", HOUSE_STANDARD_PROCESSOR["code"], HOUSE_STANDARD_PROCESSOR["name"], HOUSE_STANDARD_PROCESSOR["email"]) if is_fixed_code: fixed = FIXED_CODE_AGREEMENTS[R["name"]] _add_participant("Producer 1", fixed["code"], fixed["name"]) elif p1pfx and not is_ce and not is_house_processor: p1_role = "Producer 1" if is_locked_pair and locked_pair and locked_pair.get("mentor_code"): p1_role = "Mentee (P1)" _add_participant(p1_role, p1code, p1name) if has_p2 and p2pfx: p2_role = "Producer 2" if is_locked_pair and locked_pair and locked_pair.get("mentor_code"): p2_role = "Mentor (P2)" _add_participant(p2_role, p2code, p2name) if has_orig: _add_participant("Originating Producer" if has_orig_producer else "Originating Employee", ocode, oname) # CCP before CE in approval order (v2.1) if has_cc: # Mike Parsa always approves regardless of which CCP option was selected _add_participant("CCP (Mike Parsa)", "PARMI2", "Mike Parsa") if cepfx: # Pass the CE's own email when it came from the ClientExecutive list; # when None (legacy producer path), form_routes falls back to its # existing producer-email lookup exactly as before. _add_participant("CE as Producer" if is_ce else "Client Executive", cecode, cename, email=ce_email, no_approval=is_nocea) return { "agreement_name": R["display_name"] or R["name"], # user-facing label (PDF/DOCX/dashboard) "year_tables": year_tables, "participants": participants, "warnings": warnings, "house_processor": is_house_processor, }