lambda-erp 1.1.5__tar.gz → 1.1.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 (114) hide show
  1. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/PKG-INFO +1 -1
  2. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/chat.py +9 -0
  3. lambda_erp-1.1.6/api/erp_context.py +61 -0
  4. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/mcp.py +2 -0
  5. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/tool_permissions.py +1 -1
  6. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/pyproject.toml +1 -1
  7. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/.gitignore +0 -0
  8. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/LICENSE +0 -0
  9. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/README.md +0 -0
  10. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/__init__.py +0 -0
  11. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/attachments.py +0 -0
  12. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/auth.py +0 -0
  13. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/bootstrap.py +0 -0
  14. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/chat_links.py +0 -0
  15. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/demo_limits.py +0 -0
  16. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/deps.py +0 -0
  17. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/errors.py +0 -0
  18. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/list_values.py +0 -0
  19. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/main.py +0 -0
  20. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/mcp_oauth.py +0 -0
  21. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/oauth.py +0 -0
  22. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/pdf.py +0 -0
  23. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/pdf_contract.py +0 -0
  24. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/pdf_exports.py +0 -0
  25. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/pdf_profiles.py +0 -0
  26. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/providers.py +0 -0
  27. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/remarks_md.py +0 -0
  28. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/__init__.py +0 -0
  29. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/accounting.py +0 -0
  30. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/actions.py +0 -0
  31. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/admin.py +0 -0
  32. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/analytics.py +0 -0
  33. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/availability.py +0 -0
  34. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/bank_reconciliation.py +0 -0
  35. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/bank_statements.py +0 -0
  36. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/chat_api.py +0 -0
  37. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/documents.py +0 -0
  38. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/masters.py +0 -0
  39. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/proposals.py +0 -0
  40. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/reports.py +0 -0
  41. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/routers/setup.py +0 -0
  42. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/services.py +0 -0
  43. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/templates/_proposal_totals.html +0 -0
  44. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/templates/_record_base.html +0 -0
  45. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/templates/document.html +0 -0
  46. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/templates/proposal.html +0 -0
  47. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/templates/record.html +0 -0
  48. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/api/time_filters.py +0 -0
  49. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/docs/agents/README.md +0 -0
  50. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/frontend/LICENSE +0 -0
  51. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/frontend/README.md +0 -0
  52. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/frontend/src/api/client.ts +0 -0
  53. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/__init__.py +0 -0
  54. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/__init__.py +0 -0
  55. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/bank_account.py +0 -0
  56. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/bank_reconciliation.py +0 -0
  57. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/bank_statement_import.py +0 -0
  58. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/bank_transaction.py +0 -0
  59. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/budget.py +0 -0
  60. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/camt.py +0 -0
  61. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/chart_of_accounts.py +0 -0
  62. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/general_ledger.py +0 -0
  63. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/journal_entry.py +0 -0
  64. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/payment_entry.py +0 -0
  65. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/pos_invoice.py +0 -0
  66. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/purchase_invoice.py +0 -0
  67. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/revaluation.py +0 -0
  68. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/sales_invoice.py +0 -0
  69. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/settlement.py +0 -0
  70. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/__init__.py +0 -0
  71. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/engine.py +0 -0
  72. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/pack.py +0 -0
  73. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/__init__.py +0 -0
  74. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/ch.py +0 -0
  75. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/de_common.py +0 -0
  76. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/de_skr03.py +0 -0
  77. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/de_skr04.py +0 -0
  78. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/generic.py +0 -0
  79. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/profiles.py +0 -0
  80. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/spine.py +0 -0
  81. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/accounting/subscription.py +0 -0
  82. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/assets/__init__.py +0 -0
  83. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/assets/asset.py +0 -0
  84. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/assets/lifecycle.py +0 -0
  85. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/assets/reservation.py +0 -0
  86. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/buying/__init__.py +0 -0
  87. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/buying/purchase_order.py +0 -0
  88. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/controllers/__init__.py +0 -0
  89. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/controllers/currency.py +0 -0
  90. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/controllers/defaults.py +0 -0
  91. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/controllers/item_price.py +0 -0
  92. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/controllers/item_prices.py +0 -0
  93. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/controllers/pricing_rule.py +0 -0
  94. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/controllers/taxes_and_totals.py +0 -0
  95. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/database.py +0 -0
  96. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/exceptions.py +0 -0
  97. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/hooks.py +0 -0
  98. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/master_integrity.py +0 -0
  99. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/model.py +0 -0
  100. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/selling/__init__.py +0 -0
  101. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/selling/proposal.py +0 -0
  102. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/selling/quotation.py +0 -0
  103. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/selling/sales_order.py +0 -0
  104. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/simulation.py +0 -0
  105. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/stock/__init__.py +0 -0
  106. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/stock/delivery_note.py +0 -0
  107. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/stock/purchase_receipt.py +0 -0
  108. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/stock/stock_entry.py +0 -0
  109. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/stock/stock_ledger.py +0 -0
  110. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/timestamps.py +0 -0
  111. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/utils.py +0 -0
  112. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/validation.py +0 -0
  113. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/lambda_erp/workflow.py +0 -0
  114. {lambda_erp-1.1.5 → lambda_erp-1.1.6}/terraform/README.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: lambda-erp
