294 lines
6.5 KiB
Python
294 lines
6.5 KiB
Python
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
from typing import List, Optional
|
|
|
|
from pydantic import BaseModel
|
|
|
|
|
|
@dataclass
|
|
class Address:
|
|
"""Address information for tax calculations"""
|
|
|
|
province: str
|
|
city: str
|
|
postal_code: str
|
|
country: str = "Canada"
|
|
|
|
|
|
@dataclass
|
|
class Receipt:
|
|
id: str
|
|
file_name: str
|
|
upload_date: datetime
|
|
receipt_date: datetime
|
|
amount: float
|
|
tax: float
|
|
vendor: str
|
|
category: str
|
|
description: str
|
|
# Tax rule fields
|
|
billing_address: Optional[Address] = None
|
|
shipping_address: Optional[Address] = None
|
|
currency: str = "CAD"
|
|
is_meals_entertainment: bool = False
|
|
|
|
|
|
@dataclass
|
|
class Transaction:
|
|
id: str
|
|
transaction_date: datetime
|
|
amount: float
|
|
vendor: str
|
|
notes: str
|
|
# Tax rule fields
|
|
currency: str = "CAD"
|
|
fx_rate: Optional[float] = None
|
|
|
|
|
|
@dataclass
|
|
class Asset:
|
|
"""Asset for depreciation calculations"""
|
|
|
|
id: str
|
|
name: str
|
|
purchase_date: datetime
|
|
purchase_amount: float
|
|
useful_life_years: int
|
|
residual_value: float
|
|
cca_rate: float # Capital Cost Allowance rate
|
|
asset_class: str
|
|
|
|
|
|
@dataclass
|
|
class Match:
|
|
receipt: Receipt
|
|
transaction: Transaction
|
|
confidence_score: float
|
|
match_reason: str
|
|
tax_analysis: Optional[dict] = None
|
|
|
|
|
|
class AddressRequest(BaseModel):
|
|
province: str
|
|
city: str
|
|
postal_code: str
|
|
country: str = "Canada"
|
|
|
|
|
|
class ReceiptRequest(BaseModel):
|
|
id: str
|
|
file_name: str
|
|
upload_date: datetime
|
|
receipt_date: datetime
|
|
amount: float
|
|
tax: float
|
|
vendor: str
|
|
category: str
|
|
description: str
|
|
# Tax rule fields
|
|
billing_address: Optional[AddressRequest] = None
|
|
shipping_address: Optional[AddressRequest] = None
|
|
currency: str = "CAD"
|
|
is_meals_entertainment: bool = False
|
|
|
|
|
|
class TransactionRequest(BaseModel):
|
|
id: str
|
|
transaction_date: datetime
|
|
amount: float
|
|
vendor: str
|
|
notes: str
|
|
# Tax rule fields
|
|
currency: str = "CAD"
|
|
fx_rate: Optional[float] = None
|
|
|
|
|
|
class AssetRequest(BaseModel):
|
|
id: str
|
|
name: str
|
|
purchase_date: datetime
|
|
purchase_amount: float
|
|
useful_life_years: int
|
|
residual_value: float
|
|
cca_rate: float
|
|
asset_class: str
|
|
|
|
|
|
class MatchingRequest(BaseModel):
|
|
receipt_ids: List[str]
|
|
transaction_ids: List[str]
|
|
|
|
|
|
class MatchResponse(BaseModel):
|
|
receipt_id: str
|
|
transaction_id: str
|
|
confidence_score: float
|
|
match_reason: str
|
|
receipt_vendor: str
|
|
receipt_amount: float
|
|
receipt_description: str
|
|
receipt_category: str
|
|
receipt_tax_amount: float
|
|
transaction_vendor: str
|
|
transaction_amount: float
|
|
tax_analysis: Optional[dict] = None
|
|
|
|
|
|
class MatchingResponse(BaseModel):
|
|
matches: List[MatchResponse]
|
|
stats: dict
|
|
|
|
|
|
class ApprovalRequest(BaseModel):
|
|
match_id: str
|
|
approved: bool
|
|
reason: Optional[str] = None
|
|
|
|
|
|
class RuleRequest(BaseModel):
|
|
name: str
|
|
condition: str
|
|
action: str
|
|
source: str = "user"
|
|
|
|
|
|
class DocumentUploadResponse(BaseModel):
|
|
file_id: str
|
|
filename: str
|
|
file_type: str
|
|
upload_date: datetime
|
|
status: str
|
|
|
|
|
|
class DocumentProcessRequest(BaseModel):
|
|
file_id: Optional[str] = None
|
|
user_location: Optional[str] = (
|
|
None # Format: "State/Province, Country" (e.g., "Ontario, Canada")
|
|
)
|
|
|
|
|
|
class DocumentProcessResponse(BaseModel):
|
|
file_id: str
|
|
receipt_id: str
|
|
extraction_success: bool
|
|
vendor: Optional[str] = None
|
|
description: Optional[str] = None
|
|
total_amount: Optional[float] = None
|
|
tax_amount: Optional[float] = None
|
|
date: Optional[str] = None
|
|
category: Optional[str] = None
|
|
confidence: Optional[float] = None
|
|
error: Optional[str] = None
|
|
receipt_currency: Optional[str] = "CAD"
|
|
receipt_location: Optional[str] = (
|
|
None # Location from receipt (e.g., "Ontario, Canada" or "California, USA")
|
|
)
|
|
calculated_tax: Optional[float] = None # Calculated sales tax if not clearly shown
|
|
is_depreciable: Optional[bool] = None # Whether item is a depreciable asset
|
|
cca_rate: Optional[float] = (
|
|
None # CCA rate for tax depreciation (e.g., 0.30 for 30%)
|
|
)
|
|
useful_life: Optional[int] = (
|
|
None # Useful life in years for straight-line depreciation
|
|
)
|
|
residual_value: Optional[float] = (
|
|
None # Residual value for straight-line depreciation
|
|
)
|
|
|
|
|
|
# New tax-related models
|
|
class TaxCalculationRequest(BaseModel):
|
|
receipt_id: str
|
|
transaction_id: Optional[str] = None
|
|
|
|
|
|
class TaxCalculationResponse(BaseModel):
|
|
receipt_id: str
|
|
rules_applied: List[str]
|
|
sales_tax: dict
|
|
fx_analysis: Optional[dict] = None
|
|
meals_entertainment: dict
|
|
|
|
|
|
class DepreciationRequest(BaseModel):
|
|
asset: AssetRequest
|
|
year: int
|
|
method: str # "straight_line" or "cca"
|
|
|
|
|
|
class DepreciationResponse(BaseModel):
|
|
asset_id: str
|
|
year: int
|
|
method: str
|
|
depreciation: float
|
|
book_value: float
|
|
total_depreciation: Optional[float] = None
|
|
success: bool
|
|
error: Optional[str] = None
|
|
|
|
|
|
class CityInfo(BaseModel):
|
|
"""City information from user tax info"""
|
|
|
|
id: int
|
|
name: str
|
|
state_id: int
|
|
state_code: str
|
|
country_id: int
|
|
country_code: str
|
|
latitude: Optional[str] = None
|
|
longitude: Optional[str] = None
|
|
|
|
|
|
class StateInfo(BaseModel):
|
|
"""State/Province information from user tax info"""
|
|
|
|
id: int
|
|
name: str
|
|
country_id: int
|
|
country_code: str
|
|
state_code: str
|
|
|
|
|
|
class CountryInfo(BaseModel):
|
|
"""Country information from user tax info"""
|
|
|
|
id: int
|
|
name: str
|
|
iso3: str
|
|
iso2: str
|
|
phone_code: str
|
|
capital: str
|
|
currency: str
|
|
native: Optional[str] = None
|
|
region: Optional[str] = None
|
|
subregion: Optional[str] = None
|
|
emoji: Optional[str] = None
|
|
emojiU: Optional[str] = None
|
|
|
|
|
|
class UserTaxInfo(BaseModel):
|
|
"""User tax information for location-based tax calculations"""
|
|
|
|
id: int
|
|
user_id: int
|
|
company_name: str
|
|
tax_id: Optional[str] = ""
|
|
tax_id_type: Optional[str] = "EIN"
|
|
address_line_1: Optional[str] = ""
|
|
address_line_2: Optional[str] = ""
|
|
city: CityInfo
|
|
state: StateInfo
|
|
zip_postal_code: Optional[str] = ""
|
|
country: CountryInfo
|
|
include_on_invoices: Optional[int] = 1
|
|
created_at: Optional[str] = None
|
|
updated_at: Optional[str] = None
|
|
|
|
|
|
class MatchSpecificRequest(BaseModel):
|
|
file_ids: List[str]
|
|
categorization_id: str
|
|
user_location: Optional[str] = "Canada" # Kept for backward compatibility
|
|
user_tax_info: Optional[UserTaxInfo] = None
|