What's New in Weaf Point of Sale

What’s New in Weaf Point of Sale

Every update we have shipped, newest first.

App version 5.7.0Latest release v5.7.0Released 10 September 2026120 releasesWeafPOS_Setup_v5.7.0.exe
Get Weaf Point of Sale Download a free trial

Trying Weaf Point of Sale? Download the installer and activate a trial licence at https://weafpos.weafcompany.com/download.

Already using it? Download the latest installer from your Weafmall account under Purchase history → Digital purchases and run it over your existing installation. Your database and settings are kept — nothing is overwritten.

On a multi-till setup, update the main computer first, then each till.

Latest release

Release v5.7.0 — The hotel matches the web, a room can be let by the hour, the desk knows its regulars, and the login page says what the program is forLATEST

Released 10 September 2026

  • Who This Is For Every hotel, lodge and guest house. The Hotel section now keeps everything the web hotel keeps, under the same names, so a booking taken on the web reads the same at the desk.
  • Any house that lets a room for the day or by the hour, or receives guests who give no details.
  • Everybody who opens the program: the login page has been redesigned.
  • The Hotel Matches The Web The hotel screens are now the web's own: Front Desk, Room Status Board, Reservations, New Reservation, Check-in, Check-out, Guests, Stay History, Housekeeping, Rooms, Room Types, Rate Plans, Quotations, Banquets and Venues, Agreements, Room Service and Settings.
  • The sidebar, the top menu and the buttons on the front desk all open the same screen. Two versions of a screen with different fields is how a desk ends up with bookings one screen can see and the other cannot.
  • Forms slide in over the right-hand side of the list instead of covering it, so the desk can still read what it has already entered.
  • A booking carries the whole party, not only the person who made it, with first and last names kept apart and where they travelled from.
  • Extras such as breakfast or an airport transfer are priced per unit, booked with the room, and reach the invoice at check-out.
  • Quotations are priced like a booking and print as plain text, so one can be e-mailed, sent on WhatsApp or read out over the telephone.
  • Venues and events: a hall let for a wedding, with its own charges.
  • Agreements are generated in the house's own wording. A house can keep several named templates for the same kind of agreement, and every agreement records which wording it was made from.
  • An identity document is kept front and back. With no scanner, the desk photographs it with any camera the computer has - a laptop camera, a USB webcam, or a phone running a webcam app.
  • Room service: a basket at the till can be moved onto a resident guest's room account. Nothing is fiscalised then; it is declared with the rest of the stay at check-out.
  • A Room Let By The Night, The Day, The 24 Hours Or The Hour A room type now carries a rate for each way it is sold, and says which one it is normally sold by. A blank rate means the room is not let that way, so "not offered" can never be mistaken for "free".
  • A minimum can be set, such as two hours, and a stay keeps the minimum it began with, so changing it next month does not change what somebody already in the room is charged.
  • The front desk shows every rate a room is sold at, not only the usual one.
  • A guest's account shows room charges that are owed but not yet posted - a night the audit missed, time run over a short booking - and counts them in the balance. Check-out posts them as of the same moment, so what the cashier takes payment against is exactly what goes on the invoice.
  • Existing room types keep being sold by the night. Nothing changes until a house adds another rate.
  • A Desk That Knows Its Regulars "Returning guest?" on the booking form and on check-in opens a searchable list of guests, with how many times each has stayed, when they last stayed and what they have spent.
  • With nothing typed, the list starts with whoever stayed most recently, not whoever was registered most recently.
  • "Same as last time" fills in the rooms, rate plan and extras from the guest's last booking, at the rate they were actually charged rather than the list price. A regular's second booking is their first with new dates.
  • A Quotation Does Not Ask For A Passport The identity section is hidden on a quotation. Nobody hands over a document for a price.
  • Fixed at the same time: quoting a price to a returning guest would have overwritten the document on file with "Passport" and a blank number. A quotation now leaves the guest's documents alone.
  • A Room Let Without Taking Details Preferences > Hotel has three new switches: require an identity document, require a telephone number, and allow letting a room without taking details.
  • The first two are on and the third is off, which is what every house was already doing, so an upgrade changes nothing until a house decides otherwise.
  • With the third switched on, "Let a room now" appears on the Front Desk and Check-in screens: pick the room, how it is sold (only the ways that room is actually priced), how long, and what was paid.
  • The room shows as occupied, the money reaches the takings, and the stay is charged and invoiced like any other. A program that cannot record this trade does not stop it happening - it only keeps the room off the rack and the money off the books.
  • No person is invented. The house has one standing record for these lets, kept off the guest lists, and the rack, the account and the bill show a name if one was given, or the room and the time, such as "Room 12 · 3:40 PM".
  • Such a stay cannot have food or drink charged to the room.
  • The Login Page It now opens full screen, as a normal window: the taskbar stays reachable and it minimises and alt-tabs like anything else.
  • The old page showed invented figures such as "842 Sales Today" and "99.9% Uptime". They are gone.
  • It now says what the program is for: Retail and supermarket, Wholesale and trade, Restaurant and bar, Hotel and guest house, and One set of books. Each has a short write-up and a picture.
  • The pictures are screenshots of this program's own screens, so a buyer is shown the screen they will actually work on. Every claim in the write-ups is something the program does.
  • The trades move on every eight seconds, and stop as soon as somebody picks one.
  • The page says which database the till is connected to, so signing into the wrong copy is noticed straight away. Only the name is shown.
  • On a screen narrower than about 1080 pixels, the write-ups are left out and the sign-in form sits alone in the middle.
  • The Demo Hotel The demo data now includes a working hotel: rooms priced every way a house lets them, guests in house with bills running, bookings due in, rooms waiting to be cleaned, and a hall let for a wedding.
  • It is built through the desk's own check-in and billing, not written straight into the database, so the demo behaves exactly as a real house does.
  • Checked Before Release A brand-new installation, a copy of a real shop from before the hotel changes (49 tables, 11,109 sales), and a copy of the oldest shop database on hand (45 tables, 4,483 sales) were each upgraded. Each came up in one pass and started again with nothing left to do.
  • Every new column is added only if it is not already there, so it does not matter which part of start-up gets there first.
Previous releases (119)

Release v5.6.1 — Every till gets the standard units, a hotel gets its floor, and a cost price is optional on a service

Released 9 September 2026

  • Who This Is For Any shop whose Units of Measure list came up empty or held one entry called Each. That was not a settings mistake; it was a fault, and it could not be corrected from inside the program.
  • Every hotel. A hotel that had not also ticked Restaurant had no tables, no kitchen screen and no way to raise the bill it was allowed to charge to a room.
  • A Till That Came Up With No Units Can Now Be Put Right The standard list of 505 units URA publishes is now put into any database that has none, once, on the next start.
  • The old code seeded that list only at the moment a database was created, and only if measures.json happened to be sitting beside the program. Built from a folder without it, a shop got nothing - and no amount of restarting would ever fix it, because seeding only ever happens once. Thirteen items in one test shop were all priced in the same single placeholder unit.
  • A unit is on every invoice URA or MRA is sent and is what a stock count is counted in. Each for a litre of paraffin is not untidy, it is wrong on a tax document.
  • If the list still cannot be read, nothing is recorded as done, so the next start from a complete install puts it right instead of marking the shop as handled and leaving it empty for ever.
  • And The Shop Chooses What It Keeps Preferences > Unit of Measure > "Import or remove units" shows three lists before anything happens: the URA standard list, whatever MRA has published to this terminal, and what this shop already has. Nothing is ticked on the way in.
  • Search then tick all is how a shop takes the six units it uses out of a list of five hundred.
  • Units can be removed, including all of them, and a shop that trims its list keeps it trimmed. Nothing puts them back on the next start.
  • A unit something still points at is refused rather than deleted, and the screen says what is holding it. Deleting the unit an old invoice was priced in would rewrite what that invoice said.
  • Malawi units are fetched live from MRA rather than shipped in the installer. A unit code on a Malawi receipt has to be one MRA actually publishes, and a list shipped from memory is wrong the first time MRA changes it.
  • Two Things Found While Testing That Would Have Cost A Shop Its Data Working out which units are in use was read from the database's foreign keys. Only three tables in a real WeafPOS database were ever given one; fourteen carry a unit, InventoryItems among them. So the unit every item in the shop was priced in read as used by nobody, and with no constraint the database would not have refused the delete. Every one of those items would have been left naming a unit that no longer existed. It now asks the model, which knows the relationship whether or not the constraint was ever written.
  • The start-up audit that strikes off migrations whose work is missing would have struck this one off every time a shop had a short unit list, and put all five hundred back on the next start. A missing column is always a fault. Missing rows may be a decision.
  • A Hotel Serves Food Tables, tickets, the kitchen screen and split bills now follow whether a house serves food, not whether it called itself a restaurant. A hotel has a restaurant and a bar in it.

Release v5.6 — A restaurant can register its menu with URA and issue fiscal invoices, and an emailed receipt is the one that was printed

Released 9 September 2026

  • Who This Is For The EFRIS work is for any restaurant, bar or hotel in Uganda that has to fiscalise. A plain shop is unaffected: nothing about how a supermarket registers goods or declares stock has changed.
  • The emailed receipt is for every shop and every restaurant.
  • A Restaurant Can Now Be Fiscalised, End To End Driven against URA's test system from an empty database: EFRIS wired up, a dish with two sizes registered, a table settled, and the sale fiscalised. It comes back with a fiscal document number, a verification code and the QR a customer scans to check it.
  • A dish with sizes registers each SIZE with URA separately, under its own goods code, as its own product - because a Small and a Large are two different things to sell at two different prices, and a tax invoice has to say which one was bought.
  • The heading above the sizes is never registered. URA holding a product nobody can put on an invoice helps no one.
  • Free extras - tomato sauce, a side nobody is charged for - come off the store and stay off the tax invoice. URA is told what was charged, and nothing was. The sauce is still counted, so it does not read as shrinkage nobody can explain.
  • Three Ways To Run A Group, And The House Chooses What URA is TOLD and what the shop COUNTS were one setting. They are two questions, and treating them as one made a bar impossible to run properly.
  • Kitchen: a service to URA, counted nowhere. Right for food, because nobody has ever counted a stock of chicken curry - what the kitchen counts is chicken, which is a different item.
  • Bar: a service to URA, counted here. This is the new one. A bar's whole discipline is knowing how many bottles it had this morning and how many it has tonight, but declaring that stock to URA means an invoice can be refused because a figure is out. Now the bottles are counted here, URA holds the beer as a service and expects no stock figure, and deliveries of it stay off the EFRIS declarations.
  • Shop: ordinary goods, stock counted here and declared to URA. The supermarket arrangement, where the two sides are meant to agree and a difference is worth chasing.
  • Chosen per group on Restaurant > Menus > "Set the menu up for URA". Going back to goods is now a way out rather than a one-way door.
  • Three Fixes On The Way There URA's "this product already exists - use operationType 102 to edit" was being filed as a refusal. It is an instruction. The item was marked failed and could never register again. A restaurant meets this on the first ordinary day it has two tills: goods codes count up from an empty database, so MENU-001 gets offered to URA twice. It now re-sends that item as an update, exactly as URA asks.
  • The lookup that runs after URA says "an invoice with this reference may already exist" asked for a page of 200 records. URA caps it and refuses the whole query rather than trimming the page, so that lookup had never once succeeded - and it is the call that decides whether somebody at a till is shown "already fiscalised, here is the number" or a refusal they can do nothing with.
  • The menu setup screen filed every group under URA's Restaurants category, including a hotel's. Rooms are not a restaurant, and a wrong category is a wrong declaration rather than an untidy one. It now asks which.

Release v5.5 — A bill can say who it is for, a dish carries its tax code, and the till makes a noise when something lands

Released 9 September 2026

  • Who This Is For The customer on a bill is for anything that runs the restaurant. The beep is for every shop and every restaurant. The goods code and unit are for anybody who sends invoices to URA or MRA.
  • A Bill Can Say Who It Is For The floor had no customer at all. Every meal became a walk-in sale, whoever ate it. That is fine for the table that pays cash and leaves, and wrong for the three cases a restaurant actually has: the company that eats here every week and settles monthly, the guest who wants a fiscal invoice with their TIN on it, and anybody on a loyalty scheme.
  • The bill now carries a customer button, beside the covers and the waiter. It reads "Walk-in" until somebody says otherwise, and shows the name the whole time the meal is being rung up - so a bill about to be settled against the wrong company is visible before the money is taken, not after.
  • "Walk-in" is the biggest button on the screen that asks, and needs no reading, because it is what nine tables in ten are.
  • A customer can be created from there and then. Sending a waiter to the Customer List to make one and back to the floor to find the bill again is how a guest ends up on a walk-in receipt with no TIN on it, which is the thing they asked for.
  • Search finds them by name, phone or TIN, and each line shows what is owed or held in credit, so the right J. Okello can be told from the other two.
  • The name reaches the SALE, not just the ticket - on a whole bill, on one share of a split bill, from the order screen and from the older ticket view. A bill nobody named is still a walk-in.
  • Nothing already taken changes. A bill with no customer on it means exactly what it always meant.
  • A Dish Carries Its Tax Code And Its Unit The Add and Edit Menu Item page now shows the goods code and the unit of measure for each size, so a dish can be given what URA or MRA needs while somebody is still thinking about the dish - rather than finding out at a till that it cannot go on an invoice.
  • Both belong to the catalogue record the size sells, which is the record the tax authority is actually told about and the one a stock count works from. Editing them here edits that record; there is no second copy to go stale.
  • A record the tax authority already has is shown and locked, and says why. The goods code is what they know it by, and changing it would leave every invoice already filed pointing at something that no longer exists.
  • The unit is the shop's own list, off the shop's own table, with a + that opens the shop's own Unit of Measure screen. One place a unit is defined, so a stock count in Litres is the same Litres that goes on the invoice.
  • A Menu Can Be Made From The Dish A + beside "Choose Menu", the same one the item category already had. A house adding its first dish - or the first dish of a bar list that does not exist yet - was sent away to build the menu somewhere else and came back to a form it had to fill in again.
  • The Till Makes A Noise When Something Lands Adding an item now beeps, on the restaurant screen and on the shop till. It is the same sound the web POS makes, the same file, so somebody who works a lunch on the web and a dinner on this till learns it once.

Release v5.4 — The menu is built the way the web builds it: menus, items, categories and the questions a dish comes with

Released 9 September 2026

  • Who This Is For Anything that runs the restaurant. Nothing here changes a plain shop, and nothing already set up behaves differently after the upgrade.
  • The Menu Is One Place Now, With Five Pages Restaurant > Menus opens a window with the same five pages the web menu has, in the same order, with the same columns and the same look: Menus, Menu Items, Item Categories, Modifier Groups, Item Modifiers.
  • A house running the web restaurant and this till no longer has to learn the same job twice. Anybody who can build a menu on the web can build one here without being taught.
  • Menus shows a card for each menu with a count on it, the one being worked on filled in, and that menu's dishes listed underneath - the same shape as the web.
  • Menu Items lists every dish with its price, its category, its menu and whether it is on tonight. A dish sold in sizes shows the span, "UGX 6,000 - 11,000", instead of the small price on its own, which used to read as though the large cost the same.
  • A Menu And A Category Are Two Different Things They were one thing before, and that forced houses to build the same dish twice. "Starters" is the house's own list and can sit on lunch and on dinner; the menu is which of those a guest is handed.
  • Every dish now says which menu it is on and which category it sits under, as two separate answers, and there is a Menu box on the add and edit page to say so.
  • Nothing moved: every dish that existed keeps the menu its category had, worked out during the upgrade.
  • Build A Menu From What Is Already There A menu is assembled from dishes that already exist rather than typed again. Put an existing dish on a second menu without duplicating it, and it stays one dish in every report and comes off stock once.
  • A Plate Can Cost A Different Amount On A Different Channel Dine In, Takeaway, Delivery and Room Service can each carry their own price, per dish and per size. Delivery carries a commission, takeaway carries a box, room service carries a tray and a lift.
  • Every channel starts padlocked to the menu price; open the padlock only where the price actually differs. A house that prices everything one way never has to think about it.
  • The card, the line on the bill, the total and the receipt all read the same figure, because the price is decided in one place and carried from there.
  • The Questions A Dish Comes With Modifier Groups and Item Modifiers are now two proper pages, as on the web. A modifier group is a question - Cooking, Extras, Choice of side - with priced answers under it; an item modifier is that question attached to a dish.
  • Whether the question MUST be answered, and whether more than one answer may be given, are now decided per dish. How a steak is cooked has to be answered; the same question asked of a stew is a nicety. Before, one rule sat on the question, so a house had to build "Cooking" twice and keep both copies in step by hand.

Release v5.3 — A restaurant that you can get out of: every screen finds its way back, and a dish shows its picture

Released 8 September 2026

  • Who This Is For Anything that runs the restaurant or the hotel. The picture change and the two fixes at the foot apply to every shop.
  • Every Screen Has A Way Back To The Restaurant Fifteen screens - Sales History, Customer List, Item List, Vendors, Receiving History, Stock Adjustments, the Report Center, Expenses, Register History, Time Clock - put up a sidebar of their own and hid the main one. On a restaurant that meant a waiter who opened Sales History to check a bill was stranded: no floor, no tables, no kitchen, nothing but a Back button.
  • Each of those screens now carries "Go to" at the foot of its sidebar, offering exactly what the main menu would offer this person on this machine - Restaurant POS, Floor / Tables, the Kitchen Screen, Front Desk, Bookings, Housekeeping. A plain shop sees nothing there, and no empty gap either.
  • The four screens where a sale or a stock entry is half typed - the till, a customer order, Receive Items, a stock adjustment - are deliberately left alone. A "go to the floor" button beside a half-rung sale is an invitation to lose it.
  • Selling On A Restaurant Machine Opens The Restaurant "Make a Sale" took a restaurant terminal to the SHOP till, which is the wrong till for a restaurant: it has no tables, no courses and no kitchen ticket, and a plate rung up there is rung up twice. It now opens whichever floor the machine actually works on.
  • Turning The Restaurant Or The Hotel On Takes Effect At Once Ticking Restaurant or Hotel under Preferences > Business type used to do nothing at all until the application was closed and opened again - the menus, the sidebar and the permissions all stayed as they were at sign-in. The screen you are on updates as you press Save.
  • The Restaurant Till No Longer Covers The Taskbar The order screen filled the whole monitor, taskbar included, and has no title bar of its own. On a touch monitor with no keyboard that leaves nothing on screen to leave by, and it reads as a machine that has locked up.
  • It now stops at the edge of the working area, on whichever monitor it is on, so the taskbar stays reachable. Escape steps back to the floor, and from the floor it closes.
  • A Dish Shows The Picture Somebody Put On It An order card drew a cardboard box over items that already had a picture attached to them under Inventory. The card sells that product, so it now shows that product's picture. A photograph put on the dish itself in the Menu Designer still wins where there is one.
  • Only the cards actually on screen fetch a picture, at the size the card draws it, so a shop with a picture on every item is no slower to open.
  • Two Fixes Two quick taps on the same card put "1 x Coke" on the bill twice instead of "2 x Coke". They now make one line of two, however fast the taps.
  • Inventory > Stock Adjustments threw an error and never opened. It opens.

Release v5.2 — Malawi: purchases, returns, adjustments and stock takes all reach MRA - and a nightly backup nobody has to remember

Released 8 September 2026

  • Who This Is For The MRA sections below are Malawi only, and only once MRA EIS is switched on in File > Integrations. Two changes are for everybody: the nightly backup, and being able to choose how many decimals tax is shown to.
  • The Nightly Backup Is No Longer A Choice The backup used to be a tick box that started off. That meant the shops most likely to need it - the ones nobody has ever walked through Preferences - were the ones running without one. A backup nobody took is only discovered on the day the disk dies, and by then the day's trading is gone.
  • It is now on for every shop, new and existing, and cannot be turned off. What you still choose is WHEN, which is a real decision: a backup at noon in a busy shop is worth avoiding.
  • Existing shops that had it switched off have had it switched on, at 22:00 unless a time was already set.
  • How Many Decimals Tax Is Shown To Preferences > General now has "Tax decimal places", from 0 to 4. It sets how tax is printed on the invoice details page and on the receipt.
  • Malawi needs two, because MRA states tax to the tambala. A shop in Uganda pricing in whole shillings will want 0, and should set it once - the setting starts at 2.
  • Ura Stops Appearing Where It Does Not Belong A till running MRA no longer shows any URA or EFRIS screen. The EFRIS menu, the EFRIS entry under Integrated Applications, and the URA commodity category on the Business Type page are all hidden - they were never usable on a Malawi till and only ever raised a question.
  • Declaring A Purchase To Mra "Save & Send to MRA" on the receiving screen files the purchase as it is saved, in one step.
  • MRA was refusing purchases for two fields it requires and the till was leaving empty - a delivery note number and notes. Both are now filled from what the receipt already knows, so a purchase goes through without anything extra to type.
  • Quantities are sent as MRA expects them, to four decimals, so half a carton is declared as half a carton rather than rounded to a whole one.
  • Receiving History carries an MRA column, a filter for what has been sent and what MRA refused, a Refresh button, and "What was sent to MRA" showing the exact request and the exact reply for any purchase.
  • A stock-in of the Manufacture kind still requires a supplier, because MRA will not take a purchase without one.
  • A Sales Return Is Filed As A Cancellation MRA refuses a credit note whose lines are the same as the invoice's - a credit note is for an adjustment, not for undoing a sale. A return of the whole receipt is therefore filed as a void request against the original receipt, which is what MRA actually provides for it.
  • MRA does not approve a void immediately. The till records that it is pending and shows MRA's own words, rather than claiming the return is done.

Release v5.1 — Malawi: a till that signs its own receipts

Released 8 September 2026

  • Who This Is For Everything below is Malawi only, and only once MRA EIS is switched on in File > Integrations. A shop in Uganda on EFRIS, or a shop using neither, sees no change at all: none of these screens or buttons appear, and nothing about how it sells is different.
  • Activating The Till With Mra MRA Settings (Malawi) under File takes your TIN, whether you are on Sandbox or Production, and the activation code your dealer gives you, and activates this computer as an MRA terminal.
  • A terminal belongs to the computer it was activated on, the way the cash drawer does. MRA is told the machine's hardware address at activation and ties the terminal to it, so a terminal activated on the front till is that till's - it cannot be moved to another machine by copying a setting.
  • An activation code works exactly once, and MRA hands over the terminal's key at that moment and never again. So the whole exchange is written down before anything else is attempted, and the code is refused a second time rather than being quietly spent on a failed attempt.
  • The till never fetches terminals MRA has already activated elsewhere. Importing one would bind this computer to another machine's identity.
  • The Receipt Is Signed Here, Not Asked For Every sale is signed on the till the moment it is finalised. That signature is what makes it a fiscal receipt - it is valid and can be handed to the customer immediately, whether or not the internet is working. The receipt prints as TAX RECEIPT from that moment.
  • Sending it to MRA is a separate step that can happen later. This is deliberate and it is the whole design: if a receipt were sent first and numbered by MRA, then a reply that never arrives leaves the till unable to tell "MRA did not get it" from "MRA got it and the answer was lost". Sending again would fiscalise the same sale twice; not sending would leave a real sale undeclared. Signing first removes the choice - the same receipt, with the same number and the same signature, can be sent as many times as it takes.
  • It also means the shop keeps trading when the line goes down, and that the code used during an outage is the same code used every other day rather than an emergency path nobody has ever tested.
  • Sending Receipts To Mra "Save & Send to MRA" on the sale screen signs and sends in one go.
  • The sale details window shows what MRA knows: the MRA invoice number, MRA's own receipt number, the validation code, and whether MRA has taken it yet - with "Sign Offline", "Send to MRA", and "What was sent to MRA" showing the exact request and the exact reply.
  • "Check this receipt on MRA's portal" opens the same page a customer reaches by scanning the QR code on the paper.
  • Sales History carries an MRA column and the MRA invoice number, so a day's receipts can be read at a glance.
  • MRA > Signed but Not Sent lists everything waiting, oldest first, with its age and MRA's own words for why it has not been taken, and pushes them all when the line is back - each with the signature it was signed with.
  • When Mra Refuses A Receipt, The Number Goes Back A refused receipt used to keep its number forever, which left a permanent hole in the day's sequence - the first receipt of a day could come out as C rather than B, and a hole is a question somebody has to answer at an audit with the answer buried in a failure log.

