Use invoice items instead of amount

This commit is contained in:
Jon Staab
2026-03-31 11:22:20 -07:00
parent 15394f55d2
commit 8018950ba9
6 changed files with 60 additions and 9 deletions
+4 -4
View File
@@ -696,7 +696,7 @@ async fn list_invoices(
let pubkey = state.api.extract_auth_pubkey(&headers)?;
state.api.require_admin(&pubkey)?;
match state.api.repo.list_invoices().await {
match state.api.repo.list_invoices_with_items().await {
Ok(invoices) => Ok(ok(StatusCode::OK, invoices)),
Err(e) => Ok(err(
StatusCode::INTERNAL_SERVER_ERROR,
@@ -714,7 +714,7 @@ async fn list_tenant_invoices(
let auth = state.api.extract_auth_pubkey(&headers)?;
state.api.require_admin_or_tenant(&auth, &pubkey)?;
match state.api.repo.list_invoices_for_tenant(&pubkey).await {
match state.api.repo.list_invoices_for_tenant_with_items(&pubkey).await {
Ok(invoices) => Ok(ok(StatusCode::OK, invoices)),
Err(e) => Ok(err(
StatusCode::INTERNAL_SERVER_ERROR,
@@ -731,7 +731,7 @@ async fn get_invoice(
) -> std::result::Result<Response, ApiError> {
let auth = state.api.extract_auth_pubkey(&headers)?;
let invoice = match state.api.repo.get_invoice(&id).await {
let invoice = match state.api.repo.get_invoice_with_items(&id).await {
Ok(Some(i)) => i,
Ok(None) => return Ok(err(StatusCode::NOT_FOUND, "not-found", "invoice not found")),
Err(e) => {
@@ -743,7 +743,7 @@ async fn get_invoice(
}
};
state.api.require_admin_or_tenant(&auth, &invoice.tenant)?;
state.api.require_admin_or_tenant(&auth, &invoice.invoice.tenant)?;
Ok(ok(StatusCode::OK, invoice))
}
+7
View File
@@ -75,3 +75,10 @@ pub struct InvoiceItem {
pub relay: String,
pub sats: i64,
}
#[derive(Debug, Clone, Serialize)]
pub struct InvoiceWithItems {
#[serde(flatten)]
pub invoice: Invoice,
pub items: Vec<InvoiceItem>,
}
+34 -1
View File
@@ -7,7 +7,7 @@ use sqlx::{
sqlite::{SqliteConnectOptions, SqlitePoolOptions},
};
use crate::models::{Activity, Invoice, InvoiceItem, Plan, Relay, Tenant};
use crate::models::{Activity, Invoice, InvoiceItem, InvoiceWithItems, Plan, Relay, Tenant};
#[derive(Clone)]
pub struct Repo {
@@ -529,6 +529,39 @@ impl Repo {
Ok(rows)
}
pub async fn list_invoices_with_items(&self) -> Result<Vec<InvoiceWithItems>> {
let invoices = self.list_invoices().await?;
let mut result = Vec::with_capacity(invoices.len());
for invoice in invoices {
let items = self.get_invoice_items(&invoice.id).await?;
result.push(InvoiceWithItems { invoice, items });
}
Ok(result)
}
pub async fn list_invoices_for_tenant_with_items(
&self,
tenant_id: &str,
) -> Result<Vec<InvoiceWithItems>> {
let invoices = self.list_invoices_for_tenant(tenant_id).await?;
let mut result = Vec::with_capacity(invoices.len());
for invoice in invoices {
let items = self.get_invoice_items(&invoice.id).await?;
result.push(InvoiceWithItems { invoice, items });
}
Ok(result)
}
pub async fn get_invoice_with_items(&self, id: &str) -> Result<Option<InvoiceWithItems>> {
match self.get_invoice(id).await? {
Some(invoice) => {
let items = self.get_invoice_items(&invoice.id).await?;
Ok(Some(InvoiceWithItems { invoice, items }))
}
None => Ok(None),
}
}
pub async fn get_invoice_items(&self, invoice_id: &str) -> Result<Vec<InvoiceItem>> {
let rows = sqlx::query_as::<_, InvoiceItem>(
"SELECT id, invoice, relay, sats
+4 -2
View File
@@ -51,6 +51,8 @@ export default function PaymentDialog(props: PaymentDialogProps) {
props.onClose()
}
const totalSats = () => props.invoice.items.reduce((sum, item) => sum + item.sats, 0)
const periodLabel = () => {
const start = new Date(props.invoice.period_start * 1000)
const end = new Date(props.invoice.period_end * 1000)
@@ -69,9 +71,9 @@ export default function PaymentDialog(props: PaymentDialogProps) {
<div class="flex items-start justify-between gap-3">
<div>
<h2 class="text-lg font-semibold text-gray-900">Pay Invoice</h2>
<Show when={props.invoice.amount}>
<Show when={totalSats() > 0}>
<p class="text-2xl font-bold text-gray-900 mt-1">
{props.invoice.amount.toLocaleString()} <span class="text-base font-normal text-gray-500">sats</span>
{totalSats().toLocaleString()} <span class="text-base font-normal text-gray-500">sats</span>
</p>
</Show>
<Show when={props.invoice.period_start && props.invoice.period_end}>
+8 -1
View File
@@ -100,11 +100,18 @@ export type Tenant = {
billing_anchor: number
}
export type InvoiceItem = {
id: string
invoice: string
relay: string
sats: number
}
export type Invoice = {
id: string
tenant: string
status: string
amount: number
items: InvoiceItem[]
created_at: number
attempted_at: number
error: string
+3 -1
View File
@@ -133,7 +133,9 @@ export default function Account() {
<div class="flex items-center justify-between gap-3">
<div>
<span class="font-medium text-gray-900">
{invoice.amount ? `${invoice.amount.toLocaleString()} sats` : "—"}
{invoice.items.length > 0
? `${invoice.items.reduce((sum, item) => sum + item.sats, 0).toLocaleString()} sats`
: "—"}
</span>
<Show when={invoice.period_start && invoice.period_end}>
<p class="text-xs text-gray-500 mt-0.5">{periodLabel()}</p>