Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
301530d
update: logo replacement with the pms logo
carbonitesolutions Nov 14, 2025
762af0e
Merge pull request #1 from Carbonite-Solutions-Ltd/logo
carbonitesolutions Nov 14, 2025
a8ab05f
update: error in payment of pos
carbonitesolutions Nov 16, 2025
865e3e6
Merge pull request #2 from Carbonite-Solutions-Ltd/logo
carbonitesolutions Nov 16, 2025
4b0f8fb
fix: amount not showing on order cards in v2
carbonitesolutions Dec 2, 2025
4b7facc
Merge pull request #3 from Carbonite-Solutions-Ltd/logo
carbonitesolutions Dec 2, 2025
7bc4cf2
Merge branch 'ury-erp:develop' into develop
carbonitesolutions Dec 2, 2025
4044721
fix: print issue resolve from the orders page
carbonitesolutions Dec 3, 2025
f1e93bc
fix: kot print when order is made
carbonitesolutions Dec 3, 2025
45605fd
fix: print with kot print format
carbonitesolutions Dec 3, 2025
2d5c9c2
Merge pull request #4 from Carbonite-Solutions-Ltd/print
carbonitesolutions Dec 3, 2025
43320b1
fix:Add QZ Tray integration for cloud-based POS printing
carbonitesolutions Dec 9, 2025
080933a
Merge pull request #5 from Carbonite-Solutions-Ltd/qz
carbonitesolutions Dec 9, 2025
9fb9e4e
Ignore QZ Tray certificate file
carbonitesolutions Dec 9, 2025
24e94a2
Merge pull request #6 from Carbonite-Solutions-Ltd/qz
carbonitesolutions Dec 9, 2025
71bd7f5
feat: logos and translation and special comment
carbonitesolutions Dec 12, 2025
f744f85
Merge pull request #7 from Carbonite-Solutions-Ltd/qz
carbonitesolutions Dec 12, 2025
58568c3
ury pos display test
Someonegreat Dec 15, 2025
35fa24d
fix: POS Display not showing
Someonegreat Dec 16, 2025
fffed1d
Update: Cash Customer default and adjustment removed
Someonegreat Dec 16, 2025
a7ed186
fix: Error when creating payment
Someonegreat Dec 19, 2025
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ ury/www/URYMosaic.html
build

*.lock
ury/public/pos/assets/ury/files/cert.pem
2 changes: 1 addition & 1 deletion URYMosaic/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" href="/ury.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>URY Mosaic</title>
<title> Ex Kitchen</title>
</head>
<body>
<div id="app"></div>
Expand Down
148 changes: 102 additions & 46 deletions URYMosaic/public/URY.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified URYMosaic/public/ury.ico
Binary file not shown.
26 changes: 26 additions & 0 deletions pos/find-complete-flow.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

echo "=== Finding Complete Print Flow ==="
echo ""

echo "1. Print function usage:"
grep -r "print(" . --include="*.ts" --include="*.tsx" 2>/dev/null | grep -v node_modules | grep -v "console.log\|print:" | head -10

echo ""
echo "2. Invoice/Payment completion:"
grep -r "complete.*payment\|submit.*invoice\|process.*payment" . --include="*.ts" --include="*.tsx" 2>/dev/null | grep -v node_modules | head -10

echo ""
echo "3. Files that import print functions:"
grep -r "from.*print" . --include="*.ts" --include="*.tsx" 2>/dev/null | grep -v node_modules

echo ""
echo "4. Checking PaymentDialog.tsx for print calls:"
grep -n "print\|complete\|submit" components/PaymentDialog.tsx 2>/dev/null | head -15

echo ""
echo "5. Checking pos-store.ts for relevant functions:"
grep -n "const.*=.*(" store/pos-store.ts 2>/dev/null | grep -i "pay\|invoice\|order\|complete" | head -10

