lambda-erp 0.1.44__tar.gz → 0.1.45__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 (71) hide show
  1. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/PKG-INFO +1 -1
  2. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/reports.py +106 -0
  3. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/frontend/src/api/client.ts +5 -0
  4. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/pyproject.toml +1 -1
  5. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/.gitignore +0 -0
  6. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/LICENSE +0 -0
  7. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/README.md +0 -0
  8. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/__init__.py +0 -0
  9. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/attachments.py +0 -0
  10. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/auth.py +0 -0
  11. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/bootstrap.py +0 -0
  12. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/chat.py +0 -0
  13. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/demo_limits.py +0 -0
  14. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/deps.py +0 -0
  15. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/errors.py +0 -0
  16. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/main.py +0 -0
  17. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/oauth.py +0 -0
  18. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/pdf.py +0 -0
  19. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/providers.py +0 -0
  20. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/remarks_md.py +0 -0
  21. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/__init__.py +0 -0
  22. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/accounting.py +0 -0
  23. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/admin.py +0 -0
  24. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/analytics.py +0 -0
  25. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/bank_reconciliation.py +0 -0
  26. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/chat_api.py +0 -0
  27. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/documents.py +0 -0
  28. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/masters.py +0 -0
  29. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/proposals.py +0 -0
  30. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/setup.py +0 -0
  31. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/services.py +0 -0
  32. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/templates/document.html +0 -0
  33. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/templates/proposal.html +0 -0
  34. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/docs/agents/README.md +0 -0
  35. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/frontend/README.md +0 -0
  36. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/__init__.py +0 -0
  37. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/__init__.py +0 -0
  38. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/bank_transaction.py +0 -0
  39. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/budget.py +0 -0
  40. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/chart_of_accounts.py +0 -0
  41. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/general_ledger.py +0 -0
  42. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/journal_entry.py +0 -0
  43. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/payment_entry.py +0 -0
  44. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/pos_invoice.py +0 -0
  45. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/purchase_invoice.py +0 -0
  46. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/revaluation.py +0 -0
  47. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/sales_invoice.py +0 -0
  48. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/subscription.py +0 -0
  49. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/buying/__init__.py +0 -0
  50. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/buying/purchase_order.py +0 -0
  51. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/controllers/__init__.py +0 -0
  52. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/controllers/currency.py +0 -0
  53. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/controllers/defaults.py +0 -0
  54. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/controllers/pricing_rule.py +0 -0
  55. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/controllers/taxes_and_totals.py +0 -0
  56. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/database.py +0 -0
  57. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/exceptions.py +0 -0
  58. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/hooks.py +0 -0
  59. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/model.py +0 -0
  60. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/selling/__init__.py +0 -0
  61. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/selling/proposal.py +0 -0
  62. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/selling/quotation.py +0 -0
  63. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/selling/sales_order.py +0 -0
  64. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/simulation.py +0 -0
  65. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/stock/__init__.py +0 -0
  66. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/stock/delivery_note.py +0 -0
  67. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/stock/purchase_receipt.py +0 -0
  68. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/stock/stock_entry.py +0 -0
  69. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/stock/stock_ledger.py +0 -0
  70. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/utils.py +0 -0
  71. {lambda_erp-0.1.44 → lambda_erp-0.1.45}/terraform/README.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lambda-erp
3
- Version: 0.1.44
3
+ Version: 0.1.45
4
4
  Summary: Core ERP logic - accounting, sales, purchasing, inventory
5
5
  Author: TORUS INVESTMENTS AG
6
6
  License-Expression: MIT