Release v5.0 — A picture found for you, an expense you can correct, and URA asked before it is told

Released 7 September 2026

  • A Picture For A Product, Found For You Adding a product meant finding a picture of it yourself, so most items went in without one - and the touch tiles at the till exist so staff can pick by sight rather than by reading a name off a list.
  • There is now a "Find online" button beside "Choose picture" on the product screen, when creating a product and when editing one. It searches the web for the product you have named and shows what it found, and you pick the one that is actually on your shelf.
  • Give it the full name. "Blue Band Margarine 500g" finds the tub; "BB" does not. If the product has a barcode typed in, that is used too, because a barcode names one exact product where a name may not.
  • It finds real photographs and never draws one. An invented picture of a product looks convincing and is wrong - a label that does not exist, on a packet that was never made - and staff picking by sight would be picking the wrong item.
  • You are shown several and choose. A search for "Sugar 1kg" can return the right brand, a competitor's, and a photograph of a sugarcane field, and only the person adding the product knows which is right. A wrong picture is worse than no picture.
  • The picture is saved with the item when you press Save, so a product you decide not to keep never leaves one behind.
  • The till never holds the key to the search service and never downloads from the open web itself. Our own server does the searching and the fetching, checks what comes back really is a picture, and sends the till only what it has checked.
  • Renewing A Licence Without Ringing Anybody Renewing meant reaching somebody at WEAF, which is why tills went on trading expired over a weekend. Help > Renew Licence now asks what is owed, opens the payment in the shop's own browser, and waits for confirmation.
  • Paying happens outside the till, in the browser the shop already uses, because that is where cards, mobile money and the bank's own confirmation screens actually work - several of them refuse to run inside an embedded window. It also means the shopkeeper can pay on their phone instead.
  • The till never grants itself time and never reports the payment. The expiry moves only when WEAF has confirmed the money with the payment provider, so nothing on the till can be edited into a free licence.
  • Renewing early costs nothing: the time bought is added to what the licence already has rather than replacing it. And the expiry warning comes down the moment it is done, rather than at the next hourly check, so a shop that has just paid is not left wondering whether it worked.
  • Activating A Till You Bought From A Dealer The code box asked for a "Dealer Code (AGT-XXXX-XXXX)", which is only one of the three strings a dealer might have given you. A dealer's own licence key was answered with "not recognised", which is how somebody who has paid ends up believing they were sold nothing. It now takes whichever code or key you were handed and works out which it is.
  • When the machine cannot reach us, the window used to say "you can still press Activate" - a button that cannot work without a connection, on a machine that by definition has none. It now names what actually works offline: ask your dealer for a licence file (.lic), or for a 10-character offline code. This machine checks either one by itself.
  • Your dealer can now produce both of those from their own console using the Fingerprint shown on the left of this window, so a till that has never been online can still be licensed.

Release v4.8 — A count you have not taken is now blank, not a number

Released 2 September 2026

  • No Count Until Somebody Takes One A stocktake line opened at the system quantity. That default was doing real work - it is what stopped a count where somebody reached forty of six thousand items from driving the other five thousand nine hundred and sixty to zero - but it bought that safety by making every untouched line look like a count that happened to agree.
  • The counted column is now EMPTY until a figure is entered. The sheet shows a dash, and the footer says how many of the lines have actually been done.
  • Nothing acts on a line with no count. It is not posted, and URA is never even asked about it.
  • Only What You Counted Is Declared To Ura URA is now asked ONLY about the lines you counted. Every other line is skipped before a single request is made, rather than being looked up to learn a difference nobody is in a position to act on.
  • This matters because URA holds a THIRD figure, moved only by what has been declared to it. For this shop's own stock an untouched line and a line counted and found correct really are the same - both mean no change. For URA they are not: a line confirmed at forty may still need forty declared, because URA thinks there are four. Declaring on behalf of lines nobody looked at would put the catalogue's own opinion onto a tax record on the strength of a default.
  • The confirmation says how many lines were left for later.
  • Zero Is A Real Count Again Now that "not got to it yet" is the ABSENCE of a count, zero goes back to meaning what it says: the shelf was looked at and there was nothing on it.
  • A counted zero is posted, and it is declared to URA. That is the only way an item which has genuinely run out can ever be brought down to nothing at URA. Previously zero had to double as "not looked at", which is why it was excluded.
  • Clearing the box puts a line back to having no count at all, which is how a figure typed by mistake is undone.
  • Posting Only Moves What Was Counted Posting considers a line only where a count was entered. A line with no count is not an opinion that the figure is right - it is no opinion at all, and adjusting stock on the strength of one would move what nobody looked at.
  • The variance report prints a dash for an uncounted line rather than reporting a finding nobody made.
  • Upgrading An Existing Count Sheets already in progress are converted: the figures somebody actually took are kept, and the lines nobody reached are emptied. Tested by putting a database back the way the previous version left it, with a full sheet on it, and running the upgrade over real rows.

Release v4.7 — Registering an item now asks how many you have

Released 2 September 2026

  • Counting A Full Sheet By Scanning NEW. A sheet loaded with every item can now be SCANNED as well. Loading the lines up front only decided which lines exist; the counting is still done walking the shelves with a gun.
  • The FIRST scan of a line starts its count at one, whatever the sheet had it at. A full sheet opens every line at the system quantity, and adding to that would count ten on the shelf as eleven.
  • ONLY WHAT YOU COUNTED GOES TO URA. A line nobody has reached still sits at the system figure - that default is what stops posting from zeroing everything unreached - so declaring the lot would put the catalogue's own opinion on a tax record. Counted lines are now tracked separately from the number, and only those are declared.
  • A COUNT OF ZERO IS NOT SENT. Zero is read as "not got to it yet" rather than "there are none", because the shelf may still be walked this afternoon and wrongly declaring nought is the one mistake that empties an item at URA. The confirmation says how many were left for later.
  • The sheet shows a dash rather than a figure until a line is counted, and the footer counts how many of the sheet have been done.
  • Items can be edited or created from the sheet on any scope now, and the counts are written down before that window opens.
  • Opening Stock, From The Item Itself NEW. Register a new item with EFRIS and, if it has a quantity, you are asked straight away whether to declare that quantity to URA as its opening stock.
  • Registering a product tells URA the GOODS EXIST. It says nothing about how many there are. Until now an item could be registered while holding a hundred on the shelf and nothing at all at URA, and the two only met later - usually at the till, as an invoice refused for stock that is plainly there.
  • NEW. Items that already exist get a "Declare Opening Stock" button on their own record, for everything registered before this.
  • Opening stock is declared with the stock-in type and supplier URA expects for it, not borrowed from a stock count.
  • It Refuses When It Would Not Be True URA's stock for the item is read FIRST. Opening stock is a claim that the goods have never moved there, and URA only accepts it while that holds.
  • If URA already holds some, you are told how much and sent to EFRIS Stock Reconcile instead. It is not quietly turned into an ordinary increase - that is a different declaration on a record nobody can correct afterwards.
  • An item URA has never heard of is refused too, with the reason: it has to be registered before anything can be declared against it.
  • An item with no quantity is left alone. Opening stock is the count you are starting with, so there has to be one.

Release v4.6 — A stock take that remembers what it has already told URA

Released 2 September 2026

  • What You Just Scanned Is At The Top On a hand-built stock take the newest line is now first, instead of the sheet being sorted by name. You scan, and the thing you scanned is where you are already looking.
  • Scanning something already on the sheet moves it back to the top as its count goes up, because that is the line being worked on and it is no use halfway down.
  • Reopening a count keeps the order it was built in, so the last thing scanned yesterday is still at the top today.
  • A count that opens with the whole shop on it is left in name order. That is a sheet to work down rather than build up, and the two want opposite things.
  • A Stock Take Now Records What It Has Sent To Ura SERIOUS, and it would have shown up on the second press. Nothing recorded that a count had been declared to EFRIS, so sending it again - or reopening it tomorrow and pressing Send - declared the whole count a SECOND TIME.
  • URA has no way to know it is the same count. Its copy of your stock simply moves twice, and a declaration cannot be withdrawn: the only correction is another declaration going the other way. A shop that counted 40 and sent it twice has told URA it holds 80.
  • Every line now carries whether URA accepted it, what it was sent as, what URA said, and when. The count carries the reference, the time, who sent it, and how many were accepted and refused.
  • Only an ACCEPTED line is marked as sent. A refusal deliberately leaves the line open, so a second attempt offers exactly what did not get through instead of everything again - and a call that never got an answer counts as a refusal, because "we do not know" and "it went" must never be recorded as the same thing.
  • The screen says what has gone: the reference and when, or how many are still to go.
  • If the declaration goes through but recording it fails, you are told in as many words not to send it again until somebody has looked.
  • Register Opening Stock NEW. A posted stock take can be declared to URA as OPENING STOCK. It is the same call as an ordinary increase - URA's own interface differs only in the stock-in type and the supplier named on it, and the supplier is declared as "Opening Stock" rather than borrowing the wording used for a count.
  • Opening stock is a claim that these goods have never moved at URA, and URA only accepts it while that is true. Anything URA already holds stock for is LEFT OUT and listed, not quietly turned into an ordinary increase - somebody pressing this is saying "this is where we started", and a different event on a record that cannot be corrected is not a small thing.
  • Add A Missing Item Without Losing The Count NEW. Scan or type something the catalogue has never had and you are offered the chance to create it there and then; it goes straight onto the sheet.
  • Counting is exactly where a missing item turns up. Having to abandon a half-finished count, go and add it, and start again is why it did not get added.

Release v4.5 — One scan, one item

Released 2 September 2026

  • Every Scan On A Stock Take Counted Twice FIXED, and it mattered: on the new scan-built stocktake, scanning an item put TWO of it on the sheet. A shelf of six came out as twelve, and a count that is double is worse than no count at all - posting it would have doubled the stock, and sending it to URA would have declared the doubled figure.
  • A wedge scanner is a keyboard. It types the code one character at a time and then presses Enter, about a millisecond after the last digit.
  • Adding a line writes it to the database, so it is not instant. The box was being emptied AFTER that write finished, which left the whole code sitting there while it was in flight. Enter arrived, found the code still in the box, and added the item all over again.
  • The box is now emptied the instant the item is taken and before anything is written, so the scanner's Enter finds nothing to act on. A second guard stops two adds from overlapping at all, which would otherwise have both read "not on the sheet yet" and written a row each for one product.
  • The same shape of fault was checked for on the reconcile screen's stock take tab and on receiving, and neither has it: those add an item without touching the database first, so the box is already empty by the time Enter lands.

Release v4.4 — Count what you can reach, and tell URA about that

Released 2 September 2026

  • A Stock Take You Build As You Walk NEW. A stocktake no longer has to open with every product in the shop already on the sheet. The new scope, "Only what I scan or search", opens EMPTY and each item arrives by being scanned or looked up.
  • On a shop of ten thousand products the old sheet was unusable for a cycle count. The lines that matter are the ones somebody actually walked to, and everything else was noise to scroll past.
  • The system quantity is read AT THE MOMENT THE ITEM IS ADDED, not when the sheet was opened. On a count that runs all afternoon those are different numbers, and the one taken at the shelf is the honest one.
  • Every line is written to the database as it is added, and typed counts are saved as they are typed. A count is taken walking around a building; a sheet that only exists on screen is one power cut away from being counted all over again.
  • Scanning behaves the way it does everywhere else: the first scan of an item lands at one, scanning it again makes it two. Typing is stricter than scanning - one match is taken, several ask you to narrow it, because guessing at a stock take puts a count on the wrong product and the shelf is already behind you.
  • Edit An Item Without Losing The Count NEW. Every row on the sheet has an "Edit item" button that opens the item's own record over the count. Close it and the sheet is still there, counts and all.
  • Counting is exactly when the state of the catalogue becomes obvious - a wrong unit, a missing barcode, a name nobody can find. If fixing one meant abandoning a half-finished count, it did not get fixed.
  • What was entered is saved BEFORE the item window opens rather than after it closes. The item screen can be cancelled or take a long route through other dialogs, and none of that should be able to cost somebody an afternoon.
  • The counted figure is never touched by this. It is the only number on the screen that came from a person looking at a shelf. If the item's own stock moved while its record was open, the sheet says so and updates what it is measuring against - a variance against a stale figure would put the stock in the wrong place when posted.
  • Send A Stock Take To Ura NEW. A posted stocktake has a "Send to EFRIS" button, and posting now offers it directly.
  • It reads URA's stock FOR EACH ITEM, one at a time, as it sends. The variance on the screen is your count against what this shop believed it held, and posting has already settled that one. URA holds a THIRD figure, moved only by what has been declared to it, and it is the gap against that which has to travel.
  • Asking per item also means the figure is read at the moment it is acted on rather than minutes earlier, which is what makes the variance worth trusting. Nothing is sent for an item URA already agrees with.
  • Asking URA by product code is a SEARCH at their end, not an exact lookup - it can answer with codes that merely contain yours. Only an exact match is taken. Reading the first record back would have posted one product's variance against another.
  • The button only appears once the count is posted. URA is told what this shop holds, and until the count is posted this shop still holds the old figure.

Release v4.3 — Settling your stock with URA in one press

Released 2 September 2026

  • Reconcile With Ura Automatically NEW. One button on the EFRIS stock reconcile screen reads what URA holds, sets every counted figure to what this shop holds, works out which of URA's three calls each item has to travel by, and sends them.
  • What used to be done by hand: fetch, press "count = what we hold", read down a list of thousands, then reconcile. The clerical part of that is now the button.
  • AUTOMATIC MEANS THE CHOOSING IS AUTOMATIC, NOT THE SENDING. What goes to URA is a declaration that cannot be withdrawn - a wrong figure is only ever corrected by another declaration - so the whole plan is still shown and still asked for, once, before anything leaves.
  • IT CANNOT MOVE YOUR STOCK. Every figure it declares is the one this shop already holds, so there is no local movement to make. Only URA's copy moves. A figure nobody has counted is not a count, and an unattended run has no business changing what the shop believes it has.
  • What It Refuses To Send URA DOES NOT ACCEPT A NEGATIVE STOCK FIGURE. Items where this shop's own figure is below zero are left out and listed, not quietly sent as zero. A negative figure here means stock left without ever being received - declaring zero would write that shortage off against a tax record and make it disappear. That needs a person, not a button.
  • Because every remaining item is settled to a figure of zero or more, no adjustment can take URA's stock below zero. That is not a check that could be forgotten; there is simply no line that could do it.
  • Goods URA has never heard of are left for the Register button, since nothing can be declared against them until URA knows them.
  • A run that is mostly OPENING STOCK is called out before it goes. That is what a shop looks like when it has never declared anything - or when the reading from URA came back empty - not one correcting a drift, and unwarned it would declare the whole catalogue in one press.
  • Export The Comparison NEW. The reconcile screen saves to CSV: both figures, the gap, and what would be sent to URA. What is exported is exactly what is on screen, same filter and same order, so the file can be reconciled against the page it came from.
  • The environment and TIN are on the first line, because a sandbox figure and a production figure look identical in a spreadsheet and mean entirely different things.
  • Receiving History: Pick A Period NEW. A Period box on receiving history: today, last 7 days, this month, last month, last 30 or 90 days, this year, or all time. The two date pickers are still there for any range at all - the box just drives them.
  • "Last month" means the whole of the previous calendar month, which is what closing a period means, and is offered separately from the last thirty days.
  • "All time" clears the dates rather than reaching back to some invented year, so nothing older can be hidden by a made-up floor.
  • Moving a date by hand switches the box to "Custom range" instead of going on naming a preset the dates no longer match.

Release v4.2 — Receiving stock booked the wrong product on every scan

Released 2 September 2026

  • The Wrong Item Was Booked When Receiving Stock SERIOUS. On Receive Items, scanning a barcode could book a COMPLETELY DIFFERENT PRODUCT - and on a large catalogue it did so on most scans. Stock went onto the wrong item, and the item actually delivered stayed at its old figure.
  • The screen resolved the scan against whatever the dropdown happened to be showing, and when nothing in that list matched exactly it fell back to taking the FIRST ROW. The dropdown was loaded with the whole catalogue in the order items were created, and the search that would have narrowed it sat behind a quarter-second delay.
  • A scanner sends its Enter about a millisecond after the last digit, so Enter always arrived while that list was still the whole shop. Item number one was booked instead. On a real shop of 10,529 products that is whatever happens to be the oldest record in the file - the same wrong product, over and over, for any barcode that did not match something already on screen.
  • A comment above that delay claimed it was what kept scanning correct. It was not: it delayed the SEARCH while leaving the path that actually books the item unguarded.
  • The scan is now resolved against the catalogue itself - an index of every product code, all four barcode fields and any barcode custom field - so what is on screen cannot change what is booked. The blind first-row fallback is gone: a code that matches nothing offers to create the item, which is what the person scanning wants to be asked.
  • What Was Scanned Is Now Written Down A shop reporting "it brought up the wrong product" could never say what the scanner actually sent, because the code is gone from the box by the time anybody looks. Every scan on Receive Items now records the raw text, the code it was compared on, the item it mapped to, and WHICH FIELD answered - product code, which barcode, or a custom field.
  • That last part is the useful one. A thirteen-digit barcode answered by a four-digit product code is a different fault from one answered by another item's barcode, and the difference is not visible on screen.
  • Receiving No Longer Freezes On A Large Shop The item box was handed all ten thousand products, and every character of a scan filtered the whole catalogue and rebuilt the list from scratch. That is the stutter, the dropped characters and the freeze when the arrow is opened.
  • The list is now capped and drawn only once the typing stops, and the names and codes it searches are prepared once when the screen loads instead of on every keystroke. The exact-code match that books the item stays immediate - it never waits for anything.
  • This is the same treatment the sell screen was given. Receiving, selling and stock adjustment now resolve a scan the same way, through one piece of shared code, so the three cannot drift apart again.
  • Something Worth Checking In Your Own Catalogue Where the same barcode sits on two products, or one product's barcode is another's product code, a scan is genuinely ambiguous and no amount of code can decide it. One real shop had 10 of the first and 36 of the second, mostly duplicate products saved with the barcode typed into the product code field.
  • The scan is resolved to the older record, which is normally the real one. The duplicates are still worth tidying.
  • Switching Section Could Leave A Blank Screen FIXED. Moving between the shop counter, the restaurant and the front desk clears the screen before working out what to put back, and the two ways that could fail - no connection string, or the database not answering for the moment it takes to ask - both left an empty window with nothing on it to say so. It looked exactly like the program having hung.
  • Landing on a home screen now happens on every way out of that code, not only the one that works.

Release v4.1 — A menu of its own, and a split bill that cannot be paid for twice

Released 2 September 2026

  • A Menu Is Not The Same List As What The Store Counts The restaurant order screen used to offer the ENTIRE catalogue: every active item in the business. On a shop that also serves food, a waiter at table four could tap toilet roll onto a bill. On one demo database that was 63 items, including household goods, personal care and groceries.
  • There was a "Show on menu" setting, but it sat on the DEPARTMENT and the screen only used it to build the tabs across the top. The item list itself ignored it, so the All tab and the search box both handed back the whole warehouse.
  • NEW: Restaurant > Menu Designer. A menu, its headings, and the items under each. The order screen now shows only what somebody decided a guest could order.
  • The two lists were never the same shape. The store counts chicken, rice and oil; the menu offers Chicken Curry. Most of what a kitchen buys is never ordered by name, and most of what is ordered by name cannot be counted. So the menu is its own layer sitting on top of the catalogue rather than a filtered view of it.
  • Sizes: One Bottle, Two Things To Sell A menu item now has PORTIONS - Small and Large, Glass and Bottle, Regular and Sharing. The price belongs to the portion, because the moment a house sells a large one there is no single price to put on the item.
  • Both sizes point at ONE catalogue record. Before this, a large beer had to be a second item with its own stock line, its own barcode and its own separate EFRIS registration for the same bottle.
  • "How many store units" is the number that makes it work: a large that is physically two bottles is 2, and a large plate that uses half again of the recipe is 1.5. Selling one large beer now takes TWO bottles off the store, and a large curry takes half again of the chicken and the rice.
  • Ordering a small and a large on the same bill keeps them as two lines. They are one catalogue item at two prices, and merging them would have charged somebody the small price for a large.
  • What Ura Is Told About A Large One A stocked good sold as a large is declared to URA in the store's own units - two bottles at half the price, which is the same money and the same stock.
  • This matters more than it looks. URA decrements its own copy of your stock by whatever the invoice declares. Selling "1 x Large" where two bottles left the shelf drifts the two figures apart by one bottle every single time, and ends as a refused invoice for stock that is plainly on the shelf. That is return code 1600, and no amount of retrying fixes it.
  • A dish is left exactly as it is - URA holds no stock of a service to disagree about, and "1.5 x Chicken Curry" on a receipt is nonsense. The recipe already took the extra ingredients.
  • Only split where it divides exactly. A size that does not divide the price cleanly would put a repeating decimal on a fiscal invoice, and being one bottle out with URA is a far smaller problem than charging somebody 9,999.99 for a 10,000 round.
  • More Of What A Restaurant Actually Needs OFF TONIGHT. An item that has run out is greyed on the order screen rather than hidden, so a waiter can tell a guest it is off instead of hunting for something that is not there. It is a separate switch from taking the item out of the catalogue - running out tonight must not deactivate a record that stock, reports and EFRIS all depend on.
  • PRICE AT THE TILL. For the function plate, the bottle off the reserve list, whatever the chef sends out. Without it these get rung up as something else and every report after that is wrong.

Release v3.9.6 — Sales filed under the wrong day, and how to put them back

