Skip to main content

backbone_pos/infrastructure/persistence/
pos_discount_repository_custom.rs

1//! Hand-written PosDiscount reads (user-owned, never regenerated) — the custom methods on
2//! [`PosDiscountRepository`]. Sibling to the generated newtype file, per the module's custom-code
3//! convention. Holds the SQL per the 4-layer rule: services orchestrate, repositories hold SQL.
4//!
5//! The order-level discount master is the server-side source of the discount RATE: a ring names a
6//! discount by id, and the percentage applied is ALWAYS the one stored on the caller's scoped
7//! master row — never a rate echoed back by the client (the offline-sync trust posture: client
8//! identity, server money).
9
10use rust_decimal::Decimal;
11use sqlx::Row;
12use uuid::Uuid;
13
14use crate::infrastructure::persistence::PosDiscountRepository;
15
16/// A discount master row as the ticket compute reads it: the percentage is a FRACTION (0.1 = 10%),
17/// stored `decimal(6,4)` exactly like the register's retired flat tax rate was.
18pub struct DiscountRow {
19    pub id: Uuid,
20    pub name: String,
21    pub percentage: Decimal,
22}
23
24impl PosDiscountRepository {
25    /// Read one discount master row by id, on the CALLER'S scope-relayed transaction (the discount
26    /// gate runs inside the ring/sync unit of work). `Ok(None)` = no such discount visible to the
27    /// caller's scope (soft-deleted masters are retired — a ring naming one is refused, not silently
28    /// discounted). The fence is the whole guard (ADR-0029).
29    pub async fn fetch_discount(
30        &self,
31        conn: &mut sqlx::PgConnection,
32        discount_id: Uuid,
33    ) -> Result<Option<DiscountRow>, sqlx::Error> {
34        let row = sqlx::query(
35            r#"SELECT id, name, percentage
36               FROM pos.pos_discounts
37               WHERE id=$1 AND (metadata->>'deleted_at') IS NULL"#,
38        )
39        .bind(discount_id)
40        .fetch_optional(conn)
41        .await?;
42        Ok(row.map(|r| DiscountRow {
43            id: r.get("id"),
44            name: r.get("name"),
45            percentage: r.get("percentage"),
46        }))
47    }
48}