echo ""
echo "=== Flow search complete ==="
2 changes: 1 addition & 1 deletion pos/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<link rel="icon" href="/ury.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<title>URY POS</title>
<title>Ex POS</title>
</head>
<body>
<div id="root"></div>
Expand Down
19 changes: 19 additions & 0 deletions pos/public/assets/ury/files/cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDCTCCAfGgAwIBAgIUIZxF0ANqYD5fB1Vyri+tz31AM1YwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MTIwNjE2MTAzMloXDTI2MTIw
NjE2MTAzMlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAwHFxEeKJKuPZvaERJToplCFmr+UnEBCOdWb1LfCw99W/
TnRwDjpYMdlHbhZKGVVOLE+CBZNR2lJ1OBZffYDqP75gbv4XLblxZkdwfTDpydXS
q3UFrZe1fqYI0BGZnnF405FQhKNxf7Vmmd8V7zw5V6mvx/GQF9DNNhbJWZvCixRZ
DrtHFGh8CJFqxxRjdg2uwAa7g7UuCED9Sd3xrw++7PB3T+wYVer2FOLiNBBMXihz
vyGq3vb1MatssfAfvqq4fzeogDLx5mAzn0TbFkfeSEgmb5kuYY/WtcTgfNGZYnTr
VDCMED0EF3SxB2FhPkGxtjxe/toG1RRLu1imYNGOaQIDAQABo1MwUTAdBgNVHQ4E
FgQU9A6xJl0jtU7wXrEJ5bcK3q78VKMwHwYDVR0jBBgwFoAU9A6xJl0jtU7wXrEJ
5bcK3q78VKMwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAF0Kr
ArH3A8FbJlVMAHdemGrufsW2P5LPRgBZONuWKuJuHmIqfLTAD4hiVFoqmp17y6+x
kMARzXn1zRNb+tnKzK9CfKmQlm9N6b8JG/TjUeFFOkPJmdoPjaqHj1e8Ivjhe6u/
Kp0l2BEvwpIIKu+jYt83N8M8tPCivfcSyG5zSXt8skzkEQM2myFhMAhjM0tieDCY
nRLiGdMCVX8F7xNvG1Mn/oUKAVTgzfdHMglEF4LKpvSx0qYo/A328/5pV4c54832
c5Bs9xG2FrfGejatNEzuXO8Bj8XQAjPNHJ3daH5KzTB/Jl5/qvR9/Vh13y8X4iZb
ylJEHZBAxeWVR5RpUg==
-----END CERTIFICATE-----
Binary file modified pos/public/ury.ico
Binary file not shown.
Binary file modified pos/public/ury_pos.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 12 additions & 1 deletion pos/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import ScreenSizeProvider from './components/ScreenSizeProvider';
import { ToastProvider } from './components/ui/toast';
import { usePOSStore } from './store/pos-store';
import { useEffect } from 'react';
import { setupKotListener } from './lib/kot-listener';
import { initPosDisplay, destroyPosDisplay } from './lib/pos-display';

