MotorShop

Secure POS & Management System

Default administrator: admin / admin123

MOTORSHOP
POS & INVENTORY SYSTEM

Dashboard

Welcome back! Here's what's happening with your business today.
β‚±0.00
Today
β‚±0.00
Today
0
All recorded
0
View Details

Sales Summary (This Week)

Top Selling Products View All

PRODUCTQTY SOLDSALES

Recent Transactions View All

INVOICE #CUSTOMERTOTAL

Product Alerts View All

πŸ’‘ Tip: You can import products with initial stocks using the Import Products menu.

Point of Sale

πŸ›’ Current Order

Items0
Subtotalβ‚±0.00
Discountβ‚±0.00
TOTALβ‚±0.00

Inventory

β‚±0
0
0
0
SKUProductCategoryUnitCostRetail PriceWholesale PriceMin. Wholesale QtyStockReorderStatusValue

Sales Report

β‚±0
0
0
β‚±0

Sales Trend

Sale IDDateCustomerPaymentItemsTotalDiscountProfit

Profit Report

β‚±0
β‚±0
β‚±0
β‚±0
Revenueβ‚±0
Cost of Goods Soldβ‚±0
Gross Profitβ‚±0
Operating Expensesβ‚±0
Net Profitβ‚±0
Net Margin0%

Product Master

Import products with initial stock
CSV columns: SKU, Product Name, Category, Cost Price, Selling Price, Wholesale Price, Wholesale Min Qty, Initial Stock, Reorder Level, Icon
Add products here. They immediately appear in the POS catalog. No need to enter them again in POS.
SKUProductCategoryCostPriceStockReorderStatusAction

Expenses

DateCategoryDescriptionAmount

Receipts / Sales History

Sale IDDateCustomerTotalPayment

User & Cashier Management

Create usernames, passwords and access roles
Cashier role: POS only. Administrator role: POS, Inventory, Reports, Products, Expenses, Receipts, Settings and Users.
UsernameNameRoleStatus

Settings

Company, logo, receipt and printer settings

☁️ Cloud Synchronization

Optional cloud backup and synchronization. The POS remains fully usable offline.

Supabase connection, Test, Sync Now and Download Cloud

🏒 Company Profile

No logo

The company name, tagline and logo will be used in the header, login screen and printed receipts.

πŸ–¨οΈ Printing Settings

Bluetooth: Not connected. Bluetooth printing requires a supported browser/device and a printer that exposes a compatible BLE GATT service.

For maximum reliability, POS printers should support standard ESC/POS over USB/LAN/Bluetooth. Web Bluetooth support varies by Android/Chrome devices and printer models; iPhone/iPad browsers generally cannot provide unrestricted Bluetooth printer access.

πŸ“± Mobile / Tablet

The POS interface is responsive and can be used on phones and tablets. Product cards, search, cart and checkout automatically adapt to smaller screens.

Recommended mobile setup: Android + Chrome + Bluetooth ESC/POS printer. For iPhone/iPad, use the browser print/share workflow or a vendor-specific printing app.

πŸ§ͺ System Tools

${logoHtml}

${company}

${subtitle}
${address?`
${address}
`:""}${phone?`
${phone}
`:""}

${title}

