@khester/create-dynamics-app 1.1.0 → 2.1.0

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.
Files changed (210) hide show
  1. package/README.md +74 -0
  2. package/dist/artifacts/registry.d.ts +18 -0
  3. package/dist/artifacts/registry.d.ts.map +1 -0
  4. package/dist/artifacts/registry.js +340 -0
  5. package/dist/artifacts/registry.js.map +1 -0
  6. package/dist/artifacts/types.d.ts +122 -0
  7. package/dist/artifacts/types.d.ts.map +1 -0
  8. package/dist/artifacts/types.js +7 -0
  9. package/dist/artifacts/types.js.map +1 -0
  10. package/dist/artifacts/validators.d.ts +16 -0
  11. package/dist/artifacts/validators.d.ts.map +1 -0
  12. package/dist/artifacts/validators.js +45 -0
  13. package/dist/artifacts/validators.js.map +1 -0
  14. package/dist/fromDesign.d.ts +5 -0
  15. package/dist/fromDesign.d.ts.map +1 -0
  16. package/dist/fromDesign.js +98 -0
  17. package/dist/fromDesign.js.map +1 -0
  18. package/dist/index.js +129 -177
  19. package/dist/index.js.map +1 -1
  20. package/dist/injectDevTools.d.ts +28 -0
  21. package/dist/injectDevTools.d.ts.map +1 -0
  22. package/dist/injectDevTools.js +148 -0
  23. package/dist/injectDevTools.js.map +1 -0
  24. package/dist/scaffold.d.ts +48 -0
  25. package/dist/scaffold.d.ts.map +1 -0
  26. package/dist/scaffold.js +180 -0
  27. package/dist/scaffold.js.map +1 -0
  28. package/dist/templatePlan.d.ts +3 -0
  29. package/dist/templatePlan.d.ts.map +1 -0
  30. package/dist/templatePlan.js +43 -0
  31. package/dist/templatePlan.js.map +1 -0
  32. package/dist/utils/copyTemplate.d.ts +13 -1
  33. package/dist/utils/copyTemplate.d.ts.map +1 -1
  34. package/dist/utils/copyTemplate.js +98 -4
  35. package/dist/utils/copyTemplate.js.map +1 -1
  36. package/dist/utils/updatePackageJson.d.ts +11 -1
  37. package/dist/utils/updatePackageJson.d.ts.map +1 -1
  38. package/dist/utils/updatePackageJson.js +12 -10
  39. package/dist/utils/updatePackageJson.js.map +1 -1
  40. package/package.json +10 -7
  41. package/templates/_shared/dev-tools/auth/get-token.js +72 -0
  42. package/templates/_shared/dev-tools/dev/mock-xrm.js +42 -0
  43. package/templates/_shared/dev-tools/metadata-sync/index.js +152 -0
  44. package/templates/_shared/dev-tools/smoke/test-retrieve.js +44 -0
  45. package/templates/dialog-form/README.md +27 -0
  46. package/templates/dialog-form/_variants/App.v8.tsx +39 -0
  47. package/templates/dialog-form/_variants/App.v9.tsx +41 -0
  48. package/templates/dialog-form/gitignore +5 -0
  49. package/templates/dialog-form/package.json +27 -0
  50. package/templates/dialog-form/public/index.html +11 -0
  51. package/templates/dialog-form/src/index.tsx +10 -0
  52. package/templates/dialog-form/src/services/dataverse.ts +30 -0
  53. package/templates/dialog-form/tsconfig.json +15 -0
  54. package/templates/dialog-form/webpack.config.js +17 -0
  55. package/templates/grid-customizer/README.md +28 -0
  56. package/templates/grid-customizer/gitignore +4 -0
  57. package/templates/grid-customizer/package.json +25 -0
  58. package/templates/grid-customizer/src/GridCustomizer.ts +28 -0
  59. package/templates/grid-customizer/src/cell-renderers.tsx +35 -0
  60. package/templates/grid-customizer/src/index.ts +4 -0
  61. package/templates/grid-customizer/src/types/grid-types.ts +30 -0
  62. package/templates/grid-customizer/src/utils/color-utils.ts +24 -0
  63. package/templates/grid-customizer/tsconfig.json +15 -0
  64. package/templates/grid-customizer/webpack.config.js +17 -0
  65. package/templates/pcf-dataset/ControlManifest.Input.xml +16 -0
  66. package/templates/pcf-dataset/README.md +21 -0
  67. package/templates/pcf-dataset/gitignore +5 -0
  68. package/templates/pcf-dataset/index.ts +39 -0
  69. package/templates/pcf-dataset/package.json +30 -0
  70. package/templates/pcf-dataset/strings/{{componentName}}.1033.resx +47 -0
  71. package/templates/pcf-dataset/tsconfig.json +8 -0
  72. package/templates/pcf-dataset/{{componentName}}Component.tsx +39 -0
  73. package/templates/pcf-field/ControlManifest.Input.xml +17 -0
  74. package/templates/pcf-field/README.md +95 -0
  75. package/templates/pcf-field/_variants/ValueInput.boolean.tsx +24 -0
  76. package/templates/pcf-field/_variants/ValueInput.date.tsx +27 -0
  77. package/templates/pcf-field/_variants/ValueInput.number.tsx +35 -0
  78. package/templates/pcf-field/_variants/ValueInput.text.tsx +27 -0
  79. package/templates/pcf-field/gitignore +5 -0
  80. package/templates/pcf-field/index.ts +61 -0
  81. package/templates/pcf-field/package.json +30 -0
  82. package/templates/pcf-field/strings/{{componentName}}.1033.resx +47 -0
  83. package/templates/pcf-field/tsconfig.json +8 -0
  84. package/templates/pcf-field/{{componentName}}Component.tsx +35 -0
  85. package/templates/power-pages-starter/gitignore +5 -0
  86. package/templates/react-custom-page/gitignore +5 -0
  87. package/templates/{dynamics-365-starter → react-custom-page}/package.json +3 -3
  88. package/templates/react-custom-page/tools/metadata-sync/index.js +152 -0
  89. package/templates/static-web-app/README.md +36 -0
  90. package/templates/static-web-app/_variants/App.v8.tsx +32 -0
  91. package/templates/static-web-app/_variants/App.v9.tsx +31 -0
  92. package/templates/static-web-app/api/host.json +12 -0
  93. package/templates/static-web-app/api/package.json +19 -0
  94. package/templates/static-web-app/api/src/functions/hello.ts +16 -0
  95. package/templates/static-web-app/api/tsconfig.json +14 -0
  96. package/templates/static-web-app/frontend/index.html +12 -0
  97. package/templates/static-web-app/frontend/package.json +23 -0
  98. package/templates/static-web-app/frontend/src/index.tsx +8 -0
  99. package/templates/static-web-app/frontend/tsconfig.json +16 -0
  100. package/templates/static-web-app/frontend/vite.config.ts +13 -0
  101. package/templates/static-web-app/gitignore +8 -0
  102. package/templates/static-web-app/package.json +15 -0
  103. package/templates/static-web-app/staticwebapp.config.json +7 -0
  104. package/templates/teams-app/README.md +27 -0
  105. package/templates/teams-app/_variants/graph.off.ts +7 -0
  106. package/templates/teams-app/_variants/graph.on.ts +22 -0
  107. package/templates/teams-app/appPackage/manifest.json +26 -0
  108. package/templates/teams-app/gitignore +5 -0
  109. package/templates/teams-app/index.html +12 -0
  110. package/templates/teams-app/package.json +26 -0
  111. package/templates/teams-app/src/App.tsx +25 -0
  112. package/templates/teams-app/src/index.tsx +8 -0
  113. package/templates/teams-app/tsconfig.json +16 -0
  114. package/templates/teams-app/vite.config.ts +9 -0
  115. package/templates/web-resource/README.md +39 -0
  116. package/templates/web-resource/_variants/App.v8.tsx +29 -0
  117. package/templates/web-resource/_variants/App.v9.tsx +28 -0
  118. package/templates/web-resource/gitignore +5 -0
  119. package/templates/web-resource/package.json +27 -0
  120. package/templates/web-resource/public/index.html +11 -0
  121. package/templates/web-resource/src/index.tsx +10 -0
  122. package/templates/web-resource/src/services/dataverse.ts +30 -0
  123. package/templates/web-resource/tsconfig.json +15 -0
  124. package/templates/web-resource/webpack.config.js +17 -0
  125. package/dist/utils/consultingHelpers.d.ts +0 -13
  126. package/dist/utils/consultingHelpers.d.ts.map +0 -1
  127. package/dist/utils/consultingHelpers.js +0 -569
  128. package/dist/utils/consultingHelpers.js.map +0 -1
  129. package/templates/dynamics-365-starter/INTEGRATION_TEST_RESULTS.md +0 -302
  130. package/templates/dynamics-365-starter/PHASE_4_COMPLETION_SUMMARY.md +0 -305
  131. package/templates/dynamics-365-starter/deployment/QUICKSTART-MAC.md +0 -507
  132. package/templates/dynamics-365-starter/deployment/QUICKSTART-WINDOWS.md +0 -372
  133. package/templates/dynamics-365-starter/deployment/pipelines/README.md +0 -375
  134. package/templates/dynamics-365-starter/deployment/pipelines/azure-pipelines.yml +0 -330
  135. package/templates/dynamics-365-starter/deployment/pipelines/github-actions.yml +0 -422
  136. package/templates/dynamics-365-starter/deployment/pipelines/jenkins.groovy +0 -636
  137. package/templates/dynamics-365-starter/deployment/scripts/deploy.ps1 +0 -417
  138. package/templates/dynamics-365-starter/deployment/scripts/deploy.sh +0 -582
  139. package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.ps1 +0 -486
  140. package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.sh +0 -567
  141. package/templates/dynamics-365-starter/deployment/scripts/validate-setup.ps1 +0 -703
  142. package/templates/dynamics-365-starter/deployment/scripts/validate-setup.sh +0 -671
  143. package/templates/dynamics-365-starter/docs/team-standards/README.md +0 -273
  144. package/templates/dynamics-365-starter/docs/team-standards/client-onboarding.md +0 -577
  145. package/templates/dynamics-365-starter/docs/team-standards/code-review-checklist.md +0 -359
  146. package/templates/dynamics-365-starter/docs/team-standards/coding-standards.md +0 -700
  147. package/templates/dynamics-365-starter/docs/team-standards/cross-platform-team-guide.md +0 -736
  148. package/templates/dynamics-365-starter/docs/team-standards/development-workflows.md +0 -727
  149. package/templates/dynamics-365-starter/docs/troubleshooting/common-errors.md +0 -758
  150. package/templates/dynamics-365-starter/docs/troubleshooting/platform-specific-issues.md +0 -878
  151. package/templates/dynamics-365-starter/src/client-project-template/README.md +0 -234
  152. package/templates/dynamics-365-starter/src/client-project-template/config/client.template.json +0 -114
  153. package/templates/dynamics-365-starter/src/client-project-template/config/environments/template.json +0 -186
  154. package/templates/dynamics-365-starter/src/client-project-template/scripts/client-setup.js +0 -667
  155. package/templates/dynamics-365-starter/src/examples/README.md +0 -52
  156. package/templates/dynamics-365-starter/src/examples/component-examples/opportunity-management.tsx +0 -625
  157. package/templates/dynamics-365-starter/src/examples/entity-examples/opportunity-model.ts +0 -545
  158. package/templates/dynamics-365-starter/src/examples/integration-examples/custom-pcf-wrapper.tsx +0 -722
  159. package/templates/dynamics-365-starter/src/examples/workflow-examples/sales-workflow.ts +0 -662
  160. package/templates/dynamics-365-starter/src/page-templates/EntityDashboard.tsx +0 -519
  161. package/templates/dynamics-365-starter/src/page-templates/EntityDetailPage.tsx +0 -456
  162. package/templates/dynamics-365-starter/src/page-templates/EntityListPage.tsx +0 -406
  163. package/templates/dynamics-365-starter/src/page-templates/RelatedEntitiesPage.tsx +0 -578
  164. package/templates/dynamics-365-starter/src/page-templates/SearchPage.tsx +0 -629
  165. package/templates/dynamics-365-starter/tools/entity-generator/index.js +0 -168
  166. package/templates/dynamics-365-starter/tools/entity-generator/templates/constants.template.ts +0 -124
  167. package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.css +0 -283
  168. package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.tsx +0 -275
  169. package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.css +0 -204
  170. package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.tsx +0 -413
  171. package/templates/dynamics-365-starter/tools/entity-generator/templates/model.template.ts +0 -250
  172. package/templates/dynamics-365-starter/tools/metadata-sync/d365-client.js +0 -410
  173. package/templates/dynamics-365-starter/tools/metadata-sync/index.js +0 -512
  174. package/templates/dynamics-365-starter/tools/metadata-sync/type-generator.js +0 -675
  175. /package/templates/{dynamics-365-starter → react-custom-page}/README.md +0 -0
  176. /package/templates/{dynamics-365-starter → react-custom-page}/deployment/README.md +0 -0
  177. /package/templates/{dynamics-365-starter → react-custom-page}/docs/ARCHITECTURE_OVERVIEW.md +0 -0
  178. /package/templates/{dynamics-365-starter → react-custom-page}/docs/BEST_PRACTICES.md +0 -0
  179. /package/templates/{dynamics-365-starter → react-custom-page}/docs/MIGRATION_GUIDE.md +0 -0
  180. /package/templates/{dynamics-365-starter → react-custom-page}/public/index.html +0 -0
  181. /package/templates/{dynamics-365-starter → react-custom-page}/scripts/custom-build.js +0 -0
  182. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountForm.css +0 -0
  183. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountForm.tsx +0 -0
  184. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountManagement.css +0 -0
  185. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountManagement.tsx +0 -0
  186. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactForm.css +0 -0
  187. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactForm.tsx +0 -0
  188. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactManagement.css +0 -0
  189. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactManagement.tsx +0 -0
  190. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LogDialog.tsx +0 -0
  191. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingContext.tsx +0 -0
  192. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingDebugPanel.css +0 -0
  193. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingDebugPanel.tsx +0 -0
  194. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingProvider.tsx +0 -0
  195. /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/logger.ts +0 -0
  196. /package/templates/{dynamics-365-starter → react-custom-page}/src/constants/account.ts +0 -0
  197. /package/templates/{dynamics-365-starter → react-custom-page}/src/constants/contact.ts +0 -0
  198. /package/templates/{dynamics-365-starter → react-custom-page}/src/index.tsx +0 -0
  199. /package/templates/{dynamics-365-starter → react-custom-page}/src/models/Account.ts +0 -0
  200. /package/templates/{dynamics-365-starter → react-custom-page}/src/models/BaseEntity.ts +0 -0
  201. /package/templates/{dynamics-365-starter → react-custom-page}/src/models/Contact.ts +0 -0
  202. /package/templates/{dynamics-365-starter → react-custom-page}/src/pcf/ContactControlWrapper.tsx +0 -0
  203. /package/templates/{dynamics-365-starter → react-custom-page}/src/pcf/MultiEntityControlWrapper.tsx +0 -0
  204. /package/templates/{dynamics-365-starter → react-custom-page}/src/providers/DynamicsProvider.tsx +0 -0
  205. /package/templates/{dynamics-365-starter → react-custom-page}/src/services/MockApiService.ts +0 -0
  206. /package/templates/{dynamics-365-starter → react-custom-page}/src/services/ServiceFactory.ts +0 -0
  207. /package/templates/{dynamics-365-starter → react-custom-page}/src/services/XrmApiService.ts +0 -0
  208. /package/templates/{dynamics-365-starter → react-custom-page}/src/styles/index.css +0 -0
  209. /package/templates/{dynamics-365-starter → react-custom-page}/tsconfig.json +0 -0
  210. /package/templates/{dynamics-365-starter → react-custom-page}/webpack.config.js +0 -0
