From a8a64e064e319af3e451cb58b009b4b0b7ad983a Mon Sep 17 00:00:00 2001 From: Sibin Sabu Date: Mon, 4 Aug 2025 12:35:43 +0530 Subject: [PATCH] fix : added print , WSP and MJP logic (working) --- .../selection.service/selection.service.ts | 50 ++- .../touch-pad-menu.component.html | 2 +- .../touch-pad-menu.component.ts | 337 ++++++++++++++++-- 3 files changed, 362 insertions(+), 27 deletions(-) diff --git a/btc-UI/src/app/components/selection.service/selection.service.ts b/btc-UI/src/app/components/selection.service/selection.service.ts index 71363de..44176aa 100644 --- a/btc-UI/src/app/components/selection.service/selection.service.ts +++ b/btc-UI/src/app/components/selection.service/selection.service.ts @@ -165,18 +165,20 @@ export class SelectionService { const legCount = this.getLegCount(label); const legs = this.splitToLegs(numbers, legCount); + // Override for MJP to always start from race 1 + const baseIdx = label === 'MJP' ? 0 : this.multiLegBaseRaceIdx - 1; + const legCounts = legs.map((leg, idx) => { let count = 0; for (const item of leg) { if (item === 'F') { - count += this.getRunnerCountForLeg(this.multiLegBaseRaceIdx, idx); + count += this.getRunnerCountForLeg(baseIdx + 1, idx); } else if (typeof item === 'number') { count += 1; } } return count; }); - const combinations = legCounts.reduce((acc, count) => acc * (count || 1), 1); updated.total = combinations * value * 10; break; @@ -259,4 +261,48 @@ export class SelectionService { const race = raceCardData?.raceVenueRaces?.races?.[raceIdx] || []; return Array.isArray(race) ? race.length : 12; } + + + + private calculateTotal(data: SelectionData): number { + const temp = new BehaviorSubject(data); + const originalCurrent = this.currentRow; + this.currentRow = temp; + this.updatePartial(data); + const total = temp.value.total; + this.currentRow = originalCurrent; // Restore original + return total; +} + + + //-----------------ADDED THIS---------------------------------------------------// + createVirtualRowsFromWSP(): SelectionData[] { + const base = this.currentRow.value; + + if (!base.numbers.length || base.value <= 0) return []; + + return ['WIN', 'SHP', 'THP'].map(label => { + const newRow: SelectionData = { + ...base, + label, + total: 0 + }; + newRow.total = this.calculateTotal(newRow); + return newRow; + }); +} + +setSelections(rows: SelectionData[]) { + this.selections.next(rows); +} + +getSelections(): SelectionData[] { + return this.selections.getValue(); +} + +getCurrentRow(): SelectionData { + return this.currentRow.value; +} + + } diff --git a/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.html b/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.html index ef61dc5..46b7068 100755 --- a/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.html +++ b/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.html @@ -93,7 +93,7 @@
- +
diff --git a/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.ts b/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.ts index fbd4513..d9a7d1b 100755 --- a/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.ts +++ b/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.ts @@ -31,6 +31,8 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { labelRowsFlat: string[] = []; numbersFlat: number[] = []; + wspTicketStage: number = 0; //added this + selectedLabel: string | null = null; selectedNumbers: (number | string)[] = []; padValue: string = ''; @@ -228,6 +230,39 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { }); } +//----------------------------------ADDED THIS ----------------------------------------------------- + + if (label === 'WSP') { + const wspLabels = ['WIN', 'SHP', 'THP']; + this.wspTicketStage = 0; // Add this line + // Finalize any existing row before creating new ones + this.selectionService.finalizeCurrentRow(); + + // Immediately add 3 blank rows to the selection list + const currentSelections = this.selectionService['selections'].value; + const blankRows = wspLabels.map(lbl => ({ + label: lbl, + numbers: [], + value: 0, + total: 0, + isBoxed: false + })); + + const totalNew = 0; // Each row is empty initially + const totalExisting = currentSelections.reduce((sum, r) => sum + r.total, 0); + + if (totalExisting + totalNew <= 5000) { + this.selectionService['selections'].next([...currentSelections, ...blankRows]); + } + + // Clear the input area (so no editing conflicts) + this.selectionService.updatePartial({ label: '', numbers: [], value: 0, total: 0 }); + + return; // Skip default updatePartial below + } + + //----------------------------------ended here---------------------------------------------------- + // Reset TAN this.tanGroupStage = 0; this.tanGroups = [[], [], []]; @@ -339,12 +374,33 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { return; } - // Default single-number selection - if (!this.selectedNumbers.includes(number)) { - this.selectedNumbers.push(number); - this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); + // Default single-number selection (WIN, SHP, THP, etc.) + if (!this.selectedNumbers.includes(number)) { + this.selectedNumbers.push(number); + this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); + + // โœ… Special logic: If WSP, mirror number to WIN, SHP, and THP + if (this.selectedLabel === 'WSP') { + const labelsToUpdate = ['WIN', 'SHP', 'THP']; + const selections = this.selectionService.getSelections(); + const updated = selections.map(sel => { + if (labelsToUpdate.includes(sel.label)) { + const newNumbers = [...sel.numbers]; + if (!newNumbers.includes(number)) { + newNumbers.push(number); + } + return { ...sel, numbers: newNumbers }; + } + return sel; + }); + this.selectionService.setSelections(updated); } } + } + + + + private updateMultiLegSelection() { const combined: (number | string)[] = []; @@ -361,12 +417,55 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { return horsesPerLeg.reduce((acc, v) => acc * v, 1) * units * unitBet; } + + //-------------------------ON PAD ENTER------------------------------------// + + // onPadEnter() { + // if (this.canPrint) { + // this.print(); + // } + // } + + onPadEnter() { - if (this.canPrint) { - this.print(); - } + if (!this.canPrint) { + this.print(); + } + + const value = parseFloat(this.padValue) || 0; + + if (this.selectedLabel === 'WSP') { + const labels = ['WIN', 'SHP', 'THP']; + const targetLabel = labels[this.wspTicketStage]; + + const updatedSelections = this.selectionService.getSelections().map(sel => { + if (sel.label === targetLabel && JSON.stringify(sel.numbers) === JSON.stringify(this.selectedNumbers)) { + return { + ...sel, + value, + total: value * (sel.numbers?.length || 0) * 10 + }; + } + return sel; + }); + + this.selectionService.setSelections(updatedSelections); + + // Move to next stage + this.wspTicketStage = (this.wspTicketStage + 1) % 3; + this.padValue = ''; + this.updateCanPrint(); + + return; } + // โœ… Default path: finalize row and reset input + this.print(); +} + + +//--------------------------------------------------------------------------// + onShashEnter() { if (this.selectedLabel === 'TAN' && this.isBoxed) { return; @@ -404,28 +503,86 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { } } + //-----------------------------ENTER PAD VALUE------------------------------------- + + // enterPadVal(key: string) { + // if (!this.numericPadEnabled || this.totalAmountLimitReached) return; + + // if (key === 'X') { + // this.padValue = ''; + // } else if (/[0-9]/.test(key)) { + // const currentValue = parseInt(this.padValue + key) || 0; + // if (currentValue > 100) return; + // this.padValue += key; + // } + + // this.updateCanPrint(); + + // const value = parseFloat(this.padValue) || 0; + // this.selectionService.updatePartial({ + // value, + // isBoxed: this.isBoxed, + // label: this.selectedLabel || '', + // numbers: [...this.selectedNumbers] + // }); + // } + enterPadVal(key: string) { - if (!this.numericPadEnabled || this.totalAmountLimitReached) return; + if (!this.numericPadEnabled || this.totalAmountLimitReached) return; - if (key === 'X') { - this.padValue = ''; - } else if (/[0-9]/.test(key)) { - const currentValue = parseInt(this.padValue + key) || 0; - if (currentValue > 100) return; - this.padValue += key; + if (key === 'X') { + this.padValue = ''; + if (this.selectedLabel === 'WSP') { + this.wspTicketStage = 0; // Reset stage if WSP } - - this.updateCanPrint(); - - const value = parseFloat(this.padValue) || 0; - this.selectionService.updatePartial({ - value, - isBoxed: this.isBoxed, - label: this.selectedLabel || '', - numbers: [...this.selectedNumbers] - }); + else if (/[0-9]/.test(key)) { + const currentValue = parseInt(this.padValue + key) || 0; + if (currentValue > 100) return; + this.padValue += key; + } } + if (/[0-9]/.test(key)) { + const currentValue = parseInt(this.padValue + key) || 0; + if (currentValue > 100) return; + this.padValue += key; + } + + this.updateCanPrint(); + + const value = parseFloat(this.padValue) || 0; + + if (this.selectedLabel === 'WSP') { + const labels = ['WIN', 'SHP', 'THP']; + const targetLabel = labels[this.wspTicketStage]; + + const updatedSelections = this.selectionService.getSelections().map(sel => { + if (sel.label === targetLabel && JSON.stringify(sel.numbers) === JSON.stringify(this.selectedNumbers)) { + const total = value * (sel.numbers?.length || 0) * 10; + return { + ...sel, + value, + total + }; + } + return sel; + }); + + this.selectionService.setSelections(updatedSelections); + + return; + } + + // ๐Ÿ”ต Default path for non-WSP + this.selectionService.updatePartial({ + value, + isBoxed: this.isBoxed, + label: this.selectedLabel || '', + numbers: [...this.selectedNumbers] + }); +} +//--------------------------------------------------------------------------------------------- + updateCanPrint() { this.canPrint = this.padValue.trim().length > 0 && /^[0-9]+$/.test(this.padValue); if (this.multiLegLabels.includes(this.selectedLabel || '')) { @@ -472,6 +629,138 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { this.resetSelections(); } +//-------------------PRINT LOGIC---------------------------------------- +printTicket() { + const selectionsTotal = this.currentSelections.reduce((sum, sel) => sum + sel.total, 0); + if (selectionsTotal + this.currentTotal > 5000) { + this.showLimitPopup = true; + return; + } + + //--------------------Added Print here + + console.log("๐Ÿ–จ๏ธ Print ticket clicked"); + + const selections = this.selectionService['selections'].value; + const currentRow = this.selectionService['currentRow'].value; + + let allRows = [...selections]; + + // โœ… Calculate total if currentRow is valid and not already finalized + if (currentRow.label && currentRow.numbers.length > 0 && currentRow.value > 0) { + if (!currentRow.total) { + let combinations = 1; + + if (['TAN', 'FOR', 'QUI'].includes(currentRow.label)) { + combinations = currentRow.numbers.length * (currentRow.numbers.length - 1); + } else if (['TRE', 'JKP', 'MJP'].includes(currentRow.label)) { + combinations = 1; // or your specific logic + } else if (currentRow.label === 'BOX') { + const n = currentRow.numbers.length; + combinations = n > 1 ? (n * (n - 1)) / 2 : 0; + } + + currentRow.total = combinations * currentRow.value * 10; + } + + allRows.push(currentRow); + } + + if (allRows.length === 0) { + console.warn("No valid rows to print."); + return; + } + + const ticketCount = allRows.reduce((sum, row) => sum + (row.value || 0), 0); + const totalAmount = allRows.reduce((sum, row) => sum + (row.total || 0), 0); + + const now = new Date(); + const venue = 'MYS'; + const day = String(now.getDate()).padStart(2, '0'); + const month = String(now.getMonth() + 1).padStart(2, '0'); + const year = String(now.getFullYear()).slice(-2); + const fullYear = now.getFullYear(); + const timeStr = now.toTimeString().slice(0, 8).replace(/:/g, ''); + const millis = now.getMilliseconds().toString().padStart(3, '0'); + const ticketId = `${venue}/${fullYear}${month}${day}/1`; + const barcodeId = `1111${day}${month}${year}${timeStr}${millis}`; + + + +const winLabels = allRows.map(row => { + const label = row.label.padEnd(10); // WIN (or SHP) + const numbers = row.numbers.join(',').padEnd(15); // 1,2,3 + const value = (`*${row.value || 0}`).padEnd(8); // *4 + const total = `Rs ${row.total || 0}`.padStart(8); // Rs 80 + return `${label}${numbers}${value}${total}`; +}).join('\n'); + + // โœ… Print preview + const printData = { + ticketId, + barcodeId, + venue, + date: `${day}-${month}-${fullYear}`, + winLabels, + ticketCount, + totalAmount, + gstNumber: '29ABCDE1234F2Z5' + }; + + // ๐Ÿงพ Simulated console ticket + console.log('--- Simulated Ticket Print ---'); + console.log(`Ticket ID : ${printData.ticketId}`); + console.log(`Barcode ID : ${printData.barcodeId}`); + console.log(`|||||| ||| | ||||| |||| |`); // Dummy barcode + console.log(`WIN Labels :`); + printData.winLabels.split('\n').forEach(row => console.log(row)); + console.log(`*${printData.ticketCount} โ‚น${printData.totalAmount}`); + console.log(`GST Number : ${printData.gstNumber}`); + console.log(`Date/Time : ${now.toLocaleString()}`); + console.log('-----------------------------'); + + // ๐Ÿ–จ๏ธ Send to printer API + const payload = { + type: 'ticket', + ticketId: printData.ticketId, + barcodeId: printData.barcodeId, + winLabels: printData.winLabels, + ticketCount: printData.ticketCount, + totalAmount: printData.totalAmount, + gstNumber: printData.gstNumber, + dateTime: now.toLocaleString() + }; + + fetch('http://localhost:9100/print', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(payload) + }) + .then(response => { + if (!response.ok) { + throw new Error(`Printer error: ${response.status}`); + } + return response.text(); + }) + .then(result => { + console.log("โœ… Print successful:", result); + }) + .catch(error => { + console.error("โŒ Print failed:", error); + }); + + + //--------------------Ended Print here ----------------------------- + + this.selectionService.finalizeCurrentRow(); + this.resetSelections(); + } + + //----------------------------------PRINT ENDS HERE ------------------------------------------------------ + + + + erase() { this.selectionService.clearSelections(); this.resetSelections();