Skip to content

Commit

Permalink
feat: allow listing all invoices
Browse files Browse the repository at this point in the history
  • Loading branch information
jooakar committed Feb 1, 2024
1 parent 9d5dc7a commit 7e58a99
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The application is based on [axum](https://github.com/tokio-rs/axum):
## Features/TODO:
* [x] create invoice + validation
* [ ] create user + authentication
* [ ] list invoices
* [x] list invoices
* [ ] edit invoice
* [ ] ratelimits
* [ ] generate pdf
Expand Down
9 changes: 9 additions & 0 deletions src/api/invoices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,12 @@ pub async fn create(
axum::Json(conn.create_invoice(multipart.data.clone()).await?),
))
}

pub async fn list_all(
mut conn: DatabaseConnection
) -> Result<(StatusCode, Json<Vec<PopulatedInvoice>>), Error> {
Ok((
StatusCode::OK,
axum::Json(conn.list_invoices().await?),
))
}
1 change: 1 addition & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub fn app() -> Router<crate::database::State> {
Router::new()
.route("/health", get(health))
.route("/invoices", post(invoices::create))
.route("/invoices", get(invoices::list_all))
.layer(TraceLayer::new_for_http())
.layer(DefaultBodyLimit::disable())
.layer(RequestBodyLimitLayer::new(
Expand Down
41 changes: 41 additions & 0 deletions src/database/invoices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,45 @@ impl DatabaseConnection {
attachments,
})
}
pub async fn list_invoices(&mut self) -> Result<Vec<PopulatedInvoice>, Error> {
let (invoices, parties): (Vec<Invoice>, Vec<Party>) = {
use crate::schema::parties;
use crate::schema::invoices;
invoices::table
.inner_join(parties::table)
.select((Invoice::as_select(), Party::as_select()))
.load::<(Invoice, Party)>(&mut self.0)
.await?
.into_iter()
.unzip()
};
let invoice_rows = InvoiceRow::belonging_to(&invoices)
.select(InvoiceRow::as_select())
.load(&mut self.0)
.await?
.grouped_by(&invoices);
let attachments = Attachment::belonging_to(&invoices)
.select(Attachment::as_select())
.load(&mut self.0)
.await?
.grouped_by(&invoices);
Ok(invoice_rows
.into_iter()
.zip(attachments)
.zip(invoices)
.zip(parties)
.map(|(((rows, attachments), invoice), party)| {
PopulatedInvoice {
id: invoice.id,
status: invoice.status,
creation_time: invoice.creation_time,
counter_party: party,
rows,
due_date: invoice.due_date,
attachments,
}
})
.collect::<Vec<PopulatedInvoice>>()
)
}
}
12 changes: 8 additions & 4 deletions src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use chrono::{DateTime, NaiveDate, Utc};
use garde::Validate;

use serde_derive::{Deserialize, Serialize};
use diesel::prelude::*;

// NOTES:
// This is implemented based on https://github.com/Tietokilta/laskugeneraattori/blob/main/backend/src/procountor.rs#L293
Expand All @@ -24,7 +25,7 @@ pub enum InvoiceStatus {
}

/// A party of the invoice
#[derive(Identifiable, Queryable, Clone, Debug, Serialize)]
#[derive(Identifiable, Queryable, Selectable, Clone, Debug, Serialize)]
#[diesel(table_name = parties)]
pub struct Party {
pub id: i32,
Expand Down Expand Up @@ -61,7 +62,8 @@ pub struct NewParty {
}

/// The invoice model as stored in the database
#[derive(Identifiable, Queryable, Clone, Debug)]
#[derive(Identifiable, Queryable, Selectable, Associations, Clone, Debug)]
#[diesel(belongs_to(Party, foreign_key = counter_party_id))]
#[diesel(table_name = invoices)]
pub struct Invoice {
pub id: i32,
Expand All @@ -81,7 +83,8 @@ pub struct NewInvoice {
}

/// A single row of an invoice
#[derive(Identifiable, Queryable, Clone, Debug, Serialize)]
#[derive(Identifiable, Queryable, Selectable, Associations, Clone, Debug, Serialize)]
#[diesel(belongs_to(Invoice))]
#[diesel(table_name = invoice_rows)]
pub struct InvoiceRow {
#[serde(skip_serializing)]
Expand Down Expand Up @@ -110,7 +113,8 @@ pub struct NewInvoiceRow {
/// The metadata for an invoice attachment
/// The file itself can be requested using its hash and filename
/// => /somepath/{hash}/{filename}
#[derive(Identifiable, Queryable, Clone, Debug, Serialize)]
#[derive(Identifiable, Queryable, Selectable, Associations, Clone, Debug, Serialize)]
#[diesel(belongs_to(Invoice))]
#[diesel(table_name = invoice_attachments)]
pub struct Attachment {
#[serde(skip_serializing)]
Expand Down

0 comments on commit 7e58a99

Please sign in to comment.