@@ -121,6 +121,112 @@ 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
+ """Chart of accounts (every account, incl. groups and zero-balance ones)
126
+ with period balances — the tree the GUI renders.
127
+
128
+ Balance semantics follow standard presentation:
129
+ - Balance Sheet accounts: CLOSING balance as of ``to_date`` (all postings
130
+ up to and including it; ``from_date`` is ignored for them).
131
+ - P&L accounts: movement WITHIN [from_date, to_date].
132
+ Values are natural-signed per root_type (Asset/Expense: debit − credit;
133
+ Liability/Equity/Income: credit − debit) so revenue reads positive.
134
+ Group accounts roll up every descendant's balance (plus any postings of
135
+ their own, though entries normally land on leaves).
136
+ """
137
+ acc_filters = {}
138
+ if company:
139
+ acc_filters["company"] = company
140
+ accounts = db.get_all(
141
+ "Account", filters=acc_filters,
142
+ fields=["name", "account_name", "parent_account", "root_type",
143
+ "report_type", "account_type", "is_group", "disabled"],
144
+ order_by="name",
145
+ )
146
+
147
+ def _movement(where_extra, params_extra):
148
+ clause = "is_cancelled = 0" + where_extra
149
+ params = list(params_extra)
150
+ if company:
151
+ clause += " AND company = ?"
152
+ params.append(company)
153
+ found = db.sql(
154
+ f"""SELECT account,
155
+ COALESCE(SUM(debit), 0) AS d,
156
+ COALESCE(SUM(credit), 0) AS c
157
+ FROM "GL Entry" WHERE {clause} GROUP BY account""",
158
+ params,
159
+ )
160
+ return {r["account"]: (flt(r["d"], 2), flt(r["c"], 2)) for r in found}
161
+
162
+ bs_where, bs_params = "", []
163
+ if to_date:
164
+ bs_where, bs_params = " AND posting_date <= ?", [to_date]
165
+ bs_map = _movement(bs_where, bs_params)
166
+
167
+ if from_date or to_date:
168
+ pl_where, pl_params = "", []
169
+ if from_date:
170
+ pl_where += " AND posting_date >= ?"
171
+ pl_params.append(from_date)
172
+ if to_date:
173
+ pl_where += " AND posting_date <= ?"
174
+ pl_params.append(to_date)
175
+ pl_map = _movement(pl_where, pl_params)
176
+ else:
177
+ pl_map = bs_map
178
+
179
+ rows = []
180
+ by_name = {}
181
+ for acc in accounts:
182
+ is_pl = acc.get("report_type") == "Profit and Loss"
183
+ d, c = (pl_map if is_pl else bs_map).get(acc["name"], (0.0, 0.0))
184
+ if acc.get("root_type") in ("Liability", "Equity", "Income"):
185
+ natural = c - d
186
+ else:
187
+ natural = d - c
188
+ row = {
189
+ "name": acc["name"],
190
+ "account_name": acc.get("account_name"),
191
+ "parent_account": acc.get("parent_account") or None,
192
+ "root_type": acc.get("root_type"),
193
+ "account_type": acc.get("account_type"),
194
+ "is_group": bool(acc.get("is_group")),
195
+ "disabled": bool(acc.get("disabled")),
196
+ "balance": flt(natural, 2),
197
+ "has_entries": bool(d or c),
198
+ }
199
+ rows.append(row)
200
+ by_name[row["name"]] = row
201
+
202
+ # Roll every account's own balance up its ancestor chain so group rows
203
+ # show subtree totals.
204
+ subtree_extra = {r["name"]: 0.0 for r in rows}
205
+ for row in rows:
206
+ parent = row["parent_account"]
207
+ while parent and parent in by_name:
208
+ subtree_extra[parent] += row["balance"]
209
+ parent = by_name[parent]["parent_account"]
210
+ for row in rows:
211
+ if row["is_group"]:
212
+ row["balance"] = flt(row["balance"] + subtree_extra[row["name"]], 2)
213
+ row["has_entries"] = row["has_entries"] or bool(subtree_extra[row["name"]])
214
+
215
+ return {"accounts": rows, "from_date": from_date, "to_date": to_date}
216
+
217
+
218
+ @router.get("/chart-of-accounts")
219
+ def chart_of_accounts(
220
+ company: str | None = None,
221
+ from_date: str | None = None,
222
+ to_date: str | None = None,
223
+ presentation_currency: str | None = None,
224
+ ):
225
+ db = get_db()
226
+ return _present(db, _chart_of_accounts(db, company, from_date, to_date),
227
+ company, presentation_currency, to_date)
228
+
229
+
124
230
  def _general_ledger(db, filters=None):
125
231
  filters = filters or {}
126
232
  where = ["is_cancelled = 0"]
@@ -226,6 +226,11 @@ export const api = {
226
226
  `/reports/trial-balance${qs(params)}`,
227
227
  ),
228
228
 
229
+ chartOfAccounts: (params?: Record<string, string>) =>
230
+ request<{ accounts: any[]; from_date: string | null; to_date: string | null }>(
231
+ `/reports/chart-of-accounts${qs(params)}`,
232
+ ),
233
+
229
234
  generalLedger: (params?: Record<string, string>) =>
230
235
  request<{
231
236
  rows: any[];
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lambda-erp"
3
- version = "0.1.44"
3
+ version = "0.1.45"
4
4
  description = "Core ERP logic - accounting, sales, purchasing, inventory"
5
5
  readme = "README.md"
6
6
  license = "MIT"
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