feat: Add client extraction, amount cross-validation, and workflow fixes

OCR improvements:
- Extract client data (name, CUI, address) from B2B receipts
- Cross-validate amounts using payment methods and TVA entries
- OCR-tolerant patterns for "TOTAL LEI" with common OCR errors
- Better BON FISCAL vs CHITANTA detection

Backend workflow fixes:
- Fix SQLAlchemy deleted instance error in resubmit/submit workflow
- Add session.refresh() after deleting accounting entries
- Add unapprove endpoint (APPROVED → PENDING_REVIEW)
- Add direction filter for receipt listing

Frontend improvements:
- Fix Vue v-else-if chain broken by Menu component
- Unified OCR Preview layout with values table
- Receipt list filter by direction (plati/incasari)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-17 23:16:10 +02:00
parent 93185120df
commit a90d9093de
12 changed files with 3125 additions and 855 deletions

View File

@@ -29,7 +29,7 @@ from app.schemas.receipt import (
CashRegisterOption,
ExpenseTypeOption,
)
from app.db.models.receipt import ReceiptStatus
from app.db.models.receipt import ReceiptStatus, ReceiptDirection
# Auth integration
from auth.dependencies import get_current_user
@@ -121,6 +121,7 @@ async def create_receipt(
@router.get("/", response_model=ReceiptListResponse)
async def list_receipts(
status: Optional[ReceiptStatus] = None,
direction: Optional[ReceiptDirection] = None,
company_id: Optional[int] = None,
created_by: Optional[str] = None,
date_from: Optional[str] = None,
@@ -136,6 +137,7 @@ async def list_receipts(
filters = ReceiptFilter(
status=status,
direction=direction,
company_id=company_id or selected_company,
created_by=created_by,
date_from=date_type.fromisoformat(date_from) if date_from else None,
@@ -301,6 +303,24 @@ async def resubmit_receipt(
)
@router.post("/{receipt_id}/unapprove", response_model=WorkflowAction)
async def unapprove_receipt(
receipt_id: int,
session: AsyncSession = Depends(get_session),
current_user: CurrentUser = Depends(get_current_user),
):
"""Unapprove receipt (APPROVED → PENDING_REVIEW). Returns to pending for corrections."""
success, message, receipt = await ReceiptService.unapprove_receipt(
session, receipt_id, current_user.username
)
return WorkflowAction(
success=success,
message=message,
receipt=ReceiptResponse.model_validate(receipt) if receipt else None,
)
# ============ Accounting Entries Endpoints ============
@router.get("/{receipt_id}/entries", response_model=List[AccountingEntryResponse])