lambda-erp 0.8.2__tar.gz → 0.8.3__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 (88) hide show
  1. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/PKG-INFO +1 -1
  2. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/services.py +49 -0
  3. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/setup/packs/ch.py +9 -0
  4. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/database.py +12 -0
  5. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/pyproject.toml +1 -1
  6. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/.gitignore +0 -0
  7. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/LICENSE +0 -0
  8. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/README.md +0 -0
  9. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/__init__.py +0 -0
  10. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/attachments.py +0 -0
  11. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/auth.py +0 -0
  12. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/bootstrap.py +0 -0
  13. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/chat.py +0 -0
  14. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/demo_limits.py +0 -0
  15. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/deps.py +0 -0
  16. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/errors.py +0 -0
  17. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/main.py +0 -0
  18. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/oauth.py +0 -0
  19. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/pdf.py +0 -0
  20. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/providers.py +0 -0
  21. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/remarks_md.py +0 -0
  22. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/__init__.py +0 -0
  23. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/accounting.py +0 -0
  24. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/admin.py +0 -0
  25. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/analytics.py +0 -0
  26. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/availability.py +0 -0
  27. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/bank_reconciliation.py +0 -0
  28. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/chat_api.py +0 -0
  29. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/documents.py +0 -0
  30. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/masters.py +0 -0
  31. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/mcp.py +0 -0
  32. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/proposals.py +0 -0
  33. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/reports.py +0 -0
  34. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/routers/setup.py +0 -0
  35. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/templates/document.html +0 -0
  36. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/api/templates/proposal.html +0 -0
  37. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/docs/agents/README.md +0 -0
  38. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/frontend/LICENSE +0 -0
  39. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/frontend/README.md +0 -0
  40. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/frontend/src/api/client.ts +0 -0
  41. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/__init__.py +0 -0
  42. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/__init__.py +0 -0
  43. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/bank_transaction.py +0 -0
  44. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/budget.py +0 -0
  45. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/chart_of_accounts.py +0 -0
  46. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/general_ledger.py +0 -0
  47. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/journal_entry.py +0 -0
  48. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/payment_entry.py +0 -0
  49. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/pos_invoice.py +0 -0
  50. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/purchase_invoice.py +0 -0
  51. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/revaluation.py +0 -0
  52. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/sales_invoice.py +0 -0
  53. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/setup/__init__.py +0 -0
  54. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/setup/engine.py +0 -0
  55. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/setup/pack.py +0 -0
  56. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/setup/packs/__init__.py +0 -0
  57. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/setup/packs/de_common.py +0 -0
  58. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/setup/packs/de_skr03.py +0 -0
  59. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/setup/packs/de_skr04.py +0 -0
  60. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/setup/packs/generic.py +0 -0
  61. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/setup/profiles.py +0 -0
  62. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/setup/spine.py +0 -0
  63. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/accounting/subscription.py +0 -0
  64. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/assets/__init__.py +0 -0
  65. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/assets/asset.py +0 -0
  66. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/assets/reservation.py +0 -0
  67. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/buying/__init__.py +0 -0
  68. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/buying/purchase_order.py +0 -0
  69. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/controllers/__init__.py +0 -0
  70. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/controllers/currency.py +0 -0
  71. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/controllers/defaults.py +0 -0
  72. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/controllers/pricing_rule.py +0 -0
  73. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/controllers/taxes_and_totals.py +0 -0
  74. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/exceptions.py +0 -0
  75. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/hooks.py +0 -0
  76. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/model.py +0 -0
  77. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/selling/__init__.py +0 -0
  78. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/selling/proposal.py +0 -0
  79. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/selling/quotation.py +0 -0
  80. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/selling/sales_order.py +0 -0
  81. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/simulation.py +0 -0
  82. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/stock/__init__.py +0 -0
  83. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/stock/delivery_note.py +0 -0
  84. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/stock/purchase_receipt.py +0 -0
  85. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/stock/stock_entry.py +0 -0
  86. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/stock/stock_ledger.py +0 -0
  87. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/lambda_erp/utils.py +0 -0
  88. {lambda_erp-0.8.2 → lambda_erp-0.8.3}/terraform/README.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: lambda-erp
3
- Version: 0.8.2
3
+ Version: 0.8.3
4
4
  Summary: Core ERP logic - accounting, sales, purchasing, inventory
5
5
  Author: TORUS INVESTMENTS AG
6
6
  License-Expression: Apache-2.0
@@ -284,10 +284,59 @@ def get_document_class(doctype_slug: str):
284
284
  return doctype, DOCUMENT_CLASSES[doctype]
285
285
 
286
286
 
