TorbatYar/backend/services/accounting/app/repositories/posting.py
Mortezakoohjani 12c8615615 Ship enterprise Accounting FE/API with CRUD parity and production wiring.
Adds accounting-service PATCH/archive, fiscal helpers, COA templates and setup status, plus SuperApp Accounting UI (DS, scoreboard, masters, vouchers, ledger, ops modules) with session refresh and HTTPS public API URLs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-24 15:26:43 +03:30

109 lines
3.5 KiB
Python

"""Posting repositories."""
from __future__ import annotations
from uuid import UUID
from sqlalchemy import select
from sqlalchemy.orm import selectinload
from app.models.posting import (
AccountingAuditLog,
JournalEntry,
PostingError,
PostingLog,
PostingReference,
Voucher,
VoucherLine,
)
from app.models.types import VoucherStatus
from app.repositories.base import TenantBaseRepository
class VoucherRepository(TenantBaseRepository[Voucher]):
model = Voucher
async def get_with_lines(self, tenant_id: UUID, voucher_id: UUID) -> Voucher | None:
stmt = (
select(Voucher)
.options(selectinload(Voucher.lines))
.where(Voucher.tenant_id == tenant_id, Voucher.id == voucher_id)
)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()
async def get_by_number(self, tenant_id: UUID, voucher_number: str) -> Voucher | None:
stmt = select(Voucher).where(
Voucher.tenant_id == tenant_id, Voucher.voucher_number == voucher_number
)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()
async def list_by_status(self, tenant_id: UUID, status: VoucherStatus, *, limit: int = 50):
stmt = (
select(Voucher)
.where(Voucher.tenant_id == tenant_id, Voucher.status == status)
.limit(limit)
)
result = await self.session.execute(stmt)
return result.scalars().all()
class VoucherLineRepository(TenantBaseRepository[VoucherLine]):
model = VoucherLine
class JournalEntryRepository(TenantBaseRepository[JournalEntry]):
model = JournalEntry
async def list_by_voucher(self, tenant_id: UUID, voucher_id: UUID):
stmt = select(JournalEntry).where(
JournalEntry.tenant_id == tenant_id,
JournalEntry.voucher_id == voucher_id,
)
result = await self.session.execute(stmt)
return result.scalars().all()
async def list_by_account(self, tenant_id: UUID, account_id: UUID, *, limit: int = 100):
stmt = (
select(JournalEntry)
.where(
JournalEntry.tenant_id == tenant_id,
JournalEntry.account_id == account_id,
)
.limit(limit)
)
result = await self.session.execute(stmt)
return result.scalars().all()
class PostingLogRepository(TenantBaseRepository[PostingLog]):
model = PostingLog
class PostingErrorRepository(TenantBaseRepository[PostingError]):
model = PostingError
class PostingReferenceRepository(TenantBaseRepository[PostingReference]):
model = PostingReference
async def get_by_source(
self,
tenant_id: UUID,
source_module: str,
source_document_type: str,
source_document_id: str,
) -> PostingReference | None:
stmt = select(PostingReference).where(
PostingReference.tenant_id == tenant_id,
PostingReference.source_module == source_module,
PostingReference.source_document_type == source_document_type,
PostingReference.source_document_id == source_document_id,
)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()
class AuditLogRepository(TenantBaseRepository[AccountingAuditLog]):
model = AccountingAuditLog