Add real digital_ads + digital_branding catalogs
Built from real D.intelligence docs (not the 견적 자료 folder, which has only GA4/GTM + education — confirmed): - digital_branding: TNS 유학원 디지털 브랜딩 진단 컨설팅 → ₩9,000,000 (5 fixed stages) - digital_ads: 디하이브 디지털 광고·퍼포먼스 마케팅 대행 계약 → ₩6,000,000/월 retainer (media-spend commission % is per-deal, kept as a parameter — not invented) effort method now supports fixed-amount tasks (Unit Cost) and monthly retainers (unit: monthly); render shows 고정/—//월 and retainer/commission notes. Validated: branding ₩9.0M, ads ₩6.0M/월; no regression (SEO 25.0M, coaching 1.57M). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -57,16 +57,26 @@ def build(scope, rate, catalog):
|
||||
mult, driver, dcount = _scope_mult(rate, signals)
|
||||
roles = rate["role_rates"]
|
||||
|
||||
modules, grand = [], 0.0
|
||||
modules, grand, recurring = [], 0.0, False
|
||||
for mod in t["modules"]:
|
||||
tasks, sub = [], 0.0
|
||||
for task in mod["tasks"]:
|
||||
applied = mult if (task.get("scale") and mult != 1.0) else 1.0
|
||||
hours = round(task["hours"] * applied, 1)
|
||||
rr = roles[task["role"]]
|
||||
amt = rr * billing * hours
|
||||
tasks.append({"task": task["task"], "desc": task.get("desc", ""), "role": task["role"],
|
||||
"role_rate": rr, "hours": hours, "amount": amt, "scaled": applied != 1.0})
|
||||
unit = task.get("unit", "one_time")
|
||||
if unit == "monthly":
|
||||
recurring = True
|
||||
if "fixed" in task: # quoted lump sum / Unit Cost (no labor-hour basis)
|
||||
amt = task["fixed"] * applied
|
||||
tasks.append({"task": task["task"], "desc": task.get("desc", ""), "role": "fixed",
|
||||
"role_rate": None, "hours": None, "amount": amt,
|
||||
"scaled": applied != 1.0, "unit": unit})
|
||||
else:
|
||||
hours = round(task["hours"] * applied, 1)
|
||||
rr = roles[task["role"]]
|
||||
amt = rr * billing * hours
|
||||
tasks.append({"task": task["task"], "desc": task.get("desc", ""), "role": task["role"],
|
||||
"role_rate": rr, "hours": hours, "amount": amt,
|
||||
"scaled": applied != 1.0, "unit": unit})
|
||||
sub += amt
|
||||
modules.append({"name": mod["name"], "subtotal": sub, "tasks": tasks})
|
||||
grand += sub
|
||||
@@ -75,7 +85,8 @@ def build(scope, rate, catalog):
|
||||
proposal = int(math.floor(grand / rounding) * rounding)
|
||||
return {
|
||||
"kind": "effort", "service": catalog["service"], "label": t.get("label", catalog["service"]),
|
||||
"tier": tier, "billing_rate": billing,
|
||||
"tier": tier, "billing_rate": billing, "recurring": recurring,
|
||||
"notes": t.get("notes", []),
|
||||
"scope": {"driver": driver, "driver_count": dcount,
|
||||
"properties_total": signals.get("properties_total", 0),
|
||||
"subbrands_total": signals.get("subbrands_total", 0), "hours_multiplier": mult},
|
||||
|
||||
Reference in New Issue
Block a user