use async_trait::async_trait;
use chrono::{DateTime, NaiveDate, Utc};
use rust_decimal::Decimal;
use uuid::Uuid;
use crate::domain::gl_posting::PostingLine;
#[derive(Debug, Clone)]
pub struct PostableAccount {
pub id: Uuid,
pub number: String,
pub name: String,
pub account_type: String,
pub subtype: String,
pub normal_balance: String, pub is_detail: bool,
pub is_header: bool,
pub status: String,
pub current_balance: Decimal,
}
#[derive(Debug, Clone)]
pub struct LedgerEntryInput {
pub journal_line_id: Uuid,
pub line: PostingLine,
}
#[derive(Debug, Clone)]
pub struct PostingWrite {
pub company_id: Uuid,
pub branch_id: Option<Uuid>,
pub source_type: String,
pub source_id: Uuid,
pub source_reference: Option<String>,
pub posting_date: NaiveDate,
pub fiscal_period_id: Option<Uuid>,
pub fiscal_year: i32,
pub fiscal_month: i32,
pub currency: String,
pub posting_type: String,
pub reverses_post_id: Option<Uuid>,
pub reverses_journal_id: Option<Uuid>,
pub description: Option<String>,
pub idempotency_key: Option<String>,
pub posted_by: Option<Uuid>,
pub now: DateTime<Utc>,
pub lines: Vec<PostingLine>,
}
#[derive(Debug, Clone)]
pub struct PostingCommit {
pub post_id: Uuid,
pub journal_id: Uuid,
pub total_debit: Decimal,
pub total_credit: Decimal,
pub reused: bool,
}
#[derive(Debug, Clone)]
pub struct ReversalSource {
pub journal_id: Uuid,
pub lines: Vec<PostingLine>,
}
#[derive(Debug, Clone)]
pub struct ManualJournalForPost {
pub status: String,
pub journal_number: String,
pub branch_id: Option<Uuid>,
pub posting_date: NaiveDate,
pub fiscal_period_id: Option<Uuid>,
pub fiscal_year: i32,
pub fiscal_month: i32,
pub currency: String,
pub description: Option<String>,
pub source_type: String,
pub source_id: Uuid,
pub lines: Vec<(Uuid, PostingLine)>,
}
#[derive(Debug, Clone)]
pub struct ManualJournalCommit {
pub journal_id: Uuid,
pub company_id: Uuid,
pub branch_id: Option<Uuid>,
pub journal_number: String,
pub posting_date: NaiveDate,
pub fiscal_period_id: Option<Uuid>,
pub fiscal_year: i32,
pub fiscal_month: i32,
pub currency: String,
pub source_type: String,
pub source_id: Uuid,
pub description: Option<String>,
pub posted_by: Option<Uuid>,
pub now: DateTime<Utc>,
pub lines: Vec<LedgerEntryInput>,
}
#[derive(Debug, Clone)]
pub struct FailedPost {
pub company_id: Uuid,
pub branch_id: Option<Uuid>,
pub source_type: String,
pub source_id: Uuid,
pub source_reference: Option<String>,
pub posting_type: String,
pub currency: String,
pub total_debit: Decimal,
pub total_credit: Decimal,
pub failed_at: DateTime<Utc>,
pub error_code: String,
pub error_message: String,
}
#[async_trait]
pub trait PostingRepository: Send + Sync {
async fn find_existing_post(
&self,
source_type: &str,
source_id: Uuid,
posting_type: &str,
idempotency_key: Option<&str>,
) -> anyhow::Result<Option<(Uuid, Uuid)>>;
async fn find_postable_accounts(
&self,
ids: &[Uuid],
) -> anyhow::Result<Vec<PostableAccount>>;
async fn is_period_closed(&self, date: NaiveDate) -> anyhow::Result<bool>;
async fn find_period_id(
&self,
date: NaiveDate,
) -> anyhow::Result<Option<Uuid>>;
async fn find_reversal_source(
&self,
orig_post_id: Uuid,
) -> anyhow::Result<Option<ReversalSource>>;
async fn commit_posting(&self, write: PostingWrite) -> anyhow::Result<PostingCommit>;
async fn commit_posting_on(
&self,
conn: &mut sqlx::PgConnection,
write: PostingWrite,
) -> anyhow::Result<PostingCommit>;
async fn find_manual_journal_for_post(
&self,
journal_id: Uuid,
) -> anyhow::Result<Option<ManualJournalForPost>>;
async fn existing_post_for_journal(
&self,
journal_id: Uuid,
) -> anyhow::Result<Option<Uuid>>;
async fn commit_manual_journal(
&self,
commit: ManualJournalCommit,
) -> anyhow::Result<PostingCommit>;
async fn record_failed(&self, failed: FailedPost) -> anyhow::Result<()>;
}