Spaces:
Running
Running
Download app/rules_engine.py from pramodmisra/pif: direct link, hf CLI and curl.
- Browser
- Download file 28 kB
-
https://huggingface.co/spaces/pramodmisra/pif/resolve/main/app/rules_engine.py
- Command line
-
hf download hf://spaces/pramodmisra/pif/app/rules_engine.py
-
curl -L -o rules_engine.py https://huggingface.co/spaces/pramodmisra/pif/resolve/main/app/rules_engine.py
28 kB
| """ | |
| 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, | |
| } | |