Released 1 September 2026

  • A Till Left Open Overnight Was Filing Sales Under Yesterday FIXED. The Sale Date box on the Make a Sale screen was set when the screen opened and never looked at again. A till sits on that screen all shift, often for days, so once midnight passed the box quietly stopped meaning today while still showing exactly what it had always shown. Every sale rung after that was recorded under YESTERDAY's date, with the correct time, and nothing on screen could have told anybody.
  • This is why a day's figures could disagree with the money. One shop's drawer held 547,100 for the day while its Daily Sales Summary showed 290,600. Neither screen was lying: the drawer counts what was rung into it, the summary counts what the date says, and the dates were wrong.
  • Everything keyed on the sale date inherited it - the daily summary, the Z-Out, VAT, the URA declaration, staff performance, profit.
  • The same fault was in FOUR screens, all of which date money or stock: Make a Sale, Receive Items, Stock Adjustment and Customer Orders. All four are fixed, through one shared piece of code so they cannot drift apart again.
  • What The Date Box Does Now A date the program put there is a default, so when the calendar moves past it, it moves too. A date a person put there is theirs and is left alone.
  • Backdating lasts ONE document. A date set deliberately for a single invoice used to follow every sale after it for the rest of the shift; now the next one starts back on today.
  • Receiving, adjustments and customer orders also used to record midnight with no time of day at all. They now carry the clock, so a day's documents keep the order they were entered in.
  • PUTTING RIGHT WHAT WAS ALREADY RECORDED - Reports > Check Sale Dates
  • NEW. Finds sales that were filed under a day they cannot have happened on, and puts them back on the right one.
  • How it can be certain: every sale carries the register drawer it was rung into, and that link is written from the database at the moment of the sale, never from the date box. A sale cannot have happened before its own drawer was opened - the cash had nowhere to go. Any sale dated earlier than that is wrong, and this is not a guess.
  • The clock was always right; only the calendar was stale. So the time of day is kept exactly and only the day moves. The amount, the items, the invoice number and anything already sent to URA are untouched.
  • It uses nothing but your own data. No internet, and nothing is compared against URA - a sale that was never submitted has to read correctly in your own reports too, and those figures are what a shop is run on.
  • It refuses rather than guesses. A sale with no drawer, or one it cannot place with certainty, is reported and left exactly as it is.
  • Nothing changes until you press the button. It lists every sale first, with what it is filed under, what it should be, and why. Every change is written to the audit log with the day it moved from.

Release v3.9.5 — A till whose register is never closed can be updated again

Released 1 September 2026

  • Install Now Is No Longer Refused Because The Drawer Is Open FIXED. Pressing Install now while the cash drawer was open was refused outright, with "close the register when the shift ends and the update will be offered again". On a till whose register is never actually closed, that refusal was permanent - the update could never be installed at all.
  • This was not rare. Every till in this shop had its register left open: four out of four, open between 51 and 81 days. All four were locked out of updating, including out of any version fixing money handling or URA figures.
  • CHANGED. Somebody who has read the update and pressed Install now is told exactly what it costs - the program closes, so anything half-rung on screen is lost - and decides for themselves. The answer starts on No.
  • The open register itself is untouched. It is still open when the till starts again and the shift can be closed off normally afterwards. Only the Register screen ever closes a session, and only when somebody presses the button.
  • Nothing Has Changed About What The Till Does On Its Own The drawer rule was written so the program never shuts itself down under somebody who is serving, and it still governs that completely. No update installs itself while the drawer is open, whether the shop has asked for automatic updates or the version has been phased out.
  • What changed is only that the rule stopped overruling a person standing at the till. A guard that quietly turns updating off forever for the least careful shops protects nobody.
  • A Till That Cannot Reach Its Database No Longer Reports Itself Safe To Shut Down FIXED. The check for an open drawer went through the same code the selling screens use, which is built to keep a till trading through a blip: when it cannot reach the database it falls back to the drawer it last knew about, and in a program that has only just started there is none - so it answered "nothing open".
  • Read through the update check that meant "safe to shut down". A till having database trouble would have been shut down and handed an installer at the worst possible moment. The guard against exactly this could never fire, because the error had already been swallowed a level below it.
  • The update check now asks the database itself, and anything that is not a clear "no drawer is open" counts as unsafe. Tested against a database that is not there.

Release v3.9.4 — A vendor opens when you double-click it

Released 1 September 2026

  • Editing A Vendor No Longer Needs The Button NEW. Double-clicking a vendor in Vendor Management opens its details for editing, the same form the Edit Details button opens.
  • The button has not moved and does nothing different. This is there because a list of records that opens when you double-click it is what everything else on a computer does, so it is the first thing anybody tries - and until now it did nothing at all, which reads as the screen being broken rather than as a shortcut being missing.
  • Only a double-click that lands on a vendor counts. Double-clicking a column heading to widen it, or the empty space under the last vendor, does nothing - it does not open whichever vendor happened to still be highlighted, which would have put somebody in a stranger's details with a Save button in front of them.

Release v3.9.3 — A shop can let updates install themselves, and Weaf can retire a bad version

Released 1 September 2026

  • A Shop Decides Whether It Is Asked Every Time NEW. Company Preferences now has "Install new versions without asking". Off, which is how it starts, a new version is downloaded quietly and then waits for somebody to say yes. On, it installs itself at the first moment doing so costs nothing.
  • Worth turning on for a business running several tills, where the same question would otherwise be answered on each of them every week. Worth leaving off for a shop that wants to know exactly when its till changed.
  • Neither setting can interrupt a shift. Nothing is ever installed while the cash drawer is open on that till, whichever way this is set - an update that closes the program over a half-rung sale is worse than an update that waits until closing.
  • A Version That Is No Longer Fit To Run Can Be Retired NEW. Weaf can now mark a version as phased out. A till running it, or anything older, is told it must update rather than invited to, and cannot postpone it.
  • This is deliberately not the same thing as releasing a new version, and it is not expected to be used often. Almost every release is worth offering and not worth forcing. It is meant for the case where staying put is worse for the shop than the interruption - a version that files the wrong figure with URA, or gets a customer's change wrong - which nobody should be able to keep putting off for a month.
  • The reason is shown before the update runs, so being made to stop arrives with an explanation attached rather than as a demand from nowhere.
  • Even a required update waits for the cash drawer to be closed. Being out of date is not a reason to shut a program down in the middle of serving somebody.
  • Being Told To Update Cannot Be Faked The instruction travels inside the part of the message that is signed by Weaf, along with everything else. Something a till acts on without asking anybody is exactly what somebody able to answer a web request would most want to be able to send.
  • Turning that instruction on, or quietly turning a genuine one off, destroys the signature and the till refuses the whole message. Both were tested rather than assumed.

Release v3.9.2 — The update installs itself instead of asking somebody to close the till

Released 1 September 2026

  • The Update Now Closes The Till By Itself FIXED. Installing an update stopped with "Setup was unable to automatically close all applications", leaving somebody to close the till by hand - which is the one thing an automatic update exists to avoid. Two separate faults caused it, and both are fixed.
  • FIXED. The installer had no way to recognise a till that was open. It was left guessing from which files happened to be locked, which is unreliable. The program now holds a name while it runs and the installer looks for exactly that name, so it knows a till is open and can close it properly.
  • FIXED. The update started the installer and then closed the program, which is a race: the installer began looking at files while the till was still on its way out, and the files it needed were still held. The installer is now started by a small step that waits for the till to have actually gone before running it, so there is no guessing about how long closing takes.
  • FIXED. The program is started again once the installation finishes. A silent install does not reopen it, so a till was being left dark at the end of an update, which looks exactly like something went wrong.
  • The Download Happens Before Anybody Is Asked CHANGED. A new version is now downloaded quietly in the background as soon as it is found, before anybody is asked anything. Downloading interrupts nobody: it arrives while the shop carries on selling, and it can happen with the drawer wide open. Installing is the part that costs a shop time, and that is the part that waits for a person to agree.
  • This is the difference between "yes" meaning a two-minute wait and "yes" meaning twenty minutes on a slow line - which is how a shop learns to always press Not now.
  • The update window says when the download is already on the machine, and the button reads Install now rather than Download and install.
  • A download that fails is simply tried again next time the program opens. Nobody is told, because nobody was waiting for it.

Release v3.9.1 — The program can update itself

Released 1 September 2026

  • A Till Can Now Update Itself, When Somebody Says So NEW. The program checks once when it opens whether a newer version has been released, and if there is one it shows what changed and offers to install it. The download and the install happen on the machine itself, so nobody has to drive to a shop or talk somebody through copying a file.
  • It always asks. Nothing installs on its own, overnight or otherwise. A till belongs to the shop, and the shop decides when it can afford the two minutes with the program closed - which is very often not now. "Not now" costs nothing and the same version is offered again tomorrow.
  • What changed is shown BEFORE the decision, not after it, because whether it is worth doing now depends entirely on whether it fixes something the shop is currently suffering.
  • NEW. Help > Check for Updates asks on the spot, for when you already know something has been released. Left to itself the program stays quiet unless there is something worth saying - nobody opens a till to be told it is up to date, and a shop whose internet is down must not be shown a failure it can do nothing about every morning. But when a person asks, every answer is spoken plainly, including "there is nothing newer" and whatever went wrong.
  • NEW. Help > About shows the version, the computer name and which part of the business it is set to. The first question asked down a phone line about any problem is which version the shop is on.
  • It Will Not Interrupt A Shift Nothing is offered while the cash drawer is open on that till, and nothing installs without the drawer being closed - installing means shutting the program down, and shutting it down mid-shift means a half-rung sale on the counter and a cashier who cannot finish it.
  • The drawer is read from the database rather than from memory, for the same reason the cash drawer count was fixed: another till closing its own session used to clear this one's, and a till would then believe itself idle in the middle of a busy morning.
  • The drawer is checked twice - when the update is offered, and again at the moment Install is pressed - because somebody may have opened it and started serving in between.
  • The Version Is Shown In Full, And A Failed Check Says So FIXED. The version was shown as "3.9" when the release was 3.9.0, because a patch number of zero was hidden. Those are two different releases and this program has carried tags for both, so somebody reading the version down a phone line could not say which one they were on. All three numbers are now always shown.
  • FIXED. When the program could not reach the update service at all it said "this is the newest version there is". That is a wrong answer rather than a missing one: it stops somebody looking any further for an update that does exist. Not being able to ask and there being nothing to find are now told apart, and each says what actually happened.
  • An Update That Is Not Really From Weaf Is Refused Every offer is signed by Weaf and checked on the till before a single value in it is read, let alone downloaded or run. A program that installs whatever an internet request hands back is a door left open for anybody able to answer that request - a hijacked connection, a bad router in a hotel. Here somebody controlling the connection completely can still not produce an update this program will run.
  • The installer itself must match the fingerprint inside that signed offer. A download that stopped half way, or a file swapped on the server, is thrown away rather than run.
  • Refused, altered and unsigned updates are all turned away without the program falling over, and a till that cannot reach the internet at all carries on selling exactly as before.

Release v3.9.0 — Each computer knows which part of the business it is

Released 1 September 2026

  • Every Machine Shows Only The Part Of The Business It Is Standing In NEW. A venue that runs more than one thing - a hotel with a restaurant, a restaurant with a shop counter - now asks each computer which part it is, once, and remembers. The front desk shows hotel menus, the waiter's till shows restaurant menus, the shop counter shows neither.
  • Until now the company settings said which parts the business RUNS, and every machine in the building showed all of them. Those settings are shared, so they could never say which part the machine in front of you IS - the front desk, the waiter's till and the shop counter all read the same database and have to disagree about that.
  • The result was that everybody walked past menus for parts of the business they never touch. A waiter scrolled past rooms and housekeeping to reach the floor plan; a receptionist scrolled past kitchen screens to reach arrivals.
  • The choice is remembered on the machine itself rather than in the shared database, which is what lets two tills in one building disagree.
  • It is asked once, when the program first opens on that machine, and never again. A shop, or any business that runs only one thing, is never asked at all - a question with one possible answer is just something to dismiss every morning.
  • The machine also opens on the right screen: the front desk on arrivals, the waiter's till on the floor, the counter on the till.
  • It Can Be Changed At Any Time NEW. File > This Computer Is..., or click the part name in the status bar at the top. A bar that gets busy at eight and needs a second pair of hands on tables should not need an administrator.
  • The screen being looked at is cleared when it changes, because it may belong to a part this machine is about to stop showing.
  • Nothing Is Taken Away That Was Not Already There This only ever narrows. It is a third question asked after the two that already existed - does the business run this, and is this person allowed it - never instead of them. A machine cannot be given a module the business does not have or the person signed in may not use.
  • FIXED. A back office can ask for Everything and see the whole business on one screen, so an owner does not have to pick one part and lose sight of the rest.
  • FIXED. A machine set to a part the business later stops running falls back to showing everything, rather than quietly going blank.
  • Machines already set on the older version, when the choice was only between a bar and a restaurant, keep their answer and are not asked again after upgrading.

Release v3.8.2 — A release can no longer be labelled with the wrong build

Released 1 September 2026

  • The Release Script Could Tag The Wrong Commit FIXED. Nothing in the program itself changed in this version. This is a fix to the machinery that builds and labels a release, and it is being recorded because it decides which build a version number actually refers to.
  • A release is three things that have to agree: the code, the label put on that code, and the installer handed to a shop. The script that made them ran the commit step, and if that step failed it printed a warning and carried on to label whatever was there before - the previous release. Nothing ever compared the label to the code it named, so once it had happened it was invisible.
  • It did happen. The v3.8.1 label briefly named the 3.8.0 code. It was found and corrected by hand the same day, and the installer you were given was never affected, but nothing would have caught it a second time.
  • Now every step either finishes or the release stops with nothing sent. The label is applied to the exact commit just made, then read back and compared before anything leaves the machine; if the two disagree the label is removed and the release abandoned.
  • The version is read from the one file that holds it rather than typed in by hand, so a release cannot be labelled 3.8.2 while carrying a 3.8.1 installer. The project, assembly and file versions must already agree with it, the installer for that exact version must exist, the release notes must mention it, and the label must be unused.
  • What is about to be published is now checked before it is sent, so a customer database dump or an oversized file cannot be included by accident.

Release v3.8.1 — Every list can be read again, and a URA status updates itself

Released 1 September 2026

  • One Refresh, In One Place, For Every List NEW. A Refresh button now sits in the header beside the search box, on every screen, and Ctrl+F5 does the same thing. Twenty-two lists answer it: sales history, receiving history, returns, customer orders, stock adjustments, products, customers, suppliers, purchase orders, stocktakes, expenses, wallets, register history, the terminal dashboard, promotions, payment modes, expense categories, loyalty, and the EFRIS screens.
  • Every list in the program was read once when its screen opened and then sat there. On one machine that is fine. On a shop with a till and a back office it is stale within a minute: the other machine rings up a sale, receives a delivery or takes on a customer, and this screen carries on showing what was true when it opened. To the person looking at it, the sale did not happen.
  • Leaving the screen and coming back always worked. Nobody should have to know that.
  • It re-reads rather than resets: whatever filters and dates you have set are kept, so narrowing a list to one supplier and pressing Refresh brings that supplier up to date rather than handing back the whole list.
  • Screens with nothing to re-read - a report you ran from a date range, a form you are filling in - say so plainly instead of appearing to do nothing.
  • A Ura Status Now Corrects Itself FIXED. After sending a transaction to URA the list you were looking at carried on showing the old status. An invoice that had just been accepted still said it had not been submitted until you left the screen and came back - which reads exactly like it failed, and is how shops ended up sending things URA had already accepted a second time.
  • Anything sent to URA now says so, and the screen in front of you re-reads itself. It works the same whether you pressed the button yourself or the automatic sender did it a moment later in the background.
  • Refusals are announced too, so the reason appears on the screen without you having to go looking for it.

Release v3.8.0 — The till can be worked from the keyboard, and new sales reach URA first

Released 1 September 2026

  • A Whole Sale Without Touching The Mouse NEW. Scan the items, F10, type what the customer handed over, Enter, F11. A queue moves at the speed of the person serving it, and reaching for the mouse between every customer is what slows them down.
  • On the sell screen: F2 finds a product, F3 a customer, F4 holds the sale, F5 brings a held one back, F6 opens the line to discount or edit it, F7 to type a quantity, F8 takes the line off, F9 empties the basket, F10 takes payment, F11 finishes the sale, F12 prints the last receipt again, and Ctrl+Q opens the quick picks.
  • Plus and minus change the quantity on the selected line, and they work straight after a scan without clicking into the basket first - which was the whole point. Press minus at one and the line comes off altogether.
  • Esc is always the way back: it closes whatever is open - payment, the line editor, a list - without changing anything.
  • Anywhere in the program: Ctrl+H sales history, Ctrl+R returns, Ctrl+I receive stock, Ctrl+B products, Ctrl+U customers, Ctrl+E record an expense, Ctrl+D the cash register, Alt+X end of day, Ctrl+L locks the till back to the login screen without closing the drawer.
  • Twenty-six in all, deliberately. Forty is a list nobody learns.
  • And A Page That Says What Each One Does NEW. Help - Keyboard Shortcuts, or Ctrl+F1. Every shortcut, grouped, with a sentence on what it actually does, which ones only work on the sell screen, and which ones ask before they act.
  • The page is built from the same list the keys themselves are read from, so it cannot drift. A shortcut page that has fallen behind is worse than none: somebody learns it, presses the key in front of a customer, and gets something else.
  • Careful With The Things That Go Wrong Typing wins over commanding. While the cursor is in a box, the letter shortcuts stand down - Ctrl+H in the middle of a customer's name goes nowhere. The function keys still work, because F10 while the cursor is in the product box is exactly when you want it.
  • Nothing sits on a key a barcode scanner types, so a scan can never set one off.
  • Emptying the basket and locking the till ask first. Nothing else does, which is the point of a shortcut.
  • No two shortcuts share a key. That one is checked rather than intended.
  • A Sale Rung Up Now Reaches Ura First FIXED. The waiting list was worked through oldest first, twenty-five a minute. A shop that had just switched automatic sending on, or that had been off the network for a day, had hundreds queued - so a sale rung up in front of a customer went to the back and did not reach URA for twenty minutes, with the customer waiting on a fiscalised receipt the whole time.
  • Never-tried records now go before ones already tried, and the newest first within that. A sale rung up now is first in line. Checked with a backlog of a hundred and twenty: the new sale goes first, and the backlog still fills the rest of the same pass, so nothing is skipped - only ordered.

Release v3.7.1 — A cashier you created could not log in, and saving staff on one till deleted them on another

Released 1 September 2026

  • Staff Were Disappearing From The Employee List FIXED, and this is the one that made a cashier impossible to fix by any amount of retrying. Preferences works out who to delete as "everybody in the database who is not on my screen". That is only true of the people this window actually read when it opened. Anyone taken on since - from the server while a till had the window open, or from the other till - was never on that screen, so saving deleted them.
  • A shop lost two members of staff to it without touching them: one machine added them, the other pressed Save on a list that predated them, and they were gone.
  • Removal is now confined to the people this window actually read. Somebody who appeared after that cannot be deleted by us, because we were never in a position to know about them.
  • Somebody Typed In But Not Yet Saved Is No Longer Thrown Away The employee and customer lists are read in the background when the window opens, and that read lands whenever the network lets it. It used to clear the list outright when it arrived - so on a slow shop network it could wipe a cashier somebody was in the middle of typing in, with nothing on screen to say where they had gone.
  • Rows that have not been saved yet are now kept when the read lands.
  • Checked By Driving The Real Screen These are checked end to end against the actual Preferences window - the real Add and Edit buttons, the real entry form, the real Save - finishing at the login query with the password that was typed. Five runs: a cashier added the ordinary way, an existing member of staff edited into somebody else, a save that beats the list read, a second till taking somebody on mid-edit, and the same username used twice.
  • Run against the previous version the same checks fail exactly as the shop described: nobody created while the window reports "Settings saved successfully", the other till's employee deleted, and two accounts left sharing one username.
  • "Settings Saved Successfully" When Nothing Had Been Saved FIXED. Adding an employee in Preferences, pressing Save and being told it worked could leave no account behind at all. The person then got "Invalid username or password" every time, because there was nothing to log in to.
  • Preferences reads its lists - employees, customers, units, taxes, departments - when the window opens, and it refuses to write a list back unless it knows it read it first. That guard is right: a list that failed to load looks empty, and writing an empty list back would delete every employee in the shop.
  • What was wrong is that the reads were started and then forgotten about. Save checked a flag those reads set when they finished, but never waited for them, and a read that could not reach the database threw its error away without a word. On a till reading the database across the shop network that flag could still be false, or stay false for good - and Save then quietly skipped the lists and reported success.
  • Save now waits for those reads before writing anything, and a read that fails is written to the log instead of being swallowed.
  • Adding Somebody No Longer Depends On The List Having Loaded Creating a person needs no knowledge of who else is in the shop, so it is always safe. Only removing and editing need the real list to compare against. Those are now separated: whatever else happens, somebody you added is created.
  • And when a part really was left alone, the window says so, and names it, instead of saying everything saved. It also no longer claims "nothing has been lost" when what you just typed in was not written.
  • The Same Username Twice Is Refused If a username already belongs to somebody, a second account is no longer created for it and you are told which ones. Two accounts sharing a username make logging in a coin toss - the login screen takes whichever comes back first, so half the time the password that works is the other person's. Anyone who had been re-adding the same cashier trying to make it work would have ended up there.

Release v3.7.0 — The cash drawer was counting a fraction of the day's sales

Released 1 September 2026

  • A Morning'S Trading Showed As Three Sales FIXED. A shop that had served customers all morning was shown a handful of them at the register, and the drawer came up short by the difference. The sales themselves were never lost: they were rung up, printed, paid for and sitting in the system exactly as they should be. What they were missing was the drawer they belonged to, and the register counts by drawer.
  • The cause was that the open drawer was remembered in the application rather than looked up. Any screen could clear that memory, and one did: closing a register from the admin dashboard cleared it every time, INCLUDING when the register being closed belonged to a different till or was an old one left over from the migration. On the shop this was found on, somebody tidied away three stale drawers at a quarter past eight, and from that moment every sale for the rest of the morning was saved with no drawer on it.
  • Which drawer money goes into is now asked of the database at the moment it is recorded, for sales, refunds, deposits, expenses and till-to-till movements alike. Nothing that happens on any screen can detach a sale from the drawer the cash physically went into.
  • Closing somebody else's register no longer touches this one.
  • "Make A Sale" Did Nothing When Clicked FIXED, and it was the same fault. The tiles on the dashboard and the POS button on the main window were switched off by that same lost memory, so the moment it was cleared the till went dead: Make a Sale, Receiving, Record Expense and Customer Wallet all stopped responding while the drawer was still very much open.
  • Worse, they gave no sign of it. Those tiles are plain panels, and a switched-off panel looks identical to a working one - same colour, same hand cursor - it just swallows the click. There was nothing on screen to tell a cashier what was wrong.
  • The till now asks the database whether its drawer is open rather than trusting what it remembers. And on the rare occasion the register really is closed, the tiles dim, say so when you hover, and clicking one takes you to the register screen to open the drawer instead of doing nothing at all.
  • What Was Already Stranded Is Taken Back In Fixing the cause would have left every shop already running with takings the register could not see. So on the way into the application, and whenever the register screen is opened or closed, sales, refunds, deposits and expenses recorded on THIS till while its drawer was open and carrying no drawer of their own are taken back into it. The cash is in the drawer either way; now the count says so.
  • Strictly this till, strictly within this drawer's own hours, and never past the moment a later drawer was opened, so no two registers can claim the same money and another terminal's takings are never touched.
  • Checked end to end against the sequence that caused it: sell, have an admin close an unrelated register, sell again, and count.

Release v3.6.1 — Migrated purchases remembered whether URA already had them

Released 1 September 2026

  • Every Migrated Purchase Said "Not Submitted", Whatever The Old System Recorded FIXED. Purchases and stock adjustments brought across from the old POS all arrived marked as never sent to URA, even the ones the old system had recorded as already submitted.
  • The cause was a type rather than a value. The old database stores that yes/no as a tinyint, and the MySQL driver hands a tinyint(1) back as a true/false rather than as the number 1 or 0. The migration was turning it into text and comparing it against "1" - and a true/false becomes the text "True", which is not "1". The test could not come out true for any row in the table, so every purchase and every adjustment was labelled the same way.
  • Item registration was never affected: that flag is stored as text in the old schema and read correctly all along.
  • Yes/no columns are now read as values rather than as text, and all three spellings the old system uses are accepted.
  • Re-Running The Migration Now Corrects What Is Already There Shops have already migrated, so fixing the reading alone would have left every existing voucher mislabelled for good - a second run used to see the voucher was already there and skip it.
  • A re-run now repairs instead of skipping. It works on the voucher that is already in the system, keeping its number and everything since attached to it, and puts the true URA status on it. It also links a supplier that was missing because the purchase came across before the supplier did.
  • Lines that were lost are still put back the same way, and nothing is duplicated: same vouchers, same lines, corrected details. Checked by migrating, deliberately mislabelling everything the way an older version left it, migrating again, and confirming the statuses come right while the voucher and line counts stay put.

