@open-mercato/core 0.4.2-canary-51881f6bf3 → 0.4.2-canary-5f415b8a44
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/dist/generated/entities/workflow_event_trigger/index.js +33 -0
- package/dist/generated/entities/workflow_event_trigger/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +59 -58
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/auth/events.js +30 -0
- package/dist/modules/auth/events.js.map +7 -0
- package/dist/modules/business_rules/api/execute/[ruleId]/route.js +145 -0
- package/dist/modules/business_rules/api/execute/[ruleId]/route.js.map +7 -0
- package/dist/modules/business_rules/data/validators.js +34 -0
- package/dist/modules/business_rules/data/validators.js.map +2 -2
- package/dist/modules/business_rules/index.js +21 -1
- package/dist/modules/business_rules/index.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +182 -1
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/catalog/events.js +34 -0
- package/dist/modules/catalog/events.js.map +7 -0
- package/dist/modules/customers/events.js +49 -0
- package/dist/modules/customers/events.js.map +7 -0
- package/dist/modules/directory/events.js +23 -0
- package/dist/modules/directory/events.js.map +7 -0
- package/dist/modules/sales/acl.js +1 -0
- package/dist/modules/sales/acl.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +12 -0
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +62 -0
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/events.js +63 -0
- package/dist/modules/sales/events.js.map +7 -0
- package/dist/modules/sales/lib/dictionaries.js +3 -0
- package/dist/modules/sales/lib/dictionaries.js.map +2 -2
- package/dist/modules/sales/lib/frontend/documentDataEvents.js +25 -0
- package/dist/modules/sales/lib/frontend/documentDataEvents.js.map +7 -0
- package/dist/modules/workflows/acl.js +2 -0
- package/dist/modules/workflows/acl.js.map +2 -2
- package/dist/modules/workflows/api/instances/route.js +18 -6
- package/dist/modules/workflows/api/instances/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/route.js +6 -1
- package/dist/modules/workflows/api/tasks/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.js +9 -1
- package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.meta.js +1 -1
- package/dist/modules/workflows/backend/definitions/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/create/page.js +24 -15
- package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/create/page.meta.js +1 -1
- package/dist/modules/workflows/backend/definitions/create/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +150 -132
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js +1 -1
- package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/events/[id]/page.js +1 -1
- package/dist/modules/workflows/backend/events/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/events/[id]/page.meta.js +2 -2
- package/dist/modules/workflows/backend/events/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/instances/[id]/page.meta.js +2 -2
- package/dist/modules/workflows/backend/instances/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.js +1 -1
- package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.meta.js +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +5 -6
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/cli.js +81 -3
- package/dist/modules/workflows/cli.js.map +3 -3
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +481 -0
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +7 -0
- package/dist/modules/workflows/components/EventTriggersEditor.js +553 -0
- package/dist/modules/workflows/components/EventTriggersEditor.js.map +7 -0
- package/dist/modules/workflows/data/entities.js +64 -1
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/data/validators.js +115 -0
- package/dist/modules/workflows/data/validators.js.map +2 -2
- package/dist/modules/workflows/events.js +38 -0
- package/dist/modules/workflows/events.js.map +7 -0
- package/dist/modules/workflows/examples/checkout-demo-definition.json +1 -5
- package/dist/modules/workflows/examples/order-approval-definition.json +257 -0
- package/dist/modules/workflows/examples/order-approval-guard-rules.json +32 -0
- package/dist/modules/workflows/lib/activity-executor.js +75 -13
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/event-trigger-service.js +308 -0
- package/dist/modules/workflows/lib/event-trigger-service.js.map +7 -0
- package/dist/modules/workflows/lib/graph-utils.js +71 -2
- package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
- package/dist/modules/workflows/lib/seeds.js +22 -5
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/lib/start-validator.js +33 -23
- package/dist/modules/workflows/lib/start-validator.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +157 -45
- package/dist/modules/workflows/lib/transition-handler.js.map +3 -3
- package/dist/modules/workflows/migrations/Migration20260123143500.js +36 -0
- package/dist/modules/workflows/migrations/Migration20260123143500.js.map +7 -0
- package/dist/modules/workflows/subscribers/event-trigger.js +78 -0
- package/dist/modules/workflows/subscribers/event-trigger.js.map +7 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +323 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +7 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.js +17 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.js.map +7 -0
- package/dist/modules/workflows/widgets/injection-table.js +19 -0
- package/dist/modules/workflows/widgets/injection-table.js.map +7 -0
- package/generated/entities/workflow_event_trigger/index.ts +15 -0
- package/generated/entities.ids.generated.ts +59 -58
- package/generated/entity-fields-registry.ts +2 -0
- package/package.json +3 -5
- package/src/modules/auth/events.ts +39 -0
- package/src/modules/business_rules/api/execute/[ruleId]/route.ts +163 -0
- package/src/modules/business_rules/data/validators.ts +40 -0
- package/src/modules/business_rules/index.ts +25 -0
- package/src/modules/business_rules/lib/rule-engine.ts +281 -1
- package/src/modules/catalog/events.ts +45 -0
- package/src/modules/customers/events.ts +63 -0
- package/src/modules/directory/events.ts +31 -0
- package/src/modules/sales/acl.ts +1 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +16 -0
- package/src/modules/sales/commands/documents.ts +74 -1
- package/src/modules/sales/events.ts +82 -0
- package/src/modules/sales/lib/dictionaries.ts +3 -0
- package/src/modules/sales/lib/frontend/documentDataEvents.ts +28 -0
- package/src/modules/workflows/acl.ts +2 -0
- package/src/modules/workflows/api/instances/route.ts +21 -7
- package/src/modules/workflows/api/tasks/route.ts +7 -1
- package/src/modules/workflows/backend/definitions/[id]/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +9 -0
- package/src/modules/workflows/backend/definitions/create/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/create/page.tsx +9 -0
- package/src/modules/workflows/backend/definitions/visual-editor/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +21 -3
- package/src/modules/workflows/backend/events/[id]/page.meta.ts +2 -2
- package/src/modules/workflows/backend/events/[id]/page.tsx +1 -1
- package/src/modules/workflows/backend/instances/[id]/page.meta.ts +2 -2
- package/src/modules/workflows/backend/tasks/[id]/page.meta.ts +2 -2
- package/src/modules/workflows/backend/tasks/[id]/page.tsx +1 -1
- package/src/modules/workflows/backend/tasks/page.tsx +5 -6
- package/src/modules/workflows/cli.ts +111 -0
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +581 -0
- package/src/modules/workflows/components/EventTriggersEditor.tsx +664 -0
- package/src/modules/workflows/data/entities.ts +124 -0
- package/src/modules/workflows/data/validators.ts +138 -0
- package/src/modules/workflows/events.ts +49 -0
- package/src/modules/workflows/examples/checkout-demo-definition.json +1 -5
- package/src/modules/workflows/examples/order-approval-definition.json +257 -0
- package/src/modules/workflows/examples/order-approval-guard-rules.json +32 -0
- package/src/modules/workflows/i18n/en.json +71 -0
- package/src/modules/workflows/lib/activity-executor.ts +129 -16
- package/src/modules/workflows/lib/event-trigger-service.ts +557 -0
- package/src/modules/workflows/lib/graph-utils.ts +117 -2
- package/src/modules/workflows/lib/seeds.ts +34 -8
- package/src/modules/workflows/lib/start-validator.ts +38 -28
- package/src/modules/workflows/lib/transition-handler.ts +208 -55
- package/src/modules/workflows/migrations/Migration20260123143500.ts +38 -0
- package/src/modules/workflows/subscribers/event-trigger.ts +109 -0
- package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +446 -0
- package/src/modules/workflows/widgets/injection/order-approval/widget.ts +16 -0
- package/src/modules/workflows/widgets/injection-table.ts +21 -0
|
@@ -4,7 +4,7 @@ import * as ruleEvaluator from './rule-evaluator'
|
|
|
4
4
|
import * as actionExecutor from './action-executor'
|
|
5
5
|
import type { RuleEvaluationContext } from './rule-evaluator'
|
|
6
6
|
import type { ActionContext, ActionExecutionOutcome } from './action-executor'
|
|
7
|
-
import { ruleEngineContextSchema, ruleDiscoveryOptionsSchema } from '../data/validators'
|
|
7
|
+
import { ruleEngineContextSchema, ruleDiscoveryOptionsSchema, directRuleExecutionContextSchema, ruleIdExecutionContextSchema } from '../data/validators'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Constants
|
|
@@ -85,6 +85,65 @@ export interface RuleDiscoveryOptions {
|
|
|
85
85
|
ruleType?: RuleType
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Direct rule execution context (for executing a specific rule by ID)
|
|
90
|
+
*/
|
|
91
|
+
export interface DirectRuleExecutionContext {
|
|
92
|
+
ruleId: string // Database UUID of the rule
|
|
93
|
+
data: any
|
|
94
|
+
user?: {
|
|
95
|
+
id?: string
|
|
96
|
+
email?: string
|
|
97
|
+
role?: string
|
|
98
|
+
[key: string]: any
|
|
99
|
+
}
|
|
100
|
+
tenantId: string
|
|
101
|
+
organizationId: string
|
|
102
|
+
executedBy?: string
|
|
103
|
+
dryRun?: boolean
|
|
104
|
+
// Optional for logging (falls back to rule's entityType)
|
|
105
|
+
entityType?: string
|
|
106
|
+
entityId?: string
|
|
107
|
+
eventType?: string
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Direct rule execution result
|
|
112
|
+
*/
|
|
113
|
+
export interface DirectRuleExecutionResult {
|
|
114
|
+
success: boolean
|
|
115
|
+
ruleId: string
|
|
116
|
+
ruleName: string
|
|
117
|
+
conditionResult: boolean
|
|
118
|
+
actionsExecuted: ActionExecutionOutcome | null
|
|
119
|
+
executionTime: number
|
|
120
|
+
error?: string
|
|
121
|
+
logId?: string
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Context for executing a rule by its string rule_id identifier
|
|
126
|
+
* Unlike DirectRuleExecutionContext which uses database UUID,
|
|
127
|
+
* this uses the string identifier (e.g., "workflow_checkout_inventory_available")
|
|
128
|
+
*/
|
|
129
|
+
export interface RuleIdExecutionContext {
|
|
130
|
+
ruleId: string // String identifier (e.g., "workflow_checkout_inventory_available")
|
|
131
|
+
data: any
|
|
132
|
+
user?: {
|
|
133
|
+
id?: string
|
|
134
|
+
email?: string
|
|
135
|
+
role?: string
|
|
136
|
+
[key: string]: any
|
|
137
|
+
}
|
|
138
|
+
tenantId: string
|
|
139
|
+
organizationId: string
|
|
140
|
+
executedBy?: string
|
|
141
|
+
dryRun?: boolean
|
|
142
|
+
entityType?: string
|
|
143
|
+
entityId?: string
|
|
144
|
+
eventType?: string
|
|
145
|
+
}
|
|
146
|
+
|
|
88
147
|
/**
|
|
89
148
|
* Execute a function with a timeout
|
|
90
149
|
*/
|
|
@@ -404,6 +463,227 @@ export async function findApplicableRules(
|
|
|
404
463
|
})
|
|
405
464
|
}
|
|
406
465
|
|
|
466
|
+
/**
|
|
467
|
+
* Execute a specific rule by its database UUID
|
|
468
|
+
* This bypasses the entityType/eventType discovery mechanism and directly executes the rule
|
|
469
|
+
*/
|
|
470
|
+
export async function executeRuleById(
|
|
471
|
+
em: EntityManager,
|
|
472
|
+
context: DirectRuleExecutionContext
|
|
473
|
+
): Promise<DirectRuleExecutionResult> {
|
|
474
|
+
const startTime = Date.now()
|
|
475
|
+
|
|
476
|
+
// Validate input
|
|
477
|
+
const validation = directRuleExecutionContextSchema.safeParse(context)
|
|
478
|
+
if (!validation.success) {
|
|
479
|
+
const validationErrors = validation.error.issues.map(e => `${e.path.join('.')}: ${e.message}`)
|
|
480
|
+
return {
|
|
481
|
+
success: false,
|
|
482
|
+
ruleId: context.ruleId,
|
|
483
|
+
ruleName: 'Unknown',
|
|
484
|
+
conditionResult: false,
|
|
485
|
+
actionsExecuted: null,
|
|
486
|
+
executionTime: Date.now() - startTime,
|
|
487
|
+
error: `Validation failed: ${validationErrors.join(', ')}`,
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Fetch rule by ID with tenant/org validation
|
|
492
|
+
const rule = await em.findOne(BusinessRule, {
|
|
493
|
+
id: context.ruleId,
|
|
494
|
+
tenantId: context.tenantId,
|
|
495
|
+
organizationId: context.organizationId,
|
|
496
|
+
deletedAt: null,
|
|
497
|
+
})
|
|
498
|
+
|
|
499
|
+
if (!rule) {
|
|
500
|
+
return {
|
|
501
|
+
success: false,
|
|
502
|
+
ruleId: context.ruleId,
|
|
503
|
+
ruleName: 'Unknown',
|
|
504
|
+
conditionResult: false,
|
|
505
|
+
actionsExecuted: null,
|
|
506
|
+
executionTime: Date.now() - startTime,
|
|
507
|
+
error: 'Rule not found',
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (!rule.enabled) {
|
|
512
|
+
return {
|
|
513
|
+
success: false,
|
|
514
|
+
ruleId: rule.ruleId,
|
|
515
|
+
ruleName: rule.ruleName,
|
|
516
|
+
conditionResult: false,
|
|
517
|
+
actionsExecuted: null,
|
|
518
|
+
executionTime: Date.now() - startTime,
|
|
519
|
+
error: 'Rule is disabled',
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Check effective date range
|
|
524
|
+
const now = new Date()
|
|
525
|
+
if (rule.effectiveFrom && rule.effectiveFrom > now) {
|
|
526
|
+
return {
|
|
527
|
+
success: false,
|
|
528
|
+
ruleId: rule.ruleId,
|
|
529
|
+
ruleName: rule.ruleName,
|
|
530
|
+
conditionResult: false,
|
|
531
|
+
actionsExecuted: null,
|
|
532
|
+
executionTime: Date.now() - startTime,
|
|
533
|
+
error: `Rule is not yet effective (starts ${rule.effectiveFrom.toISOString()})`,
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
if (rule.effectiveTo && rule.effectiveTo < now) {
|
|
537
|
+
return {
|
|
538
|
+
success: false,
|
|
539
|
+
ruleId: rule.ruleId,
|
|
540
|
+
ruleName: rule.ruleName,
|
|
541
|
+
conditionResult: false,
|
|
542
|
+
actionsExecuted: null,
|
|
543
|
+
executionTime: Date.now() - startTime,
|
|
544
|
+
error: `Rule has expired (ended ${rule.effectiveTo.toISOString()})`,
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Build RuleEngineContext (use provided entityType or fall back to rule's)
|
|
549
|
+
const engineContext: RuleEngineContext = {
|
|
550
|
+
entityType: context.entityType || rule.entityType,
|
|
551
|
+
entityId: context.entityId,
|
|
552
|
+
eventType: context.eventType || rule.eventType || undefined,
|
|
553
|
+
data: context.data,
|
|
554
|
+
user: context.user,
|
|
555
|
+
tenantId: context.tenantId,
|
|
556
|
+
organizationId: context.organizationId,
|
|
557
|
+
executedBy: context.executedBy,
|
|
558
|
+
dryRun: context.dryRun,
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// Execute via existing executeSingleRule
|
|
562
|
+
const result = await executeSingleRule(em, rule, engineContext)
|
|
563
|
+
|
|
564
|
+
return {
|
|
565
|
+
success: !result.error,
|
|
566
|
+
ruleId: rule.ruleId,
|
|
567
|
+
ruleName: rule.ruleName,
|
|
568
|
+
conditionResult: result.conditionResult,
|
|
569
|
+
actionsExecuted: result.actionsExecuted,
|
|
570
|
+
executionTime: result.executionTime,
|
|
571
|
+
error: result.error,
|
|
572
|
+
logId: result.logId,
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Execute a rule by its string rule_id identifier
|
|
578
|
+
* Looks up rule by rule_id (string column) + tenant_id (unique constraint)
|
|
579
|
+
* This is useful for workflow conditions that reference rules by their string identifiers
|
|
580
|
+
*/
|
|
581
|
+
export async function executeRuleByRuleId(
|
|
582
|
+
em: EntityManager,
|
|
583
|
+
context: RuleIdExecutionContext
|
|
584
|
+
): Promise<DirectRuleExecutionResult> {
|
|
585
|
+
const startTime = Date.now()
|
|
586
|
+
|
|
587
|
+
// Validate input
|
|
588
|
+
const validation = ruleIdExecutionContextSchema.safeParse(context)
|
|
589
|
+
if (!validation.success) {
|
|
590
|
+
const validationErrors = validation.error.issues.map(e => `${e.path.join('.')}: ${e.message}`)
|
|
591
|
+
return {
|
|
592
|
+
success: false,
|
|
593
|
+
ruleId: context.ruleId || 'unknown',
|
|
594
|
+
ruleName: 'Unknown',
|
|
595
|
+
conditionResult: false,
|
|
596
|
+
actionsExecuted: null,
|
|
597
|
+
executionTime: Date.now() - startTime,
|
|
598
|
+
error: `Validation failed: ${validationErrors.join(', ')}`,
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Fetch rule by rule_id (string identifier) + tenant/org
|
|
603
|
+
const rule = await em.findOne(BusinessRule, {
|
|
604
|
+
ruleId: context.ruleId, // String identifier column
|
|
605
|
+
tenantId: context.tenantId,
|
|
606
|
+
organizationId: context.organizationId,
|
|
607
|
+
deletedAt: null,
|
|
608
|
+
})
|
|
609
|
+
|
|
610
|
+
if (!rule) {
|
|
611
|
+
return {
|
|
612
|
+
success: false,
|
|
613
|
+
ruleId: context.ruleId,
|
|
614
|
+
ruleName: 'Unknown',
|
|
615
|
+
conditionResult: false,
|
|
616
|
+
actionsExecuted: null,
|
|
617
|
+
executionTime: Date.now() - startTime,
|
|
618
|
+
error: 'Rule not found',
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (!rule.enabled) {
|
|
623
|
+
return {
|
|
624
|
+
success: false,
|
|
625
|
+
ruleId: rule.ruleId,
|
|
626
|
+
ruleName: rule.ruleName,
|
|
627
|
+
conditionResult: false,
|
|
628
|
+
actionsExecuted: null,
|
|
629
|
+
executionTime: Date.now() - startTime,
|
|
630
|
+
error: 'Rule is disabled',
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Check effective date range
|
|
635
|
+
const now = new Date()
|
|
636
|
+
if (rule.effectiveFrom && rule.effectiveFrom > now) {
|
|
637
|
+
return {
|
|
638
|
+
success: false,
|
|
639
|
+
ruleId: rule.ruleId,
|
|
640
|
+
ruleName: rule.ruleName,
|
|
641
|
+
conditionResult: false,
|
|
642
|
+
actionsExecuted: null,
|
|
643
|
+
executionTime: Date.now() - startTime,
|
|
644
|
+
error: `Rule is not yet effective (starts ${rule.effectiveFrom.toISOString()})`,
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
if (rule.effectiveTo && rule.effectiveTo < now) {
|
|
648
|
+
return {
|
|
649
|
+
success: false,
|
|
650
|
+
ruleId: rule.ruleId,
|
|
651
|
+
ruleName: rule.ruleName,
|
|
652
|
+
conditionResult: false,
|
|
653
|
+
actionsExecuted: null,
|
|
654
|
+
executionTime: Date.now() - startTime,
|
|
655
|
+
error: `Rule has expired (ended ${rule.effectiveTo.toISOString()})`,
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Build RuleEngineContext (use provided entityType or fall back to rule's)
|
|
660
|
+
const engineContext: RuleEngineContext = {
|
|
661
|
+
entityType: context.entityType || rule.entityType,
|
|
662
|
+
entityId: context.entityId,
|
|
663
|
+
eventType: context.eventType || rule.eventType || undefined,
|
|
664
|
+
data: context.data,
|
|
665
|
+
user: context.user,
|
|
666
|
+
tenantId: context.tenantId,
|
|
667
|
+
organizationId: context.organizationId,
|
|
668
|
+
executedBy: context.executedBy,
|
|
669
|
+
dryRun: context.dryRun,
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Execute via existing executeSingleRule
|
|
673
|
+
const result = await executeSingleRule(em, rule, engineContext)
|
|
674
|
+
|
|
675
|
+
return {
|
|
676
|
+
success: !result.error,
|
|
677
|
+
ruleId: rule.ruleId,
|
|
678
|
+
ruleName: rule.ruleName,
|
|
679
|
+
conditionResult: result.conditionResult,
|
|
680
|
+
actionsExecuted: result.actionsExecuted,
|
|
681
|
+
executionTime: result.executionTime,
|
|
682
|
+
error: result.error,
|
|
683
|
+
logId: result.logId,
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
407
687
|
/**
|
|
408
688
|
* Sensitive field patterns to exclude from logs
|
|
409
689
|
*/
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createModuleEvents } from '@open-mercato/shared/modules/events'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Catalog Module Events
|
|
5
|
+
*
|
|
6
|
+
* Declares all events that can be emitted by the catalog module.
|
|
7
|
+
*/
|
|
8
|
+
const events = [
|
|
9
|
+
// Products
|
|
10
|
+
{ id: 'catalog.product.created', label: 'Product Created', entity: 'product', category: 'crud' },
|
|
11
|
+
{ id: 'catalog.product.updated', label: 'Product Updated', entity: 'product', category: 'crud' },
|
|
12
|
+
{ id: 'catalog.product.deleted', label: 'Product Deleted', entity: 'product', category: 'crud' },
|
|
13
|
+
|
|
14
|
+
// Categories
|
|
15
|
+
{ id: 'catalog.category.created', label: 'Category Created', entity: 'category', category: 'crud' },
|
|
16
|
+
{ id: 'catalog.category.updated', label: 'Category Updated', entity: 'category', category: 'crud' },
|
|
17
|
+
{ id: 'catalog.category.deleted', label: 'Category Deleted', entity: 'category', category: 'crud' },
|
|
18
|
+
|
|
19
|
+
// Variants
|
|
20
|
+
{ id: 'catalog.variant.created', label: 'Variant Created', entity: 'variant', category: 'crud' },
|
|
21
|
+
{ id: 'catalog.variant.updated', label: 'Variant Updated', entity: 'variant', category: 'crud' },
|
|
22
|
+
{ id: 'catalog.variant.deleted', label: 'Variant Deleted', entity: 'variant', category: 'crud' },
|
|
23
|
+
|
|
24
|
+
// Prices
|
|
25
|
+
{ id: 'catalog.price.created', label: 'Price Created', entity: 'price', category: 'crud' },
|
|
26
|
+
{ id: 'catalog.price.updated', label: 'Price Updated', entity: 'price', category: 'crud' },
|
|
27
|
+
{ id: 'catalog.price.deleted', label: 'Price Deleted', entity: 'price', category: 'crud' },
|
|
28
|
+
|
|
29
|
+
// Lifecycle events - Pricing resolution
|
|
30
|
+
{ id: 'catalog.pricing.resolve.before', label: 'Before Pricing Resolve', category: 'lifecycle', excludeFromTriggers: true },
|
|
31
|
+
{ id: 'catalog.pricing.resolve.after', label: 'After Pricing Resolve', category: 'lifecycle', excludeFromTriggers: true },
|
|
32
|
+
] as const
|
|
33
|
+
|
|
34
|
+
export const eventsConfig = createModuleEvents({
|
|
35
|
+
moduleId: 'catalog',
|
|
36
|
+
events,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
/** Type-safe event emitter for catalog module */
|
|
40
|
+
export const emitCatalogEvent = eventsConfig.emit
|
|
41
|
+
|
|
42
|
+
/** Event IDs that can be emitted by the catalog module */
|
|
43
|
+
export type CatalogEventId = typeof events[number]['id']
|
|
44
|
+
|
|
45
|
+
export default eventsConfig
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createModuleEvents } from '@open-mercato/shared/modules/events'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Customers Module Events
|
|
5
|
+
*
|
|
6
|
+
* Declares all events that can be emitted by the customers module.
|
|
7
|
+
*/
|
|
8
|
+
const events = [
|
|
9
|
+
// People
|
|
10
|
+
{ id: 'customers.people.created', label: 'Customer (Person) Created', entity: 'people', category: 'crud' },
|
|
11
|
+
{ id: 'customers.people.updated', label: 'Customer (Person) Updated', entity: 'people', category: 'crud' },
|
|
12
|
+
{ id: 'customers.people.deleted', label: 'Customer (Person) Deleted', entity: 'people', category: 'crud' },
|
|
13
|
+
|
|
14
|
+
// Companies
|
|
15
|
+
{ id: 'customers.companies.created', label: 'Customer (Company) Created', entity: 'companies', category: 'crud' },
|
|
16
|
+
{ id: 'customers.companies.updated', label: 'Customer (Company) Updated', entity: 'companies', category: 'crud' },
|
|
17
|
+
{ id: 'customers.companies.deleted', label: 'Customer (Company) Deleted', entity: 'companies', category: 'crud' },
|
|
18
|
+
|
|
19
|
+
// Deals
|
|
20
|
+
{ id: 'customers.deals.created', label: 'Deal Created', entity: 'deals', category: 'crud' },
|
|
21
|
+
{ id: 'customers.deals.updated', label: 'Deal Updated', entity: 'deals', category: 'crud' },
|
|
22
|
+
{ id: 'customers.deals.deleted', label: 'Deal Deleted', entity: 'deals', category: 'crud' },
|
|
23
|
+
|
|
24
|
+
// Comments
|
|
25
|
+
{ id: 'customers.comments.created', label: 'Comment Created', entity: 'comments', category: 'crud' },
|
|
26
|
+
{ id: 'customers.comments.updated', label: 'Comment Updated', entity: 'comments', category: 'crud' },
|
|
27
|
+
{ id: 'customers.comments.deleted', label: 'Comment Deleted', entity: 'comments', category: 'crud' },
|
|
28
|
+
|
|
29
|
+
// Addresses
|
|
30
|
+
{ id: 'customers.addresses.created', label: 'Address Created', entity: 'addresses', category: 'crud' },
|
|
31
|
+
{ id: 'customers.addresses.updated', label: 'Address Updated', entity: 'addresses', category: 'crud' },
|
|
32
|
+
{ id: 'customers.addresses.deleted', label: 'Address Deleted', entity: 'addresses', category: 'crud' },
|
|
33
|
+
|
|
34
|
+
// Activities
|
|
35
|
+
{ id: 'customers.activities.created', label: 'Activity Created', entity: 'activities', category: 'crud' },
|
|
36
|
+
{ id: 'customers.activities.updated', label: 'Activity Updated', entity: 'activities', category: 'crud' },
|
|
37
|
+
{ id: 'customers.activities.deleted', label: 'Activity Deleted', entity: 'activities', category: 'crud' },
|
|
38
|
+
|
|
39
|
+
// Tags
|
|
40
|
+
{ id: 'customers.tags.created', label: 'Tag Created', entity: 'tags', category: 'crud' },
|
|
41
|
+
{ id: 'customers.tags.updated', label: 'Tag Updated', entity: 'tags', category: 'crud' },
|
|
42
|
+
{ id: 'customers.tags.deleted', label: 'Tag Deleted', entity: 'tags', category: 'crud' },
|
|
43
|
+
{ id: 'customers.tags.assigned', label: 'Tag Assigned', entity: 'tags', category: 'crud' },
|
|
44
|
+
{ id: 'customers.tags.removed', label: 'Tag Removed', entity: 'tags', category: 'crud' },
|
|
45
|
+
|
|
46
|
+
// Todos
|
|
47
|
+
{ id: 'customers.todos.created', label: 'Todo Created', entity: 'todos', category: 'crud' },
|
|
48
|
+
{ id: 'customers.todos.updated', label: 'Todo Updated', entity: 'todos', category: 'crud' },
|
|
49
|
+
{ id: 'customers.todos.deleted', label: 'Todo Deleted', entity: 'todos', category: 'crud' },
|
|
50
|
+
] as const
|
|
51
|
+
|
|
52
|
+
export const eventsConfig = createModuleEvents({
|
|
53
|
+
moduleId: 'customers',
|
|
54
|
+
events,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
/** Type-safe event emitter for customers module */
|
|
58
|
+
export const emitCustomersEvent = eventsConfig.emit
|
|
59
|
+
|
|
60
|
+
/** Event IDs that can be emitted by the customers module */
|
|
61
|
+
export type CustomersEventId = typeof events[number]['id']
|
|
62
|
+
|
|
63
|
+
export default eventsConfig
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createModuleEvents } from '@open-mercato/shared/modules/events'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Directory Module Events
|
|
5
|
+
*
|
|
6
|
+
* Declares all events that can be emitted by the directory module.
|
|
7
|
+
*/
|
|
8
|
+
const events = [
|
|
9
|
+
// Tenants
|
|
10
|
+
{ id: 'directory.tenants.created', label: 'Tenant Created', entity: 'tenants', category: 'crud' },
|
|
11
|
+
{ id: 'directory.tenants.updated', label: 'Tenant Updated', entity: 'tenants', category: 'crud' },
|
|
12
|
+
{ id: 'directory.tenants.deleted', label: 'Tenant Deleted', entity: 'tenants', category: 'crud' },
|
|
13
|
+
|
|
14
|
+
// Organizations
|
|
15
|
+
{ id: 'directory.organizations.created', label: 'Organization Created', entity: 'organizations', category: 'crud' },
|
|
16
|
+
{ id: 'directory.organizations.updated', label: 'Organization Updated', entity: 'organizations', category: 'crud' },
|
|
17
|
+
{ id: 'directory.organizations.deleted', label: 'Organization Deleted', entity: 'organizations', category: 'crud' },
|
|
18
|
+
] as const
|
|
19
|
+
|
|
20
|
+
export const eventsConfig = createModuleEvents({
|
|
21
|
+
moduleId: 'directory',
|
|
22
|
+
events,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
/** Type-safe event emitter for directory module */
|
|
26
|
+
export const emitDirectoryEvent = eventsConfig.emit
|
|
27
|
+
|
|
28
|
+
/** Event IDs that can be emitted by the directory module */
|
|
29
|
+
export type DirectoryEventId = typeof events[number]['id']
|
|
30
|
+
|
|
31
|
+
export default eventsConfig
|
package/src/modules/sales/acl.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export const features = [
|
|
2
2
|
{ id: 'sales.orders.view', title: 'View sales orders', module: 'sales' },
|
|
3
3
|
{ id: 'sales.orders.manage', title: 'Manage sales orders', module: 'sales' },
|
|
4
|
+
{ id: 'sales.orders.approve', title: 'Approve sales orders', module: 'sales' },
|
|
4
5
|
{ id: 'sales.quotes.view', title: 'View sales quotes', module: 'sales' },
|
|
5
6
|
{ id: 'sales.quotes.manage', title: 'Manage sales quotes', module: 'sales' },
|
|
6
7
|
{ id: 'sales.shipments.manage', title: 'Manage order shipments', module: 'sales' },
|
|
@@ -50,6 +50,9 @@ import {
|
|
|
50
50
|
emitSalesDocumentTotalsRefresh,
|
|
51
51
|
subscribeSalesDocumentTotalsRefresh,
|
|
52
52
|
} from '@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents'
|
|
53
|
+
import {
|
|
54
|
+
subscribeSalesDocumentDataRefresh,
|
|
55
|
+
} from '@open-mercato/core/modules/sales/lib/frontend/documentDataEvents'
|
|
53
56
|
import type { CommentSummary, SectionAction } from '@open-mercato/ui/backend/detail'
|
|
54
57
|
import { ICON_SUGGESTIONS } from '@open-mercato/core/modules/customers/lib/dictionaries'
|
|
55
58
|
import { readMarkdownPreferenceCookie, writeMarkdownPreferenceCookie } from '@open-mercato/core/modules/customers/lib/markdownPreference'
|
|
@@ -2601,6 +2604,19 @@ export default function SalesDocumentDetailPage({
|
|
|
2601
2604
|
[kind, record?.id, refreshDocumentTotals],
|
|
2602
2605
|
)
|
|
2603
2606
|
|
|
2607
|
+
// Subscribe to document data refresh events (e.g., from workflow status updates)
|
|
2608
|
+
React.useEffect(
|
|
2609
|
+
() =>
|
|
2610
|
+
subscribeSalesDocumentDataRefresh((detail) => {
|
|
2611
|
+
if (!record?.id) return
|
|
2612
|
+
if (detail.documentId !== record.id) return
|
|
2613
|
+
if (detail.kind && detail.kind !== kind) return
|
|
2614
|
+
// Increment reloadKey to trigger a full document reload
|
|
2615
|
+
setReloadKey((prev) => prev + 1)
|
|
2616
|
+
}),
|
|
2617
|
+
[kind, record?.id],
|
|
2618
|
+
)
|
|
2619
|
+
|
|
2604
2620
|
const statusDictionaryMap = React.useMemo(
|
|
2605
2621
|
() =>
|
|
2606
2622
|
createDictionaryMap(
|
|
@@ -4,7 +4,7 @@ import { randomUUID } from 'crypto'
|
|
|
4
4
|
import { z } from 'zod'
|
|
5
5
|
import { registerCommand } from '@open-mercato/shared/lib/commands'
|
|
6
6
|
import type { CommandHandler } from '@open-mercato/shared/lib/commands'
|
|
7
|
-
import { emitCrudSideEffects, requireId } from '@open-mercato/shared/lib/commands/helpers'
|
|
7
|
+
import { emitCrudSideEffects, requireId, type CrudEventsConfig } from '@open-mercato/shared/lib/commands/helpers'
|
|
8
8
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
9
9
|
import type { EventBus } from '@open-mercato/events'
|
|
10
10
|
import type { DataEngine } from '@open-mercato/shared/lib/data/engine'
|
|
@@ -89,6 +89,29 @@ import { resolveStatusEntryIdByValue } from '../lib/statusHelpers'
|
|
|
89
89
|
import { SalesDocumentNumberGenerator } from '../services/salesDocumentNumberGenerator'
|
|
90
90
|
import { loadSalesSettings } from './settings'
|
|
91
91
|
|
|
92
|
+
// CRUD events configuration for workflow triggers
|
|
93
|
+
const orderCrudEvents: CrudEventsConfig<SalesOrder> = {
|
|
94
|
+
module: 'sales',
|
|
95
|
+
entity: 'orders',
|
|
96
|
+
persistent: true,
|
|
97
|
+
buildPayload: (ctx) => ({
|
|
98
|
+
id: ctx.identifiers.id,
|
|
99
|
+
organizationId: ctx.identifiers.organizationId,
|
|
100
|
+
tenantId: ctx.identifiers.tenantId,
|
|
101
|
+
}),
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const quoteCrudEvents: CrudEventsConfig<SalesQuote> = {
|
|
105
|
+
module: 'sales',
|
|
106
|
+
entity: 'quotes',
|
|
107
|
+
persistent: true,
|
|
108
|
+
buildPayload: (ctx) => ({
|
|
109
|
+
id: ctx.identifiers.id,
|
|
110
|
+
organizationId: ctx.identifiers.organizationId,
|
|
111
|
+
tenantId: ctx.identifiers.tenantId,
|
|
112
|
+
}),
|
|
113
|
+
}
|
|
114
|
+
|
|
92
115
|
type DocumentAddressSnapshot = {
|
|
93
116
|
id: string
|
|
94
117
|
organizationId: string
|
|
@@ -3111,6 +3134,31 @@ const createQuoteCommand: CommandHandler<QuoteCreateInput, { quoteId: string }>
|
|
|
3111
3134
|
})
|
|
3112
3135
|
await em.flush()
|
|
3113
3136
|
|
|
3137
|
+
// Emit CRUD side effects to trigger workflow event listeners
|
|
3138
|
+
const dataEngine = ctx.container.resolve('dataEngine') as DataEngine
|
|
3139
|
+
await emitCrudSideEffects({
|
|
3140
|
+
dataEngine,
|
|
3141
|
+
action: 'created',
|
|
3142
|
+
entity: quote,
|
|
3143
|
+
identifiers: {
|
|
3144
|
+
id: quote.id,
|
|
3145
|
+
organizationId: quote.organizationId,
|
|
3146
|
+
tenantId: quote.tenantId,
|
|
3147
|
+
},
|
|
3148
|
+
events: quoteCrudEvents,
|
|
3149
|
+
indexer: { entityType: E.sales.sales_quote },
|
|
3150
|
+
})
|
|
3151
|
+
|
|
3152
|
+
// Invalidate cache
|
|
3153
|
+
const resourceKind = deriveResourceFromCommandId(createQuoteCommand.id) ?? 'sales.quote'
|
|
3154
|
+
await invalidateCrudCache(
|
|
3155
|
+
ctx.container,
|
|
3156
|
+
resourceKind,
|
|
3157
|
+
{ id: quote.id, organizationId: quote.organizationId, tenantId: quote.tenantId },
|
|
3158
|
+
ctx.auth?.tenantId ?? null,
|
|
3159
|
+
'created'
|
|
3160
|
+
)
|
|
3161
|
+
|
|
3114
3162
|
return { quoteId: quote.id }
|
|
3115
3163
|
},
|
|
3116
3164
|
captureAfter: async (_input, result, ctx) => {
|
|
@@ -3782,6 +3830,31 @@ const createOrderCommand: CommandHandler<OrderCreateInput, { orderId: string }>
|
|
|
3782
3830
|
})
|
|
3783
3831
|
await em.flush()
|
|
3784
3832
|
|
|
3833
|
+
// Emit CRUD side effects to trigger workflow event listeners
|
|
3834
|
+
const dataEngine = ctx.container.resolve('dataEngine') as DataEngine
|
|
3835
|
+
await emitCrudSideEffects({
|
|
3836
|
+
dataEngine,
|
|
3837
|
+
action: 'created',
|
|
3838
|
+
entity: order,
|
|
3839
|
+
identifiers: {
|
|
3840
|
+
id: order.id,
|
|
3841
|
+
organizationId: order.organizationId,
|
|
3842
|
+
tenantId: order.tenantId,
|
|
3843
|
+
},
|
|
3844
|
+
events: orderCrudEvents,
|
|
3845
|
+
indexer: { entityType: E.sales.sales_order },
|
|
3846
|
+
})
|
|
3847
|
+
|
|
3848
|
+
// Invalidate cache
|
|
3849
|
+
const resourceKind = deriveResourceFromCommandId(createOrderCommand.id) ?? 'sales.order'
|
|
3850
|
+
await invalidateCrudCache(
|
|
3851
|
+
ctx.container,
|
|
3852
|
+
resourceKind,
|
|
3853
|
+
{ id: order.id, organizationId: order.organizationId, tenantId: order.tenantId },
|
|
3854
|
+
ctx.auth?.tenantId ?? null,
|
|
3855
|
+
'created'
|
|
3856
|
+
)
|
|
3857
|
+
|
|
3785
3858
|
return { orderId: order.id }
|
|
3786
3859
|
},
|
|
3787
3860
|
captureAfter: async (_input, result, ctx) => {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { createModuleEvents } from '@open-mercato/shared/modules/events'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sales Module Events
|
|
5
|
+
*
|
|
6
|
+
* Declares all events that can be emitted by the sales module.
|
|
7
|
+
*/
|
|
8
|
+
const events = [
|
|
9
|
+
// Orders
|
|
10
|
+
{ id: 'sales.orders.created', label: 'Sales Order Created', entity: 'orders', category: 'crud' },
|
|
11
|
+
{ id: 'sales.orders.updated', label: 'Sales Order Updated', entity: 'orders', category: 'crud' },
|
|
12
|
+
{ id: 'sales.orders.deleted', label: 'Sales Order Deleted', entity: 'orders', category: 'crud' },
|
|
13
|
+
|
|
14
|
+
// Quotes
|
|
15
|
+
{ id: 'sales.quotes.created', label: 'Quote Created', entity: 'quotes', category: 'crud' },
|
|
16
|
+
{ id: 'sales.quotes.updated', label: 'Quote Updated', entity: 'quotes', category: 'crud' },
|
|
17
|
+
{ id: 'sales.quotes.deleted', label: 'Quote Deleted', entity: 'quotes', category: 'crud' },
|
|
18
|
+
|
|
19
|
+
// Invoices
|
|
20
|
+
{ id: 'sales.invoices.created', label: 'Invoice Created', entity: 'invoices', category: 'crud' },
|
|
21
|
+
{ id: 'sales.invoices.updated', label: 'Invoice Updated', entity: 'invoices', category: 'crud' },
|
|
22
|
+
{ id: 'sales.invoices.deleted', label: 'Invoice Deleted', entity: 'invoices', category: 'crud' },
|
|
23
|
+
|
|
24
|
+
// Order Lines
|
|
25
|
+
{ id: 'sales.lines.created', label: 'Order Line Created', entity: 'lines', category: 'crud' },
|
|
26
|
+
{ id: 'sales.lines.updated', label: 'Order Line Updated', entity: 'lines', category: 'crud' },
|
|
27
|
+
{ id: 'sales.lines.deleted', label: 'Order Line Deleted', entity: 'lines', category: 'crud' },
|
|
28
|
+
|
|
29
|
+
// Payments
|
|
30
|
+
{ id: 'sales.payments.created', label: 'Payment Created', entity: 'payments', category: 'crud' },
|
|
31
|
+
{ id: 'sales.payments.updated', label: 'Payment Updated', entity: 'payments', category: 'crud' },
|
|
32
|
+
{ id: 'sales.payments.deleted', label: 'Payment Deleted', entity: 'payments', category: 'crud' },
|
|
33
|
+
|
|
34
|
+
// Shipments
|
|
35
|
+
{ id: 'sales.shipments.created', label: 'Shipment Created', entity: 'shipments', category: 'crud' },
|
|
36
|
+
{ id: 'sales.shipments.updated', label: 'Shipment Updated', entity: 'shipments', category: 'crud' },
|
|
37
|
+
{ id: 'sales.shipments.deleted', label: 'Shipment Deleted', entity: 'shipments', category: 'crud' },
|
|
38
|
+
|
|
39
|
+
// Notes
|
|
40
|
+
{ id: 'sales.notes.created', label: 'Note Created', entity: 'notes', category: 'crud' },
|
|
41
|
+
{ id: 'sales.notes.updated', label: 'Note Updated', entity: 'notes', category: 'crud' },
|
|
42
|
+
{ id: 'sales.notes.deleted', label: 'Note Deleted', entity: 'notes', category: 'crud' },
|
|
43
|
+
|
|
44
|
+
// Configuration
|
|
45
|
+
{ id: 'sales.configuration.created', label: 'Configuration Created', entity: 'configuration', category: 'crud' },
|
|
46
|
+
{ id: 'sales.configuration.updated', label: 'Configuration Updated', entity: 'configuration', category: 'crud' },
|
|
47
|
+
{ id: 'sales.configuration.deleted', label: 'Configuration Deleted', entity: 'configuration', category: 'crud' },
|
|
48
|
+
|
|
49
|
+
// Lifecycle events - Document calculations
|
|
50
|
+
{ id: 'sales.document.totals.calculated', label: 'Document Totals Calculated', category: 'lifecycle' },
|
|
51
|
+
{ id: 'sales.document.calculate.before', label: 'Before Document Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
52
|
+
{ id: 'sales.document.calculate.after', label: 'After Document Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
53
|
+
|
|
54
|
+
// Lifecycle events - Line calculations
|
|
55
|
+
{ id: 'sales.line.calculate.before', label: 'Before Line Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
56
|
+
{ id: 'sales.line.calculate.after', label: 'After Line Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
57
|
+
|
|
58
|
+
// Lifecycle events - Tax calculations
|
|
59
|
+
{ id: 'sales.tax.calculate.before', label: 'Before Tax Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
60
|
+
{ id: 'sales.tax.calculate.after', label: 'After Tax Calculate', category: 'lifecycle', excludeFromTriggers: true },
|
|
61
|
+
|
|
62
|
+
// Lifecycle events - Shipping adjustments
|
|
63
|
+
{ id: 'sales.shipping.adjustments.apply.before', label: 'Before Shipping Adjustments', category: 'lifecycle', excludeFromTriggers: true },
|
|
64
|
+
{ id: 'sales.shipping.adjustments.apply.after', label: 'After Shipping Adjustments', category: 'lifecycle', excludeFromTriggers: true },
|
|
65
|
+
|
|
66
|
+
// Lifecycle events - Payment adjustments
|
|
67
|
+
{ id: 'sales.payment.adjustments.apply.before', label: 'Before Payment Adjustments', category: 'lifecycle', excludeFromTriggers: true },
|
|
68
|
+
{ id: 'sales.payment.adjustments.apply.after', label: 'After Payment Adjustments', category: 'lifecycle', excludeFromTriggers: true },
|
|
69
|
+
] as const
|
|
70
|
+
|
|
71
|
+
export const eventsConfig = createModuleEvents({
|
|
72
|
+
moduleId: 'sales',
|
|
73
|
+
events,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
/** Type-safe event emitter for sales module */
|
|
77
|
+
export const emitSalesEvent = eventsConfig.emit
|
|
78
|
+
|
|
79
|
+
/** Event IDs that can be emitted by the sales module */
|
|
80
|
+
export type SalesEventId = typeof events[number]['id']
|
|
81
|
+
|
|
82
|
+
export default eventsConfig
|
|
@@ -125,6 +125,9 @@ type SeedScope = { tenantId: string; organizationId: string }
|
|
|
125
125
|
|
|
126
126
|
const ORDER_STATUS_DEFAULTS: SalesDictionarySeed[] = [
|
|
127
127
|
{ value: 'draft', label: 'Draft', color: '#94a3b8', icon: 'lucide:file-pen-line' },
|
|
128
|
+
{ value: 'pending_approval', label: 'Pending Approval', color: '#f59e0b', icon: 'lucide:hourglass' },
|
|
129
|
+
{ value: 'approved', label: 'Approved', color: '#16a34a', icon: 'lucide:check-circle' },
|
|
130
|
+
{ value: 'rejected', label: 'Rejected', color: '#ef4444', icon: 'lucide:x-circle' },
|
|
128
131
|
{ value: 'sent', label: 'Sent', color: '#0ea5e9', icon: 'lucide:send' },
|
|
129
132
|
{ value: 'confirmed', label: 'Confirmed', color: '#2563eb', icon: 'lucide:badge-check' },
|
|
130
133
|
{ value: 'in_fulfillment', label: 'In fulfillment', color: '#f59e0b', icon: 'lucide:loader-2' },
|