boostreceipt-pro / script.js
Ontario's picture
Modify it to generate 80mm X 297mm with upload boost mobile logo option as well
c628e9a verified
document.addEventListener('DOMContentLoaded', function() {
// Initialize variables
let products = [];
let rtrAmount = 0;
let taxRate = 8.25;
// DOM elements
const productList = document.getElementById('productList');
const addProductBtn = document.getElementById('addProductBtn');
const rtrCheckbox = document.getElementById('rtrCheckbox');
const rtrContainer = document.getElementById('rtrContainer');
const rtrAmountInput = document.getElementById('rtrAmount');
const taxRateInput = document.getElementById('taxRate');
const generateBtn = document.getElementById('generateBtn');
const downloadBtn = document.getElementById('downloadBtn');
const resetBtn = document.getElementById('resetBtn');
const receiptPreview = document.getElementById('receiptPreview');
const storeNameInput = document.getElementById('storeName');
const storeAddressInput = document.getElementById('storeAddress');
const storeCityInput = document.getElementById('storeCity');
const logoUpload = document.getElementById('logoUpload');
const logoPreview = document.getElementById('logoPreview');
// Event listeners
addProductBtn.addEventListener('click', addProduct);
rtrCheckbox.addEventListener('change', toggleRtr);
rtrAmountInput.addEventListener('input', updateRtrAmount);
taxRateInput.addEventListener('input', updateTaxRate);
generateBtn.addEventListener('click', generateReceipt);
downloadBtn.addEventListener('click', downloadPDF);
resetBtn.addEventListener('click', resetForm);
logoUpload.addEventListener('change', handleLogoUpload);
// Handle logo upload
function handleLogoUpload(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
logoPreview.src = e.target.result;
logoPreview.classList.remove('hidden');
updateReceipt();
};
reader.readAsDataURL(file);
}
}
// Add product function
function addProduct() {
const productId = Date.now();
const productItem = document.createElement('div');
productItem.className = 'product-item';
productItem.dataset.id = productId;
productItem.innerHTML = `
<input type="text" placeholder="Product Name" class="product-name px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
<input type="number" placeholder="Price" step="0.01" min="0" class="product-price px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
<button class="remove-product px-2 py-1 text-red-500 hover:text-red-700">
<i data-feather="trash-2"></i>
</button>
`;
productList.appendChild(productItem);
feather.replace();
// Add event listener to remove button
const removeBtn = productItem.querySelector('.remove-product');
removeBtn.addEventListener('click', () => {
productList.removeChild(productItem);
updateReceipt();
});
// Add event listeners to inputs
const nameInput = productItem.querySelector('.product-name');
const priceInput = productItem.querySelector('.product-price');
nameInput.addEventListener('input', updateReceipt);
priceInput.addEventListener('input', updateReceipt);
}
// Toggle RTR payment
function toggleRtr() {
rtrContainer.classList.toggle('hidden', !rtrCheckbox.checked);
if (!rtrCheckbox.checked) {
rtrAmount = 0;
rtrAmountInput.value = '';
}
updateReceipt();
}
// Update RTR amount
function updateRtrAmount() {
rtrAmount = parseFloat(rtrAmountInput.value) || 0;
updateReceipt();
}
// Update tax rate
function updateTaxRate() {
taxRate = parseFloat(taxRateInput.value) || 0;
updateReceipt();
}
// Generate receipt preview
function updateReceipt() {
// Get all products
products = [];
const productItems = document.querySelectorAll('.product-item');
productItems.forEach(item => {
const name = item.querySelector('.product-name').value;
const price = parseFloat(item.querySelector('.product-price').value) || 0;
if (name && price > 0) {
products.push({ name, price });
}
});
// Calculate totals
const subtotal = products.reduce((sum, product) => sum + product.price, 0);
const taxableAmount = rtrCheckbox.checked ? subtotal : subtotal + rtrAmount;
const tax = taxableAmount * (taxRate / 100);
const total = subtotal + tax + (rtrCheckbox.checked ? rtrAmount : 0);
// Format current date and time
const now = new Date();
const date = now.toLocaleDateString('en-US', { month: '2-digit', day: '2-digit', year: 'numeric' });
const time = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
// Generate receipt HTML
let receiptHTML = '';
// Add logo if uploaded
if (logoPreview.src && !logoPreview.classList.contains('hidden')) {
receiptHTML += `<div class="logo-container"><img src="${logoPreview.src}" alt="Logo" class="logo"></div>\n`;
}
receiptHTML += `
<div class="header">
${storeNameInput.value || 'BOOST MOBILE'}\n
${storeAddressInput.value || '22424 IMPERIAL VALLEY DR'}\n
${storeCityInput.value || 'HOUSTON, TX 77073'}\n
\n
DATE: ${date} TIME: ${time}\n
\n
ITEM DESCRIPTION AMOUNT\n
----------------------------------------\n
`;
// Add products
products.forEach(product => {
const name = product.name.length > 20 ? product.name.substring(0, 17) + '...' : product.name;
const price = product.price.toFixed(2).padStart(8);
receiptHTML += `${name.padEnd(25)} ${price}\n`;
});
// Add RTR payment if checked
if (rtrCheckbox.checked && rtrAmount > 0) {
receiptHTML += `\nBoost RTR $5-500${' '.repeat(12)} ${rtrAmount.toFixed(2).padStart(8)}\n`;
receiptHTML += `(No Tax)${' '.repeat(25)}\n`;
}
// Add totals
receiptHTML += `
\n
----------------------------------------\n
SUBTOTAL${' '.repeat(19)} ${subtotal.toFixed(2).padStart(8)}\n
TAX${' '.repeat(24)} ${tax.toFixed(2).padStart(8)}\n
TOTAL${' '.repeat(22)} ${total.toFixed(2).padStart(8)}\n
\n
\n
THANK YOU FOR YOUR BUSINESS\n
PAYMENT PROCESSED SUCCESSFULLY\n
\n
\n
NO RETURNS - ALL SALES ARE FINAL.\n
EXCHANGES MAY BE MADE WITHIN 7 DAYS\n
OF PURCHASE.\n
APPROVED RETURNS WILL RECEIVE A\n
REFUND EXCLUDING CHARGES INCURRED\n
FOR WIRELESS SERVICE, ACCESSORIES,\n
AND ADD-ONS.\n
RETURNS MAY BE SUBJECT TO UP TO 20%\n
RESTOCKING FEE.\n
`;
receiptPreview.innerHTML = receiptHTML;
downloadBtn.disabled = false;
}
// Generate PDF receipt
function generateReceipt() {
updateReceipt();
downloadBtn.disabled = false;
}
// Download PDF
function downloadPDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF({
orientation: 'portrait',
unit: 'mm',
format: [80, 297]
});
// Get receipt content
const receiptContent = receiptPreview.textContent;
// Set font and add text
doc.setFont('courier');
doc.setFontSize(8); // Smaller font for thermal receipt
// Split content into lines and add to PDF
const lines = receiptContent.split('\n');
let y = 10;
const lineHeight = 5;
const marginLeft = 5;
lines.forEach(line => {
// Handle long lines by splitting them
if (doc.getStringUnitWidth(line) * doc.internal.scaleFactor > 70) {
const chunks = [];
let tempLine = line;
while (doc.getStringUnitWidth(tempLine) * doc.internal.scaleFactor > 70) {
let chunk = tempLine.substring(0, 40);
tempLine = tempLine.substring(40);
chunks.push(chunk);
}
chunks.push(tempLine);
chunks.forEach(chunk => {
doc.text(chunk, marginLeft, y);
y += lineHeight;
});
} else {
doc.text(line, marginLeft, y);
y += lineHeight;
}
});
// Save the PDF
doc.save('boost_receipt.pdf');
}
// Reset form
function resetForm() {
productList.innerHTML = '';
products = [];
rtrCheckbox.checked = false;
rtrContainer.classList.add('hidden');
rtrAmount = 0;
rtrAmountInput.value = '';
taxRateInput.value = '8.25';
taxRate = 8.25;
storeNameInput.value = 'BOOST MOBILE';
storeAddressInput.value = '22424 IMPERIAL VALLEY DR';
storeCityInput.value = 'HOUSTON, TX 77073';
logoUpload.value = '';
logoPreview.classList.add('hidden');
receiptPreview.innerHTML = '';
downloadBtn.disabled = true;
}
// Initialize with one product
addProduct();
});