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.
Files changed (113) hide show
  1. {shopping_cli-3.2.4/shopping_cli.egg-info → shopping_cli-3.2.6}/PKG-INFO +1 -1
  2. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/pyproject.toml +1 -1
  3. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/__init__.py +1 -1
  4. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/merchant_agent.py +23 -0
  5. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/fastapi_routes.py +82 -0
  6. shopping_cli-3.2.6/shopping_cli/api/handlers/catalog.py +902 -0
  7. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/listings_projection.py +8 -1
  8. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/route_registry.py +6 -0
  9. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/route_table.py +85 -0
  10. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli.py +93 -0
  11. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_catalog_commands.py +139 -0
  12. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/commerce/adapters.py +19 -6
  13. shopping_cli-3.2.6/shopping_cli/contracts/kiwi-contracts.lock.json +7 -0
  14. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/catalog.py +354 -3
  15. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/catalog_views.py +4 -0
  16. shopping_cli-3.2.6/shopping_cli/core/money_authority.py +433 -0
  17. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/data_sources/adapter.py +3 -0
  18. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/data_sources/erp_source.py +9 -0
  19. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/db/migrations.py +231 -1
  20. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/db/models.py +28 -0
  21. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/listings/projection.py +22 -1
  22. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation.py +6 -3
  23. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_gates.py +5 -3
  24. {shopping_cli-3.2.4 → shopping_cli-3.2.6/shopping_cli.egg-info}/PKG-INFO +1 -1
  25. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli.egg-info/SOURCES.txt +1 -0
  26. shopping_cli-3.2.4/shopping_cli/api/handlers/catalog.py +0 -432
  27. shopping_cli-3.2.4/shopping_cli/contracts/kiwi-contracts.lock.json +0 -7
  28. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/LICENSE +0 -0
  29. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/MANIFEST.in +0 -0
  30. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/README.md +0 -0
  31. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/setup.cfg +0 -0
  32. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/__init__.py +0 -0
  33. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/agent_cli.py +0 -0
  34. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/buyer_cli.py +0 -0
  35. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/merchant_daemon.py +0 -0
  36. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/merchant_state_helpers.py +0 -0
  37. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/agents/tools.py +0 -0
  38. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/__init__.py +0 -0
  39. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/app.py +0 -0
  40. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/auth.py +0 -0
  41. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/error_handlers.py +0 -0
  42. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/error_response.py +0 -0
  43. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/fallback_asgi.py +0 -0
  44. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/__init__.py +0 -0
  45. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/agents.py +0 -0
  46. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/audit.py +0 -0
  47. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/buyer.py +0 -0
  48. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/common.py +0 -0
  49. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/conversations.py +0 -0
  50. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/erp.py +0 -0
  51. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/human_review.py +0 -0
  52. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/handlers/negotiation.py +0 -0
  53. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/idempotency.py +0 -0
  54. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/limits.py +0 -0
  55. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/request_dispatch.py +0 -0
  56. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/request_limits.py +0 -0
  57. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/route_matching.py +0 -0
  58. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/routes_agents.py +0 -0
  59. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/routes_conversations.py +0 -0
  60. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/routes_marketplace.py +0 -0
  61. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/routes_merchants.py +0 -0
  62. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/api/server.py +0 -0
  63. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_adapter_commands.py +0 -0
  64. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_agent_commands.py +0 -0
  65. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_buyer_commands.py +0 -0
  66. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_common.py +0 -0
  67. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_conversation_commands.py +0 -0
  68. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_erp_commands.py +0 -0
  69. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/cli_listing_commands.py +0 -0
  70. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/commerce/__init__.py +0 -0
  71. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/commerce/data_source.py +0 -0
  72. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/config.py +0 -0
  73. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/contracts/shopping.negotiation/0.1/capabilities.schema.json +0 -0
  74. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/contracts/shopping.negotiation/0.1/decision.schema.json +0 -0
  75. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/contracts/shopping.negotiation/0.1/policy-result.schema.json +0 -0
  76. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/contracts/shopping.negotiation/0.1/snapshot.schema.json +0 -0
  77. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/__init__.py +0 -0
  78. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/catalog_scoring.py +0 -0
  79. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/catalog_text.py +0 -0
  80. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/channels.py +0 -0
  81. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/conversations.py +0 -0
  82. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/delivery.py +0 -0
  83. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/errors.py +0 -0
  84. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/harness.py +0 -0
  85. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/limits.py +0 -0
  86. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/negotiation.py +0 -0
  87. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/negotiation_contracts.py +0 -0
  88. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/policies.py +0 -0
  89. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/risk.py +0 -0
  90. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/core/tokens.py +0 -0
  91. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/data_sources/__init__.py +0 -0
  92. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/data_sources/csv_excel_source.py +0 -0
  93. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/db/__init__.py +0 -0
  94. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/db/provenance.py +0 -0
  95. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/db/session.py +0 -0
  96. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/http_client.py +0 -0
  97. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/listings/__init__.py +0 -0
  98. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/__init__.py +0 -0
  99. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/agents.py +0 -0
  100. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/audit.py +0 -0
  101. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/buyer_bootstrap.py +0 -0
  102. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/conversations.py +0 -0
  103. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/human_review.py +0 -0
  104. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_message.py +0 -0
  105. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_policy_helpers.py +0 -0
  106. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_policy_result.py +0 -0
  107. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_snapshot.py +0 -0
  108. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/negotiation_snapshot_projection.py +0 -0
  109. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli/services/tokens.py +0 -0
  110. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli.egg-info/dependency_links.txt +0 -0
  111. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli.egg-info/entry_points.txt +0 -0
  112. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli.egg-info/requires.txt +0 -0
  113. {shopping_cli-3.2.4 → shopping_cli-3.2.6}/shopping_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shopping-cli
3
- Version: 3.2.4
3
+ Version: 3.2.6
4
4
  Summary: Standalone local-commerce AI consultation marketplace runtime
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "shopping-cli"
7
- version = "3.2.4"
7
+ version = "3.2.6"
8
8
  description = "Standalone local-commerce AI consultation marketplace runtime"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,3 +1,3 @@
1
1
  """Standalone shopping-cli consultation runtime."""
2
2
 
3
- VERSION = "3.2.4"
3
+ VERSION = "3.2.6"
@@ -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 = "",