Prepare ERP source for Gitea deployment

This commit is contained in:
A R R R Associates
2026-06-20 15:01:44 +05:30
commit 5c75eb6bd9
450 changed files with 67698 additions and 0 deletions
@@ -0,0 +1,138 @@
from __future__ import annotations
from decimal import Decimal
from typing import Any
from urllib.parse import quote
from sqlalchemy import or_, select
from sqlalchemy.orm import Session, selectinload
from app.modules.billing.models import BillingInvoice, BillingInvoiceLine, BillingPayment
from app.modules.billing.services import build_invoice_print_context, is_cashfree_ready, is_payumoney_ready, money
CLIENT_VISIBLE_INVOICE_STATUSES = {"ISSUED", "PARTLY_PAID", "PAID", "OVERDUE"}
def _client_ids(client_row: Any) -> tuple[int, int]:
"""Return (tenant_id, client_id) from dict/row/model style client payload."""
if isinstance(client_row, dict):
return int(client_row.get("tenant_id") or 0), int(client_row.get("id") or 0)
return int(getattr(client_row, "tenant_id", 0) or 0), int(getattr(client_row, "id", 0) or 0)
def list_client_portal_invoices(db: Session, client_row: Any, *, q: str = "", include_paid: bool = True, financial_year: str | None = None) -> list[BillingInvoice]:
tenant_id, client_id = _client_ids(client_row)
stmt = (
select(BillingInvoice)
.options(
selectinload(BillingInvoice.lines).selectinload(BillingInvoiceLine.service),
selectinload(BillingInvoice.payments),
)
.where(
BillingInvoice.tenant_id == tenant_id,
BillingInvoice.client_id == client_id,
BillingInvoice.status.in_(CLIENT_VISIBLE_INVOICE_STATUSES),
)
)
if not include_paid:
stmt = stmt.where(BillingInvoice.status != "PAID")
if financial_year and financial_year.upper() != "ALL":
stmt = stmt.where(BillingInvoice.financial_year == financial_year)
if q.strip():
term = f"%{q.strip()}%"
stmt = stmt.where(or_(BillingInvoice.invoice_no.ilike(term), BillingInvoice.invoice_title.ilike(term)))
return db.execute(stmt.order_by(BillingInvoice.invoice_date.desc(), BillingInvoice.id.desc())).scalars().unique().all()
def get_client_portal_invoice(db: Session, client_row: Any, invoice_id: int, *, financial_year: str | None = None) -> BillingInvoice | None:
tenant_id, client_id = _client_ids(client_row)
stmt = (
select(BillingInvoice)
.options(
selectinload(BillingInvoice.client),
selectinload(BillingInvoice.lines).selectinload(BillingInvoiceLine.service),
selectinload(BillingInvoice.payments),
)
.where(
BillingInvoice.id == invoice_id,
BillingInvoice.tenant_id == tenant_id,
BillingInvoice.client_id == client_id,
BillingInvoice.status.in_(CLIENT_VISIBLE_INVOICE_STATUSES),
)
)
if financial_year and financial_year.upper() != "ALL":
stmt = stmt.where(BillingInvoice.financial_year == financial_year)
return db.execute(stmt).scalars().unique().one_or_none()
def get_client_portal_payment(db: Session, client_row: Any, payment_id: int, *, financial_year: str | None = None) -> BillingPayment | None:
tenant_id, client_id = _client_ids(client_row)
stmt = (
select(BillingPayment)
.options(
selectinload(BillingPayment.invoice).selectinload(BillingInvoice.lines),
selectinload(BillingPayment.client),
)
.where(
BillingPayment.id == payment_id,
BillingPayment.tenant_id == tenant_id,
BillingPayment.client_id == client_id,
BillingPayment.status == "RECEIVED",
)
)
if financial_year and financial_year.upper() != "ALL":
stmt = stmt.where(BillingPayment.financial_year == financial_year)
return db.execute(stmt).scalars().unique().one_or_none()
def build_client_billing_summary(db: Session, client_row: Any, *, financial_year: str | None = None) -> dict[str, Any]:
invoices = list_client_portal_invoices(db, client_row, include_paid=True, financial_year=financial_year)
open_invoices = [row for row in invoices if row.status in {"ISSUED", "PARTLY_PAID", "OVERDUE"} and money(row.balance_amount) > Decimal("0.00")]
paid_invoices = [row for row in invoices if row.status == "PAID"]
outstanding = sum((money(row.balance_amount) for row in open_invoices), Decimal("0.00"))
latest_invoice = invoices[0] if invoices else None
latest_due_invoice = open_invoices[0] if open_invoices else None
return {
"billing_invoices": invoices,
"billing_open_invoices": open_invoices,
"billing_paid_invoices": paid_invoices,
"billing_outstanding_amount": money(outstanding),
"billing_latest_invoice": latest_invoice,
"billing_latest_due_invoice": latest_due_invoice,
"billing_open_count": len(open_invoices),
"billing_paid_count": len(paid_invoices),
"billing_total_count": len(invoices),
}
def build_client_payment_context(db: Session, invoice: BillingInvoice) -> dict[str, Any]:
invoice_ctx = build_invoice_print_context(db, invoice)
settings = invoice_ctx.get("settings")
amount_due = money(invoice.balance_amount)
firm_name = invoice_ctx.get("firm_name") or "Audit Firm"
upi_id = getattr(settings, "upi_id", None) if settings else None
upi_link = None
if upi_id and amount_due > Decimal("0.00"):
upi_link = (
"upi://pay?"
f"pa={quote(str(upi_id))}"
f"&pn={quote(str(firm_name))}"
f"&am={quote(str(amount_due))}"
"&cu=INR"
f"&tn={quote('Invoice ' + str(invoice.invoice_no))}"
)
return {
"invoice_ctx": invoice_ctx,
"amount_due": amount_due,
"upi_link": upi_link,
"upi_id": upi_id,
"bank_name": invoice_ctx.get("bank_name"),
"bank_account_name": invoice_ctx.get("bank_account_name"),
"bank_account_number": invoice_ctx.get("bank_account_number"),
"bank_ifsc": invoice_ctx.get("bank_ifsc"),
"payment_instructions": getattr(settings, "bank_details", None) if settings else None,
"payumoney_enabled": is_payumoney_ready(settings),
"payumoney_mode": getattr(settings, "payumoney_mode", "TEST") if settings else "TEST",
"cashfree_enabled": is_cashfree_ready(settings),
"cashfree_mode": getattr(settings, "cashfree_mode", "TEST") if settings else "TEST",
}