@@ -1,545 +0,0 @@
1
- /**
2
- * Example: Creating a custom Opportunity entity model
3
- *
4
- * This example demonstrates how to extend the BaseEntity pattern
5
- * to create a new entity model with validation, CRUD operations,
6
- * and integration with the ServiceFactory and logging system.
7
- *
8
- * @example
9
- * ```typescript
10
- * // Create a new opportunity
11
- * const opportunity = new Opportunity({
12
- * name: 'New Sales Opportunity',
13
- * estimatedvalue: 50000,
14
- * closeprobability: 75
15
- * });
16
- *
17
- * // Validate and save
18
- * opportunity.validate();
19
- * const saved = await Opportunity.create(apiService, opportunity);
20
- * ```
21
- */
22
-
23
- import { IApiService } from '@khester/dynamics-ui-api-client';
24
- import { BaseEntity } from '../../models/BaseEntity';
25
-
26
- /**
27
- * Opportunity entity interface
28
- * Define all properties that the Opportunity entity can have
29
- */
30
- export interface IOpportunity {
31
- /** Unique identifier for the opportunity */
32
- opportunityid?: string;
33
-
34
- /** Opportunity name (required) */
35
- name: string;
36
-
37
- /** Estimated value of the opportunity */
38
- estimatedvalue?: number;
39
-
40
- /** Close probability percentage (0-100) */
41
- closeprobability?: number;
42
-
43
- /** Expected close date */
44
- estimatedclosedate?: string;
45
-
46
- /** Opportunity description */
47
- description?: string;
48
-
49
- /** Associated account ID */
50
- parentaccountid?: string;
51
-
52
- /** Associated contact ID */
53
- parentcontactid?: string;
54
-
55
- /** Sales stage option set value */
56
- salesstagecode?: number;
57
-
58
- /** Opportunity status (open/won/lost) */
59
- statecode?: number;
60
-
61
- /** Detailed status reason */
62
- statuscode?: number;
63
-
64
- /** Created date */
65
- createdon?: string;
66
-
67
- /** Modified date */
68
- modifiedon?: string;
69
-
70
- /** Owner ID */
71
- ownerid?: string;
72
- }
73
-
74
- /**
75
- * Opportunity entity constants
76
- * Following the same pattern as AccountConstants and ContactConstants
77
- */
78
- export class OpportunityConstants {
79
- /** Entity name for single opportunity */
80
- public static readonly EntityName: string = 'opportunity';
81
-
82
- /** Entity collection name for multiple opportunities */
83
- public static readonly EntityCollectionName: string = 'opportunities';
84
-
85
- /** Primary key field */
86
- public static readonly PrimaryKey: string = 'opportunityid';
87
-
88
- /** Primary name field */
89
- public static readonly PrimaryName: string = 'name';
90
-
91
- /** Estimated value field */
92
- public static readonly EstimatedValue: string = 'estimatedvalue';
93
-
94
- /** Close probability field */
95
- public static readonly CloseProbability: string = 'closeprobability';
96
-
97
- /** Estimated close date field */
98
- public static readonly EstimatedCloseDate: string = 'estimatedclosedate';
99
-
100
- /** Description field */
101
- public static readonly Description: string = 'description';
102
-
103
- /** Parent account reference */
104
- public static readonly ParentAccountId: string = 'parentaccountid';
105
-
106
- /** Parent contact reference */
107
- public static readonly ParentContactId: string = 'parentcontactid';
108
-
109
- /** Sales stage code */
110
- public static readonly SalesStageCode: string = 'salesstagecode';
111
-
112
- /** State code (Active/Inactive) */
113
- public static readonly StateCode: string = 'statecode';
114
-
115
- /** Status code (detailed status) */
116
- public static readonly StatusCode: string = 'statuscode';
117
-
118
- /** Created date */
119
- public static readonly CreatedOn: string = 'createdon';
120
-
121
- /** Modified date */
122
- public static readonly ModifiedOn: string = 'modifiedon';
123
-
124
- /** Owner ID */
125
- public static readonly OwnerId: string = 'ownerid';
126
- }
127
-
128
- /**
129
- * Sales Stage Option Set Values
130
- */
131
- export enum SalesStageCode_OptionSet {
132
- Qualify = 0,
133
- Develop = 1,
134
- Propose = 2,
135
- Close = 3,
136
- }
137
-
138
- /**
139
- * Opportunity State Code Option Set
140
- */
141
- export enum OpportunityStateCode_OptionSet {
142
- Open = 0,
143
- Won = 1,
144
- Lost = 2,
145
- }
146
-
147
- /**
148
- * Opportunity Status Code Option Set
149
- */
150
- export enum OpportunityStatusCode_OptionSet {
151
- InProgress = 1,
152
- OnHold = 2,
153
- Won = 3,
154
- Canceled = 4,
155
- OutSold = 5,
156
- }
157
-
158
- /**
159
- * Opportunity entity model class
160
- *
161
- * Extends BaseEntity to provide CRUD operations, validation,
162
- * and integration with the logging system.
163
- *
164
- * @example
165
- * ```typescript
166
- * // Create and validate an opportunity
167
- * const opp = new Opportunity({
168
- * name: 'Q1 Software License Deal',
169
- * estimatedvalue: 75000,
170
- * closeprobability: 80,
171
- * estimatedclosedate: '2024-03-31'
172
- * });
173
- *
174
- * // Validation happens automatically
175
- * const isValid = opp.validate();
176
- *
177
- * // Save to Dynamics 365
178
- * const savedOpp = await Opportunity.create(apiService, opp);
179
- * ```
180
- */
181
- export class Opportunity extends BaseEntity implements IOpportunity {
182
- opportunityid?: string;
183
- name: string;
184
- estimatedvalue?: number;
185
- closeprobability?: number;
186
- estimatedclosedate?: string;
187
- description?: string;
188
- parentaccountid?: string;
189
- parentcontactid?: string;
190
- salesstagecode?: number;
191
- statecode?: number;
192
- statuscode?: number;
193
- createdon?: string;
194
- modifiedon?: string;
195
- ownerid?: string;
196
-
197
- /**
198
- * Constructor for Opportunity entity
199
- * @param opportunity - The opportunity data to initialize with
200
- */
201
- constructor(opportunity: IOpportunity) {
202
- super();
203
- this.opportunityid = opportunity.opportunityid;
204
- this.name = opportunity.name;
205
- this.estimatedvalue = opportunity.estimatedvalue;
206
- this.closeprobability = opportunity.closeprobability;
207
- this.estimatedclosedate = opportunity.estimatedclosedate;
208
- this.description = opportunity.description;
209
- this.parentaccountid = opportunity.parentaccountid;
210
- this.parentcontactid = opportunity.parentcontactid;
211
- this.salesstagecode = opportunity.salesstagecode;
212
- this.statecode = opportunity.statecode;
213
- this.statuscode = opportunity.statuscode;
214
- this.createdon = opportunity.createdon;
215
- this.modifiedon = opportunity.modifiedon;
216
- this.ownerid = opportunity.ownerid;
217
- }
218
-
219
- /**
220
- * Validates the opportunity instance
221
- * @returns True if valid, throws error if invalid
222
- * @throws Error with validation message if validation fails
223
- *
224
- * @example
225
- * ```typescript
226
- * try {
227
- * opportunity.validate();
228
- * console.log('Opportunity is valid');
229
- * } catch (error) {
230
- * console.error('Validation failed:', error.message);
231
- * }
232
- * ```
233
- */
234
- validate(): boolean {
235
- if (!this.name || this.name.trim().length === 0) {
236
- throw new Error('Opportunity name is required');
237
- }
238
-
239
- if (this.name.length > 300) {
240
- throw new Error('Opportunity name cannot exceed 300 characters');
241
- }
242
-
243
- if (this.estimatedvalue !== undefined && this.estimatedvalue < 0) {
244
- throw new Error('Estimated value cannot be negative');
245
- }
246
-
247
- if (this.closeprobability !== undefined) {
248
- if (this.closeprobability < 0 || this.closeprobability > 100) {
249
- throw new Error('Close probability must be between 0 and 100');
250
- }
251
- }
252
-
253
- if (this.estimatedclosedate) {
254
- const closeDate = new Date(this.estimatedclosedate);
255
- const today = new Date();
256
- if (closeDate < today) {
257
- throw new Error('Estimated close date cannot be in the past');
258
- }
259
- }
260
-
261
- return true;
262
- }
263
-
264
- /**
265
- * Creates a new opportunity record
266
- * @param apiService - The API service instance
267
- * @param opportunity - The opportunity to create
268
- * @returns Promise resolving to the created opportunity
269
- *
270
- * @example
271
- * ```typescript
272
- * const newOpportunity = new Opportunity({
273
- * name: 'Enterprise Software Deal',
274
- * estimatedvalue: 100000,
275
- * closeprobability: 70
276
- * });
277
- *
278
- * const created = await Opportunity.create(apiService, newOpportunity);
279
- * console.log('Created opportunity:', created.opportunityid);
280
- * ```
281
- */
282
- public static async create(
283
- apiService: IApiService,
284
- opportunity: Opportunity
285
- ): Promise<Opportunity> {
286
- const loggerContext = 'Opportunity.create';
287
- console.log(`${loggerContext}: Creating new opportunity`, {
288
- name: opportunity.name,
289
- });
290
-
291
- return await this.createEntity<Opportunity>(
292
- apiService,
293
- opportunity,
294
- OpportunityConstants.EntityCollectionName,
295
- loggerContext
296
- );
297
- }
298
-
299
- /**
300
- * Updates an existing opportunity record
301
- * @param apiService - The API service instance
302
- * @param opportunity - The opportunity to update
303
- * @returns Promise resolving to the updated opportunity
304
- *
305
- * @example
306
- * ```typescript
307
- * // Load existing opportunity
308
- * const opportunity = await Opportunity.retrieveById(apiService, opportunityId);
309
- *
310
- * // Update properties
311
- * opportunity.closeprobability = 90;
312
- * opportunity.salesstagecode = SalesStageCode_OptionSet.Close;
313
- *
314
- * // Save changes
315
- * const updated = await Opportunity.update(apiService, opportunity);
316
- * ```
317
- */
318
- public static async update(
319
- apiService: IApiService,
320
- opportunity: Opportunity
321
- ): Promise<Opportunity> {
322
- const loggerContext = 'Opportunity.update';
323
-
324
- if (!opportunity.opportunityid) {
325
- throw new Error('Opportunity ID is required for update');
326
- }
327
-
328
- console.log(`${loggerContext}: Updating opportunity`, {
329
- opportunityid: opportunity.opportunityid,
330
- name: opportunity.name,
331
- });
332
-
333
- return await this.updateEntity<Opportunity>(
334
- apiService,
335
- opportunity.opportunityid,
336
- opportunity,
337
- OpportunityConstants.EntityCollectionName,
338
- OpportunityConstants.PrimaryKey,
339
- loggerContext
340
- );
341
- }
342
-
343
- /**
344
- * Deletes an opportunity record
345
- * @param apiService - The API service instance
346
- * @param opportunityId - The ID of the opportunity to delete
347
- * @returns Promise resolving when deletion is complete
348
- *
349
- * @example
350
- * ```typescript
351
- * await Opportunity.delete(apiService, opportunityId);
352
- * console.log('Opportunity deleted successfully');
353
- * ```
354
- */
355
- public static async delete(
356
- apiService: IApiService,
357
- opportunityId: string
358
- ): Promise<void> {
359
- const loggerContext = 'Opportunity.delete';
360
- console.log(`${loggerContext}: Deleting opportunity`, {
361
- opportunityid: opportunityId,
362
- });
363
-
364
- return await this.deleteEntity(
365
- apiService,
366
- opportunityId,
367
- OpportunityConstants.EntityCollectionName,
368
- loggerContext
369
- );
370
- }
371
-
372
- /**
373
- * Retrieves opportunities based on a filter
374
- * @param apiService - The API service instance
375
- * @param filter - Optional FetchXML filter string
376
- * @returns Promise resolving to an array of opportunities
377
- *
378
- * @example
379
- * ```typescript
380
- * // Get all high-value opportunities
381
- * const filter = `<filter type="and">
382
- * <condition attribute="estimatedvalue" operator="ge" value="50000" />
383
- * <condition attribute="statecode" operator="eq" value="0" />
384
- * </filter>`;
385
- *
386
- * const opportunities = await Opportunity.retrieveByFilter(apiService, filter);
387
- * ```
388
- */
389
- public static async retrieveByFilter(
390
- apiService: IApiService,
391
- filter?: string
392
- ): Promise<Opportunity[]> {
393
- const loggerContext = 'Opportunity.retrieveByFilter';
394
- console.log(`${loggerContext}: Retrieving opportunities with filter`, {
395
- filter,
396
- });
397
-
398
- const attributes = [
399
- OpportunityConstants.PrimaryKey,
400
- OpportunityConstants.PrimaryName,
401
- OpportunityConstants.EstimatedValue,
402
- OpportunityConstants.CloseProbability,
403
- OpportunityConstants.EstimatedCloseDate,
404
- OpportunityConstants.Description,
405
- OpportunityConstants.ParentAccountId,
406
- OpportunityConstants.ParentContactId,
407
- OpportunityConstants.SalesStageCode,
408
- OpportunityConstants.StateCode,
409
- OpportunityConstants.StatusCode,
410
- OpportunityConstants.CreatedOn,
411
- OpportunityConstants.ModifiedOn,
412
- OpportunityConstants.OwnerId,
413
- ];
414
-
415
- const fetchXml = this.buildFetchXml(
416
- OpportunityConstants.EntityName,
417
- attributes,
418
- filter,
419
- { attribute: OpportunityConstants.PrimaryName }
420
- );
421
-
422
- return await this.retrieveEntitiesByFilter<Opportunity>(
423
- apiService,
424
- OpportunityConstants.EntityCollectionName,
425
- fetchXml,
426
- Opportunity,
427
- loggerContext
428
- );
429
- }
430
-
431
- /**
432
- * Retrieves a single opportunity by ID
433
- * @param apiService - The API service instance
434
- * @param opportunityId - The opportunity ID
435
- * @returns Promise resolving to the opportunity or null if not found
436
- *
437
- * @example
438
- * ```typescript
439
- * const opportunity = await Opportunity.retrieveById(apiService, 'guid-here');
440
- * if (opportunity) {
441
- * console.log('Found opportunity:', opportunity.name);
442
- * }
443
- * ```
444
- */
445
- public static async retrieveById(
446
- apiService: IApiService,
447
- opportunityId: string
448
- ): Promise<Opportunity | null> {
449
- const loggerContext = 'Opportunity.retrieveById';
450
- console.log(`${loggerContext}: Retrieving opportunity by ID`, {
451
- opportunityid: opportunityId,
452
- });
453
-
454
- const filter = `<filter type="and">
455
- <condition attribute="${OpportunityConstants.PrimaryKey}" operator="eq" value="${this.escapeXml(opportunityId)}" />
456
- </filter>`;
457
-
458
- const opportunities = await this.retrieveByFilter(apiService, filter);
459
- return opportunities.length > 0 ? opportunities[0] : null;
460
- }
461
-
462
- /**
463
- * Retrieves active opportunities only
464
- * @param apiService - The API service instance
465
- * @returns Promise resolving to an array of active opportunities
466
- *
467
- * @example
468
- * ```typescript
469
- * const activeOpportunities = await Opportunity.retrieveActiveOpportunities(apiService);
470
- * console.log(`Found ${activeOpportunities.length} active opportunities`);
471
- * ```
472
- */
473
- public static async retrieveActiveOpportunities(
474
- apiService: IApiService
475
- ): Promise<Opportunity[]> {
476
- const loggerContext = 'Opportunity.retrieveActiveOpportunities';
477
- console.log(`${loggerContext}: Retrieving active opportunities`);
478
-
479
- const filter = `<filter type="and">
480
- <condition attribute="${OpportunityConstants.StateCode}" operator="eq" value="0" />
481
- </filter>`;
482
-
483
- return await this.retrieveByFilter(apiService, filter);
484
- }
485
-
486
- /**
487
- * Retrieves opportunities by sales stage
488
- * @param apiService - The API service instance
489
- * @param salesStage - The sales stage to filter by
490
- * @returns Promise resolving to an array of opportunities in the specified stage
491
- *
492
- * @example
493
- * ```typescript
494
- * const proposalStageOpps = await Opportunity.retrieveBySalesStage(
495
- * apiService,
496
- * SalesStageCode_OptionSet.Propose
497
- * );
498
- * ```
499
- */
500
- public static async retrieveBySalesStage(
501
- apiService: IApiService,
502
- salesStage: SalesStageCode_OptionSet
503
- ): Promise<Opportunity[]> {
504
- const loggerContext = 'Opportunity.retrieveBySalesStage';
505
- console.log(`${loggerContext}: Retrieving opportunities by sales stage`, {
506
- salesStage,
507
- });
508
-
509
- const filter = `<filter type="and">
510
- <condition attribute="${OpportunityConstants.SalesStageCode}" operator="eq" value="${salesStage}" />
511
- <condition attribute="${OpportunityConstants.StateCode}" operator="eq" value="0" />
512
- </filter>`;
513
-
514
- return await this.retrieveByFilter(apiService, filter);
515
- }
516
-
517
- /**
518
- * Retrieves opportunities by account
519
- * @param apiService - The API service instance
520
- * @param accountId - The account ID to filter by
521
- * @returns Promise resolving to an array of opportunities for the specified account
522
- *
523
- * @example
524
- * ```typescript
525
- * const accountOpportunities = await Opportunity.retrieveByAccount(apiService, accountId);
526
- * console.log(`Account has ${accountOpportunities.length} opportunities`);
527
- * ```
528
- */
529
- public static async retrieveByAccount(
530
- apiService: IApiService,
531
- accountId: string
532
- ): Promise<Opportunity[]> {
533
- const loggerContext = 'Opportunity.retrieveByAccount';
534
- console.log(`${loggerContext}: Retrieving opportunities by account`, {
535
- accountId,
536
- });
537
-
538
- const filter = `<filter type="and">
539
- <condition attribute="${OpportunityConstants.ParentAccountId}" operator="eq" value="${this.escapeXml(accountId)}" />
540
- <condition attribute="${OpportunityConstants.StateCode}" operator="eq" value="0" />
541
- </filter>`;
542
-
543
- return await this.retrieveByFilter(apiService, filter);
544
- }
545
- }