shopping-cli 3.2.4__tar.gz → 3.2.6__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.
- {shopping_cli-3.2.4/shopping_cli.egg-info → shopping_cli-3.2.6}/PKG-INFO +1 -1
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/pyproject.toml +1 -1
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/__init__.py +1 -1
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/merchant_agent.py +23 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/fastapi_routes.py +82 -0
- shopping_cli-3.2.6/shopping_cli/api/handlers/catalog.py +902 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/listings_projection.py +8 -1
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/route_registry.py +6 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/route_table.py +85 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli.py +93 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_catalog_commands.py +139 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/commerce/adapters.py +19 -6
- shopping_cli-3.2.6/shopping_cli/contracts/kiwi-contracts.lock.json +7 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/catalog.py +354 -3
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/catalog_views.py +4 -0
- shopping_cli-3.2.6/shopping_cli/core/money_authority.py +433 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/data_sources/adapter.py +3 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/data_sources/erp_source.py +9 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/db/migrations.py +231 -1
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/db/models.py +28 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/listings/projection.py +22 -1
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation.py +6 -3
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_gates.py +5 -3
- {shopping_cli-3.2.4 → shopping_cli-3.2.6/shopping_cli.egg-info}/PKG-INFO +1 -1
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli.egg-info/SOURCES.txt +1 -0
- shopping_cli-3.2.4/shopping_cli/api/handlers/catalog.py +0 -432
- shopping_cli-3.2.4/shopping_cli/contracts/kiwi-contracts.lock.json +0 -7
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/LICENSE +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/MANIFEST.in +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/README.md +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/setup.cfg +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/__init__.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/agent_cli.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/buyer_cli.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/merchant_daemon.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/merchant_state_helpers.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/tools.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/__init__.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/app.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/auth.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/error_handlers.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/error_response.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/fallback_asgi.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/__init__.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/agents.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/audit.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/buyer.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/common.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/conversations.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/erp.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/human_review.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/negotiation.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/idempotency.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/limits.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/request_dispatch.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/request_limits.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/route_matching.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/routes_agents.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/routes_conversations.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/routes_marketplace.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/routes_merchants.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/server.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_adapter_commands.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_agent_commands.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_buyer_commands.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_common.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_conversation_commands.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_erp_commands.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_listing_commands.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/commerce/__init__.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/commerce/data_source.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/config.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/contracts/shopping.negotiation/0.1/capabilities.schema.json +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/contracts/shopping.negotiation/0.1/decision.schema.json +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/contracts/shopping.negotiation/0.1/policy-result.schema.json +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/contracts/shopping.negotiation/0.1/snapshot.schema.json +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/__init__.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/catalog_scoring.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/catalog_text.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/channels.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/conversations.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/delivery.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/errors.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/harness.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/limits.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/negotiation.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/negotiation_contracts.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/policies.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/risk.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/tokens.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/data_sources/__init__.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/data_sources/csv_excel_source.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/db/__init__.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/db/provenance.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/db/session.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/http_client.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/listings/__init__.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/__init__.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/agents.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/audit.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/buyer_bootstrap.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/conversations.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/human_review.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_message.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_policy_helpers.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_policy_result.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_snapshot.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_snapshot_projection.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/tokens.py +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli.egg-info/dependency_links.txt +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli.egg-info/entry_points.txt +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli.egg-info/requires.txt +0 -0
- {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli.egg-info/top_level.txt +0 -0
|
@@ -115,6 +115,29 @@ def _authorized_bargain_amount(product: dict[str, Any]) -> str:
|
|
|
115
115
|
return ""
|
|
116
116
|
|
|
117
117
|
|
|
118
|
+
def _effective_floor_price(product: dict[str, Any]) -> float | None:
|
|
119
|
+
"""解析商家授权的最低成交价(v26 结构化优先)。
|
|
120
|
+
|
|
121
|
+
优先级:``product.floor_price > 0`` → 用它;否则
|
|
122
|
+
``0 < max_discount_percent <= 100`` → ``price * (1 - discount/100)``;
|
|
123
|
+
否则回退 ``_authorized_bargain_amount`` 自由文本正则(存量
|
|
124
|
+
``automation_boundaries`` 兼容)。全无 → None(无授权底价)。
|
|
125
|
+
"""
|
|
126
|
+
floor = _safe_non_negative_float(product.get("floor_price"))
|
|
127
|
+
if floor > 0:
|
|
128
|
+
return floor
|
|
129
|
+
discount = _safe_non_negative_float(product.get("max_discount_percent"))
|
|
130
|
+
if 0 < discount <= 100:
|
|
131
|
+
return _safe_non_negative_float(product.get("price")) * (1 - discount / 100)
|
|
132
|
+
free_text = _authorized_bargain_amount(product)
|
|
133
|
+
if free_text:
|
|
134
|
+
try:
|
|
135
|
+
return float(free_text)
|
|
136
|
+
except (TypeError, ValueError):
|
|
137
|
+
return None
|
|
138
|
+
return None
|
|
139
|
+
|
|
140
|
+
|
|
118
141
|
def generate_reply(
|
|
119
142
|
tools: MerchantAgentTools,
|
|
120
143
|
conversation: dict[str, Any],
|
|
@@ -34,6 +34,7 @@ from shopping_cli.api.route_table import (
|
|
|
34
34
|
_create_human_review,
|
|
35
35
|
_create_merchant,
|
|
36
36
|
_create_product,
|
|
37
|
+
_create_product_exact,
|
|
37
38
|
_fail_agent_message,
|
|
38
39
|
_get_agent,
|
|
39
40
|
_get_conversation,
|
|
@@ -42,6 +43,8 @@ from shopping_cli.api.route_table import (
|
|
|
42
43
|
_get_merchant,
|
|
43
44
|
_get_merchant_private_config,
|
|
44
45
|
_get_product,
|
|
46
|
+
_get_product_exact,
|
|
47
|
+
_get_product_operation_exact,
|
|
45
48
|
_health,
|
|
46
49
|
_human_review_queue,
|
|
47
50
|
_ingest_channel_message,
|
|
@@ -49,6 +52,7 @@ from shopping_cli.api.route_table import (
|
|
|
49
52
|
_list_agents,
|
|
50
53
|
_list_listing_projections,
|
|
51
54
|
_list_merchants,
|
|
55
|
+
_list_products_exact,
|
|
52
56
|
_merchant_conversations,
|
|
53
57
|
_negotiation_abandon_claim,
|
|
54
58
|
_negotiation_abandon_stale_claims,
|
|
@@ -72,6 +76,9 @@ from shopping_cli.api.route_table import (
|
|
|
72
76
|
_sync_erp,
|
|
73
77
|
_update_merchant,
|
|
74
78
|
_update_product,
|
|
79
|
+
_update_product_inventory_exact,
|
|
80
|
+
_update_product_listing_exact,
|
|
81
|
+
_update_product_money_exact,
|
|
75
82
|
)
|
|
76
83
|
|
|
77
84
|
try: # pragma: no cover - exercised when optional dependency is installed
|
|
@@ -225,6 +232,81 @@ def register_fastapi_routes(app: Any, db_path: str | Path) -> None:
|
|
|
225
232
|
) -> dict[str, Any]:
|
|
226
233
|
return _update_product(db_path, sku, api_auth.payload_with_auth(payload, authorization))
|
|
227
234
|
|
|
235
|
+
@app.get("/v1/merchant/products/exact")
|
|
236
|
+
def list_products_exact(
|
|
237
|
+
merchant_id: str,
|
|
238
|
+
limit: int = 50,
|
|
239
|
+
offset: int = 0,
|
|
240
|
+
authorization: str = AUTHORIZATION_HEADER,
|
|
241
|
+
) -> dict[str, Any]:
|
|
242
|
+
return _list_products_exact(
|
|
243
|
+
db_path,
|
|
244
|
+
{"merchant_id": merchant_id, "limit": limit, "offset": offset},
|
|
245
|
+
api_auth.payload_with_auth({}, authorization),
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
@app.post("/v1/merchant/products/exact")
|
|
249
|
+
def create_product_exact(
|
|
250
|
+
payload: dict[str, Any], authorization: str = AUTHORIZATION_HEADER
|
|
251
|
+
) -> dict[str, Any]:
|
|
252
|
+
return _create_product_exact(
|
|
253
|
+
db_path, api_auth.payload_with_auth(payload, authorization)
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
@app.get("/v1/merchant/products/{sku}/exact")
|
|
257
|
+
def get_product_exact(
|
|
258
|
+
sku: str,
|
|
259
|
+
merchant_id: str,
|
|
260
|
+
authorization: str = AUTHORIZATION_HEADER,
|
|
261
|
+
) -> dict[str, Any]:
|
|
262
|
+
return _get_product_exact(
|
|
263
|
+
db_path,
|
|
264
|
+
sku,
|
|
265
|
+
api_auth.payload_with_auth({"merchant_id": merchant_id}, authorization),
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
@app.patch("/v1/merchant/products/{sku}/money")
|
|
269
|
+
def update_product_money_exact(
|
|
270
|
+
sku: str,
|
|
271
|
+
payload: dict[str, Any],
|
|
272
|
+
authorization: str = AUTHORIZATION_HEADER,
|
|
273
|
+
) -> dict[str, Any]:
|
|
274
|
+
return _update_product_money_exact(
|
|
275
|
+
db_path, sku, api_auth.payload_with_auth(payload, authorization)
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
@app.patch("/v1/merchant/products/{sku}/inventory")
|
|
279
|
+
def update_product_inventory_exact(
|
|
280
|
+
sku: str,
|
|
281
|
+
payload: dict[str, Any],
|
|
282
|
+
authorization: str = AUTHORIZATION_HEADER,
|
|
283
|
+
) -> dict[str, Any]:
|
|
284
|
+
return _update_product_inventory_exact(
|
|
285
|
+
db_path, sku, api_auth.payload_with_auth(payload, authorization)
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
@app.patch("/v1/merchant/products/{sku}/listing")
|
|
289
|
+
def update_product_listing_exact(
|
|
290
|
+
sku: str,
|
|
291
|
+
payload: dict[str, Any],
|
|
292
|
+
authorization: str = AUTHORIZATION_HEADER,
|
|
293
|
+
) -> dict[str, Any]:
|
|
294
|
+
return _update_product_listing_exact(
|
|
295
|
+
db_path, sku, api_auth.payload_with_auth(payload, authorization)
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
@app.get("/v1/merchant/product-operations/{operation_id}")
|
|
299
|
+
def get_product_operation_exact(
|
|
300
|
+
operation_id: str,
|
|
301
|
+
merchant_id: str,
|
|
302
|
+
authorization: str = AUTHORIZATION_HEADER,
|
|
303
|
+
) -> dict[str, Any]:
|
|
304
|
+
return _get_product_operation_exact(
|
|
305
|
+
db_path,
|
|
306
|
+
operation_id,
|
|
307
|
+
api_auth.payload_with_auth({"merchant_id": merchant_id}, authorization),
|
|
308
|
+
)
|
|
309
|
+
|
|
228
310
|
@app.get("/v1/merchant/listings/projections")
|
|
229
311
|
def merchant_listing_projections(
|
|
230
312
|
merchant_id: str = "",
|