update cuz presentation
This commit is contained in:
parent
7a9e451739
commit
4e67cc4e19
29 changed files with 1065 additions and 88 deletions
9
server/api/clients/[id]/orders.get.ts
Normal file
9
server/api/clients/[id]/orders.get.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* global defineEventHandler */
|
||||
|
||||
import { baaWrapper } from "~/server/api/orders.get";
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const baa = await baaWrapper.RESTget(e, 50, 200, "`client` = ?", [e.context.params?.id]);
|
||||
console.log(baa);
|
||||
return baa;
|
||||
});
|
|
@ -3,8 +3,8 @@ import crypto from "crypto";
|
|||
|
||||
import { database, data } from "../utils/database";
|
||||
import { isString } from "../utils/isString";
|
||||
import Snowflake from "../utils/snowflake";
|
||||
import { cookieSettings } from "../utils/rootUtils";
|
||||
import Snowflake from "~/utils/snowflake";
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
if (getCookie(e, "token"))
|
||||
|
|
37
server/api/orders.get.ts
Normal file
37
server/api/orders.get.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* global defineEventHandler */
|
||||
|
||||
import BaaPagination from "../utils/baaPagination";
|
||||
import { data, database } from "../utils/database";
|
||||
import { client, orderSummary } from "~/utils/types/database";
|
||||
|
||||
export const baaWrapper = new BaaPagination<orderSummary, "id">(
|
||||
"orderSummaries",
|
||||
"id",
|
||||
"*, CONVERT(`client`, CHAR) AS `client`, CONVERT(`user`, CHAR) as `user`",
|
||||
);
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const orders = await baaWrapper.RESTget(e, 50, 200);
|
||||
|
||||
const uniqueClients: Array<string> = [];
|
||||
for (const i of orders) {
|
||||
if (!uniqueClients.includes(i.client))
|
||||
uniqueClients.push(database.escape(i.client));
|
||||
}
|
||||
|
||||
const [clients] = await database.query(
|
||||
["SELECT",
|
||||
"*,",
|
||||
"CONVERT(`id`, CHAR) AS `id`",
|
||||
"FROM `clients`",
|
||||
"WHERE `id` IN",
|
||||
`(${uniqueClients.join(', ')})`,
|
||||
].join(" "),
|
||||
) as data<client>;
|
||||
|
||||
const rvalue: Array<Omit<typeof orders, "client"> | { client?: client }> = [];
|
||||
|
||||
for (const i of orders)
|
||||
rvalue.push({ ...i, client: clients.find(e => i.client === e.id) });
|
||||
return rvalue;
|
||||
});
|
172
server/api/orders.post.ts
Normal file
172
server/api/orders.post.ts
Normal file
|
@ -0,0 +1,172 @@
|
|||
/* global defineEventHandler, createError, readBody, setResponseStatus */
|
||||
|
||||
import { createValidationError, handleRecursedValidationError } from "../utils/validation";
|
||||
import { database as db } from "../utils/database";
|
||||
import getRequestingUser from "../utils/getRequestingUser";
|
||||
import { getOrder } from "./orders/[id].get";
|
||||
import Snowflake from "~/utils/snowflake";
|
||||
|
||||
type importedProduct = {
|
||||
name: string | null,
|
||||
link: string,
|
||||
price_imported: number,
|
||||
price: number,
|
||||
}
|
||||
|
||||
type work = {
|
||||
offer: string,
|
||||
price: number,
|
||||
notes: string | null,
|
||||
is_fulfilled: boolean | 0 | 1,
|
||||
}
|
||||
|
||||
type order = {
|
||||
client: string,
|
||||
// user: string,
|
||||
is_draft: boolean | 0 | 1,
|
||||
imported_products: Array<importedProduct>,
|
||||
work: Array<work>,
|
||||
};
|
||||
|
||||
export function checkIsWork<Patch extends boolean = boolean>(
|
||||
value: any,
|
||||
patch: Patch,
|
||||
): value is Patch extends true ? Partial<work> : work {
|
||||
const errors = new Map<string, string>();
|
||||
|
||||
if (typeof value !== "object") {
|
||||
throw createError({
|
||||
message: "Invalid body",
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (!(typeof value.offer === "string" || (patch && value.offer === undefined))) errors.set("offer", "is not string");
|
||||
if (!(typeof value.price === "number" || (patch && value.price === undefined))) errors.set("price", "is not price");
|
||||
if (!(typeof value.notes === "string" || value.notes === null || (patch && value.notes === undefined))) errors.set("notes", "is not string or null");
|
||||
if (!(typeof value.is_fulfilled === "boolean" || value.is_fulfilled === 0 || value.is_fulfilled === 1 || (patch && value.is_fulfilled === undefined))) errors.set("is_fulfilled", "is not boolean");
|
||||
|
||||
if (errors.size !== 0) throw createValidationError(errors);
|
||||
return true;
|
||||
}
|
||||
|
||||
export function checkIsImportedProduct<Patch extends boolean = boolean>(
|
||||
value: any,
|
||||
patch: Patch,
|
||||
): value is Patch extends true ? Partial<importedProduct> : importedProduct {
|
||||
const errors = new Map<string, string>();
|
||||
|
||||
if (typeof value !== "object") {
|
||||
throw createError({
|
||||
message: "Invalid body",
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (!(typeof value.name === "string" || value.name === null || (patch && value.name === undefined))) errors.set("name", "is not string or null");
|
||||
if (!(typeof value.link === "string" || (patch && value.name === undefined))) errors.set("link", "is not string");
|
||||
if (!(typeof value.price_imported === "number" || (patch && value.name === undefined))) errors.set("price_imported", "is not number");
|
||||
if (!(typeof value.price || (patch && value.price === undefined))) errors.set("price", "is not number");
|
||||
|
||||
if (errors.size !== 0) throw createValidationError(errors);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function checkIsOrder<Patch extends boolean = boolean>(
|
||||
value: any,
|
||||
patch: Patch,
|
||||
): value is Patch extends true ? Partial<Pick<order, "client" | "is_draft">> : order {
|
||||
const errors = new Map<string, string>();
|
||||
|
||||
if (typeof value !== "object") {
|
||||
throw createError({
|
||||
message: "Invalid body",
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (!(typeof value.client === "string" || (patch && value.client === undefined))) errors.set("client", "is not string");
|
||||
if (!(typeof value.is_draft === "boolean" || value.is_draft === 0 || value.is_draft === 1 || (patch && value.is_draft === undefined))) errors.set("is_draft", "is not boolean");
|
||||
if (!(value.imported_products instanceof Array)) errors.set("imported_products", "is not array");
|
||||
else if (patch && value.imported_products !== undefined) errors.set("imported_products", "cannot patch from order");
|
||||
if (!(value.work instanceof Array)) errors.set("work", "is not array");
|
||||
else if (patch && value.work !== undefined) errors.set("work", "cannot patch from order");
|
||||
|
||||
if (!patch) {
|
||||
const importedProducts = value.imported_products;
|
||||
if (importedProducts instanceof Array) {
|
||||
for (const i in importedProducts) {
|
||||
try {
|
||||
checkIsImportedProduct(importedProducts[i], patch);
|
||||
} catch (e) {
|
||||
handleRecursedValidationError(e, errors, `imported_products[${i}]`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const work = value.work;
|
||||
if (work instanceof Array) {
|
||||
for (const i in work) {
|
||||
try {
|
||||
checkIsWork(work[i], patch);
|
||||
} catch (e) {
|
||||
handleRecursedValidationError(e, errors, `work[${i}]`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.size !== 0) throw createValidationError(errors);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const body = await readBody(e);
|
||||
const id = new Snowflake().toString();
|
||||
const user = await getRequestingUser(e);
|
||||
|
||||
if (!checkIsOrder(body, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
||||
|
||||
const database = await db.new();
|
||||
await database.beginTransaction();
|
||||
|
||||
await database.query(
|
||||
["INSERT INTO",
|
||||
"`orders`",
|
||||
"VALUES",
|
||||
"(?, ?, ?, ?)",
|
||||
].join(" "),
|
||||
[id, body.client, user.id, body.is_draft],
|
||||
);
|
||||
|
||||
const promises: Array<Promise<any>> = [];
|
||||
for (const i of body.imported_products) {
|
||||
promises.push(database.query(
|
||||
["INSERT INTO",
|
||||
"`imported_products`",
|
||||
"VALUES",
|
||||
"(?, ?, ?, ?, ?, ?)",
|
||||
].join(" "),
|
||||
[new Snowflake().toString(), id, i.name, i.link, i.price_imported, i.price],
|
||||
));
|
||||
}
|
||||
|
||||
for (const i of body.work) {
|
||||
promises.push(database.query(
|
||||
["INSERT INTO",
|
||||
"`work`",
|
||||
"VALUES",
|
||||
"(?, ?, ?, ?, ?, ?)",
|
||||
].join(" "),
|
||||
[new Snowflake().toString(), id, i.offer, i.price, i.notes, i.is_fulfilled],
|
||||
));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
await database.commit();
|
||||
|
||||
setResponseStatus(e, 201);
|
||||
return getOrder(id);
|
||||
});
|
17
server/api/orders/[id].delete.ts
Normal file
17
server/api/orders/[id].delete.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* global defineEventHandler, createError */
|
||||
import { ResultSetHeader } from "mysql2";
|
||||
|
||||
import { database } from "~/server/utils/database";
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const id = e.context.params?.id;
|
||||
|
||||
const [result] = await database.query(
|
||||
"DELETE FROM `orders` WHERE `id` = ?",
|
||||
[id],
|
||||
) as unknown as [ResultSetHeader];
|
||||
|
||||
if (result.affectedRows === 0) throw createError({ statusCode: 404 });
|
||||
|
||||
return null;
|
||||
});
|
108
server/api/orders/[id].get.ts
Normal file
108
server/api/orders/[id].get.ts
Normal file
|
@ -0,0 +1,108 @@
|
|||
/* global defineEventHandler, createError */
|
||||
|
||||
import { offer as offerType, order } from "~/utils/types/database";
|
||||
import { database, data } from "~/server/utils/database";
|
||||
|
||||
export async function orderExists(id: string) {
|
||||
const [[exists]] = await database.query(
|
||||
"SELECT EXISTS(*) AS `exists` FROM `orders` WHERE `id` = ?",
|
||||
[id],
|
||||
) as data<{exists: 0 | 1}>;
|
||||
|
||||
return exists.exists === 1;
|
||||
}
|
||||
|
||||
export async function getImportedProducts(id: string) {
|
||||
const [importedProducts] = await database.query(
|
||||
["SELECT",
|
||||
"CONVERT(`id`, CHAR) AS `id`,",
|
||||
"`name`,",
|
||||
"`link`,",
|
||||
"`price`,",
|
||||
"`price_imported`",
|
||||
"FROM `imported_products`",
|
||||
"WHERE `order` = ?",
|
||||
].join(" "),
|
||||
[id],
|
||||
) as data<{
|
||||
id: string,
|
||||
name: string | null,
|
||||
link: string,
|
||||
price: string,
|
||||
price_imported: string
|
||||
}>;
|
||||
|
||||
return importedProducts;
|
||||
}
|
||||
|
||||
export async function getWork(id: string) {
|
||||
const [work] = await database.query(
|
||||
["SELECT",
|
||||
"CONVERT(`id`, CHAR) AS `id`,",
|
||||
"CONVERT(`offer`, CHAR) AS `offer`,",
|
||||
"`price`,",
|
||||
"`notes`,",
|
||||
"`is_fulfilled`",
|
||||
"FROM `work`",
|
||||
"WHERE `order` = ?",
|
||||
].join(" "),
|
||||
[id],
|
||||
) as data<{
|
||||
id: string,
|
||||
offer: offerType,
|
||||
price: number,
|
||||
notes: string | null,
|
||||
is_fulfilled: 0 | 1,
|
||||
}>;
|
||||
|
||||
const [offer] = await database.query(
|
||||
["SELECT",
|
||||
"CONVERT(`offer`.`id`, CHAR) AS `id`,",
|
||||
"`offer`.`name`,",
|
||||
"`offer`.`description`,",
|
||||
"`offer`.`recommended_price`",
|
||||
"FROM",
|
||||
"`work`",
|
||||
"LEFT JOIN `offer` ON `work`.`offer` = `offer`.`id`",
|
||||
"WHERE `work`.`order` = ?",
|
||||
].join(" "),
|
||||
[id],
|
||||
) as data<offerType>;
|
||||
|
||||
// @ts-ignore i.offer is string, but it needs to be an offer object
|
||||
for (const i of work) i.offer = offer.find(e => e.id === i.offer) as offerType;
|
||||
return work;
|
||||
}
|
||||
|
||||
export async function getOrder(id: string): Promise<order> {
|
||||
const [[order]] = await database.query(
|
||||
["SELECT",
|
||||
"CONVERT(`id`, CHAR) AS `id`,",
|
||||
"CONVERT(`client`, CHAR) AS `client`,",
|
||||
"CONVERT(`user`, CHAR) AS `user`, ",
|
||||
"`is_draft`,",
|
||||
"`value`",
|
||||
"FROM `orderSummaries`",
|
||||
"WHERE `id` = ?",
|
||||
].join(" "),
|
||||
[id],
|
||||
) as data<{
|
||||
id: string,
|
||||
client: string,
|
||||
user: string,
|
||||
is_draft: 0 | 1,
|
||||
value: number,
|
||||
}>;
|
||||
|
||||
if (!order) throw createError({ statusCode: 404 });
|
||||
|
||||
const importedProducts = await getImportedProducts(id);
|
||||
const work = await getWork(id);
|
||||
|
||||
return { ...order, imported_products: importedProducts, work };
|
||||
}
|
||||
|
||||
export default defineEventHandler((e) => {
|
||||
const key = e.context.params?.id;
|
||||
return getOrder(key as string);
|
||||
});
|
17
server/api/orders/[id].patch.ts
Normal file
17
server/api/orders/[id].patch.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* global defineEventHandler, readBody, createError */
|
||||
|
||||
import { checkIsOrder } from "../orders.post";
|
||||
import { database as db } from "~/server/utils/database";
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const body = await readBody(e);
|
||||
const id = e.context.params?.id;
|
||||
|
||||
if (!checkIsOrder(e, true)) throw createError({ message: "Invalid body", statusCode: 400 });
|
||||
|
||||
const database = await db.new();
|
||||
await database.beginTransaction();
|
||||
|
||||
for (const [k, v] of Object.entries(body))
|
||||
database.query(`UPDATE TABLE \`orders\` SET \`${k}\` = ? WHERE \`id\` = ?`, [v, id]);
|
||||
});
|
12
server/api/orders/[id]/imported_products.get.ts
Normal file
12
server/api/orders/[id]/imported_products.get.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* global defineEventHandler, createError */
|
||||
|
||||
import { orderExists, getImportedProducts } from "../[id].get";
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const id = e.context.params?.id as string;
|
||||
|
||||
if (!orderExists(id)) throw createError({ statusCode: 404 });
|
||||
|
||||
const importedProducts = await getImportedProducts(id);
|
||||
return importedProducts;
|
||||
});
|
27
server/api/orders/[id]/imported_products.post.ts
Normal file
27
server/api/orders/[id]/imported_products.post.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* global defineEventHandler, readBody, createError, setResponseStatus */
|
||||
|
||||
import { checkIsImportedProduct } from "../../orders.post";
|
||||
import { getImportedProducts, orderExists } from "../[id].get";
|
||||
import Snowflake from "~/utils/snowflake";
|
||||
import { database } from "~/server/utils/database";
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const body = await readBody(e);
|
||||
const idOrder = e.context.params?.id as string;
|
||||
const idImportedProducts = new Snowflake().toString();
|
||||
|
||||
if (!orderExists(idOrder)) throw createError({ statusCode: 404 });
|
||||
if (!checkIsImportedProduct(body, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
||||
|
||||
await database.query(
|
||||
["INSERT INTO",
|
||||
"`imported_products`",
|
||||
"VALUES",
|
||||
"(?, ?, ?, ?, ?, ?)",
|
||||
].join(" "),
|
||||
[idImportedProducts, idOrder, body.name, body.link, body.price_imported, body.price],
|
||||
);
|
||||
|
||||
setResponseStatus(e, 201);
|
||||
return getImportedProducts(idOrder);
|
||||
});
|
12
server/api/orders/[id]/work.get.ts
Normal file
12
server/api/orders/[id]/work.get.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* global defineEventHandler, createError */
|
||||
|
||||
import { orderExists, getWork } from "../[id].get";
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const id = e.context.params?.id as string;
|
||||
|
||||
if (!orderExists(id)) throw createError({ statusCode: 404 });
|
||||
|
||||
const work = await getWork(id);
|
||||
return work;
|
||||
});
|
28
server/api/orders/[id]/work.post.ts
Normal file
28
server/api/orders/[id]/work.post.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* global defineEventHandler, readBody, createError, setResponseStatus */
|
||||
|
||||
import { checkIsWork } from "../../orders.post";
|
||||
import { getWork, orderExists } from "../[id].get";
|
||||
import Snowflake from "~/utils/snowflake";
|
||||
import { database } from "~/server/utils/database";
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const body = await readBody(e);
|
||||
const idOrder = e.context.params?.id as string;
|
||||
const idWork = new Snowflake().toString();
|
||||
|
||||
if (!orderExists(idOrder)) throw createError({ statusCode: 404 });
|
||||
if (!checkIsWork(body, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
||||
|
||||
await database.query(
|
||||
["INSERT INTO",
|
||||
"`work`",
|
||||
"VALUES",
|
||||
"(?, ?, ?, ?, ?, ?)",
|
||||
].join(" "),
|
||||
[idWork, idOrder, body.offer, body.price, body.notes, body.is_fulfilled],
|
||||
);
|
||||
|
||||
setResponseStatus(e, 201);
|
||||
|
||||
return getWork(idWork);
|
||||
});
|
20
server/api/orders/[id]/work/[idWork].delete.ts
Normal file
20
server/api/orders/[id]/work/[idWork].delete.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* global defineEventHandler, createError */
|
||||
|
||||
import { ResultSetHeader } from "mysql2";
|
||||
import { orderExists } from "../../[id].get";
|
||||
import { database } from "~/server/utils/database";
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const idOrder = e.context.params?.id as string;
|
||||
const idWork = e.context.params?.idWork as string;
|
||||
|
||||
if (!orderExists(idOrder)) throw createError({ statusCode: 404 });
|
||||
|
||||
const [response] = await database.query(
|
||||
"DELETE FROM `work` WHERE `id` = ?",
|
||||
[idWork],
|
||||
) as unknown as [ResultSetHeader];
|
||||
|
||||
if (response.affectedRows === 0) throw createError({ statusCode: 404 });
|
||||
return null;
|
||||
});
|
11
server/api/orders/[id]/work/[idWork].get.ts
Normal file
11
server/api/orders/[id]/work/[idWork].get.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/* global defineEventHandler, createError */
|
||||
|
||||
import { orderExists, getWork } from "../../[id].get";
|
||||
|
||||
export default defineEventHandler((e) => {
|
||||
const idOrder = e.context.params?.id as string;
|
||||
const idWork = e.context.params?.idWork as string;
|
||||
|
||||
if (!orderExists(idOrder)) throw createError({ statusCode: 404 });
|
||||
return getWork(idWork);
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue