dodil/erp-brick-hr
src/brick_hr/domain/standards.py
"""Where a playbook and its steps sit in the APQC Process Classification Framework (PCF), so a BPMN reader — an
auditor, a process-mining tool, a buyer comparing with their SAP or Oracle map — can join on an id they already use.
Every id below is from the APQC PCF Cross-Industry v8.0 (generated 2026-02-25; the workbook named in
erp-bench standards/processes.yaml), verified by id AND name; nothing is guessed. A step with no clear mapping
carries none. ©2026 APQC. ALL RIGHTS RESERVED. This Process Classification Framework® ("PCF") is the copyrighted
intellectual property of APQC; it is used here under APQC's licence, which requires this notice on every copy.
"""
from typing import Optional
# direction → the process it implements
PROCESS_PCF = {
"onboarding": ("10469", "Manage employee onboarding"), # 7.3.1
"offboarding": ("21710", "Manage offboarding"), # 7.6.2.3
"change": ("10524", "Manage and maintain employee data"), # 7.7.3
"conversion": ("10524", "Manage and maintain employee data"), # 7.7.3
}
# a capability (family) → the activity it performs
CAPABILITY_PCF = {
"identity": ("20758", "Manage IT user directory"), # 8.3.8.2
"groups": ("20759", "Manage IT user authorization"), # 8.3.8.3
"chat": ("20759", "Manage IT user authorization"), # 8.3.8.3
"contracts": ("11052", "Negotiate and document agreements/contracts"), # 12.4.9
}
# a step kind → the activity (the starter's own form keeps the employee record)
KIND_PCF = {"intake": ("10524", "Manage and maintain employee data")} # 7.7.3
# a designed step key (localisation packs) → the activity, where neither its capability nor its kind says it
KEY_PCF = {
"payroll_setup": ("10497", "Administer Payroll"), # 7.5.4
"final_pay": ("10497", "Administer Payroll"), # 7.5.4
"offer_outplacement": ("10516", "Develop and implement employee outplacement"), # 7.6.2.4
"pension_notice": ("10514", "Manage retirement"), # 7.6.2.1
"knowledge_handover": ("10514", "Manage retirement"), # 7.6.2.1
"long_service_recognition": ("10514", "Manage retirement"), # 7.6.2.1
}
def process_pcf(direction: str) -> Optional[tuple]:
return PROCESS_PCF.get(direction)
def step_pcf(key: str, kind: str, capability: Optional[str]) -> Optional[tuple]:
"""(pcf_id, name) for one step, or None when the PCF has no activity that is clearly this one."""
if key in KEY_PCF:
return KEY_PCF[key]
if capability:
return CAPABILITY_PCF.get(capability.split(".")[0])
return KIND_PCF.get(kind)
__all__ = ["process_pcf", "step_pcf", "PROCESS_PCF"]