Files
roa2web-service-auto/docs/data-entry/DATA-ENTRY-MODULE.md
Claude Agent b137e80b71 feat: multi-Oracle server support with runtime switching
Complete implementation of multi-server Oracle database support:

Backend:
- Multi-pool Oracle with lazy loading per server
- Email-to-server cache for automatic server discovery
- JWT tokens include server_id claim
- /auth/check-identity and /auth/check-email endpoints
- /auth/my-servers endpoint for listing user's accessible servers
- Server switch with password re-authentication

Frontend:
- New ServerSelector component for header dropdown
- Multi-step login flow (identity → server → password)
- Server switching from header with password modal
- Mobile drawer menu with server selection
- Dark mode support for all new components
- URL bookmark support with ?server= query param

Scripts:
- Unified start.sh replacing start-prod.sh/start-test.sh
- Unified ssh-tunnel.sh with multi-server support
- Updated status.sh for new architecture

Tests:
- E2E tests for multi-server and single-server login flows
- Backend unit tests for all new endpoints
- Oracle multi-pool integration tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 22:39:06 +00:00

12 KiB

Data Entry Module - Technical Reference

Part of ROA2WEB Ultrathin Monolith - See CLAUDE.md for general architecture

Module Overview

Purpose: Introducere date în ERP (bonuri fiscale, chitanțe) cu workflow de aprobare

Location:

  • Backend: backend/modules/data_entry/
  • Frontend: src/modules/data-entry/
  • Database: backend/modules/data/receipts/receipts.db (SQLite)
  • Uploads: backend/modules/data/receipts/uploads/

API Base Path: /api/data-entry/


Technical Stack

Backend:

  • ORM: SQLModel (Pydantic + SQLAlchemy)
  • Migrations: Alembic
  • Database: SQLite (Phase 1) → Oracle integration (Phase 2)
  • Validation: Pydantic v2

Frontend:

  • Framework: Vue.js 3 Composition API
  • UI Library: PrimeVue
  • State: Pinia stores
  • Routing: Vue Router (integrated with main app)

Workflow States

1. DRAFT
   ↓ User completes form + uploads receipt photo

2. PENDING_REVIEW
   ↓ System auto-generates accounting entries

3. APPROVED / REJECTED
   ↓ Accountant approves or rejects
   ↓ (if rejected, user can resubmit)

4. SYNCED
   └→ (Phase 2) Data synced to Oracle ERP

State Transitions

From To Allowed Action Who
DRAFT PENDING_REVIEW Submit for review User
DRAFT DRAFT Update/Delete User
PENDING_REVIEW APPROVED Approve Accountant
PENDING_REVIEW REJECTED Reject Accountant
REJECTED PENDING_REVIEW Resubmit User
APPROVED SYNCED Sync to Oracle System (Phase 2)

Database Schema (SQLite)

Main Tables

receipts - Receipt header

  • id (PK)
  • receipt_number - Document number
  • receipt_date - Document date
  • partner_id - Supplier ID (from Oracle)
  • partner_name - Supplier name
  • partner_cui - Supplier CUI/CIF
  • receipt_type - BON/CHITANTA/FACTURA
  • operation_type - EXPENSE/INCOME
  • total_amount - Total with VAT
  • vat_amount - VAT amount
  • payment_method - CASH/CARD/BANK
  • payment_amount - Amount paid
  • expense_type_code - Expense type (FUEL, MATERIALS, etc.)
  • description - Notes
  • status - DRAFT/PENDING/APPROVED/REJECTED/SYNCED
  • rejection_reason - If rejected
  • created_by - Username
  • approved_by - Accountant username
  • company_id - Company ID from Oracle

