lambda-erp 0.8.2__tar.gz → 0.8.4__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.8.2 → lambda_erp-0.8.4}/PKG-INFO +1 -1
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/chat.py +1 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/services.py +49 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/setup/packs/ch.py +9 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/database.py +12 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/pyproject.toml +1 -1
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/.gitignore +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/LICENSE +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/README.md +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/__init__.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/attachments.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/auth.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/bootstrap.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/demo_limits.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/deps.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/errors.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/main.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/oauth.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/pdf.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/providers.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/remarks_md.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/__init__.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/accounting.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/admin.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/analytics.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/availability.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/bank_reconciliation.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/chat_api.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/documents.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/masters.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/mcp.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/proposals.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/reports.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/routers/setup.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/templates/document.html +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/api/templates/proposal.html +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/docs/agents/README.md +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/frontend/LICENSE +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/frontend/README.md +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/frontend/src/api/client.ts +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/__init__.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/__init__.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/bank_transaction.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/budget.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/chart_of_accounts.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/general_ledger.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/journal_entry.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/payment_entry.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/pos_invoice.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/purchase_invoice.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/revaluation.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/sales_invoice.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/setup/__init__.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/setup/engine.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/setup/pack.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/setup/packs/__init__.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/setup/packs/de_common.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/setup/packs/de_skr03.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/setup/packs/de_skr04.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/setup/packs/generic.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/setup/profiles.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/setup/spine.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/accounting/subscription.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/assets/__init__.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/assets/asset.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/assets/reservation.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/buying/__init__.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/buying/purchase_order.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/controllers/__init__.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/controllers/currency.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/controllers/defaults.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/controllers/pricing_rule.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/controllers/taxes_and_totals.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/exceptions.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/hooks.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/model.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/selling/__init__.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/selling/proposal.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/selling/quotation.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/selling/sales_order.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/simulation.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/stock/__init__.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/stock/delivery_note.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/stock/purchase_receipt.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/stock/stock_entry.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/stock/stock_ledger.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/lambda_erp/utils.py +0 -0
- {lambda_erp-0.8.2 → lambda_erp-0.8.4}/terraform/README.md +0 -0
|
@@ -2280,6 +2280,7 @@ Use these only for items flagged `is_asset_tracked` on the Item master. Neither
|
|
|
2280
2280
|
- **Reservation** (slug `reservation`) books a time window. Required: `from_datetime` and `to_datetime` (`YYYY-MM-DD` or `YYYY-MM-DD HH:MM:SS`; a bare date means midnight). Windows are **half-open** — a hire ending on the 19th and the next starting on the 19th do NOT clash. Two ways to book:
|
|
2281
2281
|
- **pooled** — set `item_code`, `warehouse` and `qty`: "*a* machine of this type from that yard". Use this at quotation/order time when the specific unit doesn't matter yet.
|
|
2282
2282
|
- **unit** — set `asset`: "*that* machine". `item_code`, `warehouse` and `qty` are filled in from the Asset automatically.
|
|
2283
|
+
- **Who it's for (do NOT skip this):** set `party` to the hiring customer's id (e.g. `CUST-005`) with `party_type = "Customer"`. The customer is almost always given by NAME — "reserve the 17t for Hans Meisterhans" — so FIRST resolve the name to a record with `search_masters` (master_type "customer") and set `party` to the matched id; never put the raw name in `party`. No match → create the customer (or ask which existing one is meant), then book. A reservation with no `party` is only for an internal block (maintenance, transport, transfer) — if the user named a customer, a booking without `party` set is a bug, not an option.
|
|
2283
2284
|
- `status` is Reserved / Out / Returned / Cancelled. **Reserved and Out block the calendar; Returned and Cancelled do not** — so a hire that comes back early frees its slot the moment you set it to Returned. Link a booking to the order that caused it with `voucher_type` + `voucher_no`.
|
|
2284
2285
|
- **Double-booking is refused at save time.** If you get "already committed" (that unit is taken) or "free at" (the yard's pool is exhausted for that window), do NOT retry blindly — report the conflict, then offer the alternatives: different dates, a different yard, or a different model.
|
|
2285
2286
|
- To answer "what's free between X and Y", list reservations for the item over the window and compare against the Assets that exist; a unit with no overlapping Reserved/Out row is available.
|
|
@@ -284,10 +284,59 @@ def get_document_class(doctype_slug: str):
|
|
|
284
284
|
return doctype, DOCUMENT_CLASSES[doctype]
|
|
285
285
|
|
|
286
286
|
|
|
287
|
+
# Which Company default a doc's `taxes` table draws from — keyed by the taxes
|
|
288
|
+
# child doctype, so any doc that has a taxes table is covered without a hardcoded
|
|
289
|
+
# doctype list. Selling -> sales default, buying -> purchase default.
|
|
290
|
+
_TAX_CHILD_DEFAULT_FIELD = {
|
|
291
|
+
"Sales Taxes and Charges": "default_sales_tax_template",
|
|
292
|
+
"Purchase Taxes and Charges": "default_purchase_tax_template",
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def _default_tax_rows(cls, data: dict) -> list | None:
|
|
297
|
+
"""`taxes[]` rows to seed a new document from its company's default Tax
|
|
298
|
+
Template, or None to leave taxes untouched.
|
|
299
|
+
|
|
300
|
+
Applied ONLY when the caller omits `taxes` entirely — the exact case the chat
|
|
301
|
+
model kept hitting (it forgets to add MWST). An explicit `taxes: []` is left
|
|
302
|
+
alone, so a deliberately tax-free doc (export, reverse-charge, exempt) is
|
|
303
|
+
expressed by passing an empty list. The document's own tax calc then computes
|
|
304
|
+
`tax_amount` from the rate, so this only seeds charge_type/account/rate.
|
|
305
|
+
"""
|
|
306
|
+
taxes_child = cls.CHILD_TABLES.get("taxes")
|
|
307
|
+
if not taxes_child or "taxes" in data:
|
|
308
|
+
return None
|
|
309
|
+
field = _TAX_CHILD_DEFAULT_FIELD.get(taxes_child[0])
|
|
310
|
+
company = data.get("company")
|
|
311
|
+
if not field or not company:
|
|
312
|
+
return None
|
|
313
|
+
db = get_db()
|
|
314
|
+
template = db.get_value("Company", company, field)
|
|
315
|
+
if not template:
|
|
316
|
+
return None
|
|
317
|
+
details = db.get_all("Tax Template Detail", filters={"parent": template},
|
|
318
|
+
fields=["*"], order_by="idx")
|
|
319
|
+
if not details:
|
|
320
|
+
return None
|
|
321
|
+
return [
|
|
322
|
+
{
|
|
323
|
+
"charge_type": d.get("charge_type") or "On Net Total",
|
|
324
|
+
"account_head": d.get("account_head"),
|
|
325
|
+
"rate": d.get("rate") or 0,
|
|
326
|
+
"description": d.get("description") or template,
|
|
327
|
+
"add_deduct_tax": "Add",
|
|
328
|
+
}
|
|
329
|
+
for d in details
|
|
330
|
+
]
|
|
331
|
+
|
|
332
|
+
|
|
287
333
|
def create_document(doctype_slug: str, data: dict) -> dict:
|
|
288
334
|
doctype, cls = get_document_class(doctype_slug)
|
|
289
335
|
if not cls:
|
|
290
336
|
raise ValueError(f"Unknown document type: {doctype_slug}")
|
|
337
|
+
default_taxes = _default_tax_rows(cls, data)
|
|
338
|
+
if default_taxes is not None:
|
|
339
|
+
data = {**data, "taxes": default_taxes}
|
|
291
340
|
doc = cls(data)
|
|
292
341
|
doc.save()
|
|
293
342
|
return doc.as_dict()
|
|
@@ -238,6 +238,15 @@ def ch_setup_tax(company_name, currency):
|
|
|
238
238
|
for title, rate, leaf in _PURCHASE_TAXES:
|
|
239
239
|
_template(title, "Purchase", rate, leaf)
|
|
240
240
|
|
|
241
|
+
# Make the 8.1% standard rate the company's default sales tax, so new
|
|
242
|
+
# invoices/quotations pick up MWST automatically (create_document seeds it
|
|
243
|
+
# when `taxes` is omitted). Purchase Vorsteuer stays manual — it varies by
|
|
244
|
+
# goods vs. investment, so there's no single sensible default.
|
|
245
|
+
default_sales = f"MWST Normalsatz 8.1% - {abbr}"
|
|
246
|
+
if db.exists("Tax Template", default_sales):
|
|
247
|
+
db.set_value("Company", company_name, {"default_sales_tax_template": default_sales})
|
|
248
|
+
summary.append(f"default sales tax: MWST Normalsatz 8.1%")
|
|
249
|
+
|
|
241
250
|
return summary
|
|
242
251
|
|
|
243
252
|
|
|
@@ -2125,6 +2125,17 @@ def _m021_item_is_asset_tracked(db: "Database") -> None:
|
|
|
2125
2125
|
db._add_column_if_missing("Item", "is_asset_tracked", "INTEGER DEFAULT 0")
|
|
2126
2126
|
|
|
2127
2127
|
|
|
2128
|
+
def _m022_company_default_tax_templates(db: "Database") -> None:
|
|
2129
|
+
"""Per-company default sales/purchase Tax Templates. When a selling/buying
|
|
2130
|
+
document is created with NO `taxes` rows at all, create_document applies the
|
|
2131
|
+
matching default so VAT/MWST is not silently omitted (see api/services.py).
|
|
2132
|
+
Both default to NULL, so existing deployments are unaffected until a default
|
|
2133
|
+
is wired — e.g. the CH pack points the sales default at the 8.1% MWST
|
|
2134
|
+
template. Passing an explicit empty `taxes: []` still means a tax-free doc."""
|
|
2135
|
+
db._add_column_if_missing("Company", "default_sales_tax_template", "TEXT")
|
|
2136
|
+
db._add_column_if_missing("Company", "default_purchase_tax_template", "TEXT")
|
|
2137
|
+
|
|
2138
|
+
|
|
2128
2139
|
Database.MIGRATIONS = [
|
|
2129
2140
|
(1, "chat_message_session_id", _m001_chat_message_session_id),
|
|
2130
2141
|
(2, "chat_session_user_id", _m002_chat_session_user_id),
|
|
@@ -2147,6 +2158,7 @@ Database.MIGRATIONS = [
|
|
|
2147
2158
|
(19, "api_keys_per_user", _m019_api_keys_per_user),
|
|
2148
2159
|
(20, "chat_attachment_openai_file", _m020_chat_attachment_openai_file),
|
|
2149
2160
|
(21, "item_is_asset_tracked", _m021_item_is_asset_tracked),
|
|
2161
|
+
(22, "company_default_tax_templates", _m022_company_default_tax_templates),
|
|
2150
2162
|
]
|
|
2151
2163
|
|
|
2152
2164
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|