Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions frontend/src/lib/printer/unicode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const CURRENCY_ASCII_MAP: Record<string, string> = {
'₵': 'Gh',
'₡': 'Cr',
'₲': 'Pg',
'Kč': 'Kc', // Czech Koruna
};

export function normalizeCurrencyToAscii(text: string): string {
Expand All @@ -46,8 +47,10 @@ export function normalizeCurrencyToAscii(text: string): string {

/**
* Pads a resolved currency symbol to a fixed 2-character slot so amount
* columns line up whether the symbol is 1 or 2 characters wide.
* columns line up whether the symbol is 1 or 2 characters wide, and keeps
* the Czech receipt currency ASCII even when Unicode printing is enabled.
*/
export function padCurrencyPrefix(prefix: string): string {
return prefix.length >= 2 ? prefix : ' '.repeat(2 - prefix.length) + prefix;
const normalized = prefix.replaceAll('Kč', 'Kc');
return normalized.length >= 2 ? normalized : ' '.repeat(2 - normalized.length) + normalized;
}
93 changes: 93 additions & 0 deletions main/routes/orders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1471,4 +1471,97 @@ router.patch('/:id/items/:itemId/discount', requireRole('owner', 'manager'), (re
}
});


router.delete('/:id', requireRole('owner', 'manager'), (req: Request, res: Response) => {
try {
const orderId = Number(req.params.id);

if (!Number.isInteger(orderId) || orderId <= 0) {
return res.status(400).json({ error: 'Invalid order id' });
}

const db = getDatabase();

const order = db.prepare(
'SELECT id, order_number FROM orders WHERE id = ?'
).get(orderId) as { id: number; order_number: string } | undefined;

if (!order) {
return res.status(404).json({ error: 'Order not found' });
}

withTxn(() => {
// Najdi ├║─Źet nav├ízan├Ż na objedn├ívku.
const bills = db.prepare(
'SELECT id FROM bills WHERE order_id = ?'
).all(orderId) as { id: number }[];

const billIds = bills.map(bill => bill.id);

// Sma┼ż z├íznamy nav├ízan├ę na bill, kter├ę nemaj├ş ON DELETE CASCADE.
if (billIds.length > 0) {
const placeholders = billIds.map(() => '?').join(',');

db.prepare(
`DELETE FROM print_logs
WHERE bill_id IN (${placeholders})`
).run(...billIds);

db.prepare(
`DELETE FROM whatsapp_messages
WHERE bill_id IN (${placeholders})`
).run(...billIds);

// bill_items maj├ş ON DELETE CASCADE.
db.prepare(
`DELETE FROM bills
WHERE id IN (${placeholders})`
).run(...billIds);
}

// Sma┼ż addon z├íznamy objedn├ívkov├Żch polo┼żek.
const items = db.prepare(
'SELECT id FROM order_items WHERE order_id = ?'
).all(orderId) as { id: number }[];

const itemIds = items.map(item => item.id);

if (itemIds.length > 0) {
const placeholders = itemIds.map(() => '?').join(',');

db.prepare(
`DELETE FROM order_item_addons
WHERE order_item_id IN (${placeholders})`
).run(...itemIds);

db.prepare(
`DELETE FROM order_items
WHERE id IN (${placeholders})`
).run(...itemIds);
}

// Nakonec samotná objednávka.
db.prepare(
'DELETE FROM orders WHERE id = ?'
).run(orderId);
});

notifyOrderUpdated();

return res.json({
ok: true,
deleted: true,
order_number: order.order_number,
});
} catch (error: any) {
console.error('[API] Delete order error:', error);

return res.status(error.statusCode || 500).json({
error: error.statusCode
? error.message
: 'Failed to delete order',
});
}
});

export const orderRoutes = router;