Skip to content

Medusa POS 0.2.0: split payments and customers

Latest

Choose a tag to compare

@wcpos-mini wcpos-mini released this 07 Oct 14:37
· 35 commits to main since this release
54ba86a

Medusa POS 0.2.0: split payments and customers

The second tester release of Medusa POS, the browser point of sale for a Medusa store. Take part of a sale by card and the rest in cash, and attach a customer to a sale so the Medusa order is theirs. It needs the Medusa plugin 0.2.3, attached to this release, and Medusa 2.21.0.

Before you update your tills

This update changes how each till stores its sales, and there is no going back.

  • Before you update, make sure every till has sent all its sales: nothing waiting to sync.
  • After you update, don't install an older version again. An older version can't read the new storage. It shows none of the till's sales and doesn't send the ones still waiting.
  • If a till ever shows no sales after going back to an older version, don't ring those sales again. Update the till and they come back. Ringing them again would count them twice.

Update the plugin first (see Update the plugin), then the tills. The hosted app at https://app.medusapos.com updates itself: reload each till's tab once its sales have synced.

What's new at the till

  • Split payments. Pay part of a sale by card and the rest in cash. Change comes from the cash part only. The Medusa order records both payments, and the receipt lists both.
  • Customers. Search for a customer at the till, or create a new one, and attach them to the sale. The Medusa order is linked to that customer. A sale with no customer is a guest sale, as before. If the cashier types an email that matches a stored customer, the order links to that customer whatever the email's case.
  • Park and resume sales. Put a sale aside, serve the next customer, and come back to it. A resumed sale is re-priced at today's catalogue prices.
  • Change a line's price at the till.
  • Fees, delivery charges and items not in your catalogue. Add a bag fee, a delivery charge or a one-off item to a sale.
    • Your store records the fee and the one-off item as order items without a product, and the delivery as a shipping method. All are taxed at your region's rate.
    • Medusa can't keep one charge tax-free and has no tax classes, so the till doesn't offer those for your store.
  • Catalogue grid or table, and categories. Switch the catalogue between tiles and a table, and narrow it by category. Each till remembers its view. Phones show the categories without the toggle.
  • Take over a register. If a register was left open on a till that's lost, broken or replaced, another till can take it over: it shows which till holds the register, and Take over moves the register to this till. The old till's register commands are then refused, and it shows the register closed. A till that lost its local data and opens the same register again picks up where it left off.
  • Name each till. Give the till a name in Settings. It's shown to another till that finds the register open.
  • Choose who may use the POS (optional). With Medusa's role-based access control (RBAC) off, which is Medusa's default, every admin can sign in to the POS, as before. With RBAC on, only people with a "POS cashier" or "POS manager" role can. Anyone else sees "This account can't use the POS. Ask the store owner for POS access." Setting it up is step 7 of the quick start's Configure your store.
  • Clearer storage problems. A Safari private window, a second tab holding the till, and a till that needs a reload to finish updating each get their own message saying what to do.

What's new for your store

  • Registers are recorded by the server. When a till opens, counts and closes a register, your Medusa store records it and works out what the drawer should hold from the sales it received. The till's own figures (expected, counted and variance per payment method) are on its "Last closure" screen, under Register. The app doesn't show the store's figure yet; it's available from the plugin's register endpoint, GET /tally/v1/registers/{id}.
  • Sales that need an admin are held, not lost. If a sale can't be finished automatically (for example, its order was changed by hand in Medusa), it waits for an admin. The admin then completes it or rejects it with one command.
  • Rejected sales don't count in the day's figures. A sale an admin rejects no longer counts in the register's expected cash. A one-off step fixes sales rejected before this update. It first shows you exactly which closed days would change, and it can be undone.
  • Stock stays right when a sale fails. If a sale fails partway, the stock it took is put back exactly once.
  • The till's stock location must belong to your sales channel. A sale can no longer take stock from a location that isn't linked to your sales channel. The sale stays on the till's Orders screen as needing attention, with the store's message saying it's a store setup problem. Link the location to the channel in Medusa, then tap Retry on that sale and it goes through.
  • Resent sales answer the same way. A sale the store already recorded always answers its recorded result when a till sends it again. That includes after a server update, and when a till resends a sale.
  • Oversized batches get a clear answer. A batch of more than 50 sales, or one over the size limit, is refused whole, with the limit in the answer. Splitting it and resending in smaller pieces comes in a later version of the till.
  • More than one Medusa server needs shared locking. If your store runs more than one Medusa instance, configure a shared locking provider (Redis or Postgres). The plugin warns once at startup while Medusa's in-memory locking is active.
  • Experimental catalogue sync is included but off. It's the server side of a faster catalogue sync. It stays off unless you turn it on.