Release v3.6 — Automatic fiscalisation was silently sending nothing, and every answer from URA is now kept

Released 1 September 2026

  • Automatic Fiscalisation Was Sending Nothing At All FIXED, and this is the serious one. A shop could have EFRIS switched on, automatic fiscalisation switched on, sell all day, and NOT ONE REQUEST would reach URA. There was no error, no failed record, no log line and no count - from the outside it was indistinguishable from working.
  • Three separate faults stacked up to produce that silence.
  • FIRST: the query for "what has not been accepted yet" could never match a sale that had never been sent. A sale only gets a fiscal status written on it at the moment it is sent, so an unsent sale holds nothing at all - and in SQL a comparison against nothing is neither true nor false, so those rows were quietly dropped from every result. The automatic sender looked every minute and correctly found nothing, because the only sales it could ever have found were the ones already dealt with. The "send what is already waiting" button in EFRIS settings counted and queued nothing for exactly the same reason.
  • SECOND: a sale finished on the ordinary checkout button was never put in the queue. Only the "Save and EFRIS" button queued one. Whether sales are declared is the administrator's decision, made once in settings - not the cashier's, made per sale at the till - so every sale is now queued when the module is switched on.
  • THIRD: received stock was never queued either. The line that queues it sat below the "return" that ends the method, so it had never once run. The compiler had been reporting it as unreachable code all along.
  • Installing this update catches up by itself: on its first pass the sender picks up anything from the last seven days that was never queued. It deliberately stops there - a shop that turned automation on last week did not ask for two years of old sales to be declared at their original dates. Anything older is still there and can be sent deliberately from EFRIS settings, which asks first.
  • Every Answer From Ura Is Now Kept On The Record Only refusals used to be kept, and a success wiped the last refusal away. That left a record that had gone through looking exactly like one that had never been sent - both showed nothing - and it meant URA's own words for an accepted invoice were lost, which is precisely what is wanted when a figure is queried months later.
  • What URA said is now kept whether it accepted or refused, for manual sends and automatic ones alike. It is written on the record itself and OVERWRITTEN on each attempt: one record, one current answer, no error log piling up.
  • It shows on the sale details window, in colour, with a new "What was sent to URA" button beside it that opens the exact request and the exact reply.
  • WHAT URA REFUSED - A NEW SCREEN (Efris Report > What URA Refused)
  • A backlog of refusals is not really a list of records, it is a list of PROBLEMS, and there are usually far fewer problems than records. Two hundred refused invoices is a wall nobody reads. The same two hundred shown as "186 say the item has no commodity code, 11 say the buyer TIN is wrong, 3 say URA was down" is three things to fix.
  • Every refusal still outstanding is gathered by the reason URA gave, commonest first, across sales, items, stock in, adjustments and credit notes. Pick a reason to see the records behind it, open any one of them to read the full request and reply, and once the cause is fixed put the whole group back in the queue in one go.
  • Nothing Is Quietly Given Up On Any More Automatic sending used to abandon a record after five tries. That suited a reliable connection and did not suit these shops: the commonest refusals are things somebody fixes later the same day - an item without a commodity code, a TIN keyed wrong, URA itself down - and a record that had quietly stopped being retried was one nobody would think to look at again.
  • It now keeps trying. Retrying costs nothing, because every attempt overwrites the same row rather than adding to a log. The cap is still there as a setting for anyone who wants it; set it above zero to bring it back.

Release v3.5.2 — Scanning on a large catalogue: 15.6 seconds down to 0.17

Released 31 August 2026

  • Scanning One Product Took Over Fifteen Seconds On A Big Shop FIXED. A scanner is a keyboard that types very fast, and the sell screen was answering EVERY character of the barcode by building a fresh list of matching products and drawing it on screen.
  • The first character is the worst, because one character rules almost nothing out. Measured on a six-thousand-item catalogue, the first character of a barcode matched 1,626 products and took the screen 13.7 SECONDS to lay out. The full thirteen-character scan cost 15.6 seconds, of which the cashier saw only the very last list.
  • None of that was the network or the database, which is why it looked fine on the server machine, why completing a sale stayed fast, and why it got steadily worse as the shop added products.
  • Two changes. The dropdown now waits for a pause in the typing before it draws anything, so a scan - which arrives far faster than any person types - produces no list at all, just the item on the sale. And the list is capped at 50 candidates, because nobody has ever scrolled 1,626 rows to find a product; they type another character.
  • The same scan now costs 0.17 seconds instead of 15.6 - and the product proved is the LAST one in the catalogue, so nothing has been hidden behind the cap. Typing a name by hand still brings up the right candidates; that is checked too, because deferring the list too eagerly would have been a worse bug than the one being fixed.
  • The customer box had the same shape and got the same treatment, for shops with long customer lists.
  • The Installer Builder No Longer Re-Encodes The Project File FIXED. build_installer.bat patches the version number into WeafPOS.csproj before building, and the PowerShell it used to do that wrote the file back in the system's ANSI codepage rather than the UTF-8 it was read as.
  • Every run silently re-encoded the whole file. The copyright symbol in the product details went from two valid UTF-8 bytes to one ANSI byte, MSBuild then read the file as UTF-8, hit a byte that could not be one, and the build died with "Invalid character in the given encoding" pointing at a line nobody had touched.
  • The script now says which encoding to write, and the project file itself is plain ASCII throughout (the copyright symbol is written as an XML entity), so no tool can mangle it again. Checked by running the version-patch step twice over and confirming the file comes out byte-identical, and that the built application still carries "Copyright (c) 2026 WEAF COMPANY UGANDA LIMITED" in its file details.
  • A Tool For Checking A Slow Till New: tools/till-check.ps1, to be run ON the till that is slow. It reads that till's own database settings, so there is nothing to type in, and reports network latency and packet loss, how long the server takes to accept a new connection, round-trip time to the database, and how much data opening the sell screen actually pulls across the wire.
  • It calls out the usual culprit by name: a server doing a reverse-DNS lookup on every new connection stalls for seconds on connect while queries themselves stay fast.

Release v3.5.1 — The version on the main window comes from the build and nowhere else

Released 31 August 2026

  • The Version Shown Could Be Three Releases Out Of Date The version at the bottom of the main window is read from the build itself, but it was ALSO typed into the screen layout as something to show until that read happened - and the typed one had drifted three releases behind, still reading v3.3.1.
  • It only appeared on a machine where reading the build failed, which is rare. But a version that is merely stale is worse than none at all: it names the wrong build to whoever is checking it, and the only reason anybody checks is that something is already wrong.
  • There is now one place that knows the version - the build - and nothing to keep in step with it. Checked by opening the real main window and reading what it shows, rather than by trusting a constant.

Release v3.5 — Invoices URA already has are recovered, migrated purchases get their lines back, and the till stops dragging the whole shop across the network

Released 31 August 2026

  • An Invoice Ura Has Already Issued Is Now Found And Recorded FIXED. Fiscalising is two steps that are not one transaction: ask URA to issue the invoice, then write down what URA answered. Anything that interrupts the gap - a power cut, the network dropping after the request landed, the application closing while the automatic sender was mid-pass - left URA holding a perfectly good invoice that this POS had no record of.
  • The sale then looked unsent, so it was sent again, and URA answered: "2253 - Invoice(s)/receipt(s) (...) with the same Seller's Reference Number have already been issued!" Retrying could never get past that, so the sale stayed marked FAILED for ever while the invoice sat in URA's records, valid and declared. The shop was left believing it had unfiscalised sales that URA had already accepted.
  • That refusal is now treated as the answer it actually is. The invoice is looked up by the reference number it was issued against, its details are fetched, and it is CHECKED AGAINST THIS SALE - line count, line amounts, gross and tax - before its number, anti-fake code and QR code are written onto the sale.
  • If it does not match, it is deliberately left alone and says why. Putting somebody else's fiscal number on a customer's receipt would be far worse than a sale still marked failed.
  • An invoice URA has since cancelled is not claimed either - that sale genuinely still needs sending.
  • Migrated Purchases Had No Item Lines FIXED, and it was the same fault as the missing sale lines in v3.3.3. When Products failed on the first migration, every purchase line was dropped for want of an item to point at. The vouchers were saved anyway with the invoice total written on by hand, so the vendor history looked right and every voucher opened empty.
  • Running the migration again did not help: those vouchers already existed, so they were skipped as done. A re-run now puts the lines back against the voucher that is already there, keeping its id and anything since attached to it, and clears the stand-in total so the voucher is not counted twice.
  • Purchase lines also now have their own line in the migration report. They had none, which is exactly why a run that brought across 2,499 vouchers and not one line of any of them looked like a run that had worked.
  • The Till And The Stock Screens Stop Dragging The Whole Shop Across The Network The sell screen, Receive Items, Stock Adjustment and the Item List each read the whole catalogue when they open - every item with its department, tax, both units and its custom fields.
  • Four of those are references and one is a collection, and joining a collection REPEATS the whole item on every row of it: an item with four custom fields arrived four times over, carrying its department, its tax and both its units each time.
  • Measured on a 6,000-item shop: 4.8 MB fetched to show what fits in 1.7 MB. It is now asked as two questions instead of one, and not tracked - nothing on these screens is ever saved through the context that loaded it. 65% LESS ACROSS THE NETWORK, and faster even on one machine.
  • On a good local network nobody would notice either way. On a shop's own wiring, on a client-server setup with a connection that is already struggling, this is the difference between a till that opens and a till that looks broken.

Release v3.4.1 — Purchase Orders and Stocktakes stop reading every line to show a count

Released 31 August 2026

  • Purchase Orders Only Fetches The Orders It Is Showing The screen opens on orders that are still outstanding, and it fetched EVERY purchase order ever placed - with all of its lines - to find them. Closed orders are the ones that pile up, year after year; the open ones are always few.
  • The status is now part of what is asked of the database. Measured on 200 orders of 50 lines each: 20 rows fetched instead of 200 orders and 10,000 lines. Switching the status box goes back and asks again, so nothing is out of reach.
  • Stocktakes No Longer Reads Every Counted Row The screen shows one line per stocktake with the number of items, how many had a variance, and what that variance is worth. It worked those out by pulling every counted row of every stocktake ever done - name, code, quantities and cost. A stocktake of a six-thousand-line shop is six thousand rows, and ten of them is sixty thousand, to fill in thirty numbers.
  • The counting and totalling now happen in the database. The three numbers are unchanged - checked against a seeded count of 300 items with 100 deliberate variances worth 100,000.
  • Not Changed, And Why Customer Wallets, Customer List, Vendor List, Item List, Promotions and EFRIS Purchases still read their lists in full. They are lists of things rather than of events - there is no period to narrow them to, and nothing nested being read to summarise it.

Release v3.4 — Screens say when they are loading, and stop fetching the whole history to show a month

Released 31 August 2026

  • Every List Screen Now Shows A Spinner While It Fetches 18 screens gained the same "Loading..." spinner the Item List has always had: Sales History, Receive Items, Stock Adjustment, Adjustment History, Receiving History, Stock Movements, Customer List, Vendor List, Sales Returns, Expense History, Register History, Audit Log, Purchase Orders, Customer Wallets, Stocktakes, Promotions, Batch Expiry and EFRIS Purchases.
  • This matters more than it sounds. On a shared or remote database the first query takes seconds, and a screen that says nothing in the meantime looks exactly like one that has finished and found nothing - staff read an empty grid as "there are no receipts today" and either go hunting for a problem that is not there or key the work in again.
  • It is written once and used by every screen, so they cannot drift apart, and it clears from a finally: a query that fails leaves an error, never a screen stuck under a spinner that never goes away.
  • Two Screens That Used To Freeze Now Don'T Expense History and Stock Movements fetched their data on the same thread that draws the window, so the whole application stopped responding until the database answered - which reads as a crash, not as a wait. They now fetch in the background like everything else, which is also what lets them show the spinner at all.
  • The History Screens No Longer Read The Whole Shop To Show One Month Sales History, Receiving History, Adjustment History and Stock Movements each opened on a recent window and each fetched EVERYTHING to do it - every sale ever made with all of its lines, every receiving voucher with its items, every stock movement ever recorded - and then threw nearly all of it away in memory.
  • The screen showed the same few hundred rows on a shop's first day and its thousandth. Only the wait grew, every month the shop traded.
  • They now ask the database only for the period they are showing, which is the last 30 days to begin with. Measured on a shop with 400 days of trading: 31 rows fetched instead of 400, on every one of the four.
  • Nothing is out of reach. The date pickers and the period box work as before, and choosing a wider period - or "All Transactions" - goes back and fetches it. Adjustment History and Stock Movements had no starting period at all before and now open on the last 30 days like the rest.

Release v3.3.3 — URGENT FIX: a migration could report success having brought across no products at all (supersedes v3.3.2, which was tagged without the last of these fixes and should not be deployed)

Released 31 August 2026

  • No Items After Migrating, Though The Migration Said "Done" FIXED. A migration would read every product, fail to save a single one of them, and still finish with a green bar reading "Done - 138,435 records created". The shop was left with its full sales history and an empty item list.
  • The cause: an item is allowed to have no department - the screens have always shown a blank for it - but the SQL that creates the table on a NEW installation made that column compulsory. Nothing notices until something tries to save an item that has no department, and then the database rejects THE WHOLE SAVE rather than the one row. So a handful of old products naming a department that no longer exists threw away all 6,318 of them.
  • The column is now created correctly on new installations, and any machine already carrying the fault repairs itself the next time the application starts. Nothing is re-created and no data is touched.
  • And The Sale Lines That Went With Them FIXED. Because the products were gone, all 404,103 sale lines were dropped too - there was no item for them to point at. The invoice totals were right and every invoice opened empty.
  • Worse, running the migration again did not put them back: those invoices were already there, so they were skipped as done, and the lines would have been missing for good.
  • A re-run now repairs them. An invoice that is already migrated but has lost its lines has them put back against the header that is already there, keeping its number, its id and anything since attached to it. Invoices that are complete are left alone.
  • A Migration That Loses A Step Is No Longer Called A Success "Success" only ever meant "it reached the end", which is why losing every product still finished green. A run that lost a step now says so on the bar, in red, names what did not come across, and puts it in front of you before you close the window. The reason for each is in the report as before.
  • Starting A Migration Again In A Fresh Database No Longer Skips Everything And a run that LOST a step no longer records anything as done at all. A failed step quietly damages the ones after it - when the products were lost, the sales step ran next and wrote every invoice with none of its lines - so the whole run is treated as untrustworthy and the next one goes over everything. That is safe: no step ever brings the same thing across twice.
  • The note of what already came across is written against the database NAME. Somebody whose first attempt went wrong starts again by emptying the database and migrating into it afresh - and the note still matched, so twenty steps were unticked as "already done" against a database holding none of it. If the database being migrated into is empty, that note is now discarded.
  • The Sidebar No Longer Groups Its Buttons The STOCK / PEOPLE / SELLING headings have been removed. The buttons keep their order, including putting whichever module the machine is standing in first.

Release v3.3.1 — URGENT FIX: the application would not open after signing in

Released 31 August 2026

  • The Application Disappeared After Login FIXED, and this is the only thing in this release. On v3.3 the login window would accept a correct username and password, close, and then nothing appeared. No error, no message, nothing in the log after "Login successful". The application had not crashed - it had frozen while building its own main window, with no window on screen to show for it.
  • The cause was introduced by the new module-aware sidebar. The main window asks what the signed-in member of staff is allowed to see WHILE IT IS STILL BEING BUILT, and that question has to go to the database. It was being waited for on the same thread that had to finish the reading - so the read could never complete, the window could never finish, and no exception was ever thrown for anybody to see. It affected every user including administrators, on every machine, every time.
  • The question is now asked off that thread, so it cannot happen. Proven both ways: with the old code the check hangs, with the new code it returns in under half a second.
  • Two Guards So It Cannot Come Back The Same Way A till whose database has gone away now OPENS anyway. Permission questions give up after ten seconds and the window carries on, rather than sitting on a connection timeout with nothing on screen - which looks exactly like the application failing to start. It is also only attempted once per sign-in, so a machine that cannot reach its database does not pay that wait on every screen.
  • The sidebar can no longer take the application down with it. If it cannot be worked out for any reason, the failure is logged and the window still opens with its menus working.
  • The Version Is Now Visible On The Main Window The version at the bottom of the main window now shows the patch number when there is one, so a machine that has had a fix deployed can be told apart from one that has not without opening anything. This build reads v3.3.1.

Release v3.3 — Migration: resume where you stopped, and skip what you do not need

Released 31 August 2026

  • The Step That Looked Like It Had Hung FIXED: on a shop with a long history, "Migrating EFRIS responses..." could sit there for hours with the bar barely moving. It had not crashed - it was doing the work in the slowest possible shape.
  • Two things were wrong. It read the ENTIRE EFRIS log into memory before writing anything, and that table is routinely the largest in an old WeafPOS: the old system wrote one row per failed attempt, so a single stubborn invoice left fifty near-identical rows. Then, for every distinct invoice, it asked the database for that invoice BY NUMBER - one round trip each, against a column with no index, so every one of tens of thousands of lookups was a full scan of the sales table. It got slower the more sales had just been migrated, which is exactly why it died at the END of a big import.
  • Now the log is read one row at a time and thrown away as it goes, so memory is decided by how many invoices survive the fold rather than by how big the shop's history is; and every invoice is resolved from a single query up front.
  • Measured on 40,000 log rows against 20,000 sales: 3.5 seconds, against 24 seconds of pure database time for only half the old lookups. The old cost multiplied out - invoices times sales - so on a real shop it was hours.
  • You Do Not Have To Bring It At All The EFRIS responses step is now OPTIONAL, and unticked by default. It brings across nothing a shop needs in order to trade: only the text of the last URA failure against invoices that had already failed in the old system, so somebody can read why. A shop opening tomorrow should have to ASK for that, not discover it by being made to wait.
  • The step list on the Options page now says WHY a step is off, beside it, instead of leaving somebody to guess.
  • Everything a shop actually needs - products, customers, suppliers, sales, returns, purchases, stock, expenses, wallet - is still ticked and still comes across.
  • Skip A Step Without Losing The Run New: SKIP THIS STEP, on the migration screen while it is running. Abandon the step in front of you and every step after it still runs.
  • Until now the only way out of a slow step was Cancel, which stopped everything - and on a shop with a hundred thousand invoices, starting again is another evening.
  • The step that was dropped is named in the report and in the warnings, and it is deliberately NOT recorded as done, so running the migration again brings it across.
  • Pick Up Where You Stopped The wizard now remembers which steps finished, and unticks them next time - with the date and time they came across written across the top.
  • Every step already refused to import the same thing twice, so re-running was always safe. What was missing was knowing it was unnecessary: a second run used to spend an hour re-reading a hundred thousand sales in order to conclude it had seen them all. Now it does the part that is actually left.
  • Tick one again at any time to go over it; nothing is ever brought in twice.
  • Pointing the POS at a different database starts clean, because a fresh target has nothing in it whatever an earlier run did somewhere else.

Release v4.1 — Tapping: split a bill a tap at a time, decide your own KOTs, and a sidebar that fits the business

Released 31 August 2026

  • Nothing Goes To The Kitchen Until You Send It FIXED: the Send button could sit greyed out with a full bill in front of you, and only came back to life if you added a note to an item. The cause was the old "send each item to its station the moment it is added" setting: every item was despatched as it was rung up, so there was never anything left to send, and adding a note put the line back in the queue - which made it look as though items needed notes before the kitchen would take them.
  • That setting is gone, from both restaurant screens and from Preferences. There is now ONE rule everywhere: an order reaches the kitchen when somebody sends it. Ringing an item up and telling the kitchen about it are two different decisions, and a till that runs them together leaves a waiter no moment in which to fix an order - every correction becomes a void.
  • Send The Whole Bill, Or Just Part Of It Pick lines on the bill and only those go. The drinks now and the food when the last person has finally chosen is how an order is actually taken, and a waiter who cannot do that holds the whole thing back until somebody picks a pudding.
  • The Send button says exactly what it will do - "Send 3 to kitchen" or "Send 2 chosen to kitchen" - so it never quietly changes meaning depending on a selection somewhere else.
  • When everything has gone it says "Everything is with the kitchen" instead of sitting there greyed and silent.
  • New: REPRINT KOT. Printers jam, paper runs out, and a docket gets knocked into a sink. Without this the only way to make the kitchen see an order again was to ring the food up a second time, which put it on the bill twice. Reprints are marked as reprints.
  • Ringing The Same Thing Up Twice Tapping an item again now adds ONE MORE of it rather than starting another line. A bill reading "1 x Coke, 1 x Coke, 1 x Coke" is one somebody has to add up in their head, and a kitchen order saying the same is three separate drinks to pour.
  • Modifiers are part of what makes two plates the same: a steak rare and a steak with extra chips stay two lines, at two prices. So do two different notes.
  • A line the kitchen has already been told about is never joined. Another one of those is a second round, and it goes to the kitchen on its own.
  • Receipts group identical lines too, so a bill that was split and rejoined cannot print the same drink three times.
  • Splitting A Bill By Tapping Rebuilt around how a waiter actually thinks: TAP THE SHARE YOU ARE FILLING, THEN TAP WHAT THEY HAD. The share being filled is outlined and named, so there is never any doubt where the next tap lands.
  • Each tap moves ONE. Three beers rung up as a single line of three go to three different people without anybody having to think about lines at all - and when the last one has gone the item disappears from the list, so a fourth beer that was never ordered cannot be given away.
  • "All" hands over the whole lot at once, for the person paying for the round. "Back" returns one at a time.
  • Identical items are shown as one row however many lines they are stored as. That is a storage detail and no waiter should ever see it.

Release v4.0 — Hospitality: a Restaurant POS, a Hotel, and Recipes

