UNPKG

business-as-code

Version:

Primitives for expressing business logic and processes as code

242 lines 6.97 kB
/** * Business process definition and management */ /** * Define a business process with steps, inputs, outputs, and metrics * * @example * ```ts * const process = Process({ * name: 'Customer Onboarding', * description: 'Process for onboarding new customers', * category: 'core', * owner: 'Customer Success Team', * steps: [ * { * order: 1, * name: 'Welcome Email', * description: 'Send personalized welcome email', * responsible: 'CS Manager', * duration: '5 minutes', * automationLevel: 'automated', * }, * { * order: 2, * name: 'Initial Setup Call', * description: 'Schedule and conduct setup call', * responsible: 'CS Rep', * duration: '30 minutes', * automationLevel: 'manual', * }, * { * order: 3, * name: 'Account Configuration', * description: 'Configure customer account settings', * responsible: 'CS Rep', * duration: '15 minutes', * automationLevel: 'semi-automated', * }, * ], * inputs: ['Customer Information', 'Subscription Plan'], * outputs: ['Configured Account', 'Training Materials'], * metrics: [ * { * name: 'Time to First Value', * description: 'Time from signup to first successful use', * target: 24, * unit: 'hours', * }, * { * name: 'Onboarding Completion Rate', * description: 'Percentage of customers completing onboarding', * target: 90, * unit: 'percent', * }, * ], * }) * ``` */ export function Process(definition) { if (!definition.name) { throw new Error('Process name is required'); } return { ...definition, category: definition.category || 'support', steps: definition.steps || [], inputs: definition.inputs || [], outputs: definition.outputs || [], metrics: definition.metrics || [], metadata: definition.metadata || {}, }; } /** * Get process steps in order */ export function getStepsInOrder(process) { return [...(process.steps || [])].sort((a, b) => a.order - b.order); } /** * Get steps by automation level */ export function getStepsByAutomationLevel(process, level) { return process.steps?.filter((step) => step.automationLevel === level) || []; } /** * Calculate total process duration in minutes */ export function calculateTotalDuration(process) { return (process.steps?.reduce((total, step) => { return total + parseDurationToMinutes(step.duration); }, 0) || 0); } /** * Parse duration string to minutes */ function parseDurationToMinutes(duration) { if (!duration) return 0; const lower = duration.toLowerCase(); const match = lower.match(/(\d+)\s*(minute|minutes|min|hour|hours|hr|day|days|week|weeks)/); if (!match) return 0; const value = parseInt(match[1] || '0', 10); const unit = match[2]; switch (unit) { case 'minute': case 'minutes': case 'min': return value; case 'hour': case 'hours': case 'hr': return value * 60; case 'day': case 'days': return value * 60 * 24; case 'week': case 'weeks': return value * 60 * 24 * 7; default: return 0; } } /** * Format minutes to human-readable duration */ export function formatDuration(minutes) { if (minutes < 60) { return `${minutes} minutes`; } else if (minutes < 60 * 24) { const hours = Math.floor(minutes / 60); const mins = minutes % 60; return mins > 0 ? `${hours} hours ${mins} minutes` : `${hours} hours`; } else { const days = Math.floor(minutes / (60 * 24)); const hours = Math.floor((minutes % (60 * 24)) / 60); return hours > 0 ? `${days} days ${hours} hours` : `${days} days`; } } /** * Calculate automation percentage */ export function calculateAutomationPercentage(process) { if (!process.steps || process.steps.length === 0) return 0; const automatedSteps = process.steps.filter((step) => step.automationLevel === 'automated' || step.automationLevel === 'semi-automated').length; return (automatedSteps / process.steps.length) * 100; } /** * Get metric by name */ export function getMetric(process, name) { return process.metrics?.find((m) => m.name === name); } /** * Check if metric meets target */ export function meetsTarget(metric) { if (metric.target === undefined || metric.current === undefined) return false; return metric.current >= metric.target; } /** * Calculate metric achievement percentage */ export function calculateMetricAchievement(metric) { if (metric.target === undefined || metric.current === undefined) return 0; if (metric.target === 0) return 100; return (metric.current / metric.target) * 100; } /** * Update metric current value */ export function updateMetric(process, metricName, currentValue) { const metrics = process.metrics?.map((m) => m.name === metricName ? { ...m, current: currentValue } : m); const result = { ...process }; if (metrics !== undefined) result.metrics = metrics; return result; } /** * Add step to process */ export function addStep(process, step) { return { ...process, steps: [...(process.steps || []), step], }; } /** * Remove step from process */ export function removeStep(process, stepOrder) { const steps = process.steps?.filter((s) => s.order !== stepOrder); const result = { ...process }; if (steps !== undefined) result.steps = steps; return result; } /** * Validate process definition */ export function validateProcess(process) { const errors = []; if (!process.name) { errors.push('Process name is required'); } if (process.steps) { const orders = new Set(); for (const step of process.steps) { if (!step.name) { errors.push(`Step at order ${step.order} must have a name`); } if (orders.has(step.order)) { errors.push(`Duplicate step order: ${step.order}`); } orders.add(step.order); } } if (process.metrics) { for (const metric of process.metrics) { if (!metric.name) { errors.push('Metric must have a name'); } if (metric.target !== undefined && metric.target < 0) { errors.push(`Metric ${metric.name} target cannot be negative`); } if (metric.current !== undefined && metric.current < 0) { errors.push(`Metric ${metric.name} current value cannot be negative`); } } } return { valid: errors.length === 0, errors, }; } //# sourceMappingURL=process.js.map