11// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22
33import { ObjectSchema , Field } from '@objectstack/spec/data' ;
4+ import { OpportunityStateMachine } from './opportunity.state' ;
45
56export const Opportunity = ObjectSchema . create ( {
67 name : 'opportunity' ,
@@ -83,18 +84,37 @@ export const Opportunity = ObjectSchema.create({
8384 } ) ,
8485
8586 // Additional Classification
86- type : Field . select ( [ 'New Business' , 'Existing Customer - Upgrade' , 'Existing Customer - Renewal' , 'Existing Customer - Expansion' ] , {
87+ type : Field . select ( {
8788 label : 'Opportunity Type' ,
89+ options : [
90+ { label : 'New Business' , value : 'new_business' } ,
91+ { label : 'Existing Customer - Upgrade' , value : 'existing_upgrade' } ,
92+ { label : 'Existing Customer - Renewal' , value : 'existing_renewal' } ,
93+ { label : 'Existing Customer - Expansion' , value : 'existing_expansion' } ,
94+ ]
8895 } ) ,
8996
90- lead_source : Field . select ( [ 'Web' , 'Referral' , 'Event' , 'Partner' , 'Advertisement' , 'Cold Call' ] , {
97+ lead_source : Field . select ( {
9198 label : 'Lead Source' ,
99+ options : [
100+ { label : 'Web' , value : 'web' } ,
101+ { label : 'Referral' , value : 'referral' } ,
102+ { label : 'Event' , value : 'event' } ,
103+ { label : 'Partner' , value : 'partner' } ,
104+ { label : 'Advertisement' , value : 'advertisement' } ,
105+ { label : 'Cold Call' , value : 'cold_call' } ,
106+ ]
92107 } ) ,
93108
94109 // Competitor Analysis
95- competitors : Field . select ( [ 'Competitor A' , 'Competitor B' , 'Competitor C' ] , {
110+ competitors : Field . select ( {
96111 label : 'Competitors' ,
97112 multiple : true ,
113+ options : [
114+ { label : 'Competitor A' , value : 'competitor_a' } ,
115+ { label : 'Competitor B' , value : 'competitor_b' } ,
116+ { label : 'Competitor C' , value : 'competitor_c' } ,
117+ ]
98118 } ) ,
99119
100120 // Campaign tracking
@@ -124,18 +144,25 @@ export const Opportunity = ObjectSchema.create({
124144 defaultValue : false ,
125145 } ) ,
126146
127- forecast_category : Field . select ( [ 'Pipeline' , 'Best Case' , 'Commit' , 'Omitted' , 'Closed' ] , {
147+ forecast_category : Field . select ( {
128148 label : 'Forecast Category' ,
149+ options : [
150+ { label : 'Pipeline' , value : 'pipeline' } ,
151+ { label : 'Best Case' , value : 'best_case' } ,
152+ { label : 'Commit' , value : 'commit' } ,
153+ { label : 'Omitted' , value : 'omitted' } ,
154+ { label : 'Closed' , value : 'closed' } ,
155+ ]
129156 } ) ,
130157 } ,
131158
132159 // Database indexes for performance
133160 indexes : [
134- { fields : [ 'name' ] , unique : false } ,
135- { fields : [ 'account' ] , unique : false } ,
136- { fields : [ 'owner' ] , unique : false } ,
137- { fields : [ 'stage' ] , unique : false } ,
138- { fields : [ 'close_date' ] , unique : false } ,
161+ { fields : [ 'name' ] , type : 'btree' } ,
162+ { fields : [ 'account' ] , type : 'btree' } ,
163+ { fields : [ 'owner' ] , type : 'btree' } ,
164+ { fields : [ 'stage' ] , type : 'btree' } ,
165+ { fields : [ 'close_date' ] , type : 'btree' } ,
139166 ] ,
140167
141168 // Enable advanced features
@@ -153,6 +180,11 @@ export const Opportunity = ObjectSchema.create({
153180
154181 // Removed: list_views and form_views belong in UI configuration, not object definition
155182
183+ // Lifecycle State Machine(s)
184+ stateMachines : {
185+ lifecycle : OpportunityStateMachine ,
186+ } ,
187+
156188 // Validation Rules
157189 validations : [
158190 {
@@ -169,22 +201,6 @@ export const Opportunity = ObjectSchema.create({
169201 message : 'Amount must be greater than zero' ,
170202 condition : 'amount <= 0' ,
171203 } ,
172- {
173- name : 'stage_progression' ,
174- type : 'state_machine' ,
175- severity : 'error' ,
176- message : 'Invalid stage transition' ,
177- field : 'stage' ,
178- transitions : {
179- 'prospecting' : [ 'qualification' , 'closed_lost' ] ,
180- 'qualification' : [ 'needs_analysis' , 'closed_lost' ] ,
181- 'needs_analysis' : [ 'proposal' , 'closed_lost' ] ,
182- 'proposal' : [ 'negotiation' , 'closed_lost' ] ,
183- 'negotiation' : [ 'closed_won' , 'closed_lost' ] ,
184- 'closed_won' : [ ] , // Terminal state
185- 'closed_lost' : [ ] // Terminal state
186- }
187- } ,
188204 ] ,
189205
190206 // Workflow Rules
0 commit comments