You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
4.9 KiB
163 lines
4.9 KiB
use crate::app::common::query_args::datetime_range::DatetimeRangeQueryArgs;
|
|
use crate::db::adjustment::{get_adjustments_target_date_range, DbAdjustment, DbAdjustmentWithUserAndItem};
|
|
use crate::error::{AppError, QueryExtractor};
|
|
use crate::session::SessionUser;
|
|
use crate::util::time::{tz_offset_to_string, LocalTimestampRange, UtcTimestampRange};
|
|
use anyhow::Result;
|
|
use askama::Template;
|
|
use askama_axum::{IntoResponse, Response};
|
|
use axum::extract::State;
|
|
use axum_htmx::HxRequest;
|
|
use chrono::prelude::*;
|
|
use serde::Deserialize;
|
|
use sqlx::SqlitePool;
|
|
use tracing::info;
|
|
use crate::util::currency;
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "history.html")]
|
|
struct HistoryLogTemplate {
|
|
items: Vec<HistoryDisplayItem>,
|
|
start_date: String,
|
|
start_time: String,
|
|
end_date: String,
|
|
end_time: String,
|
|
time_zone: String,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "history_item_fragment.html")]
|
|
struct HistoryLogItemFragmentTemplate {
|
|
items: Vec<HistoryDisplayItem>
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
struct HistoryDisplayItem {
|
|
pub create_date: String,
|
|
pub target_date: String,
|
|
pub user_name: String,
|
|
pub item_name: String,
|
|
pub item_unit: String,
|
|
pub item_unit_abbreviation: String,
|
|
pub item_type: HistoryItemEntry,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
struct PositiveAdjustmentDisplayItem {
|
|
pub amount: String,
|
|
pub unit_value: String,
|
|
}
|
|
|
|
impl From<DbAdjustment> for PositiveAdjustmentDisplayItem {
|
|
fn from(adjustment: DbAdjustment) -> Self {
|
|
Self {
|
|
amount: format!("{}", adjustment.amount),
|
|
unit_value: currency::int_cents_to_dollars_string(adjustment.unit_price.unwrap_or_default()),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
struct NegativeAdjustmentDisplayItem {
|
|
pub amount: String,
|
|
pub reason: String,
|
|
}
|
|
|
|
impl From<DbAdjustment> for NegativeAdjustmentDisplayItem {
|
|
fn from(adjustment: DbAdjustment) -> Self {
|
|
Self {
|
|
amount: format!("{}", adjustment.amount),
|
|
reason: adjustment.reason.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
enum HistoryItemEntry {
|
|
PositiveAdjustment(PositiveAdjustmentDisplayItem),
|
|
NegativeAdjustment(NegativeAdjustmentDisplayItem),
|
|
}
|
|
|
|
impl HistoryDisplayItem {
|
|
pub fn from_adjustment(db_entry: DbAdjustmentWithUserAndItem, tz_offset: i32)
|
|
-> Result<Self> {
|
|
let simple_entry: DbAdjustment = db_entry.clone().into();
|
|
|
|
let timezone = FixedOffset::east_opt(tz_offset)
|
|
.ok_or(anyhow::anyhow!("Invalid timezone"))?;
|
|
let create_date = db_entry.create_date.with_timezone(&timezone)
|
|
.format("%Y-%m-%d %l:%M:%S %p").to_string();
|
|
let target_date = db_entry.target_date.with_timezone(&timezone)
|
|
.format("%Y-%m-%d %l:%M:%S %p").to_string();
|
|
|
|
let item_type = if simple_entry.amount > 0.0 {
|
|
HistoryItemEntry::PositiveAdjustment(simple_entry.into())
|
|
} else {
|
|
HistoryItemEntry::NegativeAdjustment(simple_entry.into())
|
|
};
|
|
|
|
Ok(Self {
|
|
create_date,
|
|
target_date,
|
|
user_name: db_entry.user_name,
|
|
item_name: db_entry.item_name,
|
|
item_unit: db_entry.item_unit,
|
|
item_unit_abbreviation: db_entry.item_unit_abbreviation,
|
|
item_type
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
pub async fn history_log_handler(
|
|
QueryExtractor(mut query): QueryExtractor<DatetimeRangeQueryArgs>,
|
|
HxRequest(hx_request): HxRequest,
|
|
State(db): State<SqlitePool>,
|
|
user: SessionUser
|
|
) -> Result<Response, AppError> {
|
|
|
|
info!("Query: {:?}", query);
|
|
|
|
let today = Local::now().naive_local().date();
|
|
|
|
let _ = query.time_zone_offset.get_or_insert(user.tz_offset);
|
|
let _ = query.end_date.get_or_insert(today.to_string());
|
|
|
|
let local_range: LocalTimestampRange = query.try_into()?;
|
|
let utc_range: UtcTimestampRange = local_range.into();
|
|
let tz_offset = local_range.start.timezone().local_minus_utc();
|
|
|
|
info!("Get items from: {} to {}", utc_range.start, utc_range.end);
|
|
|
|
let items = DbAdjustmentWithUserAndItem::query_by_date_range(
|
|
&db, utc_range.start, utc_range.end, 1000, 0)
|
|
.await?
|
|
.into_iter()
|
|
.map(|x| {
|
|
HistoryDisplayItem::from_adjustment(x, tz_offset)
|
|
})
|
|
.collect::<Result<Vec<HistoryDisplayItem>>>()?;
|
|
|
|
info!("Item count: {}", items.len());
|
|
|
|
if hx_request {
|
|
Ok(HistoryLogItemFragmentTemplate {items}.into_response())
|
|
}
|
|
else {
|
|
let time_zone = tz_offset_to_string(tz_offset);
|
|
let start_date = local_range.start.naive_local().date().to_string();
|
|
let start_time = local_range.start.naive_local().time().to_string();
|
|
let end_date = local_range.end.naive_local().date().to_string();
|
|
let end_time = local_range.end.naive_local().time().to_string();
|
|
|
|
Ok(HistoryLogTemplate {
|
|
items,
|
|
start_date,
|
|
start_time,
|
|
end_date,
|
|
end_time,
|
|
time_zone,
|
|
}.into_response())
|
|
}
|
|
}
|