287
+ # Which Company default a doc's `taxes` table draws from — keyed by the taxes
288
+ # child doctype, so any doc that has a taxes table is covered without a hardcoded
289
+ # doctype list. Selling -> sales default, buying -> purchase default.
290
+ _TAX_CHILD_DEFAULT_FIELD = {
291
+ "Sales Taxes and Charges": "default_sales_tax_template",
292
+ "Purchase Taxes and Charges": "default_purchase_tax_template",
293
+ }
294
+
295
+
296
+ def _default_tax_rows(cls, data: dict) -> list | None:
297
+ """`taxes[]` rows to seed a new document from its company's default Tax
298
+ Template, or None to leave taxes untouched.
299
+
300
+ Applied ONLY when the caller omits `taxes` entirely — the exact case the chat
301
+ model kept hitting (it forgets to add MWST). An explicit `taxes: []` is left
302
+ alone, so a deliberately tax-free doc (export, reverse-charge, exempt) is
303
+ expressed by passing an empty list. The document's own tax calc then computes
304
+ `tax_amount` from the rate, so this only seeds charge_type/account/rate.
305
+ """
306
+ taxes_child = cls.CHILD_TABLES.get("taxes")
307
+ if not taxes_child or "taxes" in data:
308
+ return None
309
+ field = _TAX_CHILD_DEFAULT_FIELD.get(taxes_child[0])
310
+ company = data.get("company")
311
+ if not field or not company:
312
+ return None
313
+ db = get_db()
314
+ template = db.get_value("Company", company, field)
315
+ if not template:
316
+ return None
317
+ details = db.get_all("Tax Template Detail", filters={"parent": template},
318
+ fields=["*"], order_by="idx")
319
+ if not details:
320
+ return None
321
+ return [
322
+ {
323
+ "charge_type": d.get("charge_type") or "On Net Total",
324
+ "account_head": d.get("account_head"),
325
+ "rate": d.get("rate") or 0,
326
+ "description": d.get("description") or template,
327
+ "add_deduct_tax": "Add",
328
+ }
329
+ for d in details
330
+ ]
331
+
332
+
287
333
  def create_document(doctype_slug: str, data: dict) -> dict:
288
334
  doctype, cls = get_document_class(doctype_slug)
289
335
  if not cls:
290
336
  raise ValueError(f"Unknown document type: {doctype_slug}")
337
+ default_taxes = _default_tax_rows(cls, data)
338
+ if default_taxes is not None:
339
+ data = {**data, "taxes": default_taxes}
291
340
  doc = cls(data)
292
341
  doc.save()
293
342
  return doc.as_dict()
@@ -238,6 +238,15 @@ def ch_setup_tax(company_name, currency):
238
238
  for title, rate, leaf in _PURCHASE_TAXES:
239
239
  _template(title, "Purchase", rate, leaf)
240
240
 
241
+ # Make the 8.1% standard rate the company's default sales tax, so new
242
+ # invoices/quotations pick up MWST automatically (create_document seeds it
243
+ # when `taxes` is omitted). Purchase Vorsteuer stays manual — it varies by
244
+ # goods vs. investment, so there's no single sensible default.
245
+ default_sales = f"MWST Normalsatz 8.1% - {abbr}"
246
+ if db.exists("Tax Template", default_sales):
247
+ db.set_value("Company", company_name, {"default_sales_tax_template": default_sales})
248
+ summary.append(f"default sales tax: MWST Normalsatz 8.1%")
249
+
241
250
  return summary
242
251
 
243
252
 
@@ -2125,6 +2125,17 @@ def _m021_item_is_asset_tracked(db: "Database") -> None:
2125
2125
  db._add_column_if_missing("Item", "is_asset_tracked", "INTEGER DEFAULT 0")
2126
2126
 
2127
2127
 
2128
+ def _m022_company_default_tax_templates(db: "Database") -> None:
2129
+ """Per-company default sales/purchase Tax Templates. When a selling/buying
2130
+ document is created with NO `taxes` rows at all, create_document applies the
2131
+ matching default so VAT/MWST is not silently omitted (see api/services.py).
2132
+ Both default to NULL, so existing deployments are unaffected until a default
2133
+ is wired — e.g. the CH pack points the sales default at the 8.1% MWST
2134
+ template. Passing an explicit empty `taxes: []` still means a tax-free doc."""
2135
+ db._add_column_if_missing("Company", "default_sales_tax_template", "TEXT")
2136
+ db._add_column_if_missing("Company", "default_purchase_tax_template", "TEXT")
2137
+
2138
+
2128
2139
  Database.MIGRATIONS = [
2129
2140
  (1, "chat_message_session_id", _m001_chat_message_session_id),
2130
2141
  (2, "chat_session_user_id", _m002_chat_session_user_id),
@@ -2147,6 +2158,7 @@ Database.MIGRATIONS = [
2147
2158
  (19, "api_keys_per_user", _m019_api_keys_per_user),
2148
2159
  (20, "chat_attachment_openai_file", _m020_chat_attachment_openai_file),
2149
2160
  (21, "item_is_asset_tracked", _m021_item_is_asset_tracked),
2161
+ (22, "company_default_tax_templates", _m022_company_default_tax_templates),
2150
2162
  ]
2151
2163
 
2152
2164
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lambda-erp"
3
- version = "0.8.2"
3
+ version = "0.8.3"
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