Released 30 August 2026

  • The One Thing That Makes A Restaurant Work With Ura Food is now declared to URA as a SERVICE, not as goods, under the category URA publishes for it (90101501 - Restaurants). A room night is the same, under 90111501 - Hotels.
  • This is the failure a fiscalised restaurant otherwise meets on its very first evening. Declared as goods, URA expects a stock figure for every dish and REFUSES any invoice that would take one below zero. Nobody has ever declared a stock of chicken curry, and nobody ever will - there is no such thing. There is chicken, there is rice, and there is a cook.
  • Declared as a service, the dish carries no stock, the invoices go through, and the kitchen goes on counting the things it actually buys - internally, where they belong, and never sent to URA at all.
  • New: Restaurant > Set the Menu Up for URA. It lists every menu group, says exactly what will change, and does it: the group goes under the restaurant category and its items become services. Your stock figures are left exactly as they are.
  • Services are now kept out of everything they have no business being in: EFRIS stock reconciliation ignores them, and a stock-in voucher or adjustment containing one drops that line rather than being refused whole and stuck for ever. A voucher that is ALL services is marked done rather than failed - it is finished with URA, and a permanent red mark against a perfectly correct document helps nobody.
  • Recipes - What A Plate Is Actually Made Of New: Inventory > Recipes and Production. Write down what a dish is made of, and selling one takes the chicken, the rice and the oil off the store instead of a plate that never existed as stock.
  • FOUR FIGURES ACROSS THE TOP, and one of them decides whether a menu makes money: food cost, selling price, FOOD COST PER CENT, and how many portions the store could make right now. Around a third is the usual target here; the figure is coloured so nobody has to remember what good looks like.
  • "Can make now" also says WHAT RUNS OUT FIRST. "Eleven more, and then the fish is gone" is what actually sends somebody to the market.
  • Recipes nest. A sauce made on Monday in a pot is stock, and a dish using it takes a ladle off that stock; a sauce made fresh per plate has no pot, so its own ingredients come off instead. A recipe that reaches itself is caught, named and stopped rather than spinning.
  • WASTAGE IS PART OF THE COST. A whole fish is not a fillet. Trim, peel, bone and spillage go on the ingredient line, and a recipe that ignores them undercosts every plate it is on.
  • Units are the kitchen's, not the store's. Write 30 ml of oil while the store counts in litres; the factor is set once, visible on the line, and the resolved figure is STORED - so changing a unit next year cannot quietly rewrite what last year's plates cost.
  • Make a batch: the pot of sauce, the tray of chapati. The ingredients come off at what they cost today and the finished item goes into store at what the batch actually worked out to - which is the only way the food cost of everything built on top of it stays honest.
  • Extra cheese is cheese. A paid modifier can point at what it takes off the store, so a house that charges for it stops quietly losing it as shrinkage nobody can explain.
  • It never refuses a sale. Kitchen stock figures are always a little behind the shelf, and a till that will not sell a plate at eight in the evening because it thinks the salt ran out is worse than useless. The shortfall is recorded and shows up on the variance report, which is where it belongs.

Release v3.9 — Restaurant Edition: Tables, Bills and the Kitchen

Released 30 August 2026

  • Choose What Kind Of Business This Is New: Preferences > General > Business Type. Pick Supermarket, Restaurant, or Both.
  • Both is the point of it. A great many venues here are a bar AND a restaurant AND a shop under one roof, and a bar counter sells much the way a shop does. Choosing Both puts the floor plan beside the till on one licence, one item list, one stock ledger, one EFRIS setup and one set of reports.
  • Nothing is taken away by choosing Restaurant: the till is still there for counter sales. Existing shops are untouched - the setting defaults to Supermarket, so an upgrade changes nothing at all.
  • The Floor New: Restaurant > Floor / Tables (also on the sidebar). Areas across the top - Main Bar, Garden, VIP - and the tables in each below.
  • Every table shows what is on it at a glance: the running total, the waiter, how long it has been sitting, and the number of guests.
  • TWO COLOURS THAT EARN THEIR PLACE. Amber means items have been ordered but never sent to the kitchen - the single most expensive mistake in a restaurant, and invisible on most systems until the customer complains. Red means the table has been sitting longer than you allow, which is either a party enjoying itself or one that quietly walked out.
  • The floor refreshes itself every ten seconds, so a table another till just opened appears without anyone pressing anything.
  • Takeaway and counter bills have nowhere to sit on a floor plan, so they get their own list rather than being invisible.
  • The Bill The menu on the left, the bill on the right, and the only two things that ever happen to a bill as big buttons at the bottom: send it to the kitchen, and settle it.
  • Menu buttons are sized for a finger, not a mouse. These screens are used standing up, at speed, often on a touch monitor.
  • Items not yet sent are amber on the bill as well, with a count above the Send button. Settling a bill with unsent items asks first - those items have not been made, so charging for them is a decision, not an accident.
  • Courses, and a note for the kitchen per line with the common ones as buttons: no onions, ALLERGY, well done. Notes are added to rather than replaced, because an allergy plus "no onions" is two facts and replacing would lose one. Changing a note after the kitchen has been told sends it again, or the note is just decoration.
  • Modifiers That Cannot Produce A Nonsense Order Ask how a steak is cooked, what goes on the side, and charge for the extras. A group can require exactly one answer, allow several, or set its own limits.
  • The rules are enforced when the item is added, so the kitchen is never sent an order that does not make sense - which is the whole point of asking rather than letting a waiter write it into a note.

Release v3.8 — Send to URA Automatically, and See Exactly What Was Sent

Released 29 August 2026

  • What Was Sent, Kept On The Record Every item, sale, stock-in voucher, adjustment and credit note now keeps the exact request that went to URA, URA's exact reply, URA's return code, the reason it was refused, how many times it has been tried and when.
  • "See what was sent" opens the two documents side by side, laid out so they can be read, with a button to copy either. When URA refuses something the reason is almost always in the payload - a commodity code the item does not really have, a unit URA does not know, a total that does not match quantity times price - so this turns "EFRIS failed" into something a person can act on without going to the log file on whichever machine happened to send it.
  • A reply that is not JSON at all, such as a gateway's HTML error page, is shown exactly as it arrived rather than disappearing behind a parse failure.
  • Fixing a record clears its old failure, so something that has since gone through no longer reads as broken.
  • Register Items In Bulk New: Efris Report > Register Items in Bulk (also on the EFRIS settings page). It lists every active item URA has never been told about - which is what a shop faces after importing a catalogue or switching EFRIS on for the first time - and registers them in batches.
  • Anything URA refuses is named on its own row with URA's own words, so the refusals can be worked through one by one instead of guessed at. Double-click a row to see that item's own request and reply.
  • Search, select all or none, and a filter for the ones URA has refused before, so a second pass after fixing categories only covers what actually failed.
  • Send To Ura Automatically, Per Module New on EFRIS Settings: switch automatic sending on for sales, items, stock in, and stock adjustments, each on its own. Everything is off until an administrator turns it on - an upgrade never starts declaring things on a shop's behalf.
  • With a module on, anything saved that has not reached URA is sent within a minute or two, and anything refused is tried again a few times before being left for a person. How many tries, and how long to wait between them, are both settings.
  • Fiscalising by hand means somebody has to notice. A till that loses its internet for an hour leaves a morning's sales undeclared and nobody finds out until URA does; this picks them up as soon as the connection is back.
  • Switching a module on covers what is saved from then on. If there is already a backlog you are asked, plainly, whether to send that too - a shop could have months of undeclared sales behind it, and that is not something to do quietly on a checkbox.
  • The settings page shows how much is waiting per module, and how much has been given up on.
  • Credit notes are deliberately not on the list. A sales return applies for its credit note BEFORE the return is recorded and abandons the return outright if URA refuses, so a recorded return has always been accepted already and there is never one waiting. Automating it would mean recording returns URA has not agreed to.
  • More Than One Till: Never The Same Thing Twice Every machine runs the automatic sender - a shop whose server is switched off should not stop declaring - and no two machines can ever send the same record.

Release v3.7 — Reconcile Your Stock Against URA

Released 29 August 2026

  • What It Is New: Inventory > EFRIS Stock Reconciliation (also on the sidebar). It reads the stock URA believes you hold, puts it beside the stock this POS holds, and settles the two. Only appears when EFRIS integration is switched on.
  • A stocktake settles the shelf against the system. This settles the system against URA, which is a different question: URA's figure only moves when something is declared to it, so it drifts whenever stock moved in ways EFRIS never saw - a delivery received before the integration was switched on, a submission that failed, stock written off here.
  • Every item is shown with what we hold, what URA holds, and the gap between them. Start on "Only the differences" so the list is the work rather than the whole catalogue.
  • Saying Which Side Is Right The page never guesses. The Counted column is what actually gets declared, and it starts at this shop's own figure - nothing goes to URA that a person has not looked at.
  • "Count = what we hold" says this shop is right and moves URA to match. "Count = URA's figure" says URA is right and moves this shop's stock to match. Or type a counted quantity per line and BOTH sides are moved to it - the same thing a stocktake does, done against both sets of books at once.
  • Each line shows in plain words how it will travel before you commit: "Opening stock of 10.00", "Stock in of 5.00", "Adjustment out of 18.00", or "Nothing - already agrees".
  • The Three Roads Ura Gives, Picked For You URA is not symmetrical about this and it matters. It offers OPENING STOCK once, and only while the goods have never held stock there; a STOCK IN to increase; and a STOCK ADJUSTMENT OUT to decrease. There is no adjustment in.
  • So increases and decreases travel by different calls, and the page picks per item rather than making anyone think about it. Where URA holds nothing, the increase is offered as opening stock, because that is what opening stock is for.
  • If URA refuses the opening stock - which is what it does once the goods have moved there, even if they are back at zero - the very same quantity is sent again as an ordinary stock in. You are not left to work that out.
  • The supplier on those stock-ins is "Stock Taking", not a real vendor. A count is not a purchase, and naming a supplier who never sold you the goods would be a false declaration.
  • Decreases go as an adjustment out, marked Others, with the reconciliation's reference on it.
  • Done Carefully YOUR OWN BOOKS ARE PUT RIGHT FIRST, and stay right even if URA refuses. Quantity on hand, the batches behind it and a stock movement are all written exactly as a stocktake writes them.
  • Sent in as few calls as possible - one for each of the three roads - and a batch URA refuses is retried one item at a time, so one bad item cannot stop the rest.
  • A call that TIMED OUT is never retried automatically. It may well have been applied, and sending it again would move the stock twice; it is reported instead, in URA's own words, for somebody to look at.

Release v3.6 — New Items Are Registered With URA Before the Stock Is Sent

Released 29 August 2026

  • FIXED THE BOUNCING: items created from a supplier's EFRIS invoice existed here but were never declared to URA, so the stock increase came back refused - "commodityGoodsId or goodsCode does not exist". The delivery could not be received until somebody went and registered every new item by hand, one at a time.
  • Items created from an invoice are now registered with URA as they are created. By the time the receiving voucher opens, URA already knows the goods and the stock increase goes straight through.
  • The whole batch is registered in ONE call rather than one call per item, so twenty new items cost one round trip instead of twenty. If URA refuses the batch, the items are offered again one at a time, so one bad item cannot stop the other nineteen from being registered.
  • Anything URA refuses is named, with URA's own reason. The item is still created here and the invoice line still matched to it, so nothing is lost - but you are told plainly that its stock will be refused until it is registered, rather than finding out at the end.
  • ALSO CLOSED: a line matched to an item that was already in your catalogue but had never been registered with URA would bounce in exactly the same way. Send to Receiving now checks every matched item and registers whatever URA does not know about, not only the ones just created.
  • Registering an item twice is safe. An item URA already has is sent as an update rather than a new registration.
  • Items are registered on the same terms as the Add Item form uses - the commodity category is the one the supplier used on the invoice, the unit is the supplier's unit matched to the standard list, and the price is the one you set.
  • Tested End To End Against The Live Sandbox Reproduced the fault first: a stock increase for a freshly created item was refused with "[658] commodityGoodsId or goodsCode does not exist!".
  • Registered the items, confirmed they are in URA's goods registry by querying it back, then sent the same stock increase again: "[00] SUCCESS".
  • Registering the same items a second time was accepted as an update, not a duplicate.

Release v3.5 — Scan Barcodes and Set Prices While Creating Items

Released 29 August 2026

  • New: when items are created from a supplier's EFRIS invoice, you are asked whether you want to scan barcodes and whether you want to set your own selling prices. Say yes and the items are shown ONE AT A TIME so you can work down them with the scanner in hand.
  • Built for a scanner. The barcode box already has focus, so you just scan; the scan ends with Enter and moves straight to the price, and Enter there moves to the next item. No clicking between items.
  • The two questions are asked separately because they are different jobs - barcodes need whoever has the scanner, prices need whoever sets prices. Answer no to both and it behaves exactly as before, using the suggested price.
  • Skip any item and it keeps what the invoice gave it, so there is no penalty for not having a barcode to hand. You can go Back to correct one you have already done.
  • NOTHING IS CREATED UNTIL YOU FINISH. The whole step runs before anything is written, so cancelling half way leaves your catalogue exactly as it was rather than a batch of items with no barcodes on them.
  • UP TO FOUR BARCODES PER ITEM, the same as the item registration form allows - a bottle and its crate, or the same drink packed by two suppliers. Only one box is shown to start with, so the ordinary one-barcode item is still a single scan; press "+ Add another barcode" for each extra one, and Enter moves between the boxes that are open before going on to the price.
  • Leave the first box blank and fill in a later one and the gaps are closed up, so the item still gets a main barcode rather than an empty first slot.
  • Come back to an item you have already done and every barcode you gave it is shown again, ready to correct.
  • A barcode already used by another item is refused, with the reason - two items sharing a barcode means the till rings up whichever it finds first, and it is caught wherever the other item carries it, not only in its first barcode slot. The same barcode scanned twice within one batch, or twice on the one item, is refused as well.
  • Prices are read properly whether or not you type a thousands separator, and a price below the cost from the invoice asks you to confirm rather than being silently accepted.
  • The same step runs when you create a single item from one invoice line, so an item made on its own is set up exactly as it would be in a batch.
  • Tested on three items, thirteen checks: four barcodes captured onto one item and read back in order; a fifth refused because there are only four slots; a barcode belonging to an existing item refused even though that item carried it in its second slot; the same code refused twice on one item and refused across two items in the batch; a code typed in the second box only promoted to the main barcode; all four shown again on going back; blanks keeping the suggested price; "ninety thousand" refused; "55,000" read as 55000; Skip clearing the lot and restoring the suggestion.

Release v3.4 — Fixes to Creating Items From a Supplier Invoice

Released 29 August 2026

  • FIXED: "Create a new item" on the matching screen opened a blank Add Item form and threw away everything the invoice already knew - you had to type the department, unit, tax and cost back in by hand. It now builds the whole item from the invoice line, exactly as "Create the missing items" does, and shows you what it will create before keeping it. The two routes now share the same code, so they cannot drift apart.
  • FIXED: the receiving voucher showed a number in the UOM column instead of the unit name - "776" rather than "BO-Bottle". The unit itself was right all along; the grid draws that column through a lookup list which had not been filled in yet when the voucher was opened straight from an invoice. The list is now guaranteed to be in place before the lines are drawn.
  • Unit matching is more forgiving. The supplier's unit is found in this system's own 505-unit list by exact code, by code ignoring case and spacing, by the code the unit name begins with, or by the full name. A unit genuinely not on the list falls back to pieces and is written to the log by name so it can be looked at. Checked on ten spellings including "BO", "bo", " PCE ", "Ltr" and the full "BO-Bottle, non protected, cylindrical".
  • FIXED (found while testing, affects receiving generally): recalling a held voucher left the Stock In Type box blank instead of showing what the voucher was. It was being set in a way that silently selected nothing, and a blank box reads back as Local Purchase - so a held IMPORT voucher would post, and be sent to URA, as a local purchase. It now selects the right type.
  • Stock In Type always shows the type the voucher will actually be saved as, and defaults to Local Purchase. It can no longer sit empty: an unrecognised or missing type falls back to Local Purchase visibly rather than blank, so what is on screen and what is sent to URA are the same thing.
  • FIXED (also affects recalling held vouchers): the voucher date was being reset to today after it had been loaded. A purchase brought in from EFRIS is dated the day the supplier invoiced it, and a held voucher keeps the date it was held on - that is the stock-in date URA is given. Today's date is now only used for a voucher being typed fresh.
  • FIXED (the other half of the same fault): once a voucher had been saved or held, changing the date on screen did nothing - the date was only read while the voucher was new. So the date shown and the stock-in date sent to URA could differ. The date on screen is now always the date saved.
  • Checked by driving the real Receive Items screen: opened from an invoice issued 28 Aug on a day that was 29 Aug, the voucher kept 28 Aug through opening, saving and into the figure sent to URA (stockInDate 2026-08-28), the type showed Local Purchase rather than blank, and a date changed afterwards stuck.
  • Note: Application version raised from 3.1 to 3.2. The main window reads it from the assembly, so it now reads v3.2.

Release v3.3 — Bring Your Purchases In From EFRIS

Released 28 August 2026

  • Pull What Your Suppliers Billed You New: Purchasing > EFRIS Purchases (also on the sidebar, beside Receive Items). It lists the invoices your suppliers have fiscalised against your TIN at URA - the purchase side of EFRIS, which until now the POS could not see at all. Only appears when EFRIS integration is switched on.
  • Pick a date range, press Fetch from URA, and the invoices come back with the supplier, their reference, the gross and the tax. Search by supplier name or TIN if you only want one of them; type digits and it searches by TIN, letters and it searches by name.
  • Open an invoice and its lines are fetched in full: what the supplier billed, in their own words, with the URA commodity category, quantity, unit and price for each line.
  • Everything fetched is kept locally, so the matching work is still there tomorrow, and a fetch over the same dates does not create the invoice a second time. Re-fetching refreshes URA's figures and leaves your own decisions - the vendor, the matches, whether it has been received - untouched.
  • Matching Their Items To Yours, Once Why matching is needed at all: a supplier's invoice is written for the supplier's books. Their item code comes from their own EFRIS goods registry and means nothing in your catalogue, the description is their name for the product, and they bill in whatever they sell by. None of that can be worked out from the document, so somebody has to say it once.
  • Say it once and it is remembered. Each line you match is recorded against that vendor, and the next invoice from them fills itself in. Tested on two real invoices carrying the same supplier line: the second matched itself with nobody touching it.
  • PACK SIZES ARE HANDLED. A supplier who bills you a carton while you stock and sell singles has a "yours per theirs" of 24, and the POS then receives 240 singles rather than 10 cartons, at the per-single cost. Ten cartons at 2,000 becomes 240 units at 83.33 - which multiplies back to exactly the 20,000 on the invoice.
  • Discounts are not lost. URA writes a discount as its own separate line with no quantity and a negative amount; read literally it looks like a second product bought at a negative price. Each one is folded back into the line it belongs to, so the cost you receive at is the cost you actually paid. Checked against URA's own totals on twelve real invoices, three of them discounted: every one reconciled to the shilling.
  • Nothing is guessed. Matching happens on its own only where the evidence is exact - your product code, your barcode, or the same name. A near miss is left for a person, because a wrong guess here puts stock and money against the wrong product.
  • If the item is genuinely new, create it from the matching screen; it opens the ordinary Add Item form with the supplier's description filled in, and the new item is matched to the line straight away.
  • If the supplier is not in your vendor list, create them from the invoice in one click - the name, TIN, address, phone and email come from URA's record of that taxpayer, not from typing.
  • Purchasing > EFRIS Purchases > Supplier Item Mappings shows everything the POS has learned, with the last cost each supplier charged and how often each mapping has been used. Forgetting one only means that line is matched by hand again; stock already received is not affected.
  • Creating What The Shop Does Not Have Yet "Create the missing items" builds catalogue items straight from the invoice for every line that matched nothing. URA's invoice already carries all of it, so nothing is asked for except the markup.
  • Product code is the supplier's own item code exactly as they sent it - which is what their next invoice will carry, so the line matches itself from then on. Where a supplier sends no code, their description is used.

Release v3.2 — Migrate From a Backup File, Not Just a Live Server

Released 28 August 2026

  • Load The Old System From A .Sql File New: the migration wizard now takes a backup file (.sql) as well as a live database server. Most shops being moved do not hand over a running system - they hand over a dump file from whoever is decommissioning the old one, and until now that could not be used.
  • Choose "A backup file from the old system (.sql)" on the second step and browse to the file. It is loaded into a temporary database of its own, read from there, and that temporary database is removed again when you finish. Nothing you already have is touched at any point, and the temporary database is named in the log both when it is created and when it goes.
  • Speed: a 54 MB backup from a live shop loads in about nine seconds.
  • IMPORTANT SAFEGUARD: a backup file names the database it was taken from. Loaded as it stands, the whole restore would go into a database of that original name - creating it, or overwriting a copy of the old POS still installed on the same machine. Those instructions are stripped as the file is read, so everything lands in the temporary database and nowhere else. This was tested with a file that names another database: the file loaded and that database was not created.
  • Old backups are often not in the same character set as this system. The file is passed through exactly as it is rather than being converted, so accented characters and anything unusual in a product or customer name arrive as they were.
  • Works without the MySQL tools installed. If the machine has them the standard client is used; if not, the file is read directly instead, so a till that only ever had the POS on it can still take a backup file.
  • A wizard closed part-way through a load leaves its temporary database behind. Any left over are cleared automatically the next time the wizard is opened.
  • Checked against the real backup from a live shop: 60 tables loaded, and the products, sales and sale item tables match the database the migration was already proven against exactly - 1,884 products, 95 sales, 731 suppliers, same checksum on every one.
  • Fixed while testing: a product or customer name that runs over two lines inside the backup file could have a line of it dropped, losing that whole record without saying so. Quotes and comments are now followed properly across lines, so only genuine instructions are removed.
  • Note: Application version updated to 3.1 for this release.

Release v3.1 — Move In From the Old WeafPOS, and EFRIS Audit

Released 28 August 2026

  • Migrate From The Old Weafpos New: File > Utilities > Migrate from Old WeafPOS. A five-step wizard that brings a shop's whole history over from the old (Java/MySQL) WeafPOS without anyone touching a database or writing a script. Admin only, and it asks for confirmation before it writes anything.
  • It connects to the old database, lists the schemas it can see so you can pick the right one, then scans it and shows you exactly what it found - how many products, sales, suppliers, purchases and so on - before a single row is written.
  • You choose what comes across. Every section has its own tick box, and sales can be brought from a cut-off date onwards if you do not want years of old history.
  • Safe to run twice. Everything is matched on its natural key - product code, invoice number, username, supplier name - so a second run updates what changed and creates nothing twice. On the test shop the second run created 0 records and left all 94 sales and 1,884 products exactly as they were.
  • One bad section cannot stop the move. If something in the old data defeats a step, that step is reported and skipped and the other twenty carry on. Proven by running with a table deliberately missing: 19 sections completed, the one failure named on its own line in the report.
  • Lenient about small differences between old installations. Table and column names are matched loosely - plural or singular, with or without underscores, any capitalisation - so a shop whose old database drifted slightly still migrates.
  • The old system stored money, quantities and dates as free text ("1,170.00", "6500.0", "04/04/2024 09:27:40"). All of it is read properly, including the real sale timestamp, which the old system kept in a column named "due date".
  • Change given back to the customer now comes across. The old "balance" column is change handed over, not money owed, and it was being read as neither. On the test shop REF002 now correctly reads total 6,500, received 7,000, change 500.
  • Invoice tax now adds up. The old system stored tax on the invoice header that does not match what recalculating the lines produces. The header figure is carried across as it stands and split across the lines in proportion, with the last line taking the remainder, so every migrated invoice reconciles to itself. Invoices that disagreed with their own header: 19 before, 0 after.
  • Departments, units of measure and tax rates are matched to what this system already uses - departments by their URA commodity code, units by their code from the standard unit list - rather than being created again under different names.
  • Old stock is brought in as a single opening balance per product, not as a replay of past movements, so nothing is double counted.
  • EFRIS ERROR LOGS ARE NOT COPIED. The old system wrote a new log row for every retry on the same invoice - one invoice in the test data had fifty near identical rows - which is why that table grows so large on some shops. Instead, the latest response for each invoice is written onto the invoice itself. On the test shop 50 log rows became 28 invoice messages, with 22 repeats dropped.
  • At the end you get a full report - read, created, updated, skipped and the reason for every skip - which can be saved to a file.
  • EFRIS AUDIT (shown when EFRIS is enabled)

Release v2.45 — Receipts That Fit the Paper, and a Cash Drawer That Balances

