@happyvertical/smrt-support 0.39.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +270 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/dist/__smrt-register__.d.ts +2 -0
- package/dist/__smrt-register__.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4358 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.json +6770 -0
- package/dist/models/index.d.ts +17 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/service-time-entry.d.ts +75 -0
- package/dist/models/service-time-entry.d.ts.map +1 -0
- package/dist/models/support-ai-run.d.ts +45 -0
- package/dist/models/support-ai-run.d.ts.map +1 -0
- package/dist/models/support-case-event.d.ts +25 -0
- package/dist/models/support-case-event.d.ts.map +1 -0
- package/dist/models/support-case.d.ts +125 -0
- package/dist/models/support-case.d.ts.map +1 -0
- package/dist/models/support-channel-binding.d.ts +47 -0
- package/dist/models/support-channel-binding.d.ts.map +1 -0
- package/dist/models/support-compensation-plan.d.ts +42 -0
- package/dist/models/support-compensation-plan.d.ts.map +1 -0
- package/dist/models/support-interaction.d.ts +49 -0
- package/dist/models/support-interaction.d.ts.map +1 -0
- package/dist/models/support-plan.d.ts +92 -0
- package/dist/models/support-plan.d.ts.map +1 -0
- package/dist/models/support-policy.d.ts +84 -0
- package/dist/models/support-policy.d.ts.map +1 -0
- package/dist/models/support-service-target.d.ts +90 -0
- package/dist/models/support-service-target.d.ts.map +1 -0
- package/dist/models/support-settlement.d.ts +58 -0
- package/dist/models/support-settlement.d.ts.map +1 -0
- package/dist/models/support-specialist.d.ts +71 -0
- package/dist/models/support-specialist.d.ts.map +1 -0
- package/dist/models/support-work-link.d.ts +31 -0
- package/dist/models/support-work-link.d.ts.map +1 -0
- package/dist/permissions.d.ts +32 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/services/coverage-calendar.d.ts +53 -0
- package/dist/services/coverage-calendar.d.ts.map +1 -0
- package/dist/services/human-handoff-service.d.ts +113 -0
- package/dist/services/human-handoff-service.d.ts.map +1 -0
- package/dist/services/index.d.ts +15 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/keyed-mutex.d.ts +22 -0
- package/dist/services/keyed-mutex.d.ts.map +1 -0
- package/dist/services/service-target-engine.d.ts +133 -0
- package/dist/services/service-target-engine.d.ts.map +1 -0
- package/dist/services/service-time-entry-service.d.ts +73 -0
- package/dist/services/service-time-entry-service.d.ts.map +1 -0
- package/dist/services/support-ai-workflow.d.ts +178 -0
- package/dist/services/support-ai-workflow.d.ts.map +1 -0
- package/dist/services/support-case-service.d.ts +162 -0
- package/dist/services/support-case-service.d.ts.map +1 -0
- package/dist/services/support-intake-service.d.ts +106 -0
- package/dist/services/support-intake-service.d.ts.map +1 -0
- package/dist/services/support-plan-admin-service.d.ts +45 -0
- package/dist/services/support-plan-admin-service.d.ts.map +1 -0
- package/dist/services/support-routing-service.d.ts +117 -0
- package/dist/services/support-routing-service.d.ts.map +1 -0
- package/dist/services/time-entry-approval-service.d.ts +162 -0
- package/dist/services/time-entry-approval-service.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +4242 -0
- package/dist/svelte/components/CaseDetail.svelte +277 -0
- package/dist/svelte/components/CaseDetail.svelte.d.ts +10 -0
- package/dist/svelte/components/CaseDetail.svelte.d.ts.map +1 -0
- package/dist/svelte/components/CaseQueue.svelte +148 -0
- package/dist/svelte/components/CaseQueue.svelte.d.ts +12 -0
- package/dist/svelte/components/CaseQueue.svelte.d.ts.map +1 -0
- package/dist/svelte/components/RoutingRationale.svelte +131 -0
- package/dist/svelte/components/RoutingRationale.svelte.d.ts +11 -0
- package/dist/svelte/components/RoutingRationale.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TargetList.svelte +127 -0
- package/dist/svelte/components/TargetList.svelte.d.ts +9 -0
- package/dist/svelte/components/TargetList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TimeEntryApprovalQueue.svelte +226 -0
- package/dist/svelte/components/TimeEntryApprovalQueue.svelte.d.ts +11 -0
- package/dist/svelte/components/TimeEntryApprovalQueue.svelte.d.ts.map +1 -0
- package/dist/svelte/components/__tests__/CaseDetail.test.js +86 -0
- package/dist/svelte/components/__tests__/CaseQueue.test.js +67 -0
- package/dist/svelte/components/__tests__/RoutingRationale.test.js +69 -0
- package/dist/svelte/components/__tests__/TargetList.test.js +84 -0
- package/dist/svelte/components/__tests__/TimeEntryApprovalQueue.test.js +105 -0
- package/dist/svelte/index.d.ts +25 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +18 -0
- package/dist/svelte/types.d.ts +129 -0
- package/dist/svelte/types.d.ts.map +1 -0
- package/dist/svelte/types.js +182 -0
- package/dist/types.d.ts +130 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +109 -0
- package/dist/types.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { SmrtObject, SmrtObjectOptions } from '@happyvertical/smrt-core';
|
|
2
|
+
import { SupportCase } from '../models/support-case.js';
|
|
3
|
+
import { SupportChannelBinding, SupportChannelBindingCollection } from '../models/support-channel-binding.js';
|
|
4
|
+
import { SupportInteraction } from '../models/support-interaction.js';
|
|
5
|
+
import { SupportCaseService } from './support-case-service.js';
|
|
6
|
+
/** Qualified source types intake understands. */
|
|
7
|
+
export declare const CHAT_MESSAGE_SOURCE_TYPE = "@happyvertical/smrt-chat:ChatMessage";
|
|
8
|
+
export declare const CHAT_ROOM_TARGET_TYPE = "@happyvertical/smrt-chat:ChatRoom";
|
|
9
|
+
export declare const EMAIL_SOURCE_TYPE = "@happyvertical/smrt-messages:Email";
|
|
10
|
+
export declare const EMAIL_ACCOUNT_TARGET_TYPE = "@happyvertical/smrt-messages:EmailAccount";
|
|
11
|
+
export interface InboundChatMessage {
|
|
12
|
+
messageId: string;
|
|
13
|
+
roomId: string;
|
|
14
|
+
threadId?: string | null;
|
|
15
|
+
senderProfileId: string;
|
|
16
|
+
/** Chat role; only `user` messages are client inbound. */
|
|
17
|
+
role?: string;
|
|
18
|
+
content: string;
|
|
19
|
+
tenantId?: string | null;
|
|
20
|
+
occurredAt?: Date;
|
|
21
|
+
}
|
|
22
|
+
export interface InboundEmail {
|
|
23
|
+
emailId: string;
|
|
24
|
+
accountId: string;
|
|
25
|
+
fromAddress: string;
|
|
26
|
+
fromName?: string;
|
|
27
|
+
subject?: string;
|
|
28
|
+
body: string;
|
|
29
|
+
/** RFC 822 Message-ID of this email. */
|
|
30
|
+
rfcMessageId?: string | null;
|
|
31
|
+
/** RFC 822 Message-ID this email replies to. */
|
|
32
|
+
inReplyTo?: string | null;
|
|
33
|
+
tenantId?: string | null;
|
|
34
|
+
occurredAt?: Date;
|
|
35
|
+
}
|
|
36
|
+
export interface IntakeResult {
|
|
37
|
+
outcome: 'created' | 'joined' | 'reopened' | 'skipped';
|
|
38
|
+
reason?: string;
|
|
39
|
+
supportCase?: SupportCase;
|
|
40
|
+
interaction?: SupportInteraction;
|
|
41
|
+
binding?: SupportChannelBinding;
|
|
42
|
+
}
|
|
43
|
+
export interface SupportIntakeOptions extends SmrtObjectOptions {
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the Client profile for an inbound email sender. When omitted and
|
|
46
|
+
* the binding has no default client, the case is parked with
|
|
47
|
+
* `metadata.unresolvedClient = true` for operator triage.
|
|
48
|
+
*/
|
|
49
|
+
resolveClientProfileId?: (input: {
|
|
50
|
+
email: string;
|
|
51
|
+
name?: string;
|
|
52
|
+
tenantId?: string | null;
|
|
53
|
+
}) => Promise<string | null>;
|
|
54
|
+
/**
|
|
55
|
+
* Called after intake creates or updates a case — the AI workflow and the
|
|
56
|
+
* target engine attach here without a hard dependency cycle.
|
|
57
|
+
*/
|
|
58
|
+
onCaseIntake?: (result: IntakeResult) => Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
export declare class SupportIntakeService {
|
|
61
|
+
readonly caseService: SupportCaseService;
|
|
62
|
+
readonly bindings: SupportChannelBindingCollection;
|
|
63
|
+
private readonly options;
|
|
64
|
+
private readonly conversationMutex;
|
|
65
|
+
protected constructor(caseService: SupportCaseService, bindings: SupportChannelBindingCollection, options: SupportIntakeOptions);
|
|
66
|
+
static create(options: SupportIntakeOptions): Promise<SupportIntakeService>;
|
|
67
|
+
/** Conversation key for a chat room/thread. */
|
|
68
|
+
static chatThreadKey(roomId: string, threadId?: string | null): string;
|
|
69
|
+
/** Idempotency key for a chat message. */
|
|
70
|
+
static chatSourceKey(messageId: string): string;
|
|
71
|
+
/** Idempotency key for an email. */
|
|
72
|
+
static emailSourceKey(emailId: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Ingest one inbound chat message from a bound room: create-or-join the
|
|
75
|
+
* conversation's case and record the interaction.
|
|
76
|
+
*/
|
|
77
|
+
ingestChatMessage(input: InboundChatMessage): Promise<IntakeResult>;
|
|
78
|
+
/**
|
|
79
|
+
* Ingest one inbound email from a bound account: joins the RFC thread's
|
|
80
|
+
* case when `inReplyTo` references a known interaction, else creates a new
|
|
81
|
+
* case keyed by the message id. Mail sent FROM the binding's own addresses
|
|
82
|
+
* is skipped (our outbound side of the conversation).
|
|
83
|
+
*/
|
|
84
|
+
ingestEmail(input: InboundEmail): Promise<IntakeResult>;
|
|
85
|
+
/** The shared create-or-join core (deterministic per conversation key). */
|
|
86
|
+
private createOrJoin;
|
|
87
|
+
private createOrJoinExclusive;
|
|
88
|
+
private findResolvedByThreadKey;
|
|
89
|
+
private findInteractionByRfcMessageId;
|
|
90
|
+
}
|
|
91
|
+
/** Interceptor name used for registration/unregistration. */
|
|
92
|
+
export declare const SUPPORT_INTAKE_INTERCEPTOR = "smrt-support:intake";
|
|
93
|
+
/**
|
|
94
|
+
* Opt-in ambient intake: observe saves of `ChatMessage` and `Email` rows via
|
|
95
|
+
* core `GlobalInterceptors` and feed them through the intake service. Only
|
|
96
|
+
* containers with an enabled {@link SupportChannelBinding} produce cases;
|
|
97
|
+
* everything else passes through untouched. Errors are logged, never thrown —
|
|
98
|
+
* intake must not break the source package's save path.
|
|
99
|
+
*
|
|
100
|
+
* @returns An unregister function.
|
|
101
|
+
*/
|
|
102
|
+
export declare function registerSupportIntake(intake: SupportIntakeService, options?: {
|
|
103
|
+
onError?: (error: unknown, instance: SmrtObject) => void;
|
|
104
|
+
}): () => void;
|
|
105
|
+
export default SupportIntakeService;
|
|
106
|
+
//# sourceMappingURL=support-intake-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"support-intake-service.d.ts","sourceRoot":"","sources":["../../src/services/support-intake-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { SmrtObjectOptions } from '@happyvertical/smrt-core';
|
|
2
|
+
import { SupportCompensationPlan, SupportCompensationPlanCollection } from '../models/support-compensation-plan.js';
|
|
3
|
+
import { SupportPlan, SupportPlanCollection } from '../models/support-plan.js';
|
|
4
|
+
import { SupportPrincipal } from '../permissions.js';
|
|
5
|
+
/** Thrown when a plan write is attempted without the manage-plans split. */
|
|
6
|
+
export declare class PlanAdminDeniedError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
export interface PlanAdminActor {
|
|
10
|
+
principal: SupportPrincipal;
|
|
11
|
+
}
|
|
12
|
+
export declare class SupportPlanAdminService {
|
|
13
|
+
readonly plans: SupportPlanCollection;
|
|
14
|
+
readonly compensationPlans: SupportCompensationPlanCollection;
|
|
15
|
+
protected constructor(collections: {
|
|
16
|
+
plans: SupportPlanCollection;
|
|
17
|
+
compensationPlans: SupportCompensationPlanCollection;
|
|
18
|
+
});
|
|
19
|
+
static create(options: SmrtObjectOptions): Promise<SupportPlanAdminService>;
|
|
20
|
+
/** Create (or overwrite via natural key) a Managed Support Plan. */
|
|
21
|
+
savePlan(input: PlanAdminActor & {
|
|
22
|
+
fields: Record<string, unknown>;
|
|
23
|
+
}): Promise<SupportPlan>;
|
|
24
|
+
/** Update an existing Managed Support Plan's fields. */
|
|
25
|
+
updatePlan(planId: string, input: PlanAdminActor & {
|
|
26
|
+
fields: Record<string, unknown>;
|
|
27
|
+
}): Promise<SupportPlan>;
|
|
28
|
+
/** Archive a Managed Support Plan (soft retirement; history untouched). */
|
|
29
|
+
archivePlan(planId: string, input: PlanAdminActor): Promise<SupportPlan>;
|
|
30
|
+
/** Create a Support Compensation Plan (effective-dated earning terms). */
|
|
31
|
+
saveCompensationPlan(input: PlanAdminActor & {
|
|
32
|
+
fields: Record<string, unknown>;
|
|
33
|
+
}): Promise<SupportCompensationPlan>;
|
|
34
|
+
/** Update an existing Support Compensation Plan's fields. */
|
|
35
|
+
updateCompensationPlan(planId: string, input: PlanAdminActor & {
|
|
36
|
+
fields: Record<string, unknown>;
|
|
37
|
+
}): Promise<SupportCompensationPlan>;
|
|
38
|
+
/** Archive a Support Compensation Plan. */
|
|
39
|
+
archiveCompensationPlan(planId: string, input: PlanAdminActor): Promise<SupportCompensationPlan>;
|
|
40
|
+
protected assertManager(principal: SupportPrincipal | undefined, act: string): void;
|
|
41
|
+
/** Cross-tenant plan writes are refused when both sides carry a tenant. */
|
|
42
|
+
protected assertTenant(principal: SupportPrincipal, planTenantId: string | null): void;
|
|
43
|
+
}
|
|
44
|
+
export default SupportPlanAdminService;
|
|
45
|
+
//# sourceMappingURL=support-plan-admin-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"support-plan-admin-service.d.ts","sourceRoot":"","sources":["../../src/services/support-plan-admin-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACL,KAAK,uBAAuB,EAC5B,iCAAiC,EAClC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,KAAK,WAAW,EAChB,qBAAqB,EACtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAE3B,4EAA4E;AAC5E,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,gBAAgB,CAAC;CAC7B;AAED,qBAAa,uBAAuB;IAClC,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IACtC,QAAQ,CAAC,iBAAiB,EAAE,iCAAiC,CAAC;IAE9D,SAAS,aAAa,WAAW,EAAE;QACjC,KAAK,EAAE,qBAAqB,CAAC;QAC7B,iBAAiB,EAAE,iCAAiC,CAAC;KACtD;WAKY,MAAM,CACjB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,uBAAuB,CAAC;IAQnC,oEAAoE;IAC9D,QAAQ,CACZ,KAAK,EAAE,cAAc,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAC1D,OAAO,CAAC,WAAW,CAAC;IASvB,wDAAwD;IAClD,UAAU,CACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,cAAc,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAC1D,OAAO,CAAC,WAAW,CAAC;IAYvB,2EAA2E;IACrE,WAAW,CACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,WAAW,CAAC;IAOvB,0EAA0E;IACpE,oBAAoB,CACxB,KAAK,EAAE,cAAc,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAC1D,OAAO,CAAC,uBAAuB,CAAC;IASnC,6DAA6D;IACvD,sBAAsB,CAC1B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,cAAc,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAC1D,OAAO,CAAC,uBAAuB,CAAC;IAYnC,2CAA2C;IACrC,uBAAuB,CAC3B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,uBAAuB,CAAC;IAOnC,SAAS,CAAC,aAAa,CACrB,SAAS,EAAE,gBAAgB,GAAG,SAAS,EACvC,GAAG,EAAE,MAAM,GACV,IAAI;IAQP,2EAA2E;IAC3E,SAAS,CAAC,YAAY,CACpB,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,GAC1B,IAAI;CAUR;AAED,eAAe,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { SmrtObjectOptions } from '@happyvertical/smrt-core';
|
|
2
|
+
import { SupportCase } from '../models/support-case.js';
|
|
3
|
+
import { SupportAvailabilityCollection, SupportQualificationCollection, SupportSpecialistCollection } from '../models/support-specialist.js';
|
|
4
|
+
import { SupportPrincipal } from '../permissions.js';
|
|
5
|
+
import { SupportActorKind } from '../types.js';
|
|
6
|
+
import { SupportCaseService } from './support-case-service.js';
|
|
7
|
+
/**
|
|
8
|
+
* Named scoring weights, so the ranking is auditable against the code.
|
|
9
|
+
* Factors carry the raw signals; the score composes them with these weights.
|
|
10
|
+
*/
|
|
11
|
+
export declare const ROUTING_WEIGHTS: {
|
|
12
|
+
/** Case/plan preferred specialist (FR-30) — considered first. */
|
|
13
|
+
readonly PREFERRED_SPECIALIST: 100;
|
|
14
|
+
/** Effective `expert` Project Support Qualification. */
|
|
15
|
+
readonly QUALIFICATION_EXPERT: 30;
|
|
16
|
+
/** Effective `qualified` Project Support Qualification. */
|
|
17
|
+
readonly QUALIFICATION_QUALIFIED: 20;
|
|
18
|
+
/** Effective `trainee` Project Support Qualification. */
|
|
19
|
+
readonly QUALIFICATION_TRAINEE: 5;
|
|
20
|
+
/** An active on-call span at the routing instant. */
|
|
21
|
+
readonly ON_CALL: 25;
|
|
22
|
+
/** A weekly availability window covering the routing instant. */
|
|
23
|
+
readonly WEEKLY_AVAILABLE: 15;
|
|
24
|
+
/** Maximum workload-headroom bonus (scaled by free capacity). */
|
|
25
|
+
readonly WORKLOAD_HEADROOM_MAX: 10;
|
|
26
|
+
/** Case language ∈ specialist languages. */
|
|
27
|
+
readonly LANGUAGE_MATCH: 10;
|
|
28
|
+
};
|
|
29
|
+
/** One specialist's routing evaluation for a case. */
|
|
30
|
+
export interface RankedSpecialist {
|
|
31
|
+
specialistId: string;
|
|
32
|
+
displayName: string;
|
|
33
|
+
score: number;
|
|
34
|
+
/** Whether every hard eligibility filter passed. */
|
|
35
|
+
eligible: boolean;
|
|
36
|
+
/** The raw signals behind the score/eligibility (rationale display). */
|
|
37
|
+
factors: Record<string, number | string | boolean>;
|
|
38
|
+
}
|
|
39
|
+
/** Result of an {@link SupportRoutingService.autoAssign} attempt. */
|
|
40
|
+
export interface AutoAssignResult {
|
|
41
|
+
assigned: boolean;
|
|
42
|
+
specialistId?: string;
|
|
43
|
+
ranking: RankedSpecialist[];
|
|
44
|
+
}
|
|
45
|
+
/** Thrown when a manual reassignment is refused (permission or tenant). */
|
|
46
|
+
export declare class ReassignDeniedError extends Error {
|
|
47
|
+
constructor(message: string);
|
|
48
|
+
}
|
|
49
|
+
/** Options for {@link SupportRoutingService.create}. */
|
|
50
|
+
export interface SupportRoutingServiceOptions extends SmrtObjectOptions {
|
|
51
|
+
/** Share an existing case service (and its collections) with the router. */
|
|
52
|
+
caseService?: SupportCaseService;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The routing engine. Construct with {@link SupportRoutingService.create}.
|
|
56
|
+
*/
|
|
57
|
+
export declare class SupportRoutingService {
|
|
58
|
+
readonly caseService: SupportCaseService;
|
|
59
|
+
readonly specialists: SupportSpecialistCollection;
|
|
60
|
+
readonly qualifications: SupportQualificationCollection;
|
|
61
|
+
readonly availabilities: SupportAvailabilityCollection;
|
|
62
|
+
protected constructor(collections: {
|
|
63
|
+
caseService: SupportCaseService;
|
|
64
|
+
specialists: SupportSpecialistCollection;
|
|
65
|
+
qualifications: SupportQualificationCollection;
|
|
66
|
+
availabilities: SupportAvailabilityCollection;
|
|
67
|
+
});
|
|
68
|
+
static create(options: SupportRoutingServiceOptions): Promise<SupportRoutingService>;
|
|
69
|
+
private resolveCase;
|
|
70
|
+
/**
|
|
71
|
+
* Rank every Support Specialist for a case at an instant.
|
|
72
|
+
*
|
|
73
|
+
* Hard eligibility filters — each recorded as a factor:
|
|
74
|
+
* - `status` must be `active`;
|
|
75
|
+
* - when the case carries a `projectId`, an *effective* Project Support
|
|
76
|
+
* Qualification for that project (`projectQualification` is the level,
|
|
77
|
+
* or `'expired'`/`'none'` on failure);
|
|
78
|
+
* - open assigned cases below `maxConcurrentCases` (`openCases`,
|
|
79
|
+
* `workloadExceeded`);
|
|
80
|
+
* - available at `at`: a weekly window in the specialist's own timezone or
|
|
81
|
+
* an active on-call span, and not inside a time-off span
|
|
82
|
+
* (`weeklyAvailable`, `onCall`, `timeOff`).
|
|
83
|
+
*
|
|
84
|
+
* Ineligible specialists are returned too (`eligible: false`) so the UI
|
|
85
|
+
* can show the failing factor. Sorted by score descending, then display
|
|
86
|
+
* name, then id.
|
|
87
|
+
*/
|
|
88
|
+
rankSpecialists(caseRef: SupportCase | string, opts?: {
|
|
89
|
+
at?: Date;
|
|
90
|
+
exclude?: string[];
|
|
91
|
+
}): Promise<RankedSpecialist[]>;
|
|
92
|
+
private evaluateSpecialist;
|
|
93
|
+
/**
|
|
94
|
+
* Assign the top eligible ranked specialist, recording the rationale
|
|
95
|
+
* (winning factors plus the compact top of the ranking) on the assignment
|
|
96
|
+
* event. When no one is eligible, records an unrouted `note` event with
|
|
97
|
+
* the full ranking and returns `assigned: false`.
|
|
98
|
+
*/
|
|
99
|
+
autoAssign(caseRef: SupportCase | string, opts?: {
|
|
100
|
+
at?: Date;
|
|
101
|
+
exclude?: string[];
|
|
102
|
+
actorKind?: SupportActorKind;
|
|
103
|
+
}): Promise<AutoAssignResult>;
|
|
104
|
+
/**
|
|
105
|
+
* Manual reassignment override (FR-30). Requires the
|
|
106
|
+
* `support.reassign-case` permission split on the acting principal and
|
|
107
|
+
* refuses cross-tenant acts; the assignment event carries
|
|
108
|
+
* `{ manual: true, note }` as its rationale.
|
|
109
|
+
*/
|
|
110
|
+
reassign(caseRef: SupportCase | string, input: {
|
|
111
|
+
specialistId: string;
|
|
112
|
+
principal: SupportPrincipal;
|
|
113
|
+
note?: string;
|
|
114
|
+
}): Promise<SupportCase>;
|
|
115
|
+
}
|
|
116
|
+
export default SupportRoutingService;
|
|
117
|
+
//# sourceMappingURL=support-routing-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"support-routing-service.d.ts","sourceRoot":"","sources":["../../src/services/support-routing-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { SmrtObjectOptions } from '@happyvertical/smrt-core';
|
|
2
|
+
import { ServiceTimeEntry, ServiceTimeEntryCollection } from '../models/service-time-entry.js';
|
|
3
|
+
import { SupportCase } from '../models/support-case.js';
|
|
4
|
+
import { SupportCompensationPlanCollection } from '../models/support-compensation-plan.js';
|
|
5
|
+
import { SupportCharge, SupportChargeCollection, SupportCompensation, SupportCompensationCollection } from '../models/support-settlement.js';
|
|
6
|
+
import { SupportPrincipal } from '../permissions.js';
|
|
7
|
+
import { TimeApprovalPolicy, TimeEntryApprovalPath, TimeEntryEvidence } from '../types.js';
|
|
8
|
+
import { SupportCaseService } from './support-case-service.js';
|
|
9
|
+
/** Thrown when an approval-path or tenant gate refuses the acting principal. */
|
|
10
|
+
export declare class TimeEntryApprovalDeniedError extends Error {
|
|
11
|
+
constructor(reason: string);
|
|
12
|
+
}
|
|
13
|
+
/** Options for {@link TimeEntryApprovalService.create}. */
|
|
14
|
+
export interface TimeEntryApprovalServiceOptions extends SmrtObjectOptions {
|
|
15
|
+
/** Share an existing case facade (otherwise one is created internally). */
|
|
16
|
+
caseService?: SupportCaseService;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The plan terms governing one entry's approval and pricing, resolved from
|
|
20
|
+
* the case's frozen `planSnapshot` first, then the live plan row, else
|
|
21
|
+
* zero-rate defaults (operator approval, nothing charged).
|
|
22
|
+
*/
|
|
23
|
+
export interface ResolvedPlanTerms {
|
|
24
|
+
policy: TimeApprovalPolicy;
|
|
25
|
+
currency: string;
|
|
26
|
+
includedMinutes: number;
|
|
27
|
+
overageHourlyRate: number;
|
|
28
|
+
onCallHourlyRate: number;
|
|
29
|
+
planId: string | null;
|
|
30
|
+
planKey: string;
|
|
31
|
+
}
|
|
32
|
+
/** Input for {@link TimeEntryApprovalService.approve}. */
|
|
33
|
+
export interface ApproveTimeEntryInput {
|
|
34
|
+
/** Acting principal; optional only for the `automatic` path. */
|
|
35
|
+
principal?: SupportPrincipal;
|
|
36
|
+
note?: string;
|
|
37
|
+
/** Approval instant (defaults to now); also the derivation timestamp. */
|
|
38
|
+
at?: Date;
|
|
39
|
+
}
|
|
40
|
+
/** Result of {@link TimeEntryApprovalService.approve}. */
|
|
41
|
+
export interface ApproveTimeEntryResult {
|
|
42
|
+
entry: ServiceTimeEntry;
|
|
43
|
+
charge: SupportCharge;
|
|
44
|
+
compensation: SupportCompensation;
|
|
45
|
+
path: TimeEntryApprovalPath;
|
|
46
|
+
}
|
|
47
|
+
/** Input for {@link TimeEntryApprovalService.reject}. */
|
|
48
|
+
export interface RejectTimeEntryInput {
|
|
49
|
+
principal: SupportPrincipal;
|
|
50
|
+
reason: string;
|
|
51
|
+
}
|
|
52
|
+
/** Input for {@link TimeEntryApprovalService.correct}. */
|
|
53
|
+
export interface CorrectTimeEntryInput {
|
|
54
|
+
principal: SupportPrincipal;
|
|
55
|
+
patch: Partial<{
|
|
56
|
+
durationSeconds: number;
|
|
57
|
+
startedAt: Date;
|
|
58
|
+
endedAt: Date;
|
|
59
|
+
description: string;
|
|
60
|
+
evidence: TimeEntryEvidence[];
|
|
61
|
+
}>;
|
|
62
|
+
note?: string;
|
|
63
|
+
}
|
|
64
|
+
/** Result of {@link TimeEntryApprovalService.correct}. */
|
|
65
|
+
export interface CorrectTimeEntryResult {
|
|
66
|
+
/** The superseded entry, now `corrected` with its snapshot intact. */
|
|
67
|
+
original: ServiceTimeEntry;
|
|
68
|
+
/** The new `draft` entry carrying the patch (flows submit → approve). */
|
|
69
|
+
correction: ServiceTimeEntry;
|
|
70
|
+
}
|
|
71
|
+
/** Charge math derived from the plan terms before any row is written. */
|
|
72
|
+
interface ChargeDerivation {
|
|
73
|
+
billableSeconds: number;
|
|
74
|
+
includedSecondsBefore: number;
|
|
75
|
+
includedSecondsApplied: number;
|
|
76
|
+
hourlyRate: number;
|
|
77
|
+
rateSource: 'overage' | 'on_call' | 'none';
|
|
78
|
+
amount: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The approval gate. Construct with {@link TimeEntryApprovalService.create}.
|
|
82
|
+
*/
|
|
83
|
+
export declare class TimeEntryApprovalService {
|
|
84
|
+
readonly entries: ServiceTimeEntryCollection;
|
|
85
|
+
readonly charges: SupportChargeCollection;
|
|
86
|
+
readonly compensations: SupportCompensationCollection;
|
|
87
|
+
readonly compensationPlans: SupportCompensationPlanCollection;
|
|
88
|
+
readonly caseService: SupportCaseService;
|
|
89
|
+
private readonly approvalMutex;
|
|
90
|
+
protected constructor(collections: {
|
|
91
|
+
entries: ServiceTimeEntryCollection;
|
|
92
|
+
charges: SupportChargeCollection;
|
|
93
|
+
compensations: SupportCompensationCollection;
|
|
94
|
+
compensationPlans: SupportCompensationPlanCollection;
|
|
95
|
+
caseService: SupportCaseService;
|
|
96
|
+
});
|
|
97
|
+
static create(options: TimeEntryApprovalServiceOptions): Promise<TimeEntryApprovalService>;
|
|
98
|
+
/** Load an entry or throw a descriptive error. */
|
|
99
|
+
getEntry(entryRef: ServiceTimeEntry | string): Promise<ServiceTimeEntry>;
|
|
100
|
+
/**
|
|
101
|
+
* Resolve the plan terms governing an entry: the case's frozen
|
|
102
|
+
* `planSnapshot` wins field-by-field (history never rewritten by plan
|
|
103
|
+
* edits), the live plan row fills gaps, and with no case or plan at all the
|
|
104
|
+
* terms fall back to zero rates under operator approval.
|
|
105
|
+
*/
|
|
106
|
+
resolvePlanTerms(entry: ServiceTimeEntry, supportCase?: SupportCase | null): Promise<ResolvedPlanTerms>;
|
|
107
|
+
/**
|
|
108
|
+
* Approve a `submitted` entry: gate the acting principal by the plan's
|
|
109
|
+
* approval policy, freeze the entry, and derive its charge and compensation
|
|
110
|
+
* snapshots. Throws {@link TimeEntryApprovalDeniedError} when the gate
|
|
111
|
+
* refuses.
|
|
112
|
+
*/
|
|
113
|
+
approve(entryRef: ServiceTimeEntry | string, input?: ApproveTimeEntryInput): Promise<ApproveTimeEntryResult>;
|
|
114
|
+
private approveExclusive;
|
|
115
|
+
/**
|
|
116
|
+
* Reject a `submitted` entry with a reason (requires the
|
|
117
|
+
* `support.approve-time-entry` split).
|
|
118
|
+
*/
|
|
119
|
+
reject(entryRef: ServiceTimeEntry | string, input: RejectTimeEntryInput): Promise<ServiceTimeEntry>;
|
|
120
|
+
/**
|
|
121
|
+
* Correct an `approved` entry (requires the `support.approve-time-entry`
|
|
122
|
+
* split): a NEW `draft` entry copies the original's context, participant,
|
|
123
|
+
* and source with the patch applied and links back via `correctionOfId`;
|
|
124
|
+
* the original flips to `corrected` with its frozen fields and snapshots
|
|
125
|
+
* untouched, and its charge/compensation rows are marked `corrected`. The
|
|
126
|
+
* correction then flows submit → approve normally, deriving fresh
|
|
127
|
+
* snapshots.
|
|
128
|
+
*/
|
|
129
|
+
correct(entryRef: ServiceTimeEntry | string, input: CorrectTimeEntryInput): Promise<CorrectTimeEntryResult>;
|
|
130
|
+
/**
|
|
131
|
+
* Determine the approval path for an entry under a policy, or throw
|
|
132
|
+
* {@link TimeEntryApprovalDeniedError} when the acting principal does not
|
|
133
|
+
* satisfy it.
|
|
134
|
+
*/
|
|
135
|
+
protected determinePath(entry: ServiceTimeEntry, policy: TimeApprovalPolicy, chargeAmount: number, principal: SupportPrincipal | undefined, supportCase: SupportCase | null): TimeEntryApprovalPath;
|
|
136
|
+
/**
|
|
137
|
+
* Charge math from the Managed Support Plan terms: remaining included time
|
|
138
|
+
* (per case — period windows are #1925's scope) absorbs first, the
|
|
139
|
+
* remainder meters at the overage (or on-call) hourly rate.
|
|
140
|
+
*/
|
|
141
|
+
protected deriveCharge(entry: ServiceTimeEntry, terms: ResolvedPlanTerms): Promise<ChargeDerivation>;
|
|
142
|
+
/**
|
|
143
|
+
* Provider earning from the Support Compensation Plan effective at the work
|
|
144
|
+
* instant (`endedAt`, falling back to the approval instant). No specialist
|
|
145
|
+
* or no plan resolves to a zero-amount row so the entry still settles.
|
|
146
|
+
*/
|
|
147
|
+
protected deriveCompensation(entry: ServiceTimeEntry, at: Date): Promise<SupportCompensation>;
|
|
148
|
+
/**
|
|
149
|
+
* Idempotent write of the entry's single charge row: an approval retry
|
|
150
|
+
* after a partial failure refreshes the existing row instead of colliding
|
|
151
|
+
* on the `time_entry_id` unique key.
|
|
152
|
+
*/
|
|
153
|
+
protected upsertChargeRow(entry: ServiceTimeEntry, fields: Record<string, unknown>): Promise<SupportCharge>;
|
|
154
|
+
/** Idempotent write of the entry's single compensation row (see above). */
|
|
155
|
+
protected upsertCompensationRow(entry: ServiceTimeEntry, fields: Record<string, unknown>): Promise<SupportCompensation>;
|
|
156
|
+
/** Cross-tenant acts are refused when both sides carry a tenant. */
|
|
157
|
+
protected assertTenantMatch(entry: ServiceTimeEntry, principal: SupportPrincipal | undefined): void;
|
|
158
|
+
/** Require the operator permission split for a privileged act. */
|
|
159
|
+
protected assertOperator(principal: SupportPrincipal | undefined, act: string): void;
|
|
160
|
+
}
|
|
161
|
+
export default TimeEntryApprovalService;
|
|
162
|
+
//# sourceMappingURL=time-entry-approval-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-entry-approval-service.d.ts","sourceRoot":"","sources":["../../src/services/time-entry-approval-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACL,KAAK,gBAAgB,EACrB,0BAA0B,EAC3B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAEL,iCAAiC,EAClC,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EACL,KAAK,aAAa,EAClB,uBAAuB,EACvB,KAAK,mBAAmB,EACxB,6BAA6B,EAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,gFAAgF;AAChF,qBAAa,4BAA6B,SAAQ,KAAK;gBACzC,MAAM,EAAE,MAAM;CAI3B;AAED,2DAA2D;AAC3D,MAAM,WAAW,+BAAgC,SAAQ,iBAAiB;IACxE,2EAA2E;IAC3E,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,0DAA0D;AAC1D,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,EAAE,CAAC,EAAE,IAAI,CAAC;CACX;AAED,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,gBAAgB,CAAC;IACxB,MAAM,EAAE,aAAa,CAAC;IACtB,YAAY,EAAE,mBAAmB,CAAC;IAClC,IAAI,EAAE,qBAAqB,CAAC;CAC7B;AAED,yDAAyD;AACzD,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,0DAA0D;AAC1D,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;QACb,eAAe,EAAE,MAAM,CAAC;QACxB,SAAS,EAAE,IAAI,CAAC;QAChB,OAAO,EAAE,IAAI,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;KAC/B,CAAC,CAAC;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB;IACrC,sEAAsE;IACtE,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,yEAAyE;IACzE,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAED,yEAAyE;AACzE,UAAU,gBAAgB;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC;CAChB;AAOD;;GAEG;AACH,qBAAa,wBAAwB;IACnC,QAAQ,CAAC,OAAO,EAAE,0BAA0B,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC;IAC1C,QAAQ,CAAC,aAAa,EAAE,6BAA6B,CAAC;IACtD,QAAQ,CAAC,iBAAiB,EAAE,iCAAiC,CAAC;IAC9D,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAElD,SAAS,aAAa,WAAW,EAAE;QACjC,OAAO,EAAE,0BAA0B,CAAC;QACpC,OAAO,EAAE,uBAAuB,CAAC;QACjC,aAAa,EAAE,6BAA6B,CAAC;QAC7C,iBAAiB,EAAE,iCAAiC,CAAC;QACrD,WAAW,EAAE,kBAAkB,CAAC;KACjC;WAQY,MAAM,CACjB,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,wBAAwB,CAAC;IAmBpC,kDAAkD;IAC5C,QAAQ,CACZ,QAAQ,EAAE,gBAAgB,GAAG,MAAM,GAClC,OAAO,CAAC,gBAAgB,CAAC;IAW5B;;;;;OAKG;IACG,gBAAgB,CACpB,KAAK,EAAE,gBAAgB,EACvB,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,GAC/B,OAAO,CAAC,iBAAiB,CAAC;IAsD7B;;;;;OAKG;IACG,OAAO,CACX,QAAQ,EAAE,gBAAgB,GAAG,MAAM,EACnC,KAAK,GAAE,qBAA0B,GAChC,OAAO,CAAC,sBAAsB,CAAC;YAWpB,gBAAgB;IAuF9B;;;OAGG;IACG,MAAM,CACV,QAAQ,EAAE,gBAAgB,GAAG,MAAM,EACnC,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,gBAAgB,CAAC;IAqB5B;;;;;;;;OAQG;IACG,OAAO,CACX,QAAQ,EAAE,gBAAgB,GAAG,MAAM,EACnC,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,sBAAsB,CAAC;IA2ElC;;;;OAIG;IACH,SAAS,CAAC,aAAa,CACrB,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,kBAAkB,EAC1B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,gBAAgB,GAAG,SAAS,EACvC,WAAW,EAAE,WAAW,GAAG,IAAI,GAC9B,qBAAqB;IAiDxB;;;;OAIG;cACa,YAAY,CAC1B,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,gBAAgB,CAAC;IA0C5B;;;;OAIG;cACa,kBAAkB,CAChC,KAAK,EAAE,gBAAgB,EACvB,EAAE,EAAE,IAAI,GACP,OAAO,CAAC,mBAAmB,CAAC;IAqD/B;;;;OAIG;cACa,eAAe,CAC7B,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,aAAa,CAAC;IAYzB,2EAA2E;cAC3D,qBAAqB,CACnC,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,mBAAmB,CAAC;IAY/B,oEAAoE;IACpE,SAAS,CAAC,iBAAiB,CACzB,KAAK,EAAE,gBAAgB,EACvB,SAAS,EAAE,gBAAgB,GAAG,SAAS,GACtC,IAAI;IAWP,kEAAkE;IAClE,SAAS,CAAC,cAAc,CACtB,SAAS,EAAE,gBAAgB,GAAG,SAAS,EACvC,GAAG,EAAE,MAAM,GACV,IAAI;CAOR;AAED,eAAe,wBAAwB,CAAC"}
|