lambda-erp 1.1.4__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.
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/PKG-INFO +1 -1
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/chat.py +9 -0
- lambda_erp-1.1.6/api/erp_context.py +61 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/mcp.py +2 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/tool_permissions.py +1 -1
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/pyproject.toml +1 -1
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/.gitignore +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/LICENSE +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/README.md +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/__init__.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/attachments.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/auth.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/bootstrap.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/chat_links.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/demo_limits.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/deps.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/errors.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/list_values.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/main.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/mcp_oauth.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/oauth.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/pdf.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/pdf_contract.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/pdf_exports.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/pdf_profiles.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/providers.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/remarks_md.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/__init__.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/accounting.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/actions.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/admin.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/analytics.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/availability.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/bank_reconciliation.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/bank_statements.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/chat_api.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/documents.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/masters.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/proposals.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/reports.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/routers/setup.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/services.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/templates/_proposal_totals.html +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/templates/_record_base.html +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/templates/document.html +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/templates/proposal.html +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/templates/record.html +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/api/time_filters.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/docs/agents/README.md +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/frontend/LICENSE +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/frontend/README.md +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/frontend/src/api/client.ts +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/__init__.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/__init__.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/bank_account.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/bank_reconciliation.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/bank_statement_import.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/bank_transaction.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/budget.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/camt.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/chart_of_accounts.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/general_ledger.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/journal_entry.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/payment_entry.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/pos_invoice.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/purchase_invoice.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/revaluation.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/sales_invoice.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/settlement.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/__init__.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/engine.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/pack.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/__init__.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/ch.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/de_common.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/de_skr03.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/de_skr04.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/packs/generic.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/profiles.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/setup/spine.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/accounting/subscription.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/assets/__init__.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/assets/asset.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/assets/lifecycle.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/assets/reservation.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/buying/__init__.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/buying/purchase_order.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/controllers/__init__.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/controllers/currency.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/controllers/defaults.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/controllers/item_price.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/controllers/item_prices.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/controllers/pricing_rule.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/controllers/taxes_and_totals.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/database.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/exceptions.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/hooks.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/master_integrity.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/model.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/selling/__init__.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/selling/proposal.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/selling/quotation.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/selling/sales_order.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/simulation.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/stock/__init__.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/stock/delivery_note.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/stock/purchase_receipt.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/stock/stock_entry.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/stock/stock_ledger.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/timestamps.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/utils.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/validation.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/lambda_erp/workflow.py +0 -0
- {lambda_erp-1.1.4 → lambda_erp-1.1.6}/terraform/README.md +0 -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",
|
|
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
|
|
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
|