attachments - Receipt photos/PDFs

  • id (PK)
  • receipt_id (FK)
  • filename - Original filename
  • file_path - Storage path
  • mime_type - image/*, application/pdf
  • file_size - Bytes
  • uploaded_at

accounting_entries - Auto-generated entries

  • id (PK)
  • receipt_id (FK)
  • account_code - Cont contabil (e.g., "6022")
  • debit_amount - Debit
  • credit_amount - Credit
  • description - Entry description
  • entry_order - Sequence number

Migrations

Location: backend/modules/data_entry/migrations/

# Create new migration
cd backend/modules/data_entry
alembic revision --autogenerate -m "description"

# Apply migrations
alembic upgrade head

# Rollback
alembic downgrade -1

Important: Migrations run automatically on module startup via lifespan event in main.py.


Expense Types (Hardcoded - Phase 1)

Code Type Account VAT Description
FUEL Combustibil 6022 19% Combustibil auto
MATERIALS Materiale 6028 19% Materiale consumabile
OFFICE Rechizite 6024 19% Rechizite birou
PHONE Telefonie 626 19% Servicii telefonie
PARKING Parcare 6022 19% Taxe parcare
FOOD Alimentație 6028 0% Alimente (fără TVA)
TRANSPORT Transport 624 19% Transport marfă
OTHER Altele 628 19% Alte cheltuieli

Auto-generation Logic:

When user submits receipt, system automatically generates:

# Entry 1: Expense account (Debit)
account_code = expense_type.account  # e.g., "6022"
debit_amount = total_amount - vat_amount
credit_amount = 0

# Entry 2: VAT account (Debit) - if VAT > 0
account_code = "4426"  # TVA deductibilă
debit_amount = vat_amount
credit_amount = 0

# Entry 3: Payment account (Credit)
account_code = cash_register.account  # e.g., "5311"
debit_amount = 0
credit_amount = total_amount

Oracle Nomenclatures (Read-Only)

Module uses shared Oracle connection for nomenclatures:

Partners (Suppliers)

Query:

SELECT B.ID_PART, B.DENUMIRE, B.COD_FISCAL, B.ADRESA
FROM {schema}.CORESP_TIP_PART A
INNER JOIN {schema}.VNOM_PARTENERI B ON A.ID_PART = B.ID_PART
WHERE A.ID_TIP_PART = 17  -- Furnizori
  AND (B.INACTIV = 0 OR B.INACTIV IS NULL)
ORDER BY B.DENUMIRE

Partner Types (id_tip_part):

  • 17 - Furnizori (Suppliers)
  • 22 - Casa LEI (Cash LEI)
  • 23 - Casa Valută (Cash FX)
  • 24 - Bancă LEI (Bank LEI)
  • 25 - Bancă Valută (Bank FX)

Cash Registers & Bank Accounts

Query:

SELECT B.ID_PART, B.DENUMIRE, B.COD_FISCAL, B.CONT
FROM {schema}.CORESP_TIP_PART A
INNER JOIN {schema}.VNOM_PARTENERI B ON A.ID_PART = B.ID_PART
WHERE A.ID_TIP_PART IN (22, 23, 24, 25)
  AND (B.INACTIV = 0 OR B.INACTIV IS NULL)
ORDER BY B.DENUMIRE

Account Mapping:

  • Casa LEI → Account 5311
  • Casa Valută → Account 5314
  • Bancă LEI → Account 5121
  • Bancă Valută → Account 5124

Oracle Integration (Phase 2)

Sync Process

When receipt is APPROVED, sync to Oracle using stored procedures:

-- 1. Initialize
EXEC {schema}.pack_contafin.init_scriere_act_rul_local(
    p_id_utilizator => :user_id,
    p_id_baza => :company_id,
    p_id_luna => :month_id
);

-- 2. Insert temp document
INSERT INTO {schema}.ACT_TEMP (
    ID_ACT, DATA_ACT, NR_DOCUMENT, ID_PART,
    TIP_ACT, STARE_ACT, ...
) VALUES (
    :act_id, :receipt_date, :receipt_number, :partner_id,
    'CUMPARARE', 'TEMP', ...
);

-- 3. Insert temp entries
INSERT INTO {schema}.ACT_TEMP_RUL (
    ID_ACT, CONT, SUMA_D, SUMA_C, EXPLICATIE
) VALUES (
    :act_id, :account_code, :debit, :credit, :description
);

-- 4. Finalize
EXEC {schema}.pack_contafin.finalizeaza_scriere_act_rul(
    p_id_utilizator => :user_id,
    p_id_act => :act_id
);

Stored Procedures:

  • pack_contafin.init_scriere_act_rul_local() - Initialize transaction
  • pack_contafin.finalizeaza_scriere_act_rul() - Commit to permanent tables
  • pack_contafin.get_next_act_id() - Get next document ID

Reference: See docs/PACK_CONTAFIN.pck for full stored procedure definitions.


API Endpoints

Receipts CRUD

List Receipts

GET /api/data-entry/receipts/
Query params: page, page_size, status, search, date_from, date_to

Get Receipt

GET /api/data-entry/receipts/{id}

Create Receipt

POST /api/data-entry/receipts/
Body: ReceiptCreate schema

Update Receipt (DRAFT only)

PUT /api/data-entry/receipts/{id}
Body: ReceiptUpdate schema

Delete Receipt (DRAFT only)

DELETE /api/data-entry/receipts/{id}

Workflow Actions

Submit for Review

POST /api/data-entry/receipts/{id}/submit
Status: DRAFT → PENDING_REVIEW
Auto-generates accounting entries

Approve

POST /api/data-entry/receipts/{id}/approve
Body: { "notes": "Optional approval notes" }
Status: PENDING_REVIEW → APPROVED

Reject

POST /api/data-entry/receipts/{id}/reject
Body: { "reason": "Rejection reason (required)" }
Status: PENDING_REVIEW → REJECTED

Resubmit (after rejection)

POST /api/data-entry/receipts/{id}/resubmit
Status: REJECTED → PENDING_REVIEW

Attachments

Upload

POST /api/data-entry/receipts/{id}/attachments
Content-Type: multipart/form-data
Field: file (image/*, application/pdf, max 10MB)

Download

GET /api/data-entry/attachments/{id}/download
Response: File stream

Delete

DELETE /api/data-entry/attachments/{id}

Nomenclatures

Partners (from Oracle)

GET /api/data-entry/receipts/nomenclature/partners
Query: search (optional)

Cash Registers (from Oracle)

GET /api/data-entry/receipts/nomenclature/cash-registers

Expense Types (hardcoded)

GET /api/data-entry/receipts/nomenclature/expense-types

Statistics

GET /api/data-entry/receipts/stats
Response: { total, by_status: { DRAFT: N, ... } }

Frontend Components

Views

Location: src/modules/data-entry/views/

  • ReceiptListView.vue - Main list with filters and status tabs
  • ReceiptCreateView.vue - Create/edit form
  • ReceiptDetailView.vue - View receipt details (future)

Key Components

Location: src/modules/data-entry/components/

  • ReceiptForm.vue - Main form component
  • AttachmentUpload.vue - Drag & drop file upload
  • AccountingEntriesTable.vue - Preview generated entries
  • WorkflowActions.vue - Approve/Reject buttons

Stores

Location: src/modules/data-entry/stores/

  • receiptsStore.js - Main receipts CRUD
  • nomenclatureStore.js - Partners, cash registers, expense types

Common Issues

1. Nomenclatoare goale / furnizori lipsă

Symptom: Partner dropdown is empty

Causes:

  • Wrong Oracle server (PROD vs TEST)
  • Selected company doesn't exist on current server
  • No suppliers configured for company

Solution:

# Check SSH tunnel status (for servers requiring SSH)
./ssh-tunnel.sh status

# Restart with correct environment
./start.sh prod  # or ./start.sh test (test uses direct connection)

2. SQLite locked errors

Symptom: database is locked

Causes:

  • Multiple backend instances accessing same DB
  • Alembic migration in progress

Solution:

# Check for multiple processes
ps aux | grep uvicorn

# Kill duplicates, restart
./start.sh prod restart

3. Upload fails

Symptom: 500 error on file upload

Causes:

  • File too large (>10MB)
  • Wrong MIME type
  • Upload directory permissions

Solution:

# Check upload directory
ls -la backend/modules/data/receipts/uploads/

# Create if missing
mkdir -p backend/modules/data/receipts/uploads/
chmod 755 backend/modules/data/receipts/uploads/

4. Migration errors

Symptom: Alembic fails on startup

Solution:

cd backend/modules/data_entry

# Check migration status
alembic current

# Rollback one version
alembic downgrade -1

# Re-apply
alembic upgrade head

Testing

Backend Tests

cd backend
pytest modules/data_entry/tests/

Frontend Tests

cd src/modules/data-entry
npm run test

Manual Testing

Test Workflow:

  1. Login as user (e.g., MARIUS M)
  2. Create receipt → status DRAFT
  3. Upload attachment
  4. Submit → status PENDING_REVIEW
  5. Login as accountant
  6. Approve/Reject
  7. Verify accounting entries generated correctly

Development Workflow

1. Start Development Environment

# Start unified monolith (backend + frontend)
./start.sh prod  # Production Oracle server
# OR
./start.sh test  # Test Oracle server

2. Make Changes

Backend:

  • Edit files in backend/modules/data_entry/
  • Uvicorn auto-reloads on file changes

Frontend:

  • Edit files in src/modules/data-entry/
  • Vite HMR auto-updates browser

3. Database Changes

cd backend/modules/data_entry

# Generate migration
alembic revision --autogenerate -m "Add new field"

# Review migration file
nano migrations/versions/xxx_add_new_field.py

# Apply
alembic upgrade head

4. Testing

# Backend
cd backend
pytest modules/data_entry/tests/ -v

# Frontend
cd src/modules/data-entry
npm run test

Production Deployment

See deployment/windows/ for Windows deployment scripts.

Module Activation:

Enabled via .env flag:

MODULE_DATA_ENTRY_ENABLED=true

Database Location:

  • Development: backend/modules/data/receipts/receipts.db
  • Production: C:\inetpub\wwwroot\roa2web\backend\modules\data\receipts\receipts.db

Uploads Location:

  • Development: backend/modules/data/receipts/uploads/
  • Production: C:\inetpub\wwwroot\roa2web\backend\modules\data\receipts\uploads\

Future Enhancements (Phase 2)

  1. Oracle Sync Implementation

    • Complete sync_to_oracle() function
    • Error handling and retry logic
    • Sync status tracking
  2. OCR Integration

    • Automatic data extraction from photos
    • Pre-fill form fields
    • Confidence scores
  3. Approval Notifications

    • Email notifications to accountants
    • User notifications on approval/rejection
    • Telegram bot integration
  4. Bulk Operations

    • Batch approve/reject
    • Bulk upload
    • Excel import
  5. Advanced Reporting

    • Expense analytics by type
    • Supplier spending reports
    • Monthly summaries

Last Updated: 2025-12-29 Architecture: Ultrathin Monolith (integrated module)