@happyvertical/smrt-commerce 0.40.70 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -2
- package/README.md +8 -8
- package/dist/chunks/money-WSMvSgWq.js +8 -0
- package/dist/chunks/money-WSMvSgWq.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +297 -115
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +613 -387
- package/dist/migrations/moneyMinorUnits.d.ts +86 -0
- package/dist/migrations/moneyMinorUnits.d.ts.map +1 -0
- package/dist/models/Contract.d.ts +19 -9
- package/dist/models/Contract.d.ts.map +1 -1
- package/dist/models/ContractLineItem.d.ts +21 -7
- package/dist/models/ContractLineItem.d.ts.map +1 -1
- package/dist/models/Customer.d.ts +7 -1
- package/dist/models/Customer.d.ts.map +1 -1
- package/dist/models/Invoice.d.ts +43 -37
- package/dist/models/Invoice.d.ts.map +1 -1
- package/dist/models/InvoiceLineItem.d.ts +34 -10
- package/dist/models/InvoiceLineItem.d.ts.map +1 -1
- package/dist/models/Payment.d.ts +31 -11
- package/dist/models/Payment.d.ts.map +1 -1
- package/dist/models/PaymentAllocation.d.ts +9 -2
- package/dist/models/PaymentAllocation.d.ts.map +1 -1
- package/dist/models/PaymentIntent.d.ts +7 -2
- package/dist/models/PaymentIntent.d.ts.map +1 -1
- package/dist/models/Payout.d.ts +15 -10
- package/dist/models/Payout.d.ts.map +1 -1
- package/dist/models/Vendor.d.ts +3 -1
- package/dist/models/Vendor.d.ts.map +1 -1
- package/dist/money.d.ts +27 -0
- package/dist/money.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +155 -93
- package/package.json +8 -7
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.
|
|
6
|
+
"packageVersion": "0.41.0",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
10
|
+
"manifest": "46c5eaaae97f2c1daa76b6ca5997adfdfe97e4380af9b2af84c9b7178338a325",
|
|
11
|
+
"packageJson": "641681852d15c8d85afaa5ecae3690ce81b2f33c0596ab4d0a97b5a4bd1689f6",
|
|
12
|
+
"agents": "0779ea7ef940bbdd32682920ad6ce6e95e402337a9e22c7db24361f5c302527d"
|
|
13
13
|
},
|
|
14
14
|
"exports": [
|
|
15
15
|
".",
|
|
@@ -1434,23 +1434,23 @@
|
|
|
1434
1434
|
},
|
|
1435
1435
|
{
|
|
1436
1436
|
"name": "subtotal",
|
|
1437
|
-
"type": "
|
|
1437
|
+
"type": "integer",
|
|
1438
1438
|
"required": false,
|
|
1439
|
-
"columnType": "
|
|
1439
|
+
"columnType": "INTEGER",
|
|
1440
1440
|
"default": 0
|
|
1441
1441
|
},
|
|
1442
1442
|
{
|
|
1443
1443
|
"name": "taxAmount",
|
|
1444
|
-
"type": "
|
|
1444
|
+
"type": "integer",
|
|
1445
1445
|
"required": false,
|
|
1446
|
-
"columnType": "
|
|
1446
|
+
"columnType": "INTEGER",
|
|
1447
1447
|
"default": 0
|
|
1448
1448
|
},
|
|
1449
1449
|
{
|
|
1450
1450
|
"name": "totalAmount",
|
|
1451
|
-
"type": "
|
|
1451
|
+
"type": "integer",
|
|
1452
1452
|
"required": false,
|
|
1453
|
-
"columnType": "
|
|
1453
|
+
"columnType": "INTEGER",
|
|
1454
1454
|
"default": 0
|
|
1455
1455
|
},
|
|
1456
1456
|
{
|
|
@@ -1869,6 +1869,12 @@
|
|
|
1869
1869
|
"field": "tenantId"
|
|
1870
1870
|
},
|
|
1871
1871
|
"tableStrategy": "sti",
|
|
1872
|
+
"conflictColumns": [
|
|
1873
|
+
"tenant_id",
|
|
1874
|
+
"slug",
|
|
1875
|
+
"context",
|
|
1876
|
+
"_meta_type"
|
|
1877
|
+
],
|
|
1872
1878
|
"surfaces": [
|
|
1873
1879
|
{
|
|
1874
1880
|
"kind": "api",
|
|
@@ -2006,23 +2012,23 @@
|
|
|
2006
2012
|
},
|
|
2007
2013
|
{
|
|
2008
2014
|
"name": "subtotal",
|
|
2009
|
-
"type": "
|
|
2015
|
+
"type": "integer",
|
|
2010
2016
|
"required": false,
|
|
2011
|
-
"columnType": "
|
|
2017
|
+
"columnType": "INTEGER",
|
|
2012
2018
|
"default": 0
|
|
2013
2019
|
},
|
|
2014
2020
|
{
|
|
2015
2021
|
"name": "taxAmount",
|
|
2016
|
-
"type": "
|
|
2022
|
+
"type": "integer",
|
|
2017
2023
|
"required": false,
|
|
2018
|
-
"columnType": "
|
|
2024
|
+
"columnType": "INTEGER",
|
|
2019
2025
|
"default": 0
|
|
2020
2026
|
},
|
|
2021
2027
|
{
|
|
2022
2028
|
"name": "totalAmount",
|
|
2023
|
-
"type": "
|
|
2029
|
+
"type": "integer",
|
|
2024
2030
|
"required": false,
|
|
2025
|
-
"columnType": "
|
|
2031
|
+
"columnType": "INTEGER",
|
|
2026
2032
|
"default": 0
|
|
2027
2033
|
},
|
|
2028
2034
|
{
|
|
@@ -2503,23 +2509,23 @@
|
|
|
2503
2509
|
},
|
|
2504
2510
|
{
|
|
2505
2511
|
"name": "subtotal",
|
|
2506
|
-
"type": "
|
|
2512
|
+
"type": "integer",
|
|
2507
2513
|
"required": false,
|
|
2508
|
-
"columnType": "
|
|
2514
|
+
"columnType": "INTEGER",
|
|
2509
2515
|
"default": 0
|
|
2510
2516
|
},
|
|
2511
2517
|
{
|
|
2512
2518
|
"name": "taxAmount",
|
|
2513
|
-
"type": "
|
|
2519
|
+
"type": "integer",
|
|
2514
2520
|
"required": false,
|
|
2515
|
-
"columnType": "
|
|
2521
|
+
"columnType": "INTEGER",
|
|
2516
2522
|
"default": 0
|
|
2517
2523
|
},
|
|
2518
2524
|
{
|
|
2519
2525
|
"name": "totalAmount",
|
|
2520
|
-
"type": "
|
|
2526
|
+
"type": "integer",
|
|
2521
2527
|
"required": false,
|
|
2522
|
-
"columnType": "
|
|
2528
|
+
"columnType": "INTEGER",
|
|
2523
2529
|
"default": 0
|
|
2524
2530
|
},
|
|
2525
2531
|
{
|
|
@@ -3000,23 +3006,23 @@
|
|
|
3000
3006
|
},
|
|
3001
3007
|
{
|
|
3002
3008
|
"name": "subtotal",
|
|
3003
|
-
"type": "
|
|
3009
|
+
"type": "integer",
|
|
3004
3010
|
"required": false,
|
|
3005
|
-
"columnType": "
|
|
3011
|
+
"columnType": "INTEGER",
|
|
3006
3012
|
"default": 0
|
|
3007
3013
|
},
|
|
3008
3014
|
{
|
|
3009
3015
|
"name": "taxAmount",
|
|
3010
|
-
"type": "
|
|
3016
|
+
"type": "integer",
|
|
3011
3017
|
"required": false,
|
|
3012
|
-
"columnType": "
|
|
3018
|
+
"columnType": "INTEGER",
|
|
3013
3019
|
"default": 0
|
|
3014
3020
|
},
|
|
3015
3021
|
{
|
|
3016
3022
|
"name": "totalAmount",
|
|
3017
|
-
"type": "
|
|
3023
|
+
"type": "integer",
|
|
3018
3024
|
"required": false,
|
|
3019
|
-
"columnType": "
|
|
3025
|
+
"columnType": "INTEGER",
|
|
3020
3026
|
"default": 0
|
|
3021
3027
|
},
|
|
3022
3028
|
{
|
|
@@ -3497,23 +3503,23 @@
|
|
|
3497
3503
|
},
|
|
3498
3504
|
{
|
|
3499
3505
|
"name": "subtotal",
|
|
3500
|
-
"type": "
|
|
3506
|
+
"type": "integer",
|
|
3501
3507
|
"required": false,
|
|
3502
|
-
"columnType": "
|
|
3508
|
+
"columnType": "INTEGER",
|
|
3503
3509
|
"default": 0
|
|
3504
3510
|
},
|
|
3505
3511
|
{
|
|
3506
3512
|
"name": "taxAmount",
|
|
3507
|
-
"type": "
|
|
3513
|
+
"type": "integer",
|
|
3508
3514
|
"required": false,
|
|
3509
|
-
"columnType": "
|
|
3515
|
+
"columnType": "INTEGER",
|
|
3510
3516
|
"default": 0
|
|
3511
3517
|
},
|
|
3512
3518
|
{
|
|
3513
3519
|
"name": "totalAmount",
|
|
3514
|
-
"type": "
|
|
3520
|
+
"type": "integer",
|
|
3515
3521
|
"required": false,
|
|
3516
|
-
"columnType": "
|
|
3522
|
+
"columnType": "INTEGER",
|
|
3517
3523
|
"default": 0
|
|
3518
3524
|
},
|
|
3519
3525
|
{
|
|
@@ -3994,23 +4000,23 @@
|
|
|
3994
4000
|
},
|
|
3995
4001
|
{
|
|
3996
4002
|
"name": "subtotal",
|
|
3997
|
-
"type": "
|
|
4003
|
+
"type": "integer",
|
|
3998
4004
|
"required": false,
|
|
3999
|
-
"columnType": "
|
|
4005
|
+
"columnType": "INTEGER",
|
|
4000
4006
|
"default": 0
|
|
4001
4007
|
},
|
|
4002
4008
|
{
|
|
4003
4009
|
"name": "taxAmount",
|
|
4004
|
-
"type": "
|
|
4010
|
+
"type": "integer",
|
|
4005
4011
|
"required": false,
|
|
4006
|
-
"columnType": "
|
|
4012
|
+
"columnType": "INTEGER",
|
|
4007
4013
|
"default": 0
|
|
4008
4014
|
},
|
|
4009
4015
|
{
|
|
4010
4016
|
"name": "totalAmount",
|
|
4011
|
-
"type": "
|
|
4017
|
+
"type": "integer",
|
|
4012
4018
|
"required": false,
|
|
4013
|
-
"columnType": "
|
|
4019
|
+
"columnType": "INTEGER",
|
|
4014
4020
|
"default": 0
|
|
4015
4021
|
},
|
|
4016
4022
|
{
|
|
@@ -4491,23 +4497,23 @@
|
|
|
4491
4497
|
},
|
|
4492
4498
|
{
|
|
4493
4499
|
"name": "subtotal",
|
|
4494
|
-
"type": "
|
|
4500
|
+
"type": "integer",
|
|
4495
4501
|
"required": false,
|
|
4496
|
-
"columnType": "
|
|
4502
|
+
"columnType": "INTEGER",
|
|
4497
4503
|
"default": 0
|
|
4498
4504
|
},
|
|
4499
4505
|
{
|
|
4500
4506
|
"name": "taxAmount",
|
|
4501
|
-
"type": "
|
|
4507
|
+
"type": "integer",
|
|
4502
4508
|
"required": false,
|
|
4503
|
-
"columnType": "
|
|
4509
|
+
"columnType": "INTEGER",
|
|
4504
4510
|
"default": 0
|
|
4505
4511
|
},
|
|
4506
4512
|
{
|
|
4507
4513
|
"name": "totalAmount",
|
|
4508
|
-
"type": "
|
|
4514
|
+
"type": "integer",
|
|
4509
4515
|
"required": false,
|
|
4510
|
-
"columnType": "
|
|
4516
|
+
"columnType": "INTEGER",
|
|
4511
4517
|
"default": 0
|
|
4512
4518
|
},
|
|
4513
4519
|
{
|
|
@@ -4988,23 +4994,23 @@
|
|
|
4988
4994
|
},
|
|
4989
4995
|
{
|
|
4990
4996
|
"name": "subtotal",
|
|
4991
|
-
"type": "
|
|
4997
|
+
"type": "integer",
|
|
4992
4998
|
"required": false,
|
|
4993
|
-
"columnType": "
|
|
4999
|
+
"columnType": "INTEGER",
|
|
4994
5000
|
"default": 0
|
|
4995
5001
|
},
|
|
4996
5002
|
{
|
|
4997
5003
|
"name": "taxAmount",
|
|
4998
|
-
"type": "
|
|
5004
|
+
"type": "integer",
|
|
4999
5005
|
"required": false,
|
|
5000
|
-
"columnType": "
|
|
5006
|
+
"columnType": "INTEGER",
|
|
5001
5007
|
"default": 0
|
|
5002
5008
|
},
|
|
5003
5009
|
{
|
|
5004
5010
|
"name": "totalAmount",
|
|
5005
|
-
"type": "
|
|
5011
|
+
"type": "integer",
|
|
5006
5012
|
"required": false,
|
|
5007
|
-
"columnType": "
|
|
5013
|
+
"columnType": "INTEGER",
|
|
5008
5014
|
"default": 0
|
|
5009
5015
|
},
|
|
5010
5016
|
{
|
|
@@ -5497,23 +5503,23 @@
|
|
|
5497
5503
|
},
|
|
5498
5504
|
{
|
|
5499
5505
|
"name": "subtotal",
|
|
5500
|
-
"type": "
|
|
5506
|
+
"type": "integer",
|
|
5501
5507
|
"required": false,
|
|
5502
|
-
"columnType": "
|
|
5508
|
+
"columnType": "INTEGER",
|
|
5503
5509
|
"default": 0
|
|
5504
5510
|
},
|
|
5505
5511
|
{
|
|
5506
5512
|
"name": "taxAmount",
|
|
5507
|
-
"type": "
|
|
5513
|
+
"type": "integer",
|
|
5508
5514
|
"required": false,
|
|
5509
|
-
"columnType": "
|
|
5515
|
+
"columnType": "INTEGER",
|
|
5510
5516
|
"default": 0
|
|
5511
5517
|
},
|
|
5512
5518
|
{
|
|
5513
5519
|
"name": "totalAmount",
|
|
5514
|
-
"type": "
|
|
5520
|
+
"type": "integer",
|
|
5515
5521
|
"required": false,
|
|
5516
|
-
"columnType": "
|
|
5522
|
+
"columnType": "INTEGER",
|
|
5517
5523
|
"default": 0
|
|
5518
5524
|
},
|
|
5519
5525
|
{
|
|
@@ -5994,23 +6000,23 @@
|
|
|
5994
6000
|
},
|
|
5995
6001
|
{
|
|
5996
6002
|
"name": "subtotal",
|
|
5997
|
-
"type": "
|
|
6003
|
+
"type": "integer",
|
|
5998
6004
|
"required": false,
|
|
5999
|
-
"columnType": "
|
|
6005
|
+
"columnType": "INTEGER",
|
|
6000
6006
|
"default": 0
|
|
6001
6007
|
},
|
|
6002
6008
|
{
|
|
6003
6009
|
"name": "taxAmount",
|
|
6004
|
-
"type": "
|
|
6010
|
+
"type": "integer",
|
|
6005
6011
|
"required": false,
|
|
6006
|
-
"columnType": "
|
|
6012
|
+
"columnType": "INTEGER",
|
|
6007
6013
|
"default": 0
|
|
6008
6014
|
},
|
|
6009
6015
|
{
|
|
6010
6016
|
"name": "totalAmount",
|
|
6011
|
-
"type": "
|
|
6017
|
+
"type": "integer",
|
|
6012
6018
|
"required": false,
|
|
6013
|
-
"columnType": "
|
|
6019
|
+
"columnType": "INTEGER",
|
|
6014
6020
|
"default": 0
|
|
6015
6021
|
},
|
|
6016
6022
|
{
|
|
@@ -6586,16 +6592,16 @@
|
|
|
6586
6592
|
},
|
|
6587
6593
|
{
|
|
6588
6594
|
"name": "unitPrice",
|
|
6589
|
-
"type": "
|
|
6595
|
+
"type": "integer",
|
|
6590
6596
|
"required": false,
|
|
6591
|
-
"columnType": "
|
|
6597
|
+
"columnType": "INTEGER",
|
|
6592
6598
|
"default": 0
|
|
6593
6599
|
},
|
|
6594
6600
|
{
|
|
6595
6601
|
"name": "discount",
|
|
6596
|
-
"type": "
|
|
6602
|
+
"type": "integer",
|
|
6597
6603
|
"required": false,
|
|
6598
|
-
"columnType": "
|
|
6604
|
+
"columnType": "INTEGER",
|
|
6599
6605
|
"default": 0
|
|
6600
6606
|
},
|
|
6601
6607
|
{
|
|
@@ -6607,9 +6613,9 @@
|
|
|
6607
6613
|
},
|
|
6608
6614
|
{
|
|
6609
6615
|
"name": "amount",
|
|
6610
|
-
"type": "
|
|
6616
|
+
"type": "integer",
|
|
6611
6617
|
"required": false,
|
|
6612
|
-
"columnType": "
|
|
6618
|
+
"columnType": "INTEGER",
|
|
6613
6619
|
"default": 0
|
|
6614
6620
|
},
|
|
6615
6621
|
{
|
|
@@ -6999,6 +7005,12 @@
|
|
|
6999
7005
|
"field": "tenantId"
|
|
7000
7006
|
},
|
|
7001
7007
|
"tableStrategy": "sti",
|
|
7008
|
+
"conflictColumns": [
|
|
7009
|
+
"tenant_id",
|
|
7010
|
+
"slug",
|
|
7011
|
+
"context",
|
|
7012
|
+
"_meta_type"
|
|
7013
|
+
],
|
|
7002
7014
|
"surfaces": [
|
|
7003
7015
|
{
|
|
7004
7016
|
"kind": "api",
|
|
@@ -7114,9 +7126,9 @@
|
|
|
7114
7126
|
},
|
|
7115
7127
|
{
|
|
7116
7128
|
"name": "creditLimit",
|
|
7117
|
-
"type": "
|
|
7129
|
+
"type": "integer",
|
|
7118
7130
|
"required": false,
|
|
7119
|
-
"columnType": "
|
|
7131
|
+
"columnType": "INTEGER",
|
|
7120
7132
|
"default": 0
|
|
7121
7133
|
},
|
|
7122
7134
|
{
|
|
@@ -7206,6 +7218,11 @@
|
|
|
7206
7218
|
"mode": "optional",
|
|
7207
7219
|
"field": "tenantId"
|
|
7208
7220
|
},
|
|
7221
|
+
"conflictColumns": [
|
|
7222
|
+
"tenant_id",
|
|
7223
|
+
"slug",
|
|
7224
|
+
"context"
|
|
7225
|
+
],
|
|
7209
7226
|
"surfaces": [
|
|
7210
7227
|
{
|
|
7211
7228
|
"kind": "api",
|
|
@@ -7432,6 +7449,11 @@
|
|
|
7432
7449
|
"mode": "optional",
|
|
7433
7450
|
"field": "tenantId"
|
|
7434
7451
|
},
|
|
7452
|
+
"conflictColumns": [
|
|
7453
|
+
"tenant_id",
|
|
7454
|
+
"slug",
|
|
7455
|
+
"context"
|
|
7456
|
+
],
|
|
7435
7457
|
"surfaces": [
|
|
7436
7458
|
{
|
|
7437
7459
|
"kind": "api",
|
|
@@ -7589,6 +7611,11 @@
|
|
|
7589
7611
|
"mode": "optional",
|
|
7590
7612
|
"field": "tenantId"
|
|
7591
7613
|
},
|
|
7614
|
+
"conflictColumns": [
|
|
7615
|
+
"tenant_id",
|
|
7616
|
+
"slug",
|
|
7617
|
+
"context"
|
|
7618
|
+
],
|
|
7592
7619
|
"surfaces": [
|
|
7593
7620
|
{
|
|
7594
7621
|
"kind": "api",
|
|
@@ -7999,6 +8026,11 @@
|
|
|
7999
8026
|
"mode": "optional",
|
|
8000
8027
|
"field": "tenantId"
|
|
8001
8028
|
},
|
|
8029
|
+
"conflictColumns": [
|
|
8030
|
+
"tenant_id",
|
|
8031
|
+
"slug",
|
|
8032
|
+
"context"
|
|
8033
|
+
],
|
|
8002
8034
|
"surfaces": [
|
|
8003
8035
|
{
|
|
8004
8036
|
"kind": "api",
|
|
@@ -8141,9 +8173,9 @@
|
|
|
8141
8173
|
},
|
|
8142
8174
|
{
|
|
8143
8175
|
"name": "taxRate",
|
|
8144
|
-
"type": "
|
|
8176
|
+
"type": "decimal",
|
|
8145
8177
|
"required": false,
|
|
8146
|
-
"columnType": "
|
|
8178
|
+
"columnType": "REAL",
|
|
8147
8179
|
"default": 0
|
|
8148
8180
|
},
|
|
8149
8181
|
{
|
|
@@ -8249,6 +8281,11 @@
|
|
|
8249
8281
|
"mode": "optional",
|
|
8250
8282
|
"field": "tenantId"
|
|
8251
8283
|
},
|
|
8284
|
+
"conflictColumns": [
|
|
8285
|
+
"tenant_id",
|
|
8286
|
+
"slug",
|
|
8287
|
+
"context"
|
|
8288
|
+
],
|
|
8252
8289
|
"surfaces": [
|
|
8253
8290
|
{
|
|
8254
8291
|
"kind": "api",
|
|
@@ -8371,9 +8408,9 @@
|
|
|
8371
8408
|
},
|
|
8372
8409
|
{
|
|
8373
8410
|
"name": "amount",
|
|
8374
|
-
"type": "
|
|
8411
|
+
"type": "integer",
|
|
8375
8412
|
"required": false,
|
|
8376
|
-
"columnType": "
|
|
8413
|
+
"columnType": "INTEGER",
|
|
8377
8414
|
"default": 0
|
|
8378
8415
|
},
|
|
8379
8416
|
{
|
|
@@ -8465,9 +8502,9 @@
|
|
|
8465
8502
|
},
|
|
8466
8503
|
{
|
|
8467
8504
|
"name": "nativeAmount",
|
|
8468
|
-
"type": "
|
|
8505
|
+
"type": "integer",
|
|
8469
8506
|
"required": false,
|
|
8470
|
-
"columnType": "
|
|
8507
|
+
"columnType": "INTEGER",
|
|
8471
8508
|
"default": 0
|
|
8472
8509
|
},
|
|
8473
8510
|
{
|
|
@@ -8479,16 +8516,16 @@
|
|
|
8479
8516
|
},
|
|
8480
8517
|
{
|
|
8481
8518
|
"name": "usdAtQuote",
|
|
8482
|
-
"type": "
|
|
8519
|
+
"type": "integer",
|
|
8483
8520
|
"required": false,
|
|
8484
|
-
"columnType": "
|
|
8521
|
+
"columnType": "INTEGER",
|
|
8485
8522
|
"default": 0
|
|
8486
8523
|
},
|
|
8487
8524
|
{
|
|
8488
8525
|
"name": "usdAtConfirmation",
|
|
8489
|
-
"type": "
|
|
8526
|
+
"type": "integer",
|
|
8490
8527
|
"required": false,
|
|
8491
|
-
"columnType": "
|
|
8528
|
+
"columnType": "INTEGER",
|
|
8492
8529
|
"default": 0
|
|
8493
8530
|
}
|
|
8494
8531
|
],
|
|
@@ -8584,6 +8621,11 @@
|
|
|
8584
8621
|
"mode": "optional",
|
|
8585
8622
|
"field": "tenantId"
|
|
8586
8623
|
},
|
|
8624
|
+
"conflictColumns": [
|
|
8625
|
+
"tenant_id",
|
|
8626
|
+
"slug",
|
|
8627
|
+
"context"
|
|
8628
|
+
],
|
|
8587
8629
|
"surfaces": [
|
|
8588
8630
|
{
|
|
8589
8631
|
"kind": "api",
|
|
@@ -8755,6 +8797,11 @@
|
|
|
8755
8797
|
"mode": "optional",
|
|
8756
8798
|
"field": "tenantId"
|
|
8757
8799
|
},
|
|
8800
|
+
"conflictColumns": [
|
|
8801
|
+
"tenant_id",
|
|
8802
|
+
"slug",
|
|
8803
|
+
"context"
|
|
8804
|
+
],
|
|
8758
8805
|
"surfaces": [
|
|
8759
8806
|
{
|
|
8760
8807
|
"kind": "api",
|
|
@@ -8938,6 +8985,11 @@
|
|
|
8938
8985
|
"mode": "optional",
|
|
8939
8986
|
"field": "tenantId"
|
|
8940
8987
|
},
|
|
8988
|
+
"conflictColumns": [
|
|
8989
|
+
"tenant_id",
|
|
8990
|
+
"slug",
|
|
8991
|
+
"context"
|
|
8992
|
+
],
|
|
8941
8993
|
"surfaces": [
|
|
8942
8994
|
{
|
|
8943
8995
|
"kind": "api",
|
|
@@ -9072,9 +9124,9 @@
|
|
|
9072
9124
|
},
|
|
9073
9125
|
{
|
|
9074
9126
|
"name": "usdPriceLocked",
|
|
9075
|
-
"type": "
|
|
9127
|
+
"type": "integer",
|
|
9076
9128
|
"required": false,
|
|
9077
|
-
"columnType": "
|
|
9129
|
+
"columnType": "INTEGER",
|
|
9078
9130
|
"default": 0
|
|
9079
9131
|
},
|
|
9080
9132
|
{
|
|
@@ -9393,23 +9445,23 @@
|
|
|
9393
9445
|
},
|
|
9394
9446
|
{
|
|
9395
9447
|
"name": "grossAmount",
|
|
9396
|
-
"type": "
|
|
9448
|
+
"type": "integer",
|
|
9397
9449
|
"required": false,
|
|
9398
|
-
"columnType": "
|
|
9450
|
+
"columnType": "INTEGER",
|
|
9399
9451
|
"default": 0
|
|
9400
9452
|
},
|
|
9401
9453
|
{
|
|
9402
9454
|
"name": "operatorFee",
|
|
9403
|
-
"type": "
|
|
9455
|
+
"type": "integer",
|
|
9404
9456
|
"required": false,
|
|
9405
|
-
"columnType": "
|
|
9457
|
+
"columnType": "INTEGER",
|
|
9406
9458
|
"default": 0
|
|
9407
9459
|
},
|
|
9408
9460
|
{
|
|
9409
9461
|
"name": "supplierNet",
|
|
9410
|
-
"type": "
|
|
9462
|
+
"type": "integer",
|
|
9411
9463
|
"required": false,
|
|
9412
|
-
"columnType": "
|
|
9464
|
+
"columnType": "INTEGER",
|
|
9413
9465
|
"default": 0
|
|
9414
9466
|
},
|
|
9415
9467
|
{
|
|
@@ -9553,6 +9605,11 @@
|
|
|
9553
9605
|
"mode": "optional",
|
|
9554
9606
|
"field": "tenantId"
|
|
9555
9607
|
},
|
|
9608
|
+
"conflictColumns": [
|
|
9609
|
+
"tenant_id",
|
|
9610
|
+
"slug",
|
|
9611
|
+
"context"
|
|
9612
|
+
],
|
|
9556
9613
|
"surfaces": [
|
|
9557
9614
|
{
|
|
9558
9615
|
"kind": "api",
|
|
@@ -9632,9 +9689,9 @@
|
|
|
9632
9689
|
},
|
|
9633
9690
|
{
|
|
9634
9691
|
"name": "minimumOrderAmount",
|
|
9635
|
-
"type": "
|
|
9692
|
+
"type": "integer",
|
|
9636
9693
|
"required": false,
|
|
9637
|
-
"columnType": "
|
|
9694
|
+
"columnType": "INTEGER",
|
|
9638
9695
|
"default": 0
|
|
9639
9696
|
},
|
|
9640
9697
|
{
|
|
@@ -9752,6 +9809,11 @@
|
|
|
9752
9809
|
"mode": "optional",
|
|
9753
9810
|
"field": "tenantId"
|
|
9754
9811
|
},
|
|
9812
|
+
"conflictColumns": [
|
|
9813
|
+
"tenant_id",
|
|
9814
|
+
"slug",
|
|
9815
|
+
"context"
|
|
9816
|
+
],
|
|
9755
9817
|
"surfaces": [
|
|
9756
9818
|
{
|
|
9757
9819
|
"kind": "api",
|
|
@@ -10765,5 +10827,5 @@
|
|
|
10765
10827
|
"polymorphicAssociations": 0,
|
|
10766
10828
|
"uuidColumns": 97
|
|
10767
10829
|
},
|
|
10768
|
-
"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**: line items on invoices.\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` (1¢ rounding tolerance) enforced on save. `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## 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\n## Gotchas\n\n- **Optional tenancy**: all models `@TenantScoped({ mode: 'optional' })` + nullable tenantId\n- **Currency in decimal fields**: price, taxAmount, totalAmount (not integer cents like affiliates)\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"
|
|
10830
|
+
"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**: line items on invoices.\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## 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\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. 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).\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 an integer count.\n- **Rounding happens where a rate meets money, and nowhere else**: `InvoiceLineItem.getTaxAmount()` and `ContractLineItem.calculateAmount()` `Math.round()` the fractional product to whole minor units. 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 overflow `int4`; `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 INTEGER 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- **`int4` ceiling**: INTEGER is 32-bit on PostgreSQL, so every money column tops out near 2.1e9 minor units — about $21.4M, or ~21 BTC in satoshis on `Payment.nativeAmount`. The preflight lists rows that would overflow. Widening to BIGINT is parked in #2373 and is a plain widening whenever it lands.\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"
|
|
10769
10831
|
}
|