lambda-erp 0.2.4__tar.gz → 0.2.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-0.2.4 → lambda_erp-0.2.6}/PKG-INFO +1 -1
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/main.py +27 -2
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/routers/reports.py +26 -5
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/pyproject.toml +1 -1
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/.gitignore +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/LICENSE +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/README.md +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/__init__.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/attachments.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/auth.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/bootstrap.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/chat.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/demo_limits.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/deps.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/errors.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/oauth.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/pdf.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/providers.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/remarks_md.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/routers/__init__.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/routers/accounting.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/routers/admin.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/routers/analytics.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/routers/bank_reconciliation.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/routers/chat_api.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/routers/documents.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/routers/masters.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/routers/proposals.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/routers/setup.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/services.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/templates/document.html +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/api/templates/proposal.html +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/docs/agents/README.md +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/frontend/README.md +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/frontend/src/api/client.ts +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/__init__.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/__init__.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/bank_transaction.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/budget.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/chart_of_accounts.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/general_ledger.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/journal_entry.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/payment_entry.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/pos_invoice.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/purchase_invoice.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/revaluation.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/sales_invoice.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/setup/__init__.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/setup/engine.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/setup/pack.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/setup/packs/__init__.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/setup/packs/ch.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/setup/packs/de_common.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/setup/packs/de_skr03.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/setup/packs/de_skr04.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/setup/packs/generic.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/setup/profiles.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/setup/spine.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/accounting/subscription.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/buying/__init__.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/buying/purchase_order.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/controllers/__init__.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/controllers/currency.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/controllers/defaults.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/controllers/pricing_rule.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/controllers/taxes_and_totals.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/database.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/exceptions.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/hooks.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/model.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/selling/__init__.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/selling/proposal.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/selling/quotation.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/selling/sales_order.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/simulation.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/stock/__init__.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/stock/delivery_note.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/stock/purchase_receipt.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/stock/stock_entry.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/stock/stock_ledger.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/lambda_erp/utils.py +0 -0
- {lambda_erp-0.2.4 → lambda_erp-0.2.6}/terraform/README.md +0 -0
|
@@ -158,11 +158,29 @@ async def ws_chat(websocket: WebSocket):
|
|
|
158
158
|
# semantics: real files (assets, favicon, logos) resolve as-is; anything
|
|
159
159
|
# else falls through to index.html and React Router handles it
|
|
160
160
|
# client-side. API and WebSocket paths keep returning their normal 404s.
|
|
161
|
+
class _ImmutableStaticFiles(StaticFiles):
|
|
162
|
+
"""Serve content-hashed build assets with a long-lived immutable cache.
|
|
163
|
+
|
|
164
|
+
Vite fingerprints every file under /assets (index-<hash>.js, etc.), so the
|
|
165
|
+
bytes at a given URL never change — a new build emits new filenames. The
|
|
166
|
+
`immutable` directive lets the browser skip revalidation entirely (no 304
|
|
167
|
+
round-trip on reload), while index.html stays `no-cache` so a new build is
|
|
168
|
+
still picked up. Net effect vs. the old default: fewer requests, not more.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
async def get_response(self, path, scope):
|
|
172
|
+
response = await super().get_response(path, scope)
|
|
173
|
+
response.headers.setdefault(
|
|
174
|
+
"Cache-Control", "public, max-age=31536000, immutable"
|
|
175
|
+
)
|
|
176
|
+
return response
|
|
177
|
+
|
|
178
|
+
|
|
161
179
|
frontend_dist = os.path.join(os.path.dirname(__file__), "..", "frontend", "dist")
|
|
162
180
|
if os.path.isdir(frontend_dist):
|
|
163
181
|
assets_dir = os.path.join(frontend_dist, "assets")
|
|
164
182
|
if os.path.isdir(assets_dir):
|
|
165
|
-
app.mount("/assets",
|
|
183
|
+
app.mount("/assets", _ImmutableStaticFiles(directory=assets_dir), name="assets")
|
|
166
184
|
|
|
167
185
|
frontend_root = os.path.realpath(frontend_dist)
|
|
168
186
|
index_html = os.path.join(frontend_root, "index.html")
|
|
@@ -183,4 +201,11 @@ if os.path.isdir(frontend_dist):
|
|
|
183
201
|
return FileResponse(candidate)
|
|
184
202
|
|
|
185
203
|
# SPA fallback — React Router takes over from here.
|
|
186
|
-
|
|
204
|
+
#
|
|
205
|
+
# `no-cache` = always revalidate the shell before reuse (a cheap 304
|
|
206
|
+
# when unchanged, fresh bytes after a deploy). index.html is the only
|
|
207
|
+
# UNHASHED file and it points at the hashed /assets bundles, so if the
|
|
208
|
+
# browser heuristically caches it (which it does when no Cache-Control
|
|
209
|
+
# is set), a soft reload serves a stale shell referencing old asset
|
|
210
|
+
# URLs — the "refresh doesn't refresh, need a hard-refresh" bug.
|
|
211
|
+
return FileResponse(index_html, headers={"Cache-Control": "no-cache"})
|
|
@@ -121,9 +121,13 @@ def trial_balance(
|
|
|
121
121
|
company, presentation_currency, to_date)
|
|
122
122
|
|
|
123
123
|
|
|
124
|
-
def _chart_of_accounts(db, company=None, from_date=None, to_date=None
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
def _chart_of_accounts(db, company=None, from_date=None, to_date=None,
|
|
125
|
+
include_disabled=False):
|
|
126
|
+
"""Chart of accounts (groups and zero-balance ones included) with period
|
|
127
|
+
balances — the tree the GUI renders. Disabled accounts are hidden by default
|
|
128
|
+
(``include_disabled=True`` to show them); balances still roll up over every
|
|
129
|
+
descendant (incl. disabled), and a disabled group with an enabled descendant
|
|
130
|
+
is kept so no active account is orphaned.
|
|
127
131
|
|
|
128
132
|
Balance semantics follow standard presentation:
|
|
129
133
|
- Balance Sheet accounts: CLOSING balance as of ``to_date`` (all postings
|
|
@@ -212,6 +216,19 @@ def _chart_of_accounts(db, company=None, from_date=None, to_date=None):
|
|
|
212
216
|
row["balance"] = flt(row["balance"] + subtree_extra[row["name"]], 2)
|
|
213
217
|
row["has_entries"] = row["has_entries"] or bool(subtree_extra[row["name"]])
|
|
214
218
|
|
|
219
|
+
# Hide disabled accounts by default, but keep any disabled ancestor of an
|
|
220
|
+
# enabled account so the enabled one isn't orphaned in the rendered tree.
|
|
221
|
+
if not include_disabled:
|
|
222
|
+
keep = set()
|
|
223
|
+
for row in rows:
|
|
224
|
+
if not row["disabled"]:
|
|
225
|
+
keep.add(row["name"])
|
|
226
|
+
parent = row["parent_account"]
|
|
227
|
+
while parent and parent in by_name and parent not in keep:
|
|
228
|
+
keep.add(parent)
|
|
229
|
+
parent = by_name[parent]["parent_account"]
|
|
230
|
+
rows = [r for r in rows if r["name"] in keep]
|
|
231
|
+
|
|
215
232
|
return {"accounts": rows, "from_date": from_date, "to_date": to_date}
|
|
216
233
|
|
|
217
234
|
|
|
@@ -221,10 +238,14 @@ def chart_of_accounts(
|
|
|
221
238
|
from_date: str | None = None,
|
|
222
239
|
to_date: str | None = None,
|
|
223
240
|
presentation_currency: str | None = None,
|
|
241
|
+
include_disabled: bool = False,
|
|
224
242
|
):
|
|
225
243
|
db = get_db()
|
|
226
|
-
return _present(
|
|
227
|
-
|
|
244
|
+
return _present(
|
|
245
|
+
db,
|
|
246
|
+
_chart_of_accounts(db, company, from_date, to_date,
|
|
247
|
+
include_disabled=include_disabled),
|
|
248
|
+
company, presentation_currency, to_date)
|
|
228
249
|
|
|
229
250
|
|
|
230
251
|
def _general_ledger(db, filters=None):
|
|
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
|