makea-cli 0.2.9__tar.gz → 0.2.11__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.9 → makea_cli-0.2.11}/CHANGELOG.md +28 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/PKG-INFO +1 -1
- makea_cli-0.2.11/makea_cli/__init__.py +1 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/api_client.py +130 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/brand/cmd.py +89 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/factory/cmd.py +104 -3
- {makea_cli-0.2.9 → makea_cli-0.2.11}/pyproject.toml +1 -1
- {makea_cli-0.2.9 → makea_cli-0.2.11}/tests/golden_manifest.json +340 -3
- makea_cli-0.2.11/tests/test_pm_reads.py +69 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/uv.lock +4 -2
- makea_cli-0.2.9/makea_cli/__init__.py +0 -1
- {makea_cli-0.2.9 → makea_cli-0.2.11}/.claude/skills/create-supplier-profile/SKILL.md +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/.claude/skills/lark-cli-setup/SKILL.md +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/.claude/skills/link-supplier-user/SKILL.md +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/.claude/skills/makea-cli-setup/SKILL.md +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/.claude/skills/payment-revenue-report/SKILL.md +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/.claude/skills/supplier-user-id-migration/SKILL.md +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/.gitignore +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/README.md +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea-collection-upload/SKILL.md +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea-collection-upload/scripts/create_products.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/__main__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/auth_pkce.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/broker.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/_util.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/analytics/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/analytics/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/auth/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/auth/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/brand/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/designer/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/designer/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/directory/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/directory/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/document/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/document/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/email/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/email/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/factory/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/library/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/library/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/metrics/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/metrics/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/orders/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/orders/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/product/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/product/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/production/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/production/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/production/pricing_spec.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/supplier/__init__.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/commands/supplier/cmd.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/config.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/errors.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/identity.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/main.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/output.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/posthog_client.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/makea_cli/registry.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/npm/makea-cli/README.md +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/npm/makea-cli/makea-cli.mjs +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/npm/makea-cli/package.json +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/tests/test_broker.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/tests/test_output_contract.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/tests/test_persona_commands.py +0 -0
- {makea_cli-0.2.9 → makea_cli-0.2.11}/tests/test_registry.py +0 -0
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.11
|
|
4
|
+
|
|
5
|
+
- Order reads for a factory (and its Beeboo):
|
|
6
|
+
- `supplier get order <rfq> [--readable]`: the sample and bulk orders on one
|
|
7
|
+
RFQ; `--readable` gives each order's state, dates, quantity and what has
|
|
8
|
+
been paid, with no ids or product payload.
|
|
9
|
+
- `supplier list milestone --production-order <id>`: the bulk order's
|
|
10
|
+
milestones, which came back and why, and the proof review's view.
|
|
11
|
+
- `supplier get payment-summary <rfq>`: whether the buyer has paid the
|
|
12
|
+
sample, deposit and balance, and the factory's own price on each PO.
|
|
13
|
+
- `supplier list purchase-order`, `supplier list order-note`.
|
|
14
|
+
- `supplier list production-order` now requires `--rfq` (the backend always
|
|
15
|
+
did; without it the command failed).
|
|
16
|
+
|
|
17
|
+
## 0.2.10
|
|
18
|
+
|
|
19
|
+
- PM reads for a brand (and Beeboo working for one):
|
|
20
|
+
- `designer get tna`: the Time & Action calendar, every pack's arrival with
|
|
21
|
+
how sure it is (done / confirmed / estimated) and its launch day.
|
|
22
|
+
- `designer list milestone --product <id>`: the bulk order's production
|
|
23
|
+
milestones, flattened (step, milestone, status, submitted/approved).
|
|
24
|
+
- `designer list note --product <id> --channel <key> [--since <date>]`: a
|
|
25
|
+
channel's messages without a search keyword, optionally only recent ones.
|
|
26
|
+
- `designer list fit-round --product <id>`: fit rounds and the corrections
|
|
27
|
+
carried into bulk.
|
|
28
|
+
- `designer get costing --style <id>`: one unit of each pack, factory price,
|
|
29
|
+
fees, the brand's freight/duty estimates, target, RRP, margin.
|
|
30
|
+
|
|
3
31
|
## 0.2.9
|
|
4
32
|
|
|
5
33
|
- The analytics commands (`admin get analytics-query`, `active-users`,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.11"
|
|
@@ -1062,6 +1062,43 @@ def supplier_list_production_orders(*, quote_request_id: str | None = None) -> A
|
|
|
1062
1062
|
return get_json("/supplier/production_orders", params=params)
|
|
1063
1063
|
|
|
1064
1064
|
|
|
1065
|
+
def supplier_get_orders(quote_request_id: str, *, readable: bool = False) -> Any:
|
|
1066
|
+
"""GET /supplier/quote_requests/{id}/orders_view — the sample and bulk orders
|
|
1067
|
+
on one RFQ. ``readable``: each order's state, dates and what was paid, with
|
|
1068
|
+
no ids or product payload (the full view runs past 100KB)."""
|
|
1069
|
+
params = {"view": "readable"} if readable else None
|
|
1070
|
+
return get_json(f"/supplier/quote_requests/{quote_request_id}/orders_view", params=params)
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
def supplier_list_milestones(production_order_id: str) -> Any:
|
|
1074
|
+
"""GET /supplier/production_orders/{id}/progress?view=readable — each step's
|
|
1075
|
+
milestones, which one came back and why, and the proof review's view."""
|
|
1076
|
+
return get_json(
|
|
1077
|
+
f"/supplier/production_orders/{production_order_id}/progress",
|
|
1078
|
+
params={"view": "readable"},
|
|
1079
|
+
)
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
def supplier_get_payment_summary(quote_request_id: str) -> Any:
|
|
1083
|
+
"""GET /supplier/quote_requests/{id}/payment_summary — whether the buyer has
|
|
1084
|
+
paid each stage, and the factory's own price on its purchase orders."""
|
|
1085
|
+
return get_json(f"/supplier/quote_requests/{quote_request_id}/payment_summary")
|
|
1086
|
+
|
|
1087
|
+
|
|
1088
|
+
def supplier_list_purchase_orders() -> Any:
|
|
1089
|
+
"""GET /supplier/purchase-orders — purchase orders raised to this factory."""
|
|
1090
|
+
return get_json("/supplier/purchase-orders")
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
def supplier_list_order_notes(
|
|
1094
|
+
*, production_order_id: str | None = None, sampling_order_id: str | None = None
|
|
1095
|
+
) -> Any:
|
|
1096
|
+
"""GET /supplier/{production|sampling}_orders/{id}/notes — an order's notes."""
|
|
1097
|
+
if production_order_id:
|
|
1098
|
+
return get_json(f"/supplier/production_orders/{production_order_id}/notes")
|
|
1099
|
+
return get_json(f"/supplier/sampling_orders/{sampling_order_id}/notes")
|
|
1100
|
+
|
|
1101
|
+
|
|
1065
1102
|
def supplier_list_actions() -> Any:
|
|
1066
1103
|
"""GET /supplier/actions — what the platform is waiting on this factory for."""
|
|
1067
1104
|
return get_json("/supplier/actions")
|
|
@@ -1359,6 +1396,99 @@ def supplier_list_quote_edit_requests(quote_request_id: str) -> Any:
|
|
|
1359
1396
|
return get_json(f"/supplier/quote_requests/{quote_request_id}/quote_edit_requests")
|
|
1360
1397
|
|
|
1361
1398
|
|
|
1399
|
+
def designer_get_tna() -> Any:
|
|
1400
|
+
"""GET /designer/tna_calendar — every pack's five steps and arrival, with
|
|
1401
|
+
the launch it is measured against when the arrival is confirmed."""
|
|
1402
|
+
return get_json("/designer/tna_calendar")
|
|
1403
|
+
|
|
1404
|
+
|
|
1405
|
+
def designer_list_milestones(product_id: str) -> Any:
|
|
1406
|
+
"""Production milestones on a pack's bulk orders, compact: what is done,
|
|
1407
|
+
submitted or waiting, never a lateness the factory did not commit to."""
|
|
1408
|
+
raw = get_json(
|
|
1409
|
+
f"/designer/products/{product_id}/production_order_details",
|
|
1410
|
+
params={"type": "PRODUCTION"},
|
|
1411
|
+
)
|
|
1412
|
+
orders = (
|
|
1413
|
+
raw.get("production_orders_details") or raw.get("orders")
|
|
1414
|
+
if isinstance(raw, dict)
|
|
1415
|
+
else raw
|
|
1416
|
+
)
|
|
1417
|
+
out = []
|
|
1418
|
+
for order in orders or []:
|
|
1419
|
+
if not isinstance(order, dict):
|
|
1420
|
+
continue
|
|
1421
|
+
for step in order.get("production_progress") or []:
|
|
1422
|
+
meta = step.get("metadata") or {}
|
|
1423
|
+
for m in meta.get("milestones") or []:
|
|
1424
|
+
if not isinstance(m, dict):
|
|
1425
|
+
continue
|
|
1426
|
+
out.append(
|
|
1427
|
+
{
|
|
1428
|
+
"order_id": order.get("production_order_id"),
|
|
1429
|
+
"step": step.get("progress_type"),
|
|
1430
|
+
"milestone": m.get("title"),
|
|
1431
|
+
"status": m.get("status"),
|
|
1432
|
+
"days_from_payment": m.get("time_window"),
|
|
1433
|
+
"submitted_at": m.get("submitted_at"),
|
|
1434
|
+
"approval_result": m.get("approval_result"),
|
|
1435
|
+
"completed_at": m.get("completed_at"),
|
|
1436
|
+
}
|
|
1437
|
+
)
|
|
1438
|
+
return {"product_id": product_id, "milestones": out}
|
|
1439
|
+
|
|
1440
|
+
|
|
1441
|
+
def designer_list_notes(
|
|
1442
|
+
product_id: str, channel_key: str, *, since: str | None = None
|
|
1443
|
+
) -> Any:
|
|
1444
|
+
"""A channel's messages, oldest first, optionally only those after
|
|
1445
|
+
``since`` (ISO date or datetime): what the factory said this week."""
|
|
1446
|
+
raw = get_json(f"/designer/products/{product_id}/channels/{channel_key}/notes")
|
|
1447
|
+
notes = raw.get("notes") if isinstance(raw, dict) else raw
|
|
1448
|
+
out = []
|
|
1449
|
+
for n in notes or []:
|
|
1450
|
+
if not isinstance(n, dict):
|
|
1451
|
+
continue
|
|
1452
|
+
if since and str(n.get("created_at") or "") < since:
|
|
1453
|
+
continue
|
|
1454
|
+
out.append(
|
|
1455
|
+
{
|
|
1456
|
+
"note_id": n.get("note_id"),
|
|
1457
|
+
"at": n.get("created_at"),
|
|
1458
|
+
"from": n.get("created_by_type"),
|
|
1459
|
+
"supplier": n.get("supplier_name"),
|
|
1460
|
+
"text": n.get("content"),
|
|
1461
|
+
"replies": len(n.get("replies") or []),
|
|
1462
|
+
}
|
|
1463
|
+
)
|
|
1464
|
+
return {"product_id": product_id, "channel": channel_key, "notes": out}
|
|
1465
|
+
|
|
1466
|
+
|
|
1467
|
+
def designer_list_fit_rounds(product_id: str) -> Any:
|
|
1468
|
+
"""GET /designer/products/{id}/fit_rounds — every fit round on the pack and
|
|
1469
|
+
the corrections carried into bulk."""
|
|
1470
|
+
return get_json(f"/designer/products/{product_id}/fit_rounds")
|
|
1471
|
+
|
|
1472
|
+
|
|
1473
|
+
def designer_get_costing(style_id: str) -> Any:
|
|
1474
|
+
"""One unit of each pack on a product card: factory price, fees, the
|
|
1475
|
+
brand's freight and duty estimates, target, RRP, margin."""
|
|
1476
|
+
raw = get_json(f"/designer/styles/{style_id}/overview")
|
|
1477
|
+
packs = raw.get("packs") if isinstance(raw, dict) else []
|
|
1478
|
+
return {
|
|
1479
|
+
"style_id": style_id,
|
|
1480
|
+
"packs": [
|
|
1481
|
+
{
|
|
1482
|
+
"product_id": p.get("product_id"),
|
|
1483
|
+
"pack": p.get("pack_label"),
|
|
1484
|
+
"costing": p.get("costing"),
|
|
1485
|
+
}
|
|
1486
|
+
for p in packs or []
|
|
1487
|
+
if isinstance(p, dict)
|
|
1488
|
+
],
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
|
|
1362
1492
|
def designer_list_actions(*, product_id: str | None = None) -> Any:
|
|
1363
1493
|
"""GET /designer/actions — the brand's pending actions, optionally for one product."""
|
|
1364
1494
|
params = {"product_id": product_id} if product_id else None
|
|
@@ -212,6 +212,95 @@ def register(app: typer.Typer) -> None:
|
|
|
212
212
|
"""List a product's channels."""
|
|
213
213
|
print_json_or_exit(console, lambda: api_client.designer_list_channels(product))
|
|
214
214
|
|
|
215
|
+
@command(
|
|
216
|
+
app,
|
|
217
|
+
"designer",
|
|
218
|
+
"get",
|
|
219
|
+
"tna",
|
|
220
|
+
api="GET /designer/tna_calendar",
|
|
221
|
+
help=(
|
|
222
|
+
"GET /designer/tna_calendar — when each pack arrives and how sure that is "
|
|
223
|
+
"(done / confirmed / estimated), with its launch day."
|
|
224
|
+
),
|
|
225
|
+
)
|
|
226
|
+
def get_tna() -> None:
|
|
227
|
+
"""The Time & Action calendar."""
|
|
228
|
+
print_json_or_exit(console, lambda: api_client.designer_get_tna())
|
|
229
|
+
|
|
230
|
+
@command(
|
|
231
|
+
app,
|
|
232
|
+
"designer",
|
|
233
|
+
"list",
|
|
234
|
+
"milestone",
|
|
235
|
+
api="GET /designer/products/{product_id}/production_order_details",
|
|
236
|
+
help=(
|
|
237
|
+
"GET /designer/products/{id}/production_order_details — the bulk order's "
|
|
238
|
+
"production milestones: done, submitted, waiting."
|
|
239
|
+
),
|
|
240
|
+
)
|
|
241
|
+
def list_milestones(
|
|
242
|
+
product: str = typer.Option(..., "--product", "-p", help="Product id."),
|
|
243
|
+
) -> None:
|
|
244
|
+
"""List a pack's production milestones."""
|
|
245
|
+
print_json_or_exit(console, lambda: api_client.designer_list_milestones(product))
|
|
246
|
+
|
|
247
|
+
@command(
|
|
248
|
+
app,
|
|
249
|
+
"designer",
|
|
250
|
+
"list",
|
|
251
|
+
"note",
|
|
252
|
+
api="GET /designer/products/{product_id}/channels/{channel_key}/notes",
|
|
253
|
+
help=(
|
|
254
|
+
"GET /designer/products/{id}/channels/{key}/notes — a channel's messages, "
|
|
255
|
+
"oldest first; --since keeps the recent ones (no keyword needed)."
|
|
256
|
+
),
|
|
257
|
+
)
|
|
258
|
+
def list_notes(
|
|
259
|
+
product: str = typer.Option(..., "--product", "-p", help="Product id."),
|
|
260
|
+
channel: str = typer.Option(..., "--channel", "-c", help="Channel key."),
|
|
261
|
+
since: str | None = typer.Option(
|
|
262
|
+
None, "--since", help="ISO date or datetime, e.g. 2026-10-01."
|
|
263
|
+
),
|
|
264
|
+
) -> None:
|
|
265
|
+
"""List a channel's messages."""
|
|
266
|
+
print_json_or_exit(
|
|
267
|
+
console, lambda: api_client.designer_list_notes(product, channel, since=since)
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
@command(
|
|
271
|
+
app,
|
|
272
|
+
"designer",
|
|
273
|
+
"list",
|
|
274
|
+
"fit-round",
|
|
275
|
+
api="GET /designer/products/{product_id}/fit_rounds",
|
|
276
|
+
help=(
|
|
277
|
+
"GET /designer/products/{id}/fit_rounds — the pack's fit rounds and the "
|
|
278
|
+
"corrections carried into bulk."
|
|
279
|
+
),
|
|
280
|
+
)
|
|
281
|
+
def list_fit_rounds(
|
|
282
|
+
product: str = typer.Option(..., "--product", "-p", help="Product id."),
|
|
283
|
+
) -> None:
|
|
284
|
+
"""List a pack's fit rounds."""
|
|
285
|
+
print_json_or_exit(console, lambda: api_client.designer_list_fit_rounds(product))
|
|
286
|
+
|
|
287
|
+
@command(
|
|
288
|
+
app,
|
|
289
|
+
"designer",
|
|
290
|
+
"get",
|
|
291
|
+
"costing",
|
|
292
|
+
api="GET /designer/styles/{style_id}/overview",
|
|
293
|
+
help=(
|
|
294
|
+
"GET /designer/styles/{id}/overview — what one unit of each pack costs and "
|
|
295
|
+
"the margin at RRP (freight and duty are the brand's estimates)."
|
|
296
|
+
),
|
|
297
|
+
)
|
|
298
|
+
def get_costing(
|
|
299
|
+
style: str = typer.Option(..., "--style", "-s", help="Product card (style) id."),
|
|
300
|
+
) -> None:
|
|
301
|
+
"""A product card's unit cost and margin."""
|
|
302
|
+
print_json_or_exit(console, lambda: api_client.designer_get_costing(style))
|
|
303
|
+
|
|
215
304
|
@command(
|
|
216
305
|
app,
|
|
217
306
|
"designer",
|
|
@@ -96,11 +96,11 @@ def register(app: typer.Typer) -> None:
|
|
|
96
96
|
"list",
|
|
97
97
|
"production-order",
|
|
98
98
|
api="GET /supplier/production_orders",
|
|
99
|
-
help="GET /supplier/production_orders —
|
|
99
|
+
help="GET /supplier/production_orders?quote_request_id=… — the bulk orders on one RFQ.",
|
|
100
100
|
)
|
|
101
101
|
def list_production_orders(
|
|
102
|
-
rfq: str
|
|
103
|
-
|
|
102
|
+
rfq: str = typer.Option(
|
|
103
|
+
..., "--rfq", help="The quote request whose orders to list (required)."
|
|
104
104
|
),
|
|
105
105
|
) -> None:
|
|
106
106
|
"""List the factory's production orders."""
|
|
@@ -108,6 +108,107 @@ def register(app: typer.Typer) -> None:
|
|
|
108
108
|
console, lambda: api_client.supplier_list_production_orders(quote_request_id=rfq)
|
|
109
109
|
)
|
|
110
110
|
|
|
111
|
+
@command(
|
|
112
|
+
app,
|
|
113
|
+
"supplier",
|
|
114
|
+
"get",
|
|
115
|
+
"order",
|
|
116
|
+
api="GET /supplier/quote_requests/{id}/orders_view",
|
|
117
|
+
help=(
|
|
118
|
+
"GET /supplier/quote_requests/{id}/orders_view — the sample and bulk orders on one RFQ."
|
|
119
|
+
),
|
|
120
|
+
)
|
|
121
|
+
def get_order(
|
|
122
|
+
quote_request_id: str = typer.Argument(..., help="The quote request."),
|
|
123
|
+
readable: bool = typer.Option(
|
|
124
|
+
False,
|
|
125
|
+
"--readable",
|
|
126
|
+
help=(
|
|
127
|
+
"Each order's state, dates, quantity and what has been paid, with "
|
|
128
|
+
"no ids or product payload. The full view runs past 100KB."
|
|
129
|
+
),
|
|
130
|
+
),
|
|
131
|
+
) -> None:
|
|
132
|
+
"""Read the orders on one RFQ."""
|
|
133
|
+
print_json_or_exit(
|
|
134
|
+
console,
|
|
135
|
+
lambda: api_client.supplier_get_orders(quote_request_id, readable=readable),
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
@command(
|
|
139
|
+
app,
|
|
140
|
+
"supplier",
|
|
141
|
+
"list",
|
|
142
|
+
"milestone",
|
|
143
|
+
api="GET /supplier/production_orders/{id}/progress",
|
|
144
|
+
help=(
|
|
145
|
+
"GET /supplier/production_orders/{id}/progress?view=readable — each "
|
|
146
|
+
"step's milestones, which came back and why, and the proof review."
|
|
147
|
+
),
|
|
148
|
+
)
|
|
149
|
+
def list_milestones(
|
|
150
|
+
production_order: str = typer.Option(
|
|
151
|
+
..., "--production-order", help="The bulk order (from `get order`)."
|
|
152
|
+
),
|
|
153
|
+
) -> None:
|
|
154
|
+
"""List a bulk order's production milestones."""
|
|
155
|
+
print_json_or_exit(console, lambda: api_client.supplier_list_milestones(production_order))
|
|
156
|
+
|
|
157
|
+
@command(
|
|
158
|
+
app,
|
|
159
|
+
"supplier",
|
|
160
|
+
"get",
|
|
161
|
+
"payment-summary",
|
|
162
|
+
api="GET /supplier/quote_requests/{id}/payment_summary",
|
|
163
|
+
help=(
|
|
164
|
+
"GET /supplier/quote_requests/{id}/payment_summary — whether the buyer "
|
|
165
|
+
"has paid the sample, deposit and balance, and your price on each PO."
|
|
166
|
+
),
|
|
167
|
+
)
|
|
168
|
+
def get_payment_summary(
|
|
169
|
+
quote_request_id: str = typer.Argument(..., help="The quote request."),
|
|
170
|
+
) -> None:
|
|
171
|
+
"""Where the money for one RFQ stands, from the factory's side."""
|
|
172
|
+
print_json_or_exit(
|
|
173
|
+
console, lambda: api_client.supplier_get_payment_summary(quote_request_id)
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
@command(
|
|
177
|
+
app,
|
|
178
|
+
"supplier",
|
|
179
|
+
"list",
|
|
180
|
+
"purchase-order",
|
|
181
|
+
api="GET /supplier/purchase-orders",
|
|
182
|
+
help="GET /supplier/purchase-orders — the purchase orders raised to you.",
|
|
183
|
+
)
|
|
184
|
+
def list_purchase_orders() -> None:
|
|
185
|
+
"""List the factory's purchase orders."""
|
|
186
|
+
print_json_or_exit(console, lambda: api_client.supplier_list_purchase_orders())
|
|
187
|
+
|
|
188
|
+
@command(
|
|
189
|
+
app,
|
|
190
|
+
"supplier",
|
|
191
|
+
"list",
|
|
192
|
+
"order-note",
|
|
193
|
+
api="GET /supplier/production_orders/{id}/notes",
|
|
194
|
+
help=("GET /supplier/{production|sampling}_orders/{id}/notes — the notes on one order."),
|
|
195
|
+
)
|
|
196
|
+
def list_order_notes(
|
|
197
|
+
production_order: str | None = typer.Option(
|
|
198
|
+
None, "--production-order", help="A bulk order."
|
|
199
|
+
),
|
|
200
|
+
sampling_order: str | None = typer.Option(None, "--sampling-order", help="A sample order."),
|
|
201
|
+
) -> None:
|
|
202
|
+
"""List the notes on one order."""
|
|
203
|
+
if bool(production_order) == bool(sampling_order):
|
|
204
|
+
raise typer.BadParameter("Give exactly one of --production-order, --sampling-order")
|
|
205
|
+
print_json_or_exit(
|
|
206
|
+
console,
|
|
207
|
+
lambda: api_client.supplier_list_order_notes(
|
|
208
|
+
production_order_id=production_order, sampling_order_id=sampling_order
|
|
209
|
+
),
|
|
210
|
+
)
|
|
211
|
+
|
|
111
212
|
@command(
|
|
112
213
|
app,
|
|
113
214
|
"supplier",
|
|
@@ -5257,6 +5257,38 @@
|
|
|
5257
5257
|
}
|
|
5258
5258
|
]
|
|
5259
5259
|
},
|
|
5260
|
+
{
|
|
5261
|
+
"name": "designer get costing",
|
|
5262
|
+
"persona": "designer",
|
|
5263
|
+
"verb": "get",
|
|
5264
|
+
"noun": "costing",
|
|
5265
|
+
"access": "read",
|
|
5266
|
+
"api": "GET /designer/styles/{style_id}/overview",
|
|
5267
|
+
"external": null,
|
|
5268
|
+
"side_effects": [],
|
|
5269
|
+
"approval": "auto",
|
|
5270
|
+
"reversible": null,
|
|
5271
|
+
"idempotent": null,
|
|
5272
|
+
"limit": null,
|
|
5273
|
+
"legacy": [],
|
|
5274
|
+
"help": "GET /designer/styles/{id}/overview — what one unit of each pack costs and the margin at RRP (freight and duty are the brand's estimates).",
|
|
5275
|
+
"function": "makea_cli.commands.brand.cmd.register.<locals>.get_costing",
|
|
5276
|
+
"flags": [
|
|
5277
|
+
{
|
|
5278
|
+
"name": "style",
|
|
5279
|
+
"kind": "option",
|
|
5280
|
+
"opts": [
|
|
5281
|
+
"--style",
|
|
5282
|
+
"-s"
|
|
5283
|
+
],
|
|
5284
|
+
"type": "text",
|
|
5285
|
+
"required": true,
|
|
5286
|
+
"multiple": false,
|
|
5287
|
+
"default": null,
|
|
5288
|
+
"help": "Product card (style) id."
|
|
5289
|
+
}
|
|
5290
|
+
]
|
|
5291
|
+
},
|
|
5260
5292
|
{
|
|
5261
5293
|
"name": "designer get lifecycle",
|
|
5262
5294
|
"persona": "designer",
|
|
@@ -5468,6 +5500,24 @@
|
|
|
5468
5500
|
}
|
|
5469
5501
|
]
|
|
5470
5502
|
},
|
|
5503
|
+
{
|
|
5504
|
+
"name": "designer get tna",
|
|
5505
|
+
"persona": "designer",
|
|
5506
|
+
"verb": "get",
|
|
5507
|
+
"noun": "tna",
|
|
5508
|
+
"access": "read",
|
|
5509
|
+
"api": "GET /designer/tna_calendar",
|
|
5510
|
+
"external": null,
|
|
5511
|
+
"side_effects": [],
|
|
5512
|
+
"approval": "auto",
|
|
5513
|
+
"reversible": null,
|
|
5514
|
+
"idempotent": null,
|
|
5515
|
+
"limit": null,
|
|
5516
|
+
"legacy": [],
|
|
5517
|
+
"help": "GET /designer/tna_calendar — when each pack arrives and how sure that is (done / confirmed / estimated), with its launch day.",
|
|
5518
|
+
"function": "makea_cli.commands.brand.cmd.register.<locals>.get_tna",
|
|
5519
|
+
"flags": []
|
|
5520
|
+
},
|
|
5471
5521
|
{
|
|
5472
5522
|
"name": "designer list action",
|
|
5473
5523
|
"persona": "designer",
|
|
@@ -5550,6 +5600,38 @@
|
|
|
5550
5600
|
"function": "makea_cli.commands.brand.cmd.register.<locals>.list_collections",
|
|
5551
5601
|
"flags": []
|
|
5552
5602
|
},
|
|
5603
|
+
{
|
|
5604
|
+
"name": "designer list fit-round",
|
|
5605
|
+
"persona": "designer",
|
|
5606
|
+
"verb": "list",
|
|
5607
|
+
"noun": "fit-round",
|
|
5608
|
+
"access": "read",
|
|
5609
|
+
"api": "GET /designer/products/{product_id}/fit_rounds",
|
|
5610
|
+
"external": null,
|
|
5611
|
+
"side_effects": [],
|
|
5612
|
+
"approval": "auto",
|
|
5613
|
+
"reversible": null,
|
|
5614
|
+
"idempotent": null,
|
|
5615
|
+
"limit": "client",
|
|
5616
|
+
"legacy": [],
|
|
5617
|
+
"help": "GET /designer/products/{id}/fit_rounds — the pack's fit rounds and the corrections carried into bulk.",
|
|
5618
|
+
"function": "makea_cli.commands.brand.cmd.register.<locals>.list_fit_rounds",
|
|
5619
|
+
"flags": [
|
|
5620
|
+
{
|
|
5621
|
+
"name": "product",
|
|
5622
|
+
"kind": "option",
|
|
5623
|
+
"opts": [
|
|
5624
|
+
"--product",
|
|
5625
|
+
"-p"
|
|
5626
|
+
],
|
|
5627
|
+
"type": "text",
|
|
5628
|
+
"required": true,
|
|
5629
|
+
"multiple": false,
|
|
5630
|
+
"default": null,
|
|
5631
|
+
"help": "Product id."
|
|
5632
|
+
}
|
|
5633
|
+
]
|
|
5634
|
+
},
|
|
5553
5635
|
{
|
|
5554
5636
|
"name": "designer list library-element",
|
|
5555
5637
|
"persona": "designer",
|
|
@@ -5593,6 +5675,95 @@
|
|
|
5593
5675
|
}
|
|
5594
5676
|
]
|
|
5595
5677
|
},
|
|
5678
|
+
{
|
|
5679
|
+
"name": "designer list milestone",
|
|
5680
|
+
"persona": "designer",
|
|
5681
|
+
"verb": "list",
|
|
5682
|
+
"noun": "milestone",
|
|
5683
|
+
"access": "read",
|
|
5684
|
+
"api": "GET /designer/products/{product_id}/production_order_details",
|
|
5685
|
+
"external": null,
|
|
5686
|
+
"side_effects": [],
|
|
5687
|
+
"approval": "auto",
|
|
5688
|
+
"reversible": null,
|
|
5689
|
+
"idempotent": null,
|
|
5690
|
+
"limit": "client",
|
|
5691
|
+
"legacy": [],
|
|
5692
|
+
"help": "GET /designer/products/{id}/production_order_details — the bulk order's production milestones: done, submitted, waiting.",
|
|
5693
|
+
"function": "makea_cli.commands.brand.cmd.register.<locals>.list_milestones",
|
|
5694
|
+
"flags": [
|
|
5695
|
+
{
|
|
5696
|
+
"name": "product",
|
|
5697
|
+
"kind": "option",
|
|
5698
|
+
"opts": [
|
|
5699
|
+
"--product",
|
|
5700
|
+
"-p"
|
|
5701
|
+
],
|
|
5702
|
+
"type": "text",
|
|
5703
|
+
"required": true,
|
|
5704
|
+
"multiple": false,
|
|
5705
|
+
"default": null,
|
|
5706
|
+
"help": "Product id."
|
|
5707
|
+
}
|
|
5708
|
+
]
|
|
5709
|
+
},
|
|
5710
|
+
{
|
|
5711
|
+
"name": "designer list note",
|
|
5712
|
+
"persona": "designer",
|
|
5713
|
+
"verb": "list",
|
|
5714
|
+
"noun": "note",
|
|
5715
|
+
"access": "read",
|
|
5716
|
+
"api": "GET /designer/products/{product_id}/channels/{channel_key}/notes",
|
|
5717
|
+
"external": null,
|
|
5718
|
+
"side_effects": [],
|
|
5719
|
+
"approval": "auto",
|
|
5720
|
+
"reversible": null,
|
|
5721
|
+
"idempotent": null,
|
|
5722
|
+
"limit": "client",
|
|
5723
|
+
"legacy": [],
|
|
5724
|
+
"help": "GET /designer/products/{id}/channels/{key}/notes — a channel's messages, oldest first; --since keeps the recent ones (no keyword needed).",
|
|
5725
|
+
"function": "makea_cli.commands.brand.cmd.register.<locals>.list_notes",
|
|
5726
|
+
"flags": [
|
|
5727
|
+
{
|
|
5728
|
+
"name": "product",
|
|
5729
|
+
"kind": "option",
|
|
5730
|
+
"opts": [
|
|
5731
|
+
"--product",
|
|
5732
|
+
"-p"
|
|
5733
|
+
],
|
|
5734
|
+
"type": "text",
|
|
5735
|
+
"required": true,
|
|
5736
|
+
"multiple": false,
|
|
5737
|
+
"default": null,
|
|
5738
|
+
"help": "Product id."
|
|
5739
|
+
},
|
|
5740
|
+
{
|
|
5741
|
+
"name": "channel",
|
|
5742
|
+
"kind": "option",
|
|
5743
|
+
"opts": [
|
|
5744
|
+
"--channel",
|
|
5745
|
+
"-c"
|
|
5746
|
+
],
|
|
5747
|
+
"type": "text",
|
|
5748
|
+
"required": true,
|
|
5749
|
+
"multiple": false,
|
|
5750
|
+
"default": null,
|
|
5751
|
+
"help": "Channel key."
|
|
5752
|
+
},
|
|
5753
|
+
{
|
|
5754
|
+
"name": "since",
|
|
5755
|
+
"kind": "option",
|
|
5756
|
+
"opts": [
|
|
5757
|
+
"--since"
|
|
5758
|
+
],
|
|
5759
|
+
"type": "text",
|
|
5760
|
+
"required": false,
|
|
5761
|
+
"multiple": false,
|
|
5762
|
+
"default": null,
|
|
5763
|
+
"help": "ISO date or datetime, e.g. 2026-10-01."
|
|
5764
|
+
}
|
|
5765
|
+
]
|
|
5766
|
+
},
|
|
5596
5767
|
{
|
|
5597
5768
|
"name": "designer list payment",
|
|
5598
5769
|
"persona": "designer",
|
|
@@ -6820,6 +6991,49 @@
|
|
|
6820
6991
|
}
|
|
6821
6992
|
]
|
|
6822
6993
|
},
|
|
6994
|
+
{
|
|
6995
|
+
"name": "supplier get order",
|
|
6996
|
+
"persona": "supplier",
|
|
6997
|
+
"verb": "get",
|
|
6998
|
+
"noun": "order",
|
|
6999
|
+
"access": "read",
|
|
7000
|
+
"api": "GET /supplier/quote_requests/{id}/orders_view",
|
|
7001
|
+
"external": null,
|
|
7002
|
+
"side_effects": [],
|
|
7003
|
+
"approval": "auto",
|
|
7004
|
+
"reversible": null,
|
|
7005
|
+
"idempotent": null,
|
|
7006
|
+
"limit": null,
|
|
7007
|
+
"legacy": [],
|
|
7008
|
+
"help": "GET /supplier/quote_requests/{id}/orders_view — the sample and bulk orders on one RFQ.",
|
|
7009
|
+
"function": "makea_cli.commands.factory.cmd.register.<locals>.get_order",
|
|
7010
|
+
"flags": [
|
|
7011
|
+
{
|
|
7012
|
+
"name": "quote_request_id",
|
|
7013
|
+
"kind": "argument",
|
|
7014
|
+
"opts": [
|
|
7015
|
+
"quote_request_id"
|
|
7016
|
+
],
|
|
7017
|
+
"type": "text",
|
|
7018
|
+
"required": true,
|
|
7019
|
+
"multiple": false,
|
|
7020
|
+
"default": null,
|
|
7021
|
+
"help": "The quote request."
|
|
7022
|
+
},
|
|
7023
|
+
{
|
|
7024
|
+
"name": "readable",
|
|
7025
|
+
"kind": "option",
|
|
7026
|
+
"opts": [
|
|
7027
|
+
"--readable"
|
|
7028
|
+
],
|
|
7029
|
+
"type": "flag",
|
|
7030
|
+
"required": false,
|
|
7031
|
+
"multiple": false,
|
|
7032
|
+
"default": false,
|
|
7033
|
+
"help": "Each order's state, dates, quantity and what has been paid, with no ids or product payload. The full view runs past 100KB."
|
|
7034
|
+
}
|
|
7035
|
+
]
|
|
7036
|
+
},
|
|
6823
7037
|
{
|
|
6824
7038
|
"name": "supplier get pack",
|
|
6825
7039
|
"persona": "supplier",
|
|
@@ -6895,6 +7109,37 @@
|
|
|
6895
7109
|
}
|
|
6896
7110
|
]
|
|
6897
7111
|
},
|
|
7112
|
+
{
|
|
7113
|
+
"name": "supplier get payment-summary",
|
|
7114
|
+
"persona": "supplier",
|
|
7115
|
+
"verb": "get",
|
|
7116
|
+
"noun": "payment-summary",
|
|
7117
|
+
"access": "read",
|
|
7118
|
+
"api": "GET /supplier/quote_requests/{id}/payment_summary",
|
|
7119
|
+
"external": null,
|
|
7120
|
+
"side_effects": [],
|
|
7121
|
+
"approval": "auto",
|
|
7122
|
+
"reversible": null,
|
|
7123
|
+
"idempotent": null,
|
|
7124
|
+
"limit": null,
|
|
7125
|
+
"legacy": [],
|
|
7126
|
+
"help": "GET /supplier/quote_requests/{id}/payment_summary — whether the buyer has paid the sample, deposit and balance, and your price on each PO.",
|
|
7127
|
+
"function": "makea_cli.commands.factory.cmd.register.<locals>.get_payment_summary",
|
|
7128
|
+
"flags": [
|
|
7129
|
+
{
|
|
7130
|
+
"name": "quote_request_id",
|
|
7131
|
+
"kind": "argument",
|
|
7132
|
+
"opts": [
|
|
7133
|
+
"quote_request_id"
|
|
7134
|
+
],
|
|
7135
|
+
"type": "text",
|
|
7136
|
+
"required": true,
|
|
7137
|
+
"multiple": false,
|
|
7138
|
+
"default": null,
|
|
7139
|
+
"help": "The quote request."
|
|
7140
|
+
}
|
|
7141
|
+
]
|
|
7142
|
+
},
|
|
6898
7143
|
{
|
|
6899
7144
|
"name": "supplier get profile",
|
|
6900
7145
|
"persona": "supplier",
|
|
@@ -6994,6 +7239,37 @@
|
|
|
6994
7239
|
}
|
|
6995
7240
|
]
|
|
6996
7241
|
},
|
|
7242
|
+
{
|
|
7243
|
+
"name": "supplier list milestone",
|
|
7244
|
+
"persona": "supplier",
|
|
7245
|
+
"verb": "list",
|
|
7246
|
+
"noun": "milestone",
|
|
7247
|
+
"access": "read",
|
|
7248
|
+
"api": "GET /supplier/production_orders/{id}/progress",
|
|
7249
|
+
"external": null,
|
|
7250
|
+
"side_effects": [],
|
|
7251
|
+
"approval": "auto",
|
|
7252
|
+
"reversible": null,
|
|
7253
|
+
"idempotent": null,
|
|
7254
|
+
"limit": "client",
|
|
7255
|
+
"legacy": [],
|
|
7256
|
+
"help": "GET /supplier/production_orders/{id}/progress?view=readable — each step's milestones, which came back and why, and the proof review.",
|
|
7257
|
+
"function": "makea_cli.commands.factory.cmd.register.<locals>.list_milestones",
|
|
7258
|
+
"flags": [
|
|
7259
|
+
{
|
|
7260
|
+
"name": "production_order",
|
|
7261
|
+
"kind": "option",
|
|
7262
|
+
"opts": [
|
|
7263
|
+
"--production-order"
|
|
7264
|
+
],
|
|
7265
|
+
"type": "text",
|
|
7266
|
+
"required": true,
|
|
7267
|
+
"multiple": false,
|
|
7268
|
+
"default": null,
|
|
7269
|
+
"help": "The bulk order (from `get order`)."
|
|
7270
|
+
}
|
|
7271
|
+
]
|
|
7272
|
+
},
|
|
6997
7273
|
{
|
|
6998
7274
|
"name": "supplier list note",
|
|
6999
7275
|
"persona": "supplier",
|
|
@@ -7039,6 +7315,49 @@
|
|
|
7039
7315
|
}
|
|
7040
7316
|
]
|
|
7041
7317
|
},
|
|
7318
|
+
{
|
|
7319
|
+
"name": "supplier list order-note",
|
|
7320
|
+
"persona": "supplier",
|
|
7321
|
+
"verb": "list",
|
|
7322
|
+
"noun": "order-note",
|
|
7323
|
+
"access": "read",
|
|
7324
|
+
"api": "GET /supplier/production_orders/{id}/notes",
|
|
7325
|
+
"external": null,
|
|
7326
|
+
"side_effects": [],
|
|
7327
|
+
"approval": "auto",
|
|
7328
|
+
"reversible": null,
|
|
7329
|
+
"idempotent": null,
|
|
7330
|
+
"limit": "client",
|
|
7331
|
+
"legacy": [],
|
|
7332
|
+
"help": "GET /supplier/{production|sampling}_orders/{id}/notes — the notes on one order.",
|
|
7333
|
+
"function": "makea_cli.commands.factory.cmd.register.<locals>.list_order_notes",
|
|
7334
|
+
"flags": [
|
|
7335
|
+
{
|
|
7336
|
+
"name": "production_order",
|
|
7337
|
+
"kind": "option",
|
|
7338
|
+
"opts": [
|
|
7339
|
+
"--production-order"
|
|
7340
|
+
],
|
|
7341
|
+
"type": "text",
|
|
7342
|
+
"required": false,
|
|
7343
|
+
"multiple": false,
|
|
7344
|
+
"default": null,
|
|
7345
|
+
"help": "A bulk order."
|
|
7346
|
+
},
|
|
7347
|
+
{
|
|
7348
|
+
"name": "sampling_order",
|
|
7349
|
+
"kind": "option",
|
|
7350
|
+
"opts": [
|
|
7351
|
+
"--sampling-order"
|
|
7352
|
+
],
|
|
7353
|
+
"type": "text",
|
|
7354
|
+
"required": false,
|
|
7355
|
+
"multiple": false,
|
|
7356
|
+
"default": null,
|
|
7357
|
+
"help": "A sample order."
|
|
7358
|
+
}
|
|
7359
|
+
]
|
|
7360
|
+
},
|
|
7042
7361
|
{
|
|
7043
7362
|
"name": "supplier list production-order",
|
|
7044
7363
|
"persona": "supplier",
|
|
@@ -7053,7 +7372,7 @@
|
|
|
7053
7372
|
"idempotent": null,
|
|
7054
7373
|
"limit": "client",
|
|
7055
7374
|
"legacy": [],
|
|
7056
|
-
"help": "GET /supplier/production_orders —
|
|
7375
|
+
"help": "GET /supplier/production_orders?quote_request_id=… — the bulk orders on one RFQ.",
|
|
7057
7376
|
"function": "makea_cli.commands.factory.cmd.register.<locals>.list_production_orders",
|
|
7058
7377
|
"flags": [
|
|
7059
7378
|
{
|
|
@@ -7063,13 +7382,31 @@
|
|
|
7063
7382
|
"--rfq"
|
|
7064
7383
|
],
|
|
7065
7384
|
"type": "text",
|
|
7066
|
-
"required":
|
|
7385
|
+
"required": true,
|
|
7067
7386
|
"multiple": false,
|
|
7068
7387
|
"default": null,
|
|
7069
|
-
"help": "
|
|
7388
|
+
"help": "The quote request whose orders to list (required)."
|
|
7070
7389
|
}
|
|
7071
7390
|
]
|
|
7072
7391
|
},
|
|
7392
|
+
{
|
|
7393
|
+
"name": "supplier list purchase-order",
|
|
7394
|
+
"persona": "supplier",
|
|
7395
|
+
"verb": "list",
|
|
7396
|
+
"noun": "purchase-order",
|
|
7397
|
+
"access": "read",
|
|
7398
|
+
"api": "GET /supplier/purchase-orders",
|
|
7399
|
+
"external": null,
|
|
7400
|
+
"side_effects": [],
|
|
7401
|
+
"approval": "auto",
|
|
7402
|
+
"reversible": null,
|
|
7403
|
+
"idempotent": null,
|
|
7404
|
+
"limit": "client",
|
|
7405
|
+
"legacy": [],
|
|
7406
|
+
"help": "GET /supplier/purchase-orders — the purchase orders raised to you.",
|
|
7407
|
+
"function": "makea_cli.commands.factory.cmd.register.<locals>.list_purchase_orders",
|
|
7408
|
+
"flags": []
|
|
7409
|
+
},
|
|
7073
7410
|
{
|
|
7074
7411
|
"name": "supplier list quote-edit-request",
|
|
7075
7412
|
"persona": "supplier",
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""The PM reads Beeboo uses: milestones, recent notes, costing — trimmed to
|
|
2
|
+
what answers "will it be on time", "what did the factory say this week",
|
|
3
|
+
"what does it cost".
|
|
4
|
+
|
|
5
|
+
Run with ``.venv/bin/python -m unittest tests.test_pm_reads``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import unittest
|
|
9
|
+
from unittest import mock
|
|
10
|
+
|
|
11
|
+
from makea_cli import api_client
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PmReadsTest(unittest.TestCase):
|
|
15
|
+
def test_milestones_are_flattened(self):
|
|
16
|
+
raw = {
|
|
17
|
+
"production_orders_details": [
|
|
18
|
+
{
|
|
19
|
+
"production_order_id": "po1",
|
|
20
|
+
"production_progress": [
|
|
21
|
+
{
|
|
22
|
+
"progress_type": "During Production",
|
|
23
|
+
"metadata": {
|
|
24
|
+
"milestones": [
|
|
25
|
+
{"title": "Cutting", "status": "completed", "time_window": ["3", "5"]},
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
with mock.patch.object(api_client, "get_json", return_value=raw):
|
|
34
|
+
out = api_client.designer_list_milestones("p1")
|
|
35
|
+
self.assertEqual(
|
|
36
|
+
out["milestones"][0],
|
|
37
|
+
{
|
|
38
|
+
"order_id": "po1",
|
|
39
|
+
"step": "During Production",
|
|
40
|
+
"milestone": "Cutting",
|
|
41
|
+
"status": "completed",
|
|
42
|
+
"days_from_payment": ["3", "5"],
|
|
43
|
+
"submitted_at": None,
|
|
44
|
+
"approval_result": None,
|
|
45
|
+
"completed_at": None,
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def test_notes_since_keep_the_recent_ones(self):
|
|
50
|
+
raw = {
|
|
51
|
+
"notes": [
|
|
52
|
+
{"note_id": "a", "created_at": "2026-09-30T10:00:00", "content": "old"},
|
|
53
|
+
{"note_id": "b", "created_at": "2026-10-05T10:00:00", "content": "new", "replies": [{}]},
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
with mock.patch.object(api_client, "get_json", return_value=raw):
|
|
57
|
+
out = api_client.designer_list_notes("p1", "supplier:s", since="2026-10-01")
|
|
58
|
+
self.assertEqual([n["note_id"] for n in out["notes"]], ["b"])
|
|
59
|
+
self.assertEqual(out["notes"][0]["replies"], 1)
|
|
60
|
+
|
|
61
|
+
def test_costing_is_per_pack(self):
|
|
62
|
+
raw = {"packs": [{"product_id": "p1", "pack_label": "v1", "costing": {"make": 50}}]}
|
|
63
|
+
with mock.patch.object(api_client, "get_json", return_value=raw):
|
|
64
|
+
out = api_client.designer_get_costing("st1")
|
|
65
|
+
self.assertEqual(out["packs"], [{"product_id": "p1", "pack": "v1", "costing": {"make": 50}}])
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
unittest.main()
|
|
@@ -115,9 +115,10 @@ wheels = [
|
|
|
115
115
|
|
|
116
116
|
[[package]]
|
|
117
117
|
name = "makea-cli"
|
|
118
|
-
version = "0.
|
|
118
|
+
version = "0.2.11"
|
|
119
119
|
source = { editable = "." }
|
|
120
120
|
dependencies = [
|
|
121
|
+
{ name = "click" },
|
|
121
122
|
{ name = "httpx" },
|
|
122
123
|
{ name = "platformdirs" },
|
|
123
124
|
{ name = "rich" },
|
|
@@ -126,10 +127,11 @@ dependencies = [
|
|
|
126
127
|
|
|
127
128
|
[package.metadata]
|
|
128
129
|
requires-dist = [
|
|
130
|
+
{ name = "click", specifier = ">=8.1,<9" },
|
|
129
131
|
{ name = "httpx", specifier = ">=0.27" },
|
|
130
132
|
{ name = "platformdirs", specifier = ">=4.2" },
|
|
131
133
|
{ name = "rich", specifier = ">=13.7" },
|
|
132
|
-
{ name = "typer", specifier = ">=0.12" },
|
|
134
|
+
{ name = "typer", specifier = ">=0.12,<0.25" },
|
|
133
135
|
]
|
|
134
136
|
|
|
135
137
|
[[package]]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.9"
|
|
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
|