lambda-erp 0.1.10__tar.gz → 0.1.11__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.10 → lambda_erp-0.1.11}/PKG-INFO +1 -1
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/pdf.py +30 -2
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/routers/masters.py +9 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/pyproject.toml +1 -1
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/.gitignore +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/LICENSE +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/README.md +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/__init__.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/attachments.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/auth.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/bootstrap.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/chat.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/demo_limits.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/deps.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/errors.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/main.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/providers.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/routers/__init__.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/routers/accounting.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/routers/admin.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/routers/analytics.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/routers/bank_reconciliation.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/routers/documents.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/routers/reports.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/routers/setup.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/services.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/api/templates/document.html +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/docs/agents/README.md +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/frontend/README.md +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/frontend/src/api/client.ts +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/__init__.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/__init__.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/bank_transaction.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/budget.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/chart_of_accounts.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/general_ledger.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/journal_entry.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/payment_entry.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/pos_invoice.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/purchase_invoice.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/revaluation.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/sales_invoice.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/accounting/subscription.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/buying/__init__.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/buying/purchase_order.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/controllers/__init__.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/controllers/currency.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/controllers/defaults.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/controllers/pricing_rule.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/controllers/taxes_and_totals.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/database.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/exceptions.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/hooks.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/model.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/selling/__init__.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/selling/quotation.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/selling/sales_order.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/simulation.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/stock/__init__.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/stock/delivery_note.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/stock/purchase_receipt.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/stock/stock_entry.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/stock/stock_ledger.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/lambda_erp/utils.py +0 -0
- {lambda_erp-0.1.10 → lambda_erp-0.1.11}/terraform/README.md +0 -0
|
@@ -1,13 +1,41 @@
|
|
|
1
1
|
"""PDF generation for ERP documents."""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
from jinja2 import Environment, FileSystemLoader
|
|
4
|
+
from jinja2 import Environment, FileSystemLoader, ChoiceLoader
|
|
5
5
|
from weasyprint import HTML
|
|
6
6
|
from lambda_erp.database import get_db
|
|
7
7
|
from api.services import load_document
|
|
8
8
|
|
|
9
9
|
TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), "templates")
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
# Extension seam: deployment plugins can register their own template
|
|
12
|
+
# directories (searched BEFORE the built-in one) to override document.html with
|
|
13
|
+
# custom branding/styling. The render context in generate_pdf is unchanged, so
|
|
14
|
+
# a custom template just re-styles the same data.
|
|
15
|
+
_plugin_template_dirs: list[str] = []
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _build_loader():
|
|
19
|
+
return ChoiceLoader(
|
|
20
|
+
[FileSystemLoader(d) for d in _plugin_template_dirs] + [FileSystemLoader(TEMPLATE_DIR)]
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
_jinja_env = Environment(loader=_build_loader(), autoescape=True)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def register_pdf_template_dir(path: str) -> None:
|
|
28
|
+
"""Register a directory of PDF templates searched before the built-in ones.
|
|
29
|
+
|
|
30
|
+
Call from a plugin's register(). Drop a `document.html` (and/or other
|
|
31
|
+
templates) in `path` to override the built-in PDF layout with your own
|
|
32
|
+
styling — the template receives the same context generate_pdf() builds
|
|
33
|
+
(doc, title, company_info, party_info, currency, meta_fields, items, taxes,
|
|
34
|
+
page_size, ...). Later registrations win.
|
|
35
|
+
"""
|
|
36
|
+
if path and path not in _plugin_template_dirs:
|
|
37
|
+
_plugin_template_dirs.insert(0, path)
|
|
38
|
+
_jinja_env.loader = _build_loader()
|
|
11
39
|
|
|
12
40
|
# Document type → (title, party_field, party_name_field, party_doctype, party_label)
|
|
13
41
|
DOC_CONFIG = {
|
|
@@ -222,6 +222,15 @@ def create_master_record(master_type: str, data: dict) -> dict:
|
|
|
222
222
|
if db.exists(doctype, doc["name"]):
|
|
223
223
|
raise HTTPException(status_code=409, detail=f"{doctype} {doc['name']} already exists")
|
|
224
224
|
|
|
225
|
+
# Party masters inherit the company's base currency when none is specified.
|
|
226
|
+
# Otherwise the Customer/Supplier default_currency column default ('USD')
|
|
227
|
+
# wins, so a non-USD company (e.g. CHF) gets USD customers that then force
|
|
228
|
+
# every sales/purchase document to USD (and fail with no USD->base rate).
|
|
229
|
+
if master_type in ("customer", "supplier") and not doc.get("default_currency"):
|
|
230
|
+
companies = db.get_all("Company", fields=["name", "default_currency"], limit=1)
|
|
231
|
+
if companies:
|
|
232
|
+
doc["default_currency"] = companies[0].get("default_currency") or "USD"
|
|
233
|
+
|
|
225
234
|
db.insert(doctype, doc)
|
|
226
235
|
row = db.get_all(doctype, filters={"name": doc["name"]}, fields=["*"])[0]
|
|
227
236
|
return _echo_identity_alias(master_type, row)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|