feat: Add data-entry-app for fiscal receipts with approval workflow
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>
This commit is contained in:
275
docs/data-entry/ARCHITECTURE.md
Normal file
275
docs/data-entry/ARCHITECTURE.md
Normal file
@@ -0,0 +1,275 @@
|
||||
# Architecture: Data Entry App
|
||||
|
||||
## Overview
|
||||
|
||||
Aplicatie separata pentru introducere date in ERP, cu workflow de aprobare si staging area inainte de sincronizare in Oracle.
|
||||
|
||||
## Decizii Arhitecturale
|
||||
|
||||
### 1. SQLModel + Alembic
|
||||
|
||||
**Alegere**: SQLModel (Pydantic + SQLAlchemy) cu Alembic pentru migrari
|
||||
|
||||
**Motivatie**:
|
||||
- Creat de autorul FastAPI - integrare perfecta
|
||||
- Un model = Pydantic + SQLAlchemy - nu duplici definitii
|
||||
- Async support nativ
|
||||
- Alembic - standard industrial pentru migrari
|
||||
- Validare automata - Pydantic valideaza input, SQLAlchemy gestioneaza DB
|
||||
|
||||
**Alternative considerate**:
|
||||
- SQLAlchemy pur: Mai verbose, necesita scheme Pydantic separate
|
||||
- Tortoise ORM: Async nativ dar comunitate mai mica
|
||||
- Peewee: Simplu dar fara async
|
||||
|
||||
### 2. Separare de Reports-App
|
||||
|
||||
**Alegere**: Aplicatie separata in `data-entry-app/`
|
||||
|
||||
**Motivatie**:
|
||||
- Responsabilitati diferite: reports = read-only, data-entry = write
|
||||
- Lifecycle diferit: data-entry poate avea releases mai frecvente
|
||||
- Risc izolat: bug in data-entry nu afecteaza raportarile
|
||||
- Scalare independenta
|
||||
|
||||
**Shared Components**:
|
||||
- `shared/database/oracle_pool.py` - conexiune Oracle pentru nomenclatoare
|
||||
- `shared/auth/` - autentificare JWT comuna
|
||||
|
||||
### 3. Workflow cu Staging Area
|
||||
|
||||
**Alegere**: SQLite local ca staging, apoi sync in Oracle
|
||||
|
||||
**Motivatie**:
|
||||
- Permite lucru offline (utilizator poate completa bonuri)
|
||||
- Review de contabil inainte de date in Oracle
|
||||
- Rollback simplu (stergem din SQLite)
|
||||
- Audit trail complet
|
||||
|
||||
**Flow**:
|
||||
```
|
||||
User Input → SQLite (staging) → Contabil Review → Oracle (final)
|
||||
```
|
||||
|
||||
### 4. Storage Fisiere
|
||||
|
||||
**Alegere**: Filesystem local cu referinte in DB
|
||||
|
||||
**Motivatie**:
|
||||
- Simplu de implementat si backup
|
||||
- Performanta buna pentru imagini
|
||||
- Poate migra la S3/Azure Blob daca e nevoie
|
||||
|
||||
**Structura**:
|
||||
```
|
||||
data/uploads/
|
||||
{year}/
|
||||
{month}/
|
||||
{uuid}.{ext}
|
||||
```
|
||||
|
||||
## Diagrama Componente
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ data-entry-app │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Frontend │────▶│ Backend │────▶│ SQLite │ │
|
||||
│ │ Vue.js │ │ FastAPI │ │ (staging) │ │
|
||||
│ │ :3010 │ │ :8003 │ │ │ │
|
||||
│ └──────────────┘ └──────┬───────┘ └──────────────┘ │
|
||||
│ │ │
|
||||
│ │ Nomenclatoare │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ Oracle │ │
|
||||
│ │ (read-only) │ │
|
||||
│ └──────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Model de Date
|
||||
|
||||
### Receipt (Bon Fiscal)
|
||||
|
||||
```
|
||||
receipts
|
||||
├── id (PK)
|
||||
├── receipt_type: enum(bon_fiscal, chitanta)
|
||||
├── direction: enum(cheltuiala, incasare)
|
||||
├── receipt_number, receipt_series
|
||||
├── receipt_date, amount, description
|
||||
├── company_id, partner_id, partner_name
|
||||
├── cash_register_id, cash_register_name
|
||||
├── expense_type_code
|
||||
├── status: enum(draft, pending_review, approved, rejected, synced)
|
||||
├── created_by, created_at, updated_at
|
||||
├── submitted_at, reviewed_by, reviewed_at
|
||||
├── rejection_reason
|
||||
└── oracle_synced_at, oracle_act_id, oracle_error
|
||||
```
|
||||
|
||||
### ReceiptAttachment (Atasamente)
|
||||
|
||||
```
|
||||
receipt_attachments
|
||||
├── id (PK)
|
||||
├── receipt_id (FK)
|
||||
├── filename, stored_filename
|
||||
├── file_path, file_size, mime_type
|
||||
└── uploaded_at
|
||||
```
|
||||
|
||||
### AccountingEntry (Note Contabile)
|
||||
|
||||
```
|
||||
accounting_entries
|
||||
├── id (PK)
|
||||
├── receipt_id (FK)
|
||||
├── entry_type: enum(debit, credit)
|
||||
├── account_code, account_name
|
||||
├── amount
|
||||
├── partner_id, cost_center_id
|
||||
├── is_auto_generated
|
||||
└── modified_by, modified_at
|
||||
```
|
||||
|
||||
## Workflow States
|
||||
|
||||
```
|
||||
┌─────────┐
|
||||
│ DRAFT │◀────────────────────┐
|
||||
└────┬────┘ │
|
||||
│ submit() │ (edit after reject)
|
||||
▼ │
|
||||
┌──────────────┐ │
|
||||
│PENDING_REVIEW│──────────────────┤
|
||||
└──────┬───────┘ │
|
||||
│ │
|
||||
┌─────┴─────┐ │
|
||||
▼ ▼ │
|
||||
┌────────┐ ┌────────┐ │
|
||||
│APPROVED│ │REJECTED│──────────────┘
|
||||
└────┬───┘ └────────┘ resubmit()
|
||||
│
|
||||
│ (Faza 2)
|
||||
▼
|
||||
┌──────┐
|
||||
│SYNCED│
|
||||
└──────┘
|
||||
```
|
||||
|
||||
## Generare Note Contabile
|
||||
|
||||
### Algoritm
|
||||
|
||||
```python
|
||||
def generate_entries(receipt):
|
||||
expense_type = EXPENSE_TYPES[receipt.expense_type_code]
|
||||
entries = []
|
||||
|
||||
if expense_type.has_vat:
|
||||
net_amount = receipt.amount / Decimal('1.19')
|
||||
vat_amount = receipt.amount - net_amount
|
||||
|
||||
# Cheltuiala (debit)
|
||||
entries.append(Entry(DEBIT, expense_type.account, net_amount))
|
||||
# TVA (debit)
|
||||
entries.append(Entry(DEBIT, "4426", vat_amount))
|
||||
else:
|
||||
entries.append(Entry(DEBIT, expense_type.account, receipt.amount))
|
||||
|
||||
# Credit casa/banca
|
||||
entries.append(Entry(CREDIT, receipt.cash_register_account, receipt.amount))
|
||||
|
||||
return entries
|
||||
```
|
||||
|
||||
### Exemplu: Bon Benzina 200 RON
|
||||
|
||||
```
|
||||
Debit 6022 Cheltuieli combustibil 168.07
|
||||
Debit 4426 TVA deductibila 31.93
|
||||
Credit 5311 Casa in lei 200.00
|
||||
```
|
||||
|
||||
## Integrare Oracle (Faza 2)
|
||||
|
||||
### Proceduri Stocate
|
||||
|
||||
```sql
|
||||
-- 1. Initializare
|
||||
pack_contafin.init_scriere_act_rul_local()
|
||||
|
||||
-- 2. Insert linii
|
||||
INSERT INTO ACT_TEMP (
|
||||
ID_ACT, DATAIREG, DATAACT, SCD, ASCD, SCC, ASCC,
|
||||
SUMA, ID_CTR, ID_PARTD, EXPLICATIA, ...
|
||||
)
|
||||
|
||||
-- 3. Finalizare
|
||||
pack_contafin.finalizeaza_scriere_act_rul()
|
||||
→ SCRIE_IN_ACT()
|
||||
→ SCRIE_IN_RUL()
|
||||
→ Actualizare situatii (BV, BP, TVA)
|
||||
```
|
||||
|
||||
## Securitate
|
||||
|
||||
### Autentificare
|
||||
- JWT tokens din shared auth
|
||||
- Middleware valideaza token si injecteaza user
|
||||
|
||||
### Autorizare
|
||||
- Permisiuni verificate in services
|
||||
- Utilizator poate edita doar bonurile proprii in DRAFT
|
||||
- Doar contabil poate aproba/respinge
|
||||
|
||||
### Upload Fisiere
|
||||
- Validare MIME type (whitelist)
|
||||
- Sanitizare nume fisier
|
||||
- Limita dimensiune (10MB)
|
||||
- Stocare cu UUID (previne path traversal)
|
||||
|
||||
## Configuratie
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
# SQLite Database
|
||||
SQLITE_DATABASE_PATH=data/receipts.db
|
||||
|
||||
# File Storage
|
||||
UPLOAD_PATH=data/uploads
|
||||
MAX_UPLOAD_SIZE=10485760 # 10MB
|
||||
|
||||
# Oracle (pentru nomenclatoare)
|
||||
ORACLE_USER=CONTAFIN_ORACLE
|
||||
ORACLE_PASSWORD=***
|
||||
ORACLE_HOST=localhost
|
||||
ORACLE_PORT=1526
|
||||
ORACLE_SID=ROA
|
||||
|
||||
# JWT (shared)
|
||||
JWT_SECRET_KEY=***
|
||||
JWT_ALGORITHM=HS256
|
||||
```
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- CRUD operations
|
||||
- Workflow transitions
|
||||
- Entry generation logic
|
||||
|
||||
### Integration Tests
|
||||
- API endpoints
|
||||
- File upload/download
|
||||
- Oracle nomenclature fetch
|
||||
|
||||
### E2E Tests
|
||||
- Complete workflow: create → submit → approve
|
||||
- File upload cu preview
|
||||
Reference in New Issue
Block a user