lambda-erp 0.6.23__tar.gz → 0.6.25__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 (84) hide show
  1. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/PKG-INFO +1 -1
  2. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/auth.py +40 -0
  3. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/frontend/src/api/client.ts +5 -0
  4. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/database.py +11 -0
  5. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/pyproject.toml +1 -1
  6. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/.gitignore +0 -0
  7. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/LICENSE +0 -0
  8. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/README.md +0 -0
  9. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/__init__.py +0 -0
  10. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/attachments.py +0 -0
  11. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/bootstrap.py +0 -0
  12. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/chat.py +0 -0
  13. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/demo_limits.py +0 -0
  14. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/deps.py +0 -0
  15. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/errors.py +0 -0
  16. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/main.py +0 -0
  17. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/oauth.py +0 -0
  18. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/pdf.py +0 -0
  19. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/providers.py +0 -0
  20. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/remarks_md.py +0 -0
  21. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/__init__.py +0 -0
  22. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/accounting.py +0 -0
  23. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/admin.py +0 -0
  24. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/analytics.py +0 -0
  25. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/bank_reconciliation.py +0 -0
  26. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/chat_api.py +0 -0
  27. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/documents.py +0 -0
  28. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/masters.py +0 -0
  29. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/mcp.py +0 -0
  30. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/proposals.py +0 -0
  31. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/reports.py +0 -0
  32. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/routers/setup.py +0 -0
  33. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/services.py +0 -0
  34. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/templates/document.html +0 -0
  35. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/api/templates/proposal.html +0 -0
  36. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/docs/agents/README.md +0 -0
  37. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/frontend/LICENSE +0 -0
  38. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/frontend/README.md +0 -0
  39. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/__init__.py +0 -0
  40. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/__init__.py +0 -0
  41. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/bank_transaction.py +0 -0
  42. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/budget.py +0 -0
  43. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/chart_of_accounts.py +0 -0
  44. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/general_ledger.py +0 -0
  45. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/journal_entry.py +0 -0
  46. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/payment_entry.py +0 -0
  47. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/pos_invoice.py +0 -0
  48. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/purchase_invoice.py +0 -0
  49. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/revaluation.py +0 -0
  50. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/sales_invoice.py +0 -0
  51. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/setup/__init__.py +0 -0
  52. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/setup/engine.py +0 -0
  53. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/setup/pack.py +0 -0
  54. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/setup/packs/__init__.py +0 -0
  55. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/setup/packs/ch.py +0 -0
  56. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/setup/packs/de_common.py +0 -0
  57. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/setup/packs/de_skr03.py +0 -0
  58. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/setup/packs/de_skr04.py +0 -0
  59. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/setup/packs/generic.py +0 -0
  60. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/setup/profiles.py +0 -0
  61. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/setup/spine.py +0 -0
  62. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/accounting/subscription.py +0 -0
  63. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/buying/__init__.py +0 -0
  64. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/buying/purchase_order.py +0 -0
  65. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/controllers/__init__.py +0 -0
  66. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/controllers/currency.py +0 -0
  67. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/controllers/defaults.py +0 -0
  68. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/controllers/pricing_rule.py +0 -0
  69. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/controllers/taxes_and_totals.py +0 -0
  70. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/exceptions.py +0 -0
  71. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/hooks.py +0 -0
  72. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/model.py +0 -0
  73. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/selling/__init__.py +0 -0
  74. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/selling/proposal.py +0 -0
  75. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/selling/quotation.py +0 -0
  76. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/selling/sales_order.py +0 -0
  77. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/simulation.py +0 -0
  78. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/stock/__init__.py +0 -0
  79. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/stock/delivery_note.py +0 -0
  80. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/stock/purchase_receipt.py +0 -0
  81. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/stock/stock_entry.py +0 -0
  82. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/stock/stock_ledger.py +0 -0
  83. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/lambda_erp/utils.py +0 -0
  84. {lambda_erp-0.6.23 → lambda_erp-0.6.25}/terraform/README.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lambda-erp
3
- Version: 0.6.23
3
+ Version: 0.6.25
4
4
  Summary: Core ERP logic - accounting, sales, purchasing, inventory
5
5
  Author: TORUS INVESTMENTS AG
6
6
  License-Expression: Apache-2.0
