Tixflow
Find concerts, conferences, parties and more. Pay with M-Pesa or card and get your ticket instantly.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗A full sales + inventory + customer CRM that never loses data on redeploy. Data lives in Supabase (free tier), courier gets notified on Telegram automatically, and the app itself is three static files you drop on Netlify or Vercel.
Files
index.html the app
app.js logic
styles.css styling (OPTML brand: Onest, ink, goal colours)
assets/ Onest font, wordmark, goal badges, product photos
supabase-schema.sql run once in Supabase
README.md this guide
optml-crm, pick a strong database password, region Sydney.supabase-schema.sql → Run.
You should see "Success. No rows returned." This creates all tables, security rules, and loads your 51 products with catalogue prices.https://abcdefgh.supabase.co)eyJ…)Keep those two handy for step 3.
/newbot → follow the prompts (name it e.g. OPTML Orders). Copy the token it gives you.If your courier prefers WhatsApp instead: every sale has a Copy courier text button that gives you the exact message to paste into WhatsApp.
optml-crm-v2 folder onto the page.https://something.netlify.app. Rename it under Site settings if you want.Both are free. Updating later = re-upload the same folder. Your data is in Supabase, so redeploying never touches it.
That's it. Add the site to your iPhone home screen (Share → Add to Home Screen) and it runs like a native app.
New Sale → Complete
│
├─ Paid + I'll post it → status "Paid" → add tracking → "Dispatched" (courier never involved)
│
├─ Paid + Courier → status "Paid" → Telegram sent to courier automatically → status "Sent to Courier"
│ │
│ courier posts it, tells you tracking #
│ │
│ Sales tab → open sale → Dispatch message → enter tracking → Copy
│ │
│ status "Dispatched" · customer message in clipboard → paste to WhatsApp
│
├─ Awaiting payment → status "New" → change to "Paid" when money lands → Resend to courier
│
└─ Walk-in → no courier message, straight to Delivered when you choose
Statuses: New → Paid → Sent to Courier → Dispatched → Delivered (or Cancelled)
Built phone-first. Five tabs along the bottom — Home · Sales · Sell · Stock · People — plus ⋯ for reports, backup and settings. On a laptop the tabs become a sidebar.
Home — today / 7-day revenue with trend, open orders, a 14-day revenue chart, a Needs attention feed (orders awaiting payment, orders not yet sent to the courier, orders waiting on tracking, launch products below minimum, overdue incoming stock — each with a one-tap action), and recent sales.
Sell (the + button) — three steps:
Sales — To dispatch / Dispatched / Delivered / All, grouped by day, search anything. Sale detail shows a status timeline, one-tap actions (mark paid, send/resend to courier, add tracking & dispatch, mark delivered, copy courier text, SMS/call), items, totals and notes. The dispatch drawer takes a tracking number (typed, or read from a label photo on phones that support it), shows the customer message, copies it and marks the sale Dispatched.
Stock — products are grouped by OPTML goal (Weight, Energy, Restore, Growth, Edge, Vitality, Sleep, Immunity, Glow, Essentials) with the goal badge and product photo. Three views: Inventory (grouped by category, 🚀 toggle, stock level with bar, − / + quick count, tap to edit; alert banner when launch products need reordering), Incoming (purchase orders with multiple lines, supplier, ref, ETA +14 days, delivery details; Arrived adds the stock), Movements (every stock change).
People — customers auto-created from sales. Spend, orders, last order, due flag (30+ days), VIP (5+ orders). Detail shows contact buttons, what they buy most, quick message templates (tap to copy), full order history and New sale pre-filled.
Insights (tap the 14-day chart on Home, or ⋯ → Insights) — pick 7 / 30 / 90 days or all time: revenue and net profit with change vs the previous period, the full profit breakdown (product cost in USD converted at your rate → gross profit → courier share → net), average order, vials per order, paid-to-dispatch time, a revenue/net trend chart, top products with gross margin, sales by goal, payment mix, best weekdays, repeat-customer rate and top customers, and stock cover (days left at the last-30-day sales pace, including incoming stock).
Profit on every sale — each sale's detail page shows product cost, gross profit, the courier's share and net profit. Supplier costs are snapshotted on the sale at the time, so later price changes don't rewrite history. Set the USD→AUD rate and courier share under ⋯ → Settings → Profit (defaults 1.55 and 25%; the courier share applies to shipped orders only).
WhatsApp — two modes, set under ⋯ → Settings → Customers — WhatsApp:
whatsapp_business_messaging, and an approved message template for dispatch (customers you haven't chatted with in 24 h can only receive templates). Create the template with body Hi {{1}}! Your order has been dispatched… Track here: https://auspost.com.au/mypost/track/#/details/{{2}}, then enter the Phone number ID, token, template name and language in Settings and hit Send test to my number. If an API send fails the app falls back to opening WhatsApp.Courier payments (⋯ → Courier payments) — the courier's share accrues on every courier-shipped order the moment it's marked Dispatched. The tracker shows what's owed now, earned this month, paid to date, the unpaid orders with each one's share, and a payment history. Record payment defaults to the full balance (or enter what you actually paid — it settles the oldest orders first and carries any remainder as credit). Statement prints a settlement page; if the courier's WhatsApp number is set you can send them the list in one tap. Home flags it when something has been owed for more than a week. Every sale's profit card shows whether its courier share is owed or paid.
Fulfilment — three options at checkout: Courier (Telegram goes to the courier when paid, courier earns their share), I'll post it (nothing goes to the courier, no share, you still get tracking + the dispatch message), Walk-in. Change it later from the sale page if plans change.
Quotes — in New Sale, build the cart, then tap Quote (top right). It writes the quote from your template (items, bac water, shipping, total, payment options), lets you edit it, and either opens it in WhatsApp to the customer's number or copies it. The template is editable under Settings → Quote message.
Reports (⋯ menu and section buttons) — Sales (today / 7 days / month / 30 / 90 / all / custom range, with payment split, by product, by day and every order), Launch & reorder (10-pack supplier order sheet), Inventory, Incoming, Movements, Customers, and a Full business report. Each opens as a clean page with Print / PDF.
Backup — ⋯ → Backup to file / Restore from file. Restore accepts backups from the old stocktake app too.
Multi-device — with Supabase, phone and laptop stay in sync within a couple of seconds.
{sale_no} {name} {phone} {address} {items} {bac} {notes} {total}{first_name} {name} {tracking} {sale_no}"Could not load data" — the Supabase URL or key is wrong, or you haven't run the SQL. Check step 1.3 and 1.5.
Sign in fails — make sure you ticked Auto Confirm User when creating the user. Or go to Authentication → Users and confirm it there.
Telegram test fails — the bot must be in the group and someone must have sent a message after adding it. Tap Find chat ID again.
Want to run it without Supabase? — tap Skip — this device only on the connection screen. Everything works, data lives in that browser only (back it up before redeploying).
Product cost is kept in USD per vial. When stock comes in at a known price — ± Adjust → In with a cost per vial (USD or AUD, converted at the Settings → Profit rate), or an incoming order with a cost on the line — the product's cost becomes the weighted average of what was on the shelf and what arrived: (on-hand × old cost + qty × new cost) ÷ (on-hand + qty). Stock in without a cost leaves the cost unchanged. The movement records the price paid and the before/after average.
Setting a sale to Cancelled puts its items (and bac water) back into stock, logged in Movements as "#N cancelled — returned to stock". Changing it back from Cancelled deducts them again. Deleting a sale that wasn't already cancelled also returns its stock. Each sale remembers whether its stock has been returned, so this can't double up.
Settings → Stock lock sets a 4–8 digit passcode. With it on, the +/− buttons, ± Adjust, the stock field in the product editor and marking incoming orders as arrived all ask for the passcode first (one correct entry unlocks that phone for 10 minutes). Sales deduct stock as normal without it. The passcode is stored hashed in settings, shared across devices.
Off-catalogue things (pens, syringes, a one-off bundle) are added in Sell → Custom items with a name, price each and quantity — as many lines as needed. They sit in the cart alongside catalogue products, can be adjusted or removed there, and never touch stock.
Customers order from the price list / wholesale catalogue sites, which send a formatted message to the business WhatsApp. In Sell → Paste order, paste that message (or tap the button with it on the clipboard): items, pack sizes, quantities, the prices they were quoted, discount, shipping, name, phone, email and address all fill in. Nothing is saved yet — change quantities, remove or add items, fix the address, then Next → Complete as usual. The order ref (OPT-xxxxx) goes into the sale notes; anything not in the catalogue is added as a custom item (name, price, qty) so the total still matches.