function App() {
const {
Expand All @@ -18,7 +20,16 @@ function App() {

useEffect(() => {
initializeApp();
// Initialize KOT listener after app is ready
setupKotListener();
// Initialize POS display for dual screen
initPosDisplay();

return () => {
destroyPosDisplay();
};
}, [initializeApp]);

return (
<>
<ToastProvider />
Expand All @@ -45,4 +56,4 @@ function App() {
);
}

export default App;
export default App;
44 changes: 22 additions & 22 deletions pos/src/components/OrderPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,28 +96,28 @@ const OrderPanel = () => {
setIsSubmitting(true);

const orderData = {
items: activeOrders.map(item => ({
item: item.id,
item_name: item.name,
rate: item.selectedVariant?.price || item.price,
qty: item.quantity,
comment: item.comment || undefined
})),
no_of_pax: 1,
pos_profile: posProfile.name,
order_type: selectedOrderType,
table: selectedTable || undefined,
room: selectedRoom || undefined,
customer: selectedOrderType === 'Aggregators' ? selectedAggregator?.customer : selectedCustomer?.name,
aggregator_id: selectedOrderType === 'Aggregators' ? selectedAggregator?.customer : undefined,
cashier: posProfile.cashier,
owner: user.name,
mode_of_payment: paymentModes[0],
last_invoice: isUpdatingOrder ? orderId : null,
invoice: isUpdatingOrder ? orderId : null,
waiter: user.name,
comments: orderComment || undefined
};
items: activeOrders.map(item => ({
item: item.id,
item_name: item.name,
rate: item.selectedVariant?.price || item.price,
qty: item.quantity,
comment: item.comment || undefined
})),
no_of_pax: 1,
pos_profile: posProfile.name,
order_type: selectedOrderType,
table: selectedTable || undefined,
room: selectedRoom || undefined,
customer: selectedOrderType === 'Aggregators' ? selectedAggregator?.customer : selectedCustomer?.name,
aggregator_id: selectedOrderType === 'Aggregators' ? selectedAggregator?.customer : undefined,
cashier: posProfile.cashier,
owner: isUpdatingOrder ? undefined : user.name, // Only set owner for new orders
mode_of_payment: paymentModes[0],
last_invoice: isUpdatingOrder ? orderId : null,
invoice: isUpdatingOrder ? orderId : null,
waiter: user.name,
comments: orderComment || undefined
};

await syncOrder(orderData);

Expand Down
20 changes: 2 additions & 18 deletions pos/src/components/PaymentDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { DEFAULT_PAYMENT_MODE } from '../data/order-types';
interface PaymentDialogProps {
onClose: () => void;
grandTotal: number;
roundedTotal: number;
invoice: string;
customer: string;
posProfile: string;
Expand All @@ -24,7 +23,6 @@ interface PaymentDialogProps {
const PaymentDialog: React.FC<PaymentDialogProps> = ({
onClose,
grandTotal,
roundedTotal,
invoice,
customer,
posProfile,
Expand Down Expand Up @@ -73,16 +71,8 @@ const PaymentDialog: React.FC<PaymentDialogProps> = ({

// Order summary logic
const subtotal = grandTotal;
const adjustment = roundedTotal - grandTotal;
const roundedAdjustment = Math.round(adjustment * 100) / 100;
const showAdjustment = Math.abs(roundedAdjustment) > 0.001;
const totalDiscount = appliedDiscount;
const discountedTotal = Math.max(0, subtotal - totalDiscount);
// If discount is applied, round up; else, round normally
const finalTotal = appliedDiscount > 0 ? Math.ceil(discountedTotal) : Math.round(discountedTotal);
const finalAdjustment = finalTotal - discountedTotal;
const roundedFinalAdjustment = Math.round(finalAdjustment * 100) / 100;
const showFinalAdjustment = Math.abs(roundedFinalAdjustment) > 0.001;
const finalTotal = Math.max(0, subtotal - totalDiscount);

useEffect(()=>{
const defaultPaymentModePresent=paymentModes.find((mode)=>mode===DEFAULT_PAYMENT_MODE)
Expand Down Expand Up @@ -254,13 +244,7 @@ const PaymentDialog: React.FC<PaymentDialogProps> = ({
<span>-{formatCurrency(appliedDiscount)}</span>
</div>
)}
{/* Adjustment (if any) */}
{showFinalAdjustment && (
<div className="flex justify-between text-blue-600">
<span>Adjustment</span>
<span>{roundedFinalAdjustment > 0 ? '+' : ''}{formatCurrency(roundedFinalAdjustment)}</span>
</div>
)}

{/* Final Total (Rounded) */}
<div className="border-t pt-2">
<div className="flex justify-between font-semibold text-lg">
Expand Down
7 changes: 4 additions & 3 deletions pos/src/components/ProductDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,12 @@ const ProductDialog: React.FC<ProductDialogProps> = ({
removeFromOrder(itemToReplace.uniqueId);
}

// Add main item as a cart line
// Add main item as a cart line with comments
const orderItem: OrderItem = {
...selectedItem,
quantity: numericQuantity,
price: basePrice
price: basePrice,
comment: comments.trim() || undefined
};
addToOrder(orderItem);

Expand Down Expand Up @@ -484,4 +485,4 @@ const ProductDialog: React.FC<ProductDialogProps> = ({
);
};

export default ProductDialog;
export default ProductDialog;
118 changes: 118 additions & 0 deletions pos/src/lib/kot-listener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { printKotWithQz } from './print-qz';

let pollingInterval: NodeJS.Timeout | null = null;
let lastCheckedKot: string | null = null;

export function setupKotListener() {
if (typeof window === 'undefined') return;

console.log('✅ KOT polling listener initialized');

// Poll every 3 seconds for new KOTs
pollingInterval = setInterval(async () => {
try {
await checkForNewKots();
} catch (error) {
console.error('Error checking for KOTs:', error);
}
}, 3000);
}

async function checkForNewKots() {
try {
// Get the latest KOT
const response = await fetch('/api/method/ury.ury_pos.api.get_latest_kot');
const result = await response.json();

if (!result?.message) return;

const { kot_name, pos_profile, printers, kot_printed } = result.message;

// Skip if already printed or if we've already processed this KOT
if (kot_printed || kot_name === lastCheckedKot) return;

console.log('🔔 New KOT detected:', kot_name);
lastCheckedKot = kot_name;

if (!printers || printers.length === 0) {
console.error('No printers configured for KOT');
return;
}

// Print to each configured printer
for (const printerSetting of printers) {
const printerName = printerSetting.printer;
const printFormat = printerSetting.custom_kot_print_format || 'KOT Print';

try {
console.log(`🖨️ Printing KOT ${kot_name} to ${printerName}`);

// Fetch KOT HTML
const html = await getKotPrintHtml(kot_name, printFormat);

// Print with QZ to specific printer
await printKotWithQz(printerName, html);

console.log(`✅ KOT printed to ${printerName}`);

// Mark as printed
await markKotAsPrinted(kot_name);
} catch (error) {
console.error(`❌ Failed to print KOT to ${printerName}:`, error);
}
}
} catch (error) {
// Silently fail if no KOTs found
}
}

async function getKotPrintHtml(kotName: string, printFormat: string): Promise<string> {
const params = new URLSearchParams({
doc: 'URY KOT',
name: kotName,
print_format: printFormat,
_lang: 'en',
no_letterhead: '1',
letterhead: 'No Letterhead',
settings: '{}'
});

const response = await fetch(`/api/method/frappe.www.printview.get_html_and_style?${params}`);
const result = await response.json();

if (!result?.message?.html) {
throw new Error('Failed to fetch KOT HTML');
}

return `
<html>
<head>
<style>${result.message.style || ''}</style>
</head>
<body>${result.message.html}</body>
</html>
`;
}

async function markKotAsPrinted(kotName: string): Promise<void> {
try {
// Use GET request which doesn't require CSRF
const response = await fetch(`/api/method/ury.ury_pos.api.mark_kot_printed?kot_name=${encodeURIComponent(kotName)}`);

if (!response.ok) {
console.error('Failed to mark KOT as printed:', response.status);
} else {
console.log('✅ KOT marked as printed in database');
}
} catch (error) {
console.error('Error marking KOT as printed:', error);
}
}

export function stopKotListener() {
if (pollingInterval) {
clearInterval(pollingInterval);
pollingInterval = null;
console.log('🛑 KOT polling listener stopped');
}
}
Loading