New application for entering fiscal receipts (bonuri fiscale) with: Backend (FastAPI + SQLModel + Alembic): - Receipt, ReceiptAttachment, AccountingEntry models - CRUD operations with async SQLite database - Workflow: DRAFT → PENDING_REVIEW → APPROVED/REJECTED - Auto-generation of accounting entries with VAT calculation - File upload support (images, PDFs) - Predefined expense types (Fuel, Materials, Office, etc.) - Nomenclature service for partners, accounts, cash registers Frontend (Vue.js 3 + PrimeVue + Pinia): - ReceiptsListView with filters and stats - ReceiptCreateView with image upload - ReceiptDetailView with accounting entries - ReceiptApprovalView for accountant approval Documentation: - REQUIREMENTS.md with functional specifications - ARCHITECTURE.md with technical decisions - CLAUDE.md for AI assistant guidance Phase 1 MVP uses SQLite, prepared for Oracle integration in Phase 2. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
165 lines
5.8 KiB
Python
165 lines
5.8 KiB
Python
"""Service for fetching nomenclatures from Oracle (read-only)."""
|
|
|
|
from typing import List, Optional
|
|
from decimal import Decimal
|
|
|
|
from app.schemas.receipt import (
|
|
PartnerOption,
|
|
AccountOption,
|
|
CashRegisterOption,
|
|
ExpenseTypeOption,
|
|
)
|
|
from app.services.expense_types import EXPENSE_TYPES
|
|
|
|
|
|
class NomenclatureService:
|
|
"""
|
|
Service for fetching nomenclatures.
|
|
|
|
In Phase 1 (MVP), some nomenclatures are hardcoded.
|
|
In Phase 2, these will be fetched from Oracle.
|
|
"""
|
|
|
|
@staticmethod
|
|
async def get_partners(company_id: int, search: Optional[str] = None) -> List[PartnerOption]:
|
|
"""
|
|
Get partners (suppliers/customers) for a company.
|
|
|
|
Phase 1: Returns empty list or mock data.
|
|
Phase 2: Will fetch from Oracle NOM_PARTENERI.
|
|
"""
|
|
# TODO: Implement Oracle fetch in Phase 2
|
|
# For now, return some mock data for testing
|
|
mock_partners = [
|
|
PartnerOption(id=1, name="OMV Petrom", code="RO123456"),
|
|
PartnerOption(id=2, name="Dedeman", code="RO789012"),
|
|
PartnerOption(id=3, name="Kaufland", code="RO345678"),
|
|
PartnerOption(id=4, name="Emag", code="RO901234"),
|
|
PartnerOption(id=5, name="Altex", code="RO567890"),
|
|
]
|
|
|
|
if search:
|
|
search_lower = search.lower()
|
|
mock_partners = [
|
|
p for p in mock_partners
|
|
if search_lower in p.name.lower() or (p.code and search_lower in p.code.lower())
|
|
]
|
|
|
|
return mock_partners
|
|
|
|
@staticmethod
|
|
async def get_accounts(company_id: int, prefix: Optional[str] = None) -> List[AccountOption]:
|
|
"""
|
|
Get chart of accounts for a company.
|
|
|
|
Phase 1: Returns common expense/income accounts.
|
|
Phase 2: Will fetch from Oracle PLAN_CONTURI.
|
|
"""
|
|
# Common accounts for expenses and receipts
|
|
accounts = [
|
|
# Expense accounts (Class 6)
|
|
AccountOption(code="6022", name="Cheltuieli cu combustibilii"),
|
|
AccountOption(code="6024", name="Cheltuieli materiale pentru ambalat"),
|
|
AccountOption(code="6028", name="Alte cheltuieli cu materiale consumabile"),
|
|
AccountOption(code="624", name="Cheltuieli cu transportul de bunuri si personal"),
|
|
AccountOption(code="626", name="Cheltuieli postale si taxe telecomunicatii"),
|
|
AccountOption(code="628", name="Alte cheltuieli cu serviciile executate de terti"),
|
|
|
|
# VAT
|
|
AccountOption(code="4426", name="TVA deductibila"),
|
|
AccountOption(code="4427", name="TVA colectata"),
|
|
|
|
# Cash and Bank (Class 5)
|
|
AccountOption(code="5311", name="Casa in lei"),
|
|
AccountOption(code="5121", name="Conturi la banci in lei"),
|
|
|
|
# Income accounts (Class 7)
|
|
AccountOption(code="7588", name="Alte venituri din exploatare"),
|
|
]
|
|
|
|
if prefix:
|
|
accounts = [a for a in accounts if a.code.startswith(prefix)]
|
|
|
|
return accounts
|
|
|
|
@staticmethod
|
|
async def get_cash_registers(company_id: int) -> List[CashRegisterOption]:
|
|
"""
|
|
Get cash registers and bank accounts for a company.
|
|
|
|
Phase 1: Returns default options.
|
|
Phase 2: Will fetch from Oracle NOM_CASE / NOM_BANCI.
|
|
"""
|
|
# Default cash registers
|
|
return [
|
|
CashRegisterOption(id=1, name="Casa principala", account_code="5311"),
|
|
CashRegisterOption(id=2, name="Cont BCR", account_code="5121"),
|
|
CashRegisterOption(id=3, name="Cont BRD", account_code="5121"),
|
|
]
|
|
|
|
@staticmethod
|
|
async def get_expense_types() -> List[ExpenseTypeOption]:
|
|
"""
|
|
Get predefined expense types with their accounting configuration.
|
|
"""
|
|
return [
|
|
ExpenseTypeOption(
|
|
code=et.code,
|
|
name=et.name,
|
|
account_code=et.account_code,
|
|
has_vat=et.has_vat,
|
|
vat_percent=et.vat_percent,
|
|
)
|
|
for et in EXPENSE_TYPES.values()
|
|
]
|
|
|
|
@staticmethod
|
|
async def get_companies(username: str) -> List[dict]:
|
|
"""
|
|
Get companies accessible by user.
|
|
|
|
Phase 1: Returns mock data.
|
|
Phase 2: Will fetch from shared auth based on user permissions.
|
|
"""
|
|
# TODO: Integrate with shared auth to get user's companies
|
|
return [
|
|
{"id": 1, "name": "SC Test SRL", "cui": "RO12345678"},
|
|
{"id": 2, "name": "SC Demo SA", "cui": "RO87654321"},
|
|
]
|
|
|
|
# ============ Phase 2 Oracle Integration Methods ============
|
|
|
|
@staticmethod
|
|
async def _fetch_partners_oracle(company_id: int, search: Optional[str] = None) -> List[PartnerOption]:
|
|
"""
|
|
Fetch partners from Oracle NOM_PARTENERI.
|
|
|
|
Will be implemented in Phase 2.
|
|
"""
|
|
# TODO: Implement using shared oracle_pool
|
|
# Example query:
|
|
# SELECT ID_PART, DEN_PART, COD_FISCAL
|
|
# FROM {schema}.NOM_PARTENERI
|
|
# WHERE DEN_PART LIKE :search
|
|
raise NotImplementedError("Oracle integration pending - Phase 2")
|
|
|
|
@staticmethod
|
|
async def _fetch_accounts_oracle(company_id: int, prefix: Optional[str] = None) -> List[AccountOption]:
|
|
"""
|
|
Fetch chart of accounts from Oracle PLAN_CONTURI.
|
|
|
|
Will be implemented in Phase 2.
|
|
"""
|
|
# TODO: Implement using shared oracle_pool
|
|
raise NotImplementedError("Oracle integration pending - Phase 2")
|
|
|
|
@staticmethod
|
|
async def _fetch_cash_registers_oracle(company_id: int) -> List[CashRegisterOption]:
|
|
"""
|
|
Fetch cash registers from Oracle NOM_CASE / NOM_BANCI.
|
|
|
|
Will be implemented in Phase 2.
|
|
"""
|
|
# TODO: Implement using shared oracle_pool
|
|
raise NotImplementedError("Oracle integration pending - Phase 2")
|