TVA BREAKDOWN
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
"""CRUD operations for receipts."""
|
||||
|
||||
import json
|
||||
from datetime import datetime, date
|
||||
from typing import Optional, List, Tuple
|
||||
from decimal import Decimal
|
||||
from typing import Optional, List, Tuple, Any
|
||||
from sqlalchemy import select, func, or_
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
@@ -10,6 +12,31 @@ from app.db.models.receipt import Receipt, ReceiptStatus
|
||||
from app.schemas.receipt import ReceiptCreate, ReceiptUpdate, ReceiptFilter
|
||||
|
||||
|
||||
def _serialize_tva_breakdown(tva_breakdown: Optional[List[Any]]) -> Optional[str]:
|
||||
"""Serialize TVA breakdown list to JSON string for SQLite storage."""
|
||||
if tva_breakdown is None:
|
||||
return None
|
||||
|
||||
# Convert Decimal to float for JSON serialization
|
||||
serializable = []
|
||||
for entry in tva_breakdown:
|
||||
if hasattr(entry, 'model_dump'):
|
||||
# Pydantic model
|
||||
item = entry.model_dump()
|
||||
elif isinstance(entry, dict):
|
||||
item = entry.copy()
|
||||
else:
|
||||
item = dict(entry)
|
||||
|
||||
# Convert Decimal to float
|
||||
if 'amount' in item and isinstance(item['amount'], Decimal):
|
||||
item['amount'] = float(item['amount'])
|
||||
|
||||
serializable.append(item)
|
||||
|
||||
return json.dumps(serializable)
|
||||
|
||||
|
||||
class ReceiptCRUD:
|
||||
"""CRUD operations for Receipt model."""
|
||||
|
||||
@@ -20,8 +47,12 @@ class ReceiptCRUD:
|
||||
created_by: str,
|
||||
) -> Receipt:
|
||||
"""Create a new receipt."""
|
||||
# Get data as dict and serialize tva_breakdown to JSON string
|
||||
receipt_data = data.model_dump()
|
||||
receipt_data['tva_breakdown'] = _serialize_tva_breakdown(receipt_data.get('tva_breakdown'))
|
||||
|
||||
receipt = Receipt(
|
||||
**data.model_dump(),
|
||||
**receipt_data,
|
||||
created_by=created_by,
|
||||
status=ReceiptStatus.DRAFT,
|
||||
)
|
||||
@@ -132,6 +163,10 @@ class ReceiptCRUD:
|
||||
"""Update receipt fields."""
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
|
||||
# Serialize tva_breakdown to JSON string if present
|
||||
if 'tva_breakdown' in update_data:
|
||||
update_data['tva_breakdown'] = _serialize_tva_breakdown(update_data['tva_breakdown'])
|
||||
|
||||
for field, value in update_data.items():
|
||||
setattr(receipt, field, value)
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
"""Pydantic schemas for receipts API."""
|
||||
|
||||
import json
|
||||
from datetime import datetime, date
|
||||
from decimal import Decimal
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional, List, Any, Union
|
||||
from pydantic import BaseModel, Field, ConfigDict, field_validator
|
||||
|
||||
from app.db.models.receipt import ReceiptType, ReceiptDirection, ReceiptStatus
|
||||
from app.db.models.accounting_entry import EntryType
|
||||
@@ -148,6 +149,21 @@ class ReceiptResponse(ReceiptBase):
|
||||
attachments: List[AttachmentResponse] = []
|
||||
entries: List[AccountingEntryResponse] = []
|
||||
|
||||
@field_validator('tva_breakdown', mode='before')
|
||||
@classmethod
|
||||
def parse_tva_breakdown(cls, v: Any) -> Optional[List[dict]]:
|
||||
"""Deserialize tva_breakdown from JSON string if needed."""
|
||||
if v is None:
|
||||
return None
|
||||
if isinstance(v, str):
|
||||
try:
|
||||
return json.loads(v)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
return None
|
||||
if isinstance(v, list):
|
||||
return v
|
||||
return None
|
||||
|
||||
|
||||
class ReceiptListResponse(BaseModel):
|
||||
"""Schema for paginated receipt list response."""
|
||||
|
||||
Reference in New Issue
Block a user