feat: bootstrap inventory templates

This commit is contained in:
Aravinth Manivannan 2025-01-10 21:13:40 +05:30
parent 288453b3ea
commit b6350f2225
Signed by: realaravinth
GPG key ID: F8F50389936984FF
15 changed files with 677 additions and 0 deletions

View file

@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::cell::RefCell;
use derive_builder::*;
use derive_more::*;
use serde::*;
use tera::Context;
use url::Url;
pub use super::*;
use crate::utils::*;
pub const ADD_CATEGORY_PAGE: TemplateFile =
TemplateFile::new("inventory.add_category", "inventory/add_category.html");
pub fn register_templates(t: &mut tera::Tera) {
ADD_CATEGORY_PAGE.register(t).expect(ADD_CATEGORY_PAGE.name);
}
pub struct AddCategoryPage {
ctx: RefCell<Context>,
}
impl AddCategoryPage {
pub fn new() -> Self {
let mut ctx = context();
//ctx.insert(PAYLOAD_KEY, p);
let ctx = RefCell::new(ctx);
Self { ctx }
}
pub fn render(&self) -> String {
TEMPLATES
.render(ADD_CATEGORY_PAGE.name, &self.ctx.borrow())
.unwrap()
}
pub fn page() -> String {
let p = Self::new();
p.render()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn render_page_and_write() {
const FILE: &str = "./tmp/inventory-add_category.html";
let tw = TestWriterBuilder::default()
.file(FILE.into())
.contents(AddCategoryPage::page())
.build()
.unwrap();
tw.write();
}
}

View file

@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::cell::RefCell;
use derive_builder::*;
use derive_more::*;
use serde::*;
use tera::Context;
use url::Url;
pub use super::*;
use crate::utils::*;
pub const ADD_CUSTOMIZATION_PAGE: TemplateFile = TemplateFile::new(
"inventory.add_customization",
"inventory/add_customization.html",
);
pub fn register_templates(t: &mut tera::Tera) {
ADD_CUSTOMIZATION_PAGE
.register(t)
.expect(ADD_CUSTOMIZATION_PAGE.name);
}
pub struct AddCustomizationPage {
ctx: RefCell<Context>,
}
impl AddCustomizationPage {
pub fn new() -> Self {
let mut ctx = context();
//ctx.insert(PAYLOAD_KEY, p);
let ctx = RefCell::new(ctx);
Self { ctx }
}
pub fn render(&self) -> String {
TEMPLATES
.render(ADD_CUSTOMIZATION_PAGE.name, &self.ctx.borrow())
.unwrap()
}
pub fn page() -> String {
let p = Self::new();
p.render()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn render_page_and_write() {
const FILE: &str = "./tmp/inventory-add_customization.html";
let tw = TestWriterBuilder::default()
.file(FILE.into())
.contents(AddCustomizationPage::page())
.build()
.unwrap();
tw.write();
}
}

View file

@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::cell::RefCell;
use derive_builder::*;
use derive_more::*;
use serde::*;
use tera::Context;
use url::Url;
pub use super::*;
use crate::utils::*;
pub const ADD_PRODUCT_PAGE: TemplateFile =
TemplateFile::new("inventory.add_product", "inventory/add_product.html");
pub fn register_templates(t: &mut tera::Tera) {
ADD_PRODUCT_PAGE.register(t).expect(ADD_PRODUCT_PAGE.name);
}
pub struct AddProductPage {
ctx: RefCell<Context>,
}
impl AddProductPage {
pub fn new() -> Self {
let mut ctx = context();
//ctx.insert(PAYLOAD_KEY, p);
let ctx = RefCell::new(ctx);
Self { ctx }
}
pub fn render(&self) -> String {
TEMPLATES
.render(ADD_PRODUCT_PAGE.name, &self.ctx.borrow())
.unwrap()
}
pub fn page() -> String {
let p = Self::new();
p.render()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn render_page_and_write() {
const FILE: &str = "./tmp/inventory-add_product.html";
let tw = TestWriterBuilder::default()
.file(FILE.into())
.contents(AddProductPage::page())
.build()
.unwrap();
tw.write();
}
}

View file

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
pub mod add_category;
pub mod add_customization;
pub mod add_product;
pub mod update_category;
pub mod update_customization;
pub mod update_product;
pub fn register_templates(t: &mut tera::Tera) {
for template in [
add_category::ADD_CATEGORY_PAGE,
update_category::UPDATE_CATEGORY_PAGE,
add_product::ADD_PRODUCT_PAGE,
update_product::UPDATE_PRODUCT_PAGE,
add_customization::ADD_CUSTOMIZATION_PAGE,
update_customization::UPDATE_CUSTOMIZATION_PAGE,
]
.iter()
{
template.register(t).expect(template.name);
}
}

View file

@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::cell::RefCell;
use derive_builder::*;
use derive_more::*;
use serde::*;
use tera::Context;
use url::Url;
pub use super::*;
use crate::utils::*;
pub const UPDATE_CATEGORY_PAGE: TemplateFile = TemplateFile::new(
"inventory.update_category",
"inventory/update_category.html",
);
pub fn register_templates(t: &mut tera::Tera) {
UPDATE_CATEGORY_PAGE
.register(t)
.expect(UPDATE_CATEGORY_PAGE.name);
}
pub struct UpdateCategoryPage {
ctx: RefCell<Context>,
}
impl UpdateCategoryPage {
pub fn new() -> Self {
let mut ctx = context();
//ctx.insert(PAYLOAD_KEY, p);
let ctx = RefCell::new(ctx);
Self { ctx }
}
pub fn render(&self) -> String {
TEMPLATES
.render(UPDATE_CATEGORY_PAGE.name, &self.ctx.borrow())
.unwrap()
}
pub fn page() -> String {
let p = Self::new();
p.render()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn render_page_and_write() {
const FILE: &str = "./tmp/inventory-update_category.html";
let tw = TestWriterBuilder::default()
.file(FILE.into())
.contents(UpdateCategoryPage::page())
.build()
.unwrap();
tw.write();
}
}

View file

@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::cell::RefCell;
use derive_builder::*;
use derive_more::*;
use serde::*;
use tera::Context;
use url::Url;
pub use super::*;
use crate::utils::*;
pub const UPDATE_CUSTOMIZATION_PAGE: TemplateFile = TemplateFile::new(
"inventory.update_customization",
"inventory/update_customization.html",
);
pub fn register_templates(t: &mut tera::Tera) {
UPDATE_CUSTOMIZATION_PAGE
.register(t)
.expect(UPDATE_CUSTOMIZATION_PAGE.name);
}
pub struct UpdateCustomizationPage {
ctx: RefCell<Context>,
}
impl UpdateCustomizationPage {
pub fn new() -> Self {
let mut ctx = context();
//ctx.insert(PAYLOAD_KEY, p);
let ctx = RefCell::new(ctx);
Self { ctx }
}
pub fn render(&self) -> String {
TEMPLATES
.render(UPDATE_CUSTOMIZATION_PAGE.name, &self.ctx.borrow())
.unwrap()
}
pub fn page() -> String {
let p = Self::new();
p.render()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn render_page_and_write() {
const FILE: &str = "./tmp/inventory-update_customization.html";
let tw = TestWriterBuilder::default()
.file(FILE.into())
.contents(UpdateCustomizationPage::page())
.build()
.unwrap();
tw.write();
}
}

View file

@ -0,0 +1,65 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::cell::RefCell;
use derive_builder::*;
use derive_more::*;
use serde::*;
use tera::Context;
use url::Url;
pub use super::*;
use crate::utils::*;
pub const UPDATE_PRODUCT_PAGE: TemplateFile =
TemplateFile::new("inventory.update_product", "inventory/update_product.html");
pub fn register_templates(t: &mut tera::Tera) {
UPDATE_PRODUCT_PAGE
.register(t)
.expect(UPDATE_PRODUCT_PAGE.name);
}
pub struct UpdateProductPage {
ctx: RefCell<Context>,
}
impl UpdateProductPage {
pub fn new() -> Self {
let mut ctx = context();
//ctx.insert(PAYLOAD_KEY, p);
let ctx = RefCell::new(ctx);
Self { ctx }
}
pub fn render(&self) -> String {
TEMPLATES
.render(UPDATE_PRODUCT_PAGE.name, &self.ctx.borrow())
.unwrap()
}
pub fn page() -> String {
let p = Self::new();
p.render()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn render_page_and_write() {
const FILE: &str = "./tmp/inventory-update_product.html";
let tw = TestWriterBuilder::default()
.file(FILE.into())
.contents(UpdateProductPage::page())
.build()
.unwrap();
tw.write();
}
}

View file

@ -3,6 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pub mod identity;
pub mod inventory;
mod log;
mod utils;

View file

@ -47,6 +47,7 @@ lazy_static! {
}
tera.autoescape_on(vec![".html", ".sql"]);
crate::identity::register_templates(&mut tera);
crate::inventory::register_templates(&mut tera);
tera
};
}

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Create Category | Vanikam</title>
</head>
<body>
<form action="/inventory/category/add" method="post">
<label for="name">
Category name
<input type="text" name="name" id="name" required>
</label>
<label for="description">
Description
<input type="text" name="description" id="description">
</label>
<button type="submit">Create Category</button>
</form>
</body>
</html>

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Add Customization | Vanikam</title>
</head>
<body>
<form action="/inventory/product/customization/add" method="post">
<label for="name">
Customization name
<input type="text" name="name" id="name" required>
</label>
<button type="submit">Add Customization</button>
</form>
</body>
</html>

View file

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Add Product | Vanikam</title>
</head>
<body>
<form action="/inventory/product/add" method="post">
<label for="category_uuid"> <!-- NOTE: when user selects category name, replace with category ID -->
Category name
<input type="text" name="category_uuid" id="category_uuid" required>
</label>
<label for="name">
Product name
<input type="text" name="name" id="name" required>
</label>
<label for="description">
Description
<input type="text" name="description" id="description">
</label>
<!--
<label for="description">
Image
<input type="file" name="description" id="description">
</label> -->
<label for="sku_able">
SKU-able
<input type="button" name="sku_able" id="sku_able">
</label>
<!-- quantity -->
<label for="quantity_minor_unit">
Quantity minor unit
<input type="text" name="quantity_minor_unit" id="quantity_minor_unit">
</label>
<label for="quantity_minor_number">
Quantity minor number
<input type="number" name="quantity_minor_number" id="quantity_minor_number">
</label>
<label for="quantity_major_unit">
Quantity major unit
<input type="text" name="quantity_major_unit" id="quantity_major_unit">
</label>
<label for="quantity_major_number">
Quantity major number
<input type="number" name="quantity_major_number" id="quantity_major_number">
</label>
<!-- price -->
<label for="price_unit">
Price unit
<input type="text" name="price_unit" id="price_unit">
</label>
<label for="price_minor_number">
Price minor number
<input type="number" name="price_minor_number" id="price_minor_number">
</label>
<label for="price_major_number">
Price major number
<input type="number" name="price_major_number" id="price_major_number">
</label>
<button type="submit">Add Product</button>
</form>
</body>
</html>

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Update Category | Vanikam</title>
</head>
<body>
<form action="/inventory/category/update" method="post">
<label for="name">
Category name
<input type="text" name="name" id="name" required>
</label>
<label for="description">
Description
<input type="text" name="description" id="description">
</label>
<button type="submit">Update Category</button>
</form>
</body>
</html>

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Update Customization | Vanikam</title>
</head>
<body>
<form action="/inventory/product/customization/update" method="post">
<label for="name">
Customization name
<input type="text" name="name" id="name" required>
</label>
<button type="submit">Update Customization</button>
</form>
</body>
</html>

View file

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Update Product | Vanikam</title>
</head>
<body>
<form action="/inventory/product/update" method="post">
<label for="category_uuid"> <!-- NOTE: when user selects category name, replace with category ID -->
Category name
<input type="text" name="category_uuid" id="category_uuid" required>
</label>
<label for="name">
Product name
<input type="text" name="name" id="name" required>
</label>
<label for="description">
Description
<input type="text" name="description" id="description">
</label>
<!--
<label for="description">
Image
<input type="file" name="description" id="description">
</label> -->
<label for="sku_able">
SKU-able
<input type="button" name="sku_able" id="sku_able">
</label>
<!-- quantity -->
<label for="quantity_minor_unit">
Quantity minor unit
<input type="text" name="quantity_minor_unit" id="quantity_minor_unit">
</label>
<label for="quantity_minor_number">
Quantity minor number
<input type="number" name="quantity_minor_number" id="quantity_minor_number">
</label>
<label for="quantity_major_unit">
Quantity major unit
<input type="text" name="quantity_major_unit" id="quantity_major_unit">
</label>
<label for="quantity_major_number">
Quantity major number
<input type="number" name="quantity_major_number" id="quantity_major_number">
</label>
<!-- price -->
<label for="price_unit">
Price unit
<input type="text" name="price_unit" id="price_unit">
</label>
<label for="price_minor_number">
Price minor number
<input type="number" name="price_minor_number" id="price_minor_number">
</label>
<label for="price_major_number">
Price major number
<input type="number" name="price_major_number" id="price_major_number">
</label>
<button type="submit">Update Product</button>
</form>
</body>
</html>