Printed: ${new Date().toLocaleString()}
${printable.innerHTML} `); w.document.close();w.focus();setTimeout(()=>w.print(),250); } function renderExpenses(){ const el=document.getElementById("expenseBody"); if(!el)return; if(!Array.isArray(expenses))expenses=[]; el.innerHTML=expenses.slice().reverse().map((x,ri)=>{ const i=expenses.length-1-ri; return `${new Date(x.date).toLocaleString()}${escapeHtml(x.category||"Other")}${escapeHtml(x.description||"")}${money(Number(x.amount)||0)}`; }).join("")||'No expenses recorded.'; } function addExpense(){ if(window.currentUser && window.currentUser.role!=="admin"){alert("Administrator access required.");return;} if(!Array.isArray(expenses))expenses=[]; const category=(prompt("Expense category:","Operating Expense")||"").trim(); if(!category)return; const description=(prompt("Expense description:","")||"").trim(); const amount=Number(prompt("Amount (β‚±):","0")); if(!Number.isFinite(amount)||amount<=0){alert("Please enter a valid expense amount.");return;} expenses.push({id:"EXP-"+Date.now(),date:new Date().toISOString(),category,description,amount}); localStorage.setItem("ms_expenses",JSON.stringify(expenses)); renderExpenses(); if(typeof renderProfit==="function")renderProfit(); alert("Expense added successfully."); } function addUser(){ if(window.currentUser && window.currentUser.role!=="admin"){alert("Administrator access required.");return;} let list=Array.isArray(users)?users:[]; const username=(prompt("Cashier username:","")||"").trim(); if(!username)return; if(list.some(x=>x&&String(x.username||"").toLowerCase()===username.toLowerCase())){alert("Username already exists.");return;} const password=prompt("Cashier password:",""); if(!password)return; const name=(prompt("Cashier full name:",username)||username).trim(); list.push({username,password,name:name||username,role:"cashier",active:true}); users=list; localStorage.setItem("ms_users",JSON.stringify(users)); if(typeof renderUsers==="function")renderUsers(); alert("Cashier registered successfully. POS-only access has been assigned."); } function renderReceipts(){ const el=document.getElementById("receiptBody"); if(!el)return; const list=Array.isArray(sales)?sales:[]; el.innerHTML=list.slice().reverse().map(x=>`${escapeHtml(x.id||"")}${new Date(x.date).toLocaleString()}${escapeHtml(x.customer||"Walk-in Customer")}${money(x.total||0)}${escapeHtml(x.payment||"")}`).join("")||'No sales recorded.'; } function printReceiptById(id){ const tx=(Array.isArray(sales)?sales:[]).find(x=>String(x.id)===String(id)); if(!tx){alert("Receipt not found.");return;} if(typeof printReceipt==="function"){printReceipt(tx,0,0);return;} alert("Receipt printing function is unavailable."); } /* Ensure requested pages are rendered when opened. */ const previousShowPageForFunctions=window.showPage; if(typeof previousShowPageForFunctions==="function"){ window.showPage=function(id,btn){ previousShowPageForFunctions(id,btn); if(id==="expenses")renderExpenses(); if(id==="receipts")renderReceipts(); if(id==="users"&&typeof renderUsers==="function")renderUsers(); if(id==="sales"&&typeof renderSales==="function")renderSales(); if(id==="profit"&&typeof renderProfit==="function")renderProfit(); }; } /* ===== CASHIER REGISTRATION β€” DEDICATED UI ===== */ function getLoggedInUserForAdminActions(){ try{ const saved=JSON.parse(sessionStorage.getItem("ms_currentUser")||"null"); if(saved&&saved.username)return saved; }catch(e){} if(window.currentUser&&window.currentUser.username)return window.currentUser; if(typeof currentUser!=="undefined"&¤tUser&¤tUser.username)return currentUser; return null; } function registerCashier(){ const sessionUser=getLoggedInUserForAdminActions(); if(!sessionUser || sessionUser.role!=="admin"){ alert("Administrator access required. Please log in as admin."); return; } const old=document.getElementById("cashierRegisterModal"); if(old)old.remove(); const modal=document.createElement("div"); modal.id="cashierRegisterModal"; modal.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:99999;display:flex;align-items:center;justify-content:center;padding:20px"; modal.innerHTML=`

Register Cashier

Cashier accounts can access POS only.
`; document.body.appendChild(modal); const close=()=>modal.remove(); document.getElementById("closeCashierModal").onclick=close; document.getElementById("cancelCashierRegister").onclick=close; const save=()=>{ const name=document.getElementById("newCashierName").value.trim(); const username=document.getElementById("newCashierUsername").value.trim(); const password=document.getElementById("newCashierPassword").value; const confirm=document.getElementById("newCashierPassword2").value; const err=document.getElementById("cashierRegisterError"); const fail=t=>{err.textContent=t;err.style.display="block";}; if(!name)return fail("Please enter the cashier's full name."); if(!username)return fail("Please enter a username."); if(username.toLowerCase()==="admin")return fail("The username 'admin' is reserved."); if(password.length<4)return fail("Password must be at least 4 characters."); if(password!==confirm)return fail("Passwords do not match."); let list=[];try{const x=JSON.parse(localStorage.getItem("ms_users")||"[]");list=Array.isArray(x)?x:[]}catch(e){} if(list.some(u=>u&&String(u.username||"").toLowerCase()===username.toLowerCase()))return fail("That username already exists."); list.push({username,password,name,role:"cashier",active:true}); try{localStorage.setItem("ms_users",JSON.stringify(list));}catch(e){return fail("Could not save the cashier account in this browser.");} try{users=list;}catch(e){} if(typeof renderUsers==="function")renderUsers(); close(); alert("Cashier registered successfully!\n\nName: "+name+"\nUsername: "+username+"\nRole: Cashier (POS only)"); }; document.getElementById("saveCashierRegister").onclick=save; document.getElementById("newCashierPassword2").onkeydown=e=>{if(e.key==="Enter")save();}; } function addUser(){registerCashier();}