backbone-banking 0.7.1

Cash & bank — bank/account master, statement import, reconciliation, and clearing postings (5th GL producer)
Documentation
//! Repository for FxGainLoss entities
//!
//! Originally generated by metaphor-schema; now **user-owned** — this exact path is declared under
//! `user_owned` in `metaphor.codegen.yaml`, so the generator skips it wholesale. The custom method
//! below holds the FX gain/loss insert (4-layer rule: services orchestrate, repos hold SQL).
//!
//! Thin newtype over `backbone_orm::GenericCrudRepository<FxGainLoss, backbone_orm::SoftDelete>`.
//! All standard CRUD methods are available via `Deref`.

use anyhow::Result;
use rust_decimal::Decimal;
use sqlx::{PgConnection, PgPool};
use uuid::Uuid;

use crate::domain::entity::FxGainLoss;

/// Table name for FxGainLoss entities
pub const TABLE_NAME: &str = "banking.fx_gain_losses";

/// Repository for FxGainLoss entities.
///
/// All standard CRUD, soft-delete, pagination, and bulk methods are
/// provided automatically via `Deref` to `backbone_orm::GenericCrudRepository`.
pub struct FxGainLossRepository(
    backbone_orm::GenericCrudRepository<FxGainLoss, backbone_orm::SoftDelete>,
);

impl std::ops::Deref for FxGainLossRepository {
    type Target = backbone_orm::GenericCrudRepository<FxGainLoss, backbone_orm::SoftDelete>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl FxGainLossRepository {
    /// Create a new repository instance.
    pub fn new(pool: PgPool) -> Self {
        Self(backbone_orm::GenericCrudRepository::new(pool, TABLE_NAME))
    }
}

/// The exact row a realised-FX-gain/loss insert writes.
pub struct NewFxGainLossRow<'a> {
    pub id: Uuid,
    pub bank_clearance_id: Option<Uuid>,
    pub matched_source_id: Uuid,
    pub currency: &'a str,
    pub original_rate: Decimal,
    pub realised_rate: Decimal,
    pub base_amount_delta: Decimal,
    pub direction: &'a str,
    pub fx_account_id: Uuid,
}

/// FX gain/loss SQL. Lives here (not in the service) per the module's 4-layer rule.
impl FxGainLossRepository {
    /// Record a realised FX gain/loss on the caller's tx. The caller has already relayed the
    /// ambient org scope onto `conn` (ADR-0029).
    pub async fn insert_gain_loss(
        &self,
        conn: &mut PgConnection,
        r: &NewFxGainLossRow<'_>,
    ) -> Result<(), sqlx::Error> {
        sqlx::query(
            r#"INSERT INTO banking.fx_gain_losses
                 (id, bank_clearance_id, matched_source_id, currency,
                  original_rate, realised_rate, base_amount_delta, direction, fx_account_id)
               VALUES ($1, $2, $3, $4, $5, $6, $7, $8::fx_direction, $9)"#,
        )
        .bind(r.id)
        .bind(r.bank_clearance_id)
        .bind(r.matched_source_id)
        .bind(r.currency)
        .bind(r.original_rate)
        .bind(r.realised_rate)
        .bind(r.base_amount_delta)
        .bind(r.direction)
        .bind(r.fx_account_id)
        .execute(conn)
        .await?;
        Ok(())
    }
}

backbone_core::impl_crud_repository!(FxGainLossRepository, FxGainLoss, soft_delete);