from __future__ import annotations from sqlalchemy import select from app.modules.accounting.taxonomy_models import AccountingNature SALES_INCOME_NATURES = [ # code, name, parent, group, cap/revenue, posting, sort, description ("SALES_INCOME", "Sales & Income", None, "income", "revenue", False, 1100, "Sales and income classification root."), ("TRADING_SALES", "Trading / Stock Sales", "SALES_INCOME", "income", "revenue", True, 1110, "Sale of goods principally held for resale."), ("MANUFACTURED_GOODS_SALES", "Manufactured Goods Sales", "SALES_INCOME", "income", "revenue", True, 1120, "Sale of goods manufactured or produced by the entity."), ("SERVICE_INCOME", "Service / Professional Income", "SALES_INCOME", "income", "revenue", True, 1130, "Revenue from services, professional work or contractual services."), ("EXPORT_SALES", "Export Sales / Services", "SALES_INCOME", "income", "revenue", True, 1140, "Export of goods or services."), ("EXEMPT_NIL_SALES", "Exempt / Nil-Rated Sales", "SALES_INCOME", "income", "revenue", True, 1150, "Sales or supplies treated as exempt or nil-rated."), ("SCRAP_SALES", "Scrap / Waste Sales", "SALES_INCOME", "income", "revenue", True, 1160, "Sale of scrap, waste or residual materials."), ("JOB_WORK_INCOME", "Job Work / Processing Income", "SALES_INCOME", "income", "revenue", True, 1170, "Income from job work, processing or conversion activity."), ("COMMISSION_INCOME", "Commission / Brokerage Income", "SALES_INCOME", "income", "revenue", True, 1180, "Commission, brokerage or intermediary income."), ("RENTAL_INCOME", "Rental / Hire Income", "SALES_INCOME", "income", "revenue", True, 1190, "Business rental, lease or hire income."), ("INTEREST_INCOME", "Interest Income", "SALES_INCOME", "income", "revenue", True, 1200, "Interest earned and accounted as income."), ("OTHER_OPERATING_INCOME", "Other Operating Income", "SALES_INCOME", "income", "revenue", True, 1210, "Other income arising from normal operations."), ("OTHER_INCOME", "Other Income", "SALES_INCOME", "income", "revenue", True, 1220, "Non-operating income not represented by a more specific nature."), ("ASSET_SALE", "Sale of Capital Asset", "SALES_INCOME", "income", "capital", True, 1230, "Disposal proceeds relating to capital assets; reviewer must determine final accounting treatment."), ("SALES_REVIEW_REQUIRED", "Sales / Income Review Required", "SALES_INCOME", "income", "review", True, 1290, "Fallback for outward transactions with insufficient evidence."), ] def ensure_sales_income_taxonomy(db, tenant_id: int, actor_user_id: int | None = None) -> int: existing = set( db.execute( select(AccountingNature.code).where(AccountingNature.tenant_id == int(tenant_id)) ).scalars().all() ) inserted = 0 for code, name, parent_code, group, cap_rev, posting, sort_order, description in SALES_INCOME_NATURES: if code in existing: continue db.add( AccountingNature( tenant_id=int(tenant_id), code=code, name=name, parent_code=parent_code, classification_group=group, capital_revenue=cap_rev, description=description, sort_order=sort_order, is_posting_nature=bool(posting), is_active=True, is_system_defined=True, created_by_user_id=actor_user_id, updated_by_user_id=actor_user_id, ) ) inserted += 1 if inserted: db.commit() return inserted def sales_income_natures(db, tenant_id: int): ensure_sales_income_taxonomy(db, tenant_id) return list( db.execute( select(AccountingNature).where( AccountingNature.tenant_id == int(tenant_id), AccountingNature.classification_group == "income", AccountingNature.is_posting_nature.is_(True), AccountingNature.is_active.is_(True), ).order_by(AccountingNature.sort_order, AccountingNature.name) ).scalars().all() )