Some refactoring

demo-mode
Wes Holland 1 year ago
parent 5fd8e249b1
commit c66ae19ea8

@ -5,7 +5,7 @@ use sqlx::SqlitePool;
use askama_axum::{IntoResponse, Response};
use crate::db::inventory_item::{inventory_item_get_all, inventory_item_get_search, DbInventoryItem};
use crate::error::{AppError, QueryExtractor};
use crate::app::SearchQueryArgs;
use crate::app::common::query_args::search::SearchQueryArgs;
#[derive(Template)]
#[template(path = "catalog.html")]

@ -0,0 +1 @@
pub mod query_args;

@ -0,0 +1,68 @@
use std::str::FromStr;
use serde::Deserialize;
use anyhow::Error;
use chrono::{FixedOffset, NaiveDate, NaiveTime};
use crate::util::parsing;
use crate::util::time::{LocalTimestampRange, DEFAULT_TIMEZONE_OFFSET};
/// Common query args for datetime ranges. Times assumed to be
/// in local time. This usually means a user configured time,
/// but can be specified as an offset of seconds
#[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>,
}
impl TryInto<LocalTimestampRange> for DatetimeRangeQueryArgs {
type Error = Error;
fn try_into(self) -> Result<LocalTimestampRange, Self::Error> {
let start_date = self.start_date
.map(|x| x.parse::<NaiveDate>()).transpose()?
.or_else(|| NaiveDate::from_ymd_opt(2000, 1, 1))
.ok_or_else(|| anyhow::anyhow!("Invalid start"))?;
let end_date = parsing::parse_or(self.end_date,
|| NaiveDate::from_ymd_opt(3000, 1, 1))?;
let start_time = parsing::parse_or(self.start_time,
|| NaiveTime::from_hms_opt(0, 0, 0))?;
let end_time = parsing::parse_or(self.end_time,
|| NaiveTime::from_hms_opt(23, 59, 59))?;
let timezone = self.time_zone_offset
.or(Some(DEFAULT_TIMEZONE_OFFSET))
.map(|tz_offset| FixedOffset::east_opt(tz_offset))
.flatten()
.ok_or_else(|| anyhow::anyhow!("Invalid timezone"))?;
let start = start_date
.and_time(start_time)
.and_local_timezone(timezone)
.earliest()
.ok_or(anyhow::anyhow!("Invalid start"))?;
let end = end_date
.and_time(end_time)
.and_local_timezone(timezone)
.latest()
.ok_or(anyhow::anyhow!("Invalid end"))?;
Ok(
LocalTimestampRange {
start,
end
}
)
}
}

@ -0,0 +1,4 @@
pub mod datetime_range;
pub mod search;

@ -0,0 +1,12 @@
use serde::Deserialize;
/// Common query args for text search
#[derive(Debug, Deserialize)]
pub struct SearchQueryArgs {
#[serde(rename = "q")]
pub search: Option<String>,
#[serde(alias = "p")]
pub page: Option<i64>,
#[serde(rename = "size")]
pub page_size: Option<i64>,
}

@ -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::error::{AppError, QueryExtractor};
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 askama::Template;
use askama_axum::{IntoResponse, Response};
@ -11,6 +12,7 @@ use chrono::prelude::*;
use serde::Deserialize;
use sqlx::SqlitePool;
use tracing::info;
use crate::util::currency;
#[derive(Template)]
#[template(path = "history.html")]
@ -46,18 +48,11 @@ struct PositiveAdjustmentDisplayItem {
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 {
fn from(adjustment: DbAdjustment) -> Self {
Self {
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(
QueryExtractor(query): QueryExtractor<DatetimeRangeQueryArgs>,
QueryExtractor(mut query): QueryExtractor<DatetimeRangeQueryArgs>,
HxRequest(hx_request): HxRequest,
State(db): State<SqlitePool>,
user: SessionUser
@ -140,45 +120,17 @@ pub async fn history_log_handler(
let today = Local::now().naive_local().date();
let start_date = query.start_date.unwrap_or("2000-01-01".to_string());
let start_time = query.start_time.unwrap_or("00:00:00".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 _ = 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();
let local_start = naive_start_date
.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);
info!("Get items from: {} to {}", utc_range.start, utc_range.end);
let items = DbAdjustmentWithUserAndItem::query_by_date_range(
&db, combined_start, combined_end, 1000, 0)
&db, utc_range.start, utc_range.end, 1000, 0)
.await?
.into_iter()
.map(|x| {
@ -193,6 +145,11 @@ pub async fn history_log_handler(
}
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,

@ -5,7 +5,7 @@ use askama_axum::{IntoResponse, Response};
use axum_htmx::HxRequest;
use crate::db::inventory_item::{inventory_item_get_search, DbInventoryItem};
use crate::error::{AppError, QueryExtractor};
use crate::app::SearchQueryArgs;
use crate::app::common::query_args::search::SearchQueryArgs;
#[derive(Template)]
#[template(path = "home.html")]

@ -15,6 +15,7 @@ mod home;
mod overview;
mod reports;
mod history;
pub mod common;
pub fn routes() -> Router<AppState> {
Router::new()
@ -62,13 +63,3 @@ impl FromRef<AppState> for BasicClient {
}
}
/// Common query args for text search
#[derive(Debug, Deserialize)]
pub struct SearchQueryArgs {
#[serde(rename = "q")]
pub search: Option<String>,
#[serde(alias = "p")]
pub page: Option<i64>,
#[serde(rename = "size")]
pub page_size: Option<i64>,
}

@ -0,0 +1,6 @@
pub fn int_cents_to_dollars_string(i: i64) -> String {
let whole = i / 100;
let cents = i % 100;
format!("${}.{}", whole, cents)
}

@ -1 +1,3 @@
pub mod time;
pub mod time;
pub mod currency;
pub mod parsing;

@ -0,0 +1,15 @@
use anyhow::Error;
use std::str::FromStr;
pub fn parse_or<T, F>(val: Option<String>, f: F) -> Result<T, Error>
where
T: FromStr,
<T as FromStr>::Err: core::error::Error + Send + Sync + 'static,
F: FnOnce() -> Option<T>
{
val.map(|x| x.parse::<T>())
.transpose()?
.or_else(f)
.ok_or_else(|| anyhow::anyhow!("Invalid start"))
}

@ -1,3 +1,28 @@
use chrono::{DateTime, FixedOffset, Utc};
pub const DEFAULT_TIMEZONE_OFFSET: i32 = -6 * 3600;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct LocalTimestampRange {
pub start: DateTime<FixedOffset>,
pub end: DateTime<FixedOffset>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct UtcTimestampRange {
pub start: DateTime<Utc>,
pub end: DateTime<Utc>,
}
impl From<LocalTimestampRange> for UtcTimestampRange {
fn from(item: LocalTimestampRange) -> Self {
Self {
start: item.start.to_utc(),
end: item.end.to_utc(),
}
}
}
/// Super naive implementation. Just a quick and dirty to get a string

Loading…
Cancel
Save

Powered by TurnKey Linux.