makea-cli 0.2.20__tar.gz → 0.2.21__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.
- {makea_cli-0.2.20 → makea_cli-0.2.21}/CHANGELOG.md +19 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/PKG-INFO +4 -1
- {makea_cli-0.2.20 → makea_cli-0.2.21}/README.md +3 -0
- makea_cli-0.2.21/makea_cli/__init__.py +1 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/api_client.py +29 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/__init__.py +2 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/directory/cmd.py +13 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/playbook/cmd.py +63 -4
- makea_cli-0.2.21/makea_cli/commands/tasks/__init__.py +0 -0
- makea_cli-0.2.21/makea_cli/commands/tasks/cmd.py +159 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/pyproject.toml +1 -1
- {makea_cli-0.2.20 → makea_cli-0.2.21}/tests/golden_manifest.json +270 -2
- {makea_cli-0.2.20 → makea_cli-0.2.21}/tests/test_persona_commands.py +55 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/uv.lock +1 -1
- makea_cli-0.2.20/makea_cli/__init__.py +0 -1
- {makea_cli-0.2.20 → makea_cli-0.2.21}/.claude/skills/create-supplier-profile/SKILL.md +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/.claude/skills/lark-cli-setup/SKILL.md +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/.claude/skills/link-supplier-user/SKILL.md +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/.claude/skills/makea-cli-setup/SKILL.md +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/.claude/skills/payment-revenue-report/SKILL.md +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/.claude/skills/supplier-user-id-migration/SKILL.md +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/.gitignore +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea-collection-upload/SKILL.md +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea-collection-upload/scripts/create_products.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/__main__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/auth_pkce.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/broker.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/_util.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/about/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/about/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/analytics/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/analytics/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/auth/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/auth/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/brand/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/brand/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/designer/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/designer/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/directory/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/document/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/document/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/email/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/email/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/factory/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/factory/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/library/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/library/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/metrics/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/metrics/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/orders/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/orders/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/playbook/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/product/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/product/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/production/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/production/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/production/pricing_spec.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/shipping/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/shipping/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/supplier/__init__.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/commands/supplier/cmd.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/config.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/errors.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/identity.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/main.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/output.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/posthog_client.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/makea_cli/registry.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/npm/makea-cli/README.md +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/npm/makea-cli/makea-cli.mjs +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/npm/makea-cli/package.json +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/tests/test_broker.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/tests/test_currency_conversion.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/tests/test_output_contract.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/tests/test_pm_reads.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/tests/test_registry.py +0 -0
- {makea_cli-0.2.20 → makea_cli-0.2.21}/tests/test_supplier_scorecard.py +0 -0
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.21
|
|
4
|
+
|
|
5
|
+
New: the Makea team's task queue. Needs the backend from the same day
|
|
6
|
+
(`/admin/tasks`).
|
|
7
|
+
|
|
8
|
+
- `admin list task [--kind …] [--user …] [--product …]`: open Makea tasks by
|
|
9
|
+
kind: `unknown` (a lesson Beeboo held because nobody said why), `once` (read
|
|
10
|
+
as one order's problem), `note` (a slip of Makea's or the platform's),
|
|
11
|
+
`sample_price`, `pp_sample`, `brand_ask`; with `--user`, that account's own
|
|
12
|
+
cards the team may settle (`setting`).
|
|
13
|
+
- `admin get task <id>`: one task with what settles it, and for a held lesson
|
|
14
|
+
the finding behind it.
|
|
15
|
+
- `admin update task <id> --done | --dismiss --note …`: close it. On a held
|
|
16
|
+
lesson, `--reason … [--caused-by …] [--recurs | --once]` records what the
|
|
17
|
+
team found out, and Beeboo's next reading of the chats uses it. A task
|
|
18
|
+
marked done stays closed when the nightly reading raises the same fact.
|
|
19
|
+
- `admin update user --billing-currency GBP`: the account's billing currency;
|
|
20
|
+
closes a "Set your billing currency" card.
|
|
21
|
+
|
|
3
22
|
## 0.2.20
|
|
4
23
|
|
|
5
24
|
New: rules for a factory and for the whole platform, and an account's About
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: makea-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.21
|
|
4
4
|
Summary: Makea admin CLI (browser login + Makea admin HTTP API)
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: click<9,>=8.1
|
|
@@ -123,6 +123,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
123
123
|
| `makea-cli admin get rule-history` | read | `GET /admin/playbook/rules/{rule_id}/history` | every revision of one rule: its words, who changed it and why, and the rule that replaced it. | — |
|
|
124
124
|
| `makea-cli admin get shipping-order` | read | `GET /admin/shipping_orders/{shipping_order_id}/details` | one shipment with its production and sampling orders, freight quotes, fees, tracking and address. | — |
|
|
125
125
|
| `makea-cli admin get supplier-profile-schema` | read | `GET /admin/supplier/profile/schema` | supplier profile v2 schema (section/field taxonomy: sections, fields, options, required rules). | `get-supplier-profile-schema` |
|
|
126
|
+
| `makea-cli admin get task` | read | `GET /admin/tasks/{task_id}` | one Makea task in full: body, admin link, what settles it, and for a held lesson the finding Beeboo kept. | — |
|
|
126
127
|
| `makea-cli admin get tech-spec-extraction` | read | `GET /admin/products/{id}/extract-tech-specifications` | AI-generate specs (not saved). | `extract-ai-tech-spec` |
|
|
127
128
|
| `makea-cli admin get top-clicks` | read | `POST /admin/analytics/query` | which buttons/elements get clicked most. | `analytics-top-clicks` |
|
|
128
129
|
| `makea-cli admin get top-features` | read | `POST /admin/analytics/query` | a quick map of which features get used most. | `analytics-top-features` |
|
|
@@ -137,6 +138,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
137
138
|
| `makea-cli admin list shipping-order` | read | `GET /admin/shipping_orders` | paginated list of all shipping orders (admin). | `list-all-shipping-orders` |
|
|
138
139
|
| `makea-cli admin list supplier` | read | `GET /admin/supplier/get_all_suppliers` | list all suppliers (admin). | `list-suppliers` |
|
|
139
140
|
| `makea-cli admin list supplier-link` | read | `GET /admin/product/linked_suppliers/by_supplier/{supplier_id}` | direct backend query. | `get-supplier-links-by-supplier-id` |
|
|
141
|
+
| `makea-cli admin list task` | read | `GET /admin/tasks` | the Makea team's open tasks (Beeboo's notes, held lessons, sample price flags, PP samples, brand asks) by kind; `--user` adds that account's own `account.*` cards. | — |
|
|
140
142
|
| `makea-cli admin list user` | read | `GET /admin/users` | list registered users (admin, optional pagination). | `list-users` |
|
|
141
143
|
| `makea-cli admin send email` | write(ask) | `POST /admin/email/send` | queue an HTML email (To required, Cc optional). From must be @makea.co; HTML from --html-file or stdin ('-'). Require… | `send-email` |
|
|
142
144
|
| `makea-cli admin set pricing-groups` | write(ask) | `POST /admin/production_orders/{id}/details/update` | Set a production order's pricing groups from a JSON file, copy them from the order's quote, or clear them (--clear) t… | `production-groups-set` |
|
|
@@ -151,6 +153,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
151
153
|
| `makea-cli admin update rule` | write(ask) | `PATCH /admin/playbook/{target}/rules/{rule_id}` | change a rule's text, status, applies_to, when, mode or end date (--valid-until), on `--user` / `--supplier` / `--global`. --reason required; the rule keeps what it was before. | — |
|
|
152
154
|
| `makea-cli admin update shipping-order` | write(ask) | `PUT /admin/shipping_orders/{shipping_order_id}/status` | Change a shipment: --status (PUT .../status), tracking flags (POST .../tracking), --address (PUT .../shipping-address… | — |
|
|
153
155
|
| `makea-cli admin update supplier` | write(ask) | `PUT /admin/supplier/update_supplier` | update an existing supplier from a JSON file (admin). Run `makea-cli get-supplier-profile-schema` FIRST to get the fi… | `update-supplier` |
|
|
156
|
+
| `makea-cli admin update task` | write(ask) | `POST /admin/tasks/{task_id}/{done\|dismiss}` | close a Makea task with a note: `--done` once handled (a held lesson's `--reason` goes to Beeboo's next reading), or `--dismiss`. | — |
|
|
154
157
|
| `makea-cli admin update tech-spec` | write(ask) | `POST /admin/products/{id}/technical-specifications` | persist specs from a JSON file. | `save-product-tech-spec` |
|
|
155
158
|
| `makea-cli admin update tracking-status` | write(ask) | `POST /admin/tracking/carrier_status` | apply a carrier status looked up by hand (tracking-sweep skill) to one order: status, fan-out, delivered emails (--silent: state only). | — |
|
|
156
159
|
| `makea-cli admin update user` | write(ask) | `PUT /admin/user-profiles/{user_id}/update` | admin updates DynamoDB user profile fields and/or Cognito custom:userType. Allowed --user-type values: "Fashion brand… | `update-user-profile` |
|
|
@@ -111,6 +111,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
111
111
|
| `makea-cli admin get rule-history` | read | `GET /admin/playbook/rules/{rule_id}/history` | every revision of one rule: its words, who changed it and why, and the rule that replaced it. | — |
|
|
112
112
|
| `makea-cli admin get shipping-order` | read | `GET /admin/shipping_orders/{shipping_order_id}/details` | one shipment with its production and sampling orders, freight quotes, fees, tracking and address. | — |
|
|
113
113
|
| `makea-cli admin get supplier-profile-schema` | read | `GET /admin/supplier/profile/schema` | supplier profile v2 schema (section/field taxonomy: sections, fields, options, required rules). | `get-supplier-profile-schema` |
|
|
114
|
+
| `makea-cli admin get task` | read | `GET /admin/tasks/{task_id}` | one Makea task in full: body, admin link, what settles it, and for a held lesson the finding Beeboo kept. | — |
|
|
114
115
|
| `makea-cli admin get tech-spec-extraction` | read | `GET /admin/products/{id}/extract-tech-specifications` | AI-generate specs (not saved). | `extract-ai-tech-spec` |
|
|
115
116
|
| `makea-cli admin get top-clicks` | read | `POST /admin/analytics/query` | which buttons/elements get clicked most. | `analytics-top-clicks` |
|
|
116
117
|
| `makea-cli admin get top-features` | read | `POST /admin/analytics/query` | a quick map of which features get used most. | `analytics-top-features` |
|
|
@@ -125,6 +126,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
125
126
|
| `makea-cli admin list shipping-order` | read | `GET /admin/shipping_orders` | paginated list of all shipping orders (admin). | `list-all-shipping-orders` |
|
|
126
127
|
| `makea-cli admin list supplier` | read | `GET /admin/supplier/get_all_suppliers` | list all suppliers (admin). | `list-suppliers` |
|
|
127
128
|
| `makea-cli admin list supplier-link` | read | `GET /admin/product/linked_suppliers/by_supplier/{supplier_id}` | direct backend query. | `get-supplier-links-by-supplier-id` |
|
|
129
|
+
| `makea-cli admin list task` | read | `GET /admin/tasks` | the Makea team's open tasks (Beeboo's notes, held lessons, sample price flags, PP samples, brand asks) by kind; `--user` adds that account's own `account.*` cards. | — |
|
|
128
130
|
| `makea-cli admin list user` | read | `GET /admin/users` | list registered users (admin, optional pagination). | `list-users` |
|
|
129
131
|
| `makea-cli admin send email` | write(ask) | `POST /admin/email/send` | queue an HTML email (To required, Cc optional). From must be @makea.co; HTML from --html-file or stdin ('-'). Require… | `send-email` |
|
|
130
132
|
| `makea-cli admin set pricing-groups` | write(ask) | `POST /admin/production_orders/{id}/details/update` | Set a production order's pricing groups from a JSON file, copy them from the order's quote, or clear them (--clear) t… | `production-groups-set` |
|
|
@@ -139,6 +141,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
139
141
|
| `makea-cli admin update rule` | write(ask) | `PATCH /admin/playbook/{target}/rules/{rule_id}` | change a rule's text, status, applies_to, when, mode or end date (--valid-until), on `--user` / `--supplier` / `--global`. --reason required; the rule keeps what it was before. | — |
|
|
140
142
|
| `makea-cli admin update shipping-order` | write(ask) | `PUT /admin/shipping_orders/{shipping_order_id}/status` | Change a shipment: --status (PUT .../status), tracking flags (POST .../tracking), --address (PUT .../shipping-address… | — |
|
|
141
143
|
| `makea-cli admin update supplier` | write(ask) | `PUT /admin/supplier/update_supplier` | update an existing supplier from a JSON file (admin). Run `makea-cli get-supplier-profile-schema` FIRST to get the fi… | `update-supplier` |
|
|
144
|
+
| `makea-cli admin update task` | write(ask) | `POST /admin/tasks/{task_id}/{done\|dismiss}` | close a Makea task with a note: `--done` once handled (a held lesson's `--reason` goes to Beeboo's next reading), or `--dismiss`. | — |
|
|
142
145
|
| `makea-cli admin update tech-spec` | write(ask) | `POST /admin/products/{id}/technical-specifications` | persist specs from a JSON file. | `save-product-tech-spec` |
|
|
143
146
|
| `makea-cli admin update tracking-status` | write(ask) | `POST /admin/tracking/carrier_status` | apply a carrier status looked up by hand (tracking-sweep skill) to one order: status, fan-out, delivered emails (--silent: state only). | — |
|
|
144
147
|
| `makea-cli admin update user` | write(ask) | `PUT /admin/user-profiles/{user_id}/update` | admin updates DynamoDB user profile fields and/or Cognito custom:userType. Allowed --user-type values: "Fashion brand… | `update-user-profile` |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.21"
|
|
@@ -1191,6 +1191,35 @@ def admin_delete_rule(base: str, rule_id: str, reason: str) -> Any:
|
|
|
1191
1191
|
return delete_json(_rule_path(base, rule_id), body={"reason": reason})
|
|
1192
1192
|
|
|
1193
1193
|
|
|
1194
|
+
# --- admin: the Makea team's task queue -------------------------------------------
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
def admin_list_tasks(
|
|
1198
|
+
*,
|
|
1199
|
+
kind: str | None = None,
|
|
1200
|
+
type_: str | None = None,
|
|
1201
|
+
user: str | None = None,
|
|
1202
|
+
product: str | None = None,
|
|
1203
|
+
) -> Any:
|
|
1204
|
+
"""GET /admin/tasks — the team's open tasks; filters are comma-separated."""
|
|
1205
|
+
params = {
|
|
1206
|
+
k: v
|
|
1207
|
+
for k, v in (("kind", kind), ("type", type_), ("user", user), ("product", product))
|
|
1208
|
+
if v
|
|
1209
|
+
}
|
|
1210
|
+
return get_json("/admin/tasks", params=params or None)
|
|
1211
|
+
|
|
1212
|
+
|
|
1213
|
+
def admin_get_task(task_id: str) -> Any:
|
|
1214
|
+
"""GET /admin/tasks/{task_id} — one task, with Beeboo's finding behind it."""
|
|
1215
|
+
return get_json(f"/admin/tasks/{quote(task_id, safe='')}")
|
|
1216
|
+
|
|
1217
|
+
|
|
1218
|
+
def admin_close_task(task_id: str, verb: str, body: dict[str, Any]) -> Any:
|
|
1219
|
+
"""POST /admin/tasks/{task_id}/{done|dismiss} — {note, reason?, caused_by?, recurs?}."""
|
|
1220
|
+
return post_json(f"/admin/tasks/{quote(task_id, safe='')}/{verb}", body)
|
|
1221
|
+
|
|
1222
|
+
|
|
1194
1223
|
# --- admin: one account's Knowledge > About you -----------------------------------
|
|
1195
1224
|
# A person (user_id or email; a supplier account's person is their factory's page)
|
|
1196
1225
|
# or one factory by supplier id. Every write but refresh carries a reason.
|
|
@@ -19,6 +19,7 @@ from makea_cli.commands.product.cmd import register as register_product
|
|
|
19
19
|
from makea_cli.commands.production.cmd import register as register_production
|
|
20
20
|
from makea_cli.commands.shipping.cmd import register as register_shipping
|
|
21
21
|
from makea_cli.commands.supplier.cmd import register as register_supplier
|
|
22
|
+
from makea_cli.commands.tasks.cmd import register as register_tasks
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
def register_all(app: typer.Typer) -> None:
|
|
@@ -39,3 +40,4 @@ def register_all(app: typer.Typer) -> None:
|
|
|
39
40
|
register_brand(app)
|
|
40
41
|
register_playbook(app)
|
|
41
42
|
register_about(app)
|
|
43
|
+
register_tasks(app)
|
|
@@ -232,6 +232,15 @@ def register(app: typer.Typer) -> None:
|
|
|
232
232
|
"--company-certificate-document-id",
|
|
233
233
|
help="Optional company-certificate document ID already stored under the user.",
|
|
234
234
|
),
|
|
235
|
+
billing_currency: str | None = typer.Option(
|
|
236
|
+
None,
|
|
237
|
+
"--billing-currency",
|
|
238
|
+
help=(
|
|
239
|
+
"Optional ISO code (GBP, USD, EUR…) the account bills in. Every product "
|
|
240
|
+
"nothing is paid on yet follows, and a 'Set your billing currency' card "
|
|
241
|
+
"closes."
|
|
242
|
+
),
|
|
243
|
+
),
|
|
235
244
|
) -> None:
|
|
236
245
|
"""
|
|
237
246
|
Admin: update a user's DDB profile fields and/or Cognito custom:userType.
|
|
@@ -262,6 +271,10 @@ def register(app: typer.Typer) -> None:
|
|
|
262
271
|
("referral_type", referral_type),
|
|
263
272
|
("referral_detail", referral_detail),
|
|
264
273
|
("company_certificate_document_id", company_certificate_document_id),
|
|
274
|
+
(
|
|
275
|
+
"billing_currency",
|
|
276
|
+
billing_currency.strip().upper() if billing_currency is not None else None,
|
|
277
|
+
),
|
|
265
278
|
]
|
|
266
279
|
for key, value in scalar_options:
|
|
267
280
|
if value is not None:
|
|
@@ -15,6 +15,8 @@ one of three targets:
|
|
|
15
15
|
Every write needs ``--reason``. The rule keeps it as an evidence entry
|
|
16
16
|
(``admin_add`` / ``admin_edit`` / ``admin_delete`` with who, why, when and,
|
|
17
17
|
for edits and deletes, what the rule was before), and the audit log records it.
|
|
18
|
+
``--reason`` is the change log and the brand never reads it; ``--why`` and
|
|
19
|
+
``--proof`` are what the brand reads under the rule on Knowledge > Rules.
|
|
18
20
|
``delete`` archives: the rule leaves the brand's Rules page and every prompt,
|
|
19
21
|
the row stays as the record, and ``update --status active`` brings it back.
|
|
20
22
|
"""
|
|
@@ -55,6 +57,11 @@ when there is no team); --scope overrides.
|
|
|
55
57
|
style, collection, supplier, element (e.g. supplier:sup_123:Ningbo Knit).
|
|
56
58
|
"all" (update only) widens it back to the whole account.
|
|
57
59
|
|
|
60
|
+
--why is the reason the brand reads under the rule; --proof (repeatable) is
|
|
61
|
+
one message behind it, WHO|YYYY-MM-DD|TEXT or WHO|TEXT, WHO being Brand,
|
|
62
|
+
Factory, record or a name. Both are kept apart from --reason, which only
|
|
63
|
+
admins see. A later --why/--proof replaces the earlier pair.
|
|
64
|
+
|
|
58
65
|
--when is which products it is for, as JSON:
|
|
59
66
|
'{"categories": ["knitwear"], "service_modes": ["cmt"]}'
|
|
60
67
|
Order conditions the rule already has (units, destination) are kept; {} means
|
|
@@ -64,7 +71,9 @@ Examples
|
|
|
64
71
|
makea-cli admin list rule --user brand@example.com
|
|
65
72
|
makea-cli admin get rule rul_0123456789ab --user brand@example.com
|
|
66
73
|
makea-cli admin create rule --user brand@example.com \\
|
|
67
|
-
--text "Always book DHL Express for samples" --reason "Agreed on the 14 Oct call"
|
|
74
|
+
--text "Always book DHL Express for samples" --reason "Agreed on the 14 Oct call" \\
|
|
75
|
+
--why "Two sample parcels were lost with the economy courier" \\
|
|
76
|
+
--proof "Brand|2026-10-14|Please only use DHL Express for samples from now on"
|
|
68
77
|
makea-cli admin update rule rul_0123456789ab --user brand@example.com \\
|
|
69
78
|
--status muted --reason "Brand asked to pause it by email"
|
|
70
79
|
makea-cli admin delete rule rul_0123456789ab --user brand@example.com \\
|
|
@@ -114,6 +123,49 @@ def _reason(raw: str) -> str:
|
|
|
114
123
|
return reason
|
|
115
124
|
|
|
116
125
|
|
|
126
|
+
def _why_option() -> Any:
|
|
127
|
+
return typer.Option(
|
|
128
|
+
None, "--why", help="Why the rule exists, as the brand reads it (max 300 chars)."
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _proof_option() -> Any:
|
|
133
|
+
return typer.Option(
|
|
134
|
+
None,
|
|
135
|
+
"--proof",
|
|
136
|
+
help="A message behind the rule, WHO|YYYY-MM-DD|TEXT or WHO|TEXT (repeatable, max 5).",
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _proof(raw: list[str]) -> list[dict[str, str]]:
|
|
141
|
+
out = []
|
|
142
|
+
for item in raw:
|
|
143
|
+
parts = [p.strip() for p in item.split("|", 2)]
|
|
144
|
+
if len(parts) == 3:
|
|
145
|
+
who, at, text = parts
|
|
146
|
+
try:
|
|
147
|
+
at = date.fromisoformat(at).isoformat()
|
|
148
|
+
except ValueError as e:
|
|
149
|
+
raise typer.BadParameter(f"--proof date must be YYYY-MM-DD: {item}") from e
|
|
150
|
+
elif len(parts) == 2:
|
|
151
|
+
(who, text), at = parts, ""
|
|
152
|
+
else:
|
|
153
|
+
raise typer.BadParameter(f"--proof must be WHO|YYYY-MM-DD|TEXT: {item}")
|
|
154
|
+
if not who or not text:
|
|
155
|
+
raise typer.BadParameter(f"--proof needs who and text: {item}")
|
|
156
|
+
out.append({"who": who, "at": at, "text": text})
|
|
157
|
+
if len(out) > 5:
|
|
158
|
+
raise typer.BadParameter("--proof at most 5 times")
|
|
159
|
+
return out
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _basis(body: dict[str, Any], why: str | None, proof: list[str] | None) -> None:
|
|
163
|
+
if why is not None and why.strip():
|
|
164
|
+
body["why"] = " ".join(why.split())
|
|
165
|
+
if proof:
|
|
166
|
+
body["proof"] = _proof(proof)
|
|
167
|
+
|
|
168
|
+
|
|
117
169
|
def _applies_to(raw: str) -> dict[str, str]:
|
|
118
170
|
if raw.strip().lower() == "all":
|
|
119
171
|
return {"kind": "all"}
|
|
@@ -348,6 +400,8 @@ def register(app: typer.Typer) -> None:
|
|
|
348
400
|
"--valid-until",
|
|
349
401
|
help="YYYY-MM-DD the rule ends on (a closure, a temporary arrangement).",
|
|
350
402
|
),
|
|
403
|
+
why: str | None = _why_option(),
|
|
404
|
+
proof: list[str] | None = _proof_option(),
|
|
351
405
|
) -> None:
|
|
352
406
|
"""Add a playbook rule for a person, a factory or everyone."""
|
|
353
407
|
base = _target(user, supplier, is_global)
|
|
@@ -374,6 +428,7 @@ def register(app: typer.Typer) -> None:
|
|
|
374
428
|
body["force"] = True
|
|
375
429
|
if valid_until is not None:
|
|
376
430
|
body["valid_until"] = _date(valid_until)
|
|
431
|
+
_basis(body, why, proof)
|
|
377
432
|
print_json_or_exit(console, lambda: api_client.admin_create_rule(base, body))
|
|
378
433
|
|
|
379
434
|
@command(
|
|
@@ -391,7 +446,8 @@ def register(app: typer.Typer) -> None:
|
|
|
391
446
|
idempotent=True,
|
|
392
447
|
help=(
|
|
393
448
|
"PATCH /admin/playbook/{target}/rules/{rule_id} — change a rule's text, "
|
|
394
|
-
"status, applies_to, when or
|
|
449
|
+
"status, applies_to, when, mode, or the --why/--proof the brand reads. --reason "
|
|
450
|
+
"required; the rule keeps what it was before."
|
|
395
451
|
),
|
|
396
452
|
epilog=_RULES_EPILOG,
|
|
397
453
|
)
|
|
@@ -415,6 +471,8 @@ def register(app: typer.Typer) -> None:
|
|
|
415
471
|
"--valid-until",
|
|
416
472
|
help='YYYY-MM-DD the rule ends on; "none" removes the end date.',
|
|
417
473
|
),
|
|
474
|
+
why: str | None = _why_option(),
|
|
475
|
+
proof: list[str] | None = _proof_option(),
|
|
418
476
|
) -> None:
|
|
419
477
|
"""Edit a playbook rule."""
|
|
420
478
|
base = _target(user, supplier, is_global)
|
|
@@ -433,10 +491,11 @@ def register(app: typer.Typer) -> None:
|
|
|
433
491
|
body["valid_until"] = (
|
|
434
492
|
"" if valid_until.strip().lower() == "none" else _date(valid_until)
|
|
435
493
|
)
|
|
494
|
+
_basis(body, why, proof)
|
|
436
495
|
if not body:
|
|
437
496
|
raise typer.BadParameter(
|
|
438
|
-
"nothing to change: pass --text, --status, --applies-to, --when, --mode "
|
|
439
|
-
"
|
|
497
|
+
"nothing to change: pass --text, --status, --applies-to, --when, --mode, "
|
|
498
|
+
"--valid-until, --why or --proof"
|
|
440
499
|
)
|
|
441
500
|
body["reason"] = _reason(reason)
|
|
442
501
|
print_json_or_exit(console, lambda: api_client.admin_update_rule(base, rule_id, body))
|
|
File without changes
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Admin commands for the Makea team's task queue.
|
|
2
|
+
|
|
3
|
+
A *task* is a card the Makea team owns: Beeboo's notes from reading the chats
|
|
4
|
+
(a lesson it held back from the brand's rules, or a slip of the platform's),
|
|
5
|
+
a sample priced far above bulk, a PP sample to see through, a brand's ask in
|
|
6
|
+
the concierge thread. With ``--user``, an account's own cards the team may
|
|
7
|
+
settle for it (``account.*``, such as its billing currency) are listed too.
|
|
8
|
+
|
|
9
|
+
Kinds: ``unknown`` (a lesson nobody said the reason for), ``once`` (a lesson
|
|
10
|
+
read as one order's problem), ``note`` (a slip of Makea's or the platform's),
|
|
11
|
+
``sample_price``, ``pp_sample``, ``brand_ask``, ``setting``.
|
|
12
|
+
|
|
13
|
+
The change a task asks for is made with the command that owns it (``admin
|
|
14
|
+
create rule``, ``admin update user``, ``admin update about`` …); ``update
|
|
15
|
+
task --done`` then records that it was handled. Only notes the team handles
|
|
16
|
+
off the platform can be marked done; the others close by themselves when the
|
|
17
|
+
fact behind them lands, and ``get task`` says which fact.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
import typer
|
|
25
|
+
from rich.console import Console
|
|
26
|
+
|
|
27
|
+
from makea_cli import api_client
|
|
28
|
+
from makea_cli.commands._util import print_json_or_exit
|
|
29
|
+
from makea_cli.registry import command
|
|
30
|
+
|
|
31
|
+
console = Console()
|
|
32
|
+
|
|
33
|
+
_CAUSES = ("factory", "brand", "makea", "outside")
|
|
34
|
+
|
|
35
|
+
_TASKS_EPILOG = """
|
|
36
|
+
Kinds: unknown (a lesson nobody said why), once (one order's problem),
|
|
37
|
+
note (a slip of Makea's or the platform's), sample_price, pp_sample,
|
|
38
|
+
brand_ask, setting.
|
|
39
|
+
|
|
40
|
+
Examples
|
|
41
|
+
makea-cli admin list task --kind unknown,once
|
|
42
|
+
makea-cli admin list task --user brand@example.com
|
|
43
|
+
makea-cli admin get task 4d85c843-3888-500e-adb2-207f0f07110d
|
|
44
|
+
makea-cli admin update task <task_id> --done --note "Asked the brand on WhatsApp" \\
|
|
45
|
+
--reason "The brand changed the cuff after approval" --caused-by brand --once
|
|
46
|
+
makea-cli admin update task <task_id> --dismiss --note "Brand keeps GBP"
|
|
47
|
+
""".strip()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def register(app: typer.Typer) -> None:
|
|
51
|
+
@command(
|
|
52
|
+
app,
|
|
53
|
+
"admin",
|
|
54
|
+
"list",
|
|
55
|
+
"task",
|
|
56
|
+
api="GET /admin/tasks",
|
|
57
|
+
help=(
|
|
58
|
+
"GET /admin/tasks — the Makea team's open tasks: task_id, type, kind, title, "
|
|
59
|
+
"owner (the account), product, due date, can_mark_done; counts by kind. "
|
|
60
|
+
"--user adds that account's own cards the team may settle (account.*)."
|
|
61
|
+
),
|
|
62
|
+
epilog=_TASKS_EPILOG,
|
|
63
|
+
)
|
|
64
|
+
def list_tasks(
|
|
65
|
+
kind: str | None = typer.Option(
|
|
66
|
+
None, "--kind", "-k", help="Only these kinds, comma-separated."
|
|
67
|
+
),
|
|
68
|
+
type_: str | None = typer.Option(
|
|
69
|
+
None, "--type", help="Only these action types, e.g. makea.beeboo_note."
|
|
70
|
+
),
|
|
71
|
+
user: str | None = typer.Option(
|
|
72
|
+
None, "--user", "-u", help="One account: user_id or email."
|
|
73
|
+
),
|
|
74
|
+
product: str | None = typer.Option(None, "--product", "-p", help="One product id."),
|
|
75
|
+
) -> None:
|
|
76
|
+
"""List the Makea team's open tasks."""
|
|
77
|
+
print_json_or_exit(
|
|
78
|
+
console,
|
|
79
|
+
lambda: api_client.admin_list_tasks(kind=kind, type_=type_, user=user, product=product),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
@command(
|
|
83
|
+
app,
|
|
84
|
+
"admin",
|
|
85
|
+
"get",
|
|
86
|
+
"task",
|
|
87
|
+
api="GET /admin/tasks/{task_id}",
|
|
88
|
+
help=(
|
|
89
|
+
"GET /admin/tasks/{task_id} — one task in full: body, context, admin_url, "
|
|
90
|
+
"next (what settles it), and for a held lesson the finding Beeboo kept "
|
|
91
|
+
"(problem, factory, product, reason so far)."
|
|
92
|
+
),
|
|
93
|
+
epilog=_TASKS_EPILOG,
|
|
94
|
+
)
|
|
95
|
+
def get_task(task_id: str = typer.Argument(..., help="Task id (from list task).")) -> None:
|
|
96
|
+
"""Show one task and what settles it."""
|
|
97
|
+
print_json_or_exit(console, lambda: api_client.admin_get_task(task_id))
|
|
98
|
+
|
|
99
|
+
@command(
|
|
100
|
+
app,
|
|
101
|
+
"admin",
|
|
102
|
+
"update",
|
|
103
|
+
"task",
|
|
104
|
+
api="POST /admin/tasks/{task_id}/{done|dismiss}",
|
|
105
|
+
side_effects=[
|
|
106
|
+
"closes the task for the whole Makea team",
|
|
107
|
+
"with --reason, Beeboo's next reading of the chats uses that reason",
|
|
108
|
+
],
|
|
109
|
+
approval="ask",
|
|
110
|
+
reversible=False,
|
|
111
|
+
idempotent=False,
|
|
112
|
+
help=(
|
|
113
|
+
"POST /admin/tasks/{task_id}/{done|dismiss} — close a task: --done once it is "
|
|
114
|
+
"handled (notes the team handles off the platform only), --dismiss when it "
|
|
115
|
+
"will not be done. --note required. On a held lesson, --reason records why "
|
|
116
|
+
"it happened for Beeboo's next reading."
|
|
117
|
+
),
|
|
118
|
+
epilog=_TASKS_EPILOG,
|
|
119
|
+
)
|
|
120
|
+
def update_task(
|
|
121
|
+
task_id: str = typer.Argument(..., help="Task id (from list task)."),
|
|
122
|
+
done: bool = typer.Option(False, "--done", help="It was handled."),
|
|
123
|
+
dismiss: bool = typer.Option(False, "--dismiss", help="It will not be done."),
|
|
124
|
+
note: str = typer.Option(..., "--note", "-n", help="What was done, or why not (required)."),
|
|
125
|
+
reason: str | None = typer.Option(
|
|
126
|
+
None,
|
|
127
|
+
"--reason",
|
|
128
|
+
help="With --done on a held lesson: why it happened, as the team found out.",
|
|
129
|
+
),
|
|
130
|
+
caused_by: str | None = typer.Option(
|
|
131
|
+
None, "--caused-by", help=f"With --reason: {', '.join(_CAUSES)}."
|
|
132
|
+
),
|
|
133
|
+
recurs: bool | None = typer.Option(
|
|
134
|
+
None,
|
|
135
|
+
"--recurs/--once",
|
|
136
|
+
help="With --reason: it will happen again, or it was this order only.",
|
|
137
|
+
),
|
|
138
|
+
) -> None:
|
|
139
|
+
"""Mark a task done, or dismiss it."""
|
|
140
|
+
if done == dismiss:
|
|
141
|
+
raise typer.BadParameter("pass exactly one of --done, --dismiss")
|
|
142
|
+
clean_note = " ".join(note.split())
|
|
143
|
+
if not clean_note:
|
|
144
|
+
raise typer.BadParameter("--note must not be empty")
|
|
145
|
+
body: dict[str, Any] = {"note": clean_note}
|
|
146
|
+
if reason is not None:
|
|
147
|
+
if not done:
|
|
148
|
+
raise typer.BadParameter("--reason goes with --done")
|
|
149
|
+
body["reason"] = " ".join(reason.split())
|
|
150
|
+
if caused_by is not None:
|
|
151
|
+
if caused_by not in _CAUSES:
|
|
152
|
+
raise typer.BadParameter(f"--caused-by: one of {', '.join(_CAUSES)}")
|
|
153
|
+
body["caused_by"] = caused_by
|
|
154
|
+
if recurs is not None:
|
|
155
|
+
body["recurs"] = recurs
|
|
156
|
+
elif caused_by is not None or recurs is not None:
|
|
157
|
+
raise typer.BadParameter("--caused-by and --recurs/--once go with --reason")
|
|
158
|
+
verb = "done" if done else "dismiss"
|
|
159
|
+
print_json_or_exit(console, lambda: api_client.admin_close_task(task_id, verb, body))
|
|
@@ -522,6 +522,30 @@
|
|
|
522
522
|
"multiple": false,
|
|
523
523
|
"default": null,
|
|
524
524
|
"help": "YYYY-MM-DD the rule ends on (a closure, a temporary arrangement)."
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
"name": "why",
|
|
528
|
+
"kind": "option",
|
|
529
|
+
"opts": [
|
|
530
|
+
"--why"
|
|
531
|
+
],
|
|
532
|
+
"type": "text",
|
|
533
|
+
"required": false,
|
|
534
|
+
"multiple": false,
|
|
535
|
+
"default": null,
|
|
536
|
+
"help": "Why the rule exists, as the brand reads it (max 300 chars)."
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
"name": "proof",
|
|
540
|
+
"kind": "option",
|
|
541
|
+
"opts": [
|
|
542
|
+
"--proof"
|
|
543
|
+
],
|
|
544
|
+
"type": "text",
|
|
545
|
+
"required": false,
|
|
546
|
+
"multiple": true,
|
|
547
|
+
"default": null,
|
|
548
|
+
"help": "A message behind the rule, WHO|YYYY-MM-DD|TEXT or WHO|TEXT (repeatable, max 5)."
|
|
525
549
|
}
|
|
526
550
|
]
|
|
527
551
|
},
|
|
@@ -2496,6 +2520,37 @@
|
|
|
2496
2520
|
"function": "makea_cli.commands.supplier.cmd.register.<locals>.get_supplier_profile_schema",
|
|
2497
2521
|
"flags": []
|
|
2498
2522
|
},
|
|
2523
|
+
{
|
|
2524
|
+
"name": "admin get task",
|
|
2525
|
+
"persona": "admin",
|
|
2526
|
+
"verb": "get",
|
|
2527
|
+
"noun": "task",
|
|
2528
|
+
"access": "read",
|
|
2529
|
+
"api": "GET /admin/tasks/{task_id}",
|
|
2530
|
+
"external": null,
|
|
2531
|
+
"side_effects": [],
|
|
2532
|
+
"approval": "auto",
|
|
2533
|
+
"reversible": null,
|
|
2534
|
+
"idempotent": null,
|
|
2535
|
+
"limit": null,
|
|
2536
|
+
"legacy": [],
|
|
2537
|
+
"help": "GET /admin/tasks/{task_id} — one task in full: body, context, admin_url, next (what settles it), and for a held lesson the finding Beeboo kept (problem, factory, product, reason so far).",
|
|
2538
|
+
"function": "makea_cli.commands.tasks.cmd.register.<locals>.get_task",
|
|
2539
|
+
"flags": [
|
|
2540
|
+
{
|
|
2541
|
+
"name": "task_id",
|
|
2542
|
+
"kind": "argument",
|
|
2543
|
+
"opts": [
|
|
2544
|
+
"task_id"
|
|
2545
|
+
],
|
|
2546
|
+
"type": "text",
|
|
2547
|
+
"required": true,
|
|
2548
|
+
"multiple": false,
|
|
2549
|
+
"default": null,
|
|
2550
|
+
"help": "Task id (from list task)."
|
|
2551
|
+
}
|
|
2552
|
+
]
|
|
2553
|
+
},
|
|
2499
2554
|
{
|
|
2500
2555
|
"name": "admin get tech-spec-extraction",
|
|
2501
2556
|
"persona": "admin",
|
|
@@ -3236,6 +3291,76 @@
|
|
|
3236
3291
|
}
|
|
3237
3292
|
]
|
|
3238
3293
|
},
|
|
3294
|
+
{
|
|
3295
|
+
"name": "admin list task",
|
|
3296
|
+
"persona": "admin",
|
|
3297
|
+
"verb": "list",
|
|
3298
|
+
"noun": "task",
|
|
3299
|
+
"access": "read",
|
|
3300
|
+
"api": "GET /admin/tasks",
|
|
3301
|
+
"external": null,
|
|
3302
|
+
"side_effects": [],
|
|
3303
|
+
"approval": "auto",
|
|
3304
|
+
"reversible": null,
|
|
3305
|
+
"idempotent": null,
|
|
3306
|
+
"limit": "client",
|
|
3307
|
+
"legacy": [],
|
|
3308
|
+
"help": "GET /admin/tasks — the Makea team's open tasks: task_id, type, kind, title, owner (the account), product, due date, can_mark_done; counts by kind. --user adds that account's own cards the team may settle (account.*).",
|
|
3309
|
+
"function": "makea_cli.commands.tasks.cmd.register.<locals>.list_tasks",
|
|
3310
|
+
"flags": [
|
|
3311
|
+
{
|
|
3312
|
+
"name": "kind",
|
|
3313
|
+
"kind": "option",
|
|
3314
|
+
"opts": [
|
|
3315
|
+
"--kind",
|
|
3316
|
+
"-k"
|
|
3317
|
+
],
|
|
3318
|
+
"type": "text",
|
|
3319
|
+
"required": false,
|
|
3320
|
+
"multiple": false,
|
|
3321
|
+
"default": null,
|
|
3322
|
+
"help": "Only these kinds, comma-separated."
|
|
3323
|
+
},
|
|
3324
|
+
{
|
|
3325
|
+
"name": "type_",
|
|
3326
|
+
"kind": "option",
|
|
3327
|
+
"opts": [
|
|
3328
|
+
"--type"
|
|
3329
|
+
],
|
|
3330
|
+
"type": "text",
|
|
3331
|
+
"required": false,
|
|
3332
|
+
"multiple": false,
|
|
3333
|
+
"default": null,
|
|
3334
|
+
"help": "Only these action types, e.g. makea.beeboo_note."
|
|
3335
|
+
},
|
|
3336
|
+
{
|
|
3337
|
+
"name": "user",
|
|
3338
|
+
"kind": "option",
|
|
3339
|
+
"opts": [
|
|
3340
|
+
"--user",
|
|
3341
|
+
"-u"
|
|
3342
|
+
],
|
|
3343
|
+
"type": "text",
|
|
3344
|
+
"required": false,
|
|
3345
|
+
"multiple": false,
|
|
3346
|
+
"default": null,
|
|
3347
|
+
"help": "One account: user_id or email."
|
|
3348
|
+
},
|
|
3349
|
+
{
|
|
3350
|
+
"name": "product",
|
|
3351
|
+
"kind": "option",
|
|
3352
|
+
"opts": [
|
|
3353
|
+
"--product",
|
|
3354
|
+
"-p"
|
|
3355
|
+
],
|
|
3356
|
+
"type": "text",
|
|
3357
|
+
"required": false,
|
|
3358
|
+
"multiple": false,
|
|
3359
|
+
"default": null,
|
|
3360
|
+
"help": "One product id."
|
|
3361
|
+
}
|
|
3362
|
+
]
|
|
3363
|
+
},
|
|
3239
3364
|
{
|
|
3240
3365
|
"name": "admin list user",
|
|
3241
3366
|
"persona": "admin",
|
|
@@ -4934,7 +5059,7 @@
|
|
|
4934
5059
|
"idempotent": true,
|
|
4935
5060
|
"limit": null,
|
|
4936
5061
|
"legacy": [],
|
|
4937
|
-
"help": "PATCH /admin/playbook/{target}/rules/{rule_id} — change a rule's text, status, applies_to, when or
|
|
5062
|
+
"help": "PATCH /admin/playbook/{target}/rules/{rule_id} — change a rule's text, status, applies_to, when, mode, or the --why/--proof the brand reads. --reason required; the rule keeps what it was before.",
|
|
4938
5063
|
"function": "makea_cli.commands.playbook.cmd.register.<locals>.update_rule",
|
|
4939
5064
|
"flags": [
|
|
4940
5065
|
{
|
|
@@ -5070,6 +5195,30 @@
|
|
|
5070
5195
|
"multiple": false,
|
|
5071
5196
|
"default": null,
|
|
5072
5197
|
"help": "YYYY-MM-DD the rule ends on; \"none\" removes the end date."
|
|
5198
|
+
},
|
|
5199
|
+
{
|
|
5200
|
+
"name": "why",
|
|
5201
|
+
"kind": "option",
|
|
5202
|
+
"opts": [
|
|
5203
|
+
"--why"
|
|
5204
|
+
],
|
|
5205
|
+
"type": "text",
|
|
5206
|
+
"required": false,
|
|
5207
|
+
"multiple": false,
|
|
5208
|
+
"default": null,
|
|
5209
|
+
"help": "Why the rule exists, as the brand reads it (max 300 chars)."
|
|
5210
|
+
},
|
|
5211
|
+
{
|
|
5212
|
+
"name": "proof",
|
|
5213
|
+
"kind": "option",
|
|
5214
|
+
"opts": [
|
|
5215
|
+
"--proof"
|
|
5216
|
+
],
|
|
5217
|
+
"type": "text",
|
|
5218
|
+
"required": false,
|
|
5219
|
+
"multiple": true,
|
|
5220
|
+
"default": null,
|
|
5221
|
+
"help": "A message behind the rule, WHO|YYYY-MM-DD|TEXT or WHO|TEXT (repeatable, max 5)."
|
|
5073
5222
|
}
|
|
5074
5223
|
]
|
|
5075
5224
|
},
|
|
@@ -5262,6 +5411,113 @@
|
|
|
5262
5411
|
}
|
|
5263
5412
|
]
|
|
5264
5413
|
},
|
|
5414
|
+
{
|
|
5415
|
+
"name": "admin update task",
|
|
5416
|
+
"persona": "admin",
|
|
5417
|
+
"verb": "update",
|
|
5418
|
+
"noun": "task",
|
|
5419
|
+
"access": "write",
|
|
5420
|
+
"api": "POST /admin/tasks/{task_id}/{done|dismiss}",
|
|
5421
|
+
"external": null,
|
|
5422
|
+
"side_effects": [
|
|
5423
|
+
"closes the task for the whole Makea team",
|
|
5424
|
+
"with --reason, Beeboo's next reading of the chats uses that reason"
|
|
5425
|
+
],
|
|
5426
|
+
"approval": "ask",
|
|
5427
|
+
"reversible": false,
|
|
5428
|
+
"idempotent": false,
|
|
5429
|
+
"limit": null,
|
|
5430
|
+
"legacy": [],
|
|
5431
|
+
"help": "POST /admin/tasks/{task_id}/{done|dismiss} — close a task: --done once it is handled (notes the team handles off the platform only), --dismiss when it will not be done. --note required. On a held lesson, --reason records why it happened for Beeboo's next reading.",
|
|
5432
|
+
"function": "makea_cli.commands.tasks.cmd.register.<locals>.update_task",
|
|
5433
|
+
"flags": [
|
|
5434
|
+
{
|
|
5435
|
+
"name": "task_id",
|
|
5436
|
+
"kind": "argument",
|
|
5437
|
+
"opts": [
|
|
5438
|
+
"task_id"
|
|
5439
|
+
],
|
|
5440
|
+
"type": "text",
|
|
5441
|
+
"required": true,
|
|
5442
|
+
"multiple": false,
|
|
5443
|
+
"default": null,
|
|
5444
|
+
"help": "Task id (from list task)."
|
|
5445
|
+
},
|
|
5446
|
+
{
|
|
5447
|
+
"name": "done",
|
|
5448
|
+
"kind": "option",
|
|
5449
|
+
"opts": [
|
|
5450
|
+
"--done"
|
|
5451
|
+
],
|
|
5452
|
+
"type": "flag",
|
|
5453
|
+
"required": false,
|
|
5454
|
+
"multiple": false,
|
|
5455
|
+
"default": false,
|
|
5456
|
+
"help": "It was handled."
|
|
5457
|
+
},
|
|
5458
|
+
{
|
|
5459
|
+
"name": "dismiss",
|
|
5460
|
+
"kind": "option",
|
|
5461
|
+
"opts": [
|
|
5462
|
+
"--dismiss"
|
|
5463
|
+
],
|
|
5464
|
+
"type": "flag",
|
|
5465
|
+
"required": false,
|
|
5466
|
+
"multiple": false,
|
|
5467
|
+
"default": false,
|
|
5468
|
+
"help": "It will not be done."
|
|
5469
|
+
},
|
|
5470
|
+
{
|
|
5471
|
+
"name": "note",
|
|
5472
|
+
"kind": "option",
|
|
5473
|
+
"opts": [
|
|
5474
|
+
"--note",
|
|
5475
|
+
"-n"
|
|
5476
|
+
],
|
|
5477
|
+
"type": "text",
|
|
5478
|
+
"required": true,
|
|
5479
|
+
"multiple": false,
|
|
5480
|
+
"default": null,
|
|
5481
|
+
"help": "What was done, or why not (required)."
|
|
5482
|
+
},
|
|
5483
|
+
{
|
|
5484
|
+
"name": "reason",
|
|
5485
|
+
"kind": "option",
|
|
5486
|
+
"opts": [
|
|
5487
|
+
"--reason"
|
|
5488
|
+
],
|
|
5489
|
+
"type": "text",
|
|
5490
|
+
"required": false,
|
|
5491
|
+
"multiple": false,
|
|
5492
|
+
"default": null,
|
|
5493
|
+
"help": "With --done on a held lesson: why it happened, as the team found out."
|
|
5494
|
+
},
|
|
5495
|
+
{
|
|
5496
|
+
"name": "caused_by",
|
|
5497
|
+
"kind": "option",
|
|
5498
|
+
"opts": [
|
|
5499
|
+
"--caused-by"
|
|
5500
|
+
],
|
|
5501
|
+
"type": "text",
|
|
5502
|
+
"required": false,
|
|
5503
|
+
"multiple": false,
|
|
5504
|
+
"default": null,
|
|
5505
|
+
"help": "With --reason: factory, brand, makea, outside."
|
|
5506
|
+
},
|
|
5507
|
+
{
|
|
5508
|
+
"name": "recurs",
|
|
5509
|
+
"kind": "option",
|
|
5510
|
+
"opts": [
|
|
5511
|
+
"--recurs"
|
|
5512
|
+
],
|
|
5513
|
+
"type": "flag",
|
|
5514
|
+
"required": false,
|
|
5515
|
+
"multiple": false,
|
|
5516
|
+
"default": null,
|
|
5517
|
+
"help": "With --reason: it will happen again, or it was this order only."
|
|
5518
|
+
}
|
|
5519
|
+
]
|
|
5520
|
+
},
|
|
5265
5521
|
{
|
|
5266
5522
|
"name": "admin update tech-spec",
|
|
5267
5523
|
"persona": "admin",
|
|
@@ -5677,6 +5933,18 @@
|
|
|
5677
5933
|
"multiple": false,
|
|
5678
5934
|
"default": null,
|
|
5679
5935
|
"help": "Optional company-certificate document ID already stored under the user."
|
|
5936
|
+
},
|
|
5937
|
+
{
|
|
5938
|
+
"name": "billing_currency",
|
|
5939
|
+
"kind": "option",
|
|
5940
|
+
"opts": [
|
|
5941
|
+
"--billing-currency"
|
|
5942
|
+
],
|
|
5943
|
+
"type": "text",
|
|
5944
|
+
"required": false,
|
|
5945
|
+
"multiple": false,
|
|
5946
|
+
"default": null,
|
|
5947
|
+
"help": "Optional ISO code (GBP, USD, EUR…) the account bills in. Every product nothing is paid on yet follows, and a 'Set your billing currency' card closes."
|
|
5680
5948
|
}
|
|
5681
5949
|
]
|
|
5682
5950
|
},
|
|
@@ -9646,4 +9914,4 @@
|
|
|
9646
9914
|
]
|
|
9647
9915
|
}
|
|
9648
9916
|
]
|
|
9649
|
-
}
|
|
9917
|
+
}
|
|
@@ -639,3 +639,58 @@ class AboutCommandTests(_PersonaCase):
|
|
|
639
639
|
) # fmt: skip
|
|
640
640
|
self.run_cli("admin", "generate", "about", "-u", "u1", "--force", expect=2)
|
|
641
641
|
self.assertEqual(self.rec.calls, [])
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
class TaskCommandTests(_PersonaCase):
|
|
645
|
+
"""admin … task: the Makea team's queue. Closing one needs a note."""
|
|
646
|
+
|
|
647
|
+
persona = "admin"
|
|
648
|
+
|
|
649
|
+
def test_list_passes_its_filters(self):
|
|
650
|
+
self.run_cli("admin", "list", "task")
|
|
651
|
+
self.assertEqual((self.rec.last["path"], self.rec.last["params"]), ("/admin/tasks", None))
|
|
652
|
+
self.run_cli("admin", "list", "task", "--kind", "unknown,once", "-u", "b@x.co")
|
|
653
|
+
self.assertEqual(self.rec.last["params"], {"kind": "unknown,once", "user": "b@x.co"})
|
|
654
|
+
|
|
655
|
+
def test_get_reads_one(self):
|
|
656
|
+
self.run_cli("admin", "get", "task", "t1")
|
|
657
|
+
self.assertEqual(self.rec.last["path"], "/admin/tasks/t1")
|
|
658
|
+
|
|
659
|
+
def test_done_with_what_the_team_found_out(self):
|
|
660
|
+
self.run_cli(
|
|
661
|
+
"admin", "update", "task", "t1", "--done", "--note", " asked the brand ",
|
|
662
|
+
"--reason", "cuff changed after approval", "--caused-by", "brand", "--once",
|
|
663
|
+
) # fmt: skip
|
|
664
|
+
self.assertEqual(
|
|
665
|
+
(self.rec.last["method"], self.rec.last["path"], self.rec.last["body"]),
|
|
666
|
+
(
|
|
667
|
+
"POST",
|
|
668
|
+
"/admin/tasks/t1/done",
|
|
669
|
+
{
|
|
670
|
+
"note": "asked the brand",
|
|
671
|
+
"reason": "cuff changed after approval",
|
|
672
|
+
"caused_by": "brand",
|
|
673
|
+
"recurs": False,
|
|
674
|
+
},
|
|
675
|
+
),
|
|
676
|
+
)
|
|
677
|
+
self.run_cli("admin", "update", "task", "t1", "--dismiss", "--note", "keeps GBP")
|
|
678
|
+
self.assertEqual(self.rec.last["path"], "/admin/tasks/t1/dismiss")
|
|
679
|
+
|
|
680
|
+
def test_refused_before_the_backend(self):
|
|
681
|
+
self.run_cli("admin", "update", "task", "t1", "--note", "x", expect=2)
|
|
682
|
+
self.run_cli("admin", "update", "task", "t1", "--done", "--dismiss", "-n", "x", expect=2)
|
|
683
|
+
self.run_cli("admin", "update", "task", "t1", "--done", expect=2)
|
|
684
|
+
self.run_cli(
|
|
685
|
+
"admin", "update", "task", "t1", "--dismiss", "-n", "x", "--reason", "r", expect=2
|
|
686
|
+
)
|
|
687
|
+
self.run_cli(
|
|
688
|
+
"admin", "update", "task", "t1", "--done", "-n", "x", "--reason", "r",
|
|
689
|
+
"--caused-by", "weather", expect=2,
|
|
690
|
+
) # fmt: skip
|
|
691
|
+
self.run_cli("admin", "update", "task", "t1", "--done", "-n", "x", "--once", expect=2)
|
|
692
|
+
self.assertEqual(self.rec.calls, [])
|
|
693
|
+
|
|
694
|
+
def test_update_user_sets_the_billing_currency(self):
|
|
695
|
+
self.run_cli("admin", "update", "user", "u1", "--billing-currency", "gbp")
|
|
696
|
+
self.assertEqual(self.rec.last["body"], {"billing_currency": "GBP"})
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.20"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|