3
- Version: 1.1.5
3
+ Version: 1.1.6
4
4
  Summary: Core ERP logic - accounting, sales, purchasing, inventory
5
5
  Author: TORUS INVESTMENTS AG
6
6
  License-Expression: Apache-2.0
@@ -28,6 +28,7 @@ from openai import OpenAI
28
28
 
29
29
  from api.time_filters import TIME_FILTER_SCHEMA, time_filter_fields
30
30
  from api import services
31
+ from api.erp_context import WORKFLOW_GUIDANCE, get_erp_context
31
32
  from api.chat_links import with_record_view_urls
32
33
  from api.tool_permissions import tool_allowed, tool_permission_error
33
34
  from api.demo_limits import (
@@ -473,6 +474,11 @@ DOCUMENT_SLUGS = [
473
474
  MASTER_TYPES = ["customer", "supplier", "item", "warehouse", "account", "company", "cost-center"]
474
475
 
475
476
  TOOLS = [
477
+ {"type": "function", "function": {
478
+ "name": "get_erp_context",
479
+ "description": "Discover this ERP's live document/master types, relationships, PDF capabilities and workflow guidance. Read this before using an unfamiliar ERP. No LLM is invoked. Use field tools for detailed schemas and tools/list for permitted operations.",
480
+ "parameters": {"type": "object", "properties": {}, "additionalProperties": False},
481
+ }},
476
482
  {
477
483
  "type": "function",
478
484
  "function": {
@@ -2244,6 +2250,7 @@ def _handle_apply_company_setup(args):
2244
2250
 
2245
2251
 
2246
2252
  TOOL_HANDLERS = {
2253
+ "get_erp_context": get_erp_context,
2247
2254
  "list_documents": _handle_list_documents,
2248
2255
  "get_document_fields": _handle_get_document_fields,
2249
2256
  "generate_document_pdf": _handle_generate_document_pdf,
@@ -2478,6 +2485,8 @@ If `jurisdiction.is_fallback` is true, tell the user their country isn't localiz
2478
2485
 
2479
2486
  return f"""You are an ERP assistant for Lambda ERP. Today's date is {date.today().isoformat()}.
2480
2487
 
2488
+ {WORKFLOW_GUIDANCE}
2489
+
2481
2490
  You help users manage their business by creating documents, looking up data, and running reports — all through natural conversation.
2482
2491
 
2483
2492
  ## Enforced document requirements (generated from backend rule metadata)
@@ -0,0 +1,61 @@
1
+ """Shared, deterministic guidance for the native chat and direct ERP clients."""
2
+
3
+ from api import services
4
+ from api.pdf_profiles import pdf_metadata
5
+
6
+
7
+ WORKFLOW_GUIDANCE = """Discover record types and inspect get_document_fields/get_master_fields before
8
+ writes; use their canonical field names, required fields, link targets and PDF requirements.
9
+ Resolve existing records by their returned name; never invent identifiers or silently choose
10
+ between ambiguous matches. Custom document records use document tools, not master tools.
11
+ Create/update, submit, cancel and convert are separate business operations. A successful
12
+ draft creation does not imply submission, stock movement or ledger posting. Check returned
13
+ status and warnings. Correct validation errors using the field metadata and user information.
14
+ Use list/search filters and pagination; an empty or partial search is not proof of zero
15
+ stock. Use query_dataset/get_report for totals and stock, with the requested scope and dates.
16
+ Generate a fresh PDF after edits. Only a successful artifact descriptor proves generation;
17
+ download that artifact, check its SHA-256 and deliver it through the calling application's
18
+ attachment mechanism. Do not invent download URLs or reuse a stale document attachment.
19
+ After a write timeout the outcome is unknown: inspect the affected records before retrying.
20
+ Do not automatically replay the operation through another tool or the chat API.
21
+ """
22
+
23
+
24
+ def get_erp_context(args=None):
25
+ """No LLM, secrets, session state or business-record snapshots are involved."""
26
+ documents = []
27
+ for slug, doctype in sorted(services.SLUG_TO_DOCTYPE.items()):
28
+ cls = services.DOCUMENT_CLASSES.get(doctype)
29
+ meta = services.CHAT_DOCTYPES.get(slug, {})
30
+ documents.append({
31
+ "type": slug, "doctype": doctype,
32
+ "description": meta.get("description", doctype),
33
+ "key_fields": meta.get("fields", []),
34
+ "links": getattr(cls, "LINK_FIELDS", None) or {},
35
+ "pdf": {k: v for k, v in pdf_metadata(doctype).items()
36
+ if k in {"supported", "reason", "kind", "required_fields", "required_any"}},
37
+ "describe_tool": "get_document_fields",
38
+ })
39
+ masters = []
40
+ for slug, (doctype, display_field) in sorted(services.MASTER_TABLES.items()):
41
+ meta = services.MASTER_METADATA.get(slug, {})
42
+ masters.append({
43
+ "type": slug, "doctype": doctype, "key_field": "name",
44
+ "display_field": display_field,
45
+ "description": meta.get("description", doctype),
46
+ "key_fields": meta.get("fields", []),
47
+ "describe_tool": "get_master_fields",
48
+ })
49
+ return {
50
+ "contract_version": 1,
51
+ "instructions": WORKFLOW_GUIDANCE,
52
+ "documents": documents,
53
+ "masters": masters,
54
+ "capability_source": "tools/list is the caller's permitted operation catalogue; never infer write permission from this type list.",
55
+ "limitations": [
56
+ "Native ERP chat history and attachments are not the calling application's history or attachments.",
57
+ "File-ID operations require files uploaded to this ERP; external application attachment IDs cannot be substituted.",
58
+ "Chat-based custom analytics generation and guided company setup are not exposed through MCP. Use an explicit chat fallback if enabled.",
59
+ "Registered extension actions may call external services or models; inspect each action's description.",
60
+ ],
61
+ }
@@ -49,6 +49,7 @@ _EXCLUDE = {
49
49
  }
50
50
 
51
51
  _READ_ONLY = {
52
+ 'get_erp_context',
52
53
  'list_documents', 'get_document_fields', 'get_document', 'get_master_fields',
53
54
  'search_masters', 'get_report', 'get_current_time', 'query_dataset',
54
55
  'preview_bank_statement_attachments', 'list_bank_reconciliation_queue',
@@ -167,6 +168,7 @@ def _handle(msg: dict, user: dict):
167
168
  else PROTOCOL_VERSION),
168
169
  "capabilities": {"tools": {"listChanged": False}},
169
170
  "serverInfo": {"name": "lambda-erp", "version": get_app_version()},
171
+ "instructions": "Call get_erp_context for live record types and workflow guidance, then inspect field schemas before writes. tools/list reflects your permissions. No ERP chat is invoked by the standard business tools.",
170
172
  })
171
173
  if method in ("notifications/initialized", "notifications/cancelled"):
172
174
  return None
@@ -15,7 +15,7 @@ _ADMINS = frozenset({"admin"})
15
15
 
16
16
  TOOL_ROLES = {
17
17
  **dict.fromkeys((
18
- "list_documents", "get_document_fields", "get_document", "generate_document_pdf",
18
+ "get_erp_context", "list_documents", "get_document_fields", "get_document", "generate_document_pdf",
19
19
  "get_master_fields", "search_masters", "get_report", "get_current_time",
20
20
  "retrieve_chat_history", "list_chat_attachments", "retrieve_chat_attachment",
21
21
  "preview_bank_statement_attachments", "query_dataset",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lambda-erp"
3
- version = "1.1.5"
3
+ version = "1.1.6"
4
4
  description = "Core ERP logic - accounting, sales, purchasing, inventory"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
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