akt-cli 0.1.0__tar.gz → 0.3.0__tar.gz
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.
- {akt_cli-0.1.0 → akt_cli-0.3.0}/PKG-INFO +98 -11
- {akt_cli-0.1.0 → akt_cli-0.3.0}/README.md +94 -10
- {akt_cli-0.1.0 → akt_cli-0.3.0}/pyproject.toml +4 -1
- {akt_cli-0.1.0 → akt_cli-0.3.0}/src/akt/__init__.py +1 -1
- {akt_cli-0.1.0 → akt_cli-0.3.0}/src/akt/cli.py +43 -12
- akt_cli-0.3.0/src/akt/client.py +415 -0
- akt_cli-0.3.0/src/akt/commands.py +205 -0
- {akt_cli-0.1.0 → akt_cli-0.3.0}/src/akt/config.py +10 -0
- {akt_cli-0.1.0 → akt_cli-0.3.0}/src/akt/registry.py +65 -0
- {akt_cli-0.1.0 → akt_cli-0.3.0}/src/akt/resources.py +278 -0
- akt_cli-0.1.0/src/akt/client.py +0 -240
- akt_cli-0.1.0/src/akt/commands.py +0 -88
- {akt_cli-0.1.0 → akt_cli-0.3.0}/LICENSE +0 -0
- {akt_cli-0.1.0 → akt_cli-0.3.0}/src/akt/output.py +0 -0
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: akt-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: akt — a CLI toolbox to fully drive an Akaunting accounting instance
|
|
5
5
|
Keywords: akaunting,accounting,cli,invoices,bills,api
|
|
6
6
|
Author: AsyncAlchemist
|
|
7
7
|
License-Expression: MIT
|
|
8
8
|
License-File: LICENSE
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
10
13
|
Classifier: Environment :: Console
|
|
11
14
|
Classifier: Topic :: Office/Business :: Financial :: Accounting
|
|
12
15
|
Requires-Dist: requests>=2.31
|
|
@@ -16,20 +19,25 @@ Project-URL: Repository, https://github.com/AsyncAlchemist/akt-cli
|
|
|
16
19
|
Project-URL: Issues, https://github.com/AsyncAlchemist/akt-cli/issues
|
|
17
20
|
Description-Content-Type: text/markdown
|
|
18
21
|
|
|
22
|
+
<div align="center">
|
|
23
|
+
|
|
19
24
|
# akt — Akaunting CLI toolbox
|
|
25
|
+
### Drive your Akaunting accounting instance entirely from the command line
|
|
26
|
+
|
|
27
|
+
>`akt` gives you full create / read / update / delete for customers, vendors, items, invoices, bills, payments, accounts, categories, taxes, currencies and transfers — plus double-entry journal entries and the chart of accounts, and a `raw` escape hatch for any other endpoint. Built and tested against [Akaunting](https://akaunting.com) **3.1.x**; works with any 3.x deployment that exposes the REST API.
|
|
20
28
|
|
|
21
|
-
[](https://pypi.org/project/akt-cli/)
|
|
22
|
-
[](https://pypi.org/project/akt-cli/)
|
|
30
|
+
[](https://github.com/AsyncAlchemist/akt-cli/actions/workflows/ci.yml)
|
|
31
|
+
[](https://github.com/AsyncAlchemist/akt-cli/actions/workflows/release.yml)
|
|
32
|
+
[](https://github.com/AsyncAlchemist/akt-cli/actions/workflows/publish.yml)
|
|
33
|
+
[](https://codecov.io/github/AsyncAlchemist/akt-cli)
|
|
25
34
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
[](https://github.com/AsyncAlchemist/akt-cli/releases)
|
|
36
|
+
[](https://pypi.org/project/akt-cli/)
|
|
37
|
+
[](https://pypi.org/project/akt-cli/)
|
|
38
|
+
[](LICENSE)
|
|
30
39
|
|
|
31
|
-
|
|
32
|
-
deployment that exposes the REST API.
|
|
40
|
+
</div>
|
|
33
41
|
|
|
34
42
|
## Install
|
|
35
43
|
|
|
@@ -93,8 +101,18 @@ Akaunting folds several nouns onto shared endpoints; `akt` hides that:
|
|
|
93
101
|
| `invoice` | `documents` | document of type `invoice` |
|
|
94
102
|
| `bill` | `documents` | document of type `bill` |
|
|
95
103
|
| `payment` | `transactions` | income (invoice) or expense (bill) transaction |
|
|
104
|
+
| `journal-entry` | `journal-entry` | double-entry general-ledger entry (module) |
|
|
105
|
+
| `chart-of-account` | `chart-of-accounts` | GL accounts — read via API, CRUD via web |
|
|
96
106
|
| `item`, `account`, `category`, `tax`, `currency`, `transfer` | as named | |
|
|
97
107
|
|
|
108
|
+
> `journal-entry` and `chart-of-account` require the **Double-Entry** module
|
|
109
|
+
> installed on the instance. The module publishes chart-of-accounts read-only on
|
|
110
|
+
> the `/api` surface (index/show); its create/update/delete live only on the
|
|
111
|
+
> session/CSRF **web** route. `akt chart-of-account` gives you the full verb set
|
|
112
|
+
> anyway — `list`/`get` hit `/api`, while `create`/`update`/`delete` transparently
|
|
113
|
+
> drive the web CRUD with your admin session (the same mechanism
|
|
114
|
+
> `download-attachment` already uses).
|
|
115
|
+
|
|
98
116
|
> The `contacts` and `documents` endpoints derive their permission from a
|
|
99
117
|
> `search=type:<x>` query param. `akt` injects this automatically — calling them
|
|
100
118
|
> raw without it returns `403 necessary access rights`.
|
|
@@ -113,6 +131,17 @@ akt <noun> enable <id> # where applicable
|
|
|
113
131
|
akt <noun> disable <id>
|
|
114
132
|
```
|
|
115
133
|
|
|
134
|
+
Bills, invoices and payments additionally support **attachments** (scanned bills,
|
|
135
|
+
receipts, PDFs):
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
akt <noun> create ... --attachment ./file.pdf # repeatable; upload on create
|
|
139
|
+
akt <noun> update <id> --attachment ./file.pdf # attach to an existing record
|
|
140
|
+
akt <noun> update <id> --remove-attachment # clear existing attachment(s)
|
|
141
|
+
akt <noun> attachments <id> # list attached files (id, name, size)
|
|
142
|
+
akt <noun> download-attachment <id> [--out DIR] [--media-id ID]
|
|
143
|
+
```
|
|
144
|
+
|
|
116
145
|
Output is a table by default; add `--json` (works before or after the verb) for
|
|
117
146
|
raw JSON suitable for piping into `jq`.
|
|
118
147
|
|
|
@@ -154,6 +183,37 @@ akt payment create --invoice 34 --amount 750 \
|
|
|
154
183
|
akt bill create --contact 13 --item 'name=Paper,price=40,quantity=5'
|
|
155
184
|
akt payment create --bill 41
|
|
156
185
|
|
|
186
|
+
# Attachments: upload the source PDF/scan and fetch it back later
|
|
187
|
+
akt bill create --contact 13 --item 'name=Paper,price=40,quantity=5' \
|
|
188
|
+
--attachment ./supplier-bill.pdf
|
|
189
|
+
akt payment update 57 --attachment ./receipt.pdf # attach to an existing payment
|
|
190
|
+
akt bill attachments 41 # list attached files
|
|
191
|
+
akt bill download-attachment 41 --out ./downloads # save to disk
|
|
192
|
+
akt payment update 57 --remove-attachment # clear attachments
|
|
193
|
+
|
|
194
|
+
# Double-entry general ledger (requires the Double-Entry module)
|
|
195
|
+
akt chart-of-account list # read the chart of accounts
|
|
196
|
+
akt chart-of-account get 12
|
|
197
|
+
|
|
198
|
+
# Build the chart of accounts as code (create/update/delete run via the web
|
|
199
|
+
# session; type-id is the double-entry account-type id — copy it from an
|
|
200
|
+
# existing account's `type_id`)
|
|
201
|
+
akt chart-of-account create --name "Cash on Hand" --code 1010 --type-id 6
|
|
202
|
+
akt chart-of-account create --name "Petty Cash" --code 1011 --type-id 6 --account-id 12
|
|
203
|
+
akt chart-of-account update 12 --code 1000 --description "Operating cash"
|
|
204
|
+
akt chart-of-account delete 12
|
|
205
|
+
|
|
206
|
+
# Post a balanced journal entry (>= 2 lines; debits must equal credits;
|
|
207
|
+
# journal number auto-generated, basis defaults to accrual)
|
|
208
|
+
akt journal-entry create --description "Owner capital contribution" \
|
|
209
|
+
--item 'account_id=10,debit=5000' \
|
|
210
|
+
--item 'account_id=30,credit=5000'
|
|
211
|
+
akt journal-entry list
|
|
212
|
+
akt journal-entry update 4 --description "Corrected memo"
|
|
213
|
+
akt journal-entry create --description "Vendor bill accrual" --basis accrual \
|
|
214
|
+
--item 'account_id=60,debit=250' --item 'account_id=21,credit=250' \
|
|
215
|
+
--attachment ./invoice.pdf
|
|
216
|
+
|
|
157
217
|
# Anything else: raw API access
|
|
158
218
|
akt raw GET reports
|
|
159
219
|
akt raw POST items --data '{"name":"Ad-hoc","type":"service","sale_price":99}'
|
|
@@ -177,8 +237,35 @@ Driving Akaunting's API directly has sharp edges; `akt` papers over these:
|
|
|
177
237
|
so they aren't lost.
|
|
178
238
|
* **Nested payment route** — paying a document must POST to
|
|
179
239
|
`documents/{id}/transactions`; the flat `transactions` endpoint rejects it.
|
|
240
|
+
The same applies to *updating* a document-linked payment (e.g. attaching a
|
|
241
|
+
file to it) — `akt` picks the nested route automatically.
|
|
242
|
+
* **Multipart uploads** — attachments switch the request from JSON to
|
|
243
|
+
`multipart/form-data` with the `attachment[]` field; updates are sent as
|
|
244
|
+
`POST` + `_method=PATCH` because PHP won't populate `$_FILES` on a real `PUT`.
|
|
245
|
+
* **Attachment download isn't on `/api`** — Akaunting only serves attachment
|
|
246
|
+
bytes from the session-authenticated web route `/{company}/uploads/{id}/download`.
|
|
247
|
+
`akt download-attachment` transparently logs in a web session with your admin
|
|
248
|
+
credentials (reused for the process) to fetch the file; metadata (id, name,
|
|
249
|
+
size) comes from the `/api` record itself.
|
|
180
250
|
* **Full-replace updates** — Akaunting PUT re-validates required fields, so
|
|
181
251
|
`akt` merges your changes onto the current record.
|
|
252
|
+
* **Journal entries must balance** — a `journal-entry` needs >= 2 lines whose
|
|
253
|
+
debits equal its credits; `akt` validates this client-side (clear error)
|
|
254
|
+
before hitting the API. Each line carries both a `debit` and a `credit` key
|
|
255
|
+
(the unused side sent as `0`) because Akaunting validates both as required.
|
|
256
|
+
* **Journal updates re-derive ledgers** — like documents, a journal update
|
|
257
|
+
deletes any ledger line absent from the request. `akt` resends the existing
|
|
258
|
+
lines (with their ledger ids) so an update that only changes a field doesn't
|
|
259
|
+
wipe the entry, and auto-generates the `journal_number` from the module's
|
|
260
|
+
`double-entry.journal.number_*` settings when you don't pass one.
|
|
261
|
+
* **Chart-of-accounts CRUD is web-only** — the Double-Entry module exposes
|
|
262
|
+
accounts read-only on `/api`; create/update/delete exist solely on the
|
|
263
|
+
session/CSRF web route. `akt chart-of-account create|update|delete` logs in a
|
|
264
|
+
web session (reusing your admin credentials, cached for the process), attaches
|
|
265
|
+
the CSRF token, and unwraps Akaunting's `{success, error, data, message}` AJAX
|
|
266
|
+
envelope — so a server-side block (e.g. *deleting an account that has ledgers*)
|
|
267
|
+
surfaces as a normal error. Updates resend `name` (required by Akaunting on
|
|
268
|
+
update) from the current record when you don't pass one.
|
|
182
269
|
|
|
183
270
|
### Invoice creation may be gated by a plan check
|
|
184
271
|
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# akt — Akaunting CLI toolbox
|
|
4
|
+
### Drive your Akaunting accounting instance entirely from the command line
|
|
5
|
+
|
|
6
|
+
>`akt` gives you full create / read / update / delete for customers, vendors, items, invoices, bills, payments, accounts, categories, taxes, currencies and transfers — plus double-entry journal entries and the chart of accounts, and a `raw` escape hatch for any other endpoint. Built and tested against [Akaunting](https://akaunting.com) **3.1.x**; works with any 3.x deployment that exposes the REST API.
|
|
2
7
|
|
|
3
|
-
[](https://pypi.org/project/akt-cli/)
|
|
4
|
-
[](https://pypi.org/project/akt-cli/)
|
|
9
|
+
[](https://github.com/AsyncAlchemist/akt-cli/actions/workflows/ci.yml)
|
|
10
|
+
[](https://github.com/AsyncAlchemist/akt-cli/actions/workflows/release.yml)
|
|
11
|
+
[](https://github.com/AsyncAlchemist/akt-cli/actions/workflows/publish.yml)
|
|
12
|
+
[](https://codecov.io/github/AsyncAlchemist/akt-cli)
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
[](https://github.com/AsyncAlchemist/akt-cli/releases)
|
|
15
|
+
[](https://pypi.org/project/akt-cli/)
|
|
16
|
+
[](https://pypi.org/project/akt-cli/)
|
|
17
|
+
[](LICENSE)
|
|
12
18
|
|
|
13
|
-
|
|
14
|
-
deployment that exposes the REST API.
|
|
19
|
+
</div>
|
|
15
20
|
|
|
16
21
|
## Install
|
|
17
22
|
|
|
@@ -75,8 +80,18 @@ Akaunting folds several nouns onto shared endpoints; `akt` hides that:
|
|
|
75
80
|
| `invoice` | `documents` | document of type `invoice` |
|
|
76
81
|
| `bill` | `documents` | document of type `bill` |
|
|
77
82
|
| `payment` | `transactions` | income (invoice) or expense (bill) transaction |
|
|
83
|
+
| `journal-entry` | `journal-entry` | double-entry general-ledger entry (module) |
|
|
84
|
+
| `chart-of-account` | `chart-of-accounts` | GL accounts — read via API, CRUD via web |
|
|
78
85
|
| `item`, `account`, `category`, `tax`, `currency`, `transfer` | as named | |
|
|
79
86
|
|
|
87
|
+
> `journal-entry` and `chart-of-account` require the **Double-Entry** module
|
|
88
|
+
> installed on the instance. The module publishes chart-of-accounts read-only on
|
|
89
|
+
> the `/api` surface (index/show); its create/update/delete live only on the
|
|
90
|
+
> session/CSRF **web** route. `akt chart-of-account` gives you the full verb set
|
|
91
|
+
> anyway — `list`/`get` hit `/api`, while `create`/`update`/`delete` transparently
|
|
92
|
+
> drive the web CRUD with your admin session (the same mechanism
|
|
93
|
+
> `download-attachment` already uses).
|
|
94
|
+
|
|
80
95
|
> The `contacts` and `documents` endpoints derive their permission from a
|
|
81
96
|
> `search=type:<x>` query param. `akt` injects this automatically — calling them
|
|
82
97
|
> raw without it returns `403 necessary access rights`.
|
|
@@ -95,6 +110,17 @@ akt <noun> enable <id> # where applicable
|
|
|
95
110
|
akt <noun> disable <id>
|
|
96
111
|
```
|
|
97
112
|
|
|
113
|
+
Bills, invoices and payments additionally support **attachments** (scanned bills,
|
|
114
|
+
receipts, PDFs):
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
akt <noun> create ... --attachment ./file.pdf # repeatable; upload on create
|
|
118
|
+
akt <noun> update <id> --attachment ./file.pdf # attach to an existing record
|
|
119
|
+
akt <noun> update <id> --remove-attachment # clear existing attachment(s)
|
|
120
|
+
akt <noun> attachments <id> # list attached files (id, name, size)
|
|
121
|
+
akt <noun> download-attachment <id> [--out DIR] [--media-id ID]
|
|
122
|
+
```
|
|
123
|
+
|
|
98
124
|
Output is a table by default; add `--json` (works before or after the verb) for
|
|
99
125
|
raw JSON suitable for piping into `jq`.
|
|
100
126
|
|
|
@@ -136,6 +162,37 @@ akt payment create --invoice 34 --amount 750 \
|
|
|
136
162
|
akt bill create --contact 13 --item 'name=Paper,price=40,quantity=5'
|
|
137
163
|
akt payment create --bill 41
|
|
138
164
|
|
|
165
|
+
# Attachments: upload the source PDF/scan and fetch it back later
|
|
166
|
+
akt bill create --contact 13 --item 'name=Paper,price=40,quantity=5' \
|
|
167
|
+
--attachment ./supplier-bill.pdf
|
|
168
|
+
akt payment update 57 --attachment ./receipt.pdf # attach to an existing payment
|
|
169
|
+
akt bill attachments 41 # list attached files
|
|
170
|
+
akt bill download-attachment 41 --out ./downloads # save to disk
|
|
171
|
+
akt payment update 57 --remove-attachment # clear attachments
|
|
172
|
+
|
|
173
|
+
# Double-entry general ledger (requires the Double-Entry module)
|
|
174
|
+
akt chart-of-account list # read the chart of accounts
|
|
175
|
+
akt chart-of-account get 12
|
|
176
|
+
|
|
177
|
+
# Build the chart of accounts as code (create/update/delete run via the web
|
|
178
|
+
# session; type-id is the double-entry account-type id — copy it from an
|
|
179
|
+
# existing account's `type_id`)
|
|
180
|
+
akt chart-of-account create --name "Cash on Hand" --code 1010 --type-id 6
|
|
181
|
+
akt chart-of-account create --name "Petty Cash" --code 1011 --type-id 6 --account-id 12
|
|
182
|
+
akt chart-of-account update 12 --code 1000 --description "Operating cash"
|
|
183
|
+
akt chart-of-account delete 12
|
|
184
|
+
|
|
185
|
+
# Post a balanced journal entry (>= 2 lines; debits must equal credits;
|
|
186
|
+
# journal number auto-generated, basis defaults to accrual)
|
|
187
|
+
akt journal-entry create --description "Owner capital contribution" \
|
|
188
|
+
--item 'account_id=10,debit=5000' \
|
|
189
|
+
--item 'account_id=30,credit=5000'
|
|
190
|
+
akt journal-entry list
|
|
191
|
+
akt journal-entry update 4 --description "Corrected memo"
|
|
192
|
+
akt journal-entry create --description "Vendor bill accrual" --basis accrual \
|
|
193
|
+
--item 'account_id=60,debit=250' --item 'account_id=21,credit=250' \
|
|
194
|
+
--attachment ./invoice.pdf
|
|
195
|
+
|
|
139
196
|
# Anything else: raw API access
|
|
140
197
|
akt raw GET reports
|
|
141
198
|
akt raw POST items --data '{"name":"Ad-hoc","type":"service","sale_price":99}'
|
|
@@ -159,8 +216,35 @@ Driving Akaunting's API directly has sharp edges; `akt` papers over these:
|
|
|
159
216
|
so they aren't lost.
|
|
160
217
|
* **Nested payment route** — paying a document must POST to
|
|
161
218
|
`documents/{id}/transactions`; the flat `transactions` endpoint rejects it.
|
|
219
|
+
The same applies to *updating* a document-linked payment (e.g. attaching a
|
|
220
|
+
file to it) — `akt` picks the nested route automatically.
|
|
221
|
+
* **Multipart uploads** — attachments switch the request from JSON to
|
|
222
|
+
`multipart/form-data` with the `attachment[]` field; updates are sent as
|
|
223
|
+
`POST` + `_method=PATCH` because PHP won't populate `$_FILES` on a real `PUT`.
|
|
224
|
+
* **Attachment download isn't on `/api`** — Akaunting only serves attachment
|
|
225
|
+
bytes from the session-authenticated web route `/{company}/uploads/{id}/download`.
|
|
226
|
+
`akt download-attachment` transparently logs in a web session with your admin
|
|
227
|
+
credentials (reused for the process) to fetch the file; metadata (id, name,
|
|
228
|
+
size) comes from the `/api` record itself.
|
|
162
229
|
* **Full-replace updates** — Akaunting PUT re-validates required fields, so
|
|
163
230
|
`akt` merges your changes onto the current record.
|
|
231
|
+
* **Journal entries must balance** — a `journal-entry` needs >= 2 lines whose
|
|
232
|
+
debits equal its credits; `akt` validates this client-side (clear error)
|
|
233
|
+
before hitting the API. Each line carries both a `debit` and a `credit` key
|
|
234
|
+
(the unused side sent as `0`) because Akaunting validates both as required.
|
|
235
|
+
* **Journal updates re-derive ledgers** — like documents, a journal update
|
|
236
|
+
deletes any ledger line absent from the request. `akt` resends the existing
|
|
237
|
+
lines (with their ledger ids) so an update that only changes a field doesn't
|
|
238
|
+
wipe the entry, and auto-generates the `journal_number` from the module's
|
|
239
|
+
`double-entry.journal.number_*` settings when you don't pass one.
|
|
240
|
+
* **Chart-of-accounts CRUD is web-only** — the Double-Entry module exposes
|
|
241
|
+
accounts read-only on `/api`; create/update/delete exist solely on the
|
|
242
|
+
session/CSRF web route. `akt chart-of-account create|update|delete` logs in a
|
|
243
|
+
web session (reusing your admin credentials, cached for the process), attaches
|
|
244
|
+
the CSRF token, and unwraps Akaunting's `{success, error, data, message}` AJAX
|
|
245
|
+
envelope — so a server-side block (e.g. *deleting an account that has ledgers*)
|
|
246
|
+
surfaces as a normal error. Updates resend `name` (required by Akaunting on
|
|
247
|
+
update) from the current record when you don't pass one.
|
|
164
248
|
|
|
165
249
|
### Invoice creation may be gated by a plan check
|
|
166
250
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "akt-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "akt — a CLI toolbox to fully drive an Akaunting accounting instance"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -12,6 +12,9 @@ requires-python = ">=3.12"
|
|
|
12
12
|
keywords = ["akaunting", "accounting", "cli", "invoices", "bills", "api"]
|
|
13
13
|
classifiers = [
|
|
14
14
|
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.12",
|
|
16
|
+
"Programming Language :: Python :: 3.13",
|
|
17
|
+
"Programming Language :: Python :: 3.14",
|
|
15
18
|
"Environment :: Console",
|
|
16
19
|
"Topic :: Office/Business :: Financial :: Accounting",
|
|
17
20
|
]
|
|
@@ -9,8 +9,10 @@ from typing import Any
|
|
|
9
9
|
from .client import ApiError, Client
|
|
10
10
|
from .config import ConfigError, load_config
|
|
11
11
|
from .commands import (
|
|
12
|
+
cmd_attachments,
|
|
12
13
|
cmd_create,
|
|
13
14
|
cmd_delete,
|
|
15
|
+
cmd_download_attachment,
|
|
14
16
|
cmd_get,
|
|
15
17
|
cmd_list,
|
|
16
18
|
cmd_toggle,
|
|
@@ -38,6 +40,18 @@ def _add_field_args(p: argparse.ArgumentParser, res: Resource, *, for_update: bo
|
|
|
38
40
|
if res.endpoint == "documents":
|
|
39
41
|
p.add_argument("--item", action="append", metavar="K=V,...",
|
|
40
42
|
help="line item, e.g. 'name=Widget,price=10,quantity=2,tax_id=1' (repeatable)")
|
|
43
|
+
elif res.endpoint == "journal-entry":
|
|
44
|
+
p.add_argument("--item", action="append", metavar="K=V,...",
|
|
45
|
+
help="ledger line (>= 2, must balance), e.g. "
|
|
46
|
+
"'account_id=10,debit=100' or 'account_id=20,credit=100' (repeatable)")
|
|
47
|
+
if res.supports_attachments:
|
|
48
|
+
p.add_argument("--attachment", action="append", metavar="PATH",
|
|
49
|
+
help="attach a file (pdf/jpg/png, repeatable); switches the "
|
|
50
|
+
"request to multipart upload")
|
|
51
|
+
if for_update:
|
|
52
|
+
p.add_argument("--remove-attachment", dest="remove_attachment",
|
|
53
|
+
action="store_true",
|
|
54
|
+
help="clear existing attachment(s) on this record")
|
|
41
55
|
p.add_argument("--set", dest="set_", action="append", metavar="KEY=VALUE",
|
|
42
56
|
help="set an arbitrary body field (repeatable; value JSON-coerced)")
|
|
43
57
|
p.add_argument("--data", metavar="JSON|@FILE",
|
|
@@ -87,18 +101,35 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
87
101
|
gp.add_argument("id")
|
|
88
102
|
gp.set_defaults(_handler=lambda res, c, ns: cmd_get(res, c, ns))
|
|
89
103
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
104
|
+
# Read-only resources (e.g. chart-of-accounts) expose only list/get; the
|
|
105
|
+
# API has no create/update/delete route for them.
|
|
106
|
+
if not res.read_only:
|
|
107
|
+
cp = verbs.add_parser("create", parents=[common], help=f"Create a {res.noun}")
|
|
108
|
+
_add_field_args(cp, res, for_update=False)
|
|
109
|
+
cp.set_defaults(_handler=lambda res, c, ns: cmd_create(res, c, ns))
|
|
110
|
+
|
|
111
|
+
up = verbs.add_parser("update", parents=[common], help=f"Update a {res.noun}")
|
|
112
|
+
up.add_argument("id")
|
|
113
|
+
_add_field_args(up, res, for_update=True)
|
|
114
|
+
up.set_defaults(_handler=lambda res, c, ns: cmd_update(res, c, ns))
|
|
115
|
+
|
|
116
|
+
dp = verbs.add_parser("delete", parents=[common], help=f"Delete a {res.noun}")
|
|
117
|
+
dp.add_argument("id")
|
|
118
|
+
dp.set_defaults(_handler=lambda res, c, ns: cmd_delete(res, c, ns))
|
|
119
|
+
|
|
120
|
+
if res.supports_attachments:
|
|
121
|
+
ap = verbs.add_parser("attachments", parents=[common],
|
|
122
|
+
help=f"List attachments on a {res.noun}")
|
|
123
|
+
ap.add_argument("id")
|
|
124
|
+
ap.set_defaults(_handler=lambda res, c, ns: cmd_attachments(res, c, ns))
|
|
125
|
+
|
|
126
|
+
dap = verbs.add_parser("download-attachment", parents=[common],
|
|
127
|
+
help=f"Download attachment(s) from a {res.noun}")
|
|
128
|
+
dap.add_argument("id")
|
|
129
|
+
dap.add_argument("--out", metavar="DIR", help="output directory (default .)")
|
|
130
|
+
dap.add_argument("--media-id", metavar="ID",
|
|
131
|
+
help="download only this media id (default: all)")
|
|
132
|
+
dap.set_defaults(_handler=lambda res, c, ns: cmd_download_attachment(res, c, ns))
|
|
102
133
|
|
|
103
134
|
if res.supports_toggle:
|
|
104
135
|
ep = verbs.add_parser("enable", parents=[common], help=f"Enable a {res.noun}")
|