|
|
|
@ -1,7 +1,8 @@
|
|
|
|
|
|
|
|
use crate::app::common::query_args::datetime_range::DatetimeRangeQueryArgs;
|
|
|
|
use crate::db::adjustment::{get_adjustments_target_date_range, DbAdjustment, DbAdjustmentWithUserAndItem};
|
|
|
|
use crate::db::adjustment::{get_adjustments_target_date_range, DbAdjustment, DbAdjustmentWithUserAndItem};
|
|
|
|
use crate::error::{AppError, QueryExtractor};
|
|
|
|
use crate::error::{AppError, QueryExtractor};
|
|
|
|
use crate::session::SessionUser;
|
|
|
|
use crate::session::SessionUser;
|
|
|
|
use crate::util::time::tz_offset_to_string;
|
|
|
|
use crate::util::time::{tz_offset_to_string, LocalTimestampRange, UtcTimestampRange};
|
|
|
|
use anyhow::Result;
|
|
|
|
use anyhow::Result;
|
|
|
|
use askama::Template;
|
|
|
|
use askama::Template;
|
|
|
|
use askama_axum::{IntoResponse, Response};
|
|
|
|
use askama_axum::{IntoResponse, Response};
|
|
|
|
@ -11,6 +12,7 @@ use chrono::prelude::*;
|
|
|
|
use serde::Deserialize;
|
|
|
|
use serde::Deserialize;
|
|
|
|
use sqlx::SqlitePool;
|
|
|
|
use sqlx::SqlitePool;
|
|
|
|
use tracing::info;
|
|
|
|
use tracing::info;
|
|
|
|
|
|
|
|
use crate::util::currency;
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Template)]
|
|
|
|
#[derive(Template)]
|
|
|
|
#[template(path = "history.html")]
|
|
|
|
#[template(path = "history.html")]
|
|
|
|
@ -46,18 +48,11 @@ struct PositiveAdjustmentDisplayItem {
|
|
|
|
pub unit_value: String,
|
|
|
|
pub unit_value: String,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn int_cents_to_currency_string(i: i64) -> String {
|
|
|
|
|
|
|
|
let whole = i / 100;
|
|
|
|
|
|
|
|
let cents = i % 100;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
format!("${}.{}", whole, cents)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl From<DbAdjustment> for PositiveAdjustmentDisplayItem {
|
|
|
|
impl From<DbAdjustment> for PositiveAdjustmentDisplayItem {
|
|
|
|
fn from(adjustment: DbAdjustment) -> Self {
|
|
|
|
fn from(adjustment: DbAdjustment) -> Self {
|
|
|
|
Self {
|
|
|
|
Self {
|
|
|
|
amount: format!("{}", adjustment.amount),
|
|
|
|
amount: format!("{}", adjustment.amount),
|
|
|
|
unit_value: int_cents_to_currency_string(adjustment.unit_price.unwrap_or_default()),
|
|
|
|
unit_value: currency::int_cents_to_dollars_string(adjustment.unit_price.unwrap_or_default()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -114,23 +109,8 @@ impl HistoryDisplayItem {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Common query args for datetime ranges
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
|
|
|
pub struct DatetimeRangeQueryArgs {
|
|
|
|
|
|
|
|
#[serde(rename = "start-date", alias = "sd")]
|
|
|
|
|
|
|
|
pub start_date: Option<String>,
|
|
|
|
|
|
|
|
#[serde(rename = "start-time", alias = "st")]
|
|
|
|
|
|
|
|
pub start_time: Option<String>,
|
|
|
|
|
|
|
|
#[serde(rename = "end-date", alias = "ed")]
|
|
|
|
|
|
|
|
pub end_date: Option<String>,
|
|
|
|
|
|
|
|
#[serde(rename = "end-time", alias = "et")]
|
|
|
|
|
|
|
|
pub end_time: Option<String>,
|
|
|
|
|
|
|
|
#[serde(rename = "timezone-offset", alias = "tz")]
|
|
|
|
|
|
|
|
pub time_zone_offset: Option<i32>,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn history_log_handler(
|
|
|
|
pub async fn history_log_handler(
|
|
|
|
QueryExtractor(query): QueryExtractor<DatetimeRangeQueryArgs>,
|
|
|
|
QueryExtractor(mut query): QueryExtractor<DatetimeRangeQueryArgs>,
|
|
|
|
HxRequest(hx_request): HxRequest,
|
|
|
|
HxRequest(hx_request): HxRequest,
|
|
|
|
State(db): State<SqlitePool>,
|
|
|
|
State(db): State<SqlitePool>,
|
|
|
|
user: SessionUser
|
|
|
|
user: SessionUser
|
|
|
|
@ -140,45 +120,17 @@ pub async fn history_log_handler(
|
|
|
|
|
|
|
|
|
|
|
|
let today = Local::now().naive_local().date();
|
|
|
|
let today = Local::now().naive_local().date();
|
|
|
|
|
|
|
|
|
|
|
|
let start_date = query.start_date.unwrap_or("2000-01-01".to_string());
|
|
|
|
let _ = query.time_zone_offset.get_or_insert(user.tz_offset);
|
|
|
|
let start_time = query.start_time.unwrap_or("00:00:00".to_string());
|
|
|
|
let _ = query.end_date.get_or_insert(today.to_string());
|
|
|
|
let end_date = query.end_date.unwrap_or(today.to_string());
|
|
|
|
|
|
|
|
let end_time = query.end_time.unwrap_or("23:59:59".to_string());
|
|
|
|
|
|
|
|
let tz_offset = query.time_zone_offset.unwrap_or(user.tz_offset);
|
|
|
|
|
|
|
|
let timezone = FixedOffset::east_opt(tz_offset)
|
|
|
|
|
|
|
|
.ok_or(anyhow::anyhow!("Invalid timezone"))?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let naive_start_date = start_date.parse::<NaiveDate>()?;
|
|
|
|
|
|
|
|
let naive_start_time = start_time.parse::<NaiveTime>()?;
|
|
|
|
|
|
|
|
let naive_end_date = end_date.parse::<NaiveDate>()?;
|
|
|
|
|
|
|
|
let naive_end_time = end_time.parse::<NaiveTime>()?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let local_range: LocalTimestampRange = query.try_into()?;
|
|
|
|
|
|
|
|
let utc_range: UtcTimestampRange = local_range.into();
|
|
|
|
|
|
|
|
let tz_offset = local_range.start.timezone().local_minus_utc();
|
|
|
|
|
|
|
|
|
|
|
|
let local_start = naive_start_date
|
|
|
|
info!("Get items from: {} to {}", utc_range.start, utc_range.end);
|
|
|
|
.and_time(naive_start_time)
|
|
|
|
|
|
|
|
.and_local_timezone(timezone)
|
|
|
|
|
|
|
|
.earliest()
|
|
|
|
|
|
|
|
.ok_or(anyhow::anyhow!("Invalid start"))?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let combined_start = local_start.to_utc();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let local_end = naive_end_date
|
|
|
|
|
|
|
|
.and_time(naive_end_time)
|
|
|
|
|
|
|
|
.and_local_timezone(timezone)
|
|
|
|
|
|
|
|
.latest()
|
|
|
|
|
|
|
|
.ok_or(anyhow::anyhow!("Invalid start"))?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let combined_end = local_end.to_utc();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let start_date = local_start.naive_local().date().to_string();
|
|
|
|
|
|
|
|
let start_time = local_start.naive_local().time().to_string();
|
|
|
|
|
|
|
|
let end_date = local_end.naive_local().date().to_string();
|
|
|
|
|
|
|
|
let end_time = local_end.naive_local().time().to_string();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
info!("Get items from: {} to {}", combined_start, combined_end);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let items = DbAdjustmentWithUserAndItem::query_by_date_range(
|
|
|
|
let items = DbAdjustmentWithUserAndItem::query_by_date_range(
|
|
|
|
&db, combined_start, combined_end, 1000, 0)
|
|
|
|
&db, utc_range.start, utc_range.end, 1000, 0)
|
|
|
|
.await?
|
|
|
|
.await?
|
|
|
|
.into_iter()
|
|
|
|
.into_iter()
|
|
|
|
.map(|x| {
|
|
|
|
.map(|x| {
|
|
|
|
@ -193,6 +145,11 @@ pub async fn history_log_handler(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
let time_zone = tz_offset_to_string(tz_offset);
|
|
|
|
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 {
|
|
|
|
Ok(HistoryLogTemplate {
|
|
|
|
items,
|
|
|
|
items,
|
|
|
|
start_date,
|
|
|
|
start_date,
|
|
|
|
|