Added supplier and updated dependencies.

This commit is contained in:
2026-07-22 19:26:57 +02:00
parent cddd9a3956
commit 581439150f
16 changed files with 3585 additions and 3068 deletions
Generated
+59 -52
View File
@@ -377,10 +377,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-link",
]
@@ -398,9 +395,8 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "common"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"chrono",
"log",
"serde",
"serde_json",
@@ -527,7 +523,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -553,9 +549,9 @@ dependencies = [
[[package]]
name = "env_filter"
version = "1.0.0"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f"
checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217"
dependencies = [
"log",
"regex",
@@ -563,9 +559,9 @@ dependencies = [
[[package]]
name = "env_logger"
version = "0.11.10"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a"
checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6"
dependencies = [
"anstream",
"anstyle",
@@ -858,9 +854,9 @@ dependencies = [
[[package]]
name = "http"
version = "1.4.1"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0"
checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425"
dependencies = [
"bytes",
"itoa",
@@ -1124,7 +1120,7 @@ checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -1148,7 +1144,7 @@ dependencies = [
[[package]]
name = "label_editor"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"common",
"server",
@@ -1205,9 +1201,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.32"
version = "0.4.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
dependencies = [
"value-bag",
]
@@ -1390,7 +1386,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -1445,9 +1441,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.12.2"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
dependencies = [
"aho-corasick",
"memchr",
@@ -1457,9 +1453,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.13"
version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad"
dependencies = [
"aho-corasick",
"memchr",
@@ -1468,9 +1464,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.8.8"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "rustix"
@@ -1511,9 +1507,9 @@ checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
[[package]]
name = "serde"
version = "1.0.228"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
dependencies = [
"serde_core",
"serde_derive",
@@ -1521,29 +1517,29 @@ dependencies = [
[[package]]
name = "serde_core"
version = "1.0.228"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 3.0.3",
]
[[package]]
name = "serde_json"
version = "1.0.150"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
dependencies = [
"itoa",
"memchr",
@@ -1577,10 +1573,9 @@ dependencies = [
[[package]]
name = "server"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"axum",
"chrono",
"common",
"dotenv",
"env_logger",
@@ -1745,7 +1740,7 @@ dependencies = [
"quote",
"sqlx-core",
"sqlx-macros-core",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -1769,7 +1764,7 @@ dependencies = [
"sqlx-mysql",
"sqlx-postgres",
"sqlx-sqlite",
"syn",
"syn 2.0.114",
"thiserror",
"url",
]
@@ -1890,6 +1885,17 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "syn"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "1.0.2"
@@ -1904,7 +1910,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -1924,7 +1930,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -1963,9 +1969,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.52.3"
version = "1.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
dependencies = [
"bytes",
"libc",
@@ -1986,7 +1992,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -2007,13 +2013,14 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.6.11"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233"
dependencies = [
"bitflags",
"bytes",
"http",
"percent-encoding",
"pin-project-lite",
"tower-layer",
"tower-service",
@@ -2051,7 +2058,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -2245,7 +2252,7 @@ dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
"wasm-bindgen-shared",
]
@@ -2329,7 +2336,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -2340,7 +2347,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -2412,7 +2419,7 @@ dependencies = [
"heck",
"indexmap",
"prettyplease",
"syn",
"syn 2.0.114",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
@@ -2428,7 +2435,7 @@ dependencies = [
"prettyplease",
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
"wit-bindgen-core",
"wit-bindgen-rust",
]
@@ -2495,7 +2502,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
"synstructure",
]
@@ -2516,7 +2523,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
"synstructure",
]
@@ -2550,7 +2557,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "label_editor"
version = "0.1.0"
version = "0.3.0"
edition = "2024"
authors = ["Matthias Lodner <matthias@lodner.de>"]
+4 -5
View File
@@ -1,17 +1,16 @@
[package]
name = "common"
version = "0.1.0"
version = "0.3.0"
edition = "2024"
authors = ["Matthias Lodner <matthias@lodner.de>"]
[dependencies]
# Deserialize/Serialize
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.150"
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.151"
# Database
sqlx = { version = "0.9.0", features = [ "runtime-async-std", "postgres", "chrono" ] }
# Etc.
chrono = { version = "0.4.45", features = [ "serde" ] }
log = "0.4.32"
log = "0.4.33"
+1
View File
@@ -4,3 +4,4 @@ pub mod variant;
pub mod unit;
pub mod label;
pub mod settings;
pub mod supplier;
+159
View File
@@ -0,0 +1,159 @@
use log::{error, info};
use serde::{Deserialize, Serialize};
use sqlx::{Arguments, AssertSqlSafe, Decode, Encode, FromRow, PgPool, Row};
use sqlx::postgres::{PgArguments, PgRow};
use crate::models::label::Label;
#[derive(Debug, Deserialize, Serialize, Clone, FromRow, Decode, Encode)]
pub struct Supplier {
pub id: i64,
pub topm_id: String,
pub name: String,
pub bio_info: Option<String>,
}
fn from_postgres_row_small(row: PgRow) -> Supplier {
Supplier {
id: row.get(0),
topm_id: row.get(1),
name: row.get(2),
bio_info: row.get(3),
}
}
pub async fn load_suppliers(pool: PgPool) -> Option<Vec<Supplier>> {
let statement = format!(
"SELECT * FROM {}",
"supplier",
);
let res = sqlx::query(
AssertSqlSafe(statement.as_str()))
.fetch_all(&pool).await;
let mut suppliers: Vec<Supplier> = Vec::new();
match res {
Ok(records) => {
for record in records {
suppliers.push(
from_postgres_row_small(record)
);
}
Some(suppliers)
}
Err(err) => {
error!("Error while loading all suppliers");
None
}
}
}
pub async fn load_supplier(id: i64, pool: &PgPool) -> Option<Supplier> {
let statement = format!(
"SELECT * FROM {} WHERE $1 = id",
"supplier",
);
let mut args = PgArguments::default();
args.add(id);
let res = sqlx::query_with(
AssertSqlSafe(statement.as_str()), args)
.fetch_one(pool).await;
match res {
Ok(record) => {
Some(from_postgres_row_small(record))
}
Err(err) => {
error!("Error while loading supplier: {}", id);
None
}
}
}
pub async fn insert_supplier(supplier: &Supplier, pool: PgPool) -> Option<Supplier> {
let mut args = PgArguments::default();
args.add(&supplier.topm_id);
args.add(&supplier.name);
args.add(&supplier.bio_info);
let statement = format!(
"INSERT INTO {} (topm_id, name, bio_info) VALUES ($1, $2, $3) RETURNING *",
"supplier",
);
let res = sqlx::query_with(
AssertSqlSafe(statement.as_str()),
args)
.fetch_one(&pool).await;
info!("{:#?}", res);
match res {
Ok(record) => {
let supplier = from_postgres_row_small(record);
Some(supplier)
}
Err(err) => {
error!("Error while loading newly created supplier: {}", supplier.name);
None
}
}
}
pub async fn update_supplier(supplier_id: i64, supplier: &Supplier, pool: PgPool) -> Option<Supplier> {
let mut args = PgArguments::default();
args.add(&supplier.id);
args.add(&supplier.topm_id);
args.add(&supplier.name);
args.add(&supplier.bio_info);
let statement = format!(
"UPDATE {} SET topm_id = $2, name = $3, bio_info = $4 WHERE id = $1 RETURNING *",
"supplier",
);
let res = sqlx::query_with(
AssertSqlSafe(statement.as_str()),
args)
.fetch_one(&pool).await;
info!("{:#?}", res);
match res {
Ok(record) => {
let supplier = from_postgres_row_small(record);
Some(supplier)
}
Err(err) => {
error!("Error while updating supplier: {}", supplier_id);
None
}
}
}
pub async fn delete_supplier(supplier_id: i64, pool: PgPool) -> Option<()> {
let result = sqlx::query(
AssertSqlSafe(format!("DELETE FROM {} WHERE id = {}",
"supplier",
supplier_id
).as_str())
).execute(&pool).await;
match result {
Ok(_) => {
Some(())
}
Err(err) => {
println!("Error deleting supplier: {:#?}", err);
None
}
}
}
@@ -14,6 +14,12 @@
:vertical="true"
/>
<Supplier/>
<v-divider
:vertical="true"
/>
<Settings/>
<v-divider
@@ -0,0 +1,96 @@
<script setup lang="ts">
import {useLabelEditorStore} from "~/store/labelEditorStore";
import type {Ref} from "vue";
import LabelCreate from "~/components/label/labelCreate.vue";
let store = useLabelEditorStore();
let dialog: Ref<boolean> = ref<boolean>(false);
let loading: Ref<boolean> = ref<boolean>(false);
watch(dialog, async (oldDialog) => {
if (oldDialog) {
loading.value = true;
await store.loadSuppliers();
loading.value = false;
}
})
function closeDialog() {
dialog.value = false;
}
</script>
<template>
<v-dialog
v-model="dialog"
:scrollable="true"
width="900"
max-height="750"
height="750"
>
<template v-slot:activator="{ props }">
<v-btn
:flat="true"
v-bind="props"
size="small"
>
<v-icon>mdi-wheel-barrow </v-icon>
<v-tooltip
activator="parent"
location="bottom"
>
Lieferanten
</v-tooltip>
</v-btn>
</template>
<v-card>
<v-card-title>
<v-row style="padding-top: 10px">
<v-icon size="small">
mdi-label
</v-icon>
Lieferanten
<v-progress-circular v-if="loading" indeterminate :size="15" :width="2"></v-progress-circular>
<v-spacer/>
<v-divider vertical/>
<SupplierCreate/>
</v-row>
</v-card-title>
<v-divider/>
<v-card-text>
<SupplierRow
v-for="(supplier) in store.suppliers"
:key="supplier.id"
v-bind:supplier="supplier"
/>
</v-card-text>
<v-divider/>
<v-card-actions>
<v-spacer/>
<v-btn
variant="text"
:disabled="loading"
@click="closeDialog()"
>
Schließen
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<style scoped>
</style>
@@ -0,0 +1,120 @@
<script setup lang="ts">
import {useLabelEditorStore} from "~/store/labelEditorStore";
import type {Ref} from "vue";
import {Supplier} from "~/types/supplier";
let store = useLabelEditorStore();
let dialog: Ref<boolean> = ref<boolean>(false);
let loading: Ref<boolean> = ref<boolean>(false);
let topm_id: Ref<string | null> = ref<string | null>(null);
let name: Ref<string | null> = ref<string | null>(null);
let bio_info: Ref<string | null> = ref<string | null>(null);
async function create() {
if (topm_id.value != null && topm_id.value.trim().length > 0 &&
name.value != null && name.value.trim().length > 0 &&
bio_info.value != null && bio_info.value.trim().length > 0) {
const supplier = new Supplier(0, topm_id.value, name.value, bio_info.value);
await store.createSupplier(supplier);
closeDialog();
}
}
function closeDialog() {
dialog.value = false;
clearVariables();
}
function clearVariables() {
topm_id.value = null;
name.value = null;
bio_info.value = null;
loading.value = false;
}
</script>
<template>
<v-dialog
v-model="dialog"
:scrollable="true"
width="800"
max-height="750"
>
<template v-slot:activator="{ props }">
<v-btn
:flat="true"
v-bind="props"
size="small"
>
<v-icon>mdi-plus-thick</v-icon>
<v-tooltip
activator="parent"
location="bottom"
>
Lieferant erstellen
</v-tooltip>
</v-btn>
</template>
<v-card>
<v-card-title>
<v-icon size="small">
mdi-plus-thick
</v-icon>
Lieferant erstellen
<v-progress-circular v-if="loading" indeterminate :size="15" :width="2"></v-progress-circular>
</v-card-title>
<v-divider/>
<v-card-text>
<v-text-field
v-model.trim="topm_id"
label="TopM ID"
autofocus
/>
<v-text-field
v-model.trim="name"
label="Name"
/>
<v-text-field
v-model.trim="bio_info"
label="BIO Info"
/>
</v-card-text>
<v-divider/>
<v-card-actions>
<v-spacer/>
<v-btn
variant="text"
:disabled="loading"
@click="closeDialog()"
>
Schließen
</v-btn>
<v-btn
variant="text"
:disabled="topm_id == null || name == null || loading"
@click="create();"
>
Erstellen
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<style scoped>
</style>
@@ -0,0 +1,140 @@
<script setup lang="ts">
import {useLabelEditorStore} from "~/store/labelEditorStore";
import type {Ref} from "vue";
import DeleteConfirm from "~/components/ui/deleteConfirm.vue";
import {Supplier} from "~/types/supplier";
let store = useLabelEditorStore();
const props = defineProps({
supplier: {type: Object as PropType<Supplier>, required: true},
});
let edit: Ref<boolean> = ref<boolean>(false);
let topm_id: Ref<string | null> = ref<string | null>(JSON.parse(JSON.stringify(props.supplier.topm_id)));
let name: Ref<string | null> = ref<string | null>(JSON.parse(JSON.stringify(props.supplier.name)));
let bio_info: Ref<string | null> = ref<string | null>(JSON.parse(JSON.stringify(props.supplier.bio_info)));
function toggleEdit() {
if (edit.value) {
disableEdit();
} else {
enableEdit();
}
}
function enableEdit() {
edit.value = true;
}
function disableEdit() {
topm_id.value = JSON.parse(JSON.stringify(props.supplier.topm_id));
name.value = JSON.parse(JSON.stringify(props.supplier.name));
bio_info.value = JSON.parse(JSON.stringify(props.supplier.bio_info));
edit.value = false;
}
async function updateSupplier() {
if (topm_id.value != null && topm_id.value.trim().length > 0 &&
name.value != null && name.value.trim().length > 0 &&
bio_info.value != null && bio_info.value.trim().length > 0) {
const supplier = new Supplier(props.supplier.id, topm_id.value, name.value, bio_info.value);
await store.updateSupplier(supplier);
disableEdit();
}
}
async function deleteSupplier() {
await store.deleteSupplier(props.supplier.id);
}
</script>
<template>
<v-card>
<v-card-title>
<v-row style="padding-top: 10px">
<v-col>
<v-text-field
v-model.trim="topm_id"
label="TopM ID"
:readonly="!edit"
/>
<v-text-field
v-model.trim="name"
label="Bezeichnung"
:readonly="!edit"
/>
<v-text-field
v-model.trim="bio_info"
label="BIO Info"
:readonly="!edit"
/>
</v-col>
<v-spacer />
<v-divider vertical/>
<DeleteConfirm
title="Lieferant löschen?"
:disable="!edit"
@delete="deleteSupplier()"
/>
<v-divider vertical/>
<v-btn
:flat="true"
:disabled="!edit"
:hidden="edit"
@click="disableEdit()"
>
<v-icon>mdi-cancel</v-icon>
<v-tooltip
activator="parent"
location="bottom"
>
Abbrechen
</v-tooltip>
</v-btn>
<v-btn
:flat="true"
:disabled="!edit"
:hidden="edit"
@click="updateSupplier()"
>
<v-icon>mdi-content-save</v-icon>
<v-tooltip
activator="parent"
location="bottom"
>
Speichern
</v-tooltip>
</v-btn>
<v-divider vertical/>
<v-btn
:flat="true"
@click="toggleEdit();"
>
<v-icon>mdi-pencil</v-icon>
<v-tooltip
activator="parent"
location="bottom"
>
Bearbeiten
</v-tooltip>
</v-btn>
</v-row>
</v-card-title>
</v-card>
</template>
<style scoped>
</style>
+70
View File
@@ -7,6 +7,7 @@ import type {Variant} from "~/types/variant";
import {Unit} from "~/types/unit";
import type {Label} from "~/types/label";
import type {Settings} from "~/types/settings";
import type {Supplier} from "~/types/supplier";
interface State {
config: RuntimeConfig,
@@ -29,6 +30,8 @@ interface State {
origins: Array<Origin>,
units: Array<Unit>,
suppliers: Array<Supplier>,
}
export const useLabelEditorStore = defineStore('label_editor_store', {
@@ -64,6 +67,8 @@ export const useLabelEditorStore = defineStore('label_editor_store', {
Unit.L,
Unit.Stk,
],
suppliers: [],
}),
actions: {
// Notification
@@ -385,5 +390,70 @@ export const useLabelEditorStore = defineStore('label_editor_store', {
this.addNotification(true, 'Kann Variante nicht gelöscht werden. Es ist kein Artikel ausgewählt.');
}
},
// Supplier:
async loadSuppliers() {
try {
const suppliers: Array<Supplier> = await $fetch<Array<Supplier>>(this.config.public.url + '/supplier', {
method: 'GET',
});
this.suppliers = suppliers;
this.addNotification(false, 'Lieferanten geladen');
} catch {
this.addNotification(true, 'Fehler beim laden der Lieferanten');
}
},
async createSupplier(supplier: Supplier) {
try {
let createdSupplier = await $fetch<Supplier>(this.config.public.url + '/supplier', {
method: 'POST',
body: JSON.stringify(supplier),
});
this.suppliers.push(createdSupplier);
this.addNotification(false, 'Lieferant "' + createdSupplier.name + '" erstellt');
} catch {
this.addNotification(true, 'Fehler beim erstellen des Lieferant: ' + supplier.name);
}
},
async updateSupplier(supplier: Supplier) {
let labelIndex = this.labels.findIndex(i => i.id === supplier.id);
try {
let updatedSupplier = await $fetch<Supplier>(this.config.public.url + '/supplier/' + supplier.id, {
method: 'POST',
body: JSON.stringify(supplier),
});
this.labels[labelIndex] = updatedSupplier;
this.addNotification(false, 'Lieferant aktualisiert.');
} catch {
this.addNotification(true, 'Fehler beim aktualisieren des Lieferanten.');
}
},
async deleteSupplier(supplierID: number) {
let supplierIndex = this.suppliers.findIndex(i => i.id === supplierID);
try {
await $fetch(this.config.public.url + '/supplier/' + supplierID, {
method: 'DELETE',
});
this.suppliers.splice(supplierIndex, 1);
this.addNotification(false, 'Lieferant gelöscht.');
} catch {
this.addNotification(true, 'Fehler beim löschen des Lieferanten.');
}
},
},
});
+13
View File
@@ -0,0 +1,13 @@
export class Supplier {
readonly id: number;
topm_id: string;
name: string;
bio_info: string | null;
constructor(id: number, topm_id: string, name: string, bio_info: string | null) {
this.id = id;
this.topm_id = topm_id;
this.name = name;
this.bio_info = bio_info;
}
}
+2802 -2994
View File
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -10,17 +10,17 @@
"postinstall": "nuxt prepare"
},
"dependencies": {
"@fontsource/roboto": "5.2.10",
"@fontsource/roboto": "5.3.00",
"@mdi/font": "7.4.47",
"@pinia/nuxt": "0.11.3",
"nuxt": "4.4.7",
"pinia": "3.0.4",
"vue": "3.5.35",
"vue-router": "5.1.0",
"vuetify-pro-tiptap": "2.8.2"
"@pinia/nuxt": "1.0.1",
"nuxt": "4.5.0",
"pinia": "4.0.2",
"vue": "3.5.40",
"vue-router": "5.2.0",
"vuetify-pro-tiptap": "3.0.0"
},
"devDependencies": {
"vite-plugin-vuetify": "2.1.3",
"vuetify": "4.1.0"
"vuetify": "4.1.5"
}
}
+7 -8
View File
@@ -1,6 +1,6 @@
[package]
name = "server"
version = "0.1.0"
version = "0.3.0"
edition = "2024"
authors = ["Matthias Lodner <matthias@lodner.de>"]
@@ -12,21 +12,20 @@ path = "src/main.rs"
common = {path = "../common"}
axum = "0.8.9"
tokio = { version = "1.52.3", default-features = false, features = ["full"] }
http = "1.4.1"
tower-http = {version = "0.6.11", features = ["cors"]}
tokio = { version = "1.53.1", default-features = false, features = ["full"] }
http = "1.4.2"
tower-http = {version = "0.7.0", features = ["cors"]}
tracing = "=0.1.44"
tracing-subscriber = "0.3.23"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.150"
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.151"
# Logging
env_logger = "0.11.10"
env_logger = "0.11.11"
# Database
sqlx = { version = "0.9.0", features = [ "runtime-async-std", "postgres", "chrono", "macros" ] }
# Etc.
dotenv = "0.15.0"
chrono = { version = "0.4.45" }
@@ -0,0 +1,11 @@
-- Add migration script here
CREATE TABLE supplier
(
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 ),
topm_id text NOT NULL,
name text NOT NULL,
bio_info text
);
-- Insert default values
INSERT INTO supplier (topm_id, name, bio_info) VALUES ('999', 'Lodner Gewürze', 'DE-ÖKO-006');
+88
View File
@@ -18,6 +18,7 @@ use http::header::{AUTHORIZATION, ACCEPT, ACCESS_CONTROL_ALLOW_ORIGIN, CONTENT_T
use common::models::article;
use common::models::label::{delete_label, insert_label, load_labels, update_label, Label};
use common::models::settings::{load_settings, update_settings, Settings};
use common::models::supplier::{delete_supplier, insert_supplier, load_suppliers, update_supplier, Supplier};
use common::models::unit::Unit;
use common::models::variant::{delete_variant, insert_variant, update_variant, Variant};
@@ -63,6 +64,10 @@ async fn main() {
.route("/label/{id}", delete(delete_label_route))
.route("/settings", get(get_settings_route))
.route("/settings", post(update_settings_route))
.route("/supplier", get(get_suppliers_route))
.route("/supplier", post(add_supplier_route))
.route("/supplier/{id}", post(update_supplier_route))
.route("/supplier/{id}", delete(delete_supplier_route))
.with_state(pool)
.layer(cors);
@@ -425,3 +430,86 @@ async fn update_settings_route(
}
}
}
#[tracing::instrument(ret)]
async fn get_suppliers_route(
State(pool): State<PgPool>,
) -> (StatusCode, Json<Vec<Supplier>>) {
info!("Get all suppliers");
match load_suppliers(pool).await {
Some(suppliers) => {
(StatusCode::OK, Json(suppliers))
}
None => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(vec![]))
}
}
}
#[tracing::instrument(ret)]
async fn add_supplier_route(
State(pool): State<PgPool>,
Json(payload): Json<Supplier>,
) -> (StatusCode, Json<Supplier>) {
info!("Add supplier");
match insert_supplier(&payload, pool).await {
Some(supplier) => {
(StatusCode::OK, Json(supplier))
}
None => {
let supplier = Supplier {
id: 0,
topm_id: "".to_string(),
name: "".to_string(),
bio_info: None,
};
(StatusCode::INTERNAL_SERVER_ERROR, Json(supplier))
}
}
}
#[tracing::instrument(ret)]
async fn update_supplier_route(
State(pool): State<PgPool>,
Path(supplier_id): Path<i64>,
Json(payload): Json<Supplier>,
) -> (StatusCode, Json<Supplier>) {
info!("Update supplier");
match update_supplier(supplier_id, &payload, pool).await {
Some(supplier) => {
(StatusCode::OK, Json(supplier))
}
None => {
let supplier = Supplier {
id: 0,
topm_id: "".to_string(),
name: "".to_string(),
bio_info: None,
};
(StatusCode::INTERNAL_SERVER_ERROR, Json(supplier))
}
}
}
async fn delete_supplier_route(
State(pool): State<PgPool>,
Path(supplier_id): Path<i64>,
) -> StatusCode {
info!("Delete supplier");
let deleted_result = delete_supplier(supplier_id, pool).await;
match deleted_result {
Some(_) => {
StatusCode::OK
}
None => {
StatusCode::INTERNAL_SERVER_ERROR
}
}
}