Released 16 August 2026

  • Cash Drawer IMPORTANT FIX: the "Total Cash Expected" on the End of Day (Z-Out) printout never included the opening float, so it read short by that amount every single day. On this store's own records that was UGX 534,500 on one day and UGX 142,200 on another. The register screen did include it, so the two screens disagreed about the very same shift.
  • Fixed: the Z-Out counted every customer wallet deposit as cash, even one paid by mobile money or bank transfer. Only deposits actually paid in cash now count toward the drawer.
  • Fixed: every expense marked "Deduct from Sales" was assumed to have been paid out of the till. Expenses now record how they were paid, and only cash ones lower the expected drawer figure - so settling a supplier by mobile money no longer leaves the till reading over.
  • Fixed: the register screen, the admin terminal dashboard and the Z-Out each decided for themselves which payment mode counted as "cash" - one matched it by name, another by an internal number. Renaming your Cash payment mode, or adding a second cash-like one, could silently drop sales from some screens but not others. Every payment mode now carries a "Money goes into the cash drawer" setting that you control, and all three screens read that one setting.
  • New: "Record Cash In / Out of Drawer" on the register screen, for money moved for a reason that is not a sale - a float top-up, or cash lifted to the safe or taken to the bank. Until now the only way to account for this was to log it as an expense, which put it in your profit and loss where it does not belong; money moved with no record at all simply left the drawer short with nothing to explain it. In practice this is the most common reason a till "does not balance".
  • Fixed: the Difference figure when closing the register never updated as you typed the counted amount. It was worked out once while the box still read zero, so the cashier watched a large red shortfall that never moved and had to close the register to find out whether the drawer balanced. It now updates on every keystroke and says plainly whether the drawer is Balanced, Over or Short.
  • Fixed: closing the register saved the expected figure worked out when the screen was first opened. Serve more customers, come back and close, and the drawer was checked against a stale number. It is now recalculated at the moment of closing, and expected against counted is shown for confirmation first.
  • Fixed: the figures written into a closed session's history were gathered as "everything since this drawer opened", with no filter by till at all. On a shop with a second terminal, every other register's takings were written into this session's history.
  • Fixed: the Notes box on the Z-Out screen was never saved - whatever was typed there was discarded.
  • New: the End of Day screen now shows the expected cash and its full breakdown on screen. Previously that figure existed only on the printout, so the drawer could not be checked without first printing a receipt.
  • Fixed: the End of Day report ended the day at 23:59:59, so anything rung up in the final second of the day appeared on no report at all.
  • On upgrade: your existing Cash payment mode is marked as a drawer mode automatically, and all expenses already recorded are marked as paid in cash - which is exactly what the old figures already assumed, so no past total changes.
  • Receipts Fixed: on an 80mm printer, long product names printed one word per line - "Supa loaf 1kg" came out as three separate lines - and could spill into the Qty column. The item column was sized in fixed steps that left it almost no room on some printers. Receipt columns now size themselves to the paper, and the item name is always given a fair share of the width.
  • Fixed: the dashed separator lines were a fixed length, so on a wider roll they stopped about two thirds of the way across. They now match the width of the paper.

Release v2.44 — Scanning the Right Item: Short Product Codes No Longer Hijack a Scan

Released 10 August 2026

  • IMPORTANT FIX: on Make a Sale, scanning a barcode could ring up a completely different product. If one item's product code happened to be the beginning of another item's barcode, the till committed the shorter one the instant those characters arrived - it did not wait for the scan to finish. The rest of the barcode then fell into an empty search box and was lost, so the cashier saw the wrong item on the sale.
  • A real example from a live store: scanning "6161105453680" (Sky View Fruity 320ml) added "Riham Minto 50pcs" instead, because that item's product code was "61611054536" - the first eleven digits of the Sky View barcode.
  • The same store was also silently affected on two other products it had not noticed: Riham Choco Sweets scanned in as Riham Minto, East African Organic Honey scanned in as a Table Spoon, and Akashenda Hot Pepper scanned in as a Belt.
  • The till now waits for the scan to finish. When a code is matched but a longer code starts the same way, the match is held for a fraction of a second: another character means the barcode was longer, silence means the scan is over. Codes that nothing else extends are still added instantly, so normal scanning is exactly as fast as before - in a 1,557-code catalogue only four codes take the short pause.
  • Pressing Enter or pasting a code still adds the item immediately, since in both cases the whole code has already arrived.
  • Worth checking: this is usually caused by very short product codes typed in by hand (for example "09", "112" or a truncated barcode). The till now handles them correctly either way, but giving those items their proper full codes removes the cause entirely.
  • Note: Application version updated to 2.9 for this release.

Release v2.43 — One Click, One Invoice: Duplicate Sales Fixed

Released 26 July 2026

  • Fixed: clicking "Confirm & Print" more than once could book the sale several times over, every copy carrying the SAME invoice number. On a till that paused for a moment a cashier could click repeatedly and get eight identical invoices in ten seconds - inflating the day's takings and deducting the stock eight times. Confirm, Hold, Finalize & Pay and Save & Send to EFRIS now refuse a second press while a sale is being saved, and the buttons grey out so it is obvious the till is working.
  • Fixed: invoice numbers are now allocated under a database lock. Two tills confirming at the same instant can no longer both be handed the same number.
  • Fixed on upgrade: any sales already duplicated this way are cleaned up automatically the first time this version starts. One copy of each is kept (the earliest), the over-deducted stock is put back, and the takings correct themselves. Every removed copy is recorded in a DuplicateSaleCleanupLog table so the change is fully auditable. Invoices already sent to EFRIS are never touched, and any sales return is moved onto the copy that is kept.
  • Fixed: the totals at the bottom of Make a Sale could disagree with the lines on screen - most often after retrieving a held invoice. Line totals and the summary are now derived directly from the lines, so they cannot drift apart. The figure the cashier is paid against, the change worked out from it, and the amount saved to the sale are now all one and the same reading, and the basket is frozen while the payment window is open.
  • Fixed: a tender typed in wrongly used to be silently read as zero. It now blocks the sale with a clear message instead of quietly putting the balance on credit.
  • Fixed: retrieving a held invoice now restores its customer and payment mode on screen, and keeps any promotion recorded against the lines.
  • Fixed: the item box no longer stutters or drops characters while items are being added. Searching used to re-scan the whole product list twice on every keystroke - and a barcode scanner sends one keystroke per character. Lookups are now indexed, so scanning stays responsive on a large catalogue.
  • Fixed: pressing Hold with an empty basket no longer files a blank held invoice and burns an invoice number.
  • Note: Application version updated to 2.8 for this release.

Release v2.42 — Customizable Columns on Sales History

Released 20 July 2026

  • New: customizable columns on the Sales History grid, just like Make a Sale, Receive Stock and the Reorder Report. A "âš™ Columns" button next to "Show Details" lets you tick or untick which columns appear, so you can hide the ones you never use and reduce congestion on smaller screens.
  • New: you can also drag the Sales History column headers to reorder them into the arrangement you prefer.
  • Your arrangement is saved to your user account in the database, so it is remembered when you come back - and it is per user, meaning each person signing in on the same till keeps their own layout without affecting anyone else's. It follows you to any machine you sign in on, since it is stored centrally.
  • A "Reset to default" option in the Columns menu restores the original columns and order.
  • The last visible column cannot be hidden, so the grid can never be left completely blank.
  • The two EFRIS columns (EFRIS Status and EFRIS Invoice No) only appear as options when EFRIS integration is switched on. On a store not using EFRIS they stay hidden and are not offered in the menu; if EFRIS is later switched on, they come back with whatever preference you had set.
  • Note: Application version was left unchanged at 2.7 for this release.

Release v2.41 — Removed the Blank Gap at the Bottom of Receipts

Released 20 July 2026

  • Fixed: sales receipts printed a noticeable blank band just above the "powered by Weaf Point of Sale" footer. On a sale with no EFRIS QR code (any non-fiscalised sale) and no thank-you message set, that space was pure wasted paper on every receipt.
  • The footer now only prints the parts that actually have something to show. The thank-you message, its separator line and its spacing are printed only when a message is set; the QR code area only when there is a QR code; and the small gap above the footer only when something was printed above it. On a receipt with neither, the "powered by" footer now follows straight on from the printed-on/printed-by lines.
  • A blank thank-you message no longer prints an empty line. If you clear the receipt message in Preferences the app now prints nothing there, instead of an empty bold line and its margin. Any message you have set is unaffected, and stores that never changed it still get the standard message.
  • The same blank-line trim was applied to customer deposit receipts.
  • Saves a little paper on every single receipt, which adds up on a busy till.
  • Note: Application version was left unchanged at 2.7 for this release.

Release v2.40 — Fixed: Store Details & Preferences Being Erased on Networked Tills

Released 20 July 2026

  • IMPORTANT FIX: on a till sharing the database over a network, the store name, address and receipt logo could be silently erased, after which receipts printed with fallback details ("WEAF") instead of the real store information. General preferences could reset to defaults the same way.
  • The cause: when Preferences opened, it read the store details and settings from the database in the background. If that read failed (a brief network drop, the database busy) or had simply not finished yet, the boxes on screen stayed empty - and pressing Save then wrote those empty boxes straight over the real data in the database. The receipt logo was wiped the same way. Because the save still reported "Settings saved successfully", nothing indicated anything had been lost.
  • Now, Preferences will never save a section it did not successfully read. If the store details or general preferences could not be loaded, they are left exactly as they are in the database, and you get a clear message naming what was skipped and confirming nothing was lost - instead of a false "saved successfully".
  • Pressing Save while the settings are still loading is now safe too: the save waits for the read to finish first, so a quick Save on a slow connection can no longer store a half-filled window.
  • The same protection was added to the discount reasons list, which could previously be emptied in the database if it had not loaded on screen.
  • The same protection was added to the EFRIS General Settings page. A failed read there could previously wipe the middleware URL, business TIN and branch ID when saving, which would stop that till fiscalising.
  • Errors while loading preferences are now recorded in the application log instead of being silently ignored, so a recurring network problem can actually be traced.
  • Note: Application version was left unchanged at 2.7 for this release.

Release v2.39 — Fixed: Discounts Were Missing From EFRIS Tax Invoices

Released 20 July 2026

  • IMPORTANT FIX: discounts given on a sale were not reaching URA on fiscal tax invoices. The app was sending each line already reduced by the discount, but EFRIS ignores a reduced line total and recalculates it as quantity x unit price. The result was that the discount disappeared: the customer's fiscal invoice showed the FULL undiscounted amount, and VAT was charged on that full amount, even though the customer had paid less.
  • Lines are now declared to URA gross (quantity x unit price) with the discount sent alongside, which is the format EFRIS expects. URA then records the full line plus its own "(Discount)" line carrying the negative amount and its share of the tax, so the invoice totals and the VAT both match what the customer actually paid.
  • This affects both ways of fiscalising: "Save & Send to Efris" on Make a Sale, and "Send to Efris" from a saved sale's details. It applies to line discounts, promotion discounts and whole-receipt discounts (a receipt discount is shared across the lines and declared per line).
  • Verified against the live URA sandbox: a sale of 3 x 1,000 with a 450 discount plus 2 x 2,000 now correctly records 6,550 with 999.16 tax, instead of the previous 7,000 with 1,067.80 tax.
  • Note: Application version was left unchanged at 2.7 for this release.

Release v2.38 — EFRIS Fiscal Receipts for Non-VAT Businesses & Item Category on Fiscal Documents

Released 20 July 2026

  • New: businesses that are NOT VAT registered can now fiscalise their sales. Previously the "Save & Send to Efris" button was hidden unless the business was VAT registered, so a non-VAT business could not send anything to URA at all. The button now shows whenever EFRIS is switched on; whether the business is VAT registered only decides WHICH document is raised.
  • New: the app now automatically raises the correct document type. A VAT-registered business sends a fiscal INVOICE (as before); a business that is not VAT registered sends a fiscal RECEIPT. This follows the "VAT Registered" setting under EFRIS Settings, so changing that one setting switches every sale. URA itself enforces this rule and rejects a receipt from a VAT-registered business (and vice versa), so this removes a class of failed submissions.
  • Fiscal receipts are built in the format URA expects for a non-VAT business: no VAT breakdown (URA returns zero tax for these sellers), and discounts declared separately per line rather than folded into the line total. Verified against the live URA sandbox, including a sale with a discounted line.
  • Fixed: discounted lines could be rejected by URA with "Multiply the quantity by the product of the unit price...". Line totals are now sent gross (quantity x unit price) with the discount declared separately, which is what URA validates against.
  • New: each item on a fiscal invoice or receipt now also carries its category - the category code and category name from the item's assigned category (for example code 53131619, name "Cosmetics"). Nothing is invented: if an item has no category, no category is sent.
  • Improved: no placeholder values are ever sent to URA any more. Previously an item missing a product code, name, unit or category had stand-in values substituted (a fixed commodity code, a fixed item code, "Goods", "PCE"). Those fields are now simply omitted when the item genuinely does not have them, so URA is never told a code or unit that is not really the item's.
  • Note: Application version was left unchanged at 2.7 for this release.

Release v2.37 — Scanning & Search Now Tolerate Stray Spaces, Item List Loader, Payment Button Fix

Released 20 July 2026

  • Fixed: scanning or typing a product code sometimes found nothing, even though the item existed - and removing a character or two would suddenly make it appear. The cause was stray spaces stored inside the code (from a barcode scanner, a paste, or from typing a code the way it is printed on the pack, e.g. "6 171105 494946"). Codes are now compared with all spaces ignored on both sides, so the item is found however the code was originally entered.
  • Fixed: scanning an item's Product Code now adds it to the sale straight away. Previously only the Barcode fields were checked on a scan, so scanning a product code merely filtered the dropdown instead of adding the item.
  • Fixed: when a code did not match exactly, pressing Enter could silently add the WRONG item (it fell back to whatever was first in the list). It now matches the correct item.
  • Fixed: searching by name now ignores extra spaces and word order. Looking for "Fanta 330mls" finds an item saved as "Fanta 330mls", and " Lato Milk" finds "Lato Milk". Nearly a quarter of a typical item list has these accidental double spaces, so many items that seemed "missing" will now come up. This applies on Make a Sale, Receive Stock, Adjust Stock, Customer Orders, Quick Pick, Purchase Orders and the Item List.
  • New: product codes and barcodes are now saved without any stray spaces, so the problem cannot be re-introduced when adding or editing an item.
  • New: existing items that already have padded codes are repaired automatically. The background housekeeping job (which already tidied blank barcodes) now also trims codes that were saved with leading or trailing spaces. It runs quietly shortly after startup and every 30 minutes, and is designed never to interrupt whoever is working. Spaces inside a code are deliberately left alone and simply ignored when searching, so two different codes can never be merged by mistake.
  • Fixed: on Make a Sale, the "CONFIRM & PRINT" button could disappear on the payment window - for example after entering 50,000 against a 1,000 sale - leaving no way to complete the sale. The payment window had no height limit, so once the wallet section, receipt discount box or quick-tender buttons appeared it grew taller than the screen and pushed the buttons out of view. The buttons are now fixed to the bottom of the window and the form scrolls if it is too tall, so BACK and CONFIRM & PRINT are always reachable.
  • New: if the CONFIRM button is greyed out, the payment window now explains why - either over-tender is switched off in Preferences (so you cannot enter more than the total due), or the sale is underpaid and needs a real customer to carry the balance. Previously it just went dead with no explanation.
  • New: the Item List now shows a loading spinner while items are being fetched, and has a "Refresh" button. On computers sharing a database over the network the first load can take a moment, and the empty grid used to look as though there were no items at all. If the load fails, the status bar now says so and invites you to click Refresh.
  • Add/Edit Item: scanning (or typing) into the Product Code field now fills in Barcode 1 automatically, so a scanned item is immediately findable at the till. It stops copying as soon as you type your own Barcode 1, and when editing an existing item that already has a barcode, the existing barcode is never overwritten.
  • Note: The application version (2.7) was already set before this release and has been left as-is.

Release v2.36 — Appearance Themes, Collapsible Daily Reminders & Customizable Reorder Report Columns

Released 4 July 2026

  • New: Appearance / Theme customization (Preferences -> Appearance). You can now change the look of the whole app - font family and size, page background colour, default text colour, and the main button colour and text colour. Changes apply live to every open window; leaving any value unset keeps the app's original look.
  • Two theme modes: "Site-wide" applies one shared look for the whole store (saved in the database, so every till matches), or "Per user" lets each login keep its own personal appearance. The defaults match the current design, so nothing changes until you customise it.
  • New: the Daily Reminders panel on the right of the main window can now be collapsed to a thin strip using its arrow button, freeing up screen space, and expanded again when you need it. Your choice is remembered against your user account and restored on every page and after restarting the app, so each user keeps their own preference.
  • New: customizable columns on the Low Stock / Reorder Report, just like Make a Sale and Receive Stock. A "Columns" button lets you show or hide columns (to reduce congestion on smaller screens) and you can drag the column headers to reorder them. Your arrangement is saved per user, with a "Reset to default" option to restore the original columns and order.
  • Licence housekeeping: the silent background licence refresh now only ever uses your own licence's registered email. A leftover hard-coded fallback email address has been removed, so an unusual licence with no stored email is simply skipped instead of contacting the server with placeholder details.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.35 — Customizable Receive Columns & Item Form Tweaks

Released 4 July 2026

  • New: customizable columns on the Receive Stock grid, just like Make a Sale. A "Columns" button lets you show or hide columns, and you can drag the column headers to reorder them. Your arrangement is saved to your user account in the database, so each user keeps their own layout across sessions, and a "Reset to default" option restores the original columns and order.
  • Add/Edit Item form: as you type the Product Name it now also fills in the Description automatically. Once you edit the Description yourself it stops copying, so your own wording is never overwritten. When editing an existing item its saved description is left untouched.
  • Fixed: the quick "Add Category" popup now resizes to fit its contents, so the Cancel and Save Category buttons are always visible (previously they could be cut off on some screens).
  • Note: Application version was intentionally left unchanged for this release.

Release v2.34 — Create Items While Scanning, Inline Categories & Barcode Hygiene

Released 4 July 2026

  • New: if you scan or type an item that does not exist on Make a Sale, Receive Stock or Adjust Stock, the app now offers to create it on the spot. Clicking "Yes" opens the Add Item form pre-filled with what you entered, and your current screen (and everything already added to the sale/voucher) is kept - nothing is lost. After saving, the new item is added straight to the transaction.
  • Smart pre-fill when creating from a scan/search: a long numeric code (6 or more digits) is treated as a barcode and fills the Barcode field; a short numeric code fills the Product Code; text (or letters mixed with digits) fills the Product Name.
  • Pasting a code into the item search now works immediately, just like a barcode scanner - you no longer need to press Enter. An existing item that matches by barcode, product code or name is added instead of prompting to create a duplicate.
  • New: "Add New Category" is now the first option in the Category dropdown on the Add/Edit Item form. Selecting it opens a quick popup to enter the category (name, code and default tax); after saving, the new category is selected automatically without leaving the item form.
  • New background housekeeping: every 30 minutes the app tidies blank barcode fields (both the built-in barcodes and any custom barcode fields), clearing empty/space-only values so they cannot cause the wrong item to be matched when scanning. This runs quietly in the background and is designed never to interrupt or slow down whoever is working.
  • The application version has been updated to 2.6 (shown in the bottom-left of the main window).

Release v2.33 — Vendor Payments, and Completed Report Figures

Released 3 July 2026

  • New: record payments to suppliers. On the Vendor Statement, a "Record Payment" button lets you enter an amount, date, payment mode and note. The payment reduces the vendor's outstanding balance, appears as a credit line on the statement, and updates the "Payments Made" total.
  • Customer Statement now shows the real Wallet balance (deposits less amounts already spent from the wallet) instead of always showing 0.
  • Cash Flow Summary: the "Withdrawals" column now reflects real money paid out to suppliers in the period (previously always 0), so the closing balance is accurate.
  • Stock Adjustment Detail report: the Print button now actually prints a formatted report (date, reference, item, type, quantity, cost effect and user) instead of showing a "being prepared" message. CSV export was already available.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.32 — Personal Column Layout on the Sales Screen

Released 3 July 2026

  • On Make a Sale you can now drag the grid column headers to reorder them, and the order is remembered for your user account - next time you sign in, your layout is restored.
  • New "Columns" button on the sales screen: tick/untick columns to show or hide them (for example hide Item Code or Tax % if you never use them). Your choices are saved per user, so each cashier keeps their own view. A "Reset to default" option restores the original columns and order.
  • The layout is stored against your user account (not a shared setting), so different tills/cashiers do not overwrite each other.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.31 — Application Version Updated to 2.5

Released 3 July 2026

  • The application version has been updated to 2.5 (shown in the bottom-left of the main window and used by the installer).
  • This rolls up the recent improvements: sale-price editing while receiving and on sales, below-cost warnings, the held-draft recall fix, working search buttons, global product search, the store logo on receipts (stored in the database), no-restriction Hold on receiving and sales, and the consistent "Hold" button across transaction screens.

Release v2.30 — Consistent "Hold" Button Across Transaction Screens

Released 3 July 2026

  • The "Save Draft" button on Make a Sale is now labelled "Hold", matching how you hold a receiving voucher.
  • Made the wording consistent everywhere you can park a transaction to finish later: Make a Sale, Receive Stock, Adjust Stock, Purchase Orders and Stocktake all now use a single "Hold" button (previously a mix of "Save Draft", "Save as Draft" and "Hold / Save Draft"). The buttons that open your parked items keep their descriptive names (Held Invoices, Held Vouchers, Held Adjustments).
  • Note: Application version was intentionally left unchanged for this release.

Release v2.29 — Holding a Receiving Voucher Has No Restrictions

Released 3 July 2026

  • Holding/saving a receiving voucher as a draft ("Hold / Save Draft") no longer runs the validation checks. You can now hold a part-finished voucher even if an item's cost is still 0 or details are incomplete, and finish it later.
  • All the checks (cost price greater than 0, cost-vs-selling-price warning, supplier required, production batch/date for Manufacture) still apply as before when you actually Post the voucher ("Save & Post Voucher").
  • Note: Application version was intentionally left unchanged for this release.

Release v2.28 — Store Logo Saved in the Database (Shared-Database Friendly)

Released 3 July 2026

  • The store logo is now stored inside the database itself instead of as a file path. This means the logo shows on receipts from every till on a shared database, not just the computer where it was selected (a file path only exists on that one machine).
  • Choosing a logo now reads the image into the database (limited to 1 MB; under 100 KB recommended for fast printing). Existing behaviour is otherwise unchanged: preview, "Use image as default logo", Remove, and printing on customer receipts, deposit receipts, customer orders and purchase vouchers.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.27 — Working Search Buttons, Global Product Search & Store Logo on Receipts

Released 3 July 2026

  • Search buttons now work everywhere: the magnifier button next to search boxes (Sales History, Customer Order History, Inventory Items, Payment Modes, Expense Categories and the item-picker) now runs the search when clicked, instead of doing nothing.
  • New global product search: the search bar at the top of the main window now works - type a product name or code and press Enter (or click the magnifier) to jump straight to the Inventory Items list filtered to your search.
  • New store logo on receipts: Preferences -> Store Information -> Logo now lets you pick a logo image, see a live preview, and tick "Use image as default logo". When enabled, your logo prints at the top of customer receipts, deposit receipts, customer orders and purchase vouchers. A "Remove" button clears it. The chosen image is copied into the app's data folder so receipts keep working even if the original file is moved.
  • Cleanup: removed more non-working placeholder buttons that did nothing when clicked.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.26 — Sale Price Editing on Receiving & Sales, Held-Draft Fix & Menu Cleanup

