""" LEDGER CSV Importer """ from typing import Dict, List, Any from datetime import date from sqlalchemy.orm import Session from .base import BaseCSVImporter, ImportValidationError from app.models.ledger import Ledger from app.models.files import File class LedgerCSVImporter(BaseCSVImporter): """CSV importer for LEDGER table""" @property def table_name(self) -> str: return "ledger" @property def required_fields(self) -> List[str]: return ["file_no", "date", "t_code", "t_type", "empl_num", "amount"] @property def field_mapping(self) -> Dict[str, str]: """Map CSV headers to database field names""" return { "file_no": "file_no", "item_no": "item_no", "date": "date", "t_code": "t_code", "t_type": "t_type", "t_type_l": "t_type_l", "empl_num": "empl_num", "quantity": "quantity", "rate": "rate", "amount": "amount", "billed": "billed", "note": "note" } def create_model_instance(self, row_data: Dict[str, Any]) -> Ledger: """Create a Ledger instance from processed row data""" # Validate required fields required_checks = [ ("file_no", "File number"), ("date", "Date"), ("t_code", "Transaction code"), ("t_type", "Transaction type"), ("empl_num", "Employee number"), ("amount", "Amount") ] for field, display_name in required_checks: if not row_data.get(field): raise ImportValidationError(f"{display_name} is required") # Validate foreign key exists (file number) file_exists = self.db_session.query(File).filter_by(file_no=row_data["file_no"]).first() if not file_exists: raise ImportValidationError(f"File number '{row_data['file_no']}' does not exist") # Parse date try: transaction_date = self.parse_date(row_data["date"]) except ValueError as e: raise ImportValidationError(f"Invalid date: {e}") # Parse numeric fields try: item_no = 1 # Default if row_data.get("item_no"): item_no = self.parse_int(row_data["item_no"]) if item_no < 1: raise ImportValidationError("Item number must be positive") except ValueError as e: raise ImportValidationError(f"Invalid item number: {e}") try: quantity = self.parse_float(row_data.get("quantity", "0")) rate = self.parse_float(row_data.get("rate", "0")) amount = self.parse_float(row_data["amount"]) except ValueError as e: raise ImportValidationError(f"Invalid numeric value: {e}") # Validate transaction code and type t_code = self.normalize_string(row_data["t_code"], 10) t_type = self.normalize_string(row_data["t_type"], 1) t_type_l = self.normalize_string(row_data.get("t_type_l", ""), 1) # Validate billed field (Y/N) billed = row_data.get("billed", "N").strip().upper() if billed not in ["Y", "N", ""]: billed = "N" # Default to N if invalid # Create instance ledger = Ledger( file_no=self.normalize_string(row_data["file_no"], 45), item_no=item_no, date=transaction_date, t_code=t_code, t_type=t_type, t_type_l=t_type_l, empl_num=self.normalize_string(row_data["empl_num"], 10), quantity=quantity, rate=rate, amount=amount, billed=billed, note=row_data.get("note", "") # Text field ) return ledger