@contractspec/example.service-business-os 3.7.6 → 3.7.7
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/README.md +66 -9
- package/dist/browser/events.js +1 -1
- package/dist/browser/index.js +170 -170
- package/dist/browser/operations/index.js +150 -150
- package/dist/client/index.d.ts +1 -1
- package/dist/events.js +1 -1
- package/dist/handlers/index.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +170 -170
- package/dist/invoice/index.d.ts +1 -1
- package/dist/job/index.d.ts +2 -2
- package/dist/node/events.js +1 -1
- package/dist/node/index.js +170 -170
- package/dist/node/operations/index.js +150 -150
- package/dist/operations/index.d.ts +5 -5
- package/dist/operations/index.js +150 -150
- package/dist/payment/index.d.ts +1 -1
- package/dist/quote/index.d.ts +2 -2
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,16 +1,73 @@
|
|
|
1
1
|
# @contractspec/example.service-business-os
|
|
2
2
|
|
|
3
|
-
Website: https://contractspec.io
|
|
3
|
+
Website: https://contractspec.io
|
|
4
4
|
|
|
5
|
+
**Service Business OS example (clients, quotes, jobs, invoices) for ContractSpec.**
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
## What This Demonstrates
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
- Multi-entity domain modeling (client, quote, job, invoice, payment).
|
|
10
|
+
- Per-entity schema and operations pattern.
|
|
11
|
+
- Capability and feature definition patterns.
|
|
12
|
+
- Presentation layer and event-driven architecture.
|
|
13
|
+
- Handler aggregation.
|
|
14
|
+
- `src/docs/` contains docblocks and documentation-facing exports.
|
|
9
15
|
|
|
10
|
-
|
|
11
|
-
- Quote lifecycle (draft → sent → accepted/rejected)
|
|
12
|
-
- Jobs scheduling and completion with reminders via `@contractspec/lib.jobs`
|
|
13
|
-
- Invoicing and payments with audit trail + notifications
|
|
14
|
-
- Attachments for proposals and receipts via `@contractspec/lib.files`
|
|
16
|
+
## Running Locally
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
From `packages/examples/service-business-os`:
|
|
19
|
+
- `bun run dev`
|
|
20
|
+
- `bun run build`
|
|
21
|
+
- `bun run typecheck`
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
Use `@contractspec/example.service-business-os` as a reference implementation, or import its exported surfaces into a workspace that composes ContractSpec examples and bundles.
|
|
26
|
+
|
|
27
|
+
## Architecture
|
|
28
|
+
|
|
29
|
+
- `src/client` is part of the package's public or composition surface.
|
|
30
|
+
- `src/docs/` contains docblocks and documentation-facing exports.
|
|
31
|
+
- `src/entities/` contains domain entities and value objects.
|
|
32
|
+
- `src/events.ts` is package-level event definitions.
|
|
33
|
+
- `src/example.ts` is the runnable example entrypoint.
|
|
34
|
+
- `src/handlers/` contains handlers or demo adapters wired to contract surfaces.
|
|
35
|
+
- `src/index.ts` is the root public barrel and package entrypoint.
|
|
36
|
+
|
|
37
|
+
## Public Entry Points
|
|
38
|
+
|
|
39
|
+
- Export `.` resolves through `./src/index.ts`.
|
|
40
|
+
- Export `./client` resolves through `./src/client/index.ts`.
|
|
41
|
+
- Export `./client/client.operations` resolves through `./src/client/client.operations.ts`.
|
|
42
|
+
- Export `./client/client.schema` resolves through `./src/client/client.schema.ts`.
|
|
43
|
+
- Export `./docs` resolves through `./src/docs/index.ts`.
|
|
44
|
+
- Export `./docs/service-business-os.docblock` resolves through `./src/docs/service-business-os.docblock.ts`.
|
|
45
|
+
- Export `./entities` resolves through `./src/entities/index.ts`.
|
|
46
|
+
- Export `./events` resolves through `./src/events.ts`.
|
|
47
|
+
- Export `./example` resolves through `./src/example.ts`.
|
|
48
|
+
- Export `./handlers` resolves through `./src/handlers/index.ts`.
|
|
49
|
+
- The package publishes 26 total export subpaths; keep docs aligned with `package.json`.
|
|
50
|
+
|
|
51
|
+
## Local Commands
|
|
52
|
+
|
|
53
|
+
- `bun run dev` — contractspec-bun-build dev
|
|
54
|
+
- `bun run build` — bun run prebuild && bun run build:bundle && bun run build:types
|
|
55
|
+
- `bun run lint` — bun lint:fix
|
|
56
|
+
- `bun run lint:check` — biome check .
|
|
57
|
+
- `bun run lint:fix` — biome check --write --unsafe --only=nursery/useSortedClasses . && biome check --write .
|
|
58
|
+
- `bun run typecheck` — tsc --noEmit
|
|
59
|
+
- `bun run publish:pkg` — bun publish --tolerate-republish --ignore-scripts --verbose
|
|
60
|
+
- `bun run publish:pkg:canary` — bun publish:pkg --tag canary
|
|
61
|
+
- `bun run clean` — rimraf dist .turbo
|
|
62
|
+
- `bun run build:bundle` — contractspec-bun-build transpile
|
|
63
|
+
- `bun run build:types` — contractspec-bun-build types
|
|
64
|
+
- `bun run prebuild` — contractspec-bun-build prebuild
|
|
65
|
+
|
|
66
|
+
## Recent Updates
|
|
67
|
+
|
|
68
|
+
- Replace eslint+prettier by biomejs to optimize speed.
|
|
69
|
+
- Missing contract layers.
|
|
70
|
+
|
|
71
|
+
## Notes
|
|
72
|
+
|
|
73
|
+
- Works alongside `@contractspec/lib.contracts-spec`, `@contractspec/lib.schema`, `@contractspec/tool.bun`, `@contractspec/tool.typescript`.
|
package/dist/browser/events.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/events.ts
|
|
2
|
-
import { ScalarTypeEnum, defineSchemaModel } from "@contractspec/lib.schema";
|
|
3
2
|
import { defineEvent } from "@contractspec/lib.contracts-spec";
|
|
3
|
+
import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
|
|
4
4
|
var QuoteEventPayload = defineSchemaModel({
|
|
5
5
|
name: "QuoteEventPayload",
|
|
6
6
|
description: "Event payload for quote lifecycle",
|
package/dist/browser/index.js
CHANGED
|
@@ -67,117 +67,74 @@ var CreateClientContract = defineCommand({
|
|
|
67
67
|
]
|
|
68
68
|
}
|
|
69
69
|
});
|
|
70
|
-
// src/
|
|
70
|
+
// src/invoice/invoice.schema.ts
|
|
71
71
|
import { defineSchemaModel as defineSchemaModel2, ScalarTypeEnum as ScalarTypeEnum2 } from "@contractspec/lib.schema";
|
|
72
|
-
var
|
|
73
|
-
name: "
|
|
74
|
-
description: "
|
|
72
|
+
var InvoiceModel = defineSchemaModel2({
|
|
73
|
+
name: "Invoice",
|
|
74
|
+
description: "Invoice issued for a job",
|
|
75
75
|
fields: {
|
|
76
76
|
id: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
jobId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
78
|
+
invoiceNumber: {
|
|
79
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
80
|
+
isOptional: false
|
|
81
|
+
},
|
|
80
82
|
amount: { type: ScalarTypeEnum2.Float_unsecure(), isOptional: false },
|
|
81
83
|
currency: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
82
84
|
status: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
});
|
|
87
|
-
var CreateQuoteInputModel = defineSchemaModel2({
|
|
88
|
-
name: "CreateQuoteInput",
|
|
89
|
-
description: "Input for creating a quote",
|
|
90
|
-
fields: {
|
|
91
|
-
clientId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
92
|
-
title: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
93
|
-
description: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
94
|
-
amount: { type: ScalarTypeEnum2.Float_unsecure(), isOptional: false },
|
|
95
|
-
currency: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
96
|
-
validUntil: { type: ScalarTypeEnum2.DateTime(), isOptional: true },
|
|
97
|
-
orgId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
98
|
-
ownerId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
85
|
+
dueDate: { type: ScalarTypeEnum2.DateTime(), isOptional: true },
|
|
86
|
+
issuedAt: { type: ScalarTypeEnum2.DateTime(), isOptional: true },
|
|
87
|
+
paidAt: { type: ScalarTypeEnum2.DateTime(), isOptional: true }
|
|
99
88
|
}
|
|
100
89
|
});
|
|
101
|
-
var
|
|
102
|
-
name: "
|
|
103
|
-
description: "Input for
|
|
90
|
+
var IssueInvoiceInputModel = defineSchemaModel2({
|
|
91
|
+
name: "IssueInvoiceInput",
|
|
92
|
+
description: "Input for issuing an invoice",
|
|
104
93
|
fields: {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
notes: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true }
|
|
94
|
+
jobId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
95
|
+
dueDate: { type: ScalarTypeEnum2.DateTime(), isOptional: true },
|
|
96
|
+
notes: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
97
|
+
lineItems: { type: ScalarTypeEnum2.JSON(), isOptional: true }
|
|
108
98
|
}
|
|
109
99
|
});
|
|
110
100
|
|
|
111
|
-
// src/
|
|
101
|
+
// src/invoice/invoice.operations.ts
|
|
112
102
|
import { defineCommand as defineCommand2 } from "@contractspec/lib.contracts-spec";
|
|
113
103
|
var OWNERS2 = ["@examples.service-business-os"];
|
|
114
|
-
var
|
|
104
|
+
var IssueInvoiceContract = defineCommand2({
|
|
115
105
|
meta: {
|
|
116
|
-
key: "service.
|
|
106
|
+
key: "service.invoice.issue",
|
|
117
107
|
version: "1.0.0",
|
|
118
108
|
stability: "stable",
|
|
119
109
|
owners: [...OWNERS2],
|
|
120
|
-
tags: ["service-business-os", "
|
|
121
|
-
description: "
|
|
122
|
-
goal: "
|
|
123
|
-
context: "
|
|
110
|
+
tags: ["service-business-os", "invoice", "issue"],
|
|
111
|
+
description: "Issue an invoice for a job.",
|
|
112
|
+
goal: "Bill clients.",
|
|
113
|
+
context: "Billing."
|
|
124
114
|
},
|
|
125
115
|
io: {
|
|
126
|
-
input:
|
|
127
|
-
output:
|
|
116
|
+
input: IssueInvoiceInputModel,
|
|
117
|
+
output: InvoiceModel
|
|
128
118
|
},
|
|
129
119
|
policy: { auth: "user" },
|
|
130
120
|
acceptance: {
|
|
131
121
|
scenarios: [
|
|
132
122
|
{
|
|
133
|
-
key: "
|
|
134
|
-
given: ["
|
|
135
|
-
when: ["User
|
|
136
|
-
then: ["
|
|
123
|
+
key: "issue-invoice-happy-path",
|
|
124
|
+
given: ["Job is complete"],
|
|
125
|
+
when: ["User issues invoice"],
|
|
126
|
+
then: ["Invoice is created and sent"]
|
|
137
127
|
}
|
|
138
128
|
],
|
|
139
129
|
examples: [
|
|
140
130
|
{
|
|
141
|
-
key: "
|
|
131
|
+
key: "issue-standard",
|
|
142
132
|
input: {
|
|
143
|
-
|
|
144
|
-
|
|
133
|
+
jobId: "job-123",
|
|
134
|
+
dueDate: "2025-02-01",
|
|
135
|
+
items: [{ description: "Service", amount: 100 }]
|
|
145
136
|
},
|
|
146
|
-
output: { id: "
|
|
147
|
-
}
|
|
148
|
-
]
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
var AcceptQuoteContract = defineCommand2({
|
|
152
|
-
meta: {
|
|
153
|
-
key: "service.quote.accept",
|
|
154
|
-
version: "1.0.0",
|
|
155
|
-
stability: "stable",
|
|
156
|
-
owners: [...OWNERS2],
|
|
157
|
-
tags: ["service-business-os", "quote", "accept"],
|
|
158
|
-
description: "Accept a quote.",
|
|
159
|
-
goal: "Confirm quote.",
|
|
160
|
-
context: "Quote acceptance."
|
|
161
|
-
},
|
|
162
|
-
io: {
|
|
163
|
-
input: AcceptQuoteInputModel,
|
|
164
|
-
output: QuoteModel
|
|
165
|
-
},
|
|
166
|
-
policy: { auth: "user" },
|
|
167
|
-
acceptance: {
|
|
168
|
-
scenarios: [
|
|
169
|
-
{
|
|
170
|
-
key: "accept-quote-happy-path",
|
|
171
|
-
given: ["Quote is open"],
|
|
172
|
-
when: ["Client accepts quote"],
|
|
173
|
-
then: ["Quote status becomes ACCEPTED"]
|
|
174
|
-
}
|
|
175
|
-
],
|
|
176
|
-
examples: [
|
|
177
|
-
{
|
|
178
|
-
key: "client-accepts",
|
|
179
|
-
input: { quoteId: "quote-123", signature: "John Doe" },
|
|
180
|
-
output: { id: "quote-123", status: "accepted" }
|
|
137
|
+
output: { id: "inv-456", status: "issued", total: 100 }
|
|
181
138
|
}
|
|
182
139
|
]
|
|
183
140
|
}
|
|
@@ -347,114 +304,42 @@ var CompleteJobContract = defineCommand3({
|
|
|
347
304
|
]
|
|
348
305
|
}
|
|
349
306
|
});
|
|
350
|
-
// src/
|
|
307
|
+
// src/payment/payment.schema.ts
|
|
351
308
|
import { defineSchemaModel as defineSchemaModel5, ScalarTypeEnum as ScalarTypeEnum5 } from "@contractspec/lib.schema";
|
|
352
|
-
var
|
|
353
|
-
name: "
|
|
354
|
-
description: "
|
|
309
|
+
var PaymentModel = defineSchemaModel5({
|
|
310
|
+
name: "Payment",
|
|
311
|
+
description: "Payment applied to invoice",
|
|
355
312
|
fields: {
|
|
356
313
|
id: { type: ScalarTypeEnum5.String_unsecure(), isOptional: false },
|
|
357
|
-
|
|
358
|
-
invoiceNumber: {
|
|
359
|
-
type: ScalarTypeEnum5.String_unsecure(),
|
|
360
|
-
isOptional: false
|
|
361
|
-
},
|
|
314
|
+
invoiceId: { type: ScalarTypeEnum5.String_unsecure(), isOptional: false },
|
|
362
315
|
amount: { type: ScalarTypeEnum5.Float_unsecure(), isOptional: false },
|
|
363
316
|
currency: { type: ScalarTypeEnum5.String_unsecure(), isOptional: false },
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
paidAt: { type: ScalarTypeEnum5.DateTime(), isOptional: true }
|
|
368
|
-
}
|
|
369
|
-
});
|
|
370
|
-
var IssueInvoiceInputModel = defineSchemaModel5({
|
|
371
|
-
name: "IssueInvoiceInput",
|
|
372
|
-
description: "Input for issuing an invoice",
|
|
373
|
-
fields: {
|
|
374
|
-
jobId: { type: ScalarTypeEnum5.String_unsecure(), isOptional: false },
|
|
375
|
-
dueDate: { type: ScalarTypeEnum5.DateTime(), isOptional: true },
|
|
376
|
-
notes: { type: ScalarTypeEnum5.String_unsecure(), isOptional: true },
|
|
377
|
-
lineItems: { type: ScalarTypeEnum5.JSON(), isOptional: true }
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
// src/invoice/invoice.operations.ts
|
|
382
|
-
import { defineCommand as defineCommand4 } from "@contractspec/lib.contracts-spec";
|
|
383
|
-
var OWNERS4 = ["@examples.service-business-os"];
|
|
384
|
-
var IssueInvoiceContract = defineCommand4({
|
|
385
|
-
meta: {
|
|
386
|
-
key: "service.invoice.issue",
|
|
387
|
-
version: "1.0.0",
|
|
388
|
-
stability: "stable",
|
|
389
|
-
owners: [...OWNERS4],
|
|
390
|
-
tags: ["service-business-os", "invoice", "issue"],
|
|
391
|
-
description: "Issue an invoice for a job.",
|
|
392
|
-
goal: "Bill clients.",
|
|
393
|
-
context: "Billing."
|
|
394
|
-
},
|
|
395
|
-
io: {
|
|
396
|
-
input: IssueInvoiceInputModel,
|
|
397
|
-
output: InvoiceModel
|
|
398
|
-
},
|
|
399
|
-
policy: { auth: "user" },
|
|
400
|
-
acceptance: {
|
|
401
|
-
scenarios: [
|
|
402
|
-
{
|
|
403
|
-
key: "issue-invoice-happy-path",
|
|
404
|
-
given: ["Job is complete"],
|
|
405
|
-
when: ["User issues invoice"],
|
|
406
|
-
then: ["Invoice is created and sent"]
|
|
407
|
-
}
|
|
408
|
-
],
|
|
409
|
-
examples: [
|
|
410
|
-
{
|
|
411
|
-
key: "issue-standard",
|
|
412
|
-
input: {
|
|
413
|
-
jobId: "job-123",
|
|
414
|
-
dueDate: "2025-02-01",
|
|
415
|
-
items: [{ description: "Service", amount: 100 }]
|
|
416
|
-
},
|
|
417
|
-
output: { id: "inv-456", status: "issued", total: 100 }
|
|
418
|
-
}
|
|
419
|
-
]
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
// src/payment/payment.schema.ts
|
|
423
|
-
import { defineSchemaModel as defineSchemaModel6, ScalarTypeEnum as ScalarTypeEnum6 } from "@contractspec/lib.schema";
|
|
424
|
-
var PaymentModel = defineSchemaModel6({
|
|
425
|
-
name: "Payment",
|
|
426
|
-
description: "Payment applied to invoice",
|
|
427
|
-
fields: {
|
|
428
|
-
id: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
429
|
-
invoiceId: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
430
|
-
amount: { type: ScalarTypeEnum6.Float_unsecure(), isOptional: false },
|
|
431
|
-
currency: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
432
|
-
method: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
433
|
-
reference: { type: ScalarTypeEnum6.String_unsecure(), isOptional: true },
|
|
434
|
-
receivedAt: { type: ScalarTypeEnum6.DateTime(), isOptional: false }
|
|
317
|
+
method: { type: ScalarTypeEnum5.String_unsecure(), isOptional: false },
|
|
318
|
+
reference: { type: ScalarTypeEnum5.String_unsecure(), isOptional: true },
|
|
319
|
+
receivedAt: { type: ScalarTypeEnum5.DateTime(), isOptional: false }
|
|
435
320
|
}
|
|
436
321
|
});
|
|
437
|
-
var RecordPaymentInputModel =
|
|
322
|
+
var RecordPaymentInputModel = defineSchemaModel5({
|
|
438
323
|
name: "RecordPaymentInput",
|
|
439
324
|
description: "Input for recording a payment",
|
|
440
325
|
fields: {
|
|
441
|
-
invoiceId: { type:
|
|
442
|
-
amount: { type:
|
|
443
|
-
method: { type:
|
|
444
|
-
reference: { type:
|
|
445
|
-
receivedAt: { type:
|
|
326
|
+
invoiceId: { type: ScalarTypeEnum5.String_unsecure(), isOptional: false },
|
|
327
|
+
amount: { type: ScalarTypeEnum5.Float_unsecure(), isOptional: false },
|
|
328
|
+
method: { type: ScalarTypeEnum5.String_unsecure(), isOptional: false },
|
|
329
|
+
reference: { type: ScalarTypeEnum5.String_unsecure(), isOptional: true },
|
|
330
|
+
receivedAt: { type: ScalarTypeEnum5.DateTime(), isOptional: true }
|
|
446
331
|
}
|
|
447
332
|
});
|
|
448
333
|
|
|
449
334
|
// src/payment/payment.operations.ts
|
|
450
|
-
import { defineCommand as
|
|
451
|
-
var
|
|
452
|
-
var RecordPaymentContract =
|
|
335
|
+
import { defineCommand as defineCommand4 } from "@contractspec/lib.contracts-spec";
|
|
336
|
+
var OWNERS4 = ["@examples.service-business-os"];
|
|
337
|
+
var RecordPaymentContract = defineCommand4({
|
|
453
338
|
meta: {
|
|
454
339
|
key: "service.payment.record",
|
|
455
340
|
version: "1.0.0",
|
|
456
341
|
stability: "stable",
|
|
457
|
-
owners: [...
|
|
342
|
+
owners: [...OWNERS4],
|
|
458
343
|
tags: ["service-business-os", "payment", "record"],
|
|
459
344
|
description: "Record a payment.",
|
|
460
345
|
goal: "Track payments.",
|
|
@@ -650,6 +535,121 @@ var PaymentListPresentation = definePresentation({
|
|
|
650
535
|
}
|
|
651
536
|
});
|
|
652
537
|
|
|
538
|
+
// src/quote/quote.schema.ts
|
|
539
|
+
import { defineSchemaModel as defineSchemaModel6, ScalarTypeEnum as ScalarTypeEnum6 } from "@contractspec/lib.schema";
|
|
540
|
+
var QuoteModel = defineSchemaModel6({
|
|
541
|
+
name: "Quote",
|
|
542
|
+
description: "Quote/proposal",
|
|
543
|
+
fields: {
|
|
544
|
+
id: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
545
|
+
clientId: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
546
|
+
title: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
547
|
+
description: { type: ScalarTypeEnum6.String_unsecure(), isOptional: true },
|
|
548
|
+
amount: { type: ScalarTypeEnum6.Float_unsecure(), isOptional: false },
|
|
549
|
+
currency: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
550
|
+
status: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
551
|
+
validUntil: { type: ScalarTypeEnum6.DateTime(), isOptional: true },
|
|
552
|
+
createdAt: { type: ScalarTypeEnum6.DateTime(), isOptional: false }
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
var CreateQuoteInputModel = defineSchemaModel6({
|
|
556
|
+
name: "CreateQuoteInput",
|
|
557
|
+
description: "Input for creating a quote",
|
|
558
|
+
fields: {
|
|
559
|
+
clientId: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
560
|
+
title: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
561
|
+
description: { type: ScalarTypeEnum6.String_unsecure(), isOptional: true },
|
|
562
|
+
amount: { type: ScalarTypeEnum6.Float_unsecure(), isOptional: false },
|
|
563
|
+
currency: { type: ScalarTypeEnum6.String_unsecure(), isOptional: true },
|
|
564
|
+
validUntil: { type: ScalarTypeEnum6.DateTime(), isOptional: true },
|
|
565
|
+
orgId: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
566
|
+
ownerId: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false }
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
var AcceptQuoteInputModel = defineSchemaModel6({
|
|
570
|
+
name: "AcceptQuoteInput",
|
|
571
|
+
description: "Input for accepting a quote",
|
|
572
|
+
fields: {
|
|
573
|
+
quoteId: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
574
|
+
acceptedBy: { type: ScalarTypeEnum6.String_unsecure(), isOptional: false },
|
|
575
|
+
notes: { type: ScalarTypeEnum6.String_unsecure(), isOptional: true }
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
// src/quote/quote.operations.ts
|
|
580
|
+
import { defineCommand as defineCommand5 } from "@contractspec/lib.contracts-spec";
|
|
581
|
+
var OWNERS5 = ["@examples.service-business-os"];
|
|
582
|
+
var CreateQuoteContract = defineCommand5({
|
|
583
|
+
meta: {
|
|
584
|
+
key: "service.quote.create",
|
|
585
|
+
version: "1.0.0",
|
|
586
|
+
stability: "stable",
|
|
587
|
+
owners: [...OWNERS5],
|
|
588
|
+
tags: ["service-business-os", "quote", "create"],
|
|
589
|
+
description: "Create a quote/proposal.",
|
|
590
|
+
goal: "Quote clients.",
|
|
591
|
+
context: "Quote creation."
|
|
592
|
+
},
|
|
593
|
+
io: {
|
|
594
|
+
input: CreateQuoteInputModel,
|
|
595
|
+
output: QuoteModel
|
|
596
|
+
},
|
|
597
|
+
policy: { auth: "user" },
|
|
598
|
+
acceptance: {
|
|
599
|
+
scenarios: [
|
|
600
|
+
{
|
|
601
|
+
key: "create-quote-happy-path",
|
|
602
|
+
given: ["Client exists"],
|
|
603
|
+
when: ["User creates quote"],
|
|
604
|
+
then: ["Quote is created"]
|
|
605
|
+
}
|
|
606
|
+
],
|
|
607
|
+
examples: [
|
|
608
|
+
{
|
|
609
|
+
key: "create-proposal",
|
|
610
|
+
input: {
|
|
611
|
+
clientId: "client-123",
|
|
612
|
+
items: [{ description: "Project A", price: 5000 }]
|
|
613
|
+
},
|
|
614
|
+
output: { id: "quote-123", status: "draft", total: 5000 }
|
|
615
|
+
}
|
|
616
|
+
]
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
var AcceptQuoteContract = defineCommand5({
|
|
620
|
+
meta: {
|
|
621
|
+
key: "service.quote.accept",
|
|
622
|
+
version: "1.0.0",
|
|
623
|
+
stability: "stable",
|
|
624
|
+
owners: [...OWNERS5],
|
|
625
|
+
tags: ["service-business-os", "quote", "accept"],
|
|
626
|
+
description: "Accept a quote.",
|
|
627
|
+
goal: "Confirm quote.",
|
|
628
|
+
context: "Quote acceptance."
|
|
629
|
+
},
|
|
630
|
+
io: {
|
|
631
|
+
input: AcceptQuoteInputModel,
|
|
632
|
+
output: QuoteModel
|
|
633
|
+
},
|
|
634
|
+
policy: { auth: "user" },
|
|
635
|
+
acceptance: {
|
|
636
|
+
scenarios: [
|
|
637
|
+
{
|
|
638
|
+
key: "accept-quote-happy-path",
|
|
639
|
+
given: ["Quote is open"],
|
|
640
|
+
when: ["Client accepts quote"],
|
|
641
|
+
then: ["Quote status becomes ACCEPTED"]
|
|
642
|
+
}
|
|
643
|
+
],
|
|
644
|
+
examples: [
|
|
645
|
+
{
|
|
646
|
+
key: "client-accepts",
|
|
647
|
+
input: { quoteId: "quote-123", signature: "John Doe" },
|
|
648
|
+
output: { id: "quote-123", status: "accepted" }
|
|
649
|
+
}
|
|
650
|
+
]
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
653
|
// src/service.feature.ts
|
|
654
654
|
import { defineFeature } from "@contractspec/lib.contracts-spec";
|
|
655
655
|
var ServiceBusinessFeature = defineFeature({
|