New skill 96-ourdigital-estimate-engine: method-aware quoting engine (effort / coaching / procurement) with universal rate_card + per-service catalog. Real catalogs: seo (effort), education (coaching); stubs: digital_ads, digital_branding. Validated to reproduce real quotes — SEO basic ₩10.5M / treatment ₩25.0M, SHR chain ₩29.5M, L'Escape basic ₩10.5M, GA4/GTM coaching ₩1,570,000, procurement +15%. Refactor 95-ourdigital-presales-seo: remove rate_card.yaml, sow_templates.yaml, estimate.py (migrated to engine); add findings_to_scope.py; Stage 5 now maps findings→scope.json and calls the engine CLI. build_deck/kg_query unchanged; end-to-end validated on SHR (29.5M) + deck renders engine estimate.json. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
19 lines
827 B
Python
19 lines
827 B
Python
"""Procurement method: cost = Σ(unit_cost × qty × (1 + markup)) for non-labor items."""
|
||
|
||
|
||
def build(scope, rate, catalog):
|
||
markup = rate.get("procurement_markup", 0.15)
|
||
items, total = [], 0.0
|
||
for it in scope.get("items", []):
|
||
qty = it.get("qty", 1)
|
||
amt = it["unit_cost"] * qty * (1 + markup)
|
||
items.append({"label": it["label"], "unit_cost": it["unit_cost"], "qty": qty,
|
||
"markup": markup, "amount": amt, "currency": it.get("currency", "KRW")})
|
||
total += amt
|
||
return {
|
||
"kind": "procurement", "service": catalog.get("service", "procurement"),
|
||
"label": "조달 항목 (Buying & Supplying)", "markup": markup,
|
||
"items": items, "subtotal_sum": total, "proposal": int(round(total)),
|
||
"stub": bool(catalog.get("_stub", False)),
|
||
}
|