Released 3 July 2026

  • Fixed: recalling held receiving drafts. On Receive Stock, pressing "Held Vouchers" (when the grid is empty) now correctly lists your held drafts. Previously the list could come up blank because the draft status was being treated as a search term, and older drafts were hidden by the default one-month date filter.
  • New: Sale Price column on the Receive Stock voucher, so you can see each item's selling price alongside its cost while receiving.
  • New preference (Preferences -> Receiving): "Allow changing product Sale Price while receiving stock". When on, the Sale Price column becomes editable and any change updates the product's master Sale Price for future sales. When off, the column is read-only.
  • New preference (Preferences -> Pricing): "Allow editing the product's master Sale Price from the Make Sales screen". Cashiers can always change a line's price for the current sale; with this on, a price change can also be saved back to the product's default Sale Price (after a confirmation prompt).
  • New: below-cost warnings. Entering a Sale Price lower than the item's cost now warns you both while receiving stock and while editing a price on Make a Sale, so items are not accidentally sold at a loss.
  • Cleanup: removed non-working placeholder buttons that did nothing when clicked - Receive Stock (Discount/Fee/Freight, Print Tags, Show Messages, and the row Edit/Return Item), Sales History (Copy, Reverse, Reports), Customer Order History (Reports), Adjust Stock (Quick Pick Items) and the Import wizard (Help).
  • Note: Application version was intentionally left unchanged for this release.

Release v2.25 — EFRIS Send Fix & Professional Installer (App v2.3)

Released 1 July 2026

  • Application version updated to 2.3 (shown in the main window).
  • Fixed a problem where sending a sale to EFRIS could fail in the installed app with a serialization error ("parameters with null names"). Generating an EFRIS fiscal invoice from Make a Sale, and re-sending from Sales History details, now work reliably in the packaged build.
  • The Windows installer is now a professional step-by-step setup: choose Standalone (one computer), Server (main computer that hosts the shared database), or Client (till that connects over the network), with a short guide screen for your choice.
  • On a Standalone or Server install, the bundled MariaDB database is now installed and configured automatically (service "MariaDB", port 3308) - no manual database setup - and for a Server the Windows Firewall is opened so tills can connect. After install, the in-app Setup Assistant finishes the rest.
  • Note: This release intentionally sets the application version to 2.3 (previous releases left it unchanged).

Release v2.24 — Guided First-Time Setup Wizard

Released 1 July 2026

  • Fresh installs now open a friendly step-by-step setup wizard instead of a technical connection screen - no database knowledge needed.
  • Step 1 asks whether this computer is the MAIN computer (holds the data) or a TILL that connects to the main computer over the network.
  • Main computer: the database settings are pre-filled with the standard values; a "Test connection" button confirms it works, and an option lets other tills connect to this computer.
  • Till: a "Scan the network" button finds the main computer automatically so you just select it and connect.
  • "Preparing your database" screen: creating tables and applying the latest updates now happens automatically behind a simple progress screen (database migrations are handled for you - nothing to type or run), with a clear "Try again" if something needs attention.
  • The wizard then walks through activating your licence and entering your store name and currency, and finishes ready to sign in.
  • This only appears on a brand-new installation; existing setups are unaffected.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.23 — Promotion Sales Report Drill-Down (3 Levels)

Released 1 July 2026

  • The Promotion Sales Report's "Breakdown" is now an expandable tree you can drill into three levels: Promotion -> Item -> individual Sale. Click the arrow on any row to expand it.
  • Level 1 shows each promotion's totals; expand it to see Level 2 (each product sold under that promotion, with its own units, discount and net); expand a product to see Level 3 (each individual sale line, labelled with invoice number and date/time).
  • Added "Expand all" / "Collapse all" buttons, kept every column (Sales, Units, Gross, Discount, Net, Avg Discount) aligned across all levels, and the CSV export now includes all three levels with a Level column.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.22 — Promotion Discounts & Reporting, Purchase Order Email/Barcode & Fixes

Released 1 July 2026

  • Promotions now apply as a visible discount instead of a silent price cut: the original price stays shown and the promotion is recorded as a line discount. The sale screen shows the discount amount, percentage and the promotion name on each affected line, and a promotions/"happy hour" banner at the top lists any promotions active right now (respecting the selected days and time window).
  • Receipts now clearly show promotions: the printed receipt lists each item at its original price with a green "{Promotion}: -amount" line, plus the discount in the totals, so customers can see exactly what they saved.
  • Choose multiple items per promotion: the promotion editor's "Specific item(s)" option now lets you search and tick several products at once (previously only a single item could be chosen), with a live "N selected" count.
  • Promotion tracking & report: every sale line now records which exact promotion was applied. New Reports -> Customers -> "Promotion Sales Report" filters by date and by promotion and shows totals (promo net sales, discount given, units sold on promo, promo share of sales), a promo-vs-regular comparison, a per-promotion breakdown, and CSV export.
  • Purchase Orders - email to supplier: the Purchase Orders list has a new "Email Supplier" button that sends the selected order as a branded email. It uses the supplier's email on file, or prompts for one.
  • Purchase Orders - barcode entry: when building a purchase order you can now scan a barcode (or press Enter in the product search) to add the item to the order; scanning an item already on the order increases its quantity.
  • EFRIS visibility fix: the "Increase Stock with Efris" button on a receiving voucher's details now only appears when EFRIS integration is enabled, matching every other EFRIS button in the app.
  • Stability fixes: fixed crashes that could occur when editing quantities in the Stocktake, Purchase Order, Sales Return and Receive-against-PO grids ("Refresh is not allowed during an AddNew or EditItem transaction"), and a crash when opening Held Quantity Adjustments.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.21 — Loyalty Points & Promotions (Tier 3)

Released 1 July 2026

  • Loyalty Points (Customers -> Loyalty Points): turn on a points program where customers earn points as they spend (configure how much spend = 1 point). Points can be redeemed to wallet credit (configure the value of 1 point and a minimum-points threshold). Points are awarded automatically on each sale to a named customer; redeem from the Loyalty screen.
  • Promotions (Customers -> Promotions): create percent-off or fixed-amount-off promotions scoped to all items, a department or a single item, with optional start/end dates and an optional recurring "happy hour" window (selected days + time range). Turn "Promotions enabled" on and matching promotions are applied automatically as a promo price when items are added at Make a Sale.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.20 — Batch & Expiry Tracking with FEFO (Tier 3)

Released 1 July 2026

  • Products are now tracked in batches (lots) with expiry dates. When receiving stock (Receive Items) you can enter a Batch # and Expiry date per line; goods received against a Purchase Order are also recorded as batches.
  • FEFO consumption: sales automatically draw down the earliest-expiring batch first (First-Expiry-First-Out). Sales returns that restock, and stocktake adjustments, keep the batches in step.
  • Existing stock is handled automatically: on first run, every product with stock on hand gets an "opening" batch (no expiry) so nothing breaks and FEFO has stock to draw from.
  • New Inventory -> "Batch & Expiry Report": see Expiring Soon (within a configurable number of days), Expired stock, all batches, or batches with no expiry set, with remaining quantity and cost value at risk, plus CSV export.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.19 — Stocktake / Cycle Count (Tier 3)

Released 1 July 2026

  • New Inventory -> "Stocktake / Cycle Count": run a guided physical count instead of one-off manual adjustments.
  • Start a count for all items or a single department; the system captures the current on-hand quantities as a snapshot.
  • Enter the counted quantity per item; the screen shows the variance (and its value) live, with a "show variances only" filter and search.
  • Post the stocktake to automatically adjust stock on hand to match the count (writing "Stocktake In/Out" stock movements for the audit trail). Drafts can be saved and resumed; counts can be cancelled before posting.
  • Variance report: view/print the variance report for any stocktake, and see a list of all stocktakes with their variance counts and net value.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.18 — Email Receipts & Statements (Tier 3)

Released 1 July 2026

  • Email a receipt: Open a sale (Sales History -> Show Details) and click "Email Receipt" to send the customer a branded HTML receipt. If the customer has no email on file you're prompted for one.
  • Email customer statements: The Customer Statement screen now has an "Email Statement" button that sends the account ledger (with running balance and closing balance) to the customer's email.
  • Email supplier statements: The Vendor/Supplier Statement screen now has an "Email Statement" button that emails the purchases ledger to the supplier.
  • All emails go through the existing Weaf email service (the same one used for EFRIS activation and password reset). Note: SMS is not included as there is no SMS gateway configured; this delivers the email side of the feature.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.17 — Sales Reports Net of Returns

Released 1 July 2026

  • Daily Sales Summary now reflects real returns: the Returns/Refunds column and Net Sales figure are drawn from actual sales returns (from the Returns feature) instead of always showing zero. Days that only have returns now also appear, and the staff filter also filters returns processed by that user.
  • Report Center dashboard "Today's Sales" is now net of today's returns, and "Today's Profit" is reduced by the margin lost on returns (the cost of restocked goods is credited back).
  • Note: Application version was intentionally left unchanged for this release.

Release v2.16 — Configurable Currency Everywhere + Returns Visibility

Released 1 July 2026

  • Currency now follows Preferences everywhere: the display currency set in Preferences -> Company (Currency Code) is now used across the whole app instead of a hard-coded "UGX". This includes Make a Sale, Receiving, Stock Adjustment, Customer Orders, the Cash Register/Z-Out screens, End of Day report, and all balances, KPIs and reports. Change it once in Preferences and it updates throughout.
  • Sales Returns shown on the Cash Register: The Z-Out / Close Register screen now has a "Sales Returns (Cash)" line so you can see how much cash was refunded during the session; it explains why Expected Cash is lower than Net Sales.
  • Sales Returns on the End of Day report: The EOD report now shows total refunds (and the cash portion) and subtracts cash refunds from the Total Cash Expected.
  • Returns visible in Sales History: A sale that has a return raised against it now shows a "Returned" badge in Sales History. Selecting a posted sale enables the (now blue) "Accept Return" button.
  • Returns History details: In Returns History you can now double-click a return (or use "View Details") to see the returned items, quantities, unit prices, tax, refund method, restock flag, reason and remarks.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.15 — Sales Return Usability Fixes

Released 1 July 2026

  • Sales Return totals: When an invoice is loaded, each line's Return Qty now defaults to the full returnable quantity, so the Subtotal / Tax / Total Refund figures are populated immediately (previously they showed 0 until a quantity was typed). Cashiers can still reduce any line for a partial return.
  • Initiate returns from Sales History: Selecting a posted sale in Sales History now enables the "Accept Return" button, which opens the Sales Return screen with that invoice already loaded. The button stays disabled for held/unposted sales.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.14 — Retail Workflows: Sales Returns, Purchase Orders, Reorder Report & Barcode Labels (Tier 2)