@@ -720,6 +720,46 @@ def update_settings(data: dict, user: dict = Depends(require_admin)):
720
720
  return settings
721
721
 
722
722
 
723
+ @router.get("/my-settings")
724
+ def get_my_settings(user: dict = Depends(get_current_user)):
725
+ """The CURRENT user's personal preferences as a {key: value} bag.
726
+
727
+ Distinct from the global, admin-only /settings above: this is scoped to the
728
+ caller and any authenticated user may read (and, via PUT, write) their OWN
729
+ row. Consumers so far: `columns.<doctype>` (personal list columns) and
730
+ `language`. Returns {} for a user who has set nothing.
731
+ """
732
+ db = get_db()
733
+ rows = db.sql('SELECT key, value FROM "User Preference" WHERE user_name = ?', [user["name"]])
734
+ return {r["key"]: r["value"] for r in rows}
735
+
736
+
737
+ @router.put("/my-settings")
738
+ def update_my_settings(data: dict, user: dict = Depends(get_current_user)):
739
+ """Merge-upsert the caller's OWN preferences (not admin-gated — a user owns
740
+ their prefs). Only rows with this user_name are ever touched, so one user can
741
+ never read or overwrite another's. Send only the keys you want to change."""
742
+ db = get_db()
743
+ uname = user["name"]
744
+ for key, value in data.items():
745
+ existing = db.sql(
746
+ 'SELECT 1 FROM "User Preference" WHERE user_name = ? AND key = ?', [uname, key]
747
+ )
748
+ if existing:
749
+ db.sql(
750
+ 'UPDATE "User Preference" SET value = ? WHERE user_name = ? AND key = ?',
751
+ [str(value), uname, key],
752
+ )
753
+ else:
754
+ db.sql(
755
+ 'INSERT INTO "User Preference" (user_name, key, value) VALUES (?, ?, ?)',
756
+ [uname, key, str(value)],
757
+ )
758
+ db.conn.commit()
759
+ rows = db.sql('SELECT key, value FROM "User Preference" WHERE user_name = ?', [uname])
760
+ return {r["key"]: r["value"] for r in rows}
761
+
762
+
723
763
  # ---------------------------------------------------------------------------
724
764
  # Programmatic chat API — Bearer API keys
725
765
  # ---------------------------------------------------------------------------
@@ -464,6 +464,11 @@ export const api = {
464
464
  getSettings: () => request<Record<string, string>>("/auth/settings"),
465
465
  updateSettings: (data: Record<string, string>) =>
466
466
  request<Record<string, string>>("/auth/settings", { method: "PUT", body: JSON.stringify(data) }),
467
+ // Per-USER preferences (columns.<doctype>, language, …) — scoped to the caller,
468
+ // not admin-gated, unlike the global getSettings/updateSettings above.
469
+ getMySettings: () => request<Record<string, string>>("/auth/my-settings"),
470
+ updateMySettings: (data: Record<string, string>) =>
471
+ request<Record<string, string>>("/auth/my-settings", { method: "PUT", body: JSON.stringify(data) }),
467
472
  getApiKeys: () =>
468
473
  request<Array<{
469
474
  id: string; name: string; user?: string; role: string; key_prefix: string;
@@ -1348,6 +1348,17 @@ class Database:
1348
1348
  value TEXT
1349
1349
  )""",
1350
1350
 
1351
+ # Per-USER preferences — distinct from the global admin-only Settings
1352
+ # above. A key->value bag scoped to one User; any authenticated user
1353
+ # reads/writes ONLY their own rows via /auth/my-settings (not admin).
1354
+ # Consumers: `columns.<doctype>` (personal list columns), `language`.
1355
+ """CREATE TABLE IF NOT EXISTS "User Preference" (
1356
+ user_name TEXT NOT NULL,
1357
+ key TEXT NOT NULL,
1358
+ value TEXT,
1359
+ PRIMARY KEY (user_name, key)
1360
+ )""",
1361
+
1351
1362
  # Bearer API keys for the programmatic chat API (off by default via
1352
1363
  # the `chat_api_enabled` Settings flag). Tokens are stored hashed
1353
1364
  # (sha256); `key_prefix` is a display-only fragment. `role` bounds the
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lambda-erp"
3
- version = "0.6.23"
3
+ version = "0.6.25"
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