Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2254a13ad0 |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "app-ts",
|
"name": "app-ts",
|
||||||
"version": "1.6.9",
|
"version": "1.7.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "dist/server.js",
|
"main": "dist/server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ export const offerListOptions = (filters: {
|
|||||||
perPage?: number;
|
perPage?: number;
|
||||||
status?: string;
|
status?: string;
|
||||||
customer_id?: number;
|
customer_id?: number;
|
||||||
has_order?: string;
|
|
||||||
}) =>
|
}) =>
|
||||||
queryOptions({
|
queryOptions({
|
||||||
queryKey: ["offers", "list", filters],
|
queryKey: ["offers", "list", filters],
|
||||||
@@ -87,7 +86,6 @@ export const offerListOptions = (filters: {
|
|||||||
if (filters.status) params.set("status", filters.status);
|
if (filters.status) params.set("status", filters.status);
|
||||||
if (filters.customer_id)
|
if (filters.customer_id)
|
||||||
params.set("customer_id", String(filters.customer_id));
|
params.set("customer_id", String(filters.customer_id));
|
||||||
if (filters.has_order) params.set("has_order", filters.has_order);
|
|
||||||
const qs = params.toString();
|
const qs = params.toString();
|
||||||
return paginatedJsonQuery(`/api/admin/offers${qs ? `?${qs}` : ""}`);
|
return paginatedJsonQuery(`/api/admin/offers${qs ? `?${qs}` : ""}`);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -168,6 +168,24 @@ function buildAddressLines(
|
|||||||
|
|
||||||
/* ── Translations ────────────────────────────────────────────────── */
|
/* ── Translations ────────────────────────────────────────────────── */
|
||||||
|
|
||||||
|
const paymentMethodMap: Record<string, Record<string, string>> = {
|
||||||
|
cs: {
|
||||||
|
"Bank transfer": "Příkazem",
|
||||||
|
Cash: "Hotově",
|
||||||
|
"Cash on delivery": "Dobírka",
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
Příkazem: "Bank transfer",
|
||||||
|
Hotově: "Cash",
|
||||||
|
Dobírka: "Cash on delivery",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function translatePaymentMethod(value: string | null, lang: string): string {
|
||||||
|
if (!value) return "";
|
||||||
|
return paymentMethodMap[lang]?.[value] || value;
|
||||||
|
}
|
||||||
|
|
||||||
const translations: Record<string, Record<string, string>> = {
|
const translations: Record<string, Record<string, string>> = {
|
||||||
cs: {
|
cs: {
|
||||||
title: "Faktura",
|
title: "Faktura",
|
||||||
@@ -181,6 +199,7 @@ const translations: Record<string, Record<string, string>> = {
|
|||||||
var_symbol: "Variabilní s.:",
|
var_symbol: "Variabilní s.:",
|
||||||
const_symbol: "Konstantní s.:",
|
const_symbol: "Konstantní s.:",
|
||||||
order_no: "Objednávka č.:",
|
order_no: "Objednávka č.:",
|
||||||
|
order_date: "Objednávka ze dne:",
|
||||||
issue_date: "Datum vystavení:",
|
issue_date: "Datum vystavení:",
|
||||||
due_date: "Datum splatnosti:",
|
due_date: "Datum splatnosti:",
|
||||||
tax_date: "Datum uskutečnění plnění:",
|
tax_date: "Datum uskutečnění plnění:",
|
||||||
@@ -213,6 +232,7 @@ const translations: Record<string, Record<string, string>> = {
|
|||||||
stamp: "Razítko:",
|
stamp: "Razítko:",
|
||||||
ico: "IČ: ",
|
ico: "IČ: ",
|
||||||
dic: "DIČ: ",
|
dic: "DIČ: ",
|
||||||
|
cnb_rate: "Přepočet kurzem ČNB ke dni",
|
||||||
},
|
},
|
||||||
en: {
|
en: {
|
||||||
title: "Invoice",
|
title: "Invoice",
|
||||||
@@ -226,6 +246,7 @@ const translations: Record<string, Record<string, string>> = {
|
|||||||
var_symbol: "Variable symbol:",
|
var_symbol: "Variable symbol:",
|
||||||
const_symbol: "Constant symbol:",
|
const_symbol: "Constant symbol:",
|
||||||
order_no: "Order No.:",
|
order_no: "Order No.:",
|
||||||
|
order_date: "Order date:",
|
||||||
issue_date: "Issue date:",
|
issue_date: "Issue date:",
|
||||||
due_date: "Due date:",
|
due_date: "Due date:",
|
||||||
tax_date: "Tax point date:",
|
tax_date: "Tax point date:",
|
||||||
@@ -257,6 +278,7 @@ const translations: Record<string, Record<string, string>> = {
|
|||||||
stamp: "Stamp:",
|
stamp: "Stamp:",
|
||||||
ico: "Reg. No.: ",
|
ico: "Reg. No.: ",
|
||||||
dic: "Tax ID: ",
|
dic: "Tax ID: ",
|
||||||
|
cnb_rate: "CNB exchange rate as of",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -923,9 +945,9 @@ ${indentCSS}
|
|||||||
<div class="info-row"><span class="lbl">${escapeHtml(t.issue_date)}</span> <span class="val">${escapeHtml(formatDate(invoice.issue_date))}</span></div>
|
<div class="info-row"><span class="lbl">${escapeHtml(t.issue_date)}</span> <span class="val">${escapeHtml(formatDate(invoice.issue_date))}</span></div>
|
||||||
<div class="info-row"><span class="lbl">${escapeHtml(t.due_date)}</span> <span class="val">${escapeHtml(formatDate(invoice.due_date))}</span></div>
|
<div class="info-row"><span class="lbl">${escapeHtml(t.due_date)}</span> <span class="val">${escapeHtml(formatDate(invoice.due_date))}</span></div>
|
||||||
<div class="info-row"><span class="lbl">${escapeHtml(t.tax_date)}</span> <span class="val">${escapeHtml(formatDate(invoice.tax_date))}</span></div>
|
<div class="info-row"><span class="lbl">${escapeHtml(t.tax_date)}</span> <span class="val">${escapeHtml(formatDate(invoice.tax_date))}</span></div>
|
||||||
<div class="info-row"><span class="lbl">${escapeHtml(t.payment_method)}</span> <span class="val">${escapeHtml(invoice.payment_method)}</span></div>
|
<div class="info-row"><span class="lbl">${escapeHtml(t.payment_method)}</span> <span class="val">${escapeHtml(translatePaymentMethod(invoice.payment_method, lang))}</span></div>
|
||||||
${orderNumber ? `<div class="info-row"><span class="lbl">${lang === "cs" ? "Objednávka č.:" : "Order no.:"}</span> <span class="val">${orderNumber}</span></div>` : ""}
|
${orderNumber ? `<div class="info-row"><span class="lbl">${escapeHtml(t.order_no)}</span> <span class="val">${orderNumber}</span></div>` : ""}
|
||||||
${orderDate ? `<div class="info-row"><span class="lbl">${lang === "cs" ? "Objednávka ze dne:" : "Order date:"}</span> <span class="val">${escapeHtml(orderDate)}</span></div>` : ""}
|
${orderDate ? `<div class="info-row"><span class="lbl">${escapeHtml(t.order_date)}</span> <span class="val">${escapeHtml(orderDate)}</span></div>` : ""}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -1008,7 +1030,7 @@ ${indentCSS}
|
|||||||
? `<tfoot>
|
? `<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" style="font-size:0.7em; color:#666; padding-top:6px; text-align:left;">
|
<td colspan="4" style="font-size:0.7em; color:#666; padding-top:6px; text-align:left;">
|
||||||
Přepočet kurzem ČNB ke dni ${formatDate(invoice.issue_date)}: 1 ${escapeHtml(currency)} = ${cnbRate.toFixed(3).replace(".", ",")} CZK
|
${escapeHtml(t.cnb_rate)} ${formatDate(invoice.issue_date)}: 1 ${escapeHtml(currency)} = ${cnbRate.toFixed(3).replace(".", ",")} CZK
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>`
|
</tfoot>`
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ export default async function quotationsRoutes(
|
|||||||
search,
|
search,
|
||||||
status: query.status ? String(query.status) : undefined,
|
status: query.status ? String(query.status) : undefined,
|
||||||
customer_id: query.customer_id ? Number(query.customer_id) : undefined,
|
customer_id: query.customer_id ? Number(query.customer_id) : undefined,
|
||||||
has_order: query.has_order ? String(query.has_order) : undefined,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return paginated(
|
return paginated(
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export const CreateQuotationSchema = z.object({
|
|||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.nullish(),
|
.nullish(),
|
||||||
|
created_at: z.string().nullish(),
|
||||||
valid_until: z.string().nullish(),
|
valid_until: z.string().nullish(),
|
||||||
currency: z.string().optional().default("CZK"),
|
currency: z.string().optional().default("CZK"),
|
||||||
language: z.string().optional().default("cs"),
|
language: z.string().optional().default("cs"),
|
||||||
@@ -76,6 +77,7 @@ export const UpdateQuotationSchema = z.object({
|
|||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
||||||
.optional(),
|
.optional(),
|
||||||
|
created_at: z.union([z.string(), z.null()]).optional(),
|
||||||
valid_until: z.union([z.string(), z.null()]).optional(),
|
valid_until: z.union([z.string(), z.null()]).optional(),
|
||||||
currency: z.string().optional(),
|
currency: z.string().optional(),
|
||||||
language: z.string().optional(),
|
language: z.string().optional(),
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ interface ListOffersParams {
|
|||||||
search: string;
|
search: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
customer_id?: number;
|
customer_id?: number;
|
||||||
has_order?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function enrichQuotation(q: any) {
|
function enrichQuotation(q: any) {
|
||||||
@@ -73,24 +72,13 @@ function enrichQuotation(q: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function listOffers(params: ListOffersParams) {
|
export async function listOffers(params: ListOffersParams) {
|
||||||
const {
|
const { page, limit, skip, sort, order, search, status, customer_id } =
|
||||||
page,
|
params;
|
||||||
limit,
|
|
||||||
skip,
|
|
||||||
sort,
|
|
||||||
order,
|
|
||||||
search,
|
|
||||||
status,
|
|
||||||
customer_id,
|
|
||||||
has_order,
|
|
||||||
} = params;
|
|
||||||
const sortField = ALLOWED_SORT_FIELDS.includes(sort) ? sort : "id";
|
const sortField = ALLOWED_SORT_FIELDS.includes(sort) ? sort : "id";
|
||||||
|
|
||||||
const where: Record<string, unknown> = {};
|
const where: Record<string, unknown> = {};
|
||||||
if (status) where.status = status;
|
if (status) where.status = status;
|
||||||
if (customer_id) where.customer_id = customer_id;
|
if (customer_id) where.customer_id = customer_id;
|
||||||
if (has_order === "yes") where.order_id = { not: null };
|
|
||||||
if (has_order === "no") where.order_id = null;
|
|
||||||
if (search) {
|
if (search) {
|
||||||
where.OR = [
|
where.OR = [
|
||||||
{ quotation_number: { contains: search } },
|
{ quotation_number: { contains: search } },
|
||||||
@@ -189,6 +177,9 @@ export async function createOffer(body: Record<string, any>) {
|
|||||||
quotation_number: quotationNumber,
|
quotation_number: quotationNumber,
|
||||||
project_code: body.project_code ? String(body.project_code) : null,
|
project_code: body.project_code ? String(body.project_code) : null,
|
||||||
customer_id: body.customer_id ? Number(body.customer_id) : null,
|
customer_id: body.customer_id ? Number(body.customer_id) : null,
|
||||||
|
created_at: body.created_at
|
||||||
|
? new Date(String(body.created_at))
|
||||||
|
: undefined,
|
||||||
valid_until: body.valid_until
|
valid_until: body.valid_until
|
||||||
? new Date(String(body.valid_until))
|
? new Date(String(body.valid_until))
|
||||||
: null,
|
: null,
|
||||||
@@ -251,6 +242,12 @@ export async function updateOffer(id: number, body: Record<string, any>) {
|
|||||||
const data = {
|
const data = {
|
||||||
customer_id:
|
customer_id:
|
||||||
body.customer_id !== undefined ? Number(body.customer_id) : undefined,
|
body.customer_id !== undefined ? Number(body.customer_id) : undefined,
|
||||||
|
created_at:
|
||||||
|
body.created_at !== undefined
|
||||||
|
? body.created_at
|
||||||
|
? new Date(String(body.created_at))
|
||||||
|
: null
|
||||||
|
: undefined,
|
||||||
valid_until:
|
valid_until:
|
||||||
body.valid_until !== undefined
|
body.valid_until !== undefined
|
||||||
? body.valid_until
|
? body.valid_until
|
||||||
|
|||||||
Reference in New Issue
Block a user