makea-cli 0.2.12__tar.gz → 0.2.14__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.12 → makea_cli-0.2.14}/CHANGELOG.md +19 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/PKG-INFO +2 -2
- {makea_cli-0.2.12 → makea_cli-0.2.14}/README.md +1 -1
- makea_cli-0.2.14/makea_cli/__init__.py +1 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/api_client.py +14 -6
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/brand/cmd.py +21 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/orders/cmd.py +7 -5
- {makea_cli-0.2.12 → makea_cli-0.2.14}/pyproject.toml +1 -1
- {makea_cli-0.2.12 → makea_cli-0.2.14}/tests/golden_manifest.json +34 -3
- {makea_cli-0.2.12 → makea_cli-0.2.14}/tests/test_pm_reads.py +14 -3
- makea_cli-0.2.14/tests/test_supplier_scorecard.py +48 -0
- makea_cli-0.2.12/makea_cli/__init__.py +0 -1
- {makea_cli-0.2.12 → makea_cli-0.2.14}/.claude/skills/create-supplier-profile/SKILL.md +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/.claude/skills/lark-cli-setup/SKILL.md +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/.claude/skills/link-supplier-user/SKILL.md +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/.claude/skills/makea-cli-setup/SKILL.md +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/.claude/skills/payment-revenue-report/SKILL.md +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/.claude/skills/supplier-user-id-migration/SKILL.md +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/.gitignore +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea-collection-upload/SKILL.md +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea-collection-upload/scripts/create_products.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/__main__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/auth_pkce.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/broker.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/_util.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/analytics/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/analytics/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/auth/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/auth/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/brand/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/designer/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/designer/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/directory/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/directory/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/document/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/document/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/email/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/email/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/factory/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/factory/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/library/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/library/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/metrics/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/metrics/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/orders/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/product/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/product/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/production/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/production/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/production/pricing_spec.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/supplier/__init__.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/commands/supplier/cmd.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/config.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/errors.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/identity.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/main.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/output.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/posthog_client.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/makea_cli/registry.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/npm/makea-cli/README.md +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/npm/makea-cli/makea-cli.mjs +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/npm/makea-cli/package.json +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/tests/test_broker.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/tests/test_output_contract.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/tests/test_persona_commands.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/tests/test_registry.py +0 -0
- {makea_cli-0.2.12 → makea_cli-0.2.14}/uv.lock +0 -0
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.14
|
|
4
|
+
|
|
5
|
+
- `admin update tracking-status`: help text no longer describes it as "the
|
|
6
|
+
17track webhook path". The 17track integration (registration and webhook)
|
|
7
|
+
was removed from the backend on 2026-10-10; this command, fed by the
|
|
8
|
+
tracking-sweep skill, is now the only way a carrier status reaches an
|
|
9
|
+
order. Behaviour is unchanged.
|
|
10
|
+
|
|
11
|
+
## 0.2.13
|
|
12
|
+
|
|
13
|
+
- `designer get supplier-scorecard [SUPPLIER_ID]`: a factory's track record
|
|
14
|
+
with the brand's team: orders on time against the factory's confirmed date,
|
|
15
|
+
milestone proofs rejected, inspections with High/Critical defects, fit
|
|
16
|
+
rounds that needed a new sample, confirmed dates moved later, median time to
|
|
17
|
+
first quote and to answer the brand's asks, chases, and orders, units and
|
|
18
|
+
styles. Every figure carries its n and period; "too few to judge" below the
|
|
19
|
+
minimum. No id: every factory the brand works with. A read (auto), and
|
|
20
|
+
brand-private: Makea refuses it in a factory's thread.
|
|
21
|
+
|
|
3
22
|
## 0.2.12
|
|
4
23
|
|
|
5
24
|
Fixes from a live exam of Beeboo (2026-10-10):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: makea-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.14
|
|
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
|
|
@@ -131,7 +131,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
131
131
|
| `makea-cli admin update quote-request` | write(ask) | `PATCH /admin/quote_requests/{quote_request_id}/update` | set a quote request's stage, status and/or due date. Only what you pass is changed. This is the door that unblocks a … | `update-quote-request` |
|
|
132
132
|
| `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` |
|
|
133
133
|
| `makea-cli admin update tech-spec` | write(ask) | `POST /admin/products/{id}/technical-specifications` | persist specs from a JSON file. | `save-product-tech-spec` |
|
|
134
|
-
| `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
|
|
134
|
+
| `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). | — |
|
|
135
135
|
| `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` |
|
|
136
136
|
| `makea-cli admin upload financial-document` | write(auto) | `POST /admin/products/{product_id}/financial_documents` | upload one or more files to AWS S3 and return financial document metadata. | `upload-financial-documents` |
|
|
137
137
|
| `makea-cli admin upload link-document` | write(auto) | `POST /admin/upload_link_document` | upload a file to AWS S3 and return document domain metadata for reuse as input in other commands. | `upload-link-document` |
|
|
@@ -119,7 +119,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
119
119
|
| `makea-cli admin update quote-request` | write(ask) | `PATCH /admin/quote_requests/{quote_request_id}/update` | set a quote request's stage, status and/or due date. Only what you pass is changed. This is the door that unblocks a … | `update-quote-request` |
|
|
120
120
|
| `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` |
|
|
121
121
|
| `makea-cli admin update tech-spec` | write(ask) | `POST /admin/products/{id}/technical-specifications` | persist specs from a JSON file. | `save-product-tech-spec` |
|
|
122
|
-
| `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
|
|
122
|
+
| `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). | — |
|
|
123
123
|
| `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` |
|
|
124
124
|
| `makea-cli admin upload financial-document` | write(auto) | `POST /admin/products/{product_id}/financial_documents` | upload one or more files to AWS S3 and return financial document metadata. | `upload-financial-documents` |
|
|
125
125
|
| `makea-cli admin upload link-document` | write(auto) | `POST /admin/upload_link_document` | upload a file to AWS S3 and return document domain metadata for reuse as input in other commands. | `upload-link-document` |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.14"
|
|
@@ -1576,9 +1576,7 @@ def designer_list_milestones(product_id: str) -> Any:
|
|
|
1576
1576
|
params={"type": "PRODUCTION"},
|
|
1577
1577
|
)
|
|
1578
1578
|
orders = (
|
|
1579
|
-
raw.get("production_orders_details") or raw.get("orders")
|
|
1580
|
-
if isinstance(raw, dict)
|
|
1581
|
-
else raw
|
|
1579
|
+
raw.get("production_orders_details") or raw.get("orders") if isinstance(raw, dict) else raw
|
|
1582
1580
|
)
|
|
1583
1581
|
out = []
|
|
1584
1582
|
for order in orders or []:
|
|
@@ -1604,9 +1602,7 @@ def designer_list_milestones(product_id: str) -> Any:
|
|
|
1604
1602
|
return {"product_id": product_id, "milestones": out}
|
|
1605
1603
|
|
|
1606
1604
|
|
|
1607
|
-
def designer_list_notes(
|
|
1608
|
-
product_id: str, channel_key: str, *, since: str | None = None
|
|
1609
|
-
) -> Any:
|
|
1605
|
+
def designer_list_notes(product_id: str, channel_key: str, *, since: str | None = None) -> Any:
|
|
1610
1606
|
"""A channel's messages, oldest first, optionally only those after
|
|
1611
1607
|
``since`` (ISO date or datetime): what the factory said this week."""
|
|
1612
1608
|
raw = get_json(f"/designer/products/{product_id}/channels/{channel_key}/notes")
|
|
@@ -1674,6 +1670,18 @@ def designer_get_costing(style_id: str | None = None, *, product_id: str | None
|
|
|
1674
1670
|
return {"style_id": style_id, "packs": packs}
|
|
1675
1671
|
|
|
1676
1672
|
|
|
1673
|
+
def designer_get_supplier_scorecard(supplier_id: str | None = None) -> Any:
|
|
1674
|
+
"""A factory's track record with the brand's team: on time against its
|
|
1675
|
+
confirmed dates, quality, responsiveness, volume. Each figure has its n and
|
|
1676
|
+
period; "too few to judge" below the minimum. No id: every factory the
|
|
1677
|
+
brand works with. Brand-private."""
|
|
1678
|
+
if supplier_id:
|
|
1679
|
+
raw = get_json(f"/designer/suppliers/{supplier_id}/scorecard")
|
|
1680
|
+
return raw.get("scorecard") if isinstance(raw, dict) else raw
|
|
1681
|
+
raw = get_json("/designer/suppliers/scorecards")
|
|
1682
|
+
return {"scorecards": raw.get("scorecards") if isinstance(raw, dict) else raw}
|
|
1683
|
+
|
|
1684
|
+
|
|
1677
1685
|
def designer_list_actions(*, product_id: str | None = None) -> Any:
|
|
1678
1686
|
"""GET /designer/actions — the brand's pending actions, optionally for one product."""
|
|
1679
1687
|
params = {"product_id": product_id} if product_id else None
|
|
@@ -348,6 +348,27 @@ def register(app: typer.Typer) -> None:
|
|
|
348
348
|
console, lambda: api_client.designer_get_costing(style, product_id=product)
|
|
349
349
|
)
|
|
350
350
|
|
|
351
|
+
@command(
|
|
352
|
+
app,
|
|
353
|
+
"designer",
|
|
354
|
+
"get",
|
|
355
|
+
"supplier-scorecard",
|
|
356
|
+
api="GET /designer/suppliers/{supplier_id}/scorecard",
|
|
357
|
+
help=(
|
|
358
|
+
"GET /designer/suppliers/{id}/scorecard — a factory's track record with the "
|
|
359
|
+
"brand's team (on time vs confirmed dates, quality, responsiveness, volume; "
|
|
360
|
+
"each figure with its n and period). No id: every factory the brand works "
|
|
361
|
+
"with. Brand-private: never shared with the factory."
|
|
362
|
+
),
|
|
363
|
+
)
|
|
364
|
+
def get_supplier_scorecard(
|
|
365
|
+
supplier_id: str | None = typer.Argument(
|
|
366
|
+
None, help="Supplier id; omit for every factory the brand works with."
|
|
367
|
+
),
|
|
368
|
+
) -> None:
|
|
369
|
+
"""A factory's track record with this brand."""
|
|
370
|
+
print_json_or_exit(console, lambda: api_client.designer_get_supplier_scorecard(supplier_id))
|
|
371
|
+
|
|
351
372
|
@command(
|
|
352
373
|
app,
|
|
353
374
|
"designer",
|
|
@@ -323,14 +323,14 @@ def register(app: typer.Typer) -> None:
|
|
|
323
323
|
api="POST /admin/tracking/carrier_status",
|
|
324
324
|
side_effects=[
|
|
325
325
|
"moves the order to delivered when the status says so",
|
|
326
|
-
"emails and messages the designer, supplier and admins
|
|
326
|
+
"emails and messages the designer, supplier and admins that the parcel arrived (none with --silent)",
|
|
327
327
|
],
|
|
328
328
|
approval="ask",
|
|
329
329
|
idempotent=True,
|
|
330
330
|
help=(
|
|
331
331
|
"POST /admin/tracking/carrier_status — apply a carrier status looked up by hand "
|
|
332
|
-
"(the tracking-sweep skill) to one order
|
|
333
|
-
"
|
|
332
|
+
"(the tracking-sweep skill) to one order: status, fan-out to every order "
|
|
333
|
+
"sharing the number, and the delivered emails."
|
|
334
334
|
),
|
|
335
335
|
)
|
|
336
336
|
def update_tracking_status(
|
|
@@ -341,7 +341,9 @@ def register(app: typer.Typer) -> None:
|
|
|
341
341
|
order_id: str = typer.Argument(..., help="Order id (product id for reference_sample)."),
|
|
342
342
|
tracking_number: str = typer.Argument(..., help="The parcel's tracking number."),
|
|
343
343
|
status: str = typer.Option(
|
|
344
|
-
...,
|
|
344
|
+
...,
|
|
345
|
+
"--status",
|
|
346
|
+
help="Carrier status as the public 17track page shows it, e.g. Delivered, InTransit.",
|
|
345
347
|
),
|
|
346
348
|
sub_status: str | None = typer.Option(None, "--sub-status"),
|
|
347
349
|
event: str | None = typer.Option(None, "--event", help="Latest carrier event text."),
|
|
@@ -358,7 +360,7 @@ def register(app: typer.Typer) -> None:
|
|
|
358
360
|
"""
|
|
359
361
|
Tell Makea what the carrier says about one parcel.
|
|
360
362
|
|
|
361
|
-
Output: JSON
|
|
363
|
+
Output: JSON: success, status, and one entry per
|
|
362
364
|
order the number was fanned out to. Repeating a Delivered update is a
|
|
363
365
|
no-op (no second email). --silent moves the orders without telling
|
|
364
366
|
anyone.
|
|
@@ -3574,14 +3574,14 @@
|
|
|
3574
3574
|
"external": null,
|
|
3575
3575
|
"side_effects": [
|
|
3576
3576
|
"moves the order to delivered when the status says so",
|
|
3577
|
-
"emails and messages the designer, supplier and admins
|
|
3577
|
+
"emails and messages the designer, supplier and admins that the parcel arrived (none with --silent)"
|
|
3578
3578
|
],
|
|
3579
3579
|
"approval": "ask",
|
|
3580
3580
|
"reversible": null,
|
|
3581
3581
|
"idempotent": true,
|
|
3582
3582
|
"limit": null,
|
|
3583
3583
|
"legacy": [],
|
|
3584
|
-
"help": "POST /admin/tracking/carrier_status — apply a carrier status looked up by hand (the tracking-sweep skill) to one order
|
|
3584
|
+
"help": "POST /admin/tracking/carrier_status — apply a carrier status looked up by hand (the tracking-sweep skill) to one order: status, fan-out to every order sharing the number, and the delivered emails.",
|
|
3585
3585
|
"function": "makea_cli.commands.orders.cmd.register.<locals>.update_tracking_status",
|
|
3586
3586
|
"flags": [
|
|
3587
3587
|
{
|
|
@@ -3630,7 +3630,7 @@
|
|
|
3630
3630
|
"required": true,
|
|
3631
3631
|
"multiple": false,
|
|
3632
3632
|
"default": null,
|
|
3633
|
-
"help": "17track
|
|
3633
|
+
"help": "Carrier status as the public 17track page shows it, e.g. Delivered, InTransit."
|
|
3634
3634
|
},
|
|
3635
3635
|
{
|
|
3636
3636
|
"name": "sub_status",
|
|
@@ -5477,6 +5477,37 @@
|
|
|
5477
5477
|
}
|
|
5478
5478
|
]
|
|
5479
5479
|
},
|
|
5480
|
+
{
|
|
5481
|
+
"name": "designer get supplier-scorecard",
|
|
5482
|
+
"persona": "designer",
|
|
5483
|
+
"verb": "get",
|
|
5484
|
+
"noun": "supplier-scorecard",
|
|
5485
|
+
"access": "read",
|
|
5486
|
+
"api": "GET /designer/suppliers/{supplier_id}/scorecard",
|
|
5487
|
+
"external": null,
|
|
5488
|
+
"side_effects": [],
|
|
5489
|
+
"approval": "auto",
|
|
5490
|
+
"reversible": null,
|
|
5491
|
+
"idempotent": null,
|
|
5492
|
+
"limit": null,
|
|
5493
|
+
"legacy": [],
|
|
5494
|
+
"help": "GET /designer/suppliers/{id}/scorecard — a factory's track record with the brand's team (on time vs confirmed dates, quality, responsiveness, volume; each figure with its n and period). No id: every factory the brand works with. Brand-private: never shared with the factory.",
|
|
5495
|
+
"function": "makea_cli.commands.brand.cmd.register.<locals>.get_supplier_scorecard",
|
|
5496
|
+
"flags": [
|
|
5497
|
+
{
|
|
5498
|
+
"name": "supplier_id",
|
|
5499
|
+
"kind": "argument",
|
|
5500
|
+
"opts": [
|
|
5501
|
+
"supplier_id"
|
|
5502
|
+
],
|
|
5503
|
+
"type": "text",
|
|
5504
|
+
"required": false,
|
|
5505
|
+
"multiple": false,
|
|
5506
|
+
"default": null,
|
|
5507
|
+
"help": "Supplier id; omit for every factory the brand works with."
|
|
5508
|
+
}
|
|
5509
|
+
]
|
|
5510
|
+
},
|
|
5480
5511
|
{
|
|
5481
5512
|
"name": "designer get tech-pack",
|
|
5482
5513
|
"persona": "designer",
|
|
@@ -22,7 +22,11 @@ class PmReadsTest(unittest.TestCase):
|
|
|
22
22
|
"progress_type": "During Production",
|
|
23
23
|
"metadata": {
|
|
24
24
|
"milestones": [
|
|
25
|
-
{
|
|
25
|
+
{
|
|
26
|
+
"title": "Cutting",
|
|
27
|
+
"status": "completed",
|
|
28
|
+
"time_window": ["3", "5"],
|
|
29
|
+
},
|
|
26
30
|
]
|
|
27
31
|
},
|
|
28
32
|
}
|
|
@@ -50,7 +54,12 @@ class PmReadsTest(unittest.TestCase):
|
|
|
50
54
|
raw = {
|
|
51
55
|
"notes": [
|
|
52
56
|
{"note_id": "a", "created_at": "2026-09-30T10:00:00", "content": "old"},
|
|
53
|
-
{
|
|
57
|
+
{
|
|
58
|
+
"note_id": "b",
|
|
59
|
+
"created_at": "2026-10-05T10:00:00",
|
|
60
|
+
"content": "new",
|
|
61
|
+
"replies": [{}],
|
|
62
|
+
},
|
|
54
63
|
]
|
|
55
64
|
}
|
|
56
65
|
with mock.patch.object(api_client, "get_json", return_value=raw):
|
|
@@ -62,7 +71,9 @@ class PmReadsTest(unittest.TestCase):
|
|
|
62
71
|
raw = {"packs": [{"product_id": "p1", "pack_label": "v1", "costing": {"make": 50}}]}
|
|
63
72
|
with mock.patch.object(api_client, "get_json", return_value=raw):
|
|
64
73
|
out = api_client.designer_get_costing("st1")
|
|
65
|
-
self.assertEqual(
|
|
74
|
+
self.assertEqual(
|
|
75
|
+
out["packs"], [{"product_id": "p1", "pack": "v1", "costing": {"make": 50}}]
|
|
76
|
+
)
|
|
66
77
|
|
|
67
78
|
|
|
68
79
|
class ExamFixesTest(unittest.TestCase):
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""`designer get supplier-scorecard`: one factory, or every factory the
|
|
2
|
+
brand works with.
|
|
3
|
+
|
|
4
|
+
Run with ``.venv/bin/python -m unittest tests.test_supplier_scorecard``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import unittest
|
|
8
|
+
from unittest import mock
|
|
9
|
+
|
|
10
|
+
from makea_cli import api_client, registry
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SupplierScorecardTest(unittest.TestCase):
|
|
14
|
+
def test_one_factory(self):
|
|
15
|
+
card = {"supplier_id": "s1", "on_time": {"text": "3 of 4 on time", "n": 4}}
|
|
16
|
+
with mock.patch.object(
|
|
17
|
+
api_client, "get_json", return_value={"success": True, "scorecard": card}
|
|
18
|
+
) as get:
|
|
19
|
+
out = api_client.designer_get_supplier_scorecard("s1")
|
|
20
|
+
get.assert_called_once_with("/designer/suppliers/s1/scorecard")
|
|
21
|
+
self.assertEqual(out, card)
|
|
22
|
+
|
|
23
|
+
def test_every_factory(self):
|
|
24
|
+
with mock.patch.object(
|
|
25
|
+
api_client,
|
|
26
|
+
"get_json",
|
|
27
|
+
return_value={"success": True, "scorecards": [{"supplier_id": "s1"}]},
|
|
28
|
+
) as get:
|
|
29
|
+
out = api_client.designer_get_supplier_scorecard()
|
|
30
|
+
get.assert_called_once_with("/designer/suppliers/scorecards")
|
|
31
|
+
self.assertEqual(out, {"scorecards": [{"supplier_id": "s1"}]})
|
|
32
|
+
|
|
33
|
+
def test_it_is_an_automatic_read(self):
|
|
34
|
+
from makea_cli import __version__
|
|
35
|
+
from makea_cli.main import build_cli
|
|
36
|
+
|
|
37
|
+
build_cli()
|
|
38
|
+
entry = next(
|
|
39
|
+
c
|
|
40
|
+
for c in registry.manifest(__version__)["commands"]
|
|
41
|
+
if c["name"] == "designer get supplier-scorecard"
|
|
42
|
+
)
|
|
43
|
+
self.assertEqual(entry["access"], "read")
|
|
44
|
+
self.assertEqual(entry["approval"], "auto")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
unittest.main()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.12"
|
|
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
|