use anyhow::Result;
use rust_decimal::Decimal;
use sqlx::{PgPool, Row};
use uuid::Uuid;
use backbone_orm::org_scope::fetch_all_rows_scoped;
use crate::domain::entity::PosInvoiceItem;
pub const TABLE_NAME: &str = "pos.pos_invoice_items";
pub struct PosInvoiceItemRepository(
backbone_orm::GenericCrudRepository<PosInvoiceItem, backbone_orm::SoftDelete>,
);
impl std::ops::Deref for PosInvoiceItemRepository {
type Target = backbone_orm::GenericCrudRepository<PosInvoiceItem, backbone_orm::SoftDelete>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl PosInvoiceItemRepository {
pub fn new(pool: PgPool) -> Self {
Self(backbone_orm::GenericCrudRepository::new(pool, TABLE_NAME))
}
}
pub struct NewInvoiceItemRow<'a> {
pub id: Uuid,
pub pos_invoice_id: Uuid,
pub client_uuid: Option<Uuid>,
pub item_id: Uuid,
pub description: Option<&'a str>,
pub course: Option<i32>,
pub quantity: Decimal,
pub unit_price: Decimal,
pub discount_amount: Decimal,
pub net_amount: Decimal,
pub revenue_account_id: Option<Uuid>,
}
pub struct RevenueLineRow {
pub item_id: Uuid,
pub net_amount: Decimal,
pub revenue_account_id: Option<Uuid>,
}
pub struct QuantityLineRow {
pub item_id: Uuid,
pub quantity: Decimal,
}
pub struct ReceiptLineRow {
pub description: Option<String>,
pub item_id: Uuid,
pub course: Option<i32>,
pub quantity: Decimal,
pub unit_price: Decimal,
pub discount_amount: Decimal,
pub net_amount: Decimal,
}
impl PosInvoiceItemRepository {
pub async fn insert_line(
&self,
conn: &mut sqlx::PgConnection,
l: &NewInvoiceItemRow<'_>,
) -> Result<(), sqlx::Error> {
sqlx::query(
r#"INSERT INTO pos.pos_invoice_items
(id, pos_invoice_id, client_uuid, item_id, description, course, quantity, unit_price, discount_amount, net_amount, revenue_account_id)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)"#,
)
.bind(l.id).bind(l.pos_invoice_id).bind(l.client_uuid).bind(l.item_id).bind(l.description).bind(l.course).bind(l.quantity)
.bind(l.unit_price).bind(l.discount_amount).bind(l.net_amount).bind(l.revenue_account_id)
.execute(conn)
.await?;
Ok(())
}
pub async fn fetch_revenue_lines(
&self,
pool: &PgPool,
pos_invoice_id: Uuid,
) -> Result<Vec<RevenueLineRow>, sqlx::Error> {
let rows = fetch_all_rows_scoped(
pool,
sqlx::query(
"SELECT item_id, net_amount, revenue_account_id FROM pos.pos_invoice_items WHERE pos_invoice_id=$1 AND (metadata->>'deleted_at') IS NULL",
)
.bind(pos_invoice_id),
)
.await?;
Ok(rows.iter().map(|r| RevenueLineRow {
item_id: r.get("item_id"), net_amount: r.get("net_amount"),
revenue_account_id: r.get("revenue_account_id"),
}).collect())
}
pub async fn fetch_quantity_lines(
&self,
pool: &PgPool,
pos_invoice_id: Uuid,
) -> Result<Vec<QuantityLineRow>, sqlx::Error> {
let rows = fetch_all_rows_scoped(
pool,
sqlx::query(
"SELECT item_id, quantity FROM pos.pos_invoice_items WHERE pos_invoice_id=$1 AND (metadata->>'deleted_at') IS NULL",
)
.bind(pos_invoice_id),
)
.await?;
Ok(rows.iter().map(|r| QuantityLineRow {
item_id: r.get("item_id"), quantity: r.get("quantity"),
}).collect())
}
pub async fn soft_delete_lines_for_ticket(
&self,
conn: &mut sqlx::PgConnection,
pos_invoice_id: Uuid,
now: chrono::DateTime<chrono::Utc>,
) -> Result<(), sqlx::Error> {
sqlx::query(
r#"UPDATE pos.pos_invoice_items
SET metadata = jsonb_set(COALESCE(metadata, '{}'::jsonb), '{deleted_at}', to_jsonb($2::timestamptz))
WHERE pos_invoice_id=$1 AND (metadata->>'deleted_at') IS NULL"#,
)
.bind(pos_invoice_id)
.bind(now)
.execute(conn)
.await?;
Ok(())
}
pub async fn fetch_receipt_lines(
&self,
pool: &PgPool,
pos_invoice_id: Uuid,
) -> Result<Vec<ReceiptLineRow>, sqlx::Error> {
let rows = fetch_all_rows_scoped(
pool,
sqlx::query(
"SELECT description, item_id, course, quantity, unit_price, discount_amount, net_amount
FROM pos.pos_invoice_items WHERE pos_invoice_id=$1 AND (metadata->>'deleted_at') IS NULL
ORDER BY (metadata->>'created_at')",
)
.bind(pos_invoice_id),
)
.await?;
Ok(rows.iter().map(|r| ReceiptLineRow {
description: r.get("description"), item_id: r.get("item_id"), course: r.get("course"),
quantity: r.get("quantity"),
unit_price: r.get("unit_price"), discount_amount: r.get("discount_amount"),
net_amount: r.get("net_amount"),
}).collect())
}
}
backbone_core::impl_crud_repository!(PosInvoiceItemRepository, PosInvoiceItem, soft_delete);