@happyvertical/smrt-commerce 0.55.1 → 0.55.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +12 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +137 -113
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1293 -186
- package/dist/models/Contract.d.ts.map +1 -1
- package/dist/models/Customer.d.ts.map +1 -1
- package/dist/models/Vendor.d.ts.map +1 -1
- package/dist/recipes.d.ts +106 -0
- package/dist/recipes.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +507 -163
- package/package.json +11 -11
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-commerce",
|
|
6
|
-
"packageVersion": "0.55.
|
|
6
|
+
"packageVersion": "0.55.2",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
10
|
+
"manifest": "9ee172924cd3daf2fceb2cb1fbfa37be9880cf4a318400d481b7c4647b053778",
|
|
11
|
+
"packageJson": "c2025b16dea77787ec9de40de8489c690e8a7a6e50da8b645aa73759289d58f8",
|
|
12
|
+
"agents": "67b16f7ce35487a5fecaca37b52edbdb66c166b2d99672ce56f08ea3f4a6f3f3",
|
|
13
13
|
"moduleDoc:agents/invoice-quantity.md": "bc3b617d4fb8cc87511763b281283107557ba64795e64522193ef967a3715d32",
|
|
14
14
|
"moduleDoc:agents/commercial-ui.md": "e806954526ffcb41864a185a42bb5425e58db107aafc95c15152a30c49167f43",
|
|
15
15
|
"moduleDoc:agents/quote-ui.md": "514568e4e7815c47113627ac044a1f31a6933377b3f6c70f5d54b2508d94200c",
|
|
@@ -4033,95 +4033,109 @@
|
|
|
4033
4033
|
"name": "status",
|
|
4034
4034
|
"type": "text",
|
|
4035
4035
|
"required": false,
|
|
4036
|
-
"columnType": "TEXT"
|
|
4036
|
+
"columnType": "TEXT",
|
|
4037
|
+
"description": "Where the order or agreement stands, for example draft, sent, accepted or completed."
|
|
4037
4038
|
},
|
|
4038
4039
|
{
|
|
4039
4040
|
"name": "customerId",
|
|
4040
4041
|
"type": "foreignKey",
|
|
4041
4042
|
"required": false,
|
|
4042
4043
|
"related": "Customer",
|
|
4043
|
-
"columnType": "UUID"
|
|
4044
|
+
"columnType": "UUID",
|
|
4045
|
+
"description": "The customer a sales order or agreement is for."
|
|
4044
4046
|
},
|
|
4045
4047
|
{
|
|
4046
4048
|
"name": "vendorId",
|
|
4047
4049
|
"type": "foreignKey",
|
|
4048
4050
|
"required": false,
|
|
4049
4051
|
"related": "Vendor",
|
|
4050
|
-
"columnType": "UUID"
|
|
4052
|
+
"columnType": "UUID",
|
|
4053
|
+
"description": "The vendor a purchase order is placed with."
|
|
4051
4054
|
},
|
|
4052
4055
|
{
|
|
4053
4056
|
"name": "subtotal",
|
|
4054
4057
|
"type": "integer",
|
|
4055
4058
|
"required": false,
|
|
4056
4059
|
"columnType": "INTEGER",
|
|
4057
|
-
"default": 0
|
|
4060
|
+
"default": 0,
|
|
4061
|
+
"description": "The amount before tax."
|
|
4058
4062
|
},
|
|
4059
4063
|
{
|
|
4060
4064
|
"name": "taxAmount",
|
|
4061
4065
|
"type": "integer",
|
|
4062
4066
|
"required": false,
|
|
4063
4067
|
"columnType": "INTEGER",
|
|
4064
|
-
"default": 0
|
|
4068
|
+
"default": 0,
|
|
4069
|
+
"description": "The tax charged."
|
|
4065
4070
|
},
|
|
4066
4071
|
{
|
|
4067
4072
|
"name": "totalAmount",
|
|
4068
4073
|
"type": "integer",
|
|
4069
4074
|
"required": false,
|
|
4070
4075
|
"columnType": "INTEGER",
|
|
4071
|
-
"default": 0
|
|
4076
|
+
"default": 0,
|
|
4077
|
+
"description": "The full amount, tax included."
|
|
4072
4078
|
},
|
|
4073
4079
|
{
|
|
4074
4080
|
"name": "currency",
|
|
4075
4081
|
"type": "text",
|
|
4076
4082
|
"required": false,
|
|
4077
4083
|
"columnType": "TEXT",
|
|
4078
|
-
"default": "USD"
|
|
4084
|
+
"default": "USD",
|
|
4085
|
+
"description": "The currency of the amounts."
|
|
4079
4086
|
},
|
|
4080
4087
|
{
|
|
4081
4088
|
"name": "issueDate",
|
|
4082
4089
|
"type": "datetime",
|
|
4083
4090
|
"required": false,
|
|
4084
|
-
"columnType": "TIMESTAMP"
|
|
4091
|
+
"columnType": "TIMESTAMP",
|
|
4092
|
+
"description": "The date it was issued or placed."
|
|
4085
4093
|
},
|
|
4086
4094
|
{
|
|
4087
4095
|
"name": "dueDate",
|
|
4088
4096
|
"type": "datetime",
|
|
4089
4097
|
"required": false,
|
|
4090
|
-
"columnType": "TIMESTAMP"
|
|
4098
|
+
"columnType": "TIMESTAMP",
|
|
4099
|
+
"description": "The date payment or delivery is due."
|
|
4091
4100
|
},
|
|
4092
4101
|
{
|
|
4093
4102
|
"name": "expiryDate",
|
|
4094
4103
|
"type": "datetime",
|
|
4095
4104
|
"required": false,
|
|
4096
|
-
"columnType": "TIMESTAMP"
|
|
4105
|
+
"columnType": "TIMESTAMP",
|
|
4106
|
+
"description": "The last day the price or offer is good for."
|
|
4097
4107
|
},
|
|
4098
4108
|
{
|
|
4099
4109
|
"name": "reference",
|
|
4100
4110
|
"type": "text",
|
|
4101
4111
|
"required": false,
|
|
4102
4112
|
"columnType": "TEXT",
|
|
4103
|
-
"default": ""
|
|
4113
|
+
"default": "",
|
|
4114
|
+
"description": "Your own number or note for finding this later, such as a purchase order or quote number."
|
|
4104
4115
|
},
|
|
4105
4116
|
{
|
|
4106
4117
|
"name": "notes",
|
|
4107
4118
|
"type": "text",
|
|
4108
4119
|
"required": false,
|
|
4109
4120
|
"columnType": "TEXT",
|
|
4110
|
-
"default": ""
|
|
4121
|
+
"default": "",
|
|
4122
|
+
"description": "Anything worth remembering about this."
|
|
4111
4123
|
},
|
|
4112
4124
|
{
|
|
4113
4125
|
"name": "terms",
|
|
4114
4126
|
"type": "text",
|
|
4115
4127
|
"required": false,
|
|
4116
4128
|
"columnType": "TEXT",
|
|
4117
|
-
"default": ""
|
|
4129
|
+
"default": "",
|
|
4130
|
+
"description": "The conditions agreed, such as deposits, payment or delivery conditions."
|
|
4118
4131
|
},
|
|
4119
4132
|
{
|
|
4120
4133
|
"name": "channelId",
|
|
4121
4134
|
"type": "text",
|
|
4122
4135
|
"required": false,
|
|
4123
4136
|
"columnType": "TEXT",
|
|
4124
|
-
"default": ""
|
|
4137
|
+
"default": "",
|
|
4138
|
+
"description": "Where it came from, for example your shop, a marketplace or a phone call."
|
|
4125
4139
|
}
|
|
4126
4140
|
],
|
|
4127
4141
|
"relationships": [
|
|
@@ -4412,95 +4426,109 @@
|
|
|
4412
4426
|
"name": "status",
|
|
4413
4427
|
"type": "text",
|
|
4414
4428
|
"required": false,
|
|
4415
|
-
"columnType": "TEXT"
|
|
4429
|
+
"columnType": "TEXT",
|
|
4430
|
+
"description": "Where the order or agreement stands, for example draft, sent, accepted or completed."
|
|
4416
4431
|
},
|
|
4417
4432
|
{
|
|
4418
4433
|
"name": "customerId",
|
|
4419
4434
|
"type": "foreignKey",
|
|
4420
4435
|
"required": false,
|
|
4421
4436
|
"related": "Customer",
|
|
4422
|
-
"columnType": "UUID"
|
|
4437
|
+
"columnType": "UUID",
|
|
4438
|
+
"description": "The customer a sales order or agreement is for."
|
|
4423
4439
|
},
|
|
4424
4440
|
{
|
|
4425
4441
|
"name": "vendorId",
|
|
4426
4442
|
"type": "foreignKey",
|
|
4427
4443
|
"required": false,
|
|
4428
4444
|
"related": "Vendor",
|
|
4429
|
-
"columnType": "UUID"
|
|
4445
|
+
"columnType": "UUID",
|
|
4446
|
+
"description": "The vendor a purchase order is placed with."
|
|
4430
4447
|
},
|
|
4431
4448
|
{
|
|
4432
4449
|
"name": "subtotal",
|
|
4433
4450
|
"type": "integer",
|
|
4434
4451
|
"required": false,
|
|
4435
4452
|
"columnType": "INTEGER",
|
|
4436
|
-
"default": 0
|
|
4453
|
+
"default": 0,
|
|
4454
|
+
"description": "The amount before tax."
|
|
4437
4455
|
},
|
|
4438
4456
|
{
|
|
4439
4457
|
"name": "taxAmount",
|
|
4440
4458
|
"type": "integer",
|
|
4441
4459
|
"required": false,
|
|
4442
4460
|
"columnType": "INTEGER",
|
|
4443
|
-
"default": 0
|
|
4461
|
+
"default": 0,
|
|
4462
|
+
"description": "The tax charged."
|
|
4444
4463
|
},
|
|
4445
4464
|
{
|
|
4446
4465
|
"name": "totalAmount",
|
|
4447
4466
|
"type": "integer",
|
|
4448
4467
|
"required": false,
|
|
4449
4468
|
"columnType": "INTEGER",
|
|
4450
|
-
"default": 0
|
|
4469
|
+
"default": 0,
|
|
4470
|
+
"description": "The full amount, tax included."
|
|
4451
4471
|
},
|
|
4452
4472
|
{
|
|
4453
4473
|
"name": "currency",
|
|
4454
4474
|
"type": "text",
|
|
4455
4475
|
"required": false,
|
|
4456
4476
|
"columnType": "TEXT",
|
|
4457
|
-
"default": "USD"
|
|
4477
|
+
"default": "USD",
|
|
4478
|
+
"description": "The currency of the amounts."
|
|
4458
4479
|
},
|
|
4459
4480
|
{
|
|
4460
4481
|
"name": "issueDate",
|
|
4461
4482
|
"type": "datetime",
|
|
4462
4483
|
"required": false,
|
|
4463
|
-
"columnType": "TIMESTAMP"
|
|
4484
|
+
"columnType": "TIMESTAMP",
|
|
4485
|
+
"description": "The date it was issued or placed."
|
|
4464
4486
|
},
|
|
4465
4487
|
{
|
|
4466
4488
|
"name": "dueDate",
|
|
4467
4489
|
"type": "datetime",
|
|
4468
4490
|
"required": false,
|
|
4469
|
-
"columnType": "TIMESTAMP"
|
|
4491
|
+
"columnType": "TIMESTAMP",
|
|
4492
|
+
"description": "The date payment or delivery is due."
|
|
4470
4493
|
},
|
|
4471
4494
|
{
|
|
4472
4495
|
"name": "expiryDate",
|
|
4473
4496
|
"type": "datetime",
|
|
4474
4497
|
"required": false,
|
|
4475
|
-
"columnType": "TIMESTAMP"
|
|
4498
|
+
"columnType": "TIMESTAMP",
|
|
4499
|
+
"description": "The last day the price or offer is good for."
|
|
4476
4500
|
},
|
|
4477
4501
|
{
|
|
4478
4502
|
"name": "reference",
|
|
4479
4503
|
"type": "text",
|
|
4480
4504
|
"required": false,
|
|
4481
4505
|
"columnType": "TEXT",
|
|
4482
|
-
"default": ""
|
|
4506
|
+
"default": "",
|
|
4507
|
+
"description": "Your own number or note for finding this later, such as a purchase order or quote number."
|
|
4483
4508
|
},
|
|
4484
4509
|
{
|
|
4485
4510
|
"name": "notes",
|
|
4486
4511
|
"type": "text",
|
|
4487
4512
|
"required": false,
|
|
4488
4513
|
"columnType": "TEXT",
|
|
4489
|
-
"default": ""
|
|
4514
|
+
"default": "",
|
|
4515
|
+
"description": "Anything worth remembering about this."
|
|
4490
4516
|
},
|
|
4491
4517
|
{
|
|
4492
4518
|
"name": "terms",
|
|
4493
4519
|
"type": "text",
|
|
4494
4520
|
"required": false,
|
|
4495
4521
|
"columnType": "TEXT",
|
|
4496
|
-
"default": ""
|
|
4522
|
+
"default": "",
|
|
4523
|
+
"description": "The conditions agreed, such as deposits, payment or delivery conditions."
|
|
4497
4524
|
},
|
|
4498
4525
|
{
|
|
4499
4526
|
"name": "channelId",
|
|
4500
4527
|
"type": "text",
|
|
4501
4528
|
"required": false,
|
|
4502
4529
|
"columnType": "TEXT",
|
|
4503
|
-
"default": ""
|
|
4530
|
+
"default": "",
|
|
4531
|
+
"description": "Where it came from, for example your shop, a marketplace or a phone call."
|
|
4504
4532
|
}
|
|
4505
4533
|
],
|
|
4506
4534
|
"relationships": [
|
|
@@ -4853,95 +4881,109 @@
|
|
|
4853
4881
|
"name": "status",
|
|
4854
4882
|
"type": "text",
|
|
4855
4883
|
"required": false,
|
|
4856
|
-
"columnType": "TEXT"
|
|
4884
|
+
"columnType": "TEXT",
|
|
4885
|
+
"description": "Where the order or agreement stands, for example draft, sent, accepted or completed."
|
|
4857
4886
|
},
|
|
4858
4887
|
{
|
|
4859
4888
|
"name": "customerId",
|
|
4860
4889
|
"type": "foreignKey",
|
|
4861
4890
|
"required": false,
|
|
4862
4891
|
"related": "Customer",
|
|
4863
|
-
"columnType": "UUID"
|
|
4892
|
+
"columnType": "UUID",
|
|
4893
|
+
"description": "The customer a sales order or agreement is for."
|
|
4864
4894
|
},
|
|
4865
4895
|
{
|
|
4866
4896
|
"name": "vendorId",
|
|
4867
4897
|
"type": "foreignKey",
|
|
4868
4898
|
"required": false,
|
|
4869
4899
|
"related": "Vendor",
|
|
4870
|
-
"columnType": "UUID"
|
|
4900
|
+
"columnType": "UUID",
|
|
4901
|
+
"description": "The vendor a purchase order is placed with."
|
|
4871
4902
|
},
|
|
4872
4903
|
{
|
|
4873
4904
|
"name": "subtotal",
|
|
4874
4905
|
"type": "integer",
|
|
4875
4906
|
"required": false,
|
|
4876
4907
|
"columnType": "INTEGER",
|
|
4877
|
-
"default": 0
|
|
4908
|
+
"default": 0,
|
|
4909
|
+
"description": "The amount before tax."
|
|
4878
4910
|
},
|
|
4879
4911
|
{
|
|
4880
4912
|
"name": "taxAmount",
|
|
4881
4913
|
"type": "integer",
|
|
4882
4914
|
"required": false,
|
|
4883
4915
|
"columnType": "INTEGER",
|
|
4884
|
-
"default": 0
|
|
4916
|
+
"default": 0,
|
|
4917
|
+
"description": "The tax charged."
|
|
4885
4918
|
},
|
|
4886
4919
|
{
|
|
4887
4920
|
"name": "totalAmount",
|
|
4888
4921
|
"type": "integer",
|
|
4889
4922
|
"required": false,
|
|
4890
4923
|
"columnType": "INTEGER",
|
|
4891
|
-
"default": 0
|
|
4924
|
+
"default": 0,
|
|
4925
|
+
"description": "The full amount, tax included."
|
|
4892
4926
|
},
|
|
4893
4927
|
{
|
|
4894
4928
|
"name": "currency",
|
|
4895
4929
|
"type": "text",
|
|
4896
4930
|
"required": false,
|
|
4897
4931
|
"columnType": "TEXT",
|
|
4898
|
-
"default": "USD"
|
|
4932
|
+
"default": "USD",
|
|
4933
|
+
"description": "The currency of the amounts."
|
|
4899
4934
|
},
|
|
4900
4935
|
{
|
|
4901
4936
|
"name": "issueDate",
|
|
4902
4937
|
"type": "datetime",
|
|
4903
4938
|
"required": false,
|
|
4904
|
-
"columnType": "TIMESTAMP"
|
|
4939
|
+
"columnType": "TIMESTAMP",
|
|
4940
|
+
"description": "The date it was issued or placed."
|
|
4905
4941
|
},
|
|
4906
4942
|
{
|
|
4907
4943
|
"name": "dueDate",
|
|
4908
4944
|
"type": "datetime",
|
|
4909
4945
|
"required": false,
|
|
4910
|
-
"columnType": "TIMESTAMP"
|
|
4946
|
+
"columnType": "TIMESTAMP",
|
|
4947
|
+
"description": "The date payment or delivery is due."
|
|
4911
4948
|
},
|
|
4912
4949
|
{
|
|
4913
4950
|
"name": "expiryDate",
|
|
4914
4951
|
"type": "datetime",
|
|
4915
4952
|
"required": false,
|
|
4916
|
-
"columnType": "TIMESTAMP"
|
|
4953
|
+
"columnType": "TIMESTAMP",
|
|
4954
|
+
"description": "The last day the price or offer is good for."
|
|
4917
4955
|
},
|
|
4918
4956
|
{
|
|
4919
4957
|
"name": "reference",
|
|
4920
4958
|
"type": "text",
|
|
4921
4959
|
"required": false,
|
|
4922
4960
|
"columnType": "TEXT",
|
|
4923
|
-
"default": ""
|
|
4961
|
+
"default": "",
|
|
4962
|
+
"description": "Your own number or note for finding this later, such as a purchase order or quote number."
|
|
4924
4963
|
},
|
|
4925
4964
|
{
|
|
4926
4965
|
"name": "notes",
|
|
4927
4966
|
"type": "text",
|
|
4928
4967
|
"required": false,
|
|
4929
4968
|
"columnType": "TEXT",
|
|
4930
|
-
"default": ""
|
|
4969
|
+
"default": "",
|
|
4970
|
+
"description": "Anything worth remembering about this."
|
|
4931
4971
|
},
|
|
4932
4972
|
{
|
|
4933
4973
|
"name": "terms",
|
|
4934
4974
|
"type": "text",
|
|
4935
4975
|
"required": false,
|
|
4936
4976
|
"columnType": "TEXT",
|
|
4937
|
-
"default": ""
|
|
4977
|
+
"default": "",
|
|
4978
|
+
"description": "The conditions agreed, such as deposits, payment or delivery conditions."
|
|
4938
4979
|
},
|
|
4939
4980
|
{
|
|
4940
4981
|
"name": "channelId",
|
|
4941
4982
|
"type": "text",
|
|
4942
4983
|
"required": false,
|
|
4943
4984
|
"columnType": "TEXT",
|
|
4944
|
-
"default": ""
|
|
4985
|
+
"default": "",
|
|
4986
|
+
"description": "Where it came from, for example your shop, a marketplace or a phone call."
|
|
4945
4987
|
}
|
|
4946
4988
|
],
|
|
4947
4989
|
"relationships": [
|
|
@@ -5294,95 +5336,109 @@
|
|
|
5294
5336
|
"name": "status",
|
|
5295
5337
|
"type": "text",
|
|
5296
5338
|
"required": false,
|
|
5297
|
-
"columnType": "TEXT"
|
|
5339
|
+
"columnType": "TEXT",
|
|
5340
|
+
"description": "Where the order or agreement stands, for example draft, sent, accepted or completed."
|
|
5298
5341
|
},
|
|
5299
5342
|
{
|
|
5300
5343
|
"name": "customerId",
|
|
5301
5344
|
"type": "foreignKey",
|
|
5302
5345
|
"required": false,
|
|
5303
5346
|
"related": "Customer",
|
|
5304
|
-
"columnType": "UUID"
|
|
5347
|
+
"columnType": "UUID",
|
|
5348
|
+
"description": "The customer a sales order or agreement is for."
|
|
5305
5349
|
},
|
|
5306
5350
|
{
|
|
5307
5351
|
"name": "vendorId",
|
|
5308
5352
|
"type": "foreignKey",
|
|
5309
5353
|
"required": false,
|
|
5310
5354
|
"related": "Vendor",
|
|
5311
|
-
"columnType": "UUID"
|
|
5355
|
+
"columnType": "UUID",
|
|
5356
|
+
"description": "The vendor a purchase order is placed with."
|
|
5312
5357
|
},
|
|
5313
5358
|
{
|
|
5314
5359
|
"name": "subtotal",
|
|
5315
5360
|
"type": "integer",
|
|
5316
5361
|
"required": false,
|
|
5317
5362
|
"columnType": "INTEGER",
|
|
5318
|
-
"default": 0
|
|
5363
|
+
"default": 0,
|
|
5364
|
+
"description": "The amount before tax."
|
|
5319
5365
|
},
|
|
5320
5366
|
{
|
|
5321
5367
|
"name": "taxAmount",
|
|
5322
5368
|
"type": "integer",
|
|
5323
5369
|
"required": false,
|
|
5324
5370
|
"columnType": "INTEGER",
|
|
5325
|
-
"default": 0
|
|
5371
|
+
"default": 0,
|
|
5372
|
+
"description": "The tax charged."
|
|
5326
5373
|
},
|
|
5327
5374
|
{
|
|
5328
5375
|
"name": "totalAmount",
|
|
5329
5376
|
"type": "integer",
|
|
5330
5377
|
"required": false,
|
|
5331
5378
|
"columnType": "INTEGER",
|
|
5332
|
-
"default": 0
|
|
5379
|
+
"default": 0,
|
|
5380
|
+
"description": "The full amount, tax included."
|
|
5333
5381
|
},
|
|
5334
5382
|
{
|
|
5335
5383
|
"name": "currency",
|
|
5336
5384
|
"type": "text",
|
|
5337
5385
|
"required": false,
|
|
5338
5386
|
"columnType": "TEXT",
|
|
5339
|
-
"default": "USD"
|
|
5387
|
+
"default": "USD",
|
|
5388
|
+
"description": "The currency of the amounts."
|
|
5340
5389
|
},
|
|
5341
5390
|
{
|
|
5342
5391
|
"name": "issueDate",
|
|
5343
5392
|
"type": "datetime",
|
|
5344
5393
|
"required": false,
|
|
5345
|
-
"columnType": "TIMESTAMP"
|
|
5394
|
+
"columnType": "TIMESTAMP",
|
|
5395
|
+
"description": "The date it was issued or placed."
|
|
5346
5396
|
},
|
|
5347
5397
|
{
|
|
5348
5398
|
"name": "dueDate",
|
|
5349
5399
|
"type": "datetime",
|
|
5350
5400
|
"required": false,
|
|
5351
|
-
"columnType": "TIMESTAMP"
|
|
5401
|
+
"columnType": "TIMESTAMP",
|
|
5402
|
+
"description": "The date payment or delivery is due."
|
|
5352
5403
|
},
|
|
5353
5404
|
{
|
|
5354
5405
|
"name": "expiryDate",
|
|
5355
5406
|
"type": "datetime",
|
|
5356
5407
|
"required": false,
|
|
5357
|
-
"columnType": "TIMESTAMP"
|
|
5408
|
+
"columnType": "TIMESTAMP",
|
|
5409
|
+
"description": "The last day the price or offer is good for."
|
|
5358
5410
|
},
|
|
5359
5411
|
{
|
|
5360
5412
|
"name": "reference",
|
|
5361
5413
|
"type": "text",
|
|
5362
5414
|
"required": false,
|
|
5363
5415
|
"columnType": "TEXT",
|
|
5364
|
-
"default": ""
|
|
5416
|
+
"default": "",
|
|
5417
|
+
"description": "Your own number or note for finding this later, such as a purchase order or quote number."
|
|
5365
5418
|
},
|
|
5366
5419
|
{
|
|
5367
5420
|
"name": "notes",
|
|
5368
5421
|
"type": "text",
|
|
5369
5422
|
"required": false,
|
|
5370
5423
|
"columnType": "TEXT",
|
|
5371
|
-
"default": ""
|
|
5424
|
+
"default": "",
|
|
5425
|
+
"description": "Anything worth remembering about this."
|
|
5372
5426
|
},
|
|
5373
5427
|
{
|
|
5374
5428
|
"name": "terms",
|
|
5375
5429
|
"type": "text",
|
|
5376
5430
|
"required": false,
|
|
5377
5431
|
"columnType": "TEXT",
|
|
5378
|
-
"default": ""
|
|
5432
|
+
"default": "",
|
|
5433
|
+
"description": "The conditions agreed, such as deposits, payment or delivery conditions."
|
|
5379
5434
|
},
|
|
5380
5435
|
{
|
|
5381
5436
|
"name": "channelId",
|
|
5382
5437
|
"type": "text",
|
|
5383
5438
|
"required": false,
|
|
5384
5439
|
"columnType": "TEXT",
|
|
5385
|
-
"default": ""
|
|
5440
|
+
"default": "",
|
|
5441
|
+
"description": "Where it came from, for example your shop, a marketplace or a phone call."
|
|
5386
5442
|
}
|
|
5387
5443
|
],
|
|
5388
5444
|
"relationships": [
|
|
@@ -5735,95 +5791,109 @@
|
|
|
5735
5791
|
"name": "status",
|
|
5736
5792
|
"type": "text",
|
|
5737
5793
|
"required": false,
|
|
5738
|
-
"columnType": "TEXT"
|
|
5794
|
+
"columnType": "TEXT",
|
|
5795
|
+
"description": "Where the order or agreement stands, for example draft, sent, accepted or completed."
|
|
5739
5796
|
},
|
|
5740
5797
|
{
|
|
5741
5798
|
"name": "customerId",
|
|
5742
5799
|
"type": "foreignKey",
|
|
5743
5800
|
"required": false,
|
|
5744
5801
|
"related": "Customer",
|
|
5745
|
-
"columnType": "UUID"
|
|
5802
|
+
"columnType": "UUID",
|
|
5803
|
+
"description": "The customer a sales order or agreement is for."
|
|
5746
5804
|
},
|
|
5747
5805
|
{
|
|
5748
5806
|
"name": "vendorId",
|
|
5749
5807
|
"type": "foreignKey",
|
|
5750
5808
|
"required": false,
|
|
5751
5809
|
"related": "Vendor",
|
|
5752
|
-
"columnType": "UUID"
|
|
5810
|
+
"columnType": "UUID",
|
|
5811
|
+
"description": "The vendor a purchase order is placed with."
|
|
5753
5812
|
},
|
|
5754
5813
|
{
|
|
5755
5814
|
"name": "subtotal",
|
|
5756
5815
|
"type": "integer",
|
|
5757
5816
|
"required": false,
|
|
5758
5817
|
"columnType": "INTEGER",
|
|
5759
|
-
"default": 0
|
|
5818
|
+
"default": 0,
|
|
5819
|
+
"description": "The amount before tax."
|
|
5760
5820
|
},
|
|
5761
5821
|
{
|
|
5762
5822
|
"name": "taxAmount",
|
|
5763
5823
|
"type": "integer",
|
|
5764
5824
|
"required": false,
|
|
5765
5825
|
"columnType": "INTEGER",
|
|
5766
|
-
"default": 0
|
|
5826
|
+
"default": 0,
|
|
5827
|
+
"description": "The tax charged."
|
|
5767
5828
|
},
|
|
5768
5829
|
{
|
|
5769
5830
|
"name": "totalAmount",
|
|
5770
5831
|
"type": "integer",
|
|
5771
5832
|
"required": false,
|
|
5772
5833
|
"columnType": "INTEGER",
|
|
5773
|
-
"default": 0
|
|
5834
|
+
"default": 0,
|
|
5835
|
+
"description": "The full amount, tax included."
|
|
5774
5836
|
},
|
|
5775
5837
|
{
|
|
5776
5838
|
"name": "currency",
|
|
5777
5839
|
"type": "text",
|
|
5778
5840
|
"required": false,
|
|
5779
5841
|
"columnType": "TEXT",
|
|
5780
|
-
"default": "USD"
|
|
5842
|
+
"default": "USD",
|
|
5843
|
+
"description": "The currency of the amounts."
|
|
5781
5844
|
},
|
|
5782
5845
|
{
|
|
5783
5846
|
"name": "issueDate",
|
|
5784
5847
|
"type": "datetime",
|
|
5785
5848
|
"required": false,
|
|
5786
|
-
"columnType": "TIMESTAMP"
|
|
5849
|
+
"columnType": "TIMESTAMP",
|
|
5850
|
+
"description": "The date it was issued or placed."
|
|
5787
5851
|
},
|
|
5788
5852
|
{
|
|
5789
5853
|
"name": "dueDate",
|
|
5790
5854
|
"type": "datetime",
|
|
5791
5855
|
"required": false,
|
|
5792
|
-
"columnType": "TIMESTAMP"
|
|
5856
|
+
"columnType": "TIMESTAMP",
|
|
5857
|
+
"description": "The date payment or delivery is due."
|
|
5793
5858
|
},
|
|
5794
5859
|
{
|
|
5795
5860
|
"name": "expiryDate",
|
|
5796
5861
|
"type": "datetime",
|
|
5797
5862
|
"required": false,
|
|
5798
|
-
"columnType": "TIMESTAMP"
|
|
5863
|
+
"columnType": "TIMESTAMP",
|
|
5864
|
+
"description": "The last day the price or offer is good for."
|
|
5799
5865
|
},
|
|
5800
5866
|
{
|
|
5801
5867
|
"name": "reference",
|
|
5802
5868
|
"type": "text",
|
|
5803
5869
|
"required": false,
|
|
5804
5870
|
"columnType": "TEXT",
|
|
5805
|
-
"default": ""
|
|
5871
|
+
"default": "",
|
|
5872
|
+
"description": "Your own number or note for finding this later, such as a purchase order or quote number."
|
|
5806
5873
|
},
|
|
5807
5874
|
{
|
|
5808
5875
|
"name": "notes",
|
|
5809
5876
|
"type": "text",
|
|
5810
5877
|
"required": false,
|
|
5811
5878
|
"columnType": "TEXT",
|
|
5812
|
-
"default": ""
|
|
5879
|
+
"default": "",
|
|
5880
|
+
"description": "Anything worth remembering about this."
|
|
5813
5881
|
},
|
|
5814
5882
|
{
|
|
5815
5883
|
"name": "terms",
|
|
5816
5884
|
"type": "text",
|
|
5817
5885
|
"required": false,
|
|
5818
5886
|
"columnType": "TEXT",
|
|
5819
|
-
"default": ""
|
|
5887
|
+
"default": "",
|
|
5888
|
+
"description": "The conditions agreed, such as deposits, payment or delivery conditions."
|
|
5820
5889
|
},
|
|
5821
5890
|
{
|
|
5822
5891
|
"name": "channelId",
|
|
5823
5892
|
"type": "text",
|
|
5824
5893
|
"required": false,
|
|
5825
5894
|
"columnType": "TEXT",
|
|
5826
|
-
"default": ""
|
|
5895
|
+
"default": "",
|
|
5896
|
+
"description": "Where it came from, for example your shop, a marketplace or a phone call."
|
|
5827
5897
|
}
|
|
5828
5898
|
],
|
|
5829
5899
|
"relationships": [
|
|
@@ -6176,95 +6246,109 @@
|
|
|
6176
6246
|
"name": "status",
|
|
6177
6247
|
"type": "text",
|
|
6178
6248
|
"required": false,
|
|
6179
|
-
"columnType": "TEXT"
|
|
6249
|
+
"columnType": "TEXT",
|
|
6250
|
+
"description": "Where the order or agreement stands, for example draft, sent, accepted or completed."
|
|
6180
6251
|
},
|
|
6181
6252
|
{
|
|
6182
6253
|
"name": "customerId",
|
|
6183
6254
|
"type": "foreignKey",
|
|
6184
6255
|
"required": false,
|
|
6185
6256
|
"related": "Customer",
|
|
6186
|
-
"columnType": "UUID"
|
|
6257
|
+
"columnType": "UUID",
|
|
6258
|
+
"description": "The customer a sales order or agreement is for."
|
|
6187
6259
|
},
|
|
6188
6260
|
{
|
|
6189
6261
|
"name": "vendorId",
|
|
6190
6262
|
"type": "foreignKey",
|
|
6191
6263
|
"required": false,
|
|
6192
6264
|
"related": "Vendor",
|
|
6193
|
-
"columnType": "UUID"
|
|
6265
|
+
"columnType": "UUID",
|
|
6266
|
+
"description": "The vendor a purchase order is placed with."
|
|
6194
6267
|
},
|
|
6195
6268
|
{
|
|
6196
6269
|
"name": "subtotal",
|
|
6197
6270
|
"type": "integer",
|
|
6198
6271
|
"required": false,
|
|
6199
6272
|
"columnType": "INTEGER",
|
|
6200
|
-
"default": 0
|
|
6273
|
+
"default": 0,
|
|
6274
|
+
"description": "The amount before tax."
|
|
6201
6275
|
},
|
|
6202
6276
|
{
|
|
6203
6277
|
"name": "taxAmount",
|
|
6204
6278
|
"type": "integer",
|
|
6205
6279
|
"required": false,
|
|
6206
6280
|
"columnType": "INTEGER",
|
|
6207
|
-
"default": 0
|
|
6281
|
+
"default": 0,
|
|
6282
|
+
"description": "The tax charged."
|
|
6208
6283
|
},
|
|
6209
6284
|
{
|
|
6210
6285
|
"name": "totalAmount",
|
|
6211
6286
|
"type": "integer",
|
|
6212
6287
|
"required": false,
|
|
6213
6288
|
"columnType": "INTEGER",
|
|
6214
|
-
"default": 0
|
|
6289
|
+
"default": 0,
|
|
6290
|
+
"description": "The full amount, tax included."
|
|
6215
6291
|
},
|
|
6216
6292
|
{
|
|
6217
6293
|
"name": "currency",
|
|
6218
6294
|
"type": "text",
|
|
6219
6295
|
"required": false,
|
|
6220
6296
|
"columnType": "TEXT",
|
|
6221
|
-
"default": "USD"
|
|
6297
|
+
"default": "USD",
|
|
6298
|
+
"description": "The currency of the amounts."
|
|
6222
6299
|
},
|
|
6223
6300
|
{
|
|
6224
6301
|
"name": "issueDate",
|
|
6225
6302
|
"type": "datetime",
|
|
6226
6303
|
"required": false,
|
|
6227
|
-
"columnType": "TIMESTAMP"
|
|
6304
|
+
"columnType": "TIMESTAMP",
|
|
6305
|
+
"description": "The date it was issued or placed."
|
|
6228
6306
|
},
|
|
6229
6307
|
{
|
|
6230
6308
|
"name": "dueDate",
|
|
6231
6309
|
"type": "datetime",
|
|
6232
6310
|
"required": false,
|
|
6233
|
-
"columnType": "TIMESTAMP"
|
|
6311
|
+
"columnType": "TIMESTAMP",
|
|
6312
|
+
"description": "The date payment or delivery is due."
|
|
6234
6313
|
},
|
|
6235
6314
|
{
|
|
6236
6315
|
"name": "expiryDate",
|
|
6237
6316
|
"type": "datetime",
|
|
6238
6317
|
"required": false,
|
|
6239
|
-
"columnType": "TIMESTAMP"
|
|
6318
|
+
"columnType": "TIMESTAMP",
|
|
6319
|
+
"description": "The last day the price or offer is good for."
|
|
6240
6320
|
},
|
|
6241
6321
|
{
|
|
6242
6322
|
"name": "reference",
|
|
6243
6323
|
"type": "text",
|
|
6244
6324
|
"required": false,
|
|
6245
6325
|
"columnType": "TEXT",
|
|
6246
|
-
"default": ""
|
|
6326
|
+
"default": "",
|
|
6327
|
+
"description": "Your own number or note for finding this later, such as a purchase order or quote number."
|
|
6247
6328
|
},
|
|
6248
6329
|
{
|
|
6249
6330
|
"name": "notes",
|
|
6250
6331
|
"type": "text",
|
|
6251
6332
|
"required": false,
|
|
6252
6333
|
"columnType": "TEXT",
|
|
6253
|
-
"default": ""
|
|
6334
|
+
"default": "",
|
|
6335
|
+
"description": "Anything worth remembering about this."
|
|
6254
6336
|
},
|
|
6255
6337
|
{
|
|
6256
6338
|
"name": "terms",
|
|
6257
6339
|
"type": "text",
|
|
6258
6340
|
"required": false,
|
|
6259
6341
|
"columnType": "TEXT",
|
|
6260
|
-
"default": ""
|
|
6342
|
+
"default": "",
|
|
6343
|
+
"description": "The conditions agreed, such as deposits, payment or delivery conditions."
|
|
6261
6344
|
},
|
|
6262
6345
|
{
|
|
6263
6346
|
"name": "channelId",
|
|
6264
6347
|
"type": "text",
|
|
6265
6348
|
"required": false,
|
|
6266
6349
|
"columnType": "TEXT",
|
|
6267
|
-
"default": ""
|
|
6350
|
+
"default": "",
|
|
6351
|
+
"description": "Where it came from, for example your shop, a marketplace or a phone call."
|
|
6268
6352
|
}
|
|
6269
6353
|
],
|
|
6270
6354
|
"relationships": [
|
|
@@ -6617,95 +6701,109 @@
|
|
|
6617
6701
|
"name": "status",
|
|
6618
6702
|
"type": "text",
|
|
6619
6703
|
"required": false,
|
|
6620
|
-
"columnType": "TEXT"
|
|
6704
|
+
"columnType": "TEXT",
|
|
6705
|
+
"description": "Where the order or agreement stands, for example draft, sent, accepted or completed."
|
|
6621
6706
|
},
|
|
6622
6707
|
{
|
|
6623
6708
|
"name": "customerId",
|
|
6624
6709
|
"type": "foreignKey",
|
|
6625
6710
|
"required": false,
|
|
6626
6711
|
"related": "Customer",
|
|
6627
|
-
"columnType": "UUID"
|
|
6712
|
+
"columnType": "UUID",
|
|
6713
|
+
"description": "The customer a sales order or agreement is for."
|
|
6628
6714
|
},
|
|
6629
6715
|
{
|
|
6630
6716
|
"name": "vendorId",
|
|
6631
6717
|
"type": "foreignKey",
|
|
6632
6718
|
"required": false,
|
|
6633
6719
|
"related": "Vendor",
|
|
6634
|
-
"columnType": "UUID"
|
|
6720
|
+
"columnType": "UUID",
|
|
6721
|
+
"description": "The vendor a purchase order is placed with."
|
|
6635
6722
|
},
|
|
6636
6723
|
{
|
|
6637
6724
|
"name": "subtotal",
|
|
6638
6725
|
"type": "integer",
|
|
6639
6726
|
"required": false,
|
|
6640
6727
|
"columnType": "INTEGER",
|
|
6641
|
-
"default": 0
|
|
6728
|
+
"default": 0,
|
|
6729
|
+
"description": "The amount before tax."
|
|
6642
6730
|
},
|
|
6643
6731
|
{
|
|
6644
6732
|
"name": "taxAmount",
|
|
6645
6733
|
"type": "integer",
|
|
6646
6734
|
"required": false,
|
|
6647
6735
|
"columnType": "INTEGER",
|
|
6648
|
-
"default": 0
|
|
6736
|
+
"default": 0,
|
|
6737
|
+
"description": "The tax charged."
|
|
6649
6738
|
},
|
|
6650
6739
|
{
|
|
6651
6740
|
"name": "totalAmount",
|
|
6652
6741
|
"type": "integer",
|
|
6653
6742
|
"required": false,
|
|
6654
6743
|
"columnType": "INTEGER",
|
|
6655
|
-
"default": 0
|
|
6744
|
+
"default": 0,
|
|
6745
|
+
"description": "The full amount, tax included."
|
|
6656
6746
|
},
|
|
6657
6747
|
{
|
|
6658
6748
|
"name": "currency",
|
|
6659
6749
|
"type": "text",
|
|
6660
6750
|
"required": false,
|
|
6661
6751
|
"columnType": "TEXT",
|
|
6662
|
-
"default": "USD"
|
|
6752
|
+
"default": "USD",
|
|
6753
|
+
"description": "The currency of the amounts."
|
|
6663
6754
|
},
|
|
6664
6755
|
{
|
|
6665
6756
|
"name": "issueDate",
|
|
6666
6757
|
"type": "datetime",
|
|
6667
6758
|
"required": false,
|
|
6668
|
-
"columnType": "TIMESTAMP"
|
|
6759
|
+
"columnType": "TIMESTAMP",
|
|
6760
|
+
"description": "The date it was issued or placed."
|
|
6669
6761
|
},
|
|
6670
6762
|
{
|
|
6671
6763
|
"name": "dueDate",
|
|
6672
6764
|
"type": "datetime",
|
|
6673
6765
|
"required": false,
|
|
6674
|
-
"columnType": "TIMESTAMP"
|
|
6766
|
+
"columnType": "TIMESTAMP",
|
|
6767
|
+
"description": "The date payment or delivery is due."
|
|
6675
6768
|
},
|
|
6676
6769
|
{
|
|
6677
6770
|
"name": "expiryDate",
|
|
6678
6771
|
"type": "datetime",
|
|
6679
6772
|
"required": false,
|
|
6680
|
-
"columnType": "TIMESTAMP"
|
|
6773
|
+
"columnType": "TIMESTAMP",
|
|
6774
|
+
"description": "The last day the price or offer is good for."
|
|
6681
6775
|
},
|
|
6682
6776
|
{
|
|
6683
6777
|
"name": "reference",
|
|
6684
6778
|
"type": "text",
|
|
6685
6779
|
"required": false,
|
|
6686
6780
|
"columnType": "TEXT",
|
|
6687
|
-
"default": ""
|
|
6781
|
+
"default": "",
|
|
6782
|
+
"description": "Your own number or note for finding this later, such as a purchase order or quote number."
|
|
6688
6783
|
},
|
|
6689
6784
|
{
|
|
6690
6785
|
"name": "notes",
|
|
6691
6786
|
"type": "text",
|
|
6692
6787
|
"required": false,
|
|
6693
6788
|
"columnType": "TEXT",
|
|
6694
|
-
"default": ""
|
|
6789
|
+
"default": "",
|
|
6790
|
+
"description": "Anything worth remembering about this."
|
|
6695
6791
|
},
|
|
6696
6792
|
{
|
|
6697
6793
|
"name": "terms",
|
|
6698
6794
|
"type": "text",
|
|
6699
6795
|
"required": false,
|
|
6700
6796
|
"columnType": "TEXT",
|
|
6701
|
-
"default": ""
|
|
6797
|
+
"default": "",
|
|
6798
|
+
"description": "The conditions agreed, such as deposits, payment or delivery conditions."
|
|
6702
6799
|
},
|
|
6703
6800
|
{
|
|
6704
6801
|
"name": "channelId",
|
|
6705
6802
|
"type": "text",
|
|
6706
6803
|
"required": false,
|
|
6707
6804
|
"columnType": "TEXT",
|
|
6708
|
-
"default": ""
|
|
6805
|
+
"default": "",
|
|
6806
|
+
"description": "Where it came from, for example your shop, a marketplace or a phone call."
|
|
6709
6807
|
}
|
|
6710
6808
|
],
|
|
6711
6809
|
"relationships": [
|
|
@@ -7058,95 +7156,109 @@
|
|
|
7058
7156
|
"name": "status",
|
|
7059
7157
|
"type": "text",
|
|
7060
7158
|
"required": false,
|
|
7061
|
-
"columnType": "TEXT"
|
|
7159
|
+
"columnType": "TEXT",
|
|
7160
|
+
"description": "Where the order or agreement stands, for example draft, sent, accepted or completed."
|
|
7062
7161
|
},
|
|
7063
7162
|
{
|
|
7064
7163
|
"name": "customerId",
|
|
7065
7164
|
"type": "foreignKey",
|
|
7066
7165
|
"required": false,
|
|
7067
7166
|
"related": "Customer",
|
|
7068
|
-
"columnType": "UUID"
|
|
7167
|
+
"columnType": "UUID",
|
|
7168
|
+
"description": "The customer a sales order or agreement is for."
|
|
7069
7169
|
},
|
|
7070
7170
|
{
|
|
7071
7171
|
"name": "vendorId",
|
|
7072
7172
|
"type": "foreignKey",
|
|
7073
7173
|
"required": false,
|
|
7074
7174
|
"related": "Vendor",
|
|
7075
|
-
"columnType": "UUID"
|
|
7175
|
+
"columnType": "UUID",
|
|
7176
|
+
"description": "The vendor a purchase order is placed with."
|
|
7076
7177
|
},
|
|
7077
7178
|
{
|
|
7078
7179
|
"name": "subtotal",
|
|
7079
7180
|
"type": "integer",
|
|
7080
7181
|
"required": false,
|
|
7081
7182
|
"columnType": "INTEGER",
|
|
7082
|
-
"default": 0
|
|
7183
|
+
"default": 0,
|
|
7184
|
+
"description": "The amount before tax."
|
|
7083
7185
|
},
|
|
7084
7186
|
{
|
|
7085
7187
|
"name": "taxAmount",
|
|
7086
7188
|
"type": "integer",
|
|
7087
7189
|
"required": false,
|
|
7088
7190
|
"columnType": "INTEGER",
|
|
7089
|
-
"default": 0
|
|
7191
|
+
"default": 0,
|
|
7192
|
+
"description": "The tax charged."
|
|
7090
7193
|
},
|
|
7091
7194
|
{
|
|
7092
7195
|
"name": "totalAmount",
|
|
7093
7196
|
"type": "integer",
|
|
7094
7197
|
"required": false,
|
|
7095
7198
|
"columnType": "INTEGER",
|
|
7096
|
-
"default": 0
|
|
7199
|
+
"default": 0,
|
|
7200
|
+
"description": "The full amount, tax included."
|
|
7097
7201
|
},
|
|
7098
7202
|
{
|
|
7099
7203
|
"name": "currency",
|
|
7100
7204
|
"type": "text",
|
|
7101
7205
|
"required": false,
|
|
7102
7206
|
"columnType": "TEXT",
|
|
7103
|
-
"default": "USD"
|
|
7207
|
+
"default": "USD",
|
|
7208
|
+
"description": "The currency of the amounts."
|
|
7104
7209
|
},
|
|
7105
7210
|
{
|
|
7106
7211
|
"name": "issueDate",
|
|
7107
7212
|
"type": "datetime",
|
|
7108
7213
|
"required": false,
|
|
7109
|
-
"columnType": "TIMESTAMP"
|
|
7214
|
+
"columnType": "TIMESTAMP",
|
|
7215
|
+
"description": "The date it was issued or placed."
|
|
7110
7216
|
},
|
|
7111
7217
|
{
|
|
7112
7218
|
"name": "dueDate",
|
|
7113
7219
|
"type": "datetime",
|
|
7114
7220
|
"required": false,
|
|
7115
|
-
"columnType": "TIMESTAMP"
|
|
7221
|
+
"columnType": "TIMESTAMP",
|
|
7222
|
+
"description": "The date payment or delivery is due."
|
|
7116
7223
|
},
|
|
7117
7224
|
{
|
|
7118
7225
|
"name": "expiryDate",
|
|
7119
7226
|
"type": "datetime",
|
|
7120
7227
|
"required": false,
|
|
7121
|
-
"columnType": "TIMESTAMP"
|
|
7228
|
+
"columnType": "TIMESTAMP",
|
|
7229
|
+
"description": "The last day the price or offer is good for."
|
|
7122
7230
|
},
|
|
7123
7231
|
{
|
|
7124
7232
|
"name": "reference",
|
|
7125
7233
|
"type": "text",
|
|
7126
7234
|
"required": false,
|
|
7127
7235
|
"columnType": "TEXT",
|
|
7128
|
-
"default": ""
|
|
7236
|
+
"default": "",
|
|
7237
|
+
"description": "Your own number or note for finding this later, such as a purchase order or quote number."
|
|
7129
7238
|
},
|
|
7130
7239
|
{
|
|
7131
7240
|
"name": "notes",
|
|
7132
7241
|
"type": "text",
|
|
7133
7242
|
"required": false,
|
|
7134
7243
|
"columnType": "TEXT",
|
|
7135
|
-
"default": ""
|
|
7244
|
+
"default": "",
|
|
7245
|
+
"description": "Anything worth remembering about this."
|
|
7136
7246
|
},
|
|
7137
7247
|
{
|
|
7138
7248
|
"name": "terms",
|
|
7139
7249
|
"type": "text",
|
|
7140
7250
|
"required": false,
|
|
7141
7251
|
"columnType": "TEXT",
|
|
7142
|
-
"default": ""
|
|
7252
|
+
"default": "",
|
|
7253
|
+
"description": "The conditions agreed, such as deposits, payment or delivery conditions."
|
|
7143
7254
|
},
|
|
7144
7255
|
{
|
|
7145
7256
|
"name": "channelId",
|
|
7146
7257
|
"type": "text",
|
|
7147
7258
|
"required": false,
|
|
7148
7259
|
"columnType": "TEXT",
|
|
7149
|
-
"default": ""
|
|
7260
|
+
"default": "",
|
|
7261
|
+
"description": "Where it came from, for example your shop, a marketplace or a phone call."
|
|
7150
7262
|
},
|
|
7151
7263
|
{
|
|
7152
7264
|
"name": "productId",
|
|
@@ -7511,95 +7623,109 @@
|
|
|
7511
7623
|
"name": "status",
|
|
7512
7624
|
"type": "text",
|
|
7513
7625
|
"required": false,
|
|
7514
|
-
"columnType": "TEXT"
|
|
7626
|
+
"columnType": "TEXT",
|
|
7627
|
+
"description": "Where the order or agreement stands, for example draft, sent, accepted or completed."
|
|
7515
7628
|
},
|
|
7516
7629
|
{
|
|
7517
7630
|
"name": "customerId",
|
|
7518
7631
|
"type": "foreignKey",
|
|
7519
7632
|
"required": false,
|
|
7520
7633
|
"related": "Customer",
|
|
7521
|
-
"columnType": "UUID"
|
|
7634
|
+
"columnType": "UUID",
|
|
7635
|
+
"description": "The customer a sales order or agreement is for."
|
|
7522
7636
|
},
|
|
7523
7637
|
{
|
|
7524
7638
|
"name": "vendorId",
|
|
7525
7639
|
"type": "foreignKey",
|
|
7526
7640
|
"required": false,
|
|
7527
7641
|
"related": "Vendor",
|
|
7528
|
-
"columnType": "UUID"
|
|
7642
|
+
"columnType": "UUID",
|
|
7643
|
+
"description": "The vendor a purchase order is placed with."
|
|
7529
7644
|
},
|
|
7530
7645
|
{
|
|
7531
7646
|
"name": "subtotal",
|
|
7532
7647
|
"type": "integer",
|
|
7533
7648
|
"required": false,
|
|
7534
7649
|
"columnType": "INTEGER",
|
|
7535
|
-
"default": 0
|
|
7650
|
+
"default": 0,
|
|
7651
|
+
"description": "The amount before tax."
|
|
7536
7652
|
},
|
|
7537
7653
|
{
|
|
7538
7654
|
"name": "taxAmount",
|
|
7539
7655
|
"type": "integer",
|
|
7540
7656
|
"required": false,
|
|
7541
7657
|
"columnType": "INTEGER",
|
|
7542
|
-
"default": 0
|
|
7658
|
+
"default": 0,
|
|
7659
|
+
"description": "The tax charged."
|
|
7543
7660
|
},
|
|
7544
7661
|
{
|
|
7545
7662
|
"name": "totalAmount",
|
|
7546
7663
|
"type": "integer",
|
|
7547
7664
|
"required": false,
|
|
7548
7665
|
"columnType": "INTEGER",
|
|
7549
|
-
"default": 0
|
|
7666
|
+
"default": 0,
|
|
7667
|
+
"description": "The full amount, tax included."
|
|
7550
7668
|
},
|
|
7551
7669
|
{
|
|
7552
7670
|
"name": "currency",
|
|
7553
7671
|
"type": "text",
|
|
7554
7672
|
"required": false,
|
|
7555
7673
|
"columnType": "TEXT",
|
|
7556
|
-
"default": "USD"
|
|
7674
|
+
"default": "USD",
|
|
7675
|
+
"description": "The currency of the amounts."
|
|
7557
7676
|
},
|
|
7558
7677
|
{
|
|
7559
7678
|
"name": "issueDate",
|
|
7560
7679
|
"type": "datetime",
|
|
7561
7680
|
"required": false,
|
|
7562
|
-
"columnType": "TIMESTAMP"
|
|
7681
|
+
"columnType": "TIMESTAMP",
|
|
7682
|
+
"description": "The date it was issued or placed."
|
|
7563
7683
|
},
|
|
7564
7684
|
{
|
|
7565
7685
|
"name": "dueDate",
|
|
7566
7686
|
"type": "datetime",
|
|
7567
7687
|
"required": false,
|
|
7568
|
-
"columnType": "TIMESTAMP"
|
|
7688
|
+
"columnType": "TIMESTAMP",
|
|
7689
|
+
"description": "The date payment or delivery is due."
|
|
7569
7690
|
},
|
|
7570
7691
|
{
|
|
7571
7692
|
"name": "expiryDate",
|
|
7572
7693
|
"type": "datetime",
|
|
7573
7694
|
"required": false,
|
|
7574
|
-
"columnType": "TIMESTAMP"
|
|
7695
|
+
"columnType": "TIMESTAMP",
|
|
7696
|
+
"description": "The last day the price or offer is good for."
|
|
7575
7697
|
},
|
|
7576
7698
|
{
|
|
7577
7699
|
"name": "reference",
|
|
7578
7700
|
"type": "text",
|
|
7579
7701
|
"required": false,
|
|
7580
7702
|
"columnType": "TEXT",
|
|
7581
|
-
"default": ""
|
|
7703
|
+
"default": "",
|
|
7704
|
+
"description": "Your own number or note for finding this later, such as a purchase order or quote number."
|
|
7582
7705
|
},
|
|
7583
7706
|
{
|
|
7584
7707
|
"name": "notes",
|
|
7585
7708
|
"type": "text",
|
|
7586
7709
|
"required": false,
|
|
7587
7710
|
"columnType": "TEXT",
|
|
7588
|
-
"default": ""
|
|
7711
|
+
"default": "",
|
|
7712
|
+
"description": "Anything worth remembering about this."
|
|
7589
7713
|
},
|
|
7590
7714
|
{
|
|
7591
7715
|
"name": "terms",
|
|
7592
7716
|
"type": "text",
|
|
7593
7717
|
"required": false,
|
|
7594
7718
|
"columnType": "TEXT",
|
|
7595
|
-
"default": ""
|
|
7719
|
+
"default": "",
|
|
7720
|
+
"description": "The conditions agreed, such as deposits, payment or delivery conditions."
|
|
7596
7721
|
},
|
|
7597
7722
|
{
|
|
7598
7723
|
"name": "channelId",
|
|
7599
7724
|
"type": "text",
|
|
7600
7725
|
"required": false,
|
|
7601
7726
|
"columnType": "TEXT",
|
|
7602
|
-
"default": ""
|
|
7727
|
+
"default": "",
|
|
7728
|
+
"description": "Where it came from, for example your shop, a marketplace or a phone call."
|
|
7603
7729
|
}
|
|
7604
7730
|
],
|
|
7605
7731
|
"relationships": [
|
|
@@ -7952,95 +8078,109 @@
|
|
|
7952
8078
|
"name": "status",
|
|
7953
8079
|
"type": "text",
|
|
7954
8080
|
"required": false,
|
|
7955
|
-
"columnType": "TEXT"
|
|
8081
|
+
"columnType": "TEXT",
|
|
8082
|
+
"description": "Where the order or agreement stands, for example draft, sent, accepted or completed."
|
|
7956
8083
|
},
|
|
7957
8084
|
{
|
|
7958
8085
|
"name": "customerId",
|
|
7959
8086
|
"type": "foreignKey",
|
|
7960
8087
|
"required": false,
|
|
7961
8088
|
"related": "Customer",
|
|
7962
|
-
"columnType": "UUID"
|
|
8089
|
+
"columnType": "UUID",
|
|
8090
|
+
"description": "The customer a sales order or agreement is for."
|
|
7963
8091
|
},
|
|
7964
8092
|
{
|
|
7965
8093
|
"name": "vendorId",
|
|
7966
8094
|
"type": "foreignKey",
|
|
7967
8095
|
"required": false,
|
|
7968
8096
|
"related": "Vendor",
|
|
7969
|
-
"columnType": "UUID"
|
|
8097
|
+
"columnType": "UUID",
|
|
8098
|
+
"description": "The vendor a purchase order is placed with."
|
|
7970
8099
|
},
|
|
7971
8100
|
{
|
|
7972
8101
|
"name": "subtotal",
|
|
7973
8102
|
"type": "integer",
|
|
7974
8103
|
"required": false,
|
|
7975
8104
|
"columnType": "INTEGER",
|
|
7976
|
-
"default": 0
|
|
8105
|
+
"default": 0,
|
|
8106
|
+
"description": "The amount before tax."
|
|
7977
8107
|
},
|
|
7978
8108
|
{
|
|
7979
8109
|
"name": "taxAmount",
|
|
7980
8110
|
"type": "integer",
|
|
7981
8111
|
"required": false,
|
|
7982
8112
|
"columnType": "INTEGER",
|
|
7983
|
-
"default": 0
|
|
8113
|
+
"default": 0,
|
|
8114
|
+
"description": "The tax charged."
|
|
7984
8115
|
},
|
|
7985
8116
|
{
|
|
7986
8117
|
"name": "totalAmount",
|
|
7987
8118
|
"type": "integer",
|
|
7988
8119
|
"required": false,
|
|
7989
8120
|
"columnType": "INTEGER",
|
|
7990
|
-
"default": 0
|
|
8121
|
+
"default": 0,
|
|
8122
|
+
"description": "The full amount, tax included."
|
|
7991
8123
|
},
|
|
7992
8124
|
{
|
|
7993
8125
|
"name": "currency",
|
|
7994
8126
|
"type": "text",
|
|
7995
8127
|
"required": false,
|
|
7996
8128
|
"columnType": "TEXT",
|
|
7997
|
-
"default": "USD"
|
|
8129
|
+
"default": "USD",
|
|
8130
|
+
"description": "The currency of the amounts."
|
|
7998
8131
|
},
|
|
7999
8132
|
{
|
|
8000
8133
|
"name": "issueDate",
|
|
8001
8134
|
"type": "datetime",
|
|
8002
8135
|
"required": false,
|
|
8003
|
-
"columnType": "TIMESTAMP"
|
|
8136
|
+
"columnType": "TIMESTAMP",
|
|
8137
|
+
"description": "The date it was issued or placed."
|
|
8004
8138
|
},
|
|
8005
8139
|
{
|
|
8006
8140
|
"name": "dueDate",
|
|
8007
8141
|
"type": "datetime",
|
|
8008
8142
|
"required": false,
|
|
8009
|
-
"columnType": "TIMESTAMP"
|
|
8143
|
+
"columnType": "TIMESTAMP",
|
|
8144
|
+
"description": "The date payment or delivery is due."
|
|
8010
8145
|
},
|
|
8011
8146
|
{
|
|
8012
8147
|
"name": "expiryDate",
|
|
8013
8148
|
"type": "datetime",
|
|
8014
8149
|
"required": false,
|
|
8015
|
-
"columnType": "TIMESTAMP"
|
|
8150
|
+
"columnType": "TIMESTAMP",
|
|
8151
|
+
"description": "The last day the price or offer is good for."
|
|
8016
8152
|
},
|
|
8017
8153
|
{
|
|
8018
8154
|
"name": "reference",
|
|
8019
8155
|
"type": "text",
|
|
8020
8156
|
"required": false,
|
|
8021
8157
|
"columnType": "TEXT",
|
|
8022
|
-
"default": ""
|
|
8158
|
+
"default": "",
|
|
8159
|
+
"description": "Your own number or note for finding this later, such as a purchase order or quote number."
|
|
8023
8160
|
},
|
|
8024
8161
|
{
|
|
8025
8162
|
"name": "notes",
|
|
8026
8163
|
"type": "text",
|
|
8027
8164
|
"required": false,
|
|
8028
8165
|
"columnType": "TEXT",
|
|
8029
|
-
"default": ""
|
|
8166
|
+
"default": "",
|
|
8167
|
+
"description": "Anything worth remembering about this."
|
|
8030
8168
|
},
|
|
8031
8169
|
{
|
|
8032
8170
|
"name": "terms",
|
|
8033
8171
|
"type": "text",
|
|
8034
8172
|
"required": false,
|
|
8035
8173
|
"columnType": "TEXT",
|
|
8036
|
-
"default": ""
|
|
8174
|
+
"default": "",
|
|
8175
|
+
"description": "The conditions agreed, such as deposits, payment or delivery conditions."
|
|
8037
8176
|
},
|
|
8038
8177
|
{
|
|
8039
8178
|
"name": "channelId",
|
|
8040
8179
|
"type": "text",
|
|
8041
8180
|
"required": false,
|
|
8042
8181
|
"columnType": "TEXT",
|
|
8043
|
-
"default": ""
|
|
8182
|
+
"default": "",
|
|
8183
|
+
"description": "Where it came from, for example your shop, a marketplace or a phone call."
|
|
8044
8184
|
},
|
|
8045
8185
|
{
|
|
8046
8186
|
"name": "skuId",
|
|
@@ -8812,59 +8952,68 @@
|
|
|
8812
8952
|
"type": "crossPackageRef",
|
|
8813
8953
|
"required": false,
|
|
8814
8954
|
"related": "@happyvertical/smrt-profiles:Profile",
|
|
8815
|
-
"columnType": "UUID"
|
|
8955
|
+
"columnType": "UUID",
|
|
8956
|
+
"description": "Links this customer to their profile record, where their name and contact details are kept."
|
|
8816
8957
|
},
|
|
8817
8958
|
{
|
|
8818
8959
|
"name": "creditLimit",
|
|
8819
8960
|
"type": "integer",
|
|
8820
8961
|
"required": false,
|
|
8821
8962
|
"columnType": "INTEGER",
|
|
8822
|
-
"default": 0
|
|
8963
|
+
"default": 0,
|
|
8964
|
+
"description": "The most this customer may owe you at one time. Leave it at zero if you do not set limits."
|
|
8823
8965
|
},
|
|
8824
8966
|
{
|
|
8825
8967
|
"name": "paymentTerms",
|
|
8826
8968
|
"type": "text",
|
|
8827
8969
|
"required": false,
|
|
8828
8970
|
"columnType": "TEXT",
|
|
8829
|
-
"default": ""
|
|
8971
|
+
"default": "",
|
|
8972
|
+
"description": "How long the customer has to pay, written the way you would say it, for example \"Net 30\"."
|
|
8830
8973
|
},
|
|
8831
8974
|
{
|
|
8832
8975
|
"name": "taxExempt",
|
|
8833
8976
|
"type": "boolean",
|
|
8834
8977
|
"required": false,
|
|
8835
8978
|
"columnType": "BOOLEAN",
|
|
8836
|
-
"default": false
|
|
8979
|
+
"default": false,
|
|
8980
|
+
"description": "Turn this on if you do not charge this customer sales tax."
|
|
8837
8981
|
},
|
|
8838
8982
|
{
|
|
8839
8983
|
"name": "defaultShippingAddress",
|
|
8840
8984
|
"type": "json",
|
|
8841
8985
|
"required": false,
|
|
8842
|
-
"columnType": "JSON"
|
|
8986
|
+
"columnType": "JSON",
|
|
8987
|
+
"description": "Where you usually send goods to this customer, so you do not retype it on every order."
|
|
8843
8988
|
},
|
|
8844
8989
|
{
|
|
8845
8990
|
"name": "defaultBillingAddress",
|
|
8846
8991
|
"type": "json",
|
|
8847
8992
|
"required": false,
|
|
8848
|
-
"columnType": "JSON"
|
|
8993
|
+
"columnType": "JSON",
|
|
8994
|
+
"description": "Where you send invoices to this customer."
|
|
8849
8995
|
},
|
|
8850
8996
|
{
|
|
8851
8997
|
"name": "status",
|
|
8852
8998
|
"type": "text",
|
|
8853
8999
|
"required": false,
|
|
8854
|
-
"columnType": "TEXT"
|
|
9000
|
+
"columnType": "TEXT",
|
|
9001
|
+
"description": "Whether you are still dealing with this customer: active, inactive or suspended."
|
|
8855
9002
|
},
|
|
8856
9003
|
{
|
|
8857
9004
|
"name": "customerType",
|
|
8858
9005
|
"type": "text",
|
|
8859
9006
|
"required": false,
|
|
8860
|
-
"columnType": "TEXT"
|
|
9007
|
+
"columnType": "TEXT",
|
|
9008
|
+
"description": "The kind of customer: a direct shopper, a wholesale buyer or a retail customer."
|
|
8861
9009
|
},
|
|
8862
9010
|
{
|
|
8863
9011
|
"name": "notes",
|
|
8864
9012
|
"type": "text",
|
|
8865
9013
|
"required": false,
|
|
8866
9014
|
"columnType": "TEXT",
|
|
8867
|
-
"default": ""
|
|
9015
|
+
"default": "",
|
|
9016
|
+
"description": "Anything worth remembering about this customer."
|
|
8868
9017
|
}
|
|
8869
9018
|
],
|
|
8870
9019
|
"relationships": [
|
|
@@ -12382,62 +12531,71 @@
|
|
|
12382
12531
|
"type": "crossPackageRef",
|
|
12383
12532
|
"required": false,
|
|
12384
12533
|
"related": "@happyvertical/smrt-profiles:Profile",
|
|
12385
|
-
"columnType": "UUID"
|
|
12534
|
+
"columnType": "UUID",
|
|
12535
|
+
"description": "Links this vendor to their profile record, where their name and contact details are kept."
|
|
12386
12536
|
},
|
|
12387
12537
|
{
|
|
12388
12538
|
"name": "leadTimeDays",
|
|
12389
12539
|
"type": "integer",
|
|
12390
12540
|
"required": false,
|
|
12391
12541
|
"columnType": "INTEGER",
|
|
12392
|
-
"default": 0
|
|
12542
|
+
"default": 0,
|
|
12543
|
+
"description": "How many days the vendor usually takes between your order and delivery."
|
|
12393
12544
|
},
|
|
12394
12545
|
{
|
|
12395
12546
|
"name": "minimumOrderAmount",
|
|
12396
12547
|
"type": "integer",
|
|
12397
12548
|
"required": false,
|
|
12398
12549
|
"columnType": "INTEGER",
|
|
12399
|
-
"default": 0
|
|
12550
|
+
"default": 0,
|
|
12551
|
+
"description": "The smallest order the vendor will accept."
|
|
12400
12552
|
},
|
|
12401
12553
|
{
|
|
12402
12554
|
"name": "paymentTerms",
|
|
12403
12555
|
"type": "text",
|
|
12404
12556
|
"required": false,
|
|
12405
12557
|
"columnType": "TEXT",
|
|
12406
|
-
"default": ""
|
|
12558
|
+
"default": "",
|
|
12559
|
+
"description": "How long you have to pay this vendor, written the way you would say it, for example \"Net 30\"."
|
|
12407
12560
|
},
|
|
12408
12561
|
{
|
|
12409
12562
|
"name": "currency",
|
|
12410
12563
|
"type": "text",
|
|
12411
12564
|
"required": false,
|
|
12412
12565
|
"columnType": "TEXT",
|
|
12413
|
-
"default": "USD"
|
|
12566
|
+
"default": "USD",
|
|
12567
|
+
"description": "The currency this vendor bills you in."
|
|
12414
12568
|
},
|
|
12415
12569
|
{
|
|
12416
12570
|
"name": "defaultContactEmail",
|
|
12417
12571
|
"type": "text",
|
|
12418
12572
|
"required": false,
|
|
12419
12573
|
"columnType": "TEXT",
|
|
12420
|
-
"default": ""
|
|
12574
|
+
"default": "",
|
|
12575
|
+
"description": "The email address you normally use to reach this vendor."
|
|
12421
12576
|
},
|
|
12422
12577
|
{
|
|
12423
12578
|
"name": "defaultContactPhone",
|
|
12424
12579
|
"type": "text",
|
|
12425
12580
|
"required": false,
|
|
12426
12581
|
"columnType": "TEXT",
|
|
12427
|
-
"default": ""
|
|
12582
|
+
"default": "",
|
|
12583
|
+
"description": "The phone number you normally use to reach this vendor."
|
|
12428
12584
|
},
|
|
12429
12585
|
{
|
|
12430
12586
|
"name": "status",
|
|
12431
12587
|
"type": "text",
|
|
12432
12588
|
"required": false,
|
|
12433
|
-
"columnType": "TEXT"
|
|
12589
|
+
"columnType": "TEXT",
|
|
12590
|
+
"description": "Whether you still buy from this vendor: active, inactive or suspended."
|
|
12434
12591
|
},
|
|
12435
12592
|
{
|
|
12436
12593
|
"name": "notes",
|
|
12437
12594
|
"type": "text",
|
|
12438
12595
|
"required": false,
|
|
12439
12596
|
"columnType": "TEXT",
|
|
12440
|
-
"default": ""
|
|
12597
|
+
"default": "",
|
|
12598
|
+
"description": "Anything worth remembering about this vendor."
|
|
12441
12599
|
}
|
|
12442
12600
|
],
|
|
12443
12601
|
"relationships": [
|
|
@@ -12698,6 +12856,7 @@
|
|
|
12698
12856
|
{
|
|
12699
12857
|
"name": "BillingAccount",
|
|
12700
12858
|
"qualifiedName": "@happyvertical/smrt-commerce:BillingAccount",
|
|
12859
|
+
"displayLabelField": "name",
|
|
12701
12860
|
"collection": "billingaccounts",
|
|
12702
12861
|
"tableName": "_smrt_billing_accounts",
|
|
12703
12862
|
"packageName": "@happyvertical/smrt-commerce",
|
|
@@ -19516,7 +19675,7 @@
|
|
|
19516
19675
|
"polymorphicAssociations": 0,
|
|
19517
19676
|
"uuidColumns": 162
|
|
19518
19677
|
},
|
|
19519
|
-
"agentDoc": "# @happyvertical/smrt-commerce\n\nE-commerce with Contract STI hierarchy, invoice lifecycle, payment tracking, payout remittance, and optional ledger integration.\n\n## Models\n\n- **Customer** / **Vendor**: linked to Profile via string ID (not FK). Customer has creditLimit, paymentTerms, customerType (DTC / WHOLESALE / RETAIL). Vendor has leadTimeDays, minimumOrder, and `payoutAddresses: Record<string, string>` — a flat map from payout-rail-qualified currency code (`USDC-base`, `BTC`, `USD-stripe`, ...) to destination string (EVM address, BTC address, Stripe Connect account id, IBAN). Use `getPayoutAddress(currency)` for a `Map.get`-style lookup; missing entries return `undefined` (caller decides skip-vs-error).\n- **Contract** (STI base → Estimate, Order, Lease, Agreement, PurchaseOrder, WholesaleOrder, ProductionOrder, Cart, LicenseSale): 9 contract types sharing one table. Carries `channelId` (open-ended string — `dtc-web`, `wholesale-b2b`, `pos-store-N`, etc.) so the same model serves DTC checkout, B2B portals, and POS.\n- **WholesaleOrder**: B2B order. Conventional pairing — customer has `customerType: 'wholesale'`, NET-30/60 terms, delivered via wholesale-portal channel.\n- **ProductionOrder**: manufacturing equivalent of a PurchaseOrder — commission your factory to make finished goods. Consumes raw materials per BOM (`@happyvertical/smrt-manufacturing`) and produces SKU stock (`@happyvertical/smrt-inventory`).\n- **Cart**: transient order-in-progress. Same shape as Order; the application promotes the row from `_meta_type: Cart` to `_meta_type: Order` at checkout instead of copying data between tables.\n- **LicenseSale**: industry-neutral licensing primitive. Carries an *immutable* rights snapshot (`rightsMedium`, `rightsDistributionScope`, `rightsExclusivity`, `rightsDuration`, `rightsTerritory`, `rightsSublicensing`, `rightsDerivatives` — typed `Meta<T>` fields), licensee identity (`licenseeEmail`, optional `licenseeLegalEntity` / `licenseeJurisdiction`), and a signed-PDF reference (`pdfUrl`, `pdfHash`, optional `onChainHashRegistryRef`). Once saved at `ContractStatus.ACCEPTED`, the rights snapshot is frozen — mutating any of the seven rights fields and re-saving throws. The only legal transition out of ACCEPTED is `revoke()` (moves to CANCELLED without touching rights). Useful for stock media, music licensing, code-asset marketplaces, license keys, anywhere rights are sold for a fee.\n- **ContractLineItem**: items on contracts.\n- **Invoice**: status machine `DRAFT → SENT → VIEWED → PARTIAL → PAID` (also OVERDUE, CANCELLED, WRITTEN_OFF). `recognizeRevenue()` creates balanced AR journal entry (DR: Accounts Receivable, CR: Revenue, CR: Tax Payable).\n- **InvoiceLineItem**: fractional-quantity line items with safe minor-unit validation/recalculation on save; editor-mode recovery and existing-column migration are documented in [invoice quantity persistence](agents/invoice-quantity.md).\n- **Payment** / **PaymentAllocation**: tracks payments against invoices. Status controlled by `Invoice.updatePaymentStatus()`, not Payment model. Carries optional backend-adapter fields for PaymentBackend-routed flows: `backendId` (rail adapter id — `base-usdc`, `btc`, `stripe`, distinct from `externalProvider` which names an accounting sync destination), `backendTxRef` (chain tx hash or gateway settlement id), `nativeAmount` / `nativeCurrency` (what actually arrived), `usdAtQuote` / `usdAtConfirmation` (drift accounting for volatile-currency rails). `Payment.usdDrift()` returns the confirmation - quote delta, or `0` when either side is unset.\n- **PaymentInstrument**: reusable saved payment method (\"card on file\"). Stores only provider references and non-sensitive display metadata (`providerCustomerId`, `providerPaymentMethodId`, brand / last4 / expiry), never raw card data. Use `PaymentInstrumentCollection.setDefaultForCustomer()` to change the default so the single-default-per-customer invariant is enforced; generated create/update routes cannot write `isDefault` directly.\n- **PaymentIntent**: short-lived pre-payment commitment with multi-option semantics. Locks a USD price for a fixed window (default 15 minutes) and lists one or more `PaymentOption`s describing different rails (`backendId`, `currency`, `payTo`, `nativeAmount`, optional `chain` / `memo` / `x402Capable` / `expiresAt`). First option to receive payment wins; the others are implicitly retired. State machine `awaiting_payment → paid → (issued | retired)` plus `expired` and `cancelled`. Mutate via dedicated `markPaid` / `markIssued` / `expire` / `cancel` / `retire` helpers — direct status assignment bypasses the invariant checks. Idempotency via natural key `(tenant_id, offering_ref, licensee_email, idempotency_key)` and `PaymentIntentCollection.getOrCreateByIdempotencyKey()`.\n- **Payout**: operator-to-supplier remittance. Distinct from Payment because direction, status machine, and chain semantics differ. Status machine `pending → sent → confirmed → failed` (failed is terminal but resettable via `resetFromFailed()` after fixing the underlying problem). References source `paymentId` (plain string) and destination `vendorId` (foreign key). Amount invariant `supplierNet === grossAmount - operatorFee` enforced exactly on save (integer minor units, no tolerance — #2401). `PayoutCollection.createFromPayment()` is the typical entry point; it pulls native amount / currency from the source Payment.\n- **Fulfillment** / **FulfillmentLineItem**: shipment/delivery tracking.\n\n## Ledger Integration\n\n`@happyvertical/smrt-ledgers` is a regular dependency, loaded lazily via dynamic `import()` so the coupling stays runtime-only (no hard static import; the package graph stays a DAG — see #1582). Invoice stores `arJournalId` and `revenueJournalId` as string references. `recognizeRevenue()` creates a balanced AR journal entry; `getArJournal()` returns null when no journal has been recognized yet.\n\n## Billing-period close (#3060)\n\n`src/billing/` closes periods from smrt-subscriptions charges; see the README\nfor usage.\n\n- **Port, not provider.** Period close, events, and credit checkout call only\n the `BillingProvider` port (integer minor units). `stripe.ts` adapts\n `@happyvertical/accounting`, which takes currency *major* units; convert with\n `units.ts` and never hand-roll a Stripe call here. `units.ts` exponents are\n an explicit ISO 4217 table matching the SDK's, never `Intl` display digits\n (CLDR differs for IQD, MGA, … and drifts by ICU release). The SDK's\n `*Minor` fields are already ISO minor units. Capabilities a rail may lack\n (`chargeSavedPaymentMethod`, `createSetupCheckout`, `getCheckout`,\n `setDefaultPaymentMethod`, `markInvoiceUncollectible`) are optional port\n methods: detect them by presence, and keep additions optional (#3139).\n `sendAndReconcile` refuses a provider invoice whose subtotal or total\n disagrees with the local invoice.\n- **Replay safety is identity.** Close, invoice, line, payment, allocation,\n and claim ids are `deterministicId()`s; `BillingLineSource` (conflict key\n `source_type, source_id`) is the only double-billing guard, so never bill a\n source without claiming it, and never widen that key. Each close step is\n persisted before the next; `acquireCloseLease()` serializes workers. A\n close that nets to a credit keeps its claims and ends `carried_forward`;\n its subtotal is a `credit_carry_forward` source for the payer's next billed\n close, which marks the carried close `completed`.\n- **Cycles and flat-plan coverage (#3116).** `cycles.ts` is the schedule\n (pure; `BillingAccount.billingAnchorAt`, null = calendar months). A close\n with no period closes each payer's `lastEndedBillingPeriod()`. Flat-plan\n claims are the exception to \"id from the source\": their `sourceId` is\n `<subscriptionId>:seq:<chainSequence>` and their `periodStart/End` is the\n exact time they bill. `claimFlatWindow()` reads the last number, then the\n coverage (claims ending after the window start), claims one gap as number\n n + 1, and retries on conflict; reading in that order is what makes it\n safe. That numbering, not the period, stops overlaps when schedules or\n payers change — never claim a flat plan outside it, and keep both reads\n bounded (no whole-history scans). Each numbered claim is its own invoice\n line keyed `lineKey|periodStart` (a function of the claim alone, so a\n resumed close rebuilds the same line ids). Proration is\n `prorateMinorUnits()` (half up, BigInt) against the period's full cycle.\n- **System tables.** `BillingAccount`, `BillingPeriodClose`, and\n `BillingLineSource` are not tenant-scoped and have no generated surface.\n Collections stay unexported; models are root exports (#3082). Invoices,\n payments, and journals are written in the seller's tenant; payer-owned\n subscriptions and credit grants in a system context, only after\n verification.\n- **Events** use smrt-jobs' delivery inbox under provider\n `<name>-billing:<sellerTenantId>` and a provider-filtered\n `ForgeProjectionRuntime`, so a runtime never claims another seller's\n events; any other runtime sharing the inbox must pass `providers` too. Only\n events this package acts on are stored: foreign checkouts are `ignored`,\n and only `smrt_*` checkout metadata is kept; it is\n HMAC-signed with the webhook secret at creation (empty values are omitted:\n Stripe drops them), so another integration on the same account cannot forge\n a credit purchase or a card setup; credit is granted only when the\n collected total equals it plus provider tax. Checkout amounts come from the\n re-read session (`getCheckout()`), never the Stripe event, whose amounts are\n in Stripe's unit. Rotating the webhook secret strands in-flight checkouts\n (up to 24 h). `observe()` re-reads provider state, so ordering never depends\n on delivery order; the only provider writes in `observe()` are idempotent\n (making a saved card the default). The standing hook runs inside the event\n transaction and must be idempotent.\n- **Card on file and top-ups (#3139).** A saved card is the payer customer's\n default `PaymentInstrument` (seller tenant, id from the provider method).\n `autoChargeInvoices` bills such payers `charge_automatically`, decided once\n and saved as `Invoice.collectionMethod` before the first push, which every\n retry reuses (never recompute it: a lost push response would record a\n method the provider was not asked for, #3190); activation follows `paid`, never send. An auto top-up attempt\n is a `PENDING` `Payment` (`reference` `auto-top-up:<policyId>`, id from the\n policy and `count()` of its attempts) inserted before the charge, so racing\n evaluations derive one id and one charge; the charge key is derived from\n that id. `applyAutoTopUpOutcome()` must run in a transaction and starts with\n a conditional `UPDATE … WHERE status = 'pending'` row lock, so the hook and\n the `payment` webhook settle once; the grant is keyed by the charge key.\n Never settle an attempt outside that function. Taxed accounts are charged\n with provider tax by default (#3194): the attempt row holds the credit\n (the charge subtotal), the tax is journaled to tax payable at settlement,\n and the attempt's tax decision is recorded in its `notes` so a re-drive\n repeats the same charge request (the provider refuses a key reused with\n different tax). `claimAttempt()` is the only place that decides a\n skip and reports it (`onAutoTopUpSkipped`); `cardOnFile()` and period close\n use `defaultCardInstrument()` — never copy that predicate. A provider write-off moves the local invoice to\n `WRITTEN_OFF` (a later payment, by card or on a rail (#3188), is recorded\n and reinstates the payer; the status stays, so \"paid in full\" for a\n written-off invoice is read from its allocations).\n- **`Invoice.providerTaxAmount`** is added to line-item tax; it is\n server-managed (not API-writable). `toAccountingInput()` emits major units.\n- **Payment rails (#3138).** A runtime has one issuing `provider` and any\n number of `paymentProviders` (unique names, one inbox namespace each; a\n provider with `capabilities.issuesInvoices === false` can never issue).\n `observe()` resolves the provider from the delivery namespace, never the\n payload. Crypto rails implement the port over `@happyvertical/payments`'\n `CryptoCheckoutGateway`; never call BTCPay (or any gateway) from here.\n Settlement is decided by the pure `decideAttempt()` from gateway state and\n `paymentPolicy` — the gateway's `settled` is authoritative and nothing here\n counts confirmations. A `BillingPaymentAttempt` (`(provider, checkout_id)`\n deterministic id) records every state and settles once; grants and payments\n are keyed by checkout id. Invoice payments close the issuer's invoice out of\n band in `observe()` (idempotent) before `project()` records the payment, and\n `settlePaidInvoice` skips (records nothing for) a `paidOutOfBand` invoice\n the rail latched with `outOfBandRequestedAt`; other out-of-band closes are\n recorded as `OTHER` payments. Rails never save cards or charge tax: a taxed\n credit purchase on a rail needs an explicit `automaticTax: false`. Exceptions are flags for operators;\n nothing reverses or refunds automatically.\n- **Known limits**: write-offs post no bad-debt journal (AR stays until paid\n or journaled by an operator); discounts still reach Stripe as negative lines (the SDK's\n line `discount` would change the lines a replayed push reconciles, so it\n needs its own migration); `RetailCharge` has no adjustment ledger. Flat\n plans are monthly, in arrears; plan changes are not prorated (#3119).\n\n## Cross-Package References\n\n- `customerId` → `@foreignKey('Customer')` (hard reference within package)\n- `profileId` → plain string to smrt-profiles\n- `arJournalId`, `revenueJournalId` → plain string to smrt-ledgers\n- `skuId` (on `PaymentIntent`, `LicenseSale`) → plain string to smrt-products\n- `paymentId` (on `PaymentIntent`, `Payout`, `LicenseSale`) → plain string to `Payment` (same package, but kept as plain string for cross-model consistency)\n- `vendorId` on `Payout` → `@foreignKey(Vendor)` (hard reference within package)\n- Billing records reference tenants with `@crossPackageRef('@happyvertical/smrt-users:Tenant')` and charges, plan periods, and adjustments by plain `sourceId`\n\n## Gotchas\n\n- **Optional tenancy**: all models `@TenantScoped({ mode: 'optional' })` + nullable tenantId\n- **Currency is integer minor units** (cents, satoshis) — `$19.99` is `1999`, like affiliates. Money is exact, so money fields initialize `= 0`, never `= 0.0`: the integer literal is what maps them to INTEGER columns (BIGINT on fresh PostgreSQL/DuckDB databases). Writing a fractional major-unit value is the bug — the model rejects it via `assertIntegerMinorUnits` on `Invoice`/`Payment`/`PaymentAllocation`/`Payout`/`Contract` before the database sees it, because PostgreSQL would reject it with `22P02` while SQLite's affinity silently stores it. `pnpm --filter @happyvertical/smrt-commerce test:postgres` is the lane that holds the line (#2361, #2401, #2373).\n- **Rates are the opposite**: `InvoiceLineItem.taxRate` and `ContractLineItem.taxRate` are inherently fractional and must initialize `= 0.0`. INTEGER would truncate every rate to 0. `ContractLineItem.quantity` is decimal for the same reason (contracts price fractional hours/weight/bandwidth); `InvoiceLineItem.quantity` is also decimal (six fractional places); existing integer columns require the explicit [quantity migration](agents/invoice-quantity.md).\n- **Rounding happens where a rate meets money, and nowhere else**: `InvoiceLineItem` uses exact shared invoice arithmetic to round fractional quantity × price and then tax to minor units; `ContractLineItem.calculateAmount()` uses `Math.round()` for tax. Everything downstream is exact integer arithmetic, which is why **there are no `EPSILON` tolerances left on any money path** (#2401). `Invoice`, `PaymentAllocation`, `Payout` and `PaymentIntent` compare with `===` / `>` / `>=`. Do not reintroduce a tolerance: against integers it forgives a real one-cent discrepancy rather than float fuzz. (`FulfillmentLineItem`'s quantity epsilon is unrelated — quantities are genuinely decimal there.)\n- **Migrating an existing database to minor units**: `preflightCommerceMoneyMinorUnits(db)` reports, per column, whether it still holds major units and which rows would be rounded or exceed JavaScript's safe-integer range; `migrateCommerceMoneyToMinorUnits(db)` converts them. Both are exported from the package root. The rescale is idempotent via a `_smrt_backfills` marker, changes the column type in place on PostgreSQL/DuckDB (`ALTER … TYPE BIGINT USING round(col * 100)`), and on SQLite rescales values only — SQLite cannot alter a declared type in place, so those columns come back in `declaredTypeChangePending` and need the table-rebuild path (#2370).\n- **`Payment.nativeAmount` is NOT in that migration, and must not be.** Its minor unit is a property of the *row's asset*: satoshis on a BTC rail (×1e8), cents on a fiat or stablecoin rail (×1e2), in one column discriminated only by `nativeCurrency`. A blanket ×100 turns 0.00713 BTC into `1` instead of `713000` sats, and a round 0.01 BTC even passes the preflight's integrality check while being wrong by six orders of magnitude. Convert it in two deliberate steps — normalise each row to its own asset's minor units while the column is still floating-point, then `rescaleMoneyColumnsToMinorUnits(db, COMMERCE_NATIVE_UNIT_COLUMNS, { scale: 1, … })` for the type change. `COMMERCE_NATIVE_UNIT_COLUMNS` is exported with a worked example; step one is deliberately the deployment's to write, because only it knows which `nativeCurrency` values it has used.\n- **`PaymentIntent.paymentOptions[].nativeAmount` has the same per-asset problem inside a JSON column and is likewise not migrated.** An intent's price lock defaults to 15 minutes, so the supported answer is to let open intents expire and be re-quoted: an unconverted option fails the exact `!==` reconciliation against the payment that arrives, which is a loud failure rather than a silently mis-scaled quote.\n- **Range and existing deployments**: fresh PostgreSQL/DuckDB INTEGER columns are BIGINT, and the runtime rejects values outside JavaScript's safe-integer range rather than rounding them. Existing PostgreSQL `int4` columns do not self-repair; widen them through the explicit migration tracked in #2424.\n- **Journals posted from commerce carry minor units**: `Payment.recordPayment()` and `Invoice.recognizeRevenue()` write `amount` / `totalAmount` straight into smrt-ledgers entries. smrt-ledgers is unit-agnostic (its `BALANCE_EPSILON` only checks debits === credits), and integer entries balance exactly, so this is strictly tighter than the major-unit journals commerce used to post.\n- **Invoice controls payment status**: not the Payment model — use `Invoice.updatePaymentStatus()`\n- **Tax rate is external**: no tax rate field on Invoice — rate must be calculated externally\n- **Profile linking**: separate `ProfileCollection.create()` needed to fetch actual Profile object\n- **PaymentIntent natural key**: `conflictColumns: ['tenant_id', 'offering_ref', 'licensee_email', 'idempotency_key']` — a retried `create` with the same tuple upserts the existing row. Use `getOrCreateByIdempotencyKey()` to branch on `{ intent, created }`. Empty natural-key inputs (e.g. blank `idempotencyKey`) disable dedup by design.\n- **Payout state-machine guards**: `markSent` requires a non-empty `backendTxRef`; `markConfirmed` only valid from `SENT`; `markFailed` only valid from `PENDING` / `SENT` (a confirmed payout can't fail — that path is a refund). `resetFromFailed()` is the dedicated escape hatch from `FAILED` back to `PENDING` after an operator fixes the underlying problem; it clears `backendTxRef` so the next attempt picks up a fresh one.\n- **PaymentInstrument defaults**: `isDefault` is domain-managed, not API-writable. Call `setDefaultForCustomer(customerId, instrumentId)` so the target is validated and the customer's other instruments are cleared.\n- **LicenseSale immutability**: rights snapshot freezes on save-with-status-ACCEPTED. The captured snapshot lives in a module-scoped `WeakMap<LicenseSale, string>` so it doesn't interact with the schema or round-trip through `_meta_data`. Drafts (status != ACCEPTED) remain mutable. To \"change\" an issued license: `revoke()` it, then issue a new `LicenseSale` row.\n- **Vendor.payoutAddresses normalization**: the constructor accepts either a `Record<string, string>` or a pre-serialized JSON string. `initialize()` re-normalizes after the framework's option-override pass; `save()` re-normalizes defensively against direct field assignment. Non-string values inside the input map are silently dropped to preserve the typed invariant downstream.\n\n## Commercial UI\n\nSee [commercial UI composition](agents/commercial-ui.md) for native form recovery, amount compatibility and backend ownership. Package-owned guides under `agents/` ship with the package.\n\n## Quote and estimate UI\n\n`src/svelte/quote-types.ts` separates unparsed draft strings from explicit\nminor-unit revision DTOs. Native row submitters, caller-owned retry identity and\nextension conventions are documented in [agents/quote-ui.md](agents/quote-ui.md).\n\n## Purchasing UI\n\n`PurchaseOrderEditor` preserves allocation IDs and explicit zeroes, including\nretained reduction rows; the server validates review fingerprints before recording.\nSee [agents/purchasing-ui.md](agents/purchasing-ui.md) for caller responsibilities.\n",
|
|
19678
|
+
"agentDoc": "# @happyvertical/smrt-commerce\n\nE-commerce with Contract STI hierarchy, invoice lifecycle, payment tracking, payout remittance, and optional ledger integration.\n\n## Models\n\n- **Customer** / **Vendor**: linked to Profile via string ID (not FK). Customer has creditLimit, paymentTerms, customerType (DTC / WHOLESALE / RETAIL). Vendor has leadTimeDays, minimumOrder, and `payoutAddresses: Record<string, string>` — a flat map from payout-rail-qualified currency code (`USDC-base`, `BTC`, `USD-stripe`, ...) to destination string (EVM address, BTC address, Stripe Connect account id, IBAN). Use `getPayoutAddress(currency)` for a `Map.get`-style lookup; missing entries return `undefined` (caller decides skip-vs-error).\n- **Contract** (STI base → Estimate, Order, Lease, Agreement, PurchaseOrder, WholesaleOrder, ProductionOrder, Cart, LicenseSale): 9 contract types sharing one table. Carries `channelId` (open-ended string — `dtc-web`, `wholesale-b2b`, `pos-store-N`, etc.) so the same model serves DTC checkout, B2B portals, and POS.\n- **WholesaleOrder**: B2B order. Conventional pairing — customer has `customerType: 'wholesale'`, NET-30/60 terms, delivered via wholesale-portal channel.\n- **ProductionOrder**: manufacturing equivalent of a PurchaseOrder — commission your factory to make finished goods. Consumes raw materials per BOM (`@happyvertical/smrt-manufacturing`) and produces SKU stock (`@happyvertical/smrt-inventory`).\n- **Cart**: transient order-in-progress. Same shape as Order; the application promotes the row from `_meta_type: Cart` to `_meta_type: Order` at checkout instead of copying data between tables.\n- **LicenseSale**: industry-neutral licensing primitive. Carries an *immutable* rights snapshot (`rightsMedium`, `rightsDistributionScope`, `rightsExclusivity`, `rightsDuration`, `rightsTerritory`, `rightsSublicensing`, `rightsDerivatives` — typed `Meta<T>` fields), licensee identity (`licenseeEmail`, optional `licenseeLegalEntity` / `licenseeJurisdiction`), and a signed-PDF reference (`pdfUrl`, `pdfHash`, optional `onChainHashRegistryRef`). Once saved at `ContractStatus.ACCEPTED`, the rights snapshot is frozen — mutating any of the seven rights fields and re-saving throws. The only legal transition out of ACCEPTED is `revoke()` (moves to CANCELLED without touching rights). Useful for stock media, music licensing, code-asset marketplaces, license keys, anywhere rights are sold for a fee.\n- **ContractLineItem**: items on contracts.\n- **Invoice**: status machine `DRAFT → SENT → VIEWED → PARTIAL → PAID` (also OVERDUE, CANCELLED, WRITTEN_OFF). `recognizeRevenue()` creates balanced AR journal entry (DR: Accounts Receivable, CR: Revenue, CR: Tax Payable).\n- **InvoiceLineItem**: fractional-quantity line items with safe minor-unit validation/recalculation on save; editor-mode recovery and existing-column migration are documented in [invoice quantity persistence](agents/invoice-quantity.md).\n- **Payment** / **PaymentAllocation**: tracks payments against invoices. Status controlled by `Invoice.updatePaymentStatus()`, not Payment model. Carries optional backend-adapter fields for PaymentBackend-routed flows: `backendId` (rail adapter id — `base-usdc`, `btc`, `stripe`, distinct from `externalProvider` which names an accounting sync destination), `backendTxRef` (chain tx hash or gateway settlement id), `nativeAmount` / `nativeCurrency` (what actually arrived), `usdAtQuote` / `usdAtConfirmation` (drift accounting for volatile-currency rails). `Payment.usdDrift()` returns the confirmation - quote delta, or `0` when either side is unset.\n- **PaymentInstrument**: reusable saved payment method (\"card on file\"). Stores only provider references and non-sensitive display metadata (`providerCustomerId`, `providerPaymentMethodId`, brand / last4 / expiry), never raw card data. Use `PaymentInstrumentCollection.setDefaultForCustomer()` to change the default so the single-default-per-customer invariant is enforced; generated create/update routes cannot write `isDefault` directly.\n- **PaymentIntent**: short-lived pre-payment commitment with multi-option semantics. Locks a USD price for a fixed window (default 15 minutes) and lists one or more `PaymentOption`s describing different rails (`backendId`, `currency`, `payTo`, `nativeAmount`, optional `chain` / `memo` / `x402Capable` / `expiresAt`). First option to receive payment wins; the others are implicitly retired. State machine `awaiting_payment → paid → (issued | retired)` plus `expired` and `cancelled`. Mutate via dedicated `markPaid` / `markIssued` / `expire` / `cancel` / `retire` helpers — direct status assignment bypasses the invariant checks. Idempotency via natural key `(tenant_id, offering_ref, licensee_email, idempotency_key)` and `PaymentIntentCollection.getOrCreateByIdempotencyKey()`.\n- **Payout**: operator-to-supplier remittance. Distinct from Payment because direction, status machine, and chain semantics differ. Status machine `pending → sent → confirmed → failed` (failed is terminal but resettable via `resetFromFailed()` after fixing the underlying problem). References source `paymentId` (plain string) and destination `vendorId` (foreign key). Amount invariant `supplierNet === grossAmount - operatorFee` enforced exactly on save (integer minor units, no tolerance — #2401). `PayoutCollection.createFromPayment()` is the typical entry point; it pulls native amount / currency from the source Payment.\n- **Fulfillment** / **FulfillmentLineItem**: shipment/delivery tracking.\n\n## Recipes (#3590)\n\n`src/recipes.ts` declares four minimal `SmrtRecipe`s, emitted into the built\n`manifest.json` and `smrt-knowledge.json` `recipes`: `commerce.customers`\n(Customer), `commerce.vendors` (Vendor), `commerce.sales` (Order, requires\ncustomers), `commerce.purchases` (PurchaseOrder, requires vendors). Headers\nonly; line items, fulfilment, invoices, and payments are later recipes. Each\nhas user-facing help in `src/<name>.recipe.md` (#3591), and the fields those\nrecipes show carry `@field({ description })` text; keep both in plain\nlanguage for end users and update them when a recipe's fields change. See\n[core recipes](../core/agents/recipes.md).\n\n## Ledger Integration\n\n`@happyvertical/smrt-ledgers` is a regular dependency, loaded lazily via dynamic `import()` so the coupling stays runtime-only (no hard static import; the package graph stays a DAG — see #1582). Invoice stores `arJournalId` and `revenueJournalId` as string references. `recognizeRevenue()` creates a balanced AR journal entry; `getArJournal()` returns null when no journal has been recognized yet.\n\n## Billing-period close (#3060)\n\n`src/billing/` closes periods from smrt-subscriptions charges; see the README\nfor usage.\n\n- **Port, not provider.** Period close, events, and credit checkout call only\n the `BillingProvider` port (integer minor units). `stripe.ts` adapts\n `@happyvertical/accounting`, which takes currency *major* units; convert with\n `units.ts` and never hand-roll a Stripe call here. `units.ts` exponents are\n an explicit ISO 4217 table matching the SDK's, never `Intl` display digits\n (CLDR differs for IQD, MGA, … and drifts by ICU release). The SDK's\n `*Minor` fields are already ISO minor units. Capabilities a rail may lack\n (`chargeSavedPaymentMethod`, `createSetupCheckout`, `getCheckout`,\n `setDefaultPaymentMethod`, `markInvoiceUncollectible`) are optional port\n methods: detect them by presence, and keep additions optional (#3139).\n `sendAndReconcile` refuses a provider invoice whose subtotal or total\n disagrees with the local invoice.\n- **Replay safety is identity.** Close, invoice, line, payment, allocation,\n and claim ids are `deterministicId()`s; `BillingLineSource` (conflict key\n `source_type, source_id`) is the only double-billing guard, so never bill a\n source without claiming it, and never widen that key. Each close step is\n persisted before the next; `acquireCloseLease()` serializes workers. A\n close that nets to a credit keeps its claims and ends `carried_forward`;\n its subtotal is a `credit_carry_forward` source for the payer's next billed\n close, which marks the carried close `completed`.\n- **Cycles and flat-plan coverage (#3116).** `cycles.ts` is the schedule\n (pure; `BillingAccount.billingAnchorAt`, null = calendar months). A close\n with no period closes each payer's `lastEndedBillingPeriod()`. Flat-plan\n claims are the exception to \"id from the source\": their `sourceId` is\n `<subscriptionId>:seq:<chainSequence>` and their `periodStart/End` is the\n exact time they bill. `claimFlatWindow()` reads the last number, then the\n coverage (claims ending after the window start), claims one gap as number\n n + 1, and retries on conflict; reading in that order is what makes it\n safe. That numbering, not the period, stops overlaps when schedules or\n payers change — never claim a flat plan outside it, and keep both reads\n bounded (no whole-history scans). Each numbered claim is its own invoice\n line keyed `lineKey|periodStart` (a function of the claim alone, so a\n resumed close rebuilds the same line ids). Proration is\n `prorateMinorUnits()` (half up, BigInt) against the period's full cycle.\n- **System tables.** `BillingAccount`, `BillingPeriodClose`, and\n `BillingLineSource` are not tenant-scoped and have no generated surface.\n Collections stay unexported; models are root exports (#3082). Invoices,\n payments, and journals are written in the seller's tenant; payer-owned\n subscriptions and credit grants in a system context, only after\n verification.\n- **Events** use smrt-jobs' delivery inbox under provider\n `<name>-billing:<sellerTenantId>` and a provider-filtered\n `ForgeProjectionRuntime`, so a runtime never claims another seller's\n events; any other runtime sharing the inbox must pass `providers` too. Only\n events this package acts on are stored: foreign checkouts are `ignored`,\n and only `smrt_*` checkout metadata is kept; it is\n HMAC-signed with the webhook secret at creation (empty values are omitted:\n Stripe drops them), so another integration on the same account cannot forge\n a credit purchase or a card setup; credit is granted only when the\n collected total equals it plus provider tax. Checkout amounts come from the\n re-read session (`getCheckout()`), never the Stripe event, whose amounts are\n in Stripe's unit. Rotating the webhook secret strands in-flight checkouts\n (up to 24 h). `observe()` re-reads provider state, so ordering never depends\n on delivery order; the only provider writes in `observe()` are idempotent\n (making a saved card the default). The standing hook runs inside the event\n transaction and must be idempotent.\n- **Card on file and top-ups (#3139).** A saved card is the payer customer's\n default `PaymentInstrument` (seller tenant, id from the provider method).\n `autoChargeInvoices` bills such payers `charge_automatically`, decided once\n and saved as `Invoice.collectionMethod` before the first push, which every\n retry reuses (never recompute it: a lost push response would record a\n method the provider was not asked for, #3190); activation follows `paid`, never send. An auto top-up attempt\n is a `PENDING` `Payment` (`reference` `auto-top-up:<policyId>`, id from the\n policy and `count()` of its attempts) inserted before the charge, so racing\n evaluations derive one id and one charge; the charge key is derived from\n that id. `applyAutoTopUpOutcome()` must run in a transaction and starts with\n a conditional `UPDATE … WHERE status = 'pending'` row lock, so the hook and\n the `payment` webhook settle once; the grant is keyed by the charge key.\n Never settle an attempt outside that function. Taxed accounts are charged\n with provider tax by default (#3194): the attempt row holds the credit\n (the charge subtotal), the tax is journaled to tax payable at settlement,\n and the attempt's tax decision is recorded in its `notes` so a re-drive\n repeats the same charge request (the provider refuses a key reused with\n different tax). `claimAttempt()` is the only place that decides a\n skip and reports it (`onAutoTopUpSkipped`); `cardOnFile()` and period close\n use `defaultCardInstrument()` — never copy that predicate. A provider write-off moves the local invoice to\n `WRITTEN_OFF` (a later payment, by card or on a rail (#3188), is recorded\n and reinstates the payer; the status stays, so \"paid in full\" for a\n written-off invoice is read from its allocations).\n- **`Invoice.providerTaxAmount`** is added to line-item tax; it is\n server-managed (not API-writable). `toAccountingInput()` emits major units.\n- **Payment rails (#3138).** A runtime has one issuing `provider` and any\n number of `paymentProviders` (unique names, one inbox namespace each; a\n provider with `capabilities.issuesInvoices === false` can never issue).\n `observe()` resolves the provider from the delivery namespace, never the\n payload. Crypto rails implement the port over `@happyvertical/payments`'\n `CryptoCheckoutGateway`; never call BTCPay (or any gateway) from here.\n Settlement is decided by the pure `decideAttempt()` from gateway state and\n `paymentPolicy` — the gateway's `settled` is authoritative and nothing here\n counts confirmations. A `BillingPaymentAttempt` (`(provider, checkout_id)`\n deterministic id) records every state and settles once; grants and payments\n are keyed by checkout id. Invoice payments close the issuer's invoice out of\n band in `observe()` (idempotent) before `project()` records the payment, and\n `settlePaidInvoice` skips (records nothing for) a `paidOutOfBand` invoice\n the rail latched with `outOfBandRequestedAt`; other out-of-band closes are\n recorded as `OTHER` payments. Rails never save cards or charge tax: a taxed\n credit purchase on a rail needs an explicit `automaticTax: false`. Exceptions are flags for operators;\n nothing reverses or refunds automatically.\n- **Known limits**: write-offs post no bad-debt journal (AR stays until paid\n or journaled by an operator); discounts still reach Stripe as negative lines (the SDK's\n line `discount` would change the lines a replayed push reconciles, so it\n needs its own migration); `RetailCharge` has no adjustment ledger. Flat\n plans are monthly, in arrears; plan changes are not prorated (#3119).\n\n## Cross-Package References\n\n- `customerId` → `@foreignKey('Customer')` (hard reference within package)\n- `profileId` → plain string to smrt-profiles\n- `arJournalId`, `revenueJournalId` → plain string to smrt-ledgers\n- `skuId` (on `PaymentIntent`, `LicenseSale`) → plain string to smrt-products\n- `paymentId` (on `PaymentIntent`, `Payout`, `LicenseSale`) → plain string to `Payment` (same package, but kept as plain string for cross-model consistency)\n- `vendorId` on `Payout` → `@foreignKey(Vendor)` (hard reference within package)\n- Billing records reference tenants with `@crossPackageRef('@happyvertical/smrt-users:Tenant')` and charges, plan periods, and adjustments by plain `sourceId`\n\n## Gotchas\n\n- **Optional tenancy**: all models `@TenantScoped({ mode: 'optional' })` + nullable tenantId\n- **Currency is integer minor units** (cents, satoshis) — `$19.99` is `1999`, like affiliates. Money is exact, so money fields initialize `= 0`, never `= 0.0`: the integer literal is what maps them to INTEGER columns (BIGINT on fresh PostgreSQL/DuckDB databases). Writing a fractional major-unit value is the bug — the model rejects it via `assertIntegerMinorUnits` on `Invoice`/`Payment`/`PaymentAllocation`/`Payout`/`Contract` before the database sees it, because PostgreSQL would reject it with `22P02` while SQLite's affinity silently stores it. `pnpm --filter @happyvertical/smrt-commerce test:postgres` is the lane that holds the line (#2361, #2401, #2373).\n- **Rates are the opposite**: `InvoiceLineItem.taxRate` and `ContractLineItem.taxRate` are inherently fractional and must initialize `= 0.0`. INTEGER would truncate every rate to 0. `ContractLineItem.quantity` is decimal for the same reason (contracts price fractional hours/weight/bandwidth); `InvoiceLineItem.quantity` is also decimal (six fractional places); existing integer columns require the explicit [quantity migration](agents/invoice-quantity.md).\n- **Rounding happens where a rate meets money, and nowhere else**: `InvoiceLineItem` uses exact shared invoice arithmetic to round fractional quantity × price and then tax to minor units; `ContractLineItem.calculateAmount()` uses `Math.round()` for tax. Everything downstream is exact integer arithmetic, which is why **there are no `EPSILON` tolerances left on any money path** (#2401). `Invoice`, `PaymentAllocation`, `Payout` and `PaymentIntent` compare with `===` / `>` / `>=`. Do not reintroduce a tolerance: against integers it forgives a real one-cent discrepancy rather than float fuzz. (`FulfillmentLineItem`'s quantity epsilon is unrelated — quantities are genuinely decimal there.)\n- **Migrating an existing database to minor units**: `preflightCommerceMoneyMinorUnits(db)` reports, per column, whether it still holds major units and which rows would be rounded or exceed JavaScript's safe-integer range; `migrateCommerceMoneyToMinorUnits(db)` converts them. Both are exported from the package root. The rescale is idempotent via a `_smrt_backfills` marker, changes the column type in place on PostgreSQL/DuckDB (`ALTER … TYPE BIGINT USING round(col * 100)`), and on SQLite rescales values only — SQLite cannot alter a declared type in place, so those columns come back in `declaredTypeChangePending` and need the table-rebuild path (#2370).\n- **`Payment.nativeAmount` is NOT in that migration, and must not be.** Its minor unit is a property of the *row's asset*: satoshis on a BTC rail (×1e8), cents on a fiat or stablecoin rail (×1e2), in one column discriminated only by `nativeCurrency`. A blanket ×100 turns 0.00713 BTC into `1` instead of `713000` sats, and a round 0.01 BTC even passes the preflight's integrality check while being wrong by six orders of magnitude. Convert it in two deliberate steps — normalise each row to its own asset's minor units while the column is still floating-point, then `rescaleMoneyColumnsToMinorUnits(db, COMMERCE_NATIVE_UNIT_COLUMNS, { scale: 1, … })` for the type change. `COMMERCE_NATIVE_UNIT_COLUMNS` is exported with a worked example; step one is deliberately the deployment's to write, because only it knows which `nativeCurrency` values it has used.\n- **`PaymentIntent.paymentOptions[].nativeAmount` has the same per-asset problem inside a JSON column and is likewise not migrated.** An intent's price lock defaults to 15 minutes, so the supported answer is to let open intents expire and be re-quoted: an unconverted option fails the exact `!==` reconciliation against the payment that arrives, which is a loud failure rather than a silently mis-scaled quote.\n- **Range and existing deployments**: fresh PostgreSQL/DuckDB INTEGER columns are BIGINT, and the runtime rejects values outside JavaScript's safe-integer range rather than rounding them. Existing PostgreSQL `int4` columns do not self-repair; widen them through the explicit migration tracked in #2424.\n- **Journals posted from commerce carry minor units**: `Payment.recordPayment()` and `Invoice.recognizeRevenue()` write `amount` / `totalAmount` straight into smrt-ledgers entries. smrt-ledgers is unit-agnostic (its `BALANCE_EPSILON` only checks debits === credits), and integer entries balance exactly, so this is strictly tighter than the major-unit journals commerce used to post.\n- **Invoice controls payment status**: not the Payment model — use `Invoice.updatePaymentStatus()`\n- **Tax rate is external**: no tax rate field on Invoice — rate must be calculated externally\n- **Profile linking**: separate `ProfileCollection.create()` needed to fetch actual Profile object\n- **PaymentIntent natural key**: `conflictColumns: ['tenant_id', 'offering_ref', 'licensee_email', 'idempotency_key']` — a retried `create` with the same tuple upserts the existing row. Use `getOrCreateByIdempotencyKey()` to branch on `{ intent, created }`. Empty natural-key inputs (e.g. blank `idempotencyKey`) disable dedup by design.\n- **Payout state-machine guards**: `markSent` requires a non-empty `backendTxRef`; `markConfirmed` only valid from `SENT`; `markFailed` only valid from `PENDING` / `SENT` (a confirmed payout can't fail — that path is a refund). `resetFromFailed()` is the dedicated escape hatch from `FAILED` back to `PENDING` after an operator fixes the underlying problem; it clears `backendTxRef` so the next attempt picks up a fresh one.\n- **PaymentInstrument defaults**: `isDefault` is domain-managed, not API-writable. Call `setDefaultForCustomer(customerId, instrumentId)` so the target is validated and the customer's other instruments are cleared.\n- **LicenseSale immutability**: rights snapshot freezes on save-with-status-ACCEPTED. The captured snapshot lives in a module-scoped `WeakMap<LicenseSale, string>` so it doesn't interact with the schema or round-trip through `_meta_data`. Drafts (status != ACCEPTED) remain mutable. To \"change\" an issued license: `revoke()` it, then issue a new `LicenseSale` row.\n- **Vendor.payoutAddresses normalization**: the constructor accepts either a `Record<string, string>` or a pre-serialized JSON string. `initialize()` re-normalizes after the framework's option-override pass; `save()` re-normalizes defensively against direct field assignment. Non-string values inside the input map are silently dropped to preserve the typed invariant downstream.\n\n## Commercial UI\n\nSee [commercial UI composition](agents/commercial-ui.md) for native form recovery, amount compatibility and backend ownership. Package-owned guides under `agents/` ship with the package.\n\n## Quote and estimate UI\n\n`src/svelte/quote-types.ts` separates unparsed draft strings from explicit\nminor-unit revision DTOs. Native row submitters, caller-owned retry identity and\nextension conventions are documented in [agents/quote-ui.md](agents/quote-ui.md).\n\n## Purchasing UI\n\n`PurchaseOrderEditor` preserves allocation IDs and explicit zeroes, including\nretained reduction rows; the server validates review fingerprints before recording.\nSee [agents/purchasing-ui.md](agents/purchasing-ui.md) for caller responsibilities.\n",
|
|
19520
19679
|
"moduleDocs": [
|
|
19521
19680
|
{
|
|
19522
19681
|
"path": "agents/invoice-quantity.md",
|
|
@@ -19538,5 +19697,190 @@
|
|
|
19538
19697
|
"module": "purchasing-ui",
|
|
19539
19698
|
"content": "# Purchasing and award presentation\n\nPublic `@happyvertical/smrt-commerce/svelte` exports `PurchaseSourceSelector`,\n`PurchaseOrderEditor`, their Props and `Purchase*` DTOs. Registry slots are\n`purchase-source-selector` and `purchase-order-editor`. Interactive playground\nentries cover ordinary amendment and explicit retained-allocation reduction.\n\nThese components use public Commerce PurchaseOrder/Contract as their owning\nfinancial domain without adding a backend command, ledger or fixed approval\npolicy. The caller decides instrument options, source availability, allocation\nlabels, prior commitments, reviewed actuals, floors/ceilings and exact source\nidentity. Construction work packages, accepted budgets, contractor entitlement\nand vendor award policy stay in the consumer. Capability/disabled props only\ncontrol presentation. Every POST needs authoritative server authorization.\n\n`PurchaseSourceSelector` uses a native GET to the supplied action with `name`\n(default `source`) and optional hidden search/context fields. It never writes an\naward. Disabled sources remain visible with caller notices; unknown saved IDs\nremain visible as unavailable. Keep source selection outside a reduction form;\nthe server must reject a downward amendment under an ordinary amendment mode\nand enforce the retained source/instrument during reductions.\n\n`PurchaseOrderEditor` receives `operation` (`create`, `amend`, `reduce`), a\nretained `source`, `currency`, explicit `minorUnitDigits`, raw `values`,\n`instruments`, native POST `action`, and caller-owned `hiddenFields`. Supply\nsource ID, currency, predecessor, tenant and retry IDs in those hidden fields\nunder the exact names your endpoint expects. `names` adapts all built-in fields.\n`labels` adapts approval language; `extensions` and `attachments` compose domain\nfields and authorized Assets evidence without fetching bytes in this component.\n`formAttributes` supports native encoding/ID and caller-owned form-retry Svelte\nattachments; `onsubmit` supports caller transport enhancement. Tokens are never\nminted or rotated here. See the shared [form/action contract](commercial-ui.md)\nand repository `docs/content/form-retry.md`.\n\nAll editable money is **raw major-unit text**, including malformed values and\nempty unknown amounts. The caller parses against the exact currency contract;\nthere is no UI floating-point calculation or implicit blank-to-zero conversion.\nSaved/source/review numbers are safe integer minor units formatted by the\nshared quotation helper. `sourceMinor: null` renders Unknown. Displayed bounds\nare guidance; the server validates floors, ceilings and source eligibility.\n\nEvery allocation posts its stable `id` and amount, even when zero. Mark every\npredecessor allocation `retained: true`. A `reduce` form requires those amounts\nexplicitly and never offers their removal. Supplying fewer predecessor rows is\nnot safe: the server must compare the complete ID set and reject omissions.\nOptional `rowActions` uses native formnovalidate add/remove POSTs carrying all\ncurrent fields; the caller re-renders unchanged rejected strings and IDs.\nNew-row IDs belong to the caller. Row editing never records a commitment.\n\nPressing Enter in an input activates review or record, preserving draft rows.\nExplicit add/remove actions remain available without JavaScript.\nDefault submitter `intent` values are `review`, `record`, `edit`, all configurable.\nOnly a caller-produced `review` snapshot or a retained `retryFingerprint` exposes\nexplicit confirmation. `review.fingerprint` posts under `reviewFingerprint` by\ndefault. After an uncertain outcome, re-render the exact submitted values,\nrequest identity and fingerprint; never fabricate a new intent/token. Confirmation\nis an unchecked required checkbox on native renders and when a new review\nfingerprint arrives in a hydrated form. Its value defaults to\n`yes`. The server must bind fingerprint to all submitted values and authority,\nreject changed/stale review data, and replay identical committed retries.\nRendering a review snapshot or selecting a source never accepts/records anything.\n\nValidation: `pnpm --filter @happyvertical/smrt-commerce exec vitest run --config\nvitest.purchasing.config.ts`, owning build/typecheck/pack checks, and the shared\nquote native/hydrated browser harness with `QUOTE_BROWSER_EXTENSION` pointing at\n`packages/commerce/test-support/purchasing-browser-extension.mjs`. Full repository\nCI/E2E is consolidated at the #3423 release boundary by owner instruction.\n\nInvalid or unsafe display amounts/scales render localized unavailable text.\nStrict money helpers continue to reject malformed data; presentation recovery\ndoes not validate or authorize submitted money.\n\nThe `attachments` snippet renders outside the editor form so an Assets\n`AttachmentPanel`/`AttachmentUpload` keeps its own multipart action and request\nidentity. The attachment region remains disabled while the editor is read-only\nor busy. Use `extensions` only for controls belonging to the editor submission;\nnever place another form there.\n\nComposition regression: run the quote SSR lane, then the maintained quote browser\nhost with `QUOTE_BROWSER_EXTENSION=packages/commerce/test-support/quote-attachments-browser.mjs`.\nIt submits actual Assets upload bytes and the separate editor action with and\nwithout JavaScript at 390px.\n"
|
|
19540
19699
|
}
|
|
19700
|
+
],
|
|
19701
|
+
"recipes": [
|
|
19702
|
+
{
|
|
19703
|
+
"id": "commerce.customers",
|
|
19704
|
+
"className": "CustomersRecipe",
|
|
19705
|
+
"label": "Customers",
|
|
19706
|
+
"summary": "Keep a list of the customers you sell to.",
|
|
19707
|
+
"synonyms": [
|
|
19708
|
+
"clients",
|
|
19709
|
+
"buyers",
|
|
19710
|
+
"accounts"
|
|
19711
|
+
],
|
|
19712
|
+
"models": [
|
|
19713
|
+
"@happyvertical/smrt-commerce:Customer"
|
|
19714
|
+
],
|
|
19715
|
+
"nav": [
|
|
19716
|
+
{
|
|
19717
|
+
"label": "Customers",
|
|
19718
|
+
"model": "@happyvertical/smrt-commerce:Customer"
|
|
19719
|
+
}
|
|
19720
|
+
],
|
|
19721
|
+
"requires": [],
|
|
19722
|
+
"help": {
|
|
19723
|
+
"markdown": "## Overview\n\nCustomers is your address book for the people and businesses you sell to. Keep\none record for each customer so you can see who they are, how they like to pay\nand what you have agreed with them, then refer back to them whenever you take an\norder.\n\n## Tasks\n\n### Add a new customer\n\n1. Choose the **New** button above the list.\n2. Describe the customer with **{field:customerType}**: a direct shopper, a\n wholesale buyer or a retail customer. Note in **{field:status}** whether you\n are still dealing with them.\n3. Fill in the **{field:defaultShippingAddress}** and\n **{field:defaultBillingAddress}** so you do not have to type them again on\n every order.\n4. Add **{field:paymentTerms}**, for example \"Net 30\", if you give this\n customer time to pay.\n5. Save. The customer is now on your list and ready to use on a sales order.\n\n### Keep track of what a customer can owe\n\n1. Open the customer from the list and choose Edit.\n2. Set **{field:creditLimit}** to the most you are comfortable letting them owe\n you at one time.\n3. If you do not charge them sales tax, turn on **{field:taxExempt}**, and keep\n their tax number on file.\n4. Use **{field:notes}** for anything the next person who deals with this\n customer should know.\n\n### Find a customer\n\nScan the list for the customer you want, or open a record to see everything you\nhave on file. To stop dealing with someone without losing their history, change\ntheir **{field:status}** to inactive instead of deleting them.\n",
|
|
19724
|
+
"fieldRefs": [
|
|
19725
|
+
"creditLimit",
|
|
19726
|
+
"customerType",
|
|
19727
|
+
"defaultBillingAddress",
|
|
19728
|
+
"defaultShippingAddress",
|
|
19729
|
+
"notes",
|
|
19730
|
+
"paymentTerms",
|
|
19731
|
+
"status",
|
|
19732
|
+
"taxExempt"
|
|
19733
|
+
]
|
|
19734
|
+
}
|
|
19735
|
+
},
|
|
19736
|
+
{
|
|
19737
|
+
"id": "commerce.purchases",
|
|
19738
|
+
"className": "PurchasesRecipe",
|
|
19739
|
+
"label": "Purchases",
|
|
19740
|
+
"summary": "Place orders with vendors and track them.",
|
|
19741
|
+
"synonyms": [
|
|
19742
|
+
"purchase orders",
|
|
19743
|
+
"buying",
|
|
19744
|
+
"procurement"
|
|
19745
|
+
],
|
|
19746
|
+
"models": [
|
|
19747
|
+
"@happyvertical/smrt-commerce:PurchaseOrder"
|
|
19748
|
+
],
|
|
19749
|
+
"nav": [
|
|
19750
|
+
{
|
|
19751
|
+
"label": "Purchase Orders",
|
|
19752
|
+
"model": "@happyvertical/smrt-commerce:PurchaseOrder"
|
|
19753
|
+
}
|
|
19754
|
+
],
|
|
19755
|
+
"requires": [
|
|
19756
|
+
"commerce.vendors"
|
|
19757
|
+
],
|
|
19758
|
+
"options": {
|
|
19759
|
+
"@happyvertical/smrt-commerce:PurchaseOrder": {
|
|
19760
|
+
"fields": {
|
|
19761
|
+
"contractType": {
|
|
19762
|
+
"default": "purchase_order",
|
|
19763
|
+
"visibility": "hidden",
|
|
19764
|
+
"locked": true
|
|
19765
|
+
},
|
|
19766
|
+
"customerId": {
|
|
19767
|
+
"visibility": "hidden",
|
|
19768
|
+
"locked": true
|
|
19769
|
+
},
|
|
19770
|
+
"vendorId": {
|
|
19771
|
+
"label": "Vendor",
|
|
19772
|
+
"order": 1
|
|
19773
|
+
}
|
|
19774
|
+
}
|
|
19775
|
+
}
|
|
19776
|
+
},
|
|
19777
|
+
"help": {
|
|
19778
|
+
"markdown": "## Overview\n\nPurchases is where you order from your vendors and keep track of what you have\nbought. Every purchase order belongs to one of your vendors and records the\namounts, the dates and where the order stands.\n\n## Tasks\n\n### Place a purchase order\n\n1. Choose the **New** button above the list.\n2. Enter the **{field:vendorId}** you are buying from. Add them under Vendors\n first so they are on your list.\n3. Enter the **{field:subtotal}** and **{field:taxAmount}**, then the\n **{field:totalAmount}** you expect to pay.\n4. Set the **{field:issueDate}**, and the **{field:dueDate}** for when the\n goods or the payment are due.\n5. Add your own **{field:reference}**, such as the vendor's quote number, so\n you can match it to their paperwork.\n6. Save.\n\n### Follow an order until it arrives\n\n1. Open the purchase order from the list and choose Edit.\n2. Update **{field:status}** as the order moves along, for example from draft to\n sent, accepted and completed.\n3. Use **{field:notes}** to record what the vendor told you, such as delays or\n partial shipments.\n\n### Record the agreement\n\n1. Open the purchase order and choose Edit.\n2. Write down the **{field:terms}** you agreed with the vendor, such as payment\n or delivery conditions.\n3. Set **{field:expiryDate}** if the vendor's offer is only good until a certain\n day.\n",
|
|
19779
|
+
"fieldRefs": [
|
|
19780
|
+
"dueDate",
|
|
19781
|
+
"expiryDate",
|
|
19782
|
+
"issueDate",
|
|
19783
|
+
"notes",
|
|
19784
|
+
"reference",
|
|
19785
|
+
"status",
|
|
19786
|
+
"subtotal",
|
|
19787
|
+
"taxAmount",
|
|
19788
|
+
"terms",
|
|
19789
|
+
"totalAmount",
|
|
19790
|
+
"vendorId"
|
|
19791
|
+
]
|
|
19792
|
+
}
|
|
19793
|
+
},
|
|
19794
|
+
{
|
|
19795
|
+
"id": "commerce.sales",
|
|
19796
|
+
"className": "SalesRecipe",
|
|
19797
|
+
"label": "Sales",
|
|
19798
|
+
"summary": "Take customer orders and track them.",
|
|
19799
|
+
"synonyms": [
|
|
19800
|
+
"sales orders",
|
|
19801
|
+
"orders",
|
|
19802
|
+
"customer orders"
|
|
19803
|
+
],
|
|
19804
|
+
"models": [
|
|
19805
|
+
"@happyvertical/smrt-commerce:Order"
|
|
19806
|
+
],
|
|
19807
|
+
"nav": [
|
|
19808
|
+
{
|
|
19809
|
+
"label": "Sales Orders",
|
|
19810
|
+
"model": "@happyvertical/smrt-commerce:Order"
|
|
19811
|
+
}
|
|
19812
|
+
],
|
|
19813
|
+
"requires": [
|
|
19814
|
+
"commerce.customers"
|
|
19815
|
+
],
|
|
19816
|
+
"options": {
|
|
19817
|
+
"@happyvertical/smrt-commerce:Order": {
|
|
19818
|
+
"fields": {
|
|
19819
|
+
"contractType": {
|
|
19820
|
+
"default": "order",
|
|
19821
|
+
"visibility": "hidden",
|
|
19822
|
+
"locked": true
|
|
19823
|
+
},
|
|
19824
|
+
"vendorId": {
|
|
19825
|
+
"visibility": "hidden",
|
|
19826
|
+
"locked": true
|
|
19827
|
+
},
|
|
19828
|
+
"customerId": {
|
|
19829
|
+
"label": "Customer",
|
|
19830
|
+
"order": 1
|
|
19831
|
+
}
|
|
19832
|
+
}
|
|
19833
|
+
}
|
|
19834
|
+
},
|
|
19835
|
+
"help": {
|
|
19836
|
+
"markdown": "## Overview\n\nSales is where you take orders from your customers and see where each one\nstands. Every order belongs to one of your customers, carries its amounts and\ndates, and keeps a status so you always know what is still open.\n\n## Tasks\n\n### Take an order\n\n1. Choose the **New** button above the list.\n2. Enter the **{field:customerId}** the order is for. Add them under Customers\n first so they are on your list.\n3. Enter the **{field:subtotal}** and **{field:taxAmount}**, then the\n **{field:totalAmount}** the customer will pay.\n4. Set the **{field:issueDate}**, and the **{field:dueDate}** if you expect\n payment by a certain day.\n5. Add your own **{field:reference}**, such as a purchase order number the\n customer gave you, so you can find the order later.\n6. Save.\n\n### Follow an order through to the end\n\n1. Open the order from the list and choose Edit.\n2. Update **{field:status}** as the order moves along, for example from draft to\n sent, accepted and completed.\n3. Check the **{field:dueDate}** against today to spot orders that are overdue.\n4. Use **{field:notes}** to record calls, changes and anything promised.\n\n### Make a quote with an expiry\n\n1. Create the order as usual and set its **{field:status}** to show it is still\n a draft.\n2. Set **{field:expiryDate}** to the last day the price is good for.\n3. Put your conditions, such as deposits or delivery, in **{field:terms}**.\n",
|
|
19837
|
+
"fieldRefs": [
|
|
19838
|
+
"customerId",
|
|
19839
|
+
"dueDate",
|
|
19840
|
+
"expiryDate",
|
|
19841
|
+
"issueDate",
|
|
19842
|
+
"notes",
|
|
19843
|
+
"reference",
|
|
19844
|
+
"status",
|
|
19845
|
+
"subtotal",
|
|
19846
|
+
"taxAmount",
|
|
19847
|
+
"terms",
|
|
19848
|
+
"totalAmount"
|
|
19849
|
+
]
|
|
19850
|
+
}
|
|
19851
|
+
},
|
|
19852
|
+
{
|
|
19853
|
+
"id": "commerce.vendors",
|
|
19854
|
+
"className": "VendorsRecipe",
|
|
19855
|
+
"label": "Vendors",
|
|
19856
|
+
"summary": "Keep a list of the vendors and suppliers you buy from.",
|
|
19857
|
+
"synonyms": [
|
|
19858
|
+
"suppliers",
|
|
19859
|
+
"sellers"
|
|
19860
|
+
],
|
|
19861
|
+
"models": [
|
|
19862
|
+
"@happyvertical/smrt-commerce:Vendor"
|
|
19863
|
+
],
|
|
19864
|
+
"nav": [
|
|
19865
|
+
{
|
|
19866
|
+
"label": "Vendors",
|
|
19867
|
+
"model": "@happyvertical/smrt-commerce:Vendor"
|
|
19868
|
+
}
|
|
19869
|
+
],
|
|
19870
|
+
"requires": [],
|
|
19871
|
+
"help": {
|
|
19872
|
+
"markdown": "## Overview\n\nVendors is your list of the suppliers you buy from. Each record holds who they\nare, how to reach them and the terms you have agreed, so you can order from them\nquickly and keep track of what you have bought.\n\n## Tasks\n\n### Add a vendor\n\n1. Choose the **New** button above the list.\n2. Enter **{field:defaultContactEmail}** and **{field:defaultContactPhone}** for\n the person you normally deal with.\n3. Set the **{field:currency}** they bill you in and your **{field:paymentTerms}**,\n for example \"Net 30\".\n4. Save. The vendor is now on your list and ready to use on a purchase order.\n\n### Note how a vendor likes to work\n\n1. Open the vendor from the list and choose Edit.\n2. Enter **{field:leadTimeDays}**, the number of days they usually need between\n your order and delivery, so you can plan ahead.\n3. Enter **{field:minimumOrderAmount}** if they will not accept small orders.\n4. Use **{field:notes}** for anything else worth remembering, such as the best\n time to call.\n\n### Keep payment details in one place\n\n1. Open the vendor and choose Edit.\n2. Record where payments to this vendor should be sent, so it is all in one\n place.\n3. Set **{field:status}** to show whether you still buy from them: active,\n inactive or suspended.\n",
|
|
19873
|
+
"fieldRefs": [
|
|
19874
|
+
"currency",
|
|
19875
|
+
"defaultContactEmail",
|
|
19876
|
+
"defaultContactPhone",
|
|
19877
|
+
"leadTimeDays",
|
|
19878
|
+
"minimumOrderAmount",
|
|
19879
|
+
"notes",
|
|
19880
|
+
"paymentTerms",
|
|
19881
|
+
"status"
|
|
19882
|
+
]
|
|
19883
|
+
}
|
|
19884
|
+
}
|
|
19541
19885
|
]
|
|
19542
19886
|
}
|