Update the plugin

App 0.2.0 needs plugin 0.2.3 and its database migrations. RBAC is optional: plugin 0.2.3 is needed either way, because it is the only released plugin with the register take-over this app uses, and it adds the POS roles for stores that turn RBAC on.

In your Medusa store's directory:

npm install https://github.com/medusapos/app/releases/download/v0.2.0/medusapos-medusa-plugin-0.2.3.tgz
npx medusa db:migrate

Then restart the backend. The plugin needs Medusa 2.21.0. If you already registered @medusapos/medusa-plugin in medusa-config.ts for 0.1.0, leave that entry as it is. New installs follow the tester quick start.

The plugin isn't on npm yet. Publishing it there needs a maintainer's one-time password and follows separately (#235); after that you'll install it by name, npm install @medusapos/medusa-plugin.

Known limits

  • No refunds or returns at the till yet.
  • No coupons or Medusa promotions at the till. Discounts are typed at the till.
  • No card charging: card payments are taken on a separate terminal and recorded as external payments.
  • No tips, emailed receipts or sales reports yet. Receipts are on screen, with browser printing.
  • No order note, and a customer can't be edited at the till.
  • One shipping profile per sale. A sale mixing products from several shipping profiles is refused.

For developers

  • App 0.2.0 pins all @tallyui/* packages at exactly 3.8.0 (RxDB 17.5.0; browser storage is SQLite-wasm, one live tab per store). It sends order.create v5 and register contract 2.
  • Plugin 0.2.3 (see packages/medusa-plugin/CHANGELOG.md for 0.2.0, 0.2.2 and 0.2.3):
    • /tally/v1/info advertises order.create [1, 2, 3, 4, 5], register: [1, 2], lineTax: { none: false, classes: false } and taxRounding: { granularity: 'per_order', mode: 'half_away_from_zero' }.
    • Breaking (meaning), 0.2.0: insufficient_stock.quantity is the units of this sale that stock did not cover, not the level's whole shortfall (#231).
    • Registers: the register commands, server-derived expected/salesCount, and GET /tally/v1/registers/{id} (#98, #99, #100); a stored register rejection replays unchanged (#108); session.rejected lists a session's unretried rejected sales (#230).
    • Register v2 (ADR 0022): take-over, same-device resume through session aliases, and the register_session_unknown warning for a sale naming a session the store doesn't know (#236). A command on a superseded session opened at contract 2 is refused register_session_superseded (#245). Needs the migration.
    • POS access (ADR 0023, part 1): the tally_pos:use policy on every /tally/v1 route when RBAC is on, and the tally-pos-roles exec script for the "POS cashier" and "POS manager" roles (#253).
    • order.create v4 and v5: net line discounts (#183); fees and custom lines become variant-less items, shipping becomes a shipping method, and taxStatus: 'none' or any taxClass is invalid_payload with data.reason tax_status_unsupported or tax_class_unknown (#224, ADR 0021).
    • Customers: an email-only sale links to the stored customer whatever the email's case, one customer per email under a lock (#164); the typed email is kept as tally_customer_email (#190); a customerId the store can't use is a customer_ignored warning (#169).
    • Warnings: figures_mismatch when a v3 sale's subtotal or tax differs from Medusa's (#170).
    • Validation: strict fields per protocol version, unknown envelope fields refused, repeated clientLineIds refused, and every client-time field bounded to 2020-01-01 through server time plus 24 h (#137, #158, #161, #165, #166).
    • needs_admin and the tally-ledger-resolve apply/reject script (#115). Rejected orders are marked tally_rejected and excluded from register figures (#121), with a one-off backfill that dry-runs by default, reports each session and can be undone (#127).
    • Stock safety: the take-back and fulfilment compensation are failure-safe (#116, #117). A sale's stock location must exist and belong to its sales channel (#130).
    • Replay first: a recorded command id answers its recorded result before every refusing check (#120); a new command id for a clientOrderId that already has an order follows the original command's ledger state (#118).
    • 413 answers: batch_too_large / body_too_large (#134).
    • Locking: a startup warning while the in-memory locking provider is active (#154).
    • Experimental sync: the tally_sync change journal, /changes routes and the rescan script, behind experimentalSync, off by default (#110, #112, #114).
    • Security: the majorToMinor ReDoS fix (#111).
    • The tarball ships .medusa/server only; CI checks the pack (#146).
  • Legacy sales carry-over (#160): after the verified copy writes its marker, it never runs again; the legacy database is kept, with deletion left to a later release. Sales written later by a tab on a pre-SQLite build are not carried over.