Released 1 July 2026

  • Sales Returns / Refunds: New Point of Sale -> "Sales Return / Refund" screen. Look up an original invoice, choose which items (and how many) are coming back, and refund to cash or to the customer's store-credit wallet. Returned goods can be added back to stock. Over-returns are blocked (you can never return more than was sold, across multiple returns). Cash refunds are deducted from the drawer's expected cash at End of Day, and a "Returns History" view (with CSV export) lists every processed return.
  • Purchase Orders: New Purchasing -> "Purchase Orders". Create an order to a supplier (items, quantities, unit costs, expected date), save it as a draft or issue it, then receive goods against it - including partial deliveries that track outstanding quantities. Each receipt adds stock, writes stock movements, updates the supplier balance and appears in Receiving History. Orders move Draft -> Open -> Partial -> Received automatically, and can be printed or cancelled.
  • Low Stock / Reorder Report: New report (Inventory menu and Reports -> Items) listing every tracked item at or below its reorder level (the product's Stock Pre-warning value), with suggested order quantities and an estimated reorder cost. A red "low stock" alert badge in the top bar shows the count and opens the report in one click. Includes CSV export and print.
  • Barcode & Shelf-Label Printing: New Inventory -> "Print Barcode / Shelf Labels". Pick products, set how many labels of each, choose what to show (name, price, code, store name, border) and the sheet layout, then print. Barcodes render as scannable Code 39 with no special font required.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.13 — Security Hardening, Activity Log & Database Backups

Released 1 July 2026

  • Password Security: All account passwords are now securely hashed instead of being stored as plain text. Existing users keep their current passwords - nothing changes for them; each password is upgraded automatically the first time they log in. Applies to login, password reset, profile changes, manager approval and employee management.
  • Activity / Audit Log: A new activity trail records key events (logins, failed logins, logouts, password changes and employee add/edit/remove). View it under Report Center -> Employees -> "Audit Log / Activity", with date filters and CSV export.
  • Database Backup & Restore: New File -> Utilities -> Backup Database / Restore Database. Backups are saved as .sql files; restore is Admin-only and asks for confirmation before overwriting.
  • Automatic Daily Backups: Preferences -> General -> Backups lets you turn on an automatic daily backup and choose the time of day. If the app is closed at that time, the backup runs the next time it is opened.
  • Default Backup Folder: Preferences -> Backups lets you choose the default folder used for manual and automatic backups.
  • Clearer Reset/Change-Password Validation: Wrong verification codes and mismatched passwords now show a clear pop-up message on the Forgot Password and Change Password screens.
  • Launch Screen: The startup splash now reads "Weaf Point of Sale (POS)".
  • Note: Application version was intentionally left unchanged for this release.

Release v2.12 — Custom Product Fields, Password Reset & User Profiles

Released 1 July 2026

  • Custom Product Fields: A new "Custom Fields" section under Preferences -> Inventory lets you define your own product fields (Text, Number, Date or Barcode). Defined fields appear on every product's Add/Edit form and on the product detail page.
  • Barcode Custom Fields in Scanning: Custom fields of type "Barcode" are now matched when scanning items in Make a Sale, Purchases (Receiving) and Stock Adjustment, in addition to the existing built-in Barcode 1-4 fields.
  • Forgot Password: The login screen's "Forgot your password?" link now works. Enter your username or email and a 6-digit verification code (OTP) is emailed to your registered email address; enter the code and choose a new password to reset it. Codes expire after 15 minutes.
  • Password Reset Email: Sent through the same email service as EFRIS activation, using a new dedicated email template.
  • My Profile: The header Profile option now opens an editable profile window where users can update their full name, phone, email and address, and change their own password (with current-password verification).
  • Help Window: Removed the old "Contact Page" link from the in-app Support window, leaving only the Support Desk link.
  • Preferences Fix: Fixed the Company Preferences window so pages no longer overlap - the Hardware (Cash Drawer) page was previously drawn on top of other pages (e.g. Database) after being viewed once.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.11 — Support Desk Link & Admin Drawer Closing

Released 30 June 2026

  • Support Desk Link: Added the Support Desk (https://supportdesk.weafcompany.com/) to the Websites section of the in-app Support window.
  • Admin Drawer Closing: Fixed the admin register flow so an Admin can actually close a drawer. Previously, when an admin opened a session from End Of Day -> Admin Register Dashboard -> View Session Details, the cash-count box and the Z-OUT / Close Register button were hidden, so the drawer could be viewed but not closed. The close inputs are now shown, with a banner indicating which terminal/cashier's drawer is being closed.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.10 — Discount Fixes: Make-Sales Crash, Mutual Exclusivity, Default-Off & Receipt Printout

Released 30 June 2026

  • Fixed a crash when opening the Make a Sale screen ("Value cannot be null (Parameter 'source')"). The receipt discount field fired its change handler during screen load before the sale items list existed; totals are now null-safe and the handler ignores load-time events.
  • Mutually Exclusive Discounts: A receipt can now use EITHER per-line discounts OR a whole-receipt (cash) discount, not both. When any line already has a discount, the Receipt Discount field is hidden at checkout and a short note explains why.
  • Receipt Discount Off by Default: The whole-receipt discount field now only appears when explicitly enabled in Preferences -> Discounts (the setting now defaults to off). Existing databases can turn it off by unchecking "Allow whole-receipt discount" and saving.
  • Discounts on Receipt Printout: The sale receipt now prints the Trade Discount and/or Cash Discount as their own lines (shown only when greater than zero), with a pre-discount subtotal so the figures reconcile to the grand total. Receipts without discounts print exactly as before.
  • Trade vs Cash discount are now recorded separately on each sale (trade = line discounts, cash = whole-receipt discount).
  • Note: Application version was intentionally left unchanged for this release.

Release v2.9 — Fix: Preferences Save Crash (NULL Discount/Tendering Settings)

Released 30 June 2026

  • Fixed a crash when opening or saving Preferences ("Unable to cast object of type 'System.DBNull' to type 'System.String'"). The new discount/tendering string settings (DefaultDiscountType, TenderRoundingMode, QuickTenderAmounts) were added as nullable columns while the app expects non-null text, so existing databases with NULL values failed to load/save.
  • On startup the app now backfills any NULL values in these columns with their defaults (Percentage, None, and the default quick-tender amounts), repairing existing databases automatically.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.8 — Discounts & Receipt Tendering Preferences with Make-Sales Enforcement

Released 30 June 2026

  • Discount Rules (Preferences -> Discounts): New configuration for enabling line/receipt discounts, default discount type, maximum discount percent, maximum fixed discount amount, manager-approval-above percent, and a "require reason" toggle, plus an editable list of preset Discount Reasons.
  • Discount Enforcement in Make Sales: Line discount inputs are disabled when discounts are turned off; entered discounts are capped to the configured limits; discounts above the threshold require Admin/Manager approval (username + password); a reason can be required and is saved on the sale line.
  • Receipt Tendering (Preferences -> Receipt Tendering): New configuration for default payment mode, require amount tendered, allow over-tender, allow split payments, require a customer for credit sales, cash rounding (None/5/10/50/100, cash-only toggle) and quick-tender button amounts.
  • Tendering Enforcement at Checkout: The payment screen preselects the default payment mode, shows quick-tender buttons, rounds the suggested cash amount, and blocks confirmation on disallowed over-tender, missing amount tendered for cash, or credit to a Walk-In customer when a customer is required.
  • Whole-Receipt (Cash) Discount: An optional receipt discount field at checkout. The discount is converted to a percentage of the sale and applied to each line item (the last line absorbs rounding), so EFRIS - which only supports line-item discounts - receives the discount consistently at the line level. Line taxes are recomputed accordingly.
  • New Manager Approval window and a DiscountReasons table; new GlobalSettings and SaleItems columns are auto-created on startup (no destructive migration).
  • Note: Application version was intentionally left unchanged for this release.

Release v2.7 — Top Menu Cleanup & Implemented "Coming Soon" Actions

Released 30 June 2026

  • Top Menu Cleanup: Removed top-bar menu items that had no page or action wired to them (placeholders). Removed items are documented in pending-menu-items.md for future implementation. Items already wired to an action were kept.
  • Data Export: File -> Utilities -> Export now opens a real Export window that exports Customers, Vendors, Suppliers, Inventory Items, Sales (including EFRIS fields), Expenses or Payment Modes to a CSV file (openable in Excel).
  • Inventory List Toolbar: The Make a Sale, Receive Items and Reports buttons in the inventory item list popup now navigate the main window to the relevant screens instead of showing "coming soon".
  • Customer Recent Sales: The customer detail page now shows the customer's last 10 sales (date, invoice number, total) loaded from the database, replacing the placeholder.
  • Vendor Recent Purchases: The vendor detail page now shows the vendor's last 10 stock-in receipts (date, reference, total), replacing the placeholder.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.6 — Fix: Payment Modes Page Crash (Status Badge Converter)

Released 30 June 2026

  • Fixed a crash when opening the Payment Modes list ("Cannot find resource named 'StatusBgConverter'"). The status-badge value converters were registered in code-behind after the view loaded, so the DataGrid's status column could not resolve them while rendering rows.
  • The converters (active/inactive background, foreground and text) are now public, top-level classes registered in the view's XAML resources at parse time, so they always resolve. Removed the fragile code-behind registration.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.5 — Custom Date Range, EFRIS Sales Import & Sales Export

Released 30 June 2026

  • Custom Date Range (Sales History): Added a "Custom Range" option to the Sales History date filter. Selecting it reveals From/To date pickers and filters sales between the chosen dates (either bound optional); the pickers auto-hide for the preset ranges.
  • Auto-Create Departments on Import: Fixed an import failure ("Column 'DepartmentId' cannot be null") by auto-creating/resolving the department for imported and auto-created products, just like products and categories. Applied to both the sales and inventory imports.
  • New "Sales (Advanced)" Import: Added a separate import type that brings in full sale records with ALL fields - including EFRIS tax details (FDN, verification code, QR code, EFRIS status and message). One row equals one sale. This is distinct from the existing itemized "Sales (with items)" import.
  • Export Existing Sales -> Template: Added an "Export Existing Sales" button on the import file step that exports every existing sale with all fields (including EFRIS) to a CSV. Users can edit this file and re-import it via Sales (Advanced) - a ready-made dynamic template populated with real data.
  • Updated Templates: Added a downloadable Advanced Sales template (all fields + EFRIS) and the Download Template button now offers CSV by default.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.4 — Import Fixes & Itemized Sales Import with Auto-Created Products

Released 30 June 2026

  • CSV Import Fix: Fixed a bug where importing from a CSV file imported 0 records silently. CSV files are now fully loaded (headers and all rows) the same way as Excel files.
  • Browse Filter Fix: The file picker now defaults to showing both CSV and Excel files together (instead of Excel only), so CSV files are visible immediately.
  • Background-Thread Fix: The import engine no longer touches UI controls from the background worker (which previously failed silently). The selected import type and column mapping are now captured up front, eliminating the silent "0 imported" result.
  • Visible Results & Errors: Import now shows a clear pop-up with the number of records imported and skipped, and surfaces any error message instead of failing quietly.
  • Import Logging: The application log now records the full import payload - import type, column headers, every data row, the number of database rows saved, and the reason for each skipped row - for easy troubleshooting.
  • Itemized Sales Import: Historical sales now import with product line items. Each row is a product line (ItemCode/ItemName, Quantity, UnitPrice, TaxRate, LineDiscount) and rows sharing the same InvoiceNumber are grouped into one sale with multiple lines; header totals are summed from the lines. Stock on hand is not changed.
  • Auto-Create Missing Products: If a product on a sales row does not exist, it is created automatically using configuration columns carried in the CSV (ItemMeasureUnit, Department, ItemType) - defaulting the unit of measure to PP-Piece - and reused for later rows in the same file.
  • Updated Templates: The downloadable Sales template now includes the product and configuration columns; Expenses and Purchases templates remain available.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.3 — Historical Data Import: Expenses, Sales & Purchases (Backdated)

Released 30 June 2026

  • Expense Import: Added an "Expenses" type to the Data Import Wizard so users can import historical (backdated) expenses from other systems via CSV/Excel. Expense categories are created automatically when missing, the ExpenseDate is honored for old-year records, and rows with missing/zero amounts are safely skipped.
  • Sales Import (Summary): Added a "Sales (Summary)" type to import historical sales totals from old years for reporting. One sale header per invoice; the original SaleDate is preserved; customers and payment modes are matched by name (falling back to Walk-In / default); the total is derived from SubTotal + Tax - Discount when not supplied. Imported sales do not change current stock.
  • Multi-Line Invoices: Sales rows that share the same InvoiceNumber are consolidated into a single sale header with the SubTotal, Tax, Discount and Total summed across all its lines. Purchases behave the same way, grouped by ReferenceNumber (GRN).
  • Purchases Import (Summary): Added a "Purchases (Summary)" type to import historical purchase totals from old years. One receipt per reference; suppliers matched by name; original PurchaseDate preserved. Imported purchases do not change current stock.
  • Persisted Purchase Total: Added a ManualTotalAmount column on StockInReceipts (auto-created on startup) so header-only (summary) purchases carry a real total into the Purchases Summary and Purchases by Supplier reports without affecting normal line-item receipts.
  • Downloadable Templates: "Download Template" now provides ready-to-fill CSV templates for Expenses, Sales (with a multi-line invoice example) and Purchases.
  • Null-Safe Imports: Hardened number/date parsing and creator-id handling during import to avoid foreign-key and parsing errors.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.2 — POS Product License Lock, Full-Screen Activation Window & Online Activation Fixes

Released 30 June 2026

  • POS Product License Lock: The application is now locked to its product type. On startup it fetches the product catalog from the server (https://weafcompany.com/api/v1/offline-licenses/products), selects the product whose type is "POS" (id is never hard-coded, so it survives catalog changes), and caches it locally (pos_products.json) so the lock keeps working offline.
  • License Product Enforcement: License verification now rejects any otherwise-valid license that was issued for a different product (e.g. Payroll). Matching is by product id first, then by product name, with a conservative name fallback when no catalog has been cached yet.
  • Dynamic Product in Activation: Online trial activation now requests the real POS product (id and name resolved from the catalog) instead of a hard-coded product, and caps the product description at 255 characters to satisfy the server's validation limit.
  • Clearer Activation Errors: When the activation server rejects a request, the exact server returnMessage (or the first field validation error) is now shown to the user instead of a generic "HTTP 4xx" message.
  • Null-Safe License Parsing: Hardened license parsing so a null/non-numeric product or license id in a server-issued license no longer throws during verification.
  • Full-Screen Activation Window: The License Activation window now fills the screen work area (without covering the taskbar). The form scrolls and the "Verify and Activate" button is docked in an always-visible action bar at the bottom.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.2 — Startup Splash, Default Login Helper, License Expiry Banner & MRA EIS (Malawi) Integration

Released 23 June 2026

  • Startup Splash Loader: Added a borderless splash window with an animated spinning ring shown during startup while the app discovers the network server and initializes the database; it closes automatically before the login screen.
  • Default Login Helper: The sign-in screen now shows the default credentials (admin / admin123) with a one-click "Use default login" button that fills and submits them.
  • Hide Default Login Setting: Added Preferences -> Store Info -> Login Screen toggle "Hide default login (admin / admin123) on the login screen" (stored in GlobalSettings.HideDefaultLogins).
  • License Expiry Banner & Countdown: A banner appears at the top of the main window when 30 days or fewer remain on the license, showing a live day countdown and a Renew / Activate link to the activation page. The countdown is re-evaluated periodically while running.
  • Auto Service Termination on Expiry: When the license has expired, the app prompts for activation and otherwise terminates, preventing continued use until renewed/activated.
  • MRA EIS (Malawi) Integration: Added a new tax integration under File -> Integrations -> "MRA EIS (Malawi)", working exactly like EFRIS (6-digit one-time activation code emailed to the store for authorization).
  • Mutually Exclusive Tax Integrations: EFRIS and MRA EIS cannot both be active at once; enabling one while the other is active is blocked with a clear message.
  • Dynamic Activation Branding: The activation authorization dialog title and the activation email (subject, title and heading) now reflect the chosen integration (EFRIS vs MRA EIS) instead of always saying EFRIS.
  • Note: Application version was intentionally left unchanged for this release.

Release v2.1 — Stock Search on Enter & Version Update

Released 12 June 2026

  • Stock Search on Enter: Implemented PreviewKeyDown Enter-interceptor for the editable search textbox in Stock Adjustment (AdjustStockView) and Receive Stock (ReceiveItemsView) to allow selecting/adding items directly on pressing Enter.
  • Walk-In Customer Restrictions: Protected default Walk-In Customer (Id=1) from deletion and ensured safe fallback selection in sales if ID search fails.
  • UOM Default Handling: Reconfigured item creation window to correctly initialize all Unit of Measures from db and default select "PP-Piece".
  • Application Version: Bumped version to 2.1 across WeafPOS.csproj, version.txt, and MainWindow.xaml.

Release v2.0 — Default UOM PP-Piece, Item List Refresh & Validation Checks

Released 12 June 2026

  • Default UOM: Configured default Unit of Measure on the item creation page to be "PP-Piece".
  • Item List Refresh: Added a Refresh button on the item list screen to reload current items dynamically while retaining filters.
  • Price & Margin Checks: Integrated validations to prevent saving zero/negative/0.0 prices, and confirmation warnings for profit margins exceeding 50%.
  • Application Version: Updated version to 2.0.

Release v1.9 — Scan Placeholder Removals, Sales History Shortcut & Login Autofocus

Released 12 June 2026

  • Scan Placeholder Removals: Removed "Scan" placeholders from the item search box across Make Sales, Receive Purchases, and Stock Adjustment views. This avoids search dropdown filtration issues and input bugs.
  • Login Input Autofocus: Configured the UsernameBox to receive focus automatically upon window load.
  • Sales History Shortcut: Added a direct Sales History shortcut in the Make Sales page left sidebar.
  • Sales History Logging: Integrated detailed diagnostic pipeline logging and case-insensitive terminal filters.

Release v1.8 — Search Autocomplete Fixes & Item Layout Enhancements

Released 12 June 2026

  • Search Results Layout: Enhanced the item search result rows in Make Sales, Receive Stock, and New Adjustment to display the item name, product code, available stock (showing both UOMs if applicable), and price horizontally in a single row with larger fonts.
  • Typing Autocomplete Disablement: Disabled native WPF ComboBox text search autocomplete (IsTextSearchEnabled="False") across Make Sales, Receive Stock, Customer Orders, and Stock Adjustments. This prevents the text box from automatically completing and highlighting match suffixes while the user is actively typing.
  • Custom Customer Search & Filtering: Added custom TextChanged search handlers on Make Sales and Customer Order pages to filter the customer dropdown list dynamically by name and phone number as the user types, without native auto-selection interference.
  • Receive Stock Dropdown Guard: Wrapped vendor selection updates in state guards on the Receive Stock page to prevent the vendor dropdown from automatically re-opening after selection.

Release v1.6 — CreatedById FK Fix, Efris Token Correction, Installer Paths & Store TIN Configuration

Released 3 June 2026

  • CreatedById Foreign Key Violations: Resolved database seeding and preference saving failures by verifying user existence in the current database context before applying audit tracking, and bypassing user tracking for system-seeded records.
  • Efris Token Schema Correction: Dropped obsolete and non-null TokenValue column in EfrisTokens table during initialization to prevent errors when saving Efris tokens.
  • Default Installer Path: Updated installer.iss configuration to set default installation directory to C:\ProgramData\WeafPOS.
  • Manual Schema Sync Improvements: Fixed duplicate column exceptions for CreatedById/TerminalName/etc. and corrected MariaDB syntax errors during automated startup schema check.
  • Store TIN Preference & UI Integration: Integrated TIN number in the Store Info section of the preferences window, enabling store settings to store and propagate TIN.
  • Auto-Activation Messages: Ensured returnMessage from the activation server is displayed to the user regardless of the returnCode to improve troubleshooting.

Release v1.2.4 — Stock-In & Stock-Adjustment Schema Reconciliation and EFRIS UI Controls

Released 2 June 2026

  • Database Schema Reconciliation: Added startup schema checks to dynamically create missing columns in StockInReceipts, StockInItems, AdjustStockReceipts, and AdjustStockItems tables.
  • Obsolete Columns Nullability: Configured legacy/obsolete database columns (e.g., ReceiptNumber and CostPrice) to be nullable to prevent insertion exceptions.
  • Cost Data Migration: Added automatic database update routines to migrate existing CostPrice values to UnitPrice in the StockInItems table where UnitPrice was 0.
  • Historical Script Correction: Aligned raw SQL scripts in historical migrations 20260307211000_AddStockInSupport and 20260309100000_AddStockAdjustmentTable to prevent issues on clean installations.
  • EFRIS Dynamic UI Visibility: Configured the Receiving History view to query settings and dynamically collapse/hide the EFRIS Status filter and DataGrid column when EFRIS integration is disabled.

Release v1.2.3 — Database Migration & Auto-Refresh Fix

Released 2 June 2026

  • Safe EfrisStatus Data Type Reconciliation: Implemented a startup schema check in DatabaseService.cs to automatically convert the EfrisStatus column data type from longtext to tinyint(1) across InventoryItems, StockInReceipts, and AdjustStockReceipts, preventing System.InvalidCastException failures.
  • Event-Driven Auto-Refresh: Added an ItemSaved event to InventoryItemDetailsWindow that automatically triggers list updates in InventoryItemListView, ReceiveItemsView, and MainWindow without requiring the window to close.
  • Reconciled Obsolete Columns: Resolved issues with faked migrations by setting safe default values and nullability on obsolete columns like Price, MovementType, and MovementDate, and added missing CreatedById column to StockMovements.

Release v1.2.2 — Production Login Cleanup & Installation Guide

Released 1 June 2026

  • Removed Default Login UI: Removed the Quick Access development buttons (Admin, Manager, Cashier) from the login window for a cleaner, production-ready interface.
  • Modern Sizing: Adjusted the login window height to 490px to perfectly match the streamlined UI layout.
  • Premium Installation Guide: Created a highly-styled, interactive HTML guide (installation_and_license_guide.html) containing system requirements, network setup details, and default credential lookups with click-to-copy badges.
  • Compilation Fix: Fixed the undefined variable build error in LicenseService.cs response body logging.

Release v1.2.1 — Online License Activation Reliability Fix

Released 1 June 2026

  • Pre-Flight Connectivity Check: Added a lightweight HEAD request to weafcompany.com before the main activation API call. If the server is unreachable, the exact TCP/DNS/SSL error is shown immediately instead of a generic "check your internet" message.
  • Increased HTTP Timeout: Raised the activation HTTP timeout from 10 seconds to 30 seconds to accommodate slower or congested connections common in the deployment region.
  • Granular Error Reporting: Changed AutoActivateTrialAsync return type from bool to a (bool Success, string ErrorMessage) tuple, surfacing the exact failure reason (timeout, HTTP status code, server rejection message, signature mismatch) directly in the activation UI status label.
  • Explicit Timeout Handling: Added a dedicated TaskCanceledException catch so a slow server response shows "request timed out (30s)" rather than silently failing.
  • Server Rejection Details: When the server returns a non-00 return code, the returnMessage from the API is now displayed verbatim in the UI so the user knows exactly why the server rejected the request.
  • Trial Auto-Activation: Implemented automatic online trial license registration on first launch, silently querying the generate API and saving the activation license.
  • Verification Option UI: Added an "Online Activation" tab to the LicenseActivationWindow to allow manual clicks for trial activation.
  • Cryptographic Signature Normalization: Added JSON normalization in LicenseService.cs signature verification logic to handle formatting/whitespace differences in license payloads.
  • Startup Background Refresh: Integrated silent background refresh of the license (AutoRefreshLicenseAsync) on startup to dynamically extend active license dates when internet is available.
  • WPF Multi-Csproj Cleanup: Resolved WPF project compilation errors caused by orphaned temporary `*_wpftmp.csproj` project files left by interrupted compilation processes.

Release v1.0.0 — License Activation Form & Dynamic Trial Application

Released 1 June 2026

  • Removed Silent Background Trial Activation: The application now prompts the user to activate immediately on start-up rather than auto-activating with hardcoded details.
  • User Trial Input Form: Redesigned the "Online Activation" tab with text inputs for Email, Full Name, Company, Phone, and Address.
  • Dynamic Activation: Integrated the user-supplied details into the trial generation API query.
  • User Form Input Validation: Validates all inputs on the activation window before submission.

Release v1.0.0 — Inventory Summary Category Export & Daily Sales Summary Report

Released 1 June 2026

  • Category Items Export & PDF Printing: Added the ability to export and print/PDF item listings when double-clicking a category in the Inventory Summary report.
  • Daily Sales Summary Report: Added a "Daily Sales Summary" report in the Report Center breaking down daily totals, payment modes (Cash, Mobile Money, Credit, Cards), discounts, and returns.
  • Staff/User Filtering: Integrated dynamic dropdown filtering to filter daily summary records by specific staff members.
  • Multi-Channel Exports: Implemented Excel (CSV) and professional FlowDocument print/PDF capabilities for daily reports.
  • Outstanding Balance in Customer Sales Ranking: Added Outstanding Balance details to the Customer Sales Ranking report to aid wholesale analysis.
  • Cashier Sales Performance Metrics: Upgraded the Employee Sales report to calculate and display Voids, Discounts Applied, and Returns Processed per employee, with full CSV export support.
  • Report Center Integration: Unified the reports by directly placing Sales by Category, Sales by Customer, and Sales by Cashier under the main "Sales" category in the Report Center.

Release v1.0.0 — Cash & Financial Reports Integration

Released 1 June 2026

  • Cash Flow Summary Report: Implemented a daily cash reconciliation report showing Opening balance, Sales (Inflows), Expenses (Outflows), Withdrawals, and Closing balance.
  • Expense Grouped Report: Added an operating expense analysis report automatically grouping company expenditures by Rent, Transport, Salaries, Utilities, and Others.
  • Income Statement (Profit & Loss): Designed a GAAP-compliant report detailing Revenue, Cost of Sales, Gross Profit, Expenses, and Net Profit with automatic margins.
  • Multi-Channel Exports: Implemented high-fidelity PDF printing/FlowDocument preview and Excel (CSV) exports for all three financial reports.
  • Report Center Navigation: Unified the financial reports under a dedicated "Financials" category section in the main Report Center.

Release v1.0.0 — Purchase Reports Integration

Released 1 June 2026

  • Purchases Summary: Implemented an invoice procurement report showing Supplier, Invoice Reference, Date, and Amount Purchased.
  • Purchases by Supplier: Added vendor purchase analysis calculating Total Bought and dynamically mapping Outstanding Balance per Supplier.
  • Purchase Returns Report: Integrated standard returned vouchers audit logs to track supplier inventory refunds and balance reversals.
  • Dynamic Exports & Print Formats: Integrated high-fidelity FlowDocument print templates and CSV/Excel exports for all three new purchase reports.
  • Report Center Registration: Fully mapped the new purchase views directly under the existing "Purchasing" category tab in the Report Center.

Release v1.0.0 — Profitability Reports Integration

Released 1 June 2026

  • Gross Profit Report: Implemented a comparative daily margin report showing Sales, Cost of Goods Sold (COGS), Gross Profit, and Margin %.
  • Profit by Product: Designed ranking list tracking itemized profitability, detailing product sales, COGS, gross profits, and weighted margins.
  • Profit by Category: Integrated category performance tracker aggregating revenue, COGS, profits, and margins per product department.
  • High-Performance Printing & CSVs: Added professional flow document print layouts and Excel CSV exporters for all three profitability views.
  • Report Center Category Section: Created and mapped a dedicated "Profitability" category sidebar tab to organize the new suite of reports.

Release v1.0.0 — Executive Insights Dashboard

Released 1 June 2026

  • Landing View Dashboard: Created a beautiful, modern, executive landing dashboard for the Report Center displaying high-level key performance indicators (KPIs) in real time.
  • Five Core KPI Metrics: Integrated real-time database calculations for Today's Sales, Today's Profit (revenue minus cost of goods sold), Low Stock Count, Outstanding Customer Debts, and Cash in Drawer (expected cashier register session balance).
  • Top 10 Best-Sellers list: Implemented a live ranked product list tracking Today's Top 10 Best-Selling Products by Profit, displaying quantity sold, revenue generated, profit generated, and margin percentage.
  • Real-Time Interactive Refreshes: Added manual "Refresh Data" functionality with modern animated overlays to retrieve the absolute latest figures instantly.
  • Seamless Sidebar Integration: Configured the Report Center landing area to display the new Dashboard view by default while keeping transitions to detailed reports smooth.

Release v1.0.1 — Sales Drafts, Stock Column, & Best/Worst Sellers Export

Released 1 June 2026

  • Auto-Clearing on Draft Save: Saving an invoice draft now resets and clears the sales interface automatically, allowing cashiers to immediately continue scanning items for other sales.
  • Draft Recall / Retrieval: Enabled the 'Held Invoices' side button to display a visual overlay of all saved drafts, allowing cashiers to retrieve any active draft in one click and resume processing.
  • Available Stock Column: Added a 'Stock' column to the sales creation items grid. This dynamically displays the available system stock (QuantityOnHand) for standard items and outputs '—' for service-based items.
  • Best/Worst Sellers Export: Implemented separate 'Export CSV' buttons next to each grid header in the Best/Worst Sellers report page to export Best Sellers, Worst Sellers, and All Products to separate CSV files.

Release v1.0.2 — Quick Select Department Browser & Sidebar Cleanup

Released 1 June 2026

  • Sidebar Cleanup: Removed non-functional button stubs ('Customer Details' and 'Apply Global Discount') from the left sidebar to present a clean, production-ready interface.
  • 🔍 Quick Select (Department Browser): Added a 'Quick Select' button to open a split-view overlay panel. Cashiers can browse items by department and easily add selected products to the sale grid.
  • Live Department Search: Integrated a text search filter inside the Quick Select panel to narrow down items in the selected department instantly.

Release v1.0.3 — Practice Mode & Message Indicators Removal

Released 1 June 2026

  • Removed Messages (2) and PRACTICE MODE: Cleaned up the global MainWindow bottom status bar, removing the mock "Messages (2)" link and the yellow "PRACTICE MODE" border to establish a clean, production-ready shell interface.

Release v1.0.4 — UI Shell Tweaks & Support Details Window

Released 1 June 2026

  • Moved License under Help: Removed the standalone header link and relocated "License Activation" as a choice under a new dropdown-style ContextMenu on the "Help" link.
  • Removed INPROGRESS Dropdown: Removed the mock "In Progress (0)" ComboBox from the top-right header panel.
  • Contact & Support Dialog: Designed a modern custom popup window displaying full product support details, direct telephone/WhatsApp hyperlinks, email, and support web links.

Release v1.0.5 — Network Service Discovery, Windows Service & Client License Bypass

Released 1 June 2026

  • Network Discovery Service: Added local UDP broadcast service discovery on port 19500 to automatically advertise Server database connection strings.
  • Windows Service Integration: Configured the main executable to run as a standard Windows Service ("WeafPOS") when started with the `--service` command-line argument, hosting the discovery server persistently in the background.
  • Active License Server Visibility: Discovery responder only advertises/responds on the Server machine if its local offline license is active.
  • Till Client Skip Activation: Added auto-discovery sequence on startup to check for active Weaf POS servers on the local network; allows clients (Tills) to choose to connect directly to the discovered server, automatically bypassing local license registration.

Release v1.0.6 — Icon, Quick Pick on Purchases, Connection Caching, & Multi-User Mode Persistence

Released 1 June 2026

  • No Background Console Terminal: Set build output type to WinExe to launch the WPF app directly without displaying a command prompt console window.
  • Persistent Multi-User Mode: Stored server Multi-User configuration in dbconfig.json. The background Windows Service now remains active when the GUI is closed and auto-starts on system boot if configured.
  • Till Client Connection Caching & Failover: Integrated a Connection Failure Troubleshooting dialog on clients with options to Retry, Scan Network (UDP discovery), Configure Manually, or Exit.
  • Server Local Address Check: Added checks for local IP addresses and hostnames to prevent locking out the Server when it is configured with its own local LAN IP.
  • Custom Application Icon: Set `logo.ico` from the `icon` folder as the application executable icon.
  • Quick Pick on Purchases: Added the split-pane Quick Select department browser to the Receive Purchases view, allowing managers to quickly add products by department.

Release v1.0.7 — Obfuscar Reverse Engineering Protection

Released 1 June 2026

  • Reverse Engineering Protection: Integrated Obfuscar NuGet package into the project to obfuscate output binaries on Release builds.
  • Dynamic Reference Mapping: Configured obfuscar.xml with WindowsDesktop reference packs path for .NET 9.0 to successfully resolve XAML and core runtime dependencies.
  • Build & Publish Automation: Automated the obfuscation process as a post-publish MSBuild target that replaces WeafPOS.dll in installer_files and cleans up WeafPOS.pdb symbols.
  • Packaging Documentation: Created a readme.txt explaining the steps for publishing and packing.

Release v1.0.8 — Installer & Distribution Package

Released 1 June 2026

  • Inno Setup Installer Script: Created installer.iss to package the application into a single distributable installer (WeafPOS_Setup_v1.0.exe).
  • .NET 9.0 Bundled: Installer detects if Microsoft .NET Desktop Runtime 9.0 is missing and silently installs it as a mandatory prerequisite before the app.
  • MariaDB Database Bundled: Installer bundles the MariaDB database server and conditionally installs it for Server Host machines if not already present.
  • Client/Server Selection: Added a custom wizard page for the user to select their installation role: 'Client Till' or 'Server Host'.
  • Conditional Database Install: If 'Server Host' is selected and no database is detected, the user is prompted to optionally install MariaDB alongside the application.
  • Publisher Details: Configured official publisher as WEAF COMPANY UGANDA LIMITED with support URL https://weafpos.weafcompany.com.

Release v1.2.0 — Preferences Concurrency & Timezone Copyright Fix

Released 1 June 2026

  • Preferences Concurrency Resolution: Eliminated the database optimistic concurrency exception (DbUpdateConcurrencyException) in PreferencesWindow by cleanly instantiating tracked models and copying scalar values during database sync rather than attaching WPF UI-bound objects directly.
  • Customer Fields Sync Update: Updated Customer sync to properly persist and update all fields, including TIN number, customer type, balance, limits, and status.
  • Dynamic Copyright Year: Reconfigured WeafPOS.csproj to dynamically compute the copyright year based on the build machine's local system timezone.
  • EFRIS Schema & Column Verification: Patched DatabaseService startup routines to robustly verify and append Efris columns if not found, eliminating DB initialization startup failures.

Release v1.7 — EFRIS Invoice Query, HTML Emails & Bug Fixes

Released 7 June 2026

  • EFRIS Invoice Receipt Query: Added a new full-featured 'Invoice Receipt Query' view under the Efris Report menu. Queries the /invoice-receipt-query endpoint with filters for Buyer Name, Invoice No, Start/End Date (DatePicker calendar), Invoice Kind, Is Invalid, Is Refund, and Page Size (All / 10 / 30 / 50 / 99). All unused filters send empty strings. Includes totals bar summing Gross Amount and Tax Amount for the current page, CSV export, and pagination.
  • HTML Activation Emails: Rewrote the EFRIS activation email from plain text to a fully styled dark-theme HTML email matching the Weaf brand (indigo header, slate card, activation code highlighted). Added sender_name field ('Weaf Point of Sale') and 'Weaf Point of Sale Team' footer sign-off.
  • Fix ILLink Trimming Crash: Replaced the anonymous object used in JsonSerializer.Serialize (EmailService) with Dictionary<string, string> to prevent parameter-name stripping by the .NET IL trimmer during publish.
  • Fix taxRate JSON Deserialization: Changed ProductRecord.TaxRate from double to string in EfrisProductsView to match the API returning taxRate as a quoted string (e.g. "0.18"). TaxRateDisplay now parses with InvariantCulture before formatting.
  • EFRIS Products Grid Cleanup: Removed 'Type' column, renamed 'Status' column to 'Tax Rule', and ensured the 'Name' column is fully visible with star width.

Weaf Point of Sale — 120 releases from 1 June 2026 to 10 September 2026. Page updated 10 September 2026.

All categories
Flash Sale
Todays Deal
Messages