jaz-clio 5.74.2 → 6.0.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/README.md +8 -8
- package/assets/skills/api/SKILL.md +3 -36
- package/assets/skills/cli/SKILL.md +18 -28
- package/assets/skills/cli/references/agent-gotchas.md +2 -2
- package/assets/skills/cli/references/command-catalog.md +15 -31
- package/assets/skills/cli/references/common-workflows.md +19 -28
- package/assets/skills/conversion/SKILL.md +1 -1
- package/assets/skills/jaz-kit/SKILL.md +1 -1
- package/assets/skills/jaz-kit/references/flows.md +2 -2
- package/assets/skills/jaz-pseudo-sql/SKILL.md +1 -1
- package/assets/skills/jobs/SKILL.md +42 -42
- package/assets/skills/jobs/references/audit-prep.md +8 -8
- package/assets/skills/jobs/references/bank-match.md +1 -1
- package/assets/skills/jobs/references/bank-recon.md +6 -6
- package/assets/skills/jobs/references/building-blocks.md +49 -30
- package/assets/skills/jobs/references/credit-control.md +13 -12
- package/assets/skills/jobs/references/document-collection.md +6 -6
- package/assets/skills/jobs/references/fa-review.md +28 -29
- package/assets/skills/jobs/references/gst-vat-filing.md +3 -3
- package/assets/skills/jobs/references/month-end-close.md +37 -33
- package/assets/skills/jobs/references/payment-run.md +3 -4
- package/assets/skills/jobs/references/quarter-end-close.md +20 -18
- package/assets/skills/jobs/references/supplier-recon.md +5 -5
- package/assets/skills/jobs/references/year-end-close.md +31 -21
- package/assets/skills/transaction-recipes/SKILL.md +54 -117
- package/assets/skills/transaction-recipes/references/accrued-expenses.md +86 -61
- package/assets/skills/transaction-recipes/references/asset-disposal.md +135 -93
- package/assets/skills/transaction-recipes/references/bad-debt-provision.md +87 -65
- package/assets/skills/transaction-recipes/references/bank-loan.md +104 -70
- package/assets/skills/transaction-recipes/references/building-blocks.md +168 -72
- package/assets/skills/transaction-recipes/references/capital-wip.md +9 -8
- package/assets/skills/transaction-recipes/references/declining-balance.md +91 -64
- package/assets/skills/transaction-recipes/references/deferred-revenue.md +105 -68
- package/assets/skills/transaction-recipes/references/dividend.md +100 -64
- package/assets/skills/transaction-recipes/references/employee-accruals.md +111 -73
- package/assets/skills/transaction-recipes/references/fixed-deposit.md +116 -63
- package/assets/skills/transaction-recipes/references/fx-revaluation.md +28 -19
- package/assets/skills/transaction-recipes/references/hire-purchase.md +45 -44
- package/assets/skills/transaction-recipes/references/ifrs16-lease.md +108 -73
- package/assets/skills/transaction-recipes/references/intercompany.md +8 -6
- package/assets/skills/transaction-recipes/references/prepaid-amortization.md +104 -65
- package/assets/skills/transaction-recipes/references/provisions.md +116 -64
- package/assets/templates/platform-rules/jaz-agent-rules.md +10 -9
- package/cli.mjs +529 -607
- package/package.json +1 -1
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
# Recipe: Declining Balance Depreciation (
|
|
1
|
+
# Recipe: Declining Balance Depreciation (calculator type: `depreciation`)
|
|
2
2
|
|
|
3
|
-
> Canonical recipe for non-straight-line depreciation methods (double declining balance / DDB, 150% declining balance / 150DB)
|
|
3
|
+
> Canonical recipe for non-straight-line depreciation methods (double declining balance / DDB, 150% declining balance / 150DB), which the Jaz native FA register does not post. One depreciation journal per period, in one capsule. **Do NOT register the asset in the Jaz FA register with straight-line depreciation** (it would post duplicate SL depreciation). You calculate, create the capsule and post each journal yourself (see `building-blocks.md` § The three-step flow).
|
|
4
4
|
|
|
5
|
-
## Tools
|
|
5
|
+
## Tools and calculator this recipe uses
|
|
6
6
|
|
|
7
|
-
###
|
|
8
|
-
-
|
|
9
|
-
-
|
|
7
|
+
### Calculator (offline, posts nothing)
|
|
8
|
+
- **MCP: `calculate(type: 'depreciation', cost, salvageValue, usefulLifeYears, method, frequency, currency)`** (step 1). `method` is `ddb` (the default), `150db` or `sl`; `frequency` is `annual` (the default) or `monthly`.
|
|
9
|
+
- **CLI: `clio calc depreciation --cost <c> --salvage <s> --life <years> --method <ddb|150db|sl> --frequency <annual|monthly> --currency <code> --json`** (step 1): the same result.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
- **`clio calc depreciation --cost <c> --salvage <s> --life <years> --method <ddb|150db|sl> --frequency <annual|monthly> --json`** (used in step 1): full depreciation schedule. Returns `{ totalDepreciation, schedule[n] }` where each row carries `period`, `openingBookValue`, `depreciationAmount`, `accumulatedDepreciation`, `closingBookValue`. Final period absorbs rounding to land at salvage value exactly.
|
|
11
|
+
The depreciation calculator takes no start date: its steps are never dated. You date each journal yourself (step 4).
|
|
13
12
|
|
|
14
|
-
###
|
|
15
|
-
- **`
|
|
16
|
-
- **`
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
### Posting tools
|
|
14
|
+
- **`list_capsule_types` / `create_capsule_type(displayName: 'Depreciation')` / `create_capsule(...)`** (step 3).
|
|
15
|
+
- **`create_journal(...)`** (step 4): one per period. The amount changes as book value falls, so a fixed-amount schedule does not fit.
|
|
16
|
+
|
|
17
|
+
### Lookup and verification tools
|
|
18
|
+
- **`search_capsules(filter: {title: {eq: <capsule title>}})`**: step 0 idempotency check. One depreciation capsule per asset; duplicate setup is almost always an error.
|
|
19
|
+
- **`search_accounts(filter: {name: {in: ['Vehicles', 'Accumulated Depreciation (Vehicles)', 'Depreciation Expense']}})`** (step 2): confirm the asset, contra-asset, and expense GL accounts exist.
|
|
20
|
+
- **`generate_trial_balance(endDate: <date>)`** (step 5): verify NBV matches the schedule.
|
|
19
21
|
|
|
20
22
|
### Cross-references
|
|
21
|
-
- Operational context: invoked during month-end close (only when an asset uses a non-SL method; Jaz native FA handles SL automatically). For SL: `create_fixed_asset` directly
|
|
22
|
-
- Sibling: `asset-disposal.md` for end-of-life de-recognition; `ifrs16-lease.md
|
|
23
|
+
- Operational context: invoked during month-end close (only when an asset uses a non-SL method; Jaz native FA handles SL automatically). For SL: `create_fixed_asset` directly; do NOT use this recipe.
|
|
24
|
+
- Sibling: `asset-disposal.md` for end-of-life de-recognition; `ifrs16-lease.md`, which uses SL depreciation via the FA register because the ROU asset is depreciated straight-line there.
|
|
23
25
|
- IFRS / accounting context: IAS 16.62, depreciation method should reflect the pattern of consumption of the asset's economic benefits. DDB / 150DB are valid alternatives to SL when usage is front-loaded (vehicles, technology). NOT for buildings, land improvements (always SL).
|
|
24
26
|
|
|
25
27
|
---
|
|
@@ -29,104 +31,129 @@
|
|
|
29
31
|
### Step 0: Idempotency check
|
|
30
32
|
|
|
31
33
|
```
|
|
32
|
-
search_capsules(filter: {title: {eq: 'DDB Depreciation
|
|
34
|
+
search_capsules(filter: {title: {eq: 'DDB Depreciation, 5 years, Delivery Vehicle TRK-001'}})
|
|
33
35
|
```
|
|
34
36
|
|
|
35
|
-
If a result returns: halt and surface "Depreciation capsule for asset `<name>` already exists. Re-
|
|
37
|
+
If a result returns: halt and surface "Depreciation capsule for asset `<name>` already exists. Re-posting would create duplicate depreciation journals. Confirm: if revising the depreciation schedule (changed useful life or salvage), delete the remaining DRAFT journals via `delete_journal`, then post the revised periods into the same capsule."
|
|
38
|
+
|
|
39
|
+
### Step 1: Calculate
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
```
|
|
42
|
+
calculate(
|
|
43
|
+
type: 'depreciation',
|
|
44
|
+
cost: 50000,
|
|
45
|
+
salvageValue: 5000,
|
|
46
|
+
usefulLifeYears: 5,
|
|
47
|
+
method: 'ddb',
|
|
48
|
+
frequency: 'monthly',
|
|
49
|
+
currency: 'SGD'
|
|
50
|
+
)
|
|
51
|
+
```
|
|
38
52
|
|
|
39
53
|
```
|
|
40
54
|
clio calc depreciation --cost 50000 --salvage 5000 --life 5 --method ddb --frequency monthly --currency SGD --json
|
|
41
55
|
```
|
|
42
56
|
|
|
43
|
-
Returns
|
|
57
|
+
Returns `{ totalDepreciation: 45000, schedule: [{ period, date, openingBookValue, ddbAmount, slAmount, methodUsed, depreciation, closingBookValue, journal }, ...60], blueprint }`. `date` is `null` on every row.
|
|
44
58
|
|
|
45
59
|
DDB rate formula: `2 / useful-life-years = 40% annual` for 5-year life.
|
|
46
60
|
150DB rate: `1.5 / useful-life-years = 30% annual` for 5-year life.
|
|
47
61
|
|
|
48
|
-
|
|
62
|
+
For this asset the annual charges are 20,000 / 12,000 / 7,200 / 4,320 / 1,480. Each year the calculator computes the declining-balance charge (`ddbAmount`) and straight-line over the remaining life (`slAmount`), and switches to SL once SL is at least the declining-balance charge or the declining-balance charge would take book value below salvage; `methodUsed` shows which applied. Here it switches in year 5 (the DDB charge would breach the $5,000 floor), so the book value lands on the salvage value exactly and never below it.
|
|
63
|
+
|
|
64
|
+
With `frequency: 'monthly'` each year's charge is spread evenly over its 12 months (1,666.67 a month in year 1, 1,000.00 in year 2, ...), and the last month of each year absorbs the rounding.
|
|
65
|
+
|
|
66
|
+
**Monthly posting reads `schedule[]`, not `blueprint.steps`.** For DDB and 150DB the blueprint always carries the ANNUAL steps (5 here), whatever the frequency. The 60 monthly entries are the `journal` on each `schedule` row.
|
|
67
|
+
|
|
68
|
+
Save the schedule to `workpapers/<period>/depreciation-<asset-id>.json` for the workpaper record (audit will sample-test).
|
|
49
69
|
|
|
50
|
-
### Step 2:
|
|
70
|
+
### Step 2: Resolve accounts
|
|
71
|
+
|
|
72
|
+
The calculator's `Depreciation Expense` and `Accumulated Depreciation` are labels. Map each to the real account:
|
|
73
|
+
- `search_accounts(filter: {name: {in: ['Vehicles', 'Accumulated Depreciation (Vehicles)', 'Depreciation Expense']}})`. If one is missing: halt. Suggested classifications: asset GL → `Non-current Asset`; accumulated depreciation → `Non-current Asset` (contra); expense → `Operating Expense`.
|
|
74
|
+
|
|
75
|
+
NO contact (depreciation has no counterparty). NO bank account.
|
|
76
|
+
|
|
77
|
+
### Step 3: Create the capsule
|
|
51
78
|
|
|
52
79
|
```
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
usefulLifeYears: 5,
|
|
59
|
-
method: 'ddb',
|
|
60
|
-
frequency: 'monthly',
|
|
61
|
-
startDate: '2025-01-01',
|
|
62
|
-
currency: 'SGD'
|
|
80
|
+
list_capsule_types()
|
|
81
|
+
create_capsule(
|
|
82
|
+
capsuleTypeResourceId: <id of 'Depreciation'>,
|
|
83
|
+
title: 'DDB Depreciation, 5 years, Delivery Vehicle TRK-001',
|
|
84
|
+
description: <blueprint.capsuleDescription>
|
|
63
85
|
)
|
|
64
86
|
```
|
|
65
87
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
### Step 3: Resolve dependencies
|
|
88
|
+
If `Depreciation` is not in the list: `create_capsule_type(displayName: 'Depreciation')` first.
|
|
69
89
|
|
|
70
|
-
|
|
71
|
-
- `search_accounts(filter: {name: {eq: <accountName>}})`. If empty: halt. Suggested classifications: asset GL → `Non-current Asset`; accumulated depreciation → `Non-current Asset` (contra); expense → `Operating Expense`.
|
|
90
|
+
### Step 4: Post the journals
|
|
72
91
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
### Step 4: Execute
|
|
92
|
+
One `create_journal` per period, dated by you (month-end for monthly, year-end for annual), with that period's amount:
|
|
76
93
|
|
|
77
94
|
```
|
|
78
|
-
|
|
95
|
+
create_journal(
|
|
96
|
+
valueDate: '2025-01-31',
|
|
97
|
+
reference: 'DEP-TRK-001-01',
|
|
98
|
+
journalEntries: [
|
|
99
|
+
{ accountResourceId: <Depreciation Expense>, type: 'DEBIT', amount: 1666.67, description: 'DDB depreciation, month 1 of 60' },
|
|
100
|
+
{ accountResourceId: <Accumulated Depreciation (Vehicles)>, type: 'CREDIT', amount: 1666.67, description: 'DDB depreciation, month 1 of 60' }
|
|
101
|
+
],
|
|
102
|
+
saveAsDraft: false,
|
|
103
|
+
capsuleResourceId: <capsule id>
|
|
104
|
+
)
|
|
79
105
|
```
|
|
80
106
|
|
|
81
|
-
|
|
107
|
+
Post each period's journal at that period's close, or post them all now as drafts and finalize one per period. Agree the cadence with the practitioner; the reference pattern (`DEP-TRK-001-01` to `-60`) is what finds a period's journal later.
|
|
82
108
|
|
|
83
|
-
**Critical:** Do NOT also
|
|
109
|
+
**Critical:** Do NOT also register this asset in the FA register with `depreciationMethod: 'STRAIGHT_LINE'`. The asset is tracked via the CoA (its cost sits in the `Vehicles` account; its NBV is `cost − accumulated depreciation` per TB). A straight-line registration would post duplicate depreciation, double-counting.
|
|
84
110
|
|
|
85
|
-
If the asset MUST be in the FA register for reporting reasons (e.g. fixed-assets
|
|
111
|
+
If the asset MUST be in the FA register for reporting reasons (e.g. the fixed-assets summary report): register it with `depreciationMethod: 'NO_DEPRECIATION'`, so the register lists the asset and posts nothing. The register's book value then stays at cost; the journals in this capsule are the depreciation record.
|
|
86
112
|
|
|
87
113
|
### Step 5: Monthly action (during monthly-close)
|
|
88
114
|
|
|
89
|
-
|
|
115
|
+
Post this period's journal, or find it by its reference and finalize it:
|
|
90
116
|
|
|
91
117
|
```
|
|
92
|
-
|
|
118
|
+
search_journals(filter: {reference: {eq: 'DEP-TRK-001-03'}})
|
|
93
119
|
update_journal(resourceId: <journal id>, saveAsDraft: false)
|
|
94
120
|
```
|
|
95
121
|
|
|
96
|
-
|
|
122
|
+
Journals cannot be filtered by capsule, and a date-plus-status search returns every matching DRAFT in the org: never feed one into `bulk_update_journals` or `delete_journal`.
|
|
123
|
+
|
|
124
|
+
Verify after each period:
|
|
97
125
|
- `generate_trial_balance(endDate: <month-end>)`.
|
|
98
|
-
- Assert: `balance['Accumulated Depreciation (Vehicles)'] == -schedule[periodIndex].
|
|
99
|
-
- Assert: `balance['Depreciation Expense'] (period MTD) == schedule[periodIndex].
|
|
126
|
+
- Assert: `balance['Accumulated Depreciation (Vehicles)'] == -(cost - schedule[periodIndex].closingBookValue)` (within 1 cent).
|
|
127
|
+
- Assert: `balance['Depreciation Expense'] (period MTD) == schedule[periodIndex].depreciation` (within 1 cent).
|
|
100
128
|
- Assert: `balance['Vehicles'] - |balance['Accumulated Depreciation (Vehicles)']| == schedule[periodIndex].closingBookValue`.
|
|
101
129
|
|
|
102
130
|
After the FINAL period (month 60):
|
|
103
|
-
- Assert: `closingBookValue == salvage` exactly ($5,000;
|
|
104
|
-
- Asset is now fully depreciated. If sold/disposed
|
|
131
|
+
- Assert: `closingBookValue == salvage` exactly ($5,000; the final period carries the rounding).
|
|
132
|
+
- Asset is now fully depreciated. If sold/disposed: follow `asset-disposal.md`. If retained at salvage value: close the capsule; no further depreciation.
|
|
105
133
|
|
|
106
134
|
---
|
|
107
135
|
|
|
108
|
-
## Common
|
|
136
|
+
## Common problems and recovery
|
|
109
137
|
|
|
110
|
-
|
|
|
138
|
+
| Where | Problem | Recovery |
|
|
111
139
|
|--------|-------|----------|
|
|
112
|
-
|
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
|
|
|
116
|
-
|
|
|
117
|
-
|
|
|
118
|
-
| Disposal mid-life | (process) | Invoke `asset-disposal.md` recipe. Then close depreciation capsule, delete remaining DRAFT depreciation journals. |
|
|
140
|
+
| Calculator | "Useful life (years) must be a positive integer" | Whole years only, 1 or more. An item with no multi-period life is a period cost: expense it via `create_bill` to `Operating Expense`. |
|
|
141
|
+
| Calculator | "Salvage value (S) must be less than cost (C)" | Salvage ≥ cost is non-sensical. Verify inputs. |
|
|
142
|
+
| Step 2 | An account is missing | `search_accounts`; create via `create_account`. |
|
|
143
|
+
| Verification | NBV stuck above schedule | Either a period's journal is missing or still a DRAFT (re-run step 5), OR Jaz FA also auto-posted SL depreciation (asset got duplicate-registered). Audit `search_fixed_assets(filter: {name: {contains: <asset>}})`. If duplicated: remove the duplicate registration and its auto-posted depreciation, **not** with `discard_fixed_asset`, whose own description is "records the disposal and final depreciation", i.e. it POSTS more entries in a case that wanted fewer. If the duplicate is still a draft, `delete_fixed_asset` (draft-only by design). If it is already active, stop: deleting is impossible and reversing its posted depreciation is a judgment call; surface both registrations to the practitioner. |
|
|
144
|
+
| Asset reaches salvage early (impairment) | (process) | Per IAS 36, if recoverable amount drops below NBV, write down. Manual journal: Dr Impairment Loss / Cr Accumulated Depreciation for the impairment amount. Delete the remaining DRAFT depreciation journals (`delete_journal`) and recalculate from the written-down value; the schedule assumed a normal life. |
|
|
145
|
+
| Disposal mid-life | (process) | Follow `asset-disposal.md`. Then close the depreciation capsule and delete any remaining DRAFT depreciation journals. |
|
|
119
146
|
|
|
120
147
|
---
|
|
121
148
|
|
|
122
149
|
## Variations
|
|
123
150
|
|
|
124
151
|
- **150DB**: `method: '150db'`. Rate is 1.5x SL instead of 2x. Less aggressive front-loading.
|
|
125
|
-
- **Annual frequency**: `frequency: 'annual'
|
|
126
|
-
- **Sum-of-years' digits (SYD)**: NOT supported by the
|
|
152
|
+
- **Annual frequency**: `frequency: 'annual'` (the default). 5 annual journals instead of 60 monthly. Used when reporting cadence is annual or asset is small. Here `blueprint.steps` and `schedule[]` agree.
|
|
153
|
+
- **Sum-of-years' digits (SYD)**: NOT supported by the calculator. Work the SYD amounts by hand and post manual journals for each period (rare in modern practice).
|
|
127
154
|
- **Units-of-production**: NOT supported (depreciation per unit produced, not per period). Manual journal pattern: at each period-end, compute `units × per-unit-rate`, post Dr Depreciation Expense / Cr Accumulated Depreciation.
|
|
128
|
-
- **Component depreciation** (
|
|
129
|
-
- **Mid-period acquisition:** The calculator does NOT prorate the first period. Schedule entries are full
|
|
155
|
+
- **Component depreciation** (IAS 16.43): different parts of an asset depreciated separately. Each component gets its own calculation + capsule.
|
|
156
|
+
- **Mid-period acquisition:** The calculator does NOT prorate the first period. Schedule entries are full periods. For partial-period accuracy, either (a) start the journals in the first full period after acquisition (lose the partial-period depreciation), or (b) post a manual partial-period journal via `create_journal` for the days in the acquisition period, then post the schedule from the next full period.
|
|
130
157
|
|
|
131
158
|
---
|
|
132
159
|
|
|
@@ -136,4 +163,4 @@ After the FINAL period (month 60):
|
|
|
136
163
|
- Year-end close (full FY-end depreciation reconciliation): sum 12 monthly journals against `clio calc depreciation --frequency annual` cross-check; auditor will sample-test.
|
|
137
164
|
- Data migration: opening accumulated depreciation loaded via conversion (Conversion Clearing > Accumulated Depreciation account); recipe runs forward from the migration date with `cost: <NBV at migration>` instead of original cost. Useful-life-years should be `remaining life`, not original.
|
|
138
165
|
- Sibling recipe `asset-disposal.md`: end-of-life de-recognition.
|
|
139
|
-
- `audit-prep.md` step 8: supporting schedule via `search_capsules(filter: {status: {eq: 'ACTIVE'}}) (capsule type is not filterable; see `jobs/references/building-blocks.md` § Filter limits)
|
|
166
|
+
- `audit-prep.md` step 8: supporting schedule via `search_capsules(filter: {status: {eq: 'ACTIVE'}})` (capsule type is not filterable; see `jobs/references/building-blocks.md` § Filter limits) + per-capsule `clio calc depreciation` recompute.
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
# Recipe: Deferred Revenue (
|
|
1
|
+
# Recipe: Deferred Revenue (calculator type: `deferred-revenue`)
|
|
2
2
|
|
|
3
|
-
> Mirror of prepaid-amortization for the income side: customer pays upfront for a service delivered over time.
|
|
3
|
+
> Mirror of prepaid-amortization for the income side: customer pays upfront for a service delivered over time. One upfront invoice coded to the Deferred Revenue liability, then N recognition entries that roll the liability into revenue, all in one capsule. Same operational pattern; opposite accounting direction. You calculate, create the capsule and post each entry yourself (see `building-blocks.md` § The three-step flow).
|
|
4
4
|
|
|
5
|
-
## Tools
|
|
5
|
+
## Tools and calculator this recipe uses
|
|
6
6
|
|
|
7
|
-
###
|
|
8
|
-
-
|
|
9
|
-
-
|
|
7
|
+
### Calculator (offline, posts nothing)
|
|
8
|
+
- **MCP: `calculate(type: 'deferred-revenue', amount, periods, frequency, startDate, currency)`** (step 1).
|
|
9
|
+
- **CLI: `clio calc deferred-revenue --amount <total> --periods <n> --start-date <YYYY-MM-DD> --currency <code> --json`** (step 1): the same result.
|
|
10
10
|
|
|
11
|
-
###
|
|
12
|
-
- **`
|
|
11
|
+
### Posting tools
|
|
12
|
+
- **`list_capsule_types` / `create_capsule_type(displayName: 'Deferred Revenue')` / `create_capsule(...)`** (step 3).
|
|
13
|
+
- **`create_invoice(...)`** (step 4): the upfront customer invoice, line coded to Deferred Revenue (NOT to Revenue).
|
|
14
|
+
- **`create_scheduled_journal(...)`** (step 4, equal monthly amounts) or **`create_journal(...)`** per period.
|
|
13
15
|
|
|
14
|
-
###
|
|
15
|
-
- **`
|
|
16
|
-
- **`
|
|
17
|
-
- **`search_accounts(filter: {name: {in: ['<deferred liability GL>', '<revenue GL>']}})
|
|
18
|
-
- **`
|
|
19
|
-
- **`
|
|
20
|
-
- **`finalize_invoice(resourceId: <id>)`**, step 4 fallback: lift the upfront invoice from DRAFT to ACTIVE once practitioner confirms the engagement is genuinely starting.
|
|
21
|
-
- **`bulk_update_journals(items: [{resourceId: <id>, saveAsDraft: false}, ...])`**, step 5 monthly: finalize this period's pre-emitted DRAFT recognition journal.
|
|
16
|
+
### Lookup and verification tools
|
|
17
|
+
- **`search_capsules(filter: {title: {eq: <capsule title>}})`** (step 0): idempotency check.
|
|
18
|
+
- **`search_contacts(filter: {customer: true, name: {eq: <customer>}})`** (step 2): resolve the paying customer; `create_contact(...)` with `customer: true` if it does not exist.
|
|
19
|
+
- **`search_accounts(filter: {name: {in: ['<deferred liability GL>', '<revenue GL>']}})`** (step 2): confirm both GL accounts exist.
|
|
20
|
+
- **`finalize_invoice(resourceId: <id>)`** (step 4): lift the upfront invoice from DRAFT to ACTIVE once the practitioner confirms the engagement is genuinely starting.
|
|
21
|
+
- **`generate_trial_balance(endDate: <date>)`** (step 5): verify the Deferred Revenue balance unwinds correctly.
|
|
22
22
|
|
|
23
23
|
### Cross-references
|
|
24
|
-
- Operational context: invoked during month-end close (
|
|
25
|
-
- Sibling recipes: `prepaid-amortization.md` (mirror: same
|
|
24
|
+
- Operational context: invoked during month-end close (confirm this period's recognition for existing capsules; set up a new capsule for any new deferred arrangement starting this period).
|
|
25
|
+
- Sibling recipes: `prepaid-amortization.md` (mirror: same pattern, opposite direction).
|
|
26
26
|
- IFRS / accounting context: IFRS 15, revenue recognition over time when control transfers gradually (subscriptions, retainers, multi-period service contracts). The recipe assumes ratable straight-line recognition; for stage-based / milestone billing, use a different pattern (see Variations).
|
|
27
27
|
|
|
28
28
|
---
|
|
@@ -35,22 +35,13 @@
|
|
|
35
35
|
search_capsules(filter: {title: {eq: 'FY2025 Acme Annual License'}})
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
If a result returns: halt and surface "Deferred revenue capsule `<name>` already exists. Re-
|
|
38
|
+
If a result returns: halt and surface "Deferred revenue capsule `<name>` already exists. Re-posting would create a duplicate upfront invoice. Confirm intent; if extending an existing arrangement, post the extra entries into the existing capsule."
|
|
39
39
|
|
|
40
|
-
### Step 1:
|
|
40
|
+
### Step 1: Calculate
|
|
41
41
|
|
|
42
42
|
```
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
Returns: `{ perPeriodAmount: 2000, recognitionStartDate: '2025-01-31', recognitionEndDate: '2025-12-31', schedule: [{period, recognitionDate, amount}, ...12] }`. Verify total recognition matches the invoice amount within 1 cent (engine carries rounding into final period).
|
|
47
|
-
|
|
48
|
-
### Step 2: Plan the recipe
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
plan_recipe(
|
|
52
|
-
// Accounts, capsule and counterparty are not plan_recipe params: execute_recipe resolves accounts from the CoA and takes bankAccountName / contactName.
|
|
53
|
-
recipe: 'deferred-revenue',
|
|
43
|
+
calculate(
|
|
44
|
+
type: 'deferred-revenue',
|
|
54
45
|
amount: 24000,
|
|
55
46
|
periods: 12,
|
|
56
47
|
startDate: '2025-01-01',
|
|
@@ -58,75 +49,121 @@ plan_recipe(
|
|
|
58
49
|
)
|
|
59
50
|
```
|
|
60
51
|
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
52
|
+
```
|
|
53
|
+
clio calc deferred-revenue --amount 24000 --periods 12 --start-date 2025-01-01 --currency SGD --json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Returns `{ perPeriodAmount: 2000, schedule: [{ period, date, amortized, remainingBalance, journal }, ...12], blueprint }`. Total recognition equals the invoice amount: the final period absorbs any rounding remainder.
|
|
57
|
+
|
|
58
|
+
`blueprint.steps`:
|
|
59
|
+
- Step 1, `invoice`, dated `2025-01-01`: Dr Cash / Bank Account 24,000 / Cr Deferred Revenue 24,000.
|
|
60
|
+
- Steps 2 to 13, `journal`, dated `2025-02-01` through `2026-01-01`: Dr Deferred Revenue 2,000 / Cr Revenue 2,000.
|
|
66
61
|
|
|
67
|
-
|
|
62
|
+
For month-end recognition dates, pass a month-end start date (`2024-12-31` gives `2025-01-31`, `2025-02-28`, ...) and date the invoice separately.
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
### Step 2: Resolve accounts and the customer
|
|
65
|
+
|
|
66
|
+
The blueprint's `Deferred Revenue`, `Revenue` and `Cash / Bank Account` are labels. Map each to the real account:
|
|
67
|
+
- `search_accounts(filter: {name: {in: ['Deferred Revenue', 'Subscription Revenue']}})`. If one is missing: halt. Suggested classifications: `Deferred Revenue` → `Current Liability`; `Subscription Revenue` (or whatever revenue line) → `Operating Revenue`.
|
|
71
68
|
|
|
72
69
|
Customer:
|
|
73
|
-
- `search_contacts(filter: {customer: true, name: {eq: 'Acme Pte Ltd'}})`. If empty: halt and surface "Customer `Acme Pte Ltd` not in Jaz contacts (or not flagged customer: true). Create via `create_contact(customer: true, ...)` or remap the customer
|
|
70
|
+
- `search_contacts(filter: {customer: true, name: {eq: 'Acme Pte Ltd'}})`. If empty: halt and surface "Customer `Acme Pte Ltd` not in Jaz contacts (or not flagged customer: true). Create via `create_contact(customer: true, ...)` or remap the customer."
|
|
74
71
|
|
|
75
|
-
### Step
|
|
72
|
+
### Step 3: Create the capsule
|
|
76
73
|
|
|
77
74
|
```
|
|
78
|
-
|
|
75
|
+
list_capsule_types()
|
|
76
|
+
create_capsule(
|
|
77
|
+
capsuleTypeResourceId: <id of 'Deferred Revenue'>,
|
|
78
|
+
title: 'FY2025 Acme Annual License',
|
|
79
|
+
description: <blueprint.capsuleDescription>
|
|
80
|
+
)
|
|
79
81
|
```
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
If `Deferred Revenue` is not in the list: `create_capsule_type(displayName: 'Deferred Revenue')` first.
|
|
84
|
+
|
|
85
|
+
### Step 4: Post the entries
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
**4a. The upfront invoice** (blueprint step 1). The credit line becomes the invoice's line item; the bank line is the receipt, recorded when the customer pays:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
create_invoice(
|
|
91
|
+
contactResourceId: <customer>,
|
|
92
|
+
autoReference: true,
|
|
93
|
+
valueDate: '2025-01-01',
|
|
94
|
+
dueDate: '2025-01-31',
|
|
95
|
+
lineItems: [{ name: 'Annual licence FY2025', quantity: 1, unitPrice: 24000, accountResourceId: <Deferred Revenue> }],
|
|
96
|
+
saveAsDraft: true,
|
|
97
|
+
capsuleResourceId: <capsule id>
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The invoice is a DRAFT; finalize via `finalize_invoice(resourceId: <invoiceResourceId>)` once the engagement starts. Customer payment is recorded separately with `pay_invoice` when the cash arrives; it settles AR and is not part of the recognition schedule.
|
|
102
|
+
|
|
103
|
+
**4b. The recognition entries** (blueprint steps 2 to 13). **Create these only after the invoice is finalized.** A schedule posts on its own dates: one created while the invoice is still a draft starts recognising revenue out of a deferred balance the books do not hold yet. If the invoice cannot be finalized now, stop here and come back.
|
|
104
|
+
|
|
105
|
+
Equal monthly amounts, so one schedule replaces the twelve journals:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
create_scheduled_journal(
|
|
109
|
+
startDate: '2025-02-01',
|
|
110
|
+
endDate: '2026-01-01',
|
|
111
|
+
repeat: 'MONTHLY',
|
|
112
|
+
valueDate: '2025-02-01',
|
|
113
|
+
reference: 'DEFREV-ACME-2025',
|
|
114
|
+
schedulerEntries: [
|
|
115
|
+
{ accountResourceId: <Deferred Revenue>, type: 'DEBIT', amount: 2000, description: 'Licence revenue: {{MONTH_NAME}} {{YEAR}}' },
|
|
116
|
+
{ accountResourceId: <Subscription Revenue>, type: 'CREDIT', amount: 2000, description: 'Licence revenue: {{MONTH_NAME}} {{YEAR}}' }
|
|
117
|
+
],
|
|
118
|
+
capsuleResourceId: <capsule id>
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Read `building-blocks.md` § "Same amount every period" for the schedule's limits (no quarterly repeat, fixed amount). With `capsuleResourceId` on the schedule, every journal it generates lands in the capsule. The alternative is one `create_journal` per blueprint step, each with `valueDate` = the step date, a findable `reference` (`DEFREV-ACME-2025-01` ...) and `capsuleResourceId`.
|
|
86
123
|
|
|
87
124
|
### Step 5: Monthly action (during monthly-close)
|
|
88
125
|
|
|
89
|
-
|
|
126
|
+
With a schedule, confirm the period's journal posted. With dated draft journals, find this period's journal by its reference and finalize it:
|
|
90
127
|
|
|
91
128
|
```
|
|
92
|
-
|
|
129
|
+
search_journals(filter: {reference: {eq: 'DEFREV-ACME-2025-03'}})
|
|
93
130
|
update_journal(resourceId: <journal id>, saveAsDraft: false)
|
|
94
131
|
```
|
|
95
132
|
|
|
96
|
-
|
|
133
|
+
Journals cannot be filtered by capsule, and a date-plus-status search returns every matching DRAFT in the org: never feed one into `bulk_update_journals` or `delete_journal`.
|
|
134
|
+
|
|
135
|
+
Verify after each period:
|
|
97
136
|
- `generate_trial_balance(endDate: <period-end>)`.
|
|
98
|
-
- Assert: `balance['Deferred Revenue'] == amount - (perPeriodAmount ×
|
|
137
|
+
- Assert: `balance['Deferred Revenue'] == amount - (perPeriodAmount × periodsRecognizedSoFar)` (within 1 cent).
|
|
99
138
|
- Assert: `balance['Subscription Revenue'] (period MTD) == perPeriodAmount` (within 1 cent).
|
|
100
139
|
|
|
101
|
-
After the FINAL period
|
|
140
|
+
After the FINAL period:
|
|
102
141
|
- Assert: `balance['Deferred Revenue'] == 0` exactly (final-period rounding absorbed).
|
|
103
|
-
- Close the capsule via a manual `update_capsule(title: '<original> [CLOSED]')` (the API has no `status` field for capsules; closure is informational only) if the org tracks capsule status.
|
|
142
|
+
- Close the capsule via a manual `update_capsule(resourceId: <id>, title: '<original> [CLOSED]')` (the API has no `status` field for capsules; closure is informational only) if the org tracks capsule status.
|
|
104
143
|
|
|
105
|
-
If customer cancels mid-term:
|
|
144
|
+
If the customer cancels mid-term: stop the remaining recognition (end the schedule with `update_scheduled_journal(resourceId: <scheduler id>, status: 'INACTIVE')`, or `delete_journal(resourceId: <id>)` for each remaining DRAFT), and post a customer credit note via `create_customer_credit_note(...)` for the unrecognized portion.
|
|
106
145
|
|
|
107
146
|
---
|
|
108
147
|
|
|
109
|
-
## Common
|
|
148
|
+
## Common problems and recovery
|
|
110
149
|
|
|
111
|
-
|
|
|
150
|
+
| Where | Problem | Recovery |
|
|
112
151
|
|--------|-------|----------|
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
|
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
118
|
-
|
|
|
119
|
-
|
|
|
120
|
-
| `bulk_update_journals` | 422 `journal_in_locked_period` | Period was locked before this monthly-close. Lift lock, finalize, re-lock. |
|
|
121
|
-
| Customer cancels mid-term | (process) | Delete remaining DRAFT journals via `delete_journal(resourceId: <id>)` per period; issue customer credit note for the unrecognized portion via `create_customer_credit_note`. |
|
|
152
|
+
| Calculator | "must be a positive number" / "must be a positive integer" | `amount` must be positive and `periods` a positive integer. For lump-sum recognition (no deferral), use `create_invoice` directly with the line coded to Revenue. |
|
|
153
|
+
| Step 2 | An account is missing | `search_accounts`; create via `create_account` if the practitioner confirms. |
|
|
154
|
+
| Step 2 | Contact exists but is not a customer | `update_contact(resourceId: <id>, customer: true)` first. |
|
|
155
|
+
| `create_invoice` | Currency not enabled for the org | `add_currency` first. |
|
|
156
|
+
| `create_capsule` | Returns the existing capsule instead of a new one | Step 0 should have caught this. Re-run step 0 and confirm intent. |
|
|
157
|
+
| Monthly finalize | Journal falls in a locked period | The period was locked before this monthly-close. Lift the lock, finalize, re-lock. |
|
|
158
|
+
| Customer cancels mid-term | (process) | Stop the remaining recognition (see step 5); issue a customer credit note for the unrecognized portion via `create_customer_credit_note`. |
|
|
122
159
|
|
|
123
160
|
---
|
|
124
161
|
|
|
125
162
|
## Variations
|
|
126
163
|
|
|
127
|
-
- **Quarterly recognition:** `periods: 4, frequency: 'quarterly'`. 4
|
|
164
|
+
- **Quarterly recognition:** `periods: 4, frequency: 'quarterly'`. 4 quarterly recognition journals at $6,000 each. Post them as dated journals (schedules have no quarterly repeat).
|
|
128
165
|
- **Partial first period:** The calculator does NOT prorate. Schedule entries are equal full-period amounts (`amount / periods`). For partial-period revenue (e.g. annual subscription starting mid-month), use `create_subscription` (handles proration natively) rather than this recipe.
|
|
129
|
-
- **Multi-currency:** Pass `currency: 'USD'` if invoice in USD; per `jaz-api/SKILL.md` rule 25, invoice records via `currency: { sourceCurrency: 'USD' }`. Recognition journals also in USD; Jaz auto-handles period-end FX revaluation of the Deferred Revenue liability balance per IAS 21.23 (do NOT
|
|
166
|
+
- **Multi-currency:** Pass `currency: 'USD'` if invoice in USD; per `jaz-api/SKILL.md` rule 25, invoice records via `currency: { sourceCurrency: 'USD' }`. Recognition journals also in USD; Jaz auto-handles period-end FX revaluation of the Deferred Revenue liability balance per IAS 21.23 (do NOT post an `fx-reval` result; see `fx-revaluation.md`).
|
|
130
167
|
- **Renewal:** New capsule per term (`'FY2026 Acme Annual License'`). Capsule lifecycle is per recognition cycle.
|
|
131
168
|
- **Stage-based / milestone billing** (NOT ratable): NOT supported by this recipe. Use `create_invoice` per milestone with line coded directly to Revenue; no deferral capsule needed.
|
|
132
169
|
- **Subscription contracts with proration / mid-cycle upgrades:** prefer Jaz native subscription tools (`create_subscription`) over this recipe; subscriptions handle proration natively. Recipe is for non-subscription deferred revenue (one-time annual licences, retainers, prepaid services).
|
|
@@ -135,7 +172,7 @@ If customer cancels mid-term: invoke ad-hoc adjustment; delete remaining DRAFT r
|
|
|
135
172
|
|
|
136
173
|
## Cross-references
|
|
137
174
|
|
|
138
|
-
- Month-end close: invoked monthly to
|
|
175
|
+
- Month-end close: invoked monthly to confirm this period's recognition per existing Deferred Revenue capsule, AND to set up new capsules when a fresh deferred arrangement starts in the period.
|
|
139
176
|
- Data migration: opening trial balance may include opening Deferred Revenue (subscriptions in flight at conversion date). Conversion (`jaz-conversion/SKILL.md § Option 2`) loads the opening balance via clearing account; this recipe then sets up forward recognition only (do NOT model historical periods retroactively).
|
|
140
177
|
- Year-end close: the final monthly close before year-end handles the December recognition journal; year-end close confirms Deferred Revenue is correctly classified as current vs non-current liability for BS presentation.
|
|
141
|
-
- Sibling recipe `prepaid-amortization.md`: same
|
|
178
|
+
- Sibling recipe `prepaid-amortization.md`: the same pattern from the buyer's perspective.
|