@happyvertical/smrt-commerce 0.51.23 → 0.51.24
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 +47 -0
- package/README.md +104 -0
- package/dist/billing/credits.d.ts +33 -0
- package/dist/billing/credits.d.ts.map +1 -0
- package/dist/billing/events.d.ts +26 -0
- package/dist/billing/events.d.ts.map +1 -0
- package/dist/billing/index.d.ts +13 -0
- package/dist/billing/index.d.ts.map +1 -0
- package/dist/billing/jobs.d.ts +31 -0
- package/dist/billing/jobs.d.ts.map +1 -0
- package/dist/billing/period-close.d.ts +41 -0
- package/dist/billing/period-close.d.ts.map +1 -0
- package/dist/billing/provider.d.ts +136 -0
- package/dist/billing/provider.d.ts.map +1 -0
- package/dist/billing/runtime.d.ts +168 -0
- package/dist/billing/runtime.d.ts.map +1 -0
- package/dist/billing/stripe.d.ts +12 -0
- package/dist/billing/stripe.d.ts.map +1 -0
- package/dist/billing/units.d.ts +31 -0
- package/dist/billing/units.d.ts.map +1 -0
- package/dist/chunks/types-CRnln577.js.map +1 -1
- package/dist/chunks/units--tTn2ps8.js +52 -0
- package/dist/chunks/units--tTn2ps8.js.map +1 -0
- package/dist/collections/InvoiceLineItemCollection.d.ts +2 -1
- package/dist/collections/InvoiceLineItemCollection.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4258 -2584
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1397 -6
- package/dist/models/Invoice.d.ts +13 -2
- package/dist/models/Invoice.d.ts.map +1 -1
- package/dist/models/InvoiceLineItem.d.ts +6 -2
- package/dist/models/InvoiceLineItem.d.ts.map +1 -1
- package/dist/models/billing.d.ts +117 -0
- package/dist/models/billing.d.ts.map +1 -0
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +529 -9
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +10 -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.51.
|
|
6
|
+
"packageVersion": "0.51.24",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
10
|
+
"manifest": "e2dd1f1424fde5565e457f500c6baa2fa52abfe702aa7326b3617dbfb39ae69c",
|
|
11
|
+
"packageJson": "6009d6c1983c040f77dabe66be1b0a6a44f7d563d3093682e2ba7be4b2866b15",
|
|
12
|
+
"agents": "392119d6245dce8b628fa022d1a628008e4a85950a3b0cd79c1c82d60f26ccca"
|
|
13
13
|
},
|
|
14
14
|
"exports": [
|
|
15
15
|
".",
|
|
@@ -19,8 +19,11 @@
|
|
|
19
19
|
"./svelte"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
+
"@happyvertical/accounting": "catalog:",
|
|
22
23
|
"@happyvertical/smrt-core": "workspace:*",
|
|
24
|
+
"@happyvertical/smrt-jobs": "workspace:*",
|
|
23
25
|
"@happyvertical/smrt-ledgers": "workspace:*",
|
|
26
|
+
"@happyvertical/smrt-subscriptions": "workspace:*",
|
|
24
27
|
"@happyvertical/smrt-tenancy": "workspace:*",
|
|
25
28
|
"@happyvertical/smrt-types": "workspace:*",
|
|
26
29
|
"@happyvertical/smrt-ui": "workspace:*",
|
|
@@ -37,7 +40,9 @@
|
|
|
37
40
|
},
|
|
38
41
|
"smrtDependencies": [
|
|
39
42
|
"@happyvertical/smrt-core",
|
|
43
|
+
"@happyvertical/smrt-jobs",
|
|
40
44
|
"@happyvertical/smrt-ledgers",
|
|
45
|
+
"@happyvertical/smrt-subscriptions",
|
|
41
46
|
"@happyvertical/smrt-tenancy",
|
|
42
47
|
"@happyvertical/smrt-types",
|
|
43
48
|
"@happyvertical/smrt-ui",
|
|
@@ -55,7 +60,7 @@
|
|
|
55
60
|
"smrt"
|
|
56
61
|
],
|
|
57
62
|
"risks": [
|
|
58
|
-
"cross-package-refs:
|
|
63
|
+
"cross-package-refs:12",
|
|
59
64
|
"sensitive-fields-excluded",
|
|
60
65
|
"sti-inheritance"
|
|
61
66
|
],
|
|
@@ -9617,6 +9622,13 @@
|
|
|
9617
9622
|
"columnType": "INTEGER",
|
|
9618
9623
|
"default": 0
|
|
9619
9624
|
},
|
|
9625
|
+
{
|
|
9626
|
+
"name": "providerTaxAmount",
|
|
9627
|
+
"type": "integer",
|
|
9628
|
+
"required": false,
|
|
9629
|
+
"columnType": "INTEGER",
|
|
9630
|
+
"default": 0
|
|
9631
|
+
},
|
|
9620
9632
|
{
|
|
9621
9633
|
"name": "totalAmount",
|
|
9622
9634
|
"type": "integer",
|
|
@@ -10307,6 +10319,9 @@
|
|
|
10307
10319
|
},
|
|
10308
10320
|
{
|
|
10309
10321
|
"name": "toAccountingLineItem",
|
|
10322
|
+
"params": [
|
|
10323
|
+
"currency?: string"
|
|
10324
|
+
],
|
|
10310
10325
|
"returns": "AccountingLineItemInput"
|
|
10311
10326
|
}
|
|
10312
10327
|
],
|
|
@@ -12603,6 +12618,511 @@
|
|
|
12603
12618
|
],
|
|
12604
12619
|
"tags": [],
|
|
12605
12620
|
"risks": []
|
|
12621
|
+
},
|
|
12622
|
+
{
|
|
12623
|
+
"name": "BillingAccount",
|
|
12624
|
+
"qualifiedName": "@happyvertical/smrt-commerce:BillingAccount",
|
|
12625
|
+
"collection": "billingaccounts",
|
|
12626
|
+
"tableName": "_smrt_billing_accounts",
|
|
12627
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
12628
|
+
"extends": "SmrtObject",
|
|
12629
|
+
"fields": [
|
|
12630
|
+
{
|
|
12631
|
+
"name": "sellerTenantId",
|
|
12632
|
+
"type": "crossPackageRef",
|
|
12633
|
+
"required": true,
|
|
12634
|
+
"related": "@happyvertical/smrt-users:Tenant",
|
|
12635
|
+
"columnType": "UUID"
|
|
12636
|
+
},
|
|
12637
|
+
{
|
|
12638
|
+
"name": "payerTenantId",
|
|
12639
|
+
"type": "crossPackageRef",
|
|
12640
|
+
"required": true,
|
|
12641
|
+
"related": "@happyvertical/smrt-users:Tenant",
|
|
12642
|
+
"columnType": "UUID"
|
|
12643
|
+
},
|
|
12644
|
+
{
|
|
12645
|
+
"name": "customerId",
|
|
12646
|
+
"type": "foreignKey",
|
|
12647
|
+
"required": false,
|
|
12648
|
+
"related": "Customer",
|
|
12649
|
+
"columnType": "UUID"
|
|
12650
|
+
},
|
|
12651
|
+
{
|
|
12652
|
+
"name": "name",
|
|
12653
|
+
"type": "text",
|
|
12654
|
+
"required": false,
|
|
12655
|
+
"columnType": "TEXT",
|
|
12656
|
+
"default": ""
|
|
12657
|
+
},
|
|
12658
|
+
{
|
|
12659
|
+
"name": "email",
|
|
12660
|
+
"type": "text",
|
|
12661
|
+
"required": false,
|
|
12662
|
+
"columnType": "TEXT",
|
|
12663
|
+
"default": ""
|
|
12664
|
+
},
|
|
12665
|
+
{
|
|
12666
|
+
"name": "provider",
|
|
12667
|
+
"type": "text",
|
|
12668
|
+
"required": false,
|
|
12669
|
+
"columnType": "TEXT",
|
|
12670
|
+
"default": ""
|
|
12671
|
+
},
|
|
12672
|
+
{
|
|
12673
|
+
"name": "providerCustomerId",
|
|
12674
|
+
"type": "text",
|
|
12675
|
+
"required": false,
|
|
12676
|
+
"columnType": "TEXT",
|
|
12677
|
+
"default": ""
|
|
12678
|
+
},
|
|
12679
|
+
{
|
|
12680
|
+
"name": "automaticTax",
|
|
12681
|
+
"type": "boolean",
|
|
12682
|
+
"required": false,
|
|
12683
|
+
"columnType": "BOOLEAN",
|
|
12684
|
+
"default": true
|
|
12685
|
+
},
|
|
12686
|
+
{
|
|
12687
|
+
"name": "flatDiscountBasisPoints",
|
|
12688
|
+
"type": "integer",
|
|
12689
|
+
"required": false,
|
|
12690
|
+
"columnType": "INTEGER",
|
|
12691
|
+
"default": 0
|
|
12692
|
+
},
|
|
12693
|
+
{
|
|
12694
|
+
"name": "paymentTermsDays",
|
|
12695
|
+
"type": "integer",
|
|
12696
|
+
"required": false,
|
|
12697
|
+
"columnType": "INTEGER",
|
|
12698
|
+
"default": 30
|
|
12699
|
+
},
|
|
12700
|
+
{
|
|
12701
|
+
"name": "standing",
|
|
12702
|
+
"type": "text",
|
|
12703
|
+
"required": false,
|
|
12704
|
+
"columnType": "TEXT",
|
|
12705
|
+
"default": "current"
|
|
12706
|
+
}
|
|
12707
|
+
],
|
|
12708
|
+
"relationships": [
|
|
12709
|
+
{
|
|
12710
|
+
"name": "sellerTenantId",
|
|
12711
|
+
"type": "crossPackageRef",
|
|
12712
|
+
"required": true,
|
|
12713
|
+
"related": "@happyvertical/smrt-users:Tenant",
|
|
12714
|
+
"columnType": "UUID"
|
|
12715
|
+
},
|
|
12716
|
+
{
|
|
12717
|
+
"name": "payerTenantId",
|
|
12718
|
+
"type": "crossPackageRef",
|
|
12719
|
+
"required": true,
|
|
12720
|
+
"related": "@happyvertical/smrt-users:Tenant",
|
|
12721
|
+
"columnType": "UUID"
|
|
12722
|
+
},
|
|
12723
|
+
{
|
|
12724
|
+
"name": "customerId",
|
|
12725
|
+
"type": "foreignKey",
|
|
12726
|
+
"required": false,
|
|
12727
|
+
"related": "Customer",
|
|
12728
|
+
"columnType": "UUID"
|
|
12729
|
+
}
|
|
12730
|
+
],
|
|
12731
|
+
"methods": [],
|
|
12732
|
+
"conflictColumns": [
|
|
12733
|
+
"seller_tenant_id",
|
|
12734
|
+
"payer_tenant_id"
|
|
12735
|
+
],
|
|
12736
|
+
"surfaces": [],
|
|
12737
|
+
"relationshipFeatures": [
|
|
12738
|
+
"crossPackageRef",
|
|
12739
|
+
"foreignKey",
|
|
12740
|
+
"uuidColumns"
|
|
12741
|
+
],
|
|
12742
|
+
"tags": [],
|
|
12743
|
+
"risks": []
|
|
12744
|
+
},
|
|
12745
|
+
{
|
|
12746
|
+
"name": "BillingPeriodClose",
|
|
12747
|
+
"qualifiedName": "@happyvertical/smrt-commerce:BillingPeriodClose",
|
|
12748
|
+
"collection": "billingperiodcloses",
|
|
12749
|
+
"tableName": "_smrt_billing_period_closes",
|
|
12750
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
12751
|
+
"extends": "SmrtObject",
|
|
12752
|
+
"fields": [
|
|
12753
|
+
{
|
|
12754
|
+
"name": "sellerTenantId",
|
|
12755
|
+
"type": "crossPackageRef",
|
|
12756
|
+
"required": true,
|
|
12757
|
+
"related": "@happyvertical/smrt-users:Tenant",
|
|
12758
|
+
"columnType": "UUID"
|
|
12759
|
+
},
|
|
12760
|
+
{
|
|
12761
|
+
"name": "kind",
|
|
12762
|
+
"type": "text",
|
|
12763
|
+
"required": false,
|
|
12764
|
+
"columnType": "TEXT",
|
|
12765
|
+
"default": "provider"
|
|
12766
|
+
},
|
|
12767
|
+
{
|
|
12768
|
+
"name": "payerTenantId",
|
|
12769
|
+
"type": "crossPackageRef",
|
|
12770
|
+
"required": true,
|
|
12771
|
+
"related": "@happyvertical/smrt-users:Tenant",
|
|
12772
|
+
"columnType": "UUID"
|
|
12773
|
+
},
|
|
12774
|
+
{
|
|
12775
|
+
"name": "currency",
|
|
12776
|
+
"type": "text",
|
|
12777
|
+
"required": false,
|
|
12778
|
+
"columnType": "TEXT",
|
|
12779
|
+
"default": "USD"
|
|
12780
|
+
},
|
|
12781
|
+
{
|
|
12782
|
+
"name": "periodStart",
|
|
12783
|
+
"type": "datetime",
|
|
12784
|
+
"required": false,
|
|
12785
|
+
"columnType": "TIMESTAMP"
|
|
12786
|
+
},
|
|
12787
|
+
{
|
|
12788
|
+
"name": "periodEnd",
|
|
12789
|
+
"type": "datetime",
|
|
12790
|
+
"required": false,
|
|
12791
|
+
"columnType": "TIMESTAMP"
|
|
12792
|
+
},
|
|
12793
|
+
{
|
|
12794
|
+
"name": "billingAccountId",
|
|
12795
|
+
"type": "foreignKey",
|
|
12796
|
+
"required": false,
|
|
12797
|
+
"related": "BillingAccount",
|
|
12798
|
+
"columnType": "UUID"
|
|
12799
|
+
},
|
|
12800
|
+
{
|
|
12801
|
+
"name": "status",
|
|
12802
|
+
"type": "text",
|
|
12803
|
+
"required": false,
|
|
12804
|
+
"columnType": "TEXT",
|
|
12805
|
+
"default": "collecting"
|
|
12806
|
+
},
|
|
12807
|
+
{
|
|
12808
|
+
"name": "invoiceId",
|
|
12809
|
+
"type": "foreignKey",
|
|
12810
|
+
"required": false,
|
|
12811
|
+
"related": "Invoice",
|
|
12812
|
+
"columnType": "UUID"
|
|
12813
|
+
},
|
|
12814
|
+
{
|
|
12815
|
+
"name": "providerInvoiceId",
|
|
12816
|
+
"type": "text",
|
|
12817
|
+
"required": false,
|
|
12818
|
+
"columnType": "TEXT",
|
|
12819
|
+
"default": ""
|
|
12820
|
+
},
|
|
12821
|
+
{
|
|
12822
|
+
"name": "subtotal",
|
|
12823
|
+
"type": "integer",
|
|
12824
|
+
"required": false,
|
|
12825
|
+
"columnType": "INTEGER",
|
|
12826
|
+
"default": 0
|
|
12827
|
+
},
|
|
12828
|
+
{
|
|
12829
|
+
"name": "lineCount",
|
|
12830
|
+
"type": "integer",
|
|
12831
|
+
"required": false,
|
|
12832
|
+
"columnType": "INTEGER",
|
|
12833
|
+
"default": 0
|
|
12834
|
+
},
|
|
12835
|
+
{
|
|
12836
|
+
"name": "issuedAt",
|
|
12837
|
+
"type": "datetime",
|
|
12838
|
+
"required": false,
|
|
12839
|
+
"columnType": "TIMESTAMP"
|
|
12840
|
+
},
|
|
12841
|
+
{
|
|
12842
|
+
"name": "leaseToken",
|
|
12843
|
+
"type": "text",
|
|
12844
|
+
"required": false,
|
|
12845
|
+
"columnType": "TEXT"
|
|
12846
|
+
},
|
|
12847
|
+
{
|
|
12848
|
+
"name": "leaseExpiresAt",
|
|
12849
|
+
"type": "datetime",
|
|
12850
|
+
"required": false,
|
|
12851
|
+
"columnType": "TIMESTAMP"
|
|
12852
|
+
},
|
|
12853
|
+
{
|
|
12854
|
+
"name": "attempts",
|
|
12855
|
+
"type": "integer",
|
|
12856
|
+
"required": false,
|
|
12857
|
+
"columnType": "INTEGER",
|
|
12858
|
+
"default": 0
|
|
12859
|
+
},
|
|
12860
|
+
{
|
|
12861
|
+
"name": "lastError",
|
|
12862
|
+
"type": "text",
|
|
12863
|
+
"required": false,
|
|
12864
|
+
"columnType": "TEXT",
|
|
12865
|
+
"default": ""
|
|
12866
|
+
}
|
|
12867
|
+
],
|
|
12868
|
+
"relationships": [
|
|
12869
|
+
{
|
|
12870
|
+
"name": "sellerTenantId",
|
|
12871
|
+
"type": "crossPackageRef",
|
|
12872
|
+
"required": true,
|
|
12873
|
+
"related": "@happyvertical/smrt-users:Tenant",
|
|
12874
|
+
"columnType": "UUID"
|
|
12875
|
+
},
|
|
12876
|
+
{
|
|
12877
|
+
"name": "payerTenantId",
|
|
12878
|
+
"type": "crossPackageRef",
|
|
12879
|
+
"required": true,
|
|
12880
|
+
"related": "@happyvertical/smrt-users:Tenant",
|
|
12881
|
+
"columnType": "UUID"
|
|
12882
|
+
},
|
|
12883
|
+
{
|
|
12884
|
+
"name": "billingAccountId",
|
|
12885
|
+
"type": "foreignKey",
|
|
12886
|
+
"required": false,
|
|
12887
|
+
"related": "BillingAccount",
|
|
12888
|
+
"columnType": "UUID"
|
|
12889
|
+
},
|
|
12890
|
+
{
|
|
12891
|
+
"name": "invoiceId",
|
|
12892
|
+
"type": "foreignKey",
|
|
12893
|
+
"required": false,
|
|
12894
|
+
"related": "Invoice",
|
|
12895
|
+
"columnType": "UUID"
|
|
12896
|
+
}
|
|
12897
|
+
],
|
|
12898
|
+
"methods": [
|
|
12899
|
+
"processBillingEvents",
|
|
12900
|
+
"runPeriodClose"
|
|
12901
|
+
],
|
|
12902
|
+
"methodSignatures": [
|
|
12903
|
+
{
|
|
12904
|
+
"name": "processBillingEvents",
|
|
12905
|
+
"async": true,
|
|
12906
|
+
"params": [
|
|
12907
|
+
"args?: Record<string, unknown>",
|
|
12908
|
+
"_context?: JobExecutionContext"
|
|
12909
|
+
],
|
|
12910
|
+
"returns": "Promise<unknown>"
|
|
12911
|
+
},
|
|
12912
|
+
{
|
|
12913
|
+
"name": "runPeriodClose",
|
|
12914
|
+
"async": true,
|
|
12915
|
+
"params": [
|
|
12916
|
+
"args?: Record<string, unknown>",
|
|
12917
|
+
"_context?: JobExecutionContext"
|
|
12918
|
+
],
|
|
12919
|
+
"returns": "Promise<unknown>"
|
|
12920
|
+
}
|
|
12921
|
+
],
|
|
12922
|
+
"conflictColumns": [
|
|
12923
|
+
"seller_tenant_id",
|
|
12924
|
+
"kind",
|
|
12925
|
+
"payer_tenant_id",
|
|
12926
|
+
"currency",
|
|
12927
|
+
"period_start",
|
|
12928
|
+
"period_end"
|
|
12929
|
+
],
|
|
12930
|
+
"surfaces": [],
|
|
12931
|
+
"withheldSurfaces": [
|
|
12932
|
+
{
|
|
12933
|
+
"kind": "api",
|
|
12934
|
+
"operation": "processBillingEvents",
|
|
12935
|
+
"code": "api-disabled",
|
|
12936
|
+
"reason": "api is disabled",
|
|
12937
|
+
"objectName": "@happyvertical/smrt-commerce:BillingPeriodClose"
|
|
12938
|
+
},
|
|
12939
|
+
{
|
|
12940
|
+
"kind": "api",
|
|
12941
|
+
"operation": "runPeriodClose",
|
|
12942
|
+
"code": "api-disabled",
|
|
12943
|
+
"reason": "api is disabled",
|
|
12944
|
+
"objectName": "@happyvertical/smrt-commerce:BillingPeriodClose"
|
|
12945
|
+
}
|
|
12946
|
+
],
|
|
12947
|
+
"relationshipFeatures": [
|
|
12948
|
+
"crossPackageRef",
|
|
12949
|
+
"foreignKey",
|
|
12950
|
+
"uuidColumns"
|
|
12951
|
+
],
|
|
12952
|
+
"tags": [],
|
|
12953
|
+
"risks": []
|
|
12954
|
+
},
|
|
12955
|
+
{
|
|
12956
|
+
"name": "BillingLineSource",
|
|
12957
|
+
"qualifiedName": "@happyvertical/smrt-commerce:BillingLineSource",
|
|
12958
|
+
"collection": "billinglinesources",
|
|
12959
|
+
"tableName": "_smrt_billing_line_sources",
|
|
12960
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
12961
|
+
"extends": "SmrtObject",
|
|
12962
|
+
"fields": [
|
|
12963
|
+
{
|
|
12964
|
+
"name": "sellerTenantId",
|
|
12965
|
+
"type": "crossPackageRef",
|
|
12966
|
+
"required": true,
|
|
12967
|
+
"related": "@happyvertical/smrt-users:Tenant",
|
|
12968
|
+
"columnType": "UUID"
|
|
12969
|
+
},
|
|
12970
|
+
{
|
|
12971
|
+
"name": "periodCloseId",
|
|
12972
|
+
"type": "foreignKey",
|
|
12973
|
+
"required": false,
|
|
12974
|
+
"related": "BillingPeriodClose",
|
|
12975
|
+
"columnType": "UUID"
|
|
12976
|
+
},
|
|
12977
|
+
{
|
|
12978
|
+
"name": "sourceType",
|
|
12979
|
+
"type": "text",
|
|
12980
|
+
"required": false,
|
|
12981
|
+
"columnType": "TEXT",
|
|
12982
|
+
"default": "client_charge"
|
|
12983
|
+
},
|
|
12984
|
+
{
|
|
12985
|
+
"name": "sourceId",
|
|
12986
|
+
"type": "text",
|
|
12987
|
+
"required": false,
|
|
12988
|
+
"columnType": "TEXT",
|
|
12989
|
+
"default": ""
|
|
12990
|
+
},
|
|
12991
|
+
{
|
|
12992
|
+
"name": "lineKey",
|
|
12993
|
+
"type": "text",
|
|
12994
|
+
"required": false,
|
|
12995
|
+
"columnType": "TEXT",
|
|
12996
|
+
"default": ""
|
|
12997
|
+
},
|
|
12998
|
+
{
|
|
12999
|
+
"name": "lineDescription",
|
|
13000
|
+
"type": "text",
|
|
13001
|
+
"required": false,
|
|
13002
|
+
"columnType": "TEXT",
|
|
13003
|
+
"default": ""
|
|
13004
|
+
},
|
|
13005
|
+
{
|
|
13006
|
+
"name": "amount",
|
|
13007
|
+
"type": "integer",
|
|
13008
|
+
"required": false,
|
|
13009
|
+
"columnType": "INTEGER",
|
|
13010
|
+
"default": 0
|
|
13011
|
+
},
|
|
13012
|
+
{
|
|
13013
|
+
"name": "discount",
|
|
13014
|
+
"type": "integer",
|
|
13015
|
+
"required": false,
|
|
13016
|
+
"columnType": "INTEGER",
|
|
13017
|
+
"default": 0
|
|
13018
|
+
},
|
|
13019
|
+
{
|
|
13020
|
+
"name": "quantity",
|
|
13021
|
+
"type": "decimal",
|
|
13022
|
+
"required": false,
|
|
13023
|
+
"columnType": "REAL",
|
|
13024
|
+
"default": 0
|
|
13025
|
+
},
|
|
13026
|
+
{
|
|
13027
|
+
"name": "currency",
|
|
13028
|
+
"type": "text",
|
|
13029
|
+
"required": false,
|
|
13030
|
+
"columnType": "TEXT",
|
|
13031
|
+
"default": "USD"
|
|
13032
|
+
},
|
|
13033
|
+
{
|
|
13034
|
+
"name": "periodStart",
|
|
13035
|
+
"type": "datetime",
|
|
13036
|
+
"required": false,
|
|
13037
|
+
"columnType": "TIMESTAMP"
|
|
13038
|
+
},
|
|
13039
|
+
{
|
|
13040
|
+
"name": "periodEnd",
|
|
13041
|
+
"type": "datetime",
|
|
13042
|
+
"required": false,
|
|
13043
|
+
"columnType": "TIMESTAMP"
|
|
13044
|
+
}
|
|
13045
|
+
],
|
|
13046
|
+
"relationships": [
|
|
13047
|
+
{
|
|
13048
|
+
"name": "sellerTenantId",
|
|
13049
|
+
"type": "crossPackageRef",
|
|
13050
|
+
"required": true,
|
|
13051
|
+
"related": "@happyvertical/smrt-users:Tenant",
|
|
13052
|
+
"columnType": "UUID"
|
|
13053
|
+
},
|
|
13054
|
+
{
|
|
13055
|
+
"name": "periodCloseId",
|
|
13056
|
+
"type": "foreignKey",
|
|
13057
|
+
"required": false,
|
|
13058
|
+
"related": "BillingPeriodClose",
|
|
13059
|
+
"columnType": "UUID"
|
|
13060
|
+
}
|
|
13061
|
+
],
|
|
13062
|
+
"methods": [],
|
|
13063
|
+
"conflictColumns": [
|
|
13064
|
+
"source_type",
|
|
13065
|
+
"source_id"
|
|
13066
|
+
],
|
|
13067
|
+
"surfaces": [],
|
|
13068
|
+
"relationshipFeatures": [
|
|
13069
|
+
"crossPackageRef",
|
|
13070
|
+
"foreignKey",
|
|
13071
|
+
"uuidColumns"
|
|
13072
|
+
],
|
|
13073
|
+
"tags": [],
|
|
13074
|
+
"risks": []
|
|
13075
|
+
},
|
|
13076
|
+
{
|
|
13077
|
+
"name": "BillingAccountCollection",
|
|
13078
|
+
"qualifiedName": "@happyvertical/smrt-commerce:BillingAccountCollection",
|
|
13079
|
+
"collection": "billingaccounts",
|
|
13080
|
+
"tableName": "_smrt_billing_accounts",
|
|
13081
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
13082
|
+
"extends": "SmrtCollection",
|
|
13083
|
+
"fields": [],
|
|
13084
|
+
"relationships": [],
|
|
13085
|
+
"methods": [],
|
|
13086
|
+
"surfaces": [],
|
|
13087
|
+
"relationshipFeatures": [
|
|
13088
|
+
"uuidColumns"
|
|
13089
|
+
],
|
|
13090
|
+
"tags": [],
|
|
13091
|
+
"risks": []
|
|
13092
|
+
},
|
|
13093
|
+
{
|
|
13094
|
+
"name": "BillingPeriodCloseCollection",
|
|
13095
|
+
"qualifiedName": "@happyvertical/smrt-commerce:BillingPeriodCloseCollection",
|
|
13096
|
+
"collection": "billingperiodcloses",
|
|
13097
|
+
"tableName": "_smrt_billing_period_closes",
|
|
13098
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
13099
|
+
"extends": "SmrtCollection",
|
|
13100
|
+
"fields": [],
|
|
13101
|
+
"relationships": [],
|
|
13102
|
+
"methods": [],
|
|
13103
|
+
"surfaces": [],
|
|
13104
|
+
"relationshipFeatures": [
|
|
13105
|
+
"uuidColumns"
|
|
13106
|
+
],
|
|
13107
|
+
"tags": [],
|
|
13108
|
+
"risks": []
|
|
13109
|
+
},
|
|
13110
|
+
{
|
|
13111
|
+
"name": "BillingLineSourceCollection",
|
|
13112
|
+
"qualifiedName": "@happyvertical/smrt-commerce:BillingLineSourceCollection",
|
|
13113
|
+
"collection": "billinglinesources",
|
|
13114
|
+
"tableName": "_smrt_billing_line_sources",
|
|
13115
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
13116
|
+
"extends": "SmrtCollection",
|
|
13117
|
+
"fields": [],
|
|
13118
|
+
"relationships": [],
|
|
13119
|
+
"methods": [],
|
|
13120
|
+
"surfaces": [],
|
|
13121
|
+
"relationshipFeatures": [
|
|
13122
|
+
"uuidColumns"
|
|
13123
|
+
],
|
|
13124
|
+
"tags": [],
|
|
13125
|
+
"risks": []
|
|
12606
13126
|
}
|
|
12607
13127
|
],
|
|
12608
13128
|
"surfaces": [
|
|
@@ -18571,12 +19091,12 @@
|
|
|
18571
19091
|
],
|
|
18572
19092
|
"prompts": [],
|
|
18573
19093
|
"relationshipsV2": {
|
|
18574
|
-
"foreignKeyFields":
|
|
18575
|
-
"crossPackageRefFields":
|
|
19094
|
+
"foreignKeyFields": 37,
|
|
19095
|
+
"crossPackageRefFields": 12,
|
|
18576
19096
|
"junctionCollections": 0,
|
|
18577
19097
|
"hierarchicalObjects": 0,
|
|
18578
19098
|
"polymorphicAssociations": 0,
|
|
18579
|
-
"uuidColumns":
|
|
19099
|
+
"uuidColumns": 156
|
|
18580
19100
|
},
|
|
18581
|
-
"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 (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 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 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"
|
|
19101
|
+
"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## 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` (ISO 4217 exponent) and never hand-roll a Stripe call here.\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- **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; credit is granted only when the collected total equals\n it. Rotating the webhook secret strands in-flight checkouts (up to 24 h). `observe()` re-reads provider state, so\n ordering never depends on delivery order. The standing hook runs inside the\n event transaction and must be idempotent.\n- **`Invoice.providerTaxAmount`** is added to line-item tax; it is\n server-managed (not API-writable). `toAccountingInput()` emits major units.\n- **Known limits** (each tracked upstream): provider customer creation is not\n idempotent (happyvertical/sdk#1268); credit checkouts are untaxed and\n two-decimal only (sdk#1269); `autoTopUp` cannot charge a saved card\n (sdk#1270); Stripe line discounts and uncollectible status are worked around\n as negative lines and event types (sdk#1271). `RetailCharge` has no\n adjustment ledger. Flat plans are monthly, in arrears, without proration.\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 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 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"
|
|
18582
19102
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -257,7 +257,8 @@ export interface AccountingLineItemInput {
|
|
|
257
257
|
}
|
|
258
258
|
/**
|
|
259
259
|
* An invoice in the format expected by `@happyvertical/accounting` providers.
|
|
260
|
-
* Mirrors the object built by {@link Invoice.toAccountingInput}
|
|
260
|
+
* Mirrors the object built by {@link Invoice.toAccountingInput}; money is in
|
|
261
|
+
* currency **major** units, as the SDK expects.
|
|
261
262
|
*/
|
|
262
263
|
export interface AccountingInvoiceInput {
|
|
263
264
|
id: string;
|
|
@@ -382,6 +383,7 @@ export interface InvoiceOptions extends SmrtObjectOptions {
|
|
|
382
383
|
paidDate?: Date | null;
|
|
383
384
|
subtotal?: number;
|
|
384
385
|
taxAmount?: number;
|
|
386
|
+
providerTaxAmount?: number;
|
|
385
387
|
totalAmount?: number;
|
|
386
388
|
amountPaid?: number;
|
|
387
389
|
currency?: string;
|