lambda-erp 0.6.22__tar.gz → 0.6.24__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-0.6.22 → lambda_erp-0.6.24}/PKG-INFO +1 -1
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/auth.py +40 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/frontend/src/api/client.ts +5 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/database.py +11 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/pyproject.toml +1 -1
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/.gitignore +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/LICENSE +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/README.md +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/__init__.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/attachments.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/bootstrap.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/chat.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/demo_limits.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/deps.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/errors.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/main.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/oauth.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/pdf.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/providers.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/remarks_md.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/__init__.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/accounting.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/admin.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/analytics.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/bank_reconciliation.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/chat_api.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/documents.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/masters.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/mcp.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/proposals.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/reports.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/routers/setup.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/services.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/templates/document.html +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/api/templates/proposal.html +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/docs/agents/README.md +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/frontend/LICENSE +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/frontend/README.md +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/__init__.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/__init__.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/bank_transaction.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/budget.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/chart_of_accounts.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/general_ledger.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/journal_entry.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/payment_entry.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/pos_invoice.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/purchase_invoice.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/revaluation.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/sales_invoice.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/setup/__init__.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/setup/engine.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/setup/pack.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/setup/packs/__init__.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/setup/packs/ch.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/setup/packs/de_common.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/setup/packs/de_skr03.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/setup/packs/de_skr04.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/setup/packs/generic.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/setup/profiles.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/setup/spine.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/accounting/subscription.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/buying/__init__.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/buying/purchase_order.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/controllers/__init__.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/controllers/currency.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/controllers/defaults.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/controllers/pricing_rule.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/controllers/taxes_and_totals.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/exceptions.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/hooks.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/model.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/selling/__init__.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/selling/proposal.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/selling/quotation.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/selling/sales_order.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/simulation.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/stock/__init__.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/stock/delivery_note.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/stock/purchase_receipt.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/stock/stock_entry.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/stock/stock_ledger.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/lambda_erp/utils.py +0 -0
- {lambda_erp-0.6.22 → lambda_erp-0.6.24}/terraform/README.md +0 -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
|
|
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
|