mirror of
https://github.com/sortedcord/alemno-payments.git
synced 2026-07-22 20:22:51 +05:30
refactor: Add JobSummary and Transaction models, client to get currency exchange rate
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
from app.db.base import Base
|
||||
from app.db.models.job import Job
|
||||
from app.db.models.transaction import Transaction
|
||||
from app.db.models.job_summary import JobSummary
|
||||
|
||||
__all__ = ["Base", "Job"]
|
||||
__all__ = ["Base", "Job", "Transaction", "JobSummary"]
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
from __future__ import annotations
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, Optional
|
||||
from sqlalchemy import String, Integer, DateTime, JSON, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from typing import List, Optional, TYPE_CHECKING
|
||||
from sqlalchemy import DateTime, Integer, String, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from app.db.base import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.db.models.transaction import Transaction
|
||||
from app.db.models.job_summary import JobSummary
|
||||
|
||||
|
||||
class Job(Base):
|
||||
__tablename__ = "jobs"
|
||||
@@ -21,24 +26,31 @@ class Job(Base):
|
||||
default="pending",
|
||||
index=True,
|
||||
)
|
||||
row_count: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
||||
row_count_raw: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
||||
row_count_clean: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
server_default=func.now(),
|
||||
nullable=False,
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
completed_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
nullable=False,
|
||||
)
|
||||
# JSON summaries and results
|
||||
summary: Mapped[Optional[Dict[str, Any]]] = mapped_column(
|
||||
JSON,
|
||||
nullable=True,
|
||||
)
|
||||
results: Mapped[Optional[Dict[str, Any]]] = mapped_column(
|
||||
JSON,
|
||||
error_message: Mapped[Optional[str]] = mapped_column(
|
||||
String(500),
|
||||
nullable=True,
|
||||
)
|
||||
|
||||
# Relationships
|
||||
transactions: Mapped[List["Transaction"]] = relationship(
|
||||
"Transaction",
|
||||
back_populates="job",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
summary: Mapped[Optional["JobSummary"]] = relationship(
|
||||
"JobSummary",
|
||||
back_populates="job",
|
||||
cascade="all, delete-orphan",
|
||||
uselist=False,
|
||||
)
|
||||
|
||||
38
app/db/models/job_summary.py
Normal file
38
app/db/models/job_summary.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from __future__ import annotations
|
||||
import uuid
|
||||
from typing import Any, Dict, Optional, TYPE_CHECKING
|
||||
from sqlalchemy import Float, ForeignKey, Integer, JSON, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from app.db.base import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.db.models.job import Job
|
||||
|
||||
|
||||
class JobSummary(Base):
|
||||
__tablename__ = "job_summaries"
|
||||
|
||||
id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
primary_key=True,
|
||||
default=lambda: str(uuid.uuid4()),
|
||||
index=True,
|
||||
)
|
||||
job_id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
ForeignKey("jobs.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
unique=True,
|
||||
index=True,
|
||||
)
|
||||
total_spend_inr: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
|
||||
total_spend_usd: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
|
||||
top_merchants: Mapped[Dict[str, Any]] = mapped_column(
|
||||
JSON, nullable=False, default=dict
|
||||
)
|
||||
anomaly_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
narrative: Mapped[Optional[str]] = mapped_column(String(2000), nullable=True)
|
||||
risk_level: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
|
||||
|
||||
# Relationships
|
||||
job: Mapped["Job"] = relationship("Job", back_populates="summary")
|
||||
43
app/db/models/transaction.py
Normal file
43
app/db/models/transaction.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from __future__ import annotations
|
||||
import uuid
|
||||
from datetime import date
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from sqlalchemy import Boolean, Date, Float, ForeignKey, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from app.db.base import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.db.models.job import Job
|
||||
|
||||
|
||||
class Transaction(Base):
|
||||
__tablename__ = "transactions"
|
||||
|
||||
id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
primary_key=True,
|
||||
default=lambda: str(uuid.uuid4()),
|
||||
index=True,
|
||||
)
|
||||
job_id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
ForeignKey("jobs.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
txn_id: Mapped[str] = mapped_column(String(100), nullable=False)
|
||||
date: Mapped[date] = mapped_column(Date, nullable=False)
|
||||
merchant: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
amount: Mapped[float] = mapped_column(Float, nullable=False)
|
||||
currency: Mapped[str] = mapped_column(String(10), nullable=False, default="INR")
|
||||
status: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
|
||||
category: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
|
||||
account_id: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
|
||||
is_anomaly: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
anomaly_reason: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
|
||||
llm_category: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
|
||||
llm_raw_response: Mapped[Optional[str]] = mapped_column(String(1000), nullable=True)
|
||||
llm_failed: Mapped[Optional[bool]] = mapped_column(Boolean, default=False)
|
||||
|
||||
# Relationships
|
||||
job: Mapped["Job"] = relationship("Job", back_populates="transactions")
|
||||
Reference in New Issue
Block a user