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.
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/PKG-INFO +1 -1
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/reports.py +106 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/frontend/src/api/client.ts +5 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/pyproject.toml +1 -1
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/.gitignore +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/LICENSE +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/README.md +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/__init__.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/attachments.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/auth.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/bootstrap.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/chat.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/demo_limits.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/deps.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/errors.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/main.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/oauth.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/pdf.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/providers.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/remarks_md.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/__init__.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/accounting.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/admin.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/analytics.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/bank_reconciliation.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/chat_api.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/documents.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/masters.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/proposals.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/routers/setup.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/services.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/templates/document.html +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/api/templates/proposal.html +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/docs/agents/README.md +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/frontend/README.md +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/__init__.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/__init__.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/bank_transaction.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/budget.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/chart_of_accounts.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/general_ledger.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/journal_entry.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/payment_entry.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/pos_invoice.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/purchase_invoice.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/revaluation.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/sales_invoice.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/accounting/subscription.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/buying/__init__.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/buying/purchase_order.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/controllers/__init__.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/controllers/currency.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/controllers/defaults.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/controllers/pricing_rule.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/controllers/taxes_and_totals.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/database.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/exceptions.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/hooks.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/model.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/selling/__init__.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/selling/proposal.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/selling/quotation.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/selling/sales_order.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/simulation.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/stock/__init__.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/stock/delivery_note.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/stock/purchase_receipt.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/stock/stock_entry.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/stock/stock_ledger.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/lambda_erp/utils.py +0 -0
- {lambda_erp-0.1.44 → lambda_erp-0.1.45}/terraform/README.md +0 -0
|
@@ -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[];
|
|
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
|