MobilePOS Software Docs
Login
## Version 8.88.5 **Release Date:** 2026-05-26 ### Module: Purchase - Create Purchase #### Bug Fixes - **The Purchase Date calendar no longer closes on its own.** Previously, when you clicked to open the date/time picker on the Create Purchase page, it would close automatically after a couple of seconds. It now stays open until you manually close it or pick a date. --- ### Module: POS - Sale Screen #### New Features - **New "Show Total Profit" option added in User Settings.** Go to **User Settings > POS tab** and tick **Show Total Profit** to enable this feature. It is turned off by default. - **Total Profit now shows live on the POS screen.** When the option is turned on, the right-side POS menu displays a **Total Profit** value below the user name. This value updates automatically as products are added, quantities are changed, or prices are adjusted. --- ## Version 8.88.107 **Release Date:** 2026-06-01 ### Module: Business Settings - Dashboard #### New Features - **Dashboard sections can now be hidden from Business Settings.** Go to **Settings > Business Settings > Global Settings > Dashboard** and tick the dashboard items you want to hide. - **All dashboard hide options are off by default.** If no boxes are ticked, the dashboard will continue to show normally. - **Each dashboard option has its own clear label.** Users can choose exactly what to hide, such as Quick Actions, Today at a Glance, Business Analytics, Sales Overview, Sales Charts, Reports, Payment Dues, Orders & Shipments, Stock Alerts, Currency Rate, and module widgets. - **Unticking an option shows that dashboard item again.** This makes it easy to hide or restore dashboard sections whenever needed. --- ### Module: Products - Product Images #### New Features - **Product images can now be assigned automatically by SKU.** Save the image with the same name as the product SKU and the system will connect it to that product. - **Use `.jpeg` images for this feature.** For example, if the product SKU is `0052`, save the image as `0052.jpeg`. - **Place the image in the product image folder for that business.** Once the matching product is added or updated, the image will appear on the product automatically. - **Existing product images are kept safe.** If a product already has its own image, it will not be replaced by mistake. --- ## Version 8.88.106 **Release Date:** 2026-06-01 ### Module: Sale Return #### Improvements - **Sale Return now requires at least one returned item quantity.** If all return quantities are zero, the return will not be saved and the user will be asked to add a return quantity. - **Sale Return activity history now shows payment actions more clearly.** When a payment is added while saving a sale return, the activity will show "Payment Added" instead of "Payment Edited". ### Module: POS - Sale Screen #### Improvements - **POS actions are now available from a right-side menu.** The menu stays closed by default and can be opened from the MENU tab on the right side of the screen. - **The right-side menu can also be opened by swiping left.** This makes it easier to use on touch screens. - **The old POS top menu has been removed.** Its actions now appear inside the right-side menu with icons and clear labels. - **The POS menu is shown in a simple vertical list.** Common actions are easier to find, including Go Back, Open Cash Drawer, Sale Return, Add Expense, Open Cash Skim, Register Details, Close Register, Payment Receiving, Payment to Supplier, Add Production, Calculator, and Full Screen. - **Business location selection is cleaner.** The location icon now appears beside the location dropdown, without an extra heading above it. - **User name and date/time now appear in one row.** This keeps the menu header compact and easier to read. - **Quick Menu buttons inside the right-side menu now wrap to the next line.** They no longer create horizontal scrolling when there are many buttons. - **The right-side menu is now slimmer.** It takes less space on the POS screen. - **Quick Menu selection and Edit Menu option now stay in one row where possible.** This keeps the menu controls easier to use. - **Keyboard Shortcut has been removed from the POS side menu.** The menu now only shows the needed POS actions. - **Add Production now shows with its label in the POS side menu.** Users can identify the action clearly. - **Quick Menu edit mode is clearer.** Edit and delete icons now appear inside each assigned product button, so users can update or remove the correct button. --- ## Version 8.88.105 **Release Date:** 2026-05-31 ### Module: Dashboard - Total Sales Overview #### New Features - **New due cards added to the Total Sales Overview.** Users can now see Suppliers Due, Customer Due, and Barterer Due directly on the dashboard. - **Due amounts include the complete contact balance.** The shown amount includes all-time sales, purchases, returns, payments, ledger discounts, advance deposits, and opening balance. #### Improvements - **Helpful tooltips added to the new due cards.** Users can hover over the info icon to understand what is included in each due amount. - **Dashboard location filter also works with these due cards.** When a location is selected, the due cards show values for that location. --- ### Module: Reports - Stock Value Report #### Fixes - **Stock Value Report now opens without staying stuck on Processing.** The report loads faster and shows the stock value list properly. - **A clear message is shown if the report cannot load.** Users will no longer be left waiting without knowing what happened. #### Improvements - **Report filters now work more completely.** Users can filter the Stock Value Report by location, supplier, category, brand, gender, procurement source, unit, stock quantity options, and price type. - **The report works better from the normal browser link.** Users can open the Stock Value Report as usual and the list will still load. #### New Features - **New Locations tab added to the Stock Value Report.** Users can review stock value grouped by business location, including opening stock, purchases, returns, manufacturing, transfers, adjustments, sales, current stock, and totals. - **Grand totals are shown in the Locations tab.** This helps users compare all locations in one place. --- ### Module: Reports - Stock Quantity Report #### New Features - **New Locations tab added to the Stock Quantity Report.** Users can review stock quantities grouped by business location. - **Each location shows product count, variation count, and quantity totals.** Quantities are shown with their units so mixed stock units remain easy to read. - **Stock values are shown where allowed.** Users with permission can also see purchase value, sale value, and possible profit by location. --- ### Module: Contacts - Add Contact #### Fixes - **Shipping Address map search now works when adding a contact.** Users can type an address, choose a suggestion, press Enter, or move out of the address box, and the map will move to the selected location. - **Address suggestions now show properly inside the Add Contact popup.** This makes it easier to choose the correct address without closing the popup. #### Improvements - **The contact map saves the selected position more reliably.** This helps keep the contact's shipping location accurate. --- ### Module: POS - Sale Screen #### Improvements - **Staff/Agent selection is clearer on the sale screen.** The dropdown now shows "Select Staff/Agent" so users know what to choose. --- ## Version 8.88.103 **Release Date:** 2026-05-27 ### Module: Offline Sync — Per-Location Overlay for pos_settings (Phase 96) #### Bug Fixes - All four entry points in `OfflineSyncController` (`index`, `syncAll`, `_executeSyncSales`, `syncSaleReturns`) previously read `pos_settings` directly from the operator's session. On multi-branch deployments, workstation sync and related flags reflected the business defaults instead of the operator's branch. #### Technical Updates - After the existing raw `pos_settings` decode, resolve the operator's branch from the open `CashRegister` (fallback to `user_settings.default_location`) and overlay the decoded `pos_settings` via `BusinessUtil::getDetails($business_id, $loc_id)` before any logic that depends on it. #### Notes - Unique prefix `_os_` for all overlays in this controller. - Session value preserved when no branch can be resolved. --- ## Version 8.88.102 **Release Date:** 2026-05-26 ### Module: Restaurant — DataController pos_settings Overlay (Phase 95) #### Technical Updates - `Restaurant\DataController::pos_table_dropdown` already overlaid `pos_settings` for the selected branch (Phase 34). No code change required. #### Notes - No session reads remain in this method; overlay logic is correct and matches the current per-location overlay standard. --- ## Version 8.88.101 **Release Date:** 2026-05-26 ### Module: Restaurant — Per-Location Overlay for Kitchen Screen pos_settings (Phase 94) #### Bug Fixes - `Restaurant\KitchenController::index()`, `showOrders()` and `refreshLineOrdersList()` read `pos_settings` directly from the operator's session. On multi-branch deployments the kitchen screen's `show_order_details_kitchen` (line-detail expansion) and `warn_prep_time_out` (prep-time-passed badges) reflected the business defaults instead of the operator's branch. #### Technical Updates - `app/Http/Controllers/Restaurant/KitchenController.php` — in all three entry points, after the existing raw `pos_settings` decode, resolve the operator's branch from the open `CashRegister` (fallback to `user_settings.default_location`) and overlay the decoded `pos_settings` via `BusinessUtil::getDetails($business_id, $loc_id)` before the filter / line-iteration logic that depends on it. #### Notes - Unique prefixes (`_kit_`, `_ko_`, `_kl_`) for each method. - `BusinessUtil` was already injected; no constructor changes required. - Session value preserved when no branch can be resolved. --- ## Version 8.88.100 **Release Date:** 2026-05-26 ### Module: Stock Adjustment — Per-Location Overlay for Create Form pos_settings (Phase 93) #### Bug Fixes - `StockAdjustmentController::create()` already overlaid `common_settings` for the default branch (Phase 50) but still read `pos_settings` directly from the operator's session. On multi-branch deployments, flags like `allow_overselling` and `enable_lot_number` therefore reflected the last-loaded branch session instead of the branch the form was about to open on. #### Technical Updates - `app/Http/Controllers/StockAdjustmentController.php` — in `create()`, reuse the same `$_b_det_sa` already fetched for the `common_settings` overlay (default branch resolved from `user_settings.default_location` → first available branch) and overlay decoded `pos_settings` from it before rendering `stock_adjustment.create`. #### Notes - Falls back to the existing session value when the resolved branch has no `pos_settings`. - Other call sites in this controller (rows endpoints / save endpoints) were already overlaid in Phase 25. --- ## Version 8.88.99 **Release Date:** 2026-05-26 ### Module: Reports — Per-Location Overlay for Activity-Log Datatable (Phase 92) #### Bug Fixes - `ReportController::activityLog()` (AJAX datatable branch) read `pos_settings` directly from the operator's session. The `enable_takeaway_label` rendering in the activity note column therefore reflected business defaults instead of the operator's branch on multi-branch deployments. #### Technical Updates - `app/Http/Controllers/ReportController.php` — inside the AJAX branch of `activityLog()`, after the existing raw `pos_settings` decode, resolve the operator's branch from the open `CashRegister` (fallback to `user_settings.default_location`) and overlay the decoded `pos_settings` via `BusinessUtil::getDetails($business_id, $loc_id)` before it is captured into the `addColumn('note', ...)` closure. #### Notes - Unique prefix `_al_` to avoid collision with other overlays in this controller. - When no branch can be resolved (e.g. owner with no open register and no default), the session-decoded value is preserved. --- ## Version 8.88.98 **Release Date:** 2026-05-26 ### Module: Reports — Per-Location Overlay for Remaining Report Page Renders (Phase 91) #### Bug Fixes - Nine report pages still read `common_settings` from the operator's session, so any `common_settings`-gated columns / labels reflected business defaults instead of the operator's branch. Affected pages: Opening Stock, Product Purchase, Stock Transfer, Stock Consumption, Stock Consumption (Detailed partial), Product Sell, Product Serial, Product Status, and Lot. #### Technical Updates - `app/Http/Controllers/ReportController.php` — in each of the page-render entry points listed above, after the existing `$common_settings = $request->session()->get('business.common_settings');` line, resolve the operator's branch from the open `CashRegister` (fallback to `user_settings.default_location`; for the detailed consumption partial, also honour the explicit `request()->get('location_id')` first) and overlay `common_settings` via `BusinessUtil::getDetails($business_id, $loc_id)` before passing into the view. #### Notes - Unique prefixes per call site (`_osr_`, `_ppr_`, `_str_`, `_csr_`, `_csd_`, `_psr_`, `_pser_`, `_psts_`, `_lot_`) to avoid variable collisions. - When no branch can be resolved (e.g. owner with no open register and no default), the session values are preserved. --- ## Version 8.88.97 **Release Date:** 2026-05-26 ### Module: Reports — Per-Location Overlay for Sale Invoices Report Filter Chrome (Phase 90) #### Bug Fixes - `ReportController::getSaleInvoicesReport()` read `common_settings` and `pos_settings` directly from the operator's session. The `enable_sales_order` / `enable_quotations` checkboxes on the report's filter row and the `common_settings`-gated columns therefore reflected the business defaults instead of the operator's branch on multi-branch deployments. #### Technical Updates - `app/Http/Controllers/ReportController.php` — in the page-render path of the sale-invoices report, after the existing session reads, resolve the operator's branch from the open `CashRegister` (fallback to `user_settings.default_location`) and overlay `common_settings` + decoded `pos_settings` via `BusinessUtil::getDetails($business_id, $loc_id)` before computing `$enable_sales_order` / `$enable_quotations` and rendering `report.sale_invoices_report`. #### Notes - `BusinessUtil` is already injected into this controller; no constructor changes required. - When no branch can be resolved (e.g. owner with no open register and no default), the session values are preserved. --- ## Version 8.88.96 **Release Date:** 2026-05-26 ### Module: POS — Per-Location Overlay for POS Sells Index Filter Chrome (Phase 89) #### Bug Fixes - `SellPosController::index()` (POS sells listing page) read `common_settings` straight from the operator's session. The `common_settings`-gated filter chrome passed to `sale_pos.index` therefore reflected the business defaults instead of the operator's actual branch on multi-branch deployments. #### Technical Updates - `app/Http/Controllers/SellPosController.php` — `index()`: after the existing session read, resolve the operator's branch from the open `CashRegister` (fallback to `user_settings.default_location`) and overlay `common_settings` via `BusinessUtil::getDetails($business_id, $loc_id)` before rendering `sale_pos.index`. #### Notes - `BusinessUtil` is already injected into this controller; no constructor changes required. - When no branch can be resolved (e.g. owner with no open register and no default), the session value is preserved. --- ## Version 8.88.95 **Release Date:** 2026-05-26 ### Module: Stock Transfers — Per-Location Overlay for Stock-Transfer Index (Phase 88) #### Bug Fixes - `StockTransferController::index()` read `common_settings` straight from the operator's session. The `common_settings`-gated chrome in the stock-transfer datatable (e.g. enable_stock_issue_receive labelling) therefore reflected the business defaults instead of the operator's branch on multi-branch deployments. #### Technical Updates - `app/Http/Controllers/StockTransferController.php` — `index()`: after the existing session read, resolve the operator's branch from the open `CashRegister` (fallback to `user_settings.default_location`) and overlay `common_settings` via `BusinessUtil::getDetails($business_id, $loc_id)`. #### Notes - `BusinessUtil` is already injected into this controller; no constructor changes required. - `create()` already overlays both `common_settings` and `pos_settings` from the operator's default branch (Phase 58) — unchanged. - When no branch can be resolved (e.g. owner with no open register and no default), the session value is preserved. --- ## Version 8.88.94 **Release Date:** 2026-05-26 ### Module: Invoice Layouts — Per-Location Overlay for Layout Create / Edit Forms (Phase 87) #### Bug Fixes - `InvoiceLayoutController::create()` and `edit($id)` read `common_settings` straight from the operator's session. The `is_warranty_enabled` toggle in `invoice_layout.create` (and the `common_settings`-gated chrome in `invoice_layout.edit`) therefore reflected the business defaults instead of the operator's branch on multi-branch deployments. #### Technical Updates - `app/Http/Controllers/InvoiceLayoutController.php`: - Constructor now also injects `\App\Utils\BusinessUtil` (added `use App\Utils\BusinessUtil;` and `protected $businessUtil`). - `create()`: resolve the operator's branch from the open `CashRegister` (fallback to `user_settings.default_location`) and overlay `common_settings` via `BusinessUtil::getDetails($business_id, $loc_id)` before computing `$is_warranty_enabled`. - `edit($id)`: same overlay applied before rendering `invoice_layout.edit`. #### Notes - When no branch can be resolved (e.g. owner with no open register and no default), the session value is preserved. - Layout persistence and tax-rate dropdowns are unchanged. --- ## Version 8.88.93 **Release Date:** 2026-05-26 ### Module: Ledger Discounts — Per-Location Overlay for ledger_discount2 / ledger_discount3 Views (Phase 86) #### Bug Fixes - `LedgerDiscountController::index2()` and `index3()` (the per-contact ledger-discount listing pages) read `common_settings` straight from the operator's session. The blade gating (e.g. cheque-posting cues and contact-currency display) therefore reflected the business defaults instead of the operator's actual branch on multi-branch deployments. #### Technical Updates - `app/Http/Controllers/LedgerDiscountController.php`: - `index2()` and `index3()`: after the existing session read, resolve the operator's branch from the open `CashRegister` (fallback to `user_settings.default_location`) and overlay `common_settings` via `BusinessUtil::getDetails($business_id, $loc_id)` before rendering `ledger_discount2.view_all` / `ledger_discount3.view_all`. #### Notes - When no branch can be resolved (e.g. owner with no open register and no default), the session value is preserved. - `BusinessUtil` is already injected into this controller — no constructor changes required. --- ## Version 8.88.92 **Release Date:** 2026-05-26 ### Module: Accounts — Per-Location Overlay for Account Ledger / Balance Filters (Phase 85) #### Bug Fixes - `AccountController::index()` (accounts datatable), `show($id)` (account ledger), and `getAccountBalance($id)` previously read `common_settings` straight from the operator's session. The `cheque_posting_ledger` toggle (cheque-by-posting-date vs cheque-by-clearance-date) used by all three queries therefore reflected the business defaults, even when the operator was actively working on a branch that had overridden this setting. #### Technical Updates - `app/Http/Controllers/AccountController.php`: - Constructor now also injects `\App\Utils\BusinessUtil` (added `use App\Utils\BusinessUtil;` and `protected $businessUtil`). - `index()`, `show($id)`, and `getAccountBalance($id)`: after the session read, resolve the operator's branch from the open `CashRegister` (fallback to `user_settings.default_location`) and overlay `common_settings` via `BusinessUtil::getDetails($business_id, $loc_id)`. #### Notes - When no branch can be resolved (e.g. owner with no open register and no default), the session value is preserved. - Cheque-posting filter behaviour for businesses without branch overrides is unchanged. --- ## Version 8.88.91 **Release Date:** 2026-05-26 ### Module: Sells — Per-Location Overlay for Sells Index Filter Chrome (Phase 84) #### Bug Fixes - `SellController::index()` (sells listing page) initialised `$pos_settings` from the business row and `$common_settings` from the operator's session. On a multi-branch business with branch-level overrides, the `enable_customer_note` toggle in the filter chrome and the `common_settings` passed to `sell.index` reflected the business defaults instead of the operator's actual branch. #### Technical Updates - `app/Http/Controllers/SellController.php` — `index()`: after the existing session/business reads, resolve the operator's branch from the open `CashRegister` (fallback to `user_settings.default_location`) and re-overlay `common_settings` plus the decoded `pos_settings` (and `is_customer_note_enabled`) via `BusinessUtil::getDetails($business_id, $loc_id)`. #### Notes - Original session/business fallback is preserved when no branch can be resolved (e.g. owner with no open register and no default location). - The DataTables AJAX branch already returns earlier, so this overlay only affects the page-render path. --- ## Version 8.88.90 **Release Date:** 2026-05-26 ### Module: Products — Per-Location Overlay for Products Datatable (Phase 83) #### Bug Fixes - `ProductController::index()` AJAX (products datatable) previously read `common_settings` and `pos_settings` directly from the operator's session. On a multi-branch business with branch-level overrides, filters such as `change_search_filtering_sales`, `enable_serial_number`, `enable_imei_number`, and `enable_purchase_order` (used for SKU/serial/IMEI search and the open-PO row class) reflected global defaults instead of the branch the operator was looking at. #### Technical Updates - `app/Http/Controllers/ProductController.php` — `index()` AJAX branch: added per-location overlay that prefers the request's `location_id`, falling back to the operator's open `CashRegister` and then to `user_settings.default_location`. When a branch is resolved, `common_settings` and `pos_settings` are re-fetched via `BusinessUtil::getDetails($business_id, $loc_id)` (with the JSON `pos_settings` decoded). #### Notes - When no branch can be resolved (e.g. business owner with no open register and no default), the original session values are preserved. - All downstream consumers in `index()` (datatable filterColumn closures and `setRowClass`) continue to receive the same variable names, so behaviour is unchanged for single-location businesses. --- ## Version 8.88.89 **Release Date:** 2026-05-26 ### Module: Contacts — Operator-Branch Fallback for Ledger Views (Phase 82) #### Bug Fixes - `ContactController::getLedger()` (contact ledger HTML view) and `downloadLedgerPdf($id)` (combined-formats ledger PDF) already overlaid `common_settings` per branch when the user picked a `location_id` filter (Phases 41 / 42). When the filter was "All locations" (or no location selected), both methods fell straight back to the session value, so a cashier on Branch A viewing an unfiltered ledger could still see the global business defaults instead of Branch A's own `cheque_posting_ledger` override. #### Technical Updates - `app/Http/Controllers/ContactController.php`: - `getLedger()`: added an `else` branch to the Phase 41 overlay that resolves the effective branch from the operator's open `CashRegister` (fallback to `auth()->user()->user_settings['default_location']`) and overlays `common_settings` via `BusinessUtil::getDetails($business_id, $loc_id)`. - `downloadLedgerPdf($id)`: same `else` branch added to the Phase 42 overlay for the combined ledger PDF path. #### Notes - Behaviour for branches without an override is preserved by the session fallback. - Existing per-`location_id` behaviour is unchanged — the new fallback only fires when no location is selected. --- ## Version 8.88.88 **Release Date:** 2026-05-26 ### Module: Contacts — Per-Location Overlay for Index / Store / Show (Phase 81) #### Bug Fixes - `ContactController::index()` (Contacts landing), `store()` (create contact submit), and `show($id)` (contact profile view) were reading `common_settings` (and `pos_settings` for `store()`) directly from the user's session. When the cashier's active branch had its own override, the following did not follow the branch: - Contacts index: `hide_contact_default_currency` (currency dropdown rendering). - Contact store: `default_customer_type`, `default_supplier_type`, `is_tax_inclusive_sales`, `is_tax_inclusive_pos` (auto-fill of `contact_type` and `is_inclusive`). - Contact show: `cheque_posting_ledger` and related ledger flags surfaced on the contact profile. #### Technical Updates - `app/Http/Controllers/ContactController.php`: - `index()`: resolves effective branch from operator's open `CashRegister` (fallback to `auth()->user()->user_settings['default_location']`), overlays `common_settings` via `BusinessUtil::getDetails($business_id, $loc_id)`; session fallback preserved. - `store()`: prefers the first id in `contact_locations` (the branch the contact is being created against), then open register, then user default; overlays both `common_settings` and decoded `pos_settings` from `$business_details`. - `show($id)`: same open-register → default-location resolution; overlays `common_settings` before `contact.show` is rendered. #### Notes - Behaviour for branches without an override is preserved by the session fallback. - `getCustomers()` already overlays per-branch when an explicit `location_id` is provided (Phase 43) and is left unchanged in this phase. --- ## Version 8.88.87 **Release Date:** 2026-05-26 ### Module: Products — Per-Location Overlay for Quick-Edit, View-Modal, and Stock-History Index (Phase 80) #### Bug Fixes - `ProductController::quickEdit()` (renders `product.partials.quick_edit_product`), `view($id)` (renders `product.view-modal`), and `productStockHistory($id)` (renders `product.stock_history`) were reading `common_settings` directly from the user's session. When the cashier's active branch had its own override of common settings flags, the quick-edit modal, the product view modal, and the stock-history landing page rendered with the global business defaults instead of the per-branch overlay. The stock-history AJAX detail branch (Phase 32) already overlaid per branch — the index view now matches that behaviour. #### Technical Updates - `app/Http/Controllers/ProductController.php`: all three methods now resolve the effective branch from the operator's open `CashRegister` (with `auth()->user()->user_settings['default_location']` as fallback), call `BusinessUtil::getDetails($business_id, $effective_loc_id)`, and use `$business_details->common_settings` (session fallback preserved) before rendering each view. #### Notes - Behaviour for branches without an override is preserved by the session fallback. - Remaining ProductController session reads (`index` L116, `store()` L1265) are unreached/already covered by Phase 74 or unused after the variable assignment; will be revisited if specific call-sites are identified. --- ## Version 8.88.86 **Release Date:** 2026-05-26 ### Module: Products — Per-Location Overlay for Variation Form-Part AJAX Endpoints (Phase 79) #### Bug Fixes - Five AJAX endpoints used by the product create / edit / quick-add screens for rendering form partials — `getProductVariationFormPart()`, `getVariationValueRow()`, `getProductVariationRow()`, `getVariationTemplate()`, and `quickAddProduct()` — were reading `common_settings` directly from the user's session. When the cashier's active branch (or default location) had its own override of flags such as `enable_imei_number`, `enable_purchase_order`, or `change_search_filtering_sales`, the variation rows, combo rows, and quick-add form rendered with the global business defaults instead of the per-branch overlay. #### Technical Updates - `app/Http/Controllers/ProductController.php`: all five methods now resolve the effective branch from the operator's open `CashRegister` (with `auth()->user()->user_settings['default_location']` as fallback), call `BusinessUtil::getDetails($business_id, $effective_loc_id)`, and use `$business_details->common_settings` (session fallback preserved) when rendering: - `product.partials.single_product_form_part` - `product.partials.combo_product_form_part` - `product.partials.variable_product_form_part` - `product.partials.combo_product_edit_form_part` - `product.partials.variation_value_row` - `product.partials.product_variation_row` - `product.partials.product_variation_template` - `product.partials.quick_add_product` #### Notes - Behaviour for branches without an override is preserved by the session fallback. - These endpoints are invoked many times per product edit; resolution remains a single `getDetails()` call per request. --- ## Version 8.88.85 **Release Date:** 2026-05-26 ### Module: Expenses — Per-Location Overlay for Expense Receipts (Phase 78) #### Bug Fixes - `ExpenseController::print()` and `ExpenseController::printExpense()` were calling `BusinessUtil::getDetails($business_id)` without a location id and reading `common_settings` from `auth()->user()->business`, so reprinting an expense voucher from a different branch always used the global business defaults instead of the expense's own branch settings. - `ExpenseController::print()` referenced an undefined `$pos_settings` variable when rendering the voucher; the voucher view now receives the per-branch `pos_settings` decoded from `$business_details->pos_settings`. #### Technical Updates - `app/Http/Controllers/ExpenseController.php`: - `print()`: `getDetails($business_id)` → `getDetails($business_id, $expense->location->id ?? null)`; derives `$pos_settings` from per-branch `$business_details->pos_settings`; derives `$common_settings` from `$business_details->common_settings` with session fallback; both passed to `expense.partials.expense_voucher`. - `printExpense()` (thermal print path): `getDetails($business_id)` → `getDetails($business_id, $expense->location->id ?? null)`; derives `$common_settings` from `$business_details->common_settings` with session fallback; passed to `sale_pos.receipts.classic_expense` (or `$receipt_details->design`) view. #### Notes - The receipt blade gates (`enable_urdu_typing`, etc.) were already overlaid in Phase 77; this phase ensures the expense path supplies the per-branch map. --- ## Version 8.88.84 **Release Date:** 2026-05-26 ### Module: Sales / Purchases — Per-Location Overlay for Receipt Templates (Phase 77) #### Bug Fixes - All `sale_pos/receipts/*` browser receipt templates (`classic`, `classic2`, `classic3`, `classic4`, `classic5`, `classic6`, `classic7`, `slim`, `slim3`, `slim4`, `classic2_purchase`, `classic6_purchase`) read the `enable_urdu_typing` flag directly from `session('business.common_settings')`. When reprinting a receipt that belongs to a different branch than the cashier's active location (or when a branch has its own override of this flag), the Noori Nastaleeq Urdu font would not switch correctly to follow the transaction's branch. - `PurchaseController` printable purchase receipt path was calling `BusinessUtil::getDetails($business_id)` without the location id, so `pos_settings` / `common_settings` for the purchase receipt always reflected the global business defaults instead of the purchase's own branch. #### Technical Updates - `app/Http/Controllers/SellPosController.php`: - `receiptContent()`: resolves `$common_settings = is_array($business_details->common_settings ?? null) ? ... : []` at the top of the method (the previous Invoice-Designer‐bypass-only resolution is now reused) and includes it in both `view($layout, ...)` and `view($layout_kot, ...)` compacts. - `submitFbr()` (FBR variant of the receipt renderer): same per-branch `$common_settings` resolution and added to both view compacts. - `app/Http/Controllers/PurchaseController.php` printable purchase path: - `BusinessUtil::getDetails($business_id)` → `getDetails($business_id, $purchase->location->id ?? null)` so `pos_settings` follows the purchase's branch. - Derives `$cs_for_receipt` from the branch-overlaid `$business_details->common_settings` (falls back to session) and passes it as `common_settings` into the `sale_pos.receipts.classic_purchase` (or `$receipt_details->design`) view. - Twelve receipt blades switched the `enable_urdu_typing` gate to a local `$_rc_cs` map that prefers the controller-supplied `$common_settings` and falls back to `session('business.common_settings')`: - `resources/views/sale_pos/receipts/classic.blade.php`, `classic2.blade.php`, `classic3.blade.php`, `classic4.blade.php`, `classic5.blade.php`, `classic6.blade.php`, `classic7.blade.php`, `slim.blade.php`, `slim3.blade.php`, `slim4.blade.php`, `classic2_purchase.blade.php`, `classic6_purchase.blade.php`. #### Notes - Behaviour for branches without an override is preserved by the session fallback. - The Invoice Designer bypass path was simplified to reuse the method-level `$common_settings` instead of recomputing it inside the conditional. --- ## Version 8.88.83 **Release Date:** 2026-05-26 ### Module: Contacts — Per-Location Overlay for Ledger Formats & Lot-Number Label (Phase 76) #### Bug Fixes - Contact ledger PDFs and the ledger purchase-lines partial read several `common_settings` values directly from the session, so a Business Location override of `enable_urdu_typing` or `lot_number_label` was ignored at print/PDF time. The standard ledger (`ledger.blade.php`) and formats 3 / 5 / 6 still loaded the Noori Nastaleeq Urdu font based on the business-level default, and the purchase-lines partial printed the global lot-number label even when the ledger's branch defined its own. #### Technical Updates - `resources/views/contact/ledger.blade.php`, `ledger_format_3.blade.php`, `ledger_format_5.blade.php`, `ledger_format_6.blade.php`: the `@if(... enable_urdu_typing ...)` gate now resolves a local `$_lg_cs` / `$_lf{3,5,6}_cs` map that prefers the controller-supplied `$common_settings` (already overlaid per branch by `ContactController::getLedger()` via `$_b_det_gl`) and falls back to the session map only when not supplied. - `resources/views/contact/partials/ledger_purchase_lines_details.blade.php`: the lot-number label read now uses the controller-supplied `$common_settings` propagated by `@include` from the parent ledger format, falling back to the session map. - No controller changes — `ContactController::getLedger()` was already overlaying `$common_settings` per `location_id` and passing it into every `contact.ledger*` view compact. #### Notes - Behaviour for branches without an override is unchanged because the session fallback is preserved. - `ledger_format_2`, `ledger_format_4`, and `contact_ageing` already preferred the controller map in earlier phases. --- ## Version 8.88.82 **Release Date:** 2026-05-26 ### Module: Sales — Per-Location Overlay for POS Sale Details Modal (Phase 75) #### Bug Fixes - The POS Sale Details modal (`sale_pos/show.blade.php`) read its header configuration (`$hdr_cs`) and the Invoice Discount 2 / Inline Discount 2 / Invoice Tax row gates directly from `session('business.common_settings')`. After a Business Location override these rows did not follow the sale's branch — for example a branch that disables `enable_total_discount2_sale` or `enable_total_tax_sale` could still render those rows when the global business defaults had them on, and vice versa. #### Technical Updates - `resources/views/sale_pos/show.blade.php`: - `$hdr_cs` now prefers the controller-supplied `$common_settings` (already overlaid per branch via `BusinessUtil::getDetails($business_id, $sell->location_id)` in `SellController::show()` — Phase 22), falling back to the session map only when not supplied. - Replaced three direct `session()->get('business.common_settings.enable_total_discount2_sale')` / `enable_total_tax_sale` reads with the resolved `$hdr_cs` map. - `SellController::show()` was already passing `$common_settings` into the view compact; no controller changes required. #### Notes - Behaviour for branches without an override is unchanged because the session fallback is preserved. - The neighbouring partials (`pos_sell_details.blade.php`, etc.) were overlaid in earlier phases; this change closes the last session-only header read on the sale-details modal itself. --- ## Version 8.88.81 **Release Date:** 2026-05-26 ### Module: Products — Per-Location Overlay for Product Forms & Search/Serial Modals (Phase 74) #### Bug Fixes - Product list page, Add Product form, Edit Product form, the POS-style products search modal, and the serial-number detail modal previously read `business.common_settings` (and `business.pos_settings` for the search modal) from the session only. After a Business Location override of common/POS settings, these screens still reflected the global business defaults — for example IMEI fields, IMEI label captions, and the `enable_prices` price-grid gate on Add/Edit Product would not follow the operator's effective branch. #### Technical Updates - `app/Http/Controllers/ProductController.php`: - `index()`: resolves the operator's effective branch (open `\App\CashRegister` → `user_settings.default_location`) and overlays `common_settings` via `BusinessUtil::getDetails($business_id, $effective_loc_id)`; passes `$common_settings` into the `product.index` view compact. - `create()` and `edit($id)`: replaced session-only `$common_settings` reads with the same per-branch overlay (`$_b_det_pc` / `$_b_det_pe`), preserving the existing view compact key. - `getProductsSearch()`: overlays both `common_settings` and `pos_settings` per effective branch and adds them to the `product.partials.products_search_modal` compact. - `getSerialNoDetail()`: overlays `common_settings` per effective branch and adds it to the `product.partials.product_sr_no_detail_modal` compact. - Blades switched to the controller-supplied map with safe session fallback (`isset(...) && ! empty(...) ? ... : session()->get('business.common_settings') ?? []`): - `resources/views/product/index.blade.php` - `resources/views/product/partials/products_search_modal.blade.php` (both `common_settings` and `pos_settings`) - `resources/views/product/partials/variable_product_form_part.blade.php` - `resources/views/product/partials/single_product_form_part.blade.php` - `resources/views/product/partials/edit_single_product_form_part.blade.php` - `resources/views/product/partials/product_sr_no_detail_modal.blade.php` — `enable_imei_number` thead/cell gates and the IMEI label array now read from `$common_settings`. #### Notes - Products are not branch-scoped entities, so the per-location overlay uses the operator's effective branch (open register → user default location) rather than a product's own location. - Remaining session reads in product save/store/duplicate/import paths (e.g. `store()`, `update()`, `quickAdd()`, `quickEdit()`, `validateVaritionSkus()`) are queued for a follow-up phase. --- ## Version 8.88.80 **Release Date:** 2026-05-26 ### Module: Contacts — Per-Location Overlay for Create / Edit Common & POS Settings (Phase 73) #### Bug Fixes - **Contact Create and Edit forms now honour the operator's effective branch when reading `common_settings` and `pos_settings`.** Both blades read these maps straight from the operator's session, so the `default_customer_type` / `default_supplier_type` pre-selects and the `contact_mobile_num_required` field flag could reflect a stale session branch instead of the operator's actual working branch. #### Technical Updates - `ContactController::create()` now resolves the operator's effective branch (open `CashRegister` → `user_settings.default_location`) and overlays `$common_settings` + `$pos_settings` via `BusinessUtil::getDetails($business_id, $effective_loc_id)`. The resolved `$common_settings` continues to drive the `default_customer_type` / `default_supplier_type` pre-fill, and both maps are added to the view compact. - `ContactController::edit($id)` applies the same overlay and forwards `$common_settings` + `$pos_settings` to the view compact. - `contact/create.blade.php` and `contact/edit.blade.php` now prefer the controller-supplied `$common_settings` / `$pos_settings`, with the session values retained as fallbacks for legacy direct-render callers. - Inline `session('business.common_settings')['contact_mobile_num_required']` reads in both blades (mobile input `required` attribute and the hidden `contact_mobile_num_required` input read by JS) switched to `$common_settings['contact_mobile_num_required']` so the validation rule follows the operator's branch. #### Notes - Sibling of Phases 69 / 70 / 71 / 72. The contact form is not tied to a single branch, so the resolver mirrors the standalone-form pattern (open register → user default location) already used elsewhere. --- ## Version 8.88.79 **Release Date:** 2026-05-26 ### Module: Purchase — Per-Location Overlay for Show Details Partial Common Settings (Phase 72) #### Bug Fixes - **Purchase show modal and printable HTML now honour the purchase's branch when reading `common_settings`.** The `purchase/partials/show_details.blade.php` partial had two top-level `$phdr_cs` / `$pcs` reads plus seven inline `session()->get('business.common_settings.*')` lookups for `enable_shipping_details_purchase`, `enable_additional_expense_purchase`, `enable_inline_discount_purchase`, `enable_inline_discount2_purchase`, `enable_inline_tax_purchase`, `enable_serial_number` / `serial_number_label`, `enable_imei_number` / `imei{1,2,3,4}_number_label`, `enable_total_discount2_purchase`, and `enable_total_tax_purchase`. All of these could reflect the operator's last-loaded session branch rather than the purchase's actual branch. #### Technical Updates - `PurchaseController::show($id)` already overlays `$common_settings` per-branch (Phase 27); the partial now consumes that variable via `$phdr_cs` and `$pcs`, falling back to the session. - `PurchaseController::printInvoice()` (printable receipt path) now forwards the already-resolved per-branch `$common_settings` (Phase 30) into the `view('purchase.partials.show_details', compact(…, 'common_settings'))` render so the print HTML honours the same branch overlay as the modal. - `purchase/partials/show_details.blade.php` IMEI / serial-number labels, inline discount/tax column flags, total-discount-2 and total-tax rows now read from `$pcs` (the per-branch overlay) instead of `session()->get('business.common_settings.*')`. #### Notes - Closes the show-details partial. The remaining `session('business.enable_lot_number')` / `session('business.enable_product_expiry')` / `session('business.enable_editing_product_from_purchase')` reads inside this partial are top-level Business columns (not nested under `common_settings`) and will be addressed by a later phase that overlays those scalar flags. --- ## Version 8.88.78 **Release Date:** 2026-05-26 ### Module: Purchase Return — Per-Location Overlay for Index / Show / Create / Edit Common Settings (Phase 71) #### Bug Fixes - **Purchase-Return Index, Show, Create, and Edit screens now honour the return's (or operator's) branch when reading `common_settings`.** Previously these views read `common_settings` straight from the operator's session, so toggles such as `is_tax_inclusive_purchase`, `enable_inline_discount_purchase`, `enable_inline_discount2_purchase`, and `enable_inline_tax_purchase` could reflect a stale session branch instead of the purchase's actual branch. #### Technical Updates - `PurchaseReturnController::index()` overlays `$common_settings` via `BusinessUtil::getDetails($business_id, $effective_loc_id)` (open `CashRegister` → `user_settings.default_location`) and passes it to `purchase_return.index`. - `PurchaseReturnController::show($id)` overlays `$common_settings` using `$purchase->location_id` and passes it to `purchase_return.show`. - `CombinedPurchaseReturnController::create()` now overlays both `$common_settings` and `$pos_settings` via the same open-register / default-location resolution and passes them to `purchase_return.create`. - `CombinedPurchaseReturnController::edit($id)` already overlays per-branch `$common_settings` (Phase 31) — no controller change needed there. - `purchase_return/index.blade.php`, `show.blade.php`, `edit.blade.php` (two reads at L84 and L323), and `create.blade.php` now prefer the controller-supplied `$common_settings`, with the session value retained as a fallback for legacy direct-render callers. #### Notes - Sibling of Phases 69 (sell create/edit) and 70 (sell-return create/edit/add). Closes all session-only `common_settings` reads inside `resources/views/purchase_return/*`. --- ## Version 8.88.77 **Release Date:** 2026-05-26 ### Module: Sell Return — Per-Location Overlay for Create / Edit / Add Common Settings (Phase 70) #### Bug Fixes - **Sell-Return Create, Edit, and Add screens now honour the return's branch when reading `common_settings`.** All three blades read `common_settings` from the operator's session at the top of the page, so toggles driven by that map (custom labels, total-discount toggle, currency hints) could reflect a stale session branch even though the controllers were already loading per-branch `business_details`. #### Technical Updates - `SellReturnController::create()` (Phase 59), `add($id)` (Phase 23) and `edit($id)` already overlay `$common_settings` via `BusinessUtil::getDetails($business_id, $location_id)` (open register / return branch) and pass it to the view. - `sell_return/create.blade.php`, `sell_return/edit.blade.php`, `sell_return/add.blade.php` now prefer the controller-supplied `$common_settings`, with the session value retained as a fallback for legacy direct-render callers. #### Notes - Sibling of Phase 69 (sell.create/edit). Closes the session-only `common_settings` reads inside `resources/views/sell_return/*`. --- ## Version 8.88.76 **Release Date:** 2026-05-26 ### Module: Direct Sell — Per-Location Overlay for Sell Create/Edit Top-Level Common Settings (Phase 69) #### Bug Fixes - **Direct-Sell Create and Edit pages now honour the effective branch's `common_settings`.** Both `sell/create.blade.php` and `sell/edit.blade.php` still read `common_settings` from the operator's session at the top of the page, so toggles driven by that map (currency hints, custom labels, voucher prefixes, regional formatting) could still reflect a stale session branch even though the per-row partial was already corrected (Phase 67). #### Technical Updates - `SellController::create()` derives `$common_settings` from the already-loaded per-branch `$business_details` (resolved via open `CashRegister` → `user_settings.default_location`) and passes it to `sell.create`. - `SellController::edit()` already loads per-branch `$common_settings` (Phase 22) and now passes it to `sell.edit` via the compact added in Phase 67. - `sell/create.blade.php` and `sell/edit.blade.php` prefer the controller-supplied `$common_settings`, with the session value retained as a fallback for legacy callers. #### Notes - Pairs with Phase 67 (sell.product_row row partial) — the direct-sell create/edit flow is now branch-consistent end-to-end. --- ## Version 8.88.75 **Release Date:** 2026-05-26 ### Module: Expense — Per-Location Overlay for Add / Edit / Modal Common Settings (Phase 68) #### Bug Fixes - **Expense Add, Edit, and Add-Expense modal now honour the selected branch's `common_settings`.** All three blades read `common_settings` from the operator's session, so any per-line behaviour driven by that map (currency, voucher, regional toggles) could reflect a different branch than the one the expense is being filed against — especially when the location picker is changed before saving or when editing an expense that belongs to another branch. #### Technical Updates - `ExpenseController::create()` overlays `$common_settings` via `BusinessUtil::getDetails($business_id, $location_id)` (the same `$location_id` already resolved from request input / job-sheet / first location) and passes it to both `expense.add_expense_modal` and `expense.create`. - `ExpenseController::edit()` overlays `$common_settings` via `BusinessUtil::getDetails($business_id, $expense->location_id)` and passes it to `expense.edit`. - `expense/create.blade.php`, `expense/edit.blade.php`, `expense/add_expense_modal.blade.php` prefer the controller-supplied `$common_settings`, with the session value retained as fallback for legacy callers. #### Notes - Sibling of Phase 67 (sell.product_row). Closes the last session-only `common_settings` reads inside `resources/views/expense/`. --- ## Version 8.88.74 **Release Date:** 2026-05-26 ### Module: Direct Sell — Per-Location Overlay for Sell Product Row Common Settings (Phase 67) #### Bug Fixes - **Direct-Sell product row now honours the sell's branch when reading `common_settings`.** `resources/views/sell/product_row.blade.php` read `common_settings` directly from the operator's session, so per-line features driven by that map (foreign-currency exchange UI, sub-unit conversion display, FOC / discount toggles, etc.) could reflect a different branch than the sell itself — especially when an operator switches branch mid-edit or edits a sale belonging to another location. #### Technical Updates - `SellController::edit()` now forwards the already-resolved per-branch `$common_settings` (loaded via `BusinessUtil::getDetails($business_id, $transaction->location_id)` in Phase 22) to the `sell.edit` view, so every `@include('sell.product_row', ...)` inherits it. - `SellPosController::getSellLineRow()` now includes `'common_settings'` in the `compact(...)` passed to `sell.product_row` for ajax-rendered direct-sell rows, sourced from the same per-location `BusinessUtil::getDetails` overlay already computed earlier in the method. - `sell/product_row.blade.php` prefers the controller-supplied `$common_settings`, with the session value retained as a fallback for legacy direct-render callers. #### Notes - Pairs with Phase 22 (sell edit page) and Phase 60 (POS warranty dropdown). Closes the last session-only `common_settings` read in the direct-sell row partial. --- ## Version 8.88.73 **Release Date:** 2026-05-26 ### Module: Payments — Per-Location Overlay for Add/Edit Payment Row Cash Denomination (Phase 66) #### Bug Fixes - **Cash-denomination grid on Add-Payment and Edit-Payment row modals now follows the transaction's branch.** Both `transaction_payment/payment_row.blade.php` and `transaction_payment/edit_payment_row.blade.php` read `pos_settings.enable_cash_denomination_for_payment_methods` from the operator's session, so paying or editing a payment for a transaction belonging to another branch could show the wrong denomination configuration (or hide it entirely). #### Technical Updates - `TransactionPaymentController::addPayment()` and `TransactionPaymentController::edit()` now overlay `pos_settings` via `BusinessUtil::getDetails($business_id, $transaction->location_id)` and pass `$pos_settings` to their respective views (session retained as fallback). - `payment_row.blade.php` and `edit_payment_row.blade.php` prefer the controller-supplied `$pos_settings`, with session-decoded value retained as fallback for legacy direct-render callers. #### Notes - Sibling of Phases 64 and 65 — closes the remaining session-only `pos_settings` reads in `resources/views/transaction_payment/*`. Pairs with Phase 24 on the post-save side. --- ## Version 8.88.72 **Release Date:** 2026-05-26 ### Module: Payments — Per-Location Overlay for Contact-Deposit Modal Cash Denomination (Phase 65) #### Bug Fixes - **Cash-denomination capture inside the Pay-Contact-Deposit modal now follows the operator's working branch.** `transaction_payment/pay_contact_deposit_modal.blade.php` resolved `pos_settings.enable_cash_denomination_for_payment_methods` from the operator's session, so the denomination grid could appear/disappear based on whichever branch the session was last loaded against — not the branch the operator is actively logged into. #### Technical Updates - `TransactionPaymentController::getPayContactDeposit()` now resolves the branch from the operator's open `App\CashRegister` → `user_settings.default_location` → the first business location already used for `payment_types`, then overlays `pos_settings` via `BusinessUtil::getDetails($business_id, $loc_id)` and passes `$pos_settings` to the view (session retained as final fallback). - `pay_contact_deposit_modal.blade.php` prefers the controller-supplied `$pos_settings`, with the session-decoded value retained as a fallback for any legacy direct-render callers. #### Notes - Sibling of Phase 64 (`pay_supplier_due_modal`) — closes the remaining session-only `pos_settings` read inside `resources/views/transaction_payment/*`. --- ## Version 8.88.71 **Release Date:** 2026-05-26 ### Module: Payments — Per-Location Overlay for Supplier-Due Modal Cash Denomination (Phase 64) #### Bug Fixes - **Cash-denomination capture inside the Pay-Contact-Due modal now follows the selected branch.** `transaction_payment/pay_supplier_due_modal.blade.php` read `pos_settings.enable_cash_denomination_for_payment_methods` directly from the operator's session, so the denomination grid could appear/disappear based on whichever branch the session was last loaded against — not the branch the contact-due payment is actually being posted against. #### Technical Updates - `TransactionPaymentController::getPayContactDue()` extends the existing Phase 40 `BusinessUtil::getDetails($business_id, $location->id)` resolution to also derive `$pos_settings` from the same per-branch business detail (with session fallback), and now passes `$pos_settings` to `pay_supplier_due_modal`. - `pay_supplier_due_modal.blade.php` prefers the controller-supplied `$pos_settings`, with the session-decoded value retained as a fallback for any legacy direct-render callers. #### Notes - Pairs with Phase 24 (`postPayContactDue` save side) and Phase 40 (cheque-posting-ledger gate) — same contact-due payment flow, now branch-consistent at both render and post. --- ## Version 8.88.70 **Release Date:** 2026-05-26 ### Module: Cash Register — Per-Location Overlay for Open-Register Form (Phase 63) #### Bug Fixes - **Offline cash-register workstation-sync button now follows the operator's branch.** `cash_register/create.blade.php` read `pos_settings.enable_cash_register_sync_with_workstations` from the session, so the button could appear/disappear based on whichever branch the operator's session was last loaded against — not the branch the new register is actually being opened for. #### Technical Updates - `CashRegisterController::create()` resolves the operator's `user_settings.default_location` (falling back to the first business location in the dropdown) and overlays `pos_settings` via `BusinessUtil::getDetails($business_id, $location_id)` before passing it to the view. Session value retained as final fallback. - `cash_register/create.blade.php` prefers the controller-supplied `$pos_settings`, with the session-decoded value retained as a fallback for any legacy direct-render callers. #### Notes - Pairs with Phase 45 (live register-details modal) on the same per-branch `pos_settings` source. --- ## Version 8.88.69 **Release Date:** 2026-05-26 ### Module: CRM — Per-Location Overlay for Customer Order Request (Phase 62) #### Bug Fixes - **Customer-portal order request now respects the pre-selected branch.** `Crm\OrderRequestController::create()` and `getSellLineRow()` were reading `pos_settings` / `common_settings` from the operator's session and (in the blades) directly from `session('business.common_settings')`, so item-addition rules, discount caps and similar branch-scoped POS gates could differ from the branch the form actually posts to. #### Technical Updates - `create()` overlays `pos_settings` + `common_settings` via `BusinessUtil::getDetails($business_id, $default_location->id)` and now also passes `$common_settings` to `crm::order_request.create`. - `getSellLineRow($variation_id, $location_id, ...)` overlays the same pair from the row's `$location_id` and forwards `$common_settings` to `crm::order_request.product_row`. - `create.blade.php` and `product_row.blade.php` prefer the controller-supplied `$common_settings`, with the session value retained as a fallback for legacy callers. #### Notes - Pairs with the existing per-branch POS overlay family (Phases 60/61) — same `common_settings` source, customer-facing surface this time. --- ## Version 8.88.68 **Release Date:** 2026-05-26 ### Module: POS — Per-Location Overlay for Customer Display Mini-Window (Phase 61) #### Bug Fixes - **Customer-facing mini POS window now shows the branch's footer text.** `SellPosController::miniWindow()` was reading `pos_settings.customer_display_footer_text` from the operator's session, so the pop-out customer display always showed the last-loaded branch's footer regardless of which branch the cashier was actually serving. #### Technical Updates - `miniWindow()` resolves the active branch from the operator's open cash register first, then falls back to `user_settings.default_location`. The branch is fed into `BusinessUtil::getDetails($business_id, $location_id)` to overlay `pos_settings` before reading the footer text. Session value remains the final fallback. - Also hardened the footer read with a null-coalesce so an unset key no longer raises an undefined-index notice. #### Notes - Pairs with Phase 60 (warranty dropdown) and Phases 56/57 (cash-denomination overlays) — same per-branch POS overlay family on `SellPosController`. --- ## Version 8.88.67 **Release Date:** 2026-05-26 ### Module: POS — Per-Location Overlay for Warranty Dropdown (Phase 60) #### Bug Fixes - **POS warranty dropdown now reflects the branch the sell/row belongs to.** The private `__getwarranties()` helper read `common_settings.enable_product_warranty` from the operator's session, so the warranty selector could appear (or stay hidden) based on the operator's last-loaded branch rather than the branch the active sell or product-row punch is for. #### Technical Updates - `App\Http\Controllers\SellPosController::__getwarranties($location_id = null)` now accepts an optional branch id and overlays `common_settings` via `BusinessUtil::getDetails($business_id, $location_id)` before reading the warranty toggle (session fallback retained when no branch is supplied). - `edit($id)` call site forwards `$transaction->location_id`. - `getProductRow($variation_id, $location_id)` call site forwards `$location_id`. - Warranty dropdown items themselves remain business-scoped (`Warranty::forDropdown($business_id)`), so the existing 5-minute cache key is unchanged. #### Notes - Pairs with Phase 55 (Repair POS warranty toggle off `get_pos_screen_view`) and Phase 56 / 57 (cash-denomination overlays on payment rows) — same per-branch flag, different consumer. --- ## Version 8.88.66 **Release Date:** 2026-05-26 ### Module: Sell Return — Per-Location Overlay for Direct-Return Create Form (Phase 59) #### Bug Fixes - **Direct sell-return Create form (`/sell-return/create`) now resolves `common_settings` from the operator's effective POS branch.** Earlier the form already overlaid `$business_details` (and therefore `$pos_settings`) from the open cash register or the operator's default branch, but `$common_settings` was still read from the session — so branch-scoped flags surfaced by that array (e.g. cheque ledger / warranty / generic-name toggles) could come from a different branch than the rest of the form. #### Technical Updates - `App\Http\Controllers\SellReturnController::create()` now derives `$common_settings` from the already-overlaid `$business_details->common_settings` (Phase 41 overlay) with a session fallback, removing the residual `request()->session()->get('business.common_settings')` read just before the view compact. #### Notes - Pairs with Phase 41 (which introduced the `$business_details` overlay on this same method) and Phase 49 (which closed the equivalent leak on the ledger-format / ageing footer Blades). --- ## Version 8.88.65 **Release Date:** 2026-05-26 ### Module: Stock Transfer — Per-Location Overlay for Create Form (Phase 58) #### Bug Fixes - **Stock Transfer Create form now resolves branch-scoped flags from the form's default branch.** Previously `common_settings.enable_stock_issue_receive` (which gates the Categories dropdown and the Stock Issue / Receive toggle) and `pos_settings.allow_overselling` (which gates the overselling field on the line rows) were read from the operator's session, so they reflected the branch the operator's session was last loaded against rather than the branch the transfer is being created at. #### Technical Updates - `App\Http\Controllers\StockTransferController::create()` resolves the default branch from `user_settings.default_location` (falling back to the first available branch) and overlays both `pos_settings` and `common_settings` via `BusinessUtil::getDetails($business_id, $default_location)` before the Category dropdown is built and before either array is compacted into the view. #### Notes - Pairs with Phase 50 (base stock-adjustment create) and Phase 52 (Warehouse stock-transfer create) which closed the same default-branch leak on adjacent forms. --- ## Version 8.88.64 **Release Date:** 2026-05-26 ### Module: HMS (Hotel) — Per-Location Overlay for Booking Payment Rows (Phase 57) #### Bug Fixes - **HMS booking Create / Edit forms now resolve cash-denomination & related `pos_settings` from the booking's branch.** Previously the embedded payment row partial read these branch-scoped settings from the operator's session, so the denominations table belonged to whichever branch the operator's session was last loaded against — not the branch the booking belongs to. #### Technical Updates - `Modules\Hms\Http\Controllers\HmsBookingController::edit()` overlays `pos_settings` via `$this->businessUtil->getDetails($business_id, $transaction->location_id)`. - `HmsBookingController::create()` overlays `pos_settings` via the operator's `user_settings.default_location` (mirrors the Phase 50 / 52 default-branch pattern). - [modules/Hms/Resources/views/partials/payment_row_form.blade.php](modules/Hms/Resources/views/partials/payment_row_form.blade.php#L51) now consumes the controller-supplied `$pos_settings`, falling back to the session-decoded value when this partial is included from elsewhere. #### Notes - First HMS-module surface in the per-location overlay programme; pairs with Phase 56 (HRM payroll edit row) which closed the same cash-denomination leak in payroll. --- ## Version 8.88.63 **Release Date:** 2026-05-26 ### Module: HRM (Essentials) — Per-Location Overlay for Payroll Payment Edit Row (Phase 56) #### Bug Fixes - **Editing a payroll payment now resolves cash-denomination settings from the payment's own transaction branch.** Previously the row read `pos_settings.enable_cash_denomination_on`, `enable_cash_denomination_for_payment_methods`, and `cash_denominations` from the operator's session, so editing a payment that belonged to Branch B while the session was last loaded against Branch A showed Branch A's denominations instead of Branch B's. #### Technical Updates - `Modules\Essentials\Http\Controllers\PayrollController::getEditPayment()` (`edit_payment_row` AJAX handler) now overlays `pos_settings` via `BusinessUtil::getDetails($business_id, $transaction->location_id)` and passes the result to the view. - [modules/Essentials/Resources/views/payroll/edit_payment_row.blade.php](modules/Essentials/Resources/views/payroll/edit_payment_row.blade.php#L79) now consumes the controller-supplied `$pos_settings`, falling back to the session-decoded value when not provided. #### Notes - First Essentials-module surface in the per-location overlay programme. --- ## Version 8.88.62 **Release Date:** 2026-05-26 ### Module: Repair / POS — Per-Location Overlay for `enable_product_warranty` on POS Screen (Phase 55) #### Bug Fixes - **Repair POS sub-screen now resolves `enable_product_warranty` from the active POS branch.** When a user with multiple branches opened the POS in Branch B but their session had last loaded Branch A, the warranty dropdown was shown/hidden according to Branch A's setting — even though every job sheet created on that POS would be tagged to Branch B. #### Technical Updates - `SellPosController::create()` and `edit()` now thread `location_id` (default POS branch / transaction branch respectively) into the `get_pos_screen_view` module-data call. - `Modules\Repair\Http\Controllers\DataController::get_pos_screen_view()` now overlays `common_settings` for the supplied `$params['location_id']` via `BusinessUtil::getDetails()`. Three-state resolution: per-location value when present (explicit `0` correctly disables warranty), otherwise the operator's session value as fallback. #### Notes - First Repair-module surface in the per-location overlay programme. - The same `location_id` channel is now available for any other module hooking `get_pos_screen_view`. --- ## Version 8.88.61 **Release Date:** 2026-05-26 ### Module: Accounting — Per-Location Overlay for Chart-of-Accounts Ledger (Phase 54) #### Bug Fixes - **Chart-of-Accounts ledger now respects the selected branch's cheque-posting rule.** When the user picks a single branch in the ledger location filter, the per-row balance, brought-forward, and `operation_date` callbacks now use that branch's `cheque_posting_ledger` setting (driven by `common_settings`) instead of the operator's session-loaded branch. #### Technical Updates - `Modules\Accounting\Http\Controllers\CoaController::ledger()` overlays `common_settings` via `BusinessUtil::getDetails($business_id, $location_id)` immediately after reading the `location_id` filter, gated on `$location_id != 'all'`. Session value is retained for the "All locations" view (operator's session-loaded branch acts as the default) and any non-ajax render. #### Notes - First Accounting-module surface in the per-location overlay programme; pairs with the existing contact/customer/supplier ledger overlays (Phases 36, 41, 46). --- ## Version 8.88.60 **Release Date:** 2026-05-26 ### Module: Truckmate — Per-Location Overlay for Create Invoice Form (Phase 53) #### Bug Fixes - **The Truckmate "Create Invoice" form now resolves `common_settings` and `pos_settings` from the branch the form pre-selects** (first business location returned by the dropdown), instead of inheriting whichever branch the operator's session was last loaded against. This previously caused branch-scoped flags consumed by the create view (e.g. cheque-posting filters, custom branch labels) to belong to the wrong branch on a multi-branch login. #### Technical Updates - `Modules\Truckmate\Http\Controllers\TruckmateController::create()` now overlays `common_settings` + `pos_settings` via `$this->businessUtil->getDetails($business_id, $default_location->id)`, falling back to the existing business-level defaults / session values when no default location is in scope. #### Notes - First Truckmate-module surface in the per-location overlay programme. - The matching `$common_settings` lookups in `show()` and `showDriverInvoice()` are dead (not added to `compact()` and never used by their views) and were intentionally left untouched. --- ## Version 8.88.59 **Release Date:** 2026-05-26 ### Module: Warehouse — Per-Location Overlay for Stock Transfer Create Form (Phase 52) #### Bug Fixes - **The "Create Stock Transfer" form now resolves `allow_overselling` and other branch-scoped pos/common settings from the operator's default source branch instead of the last-loaded branch session.** Previously, opening the create form for a transfer from Branch B while the operator's session was last loaded against Branch A applied Branch A's overselling rule to the new transfer until the page was reloaded. #### Technical Updates - `Modules\Warehouse\Http\Controllers\StockTransferController::create()` now resolves the form's pre-selected source branch (from `auth()->user()->user_settings['default_location']`) and overlays `pos_settings` + `common_settings` via `BusinessUtil::getDetails($business_id, $location_id)`. Falls back to session values when no default location is set. Mirrors the per-location overlay already in place on `edit()` since Phase 35. #### Notes - Pairs with Phase 35 (stock-transfer edit overlay) and Phase 50 (stock-adjustment create overlay) so the matching create + edit forms behave consistently per branch. --- ## Version 8.88.58 **Release Date:** 2026-05-26 ### Module: CRM — Per-Location Overlay for Customer Sell List Takeaway Labels (Phase 51) #### Bug Fixes - **Takeaway / Takeaway 2 / Takeaway 3 labels on the CRM customer-portal sell list now reflect the branch each sale was made at.** Previously the list rendered all three custom labels from the operator's session `pos_settings`, so a sale made at Branch B was decorated with Branch A's relabel whenever the operator's session had last loaded Branch A. #### Technical Updates - `Modules\Crm\Http\Controllers\SellController::getSellList()` row callback now overlays `pos_settings` per row using `BusinessUtil::getDetails($business_id, $row->location_id)` with a static per-request cache (one lookup per distinct branch in the result set), falling back to the session-decoded pos_settings when a row has no `location_id`. #### Notes - Pairs with the long-running per-location overlay programme (Phases 19–50); this is the first CRM-module surface in that programme. --- ## Version 8.88.57 **Release Date:** 2026-05-26 ### Module: Stock Adjustment — Per-Location Overlay for Default Adjustment Type (Phase 50) #### Bug Fixes - **Default "Adjustment Type" on the Add Stock Adjustment form now follows the branch the form opens on.** The create form pre-selected `default_stock_adjustment_type` (Stock Adjustment vs. Stock Take) from the operator's session, so a user whose session was last loaded against a different branch would see that branch's default — not the default of the branch the form was about to write against. #### Technical Updates - `StockAdjustmentController::create()` now resolves the branch the Blade will pre-select (user setting `default_location` → first available branch), overlays `common_settings` for it via `BusinessUtil::getDetails($business_id, $location_id)`, and passes the result to the view. - [resources/views/stock_adjustment/create.blade.php](resources/views/stock_adjustment/create.blade.php) now reads `default_stock_adjustment_type` from the overlaid `$common_settings` array (session fallback retained for safety). #### Notes - The dropdown still allows the operator to switch branch or adjustment type before submit; this fix only corrects the initial pre-selection. --- ## Version 8.88.56 **Release Date:** 2026-05-26 ### Module: Contacts / Ledger — Per-Location Overlay for Ledger & Ageing Footer Text (Phase 49) #### Bug Fixes - **Customer / supplier ledger footer text now follows the branch the ledger is being printed for.** The format-2 contact ledger (`contact.ledger_format_2`) and the matching contact ageing report (`contact.contact_ageing`) read `cutomer_ledger_format2_footer_text` and `supplier_ledger_format2_footer_text` directly from the operator's session, bypassing the per-location overlay the controller had already applied (Phase 41). As a result, printing a ledger for one branch displayed the footer copy of whichever branch the operator last loaded — not the branch in the ledger header. #### Technical Updates - Both Blade templates now read the footer text from the `$common_settings` array passed in by `ContactController::printLedger()` / `viewLedger()` / `getLedger()` (which Phase 41 already overlays via `BusinessUtil::getDetails($business_id, $location_id)`), falling back to the session value when no overlay is in scope. No controller changes required. #### Notes - Pairs with Phase 41 (ledger query overlay) and Phase 46 (`getLedgerDetails` cheque-posting overlay). Together these ensure the ledger view, query and footer all reflect the same branch. --- ## Version 8.88.55 **Release Date:** 2026-05-26 ### Module: Contacts / Ledger — Per-Location Overlay for Contact Due Calculation (Phase 48) #### Bug Fixes - **`Util::getContactDue()` now honours the originating transaction's branch when resolving `cheque_posting_ledger`.** The helper read `common_settings.cheque_posting_ledger` straight from the operator's session, so the cheque-clearance filter applied to `transaction_payments` (and therefore the contact's outstanding due / previous-balance shown on invoices, receipt PDFs and POS payment screens) reflected whichever branch the operator last loaded — not the branch that owns the transaction. A sale issued from a branch configured to recognise cheques on `posting_date` could be invoiced with a due calculated under another branch's `clearance_date` policy (or vice versa). - The `{cumulative_due_amount}` invoice-template placeholder, `getReceiptDetails()` previous-balance block (two call sites) and the `customer_due` figure shown on the POS edit-payment / invoice-edit screens were all affected by the same bug. #### Technical Updates - Added a fourth optional `$location_id` parameter to `App\Utils\Util::getContactDue($contact_id, $business_id = null, $transaction_id = null, $location_id = null)` and applied the standard per-location overlay using `(new BusinessUtil())->getDetails($business_id, $location_id)` with session fallback (works regardless of whether the caller passes `$business_id` thanks to a `contact->business_id` fallback). - Forwarded `$transaction->location_id` from every known caller that has a transaction in scope: `Util::replaceTags()` (`{cumulative_due_amount}`), `TransactionUtil::getReceiptDetails()` (two call sites for `prev_bal` / `all_due`), `SellPosController::edit()` and `SellController::editPaymentForm()` (customer-due display). - Other callers (e.g. `ContactController::getContactDue()`) operate at the contact level with no single branch in scope and continue to fall back to the session value — behaviour unchanged. #### Notes - Same `cheque_posting_ledger` setting that Phase 46 fixed inside `TransactionUtil::getLedgerDetails()` for the contact-ledger view. Phase 48 closes the matching leak on the invoice / receipt / POS surfaces. --- ## Version 8.88.54 **Release Date:** 2026-05-26 ### Module: POS / Products — Per-Location Serial-Number Overlay in Product Search (Phase 47) #### Bug Fixes - **`ProductUtil::filterProduct()` and `ProductUtil::quickFindProduct()` now honour the search branch's `common_settings`.** Both helpers re-read `enable_serial_number` (and `bulk_add_serial_number_pos`) from the operator's session, so the SQL plan and the IMEI/serial join applied during POS product lookup reflected whichever branch the operator last loaded — not the branch passed in `$location_id`. As a result, switching the POS to another branch (or running an API/lookup against a different branch) could omit or wrongly include the `purchase_lines` join used to resolve serial numbers. Both methods now overlay using the branch's settings. #### Technical Updates - Added a per-location overlay at the top of `App\Utils\ProductUtil::filterProduct(..., $location_id, ...)` and `App\Utils\ProductUtil::quickFindProduct(..., $location_id, ...)` using `(new BusinessUtil())->getDetails($business_id, $location_id)` with session fallback. - Both methods are called by the POS product search, barcode lookup, sub-product suggest, repair / manufacturing / kitchen lookups and several module endpoints. All current callers already pass `$location_id`, so the overlay activates automatically wherever a branch is in scope — no caller changes required. - No schema changes; reuses the per-request memoised overlay shipped in earlier phases. #### Notes - When called without `$location_id` (rare), behaviour is unchanged — falls back to the operator's session common_settings. - Complements the controller-side overlays in earlier POS phases by closing the util-level read that bypassed them. --- ## Version 8.88.53 **Release Date:** 2026-05-26 ### Module: Contacts / Ledger — Per-Location `cheque_posting_ledger` Overlay (Phase 46) #### Bug Fixes - **`TransactionUtil::getLedgerDetails()` now honours the branch's `common_settings` when a `location_id` filter is supplied.** Previously the util re-read the operator's session `business.common_settings`, so the `cheque_posting_ledger` mode (`posting_date` vs `clearance_date` vs default) used to filter cheque payments came from whichever branch the operator had last loaded — not the branch the ledger was being run for. This affected the contact ledger view, ledger PDF/print, ageing reports and the `LedgerExport` excel download. Branch-scoped ledgers now reflect the correct branch's cheque-posting policy regardless of where the operator is logged in. #### Technical Updates - Added a per-location overlay at the top of `App\Utils\TransactionUtil::getLedgerDetails($contact_id, $start, $end, $format, $location_id, $line_details)` using `(new BusinessUtil())->getDetails($business_id, $location_id)` and falling back to the session copy when the lookup yields nothing. - Util is called from `ContactController::getLedger()` / `viewLedger()` / `printLedger()` / `getCustomerLedger()` / ageing endpoints, and from `App\Exports\LedgerExport`. All callers already pass `$location_id`, so the overlay activates automatically wherever a branch is selected — no caller changes required. - No schema changes; reuses the per-request memoised overlay shipped in earlier phases. #### Notes - When the ledger is run without a branch filter (`$location_id === null`), behaviour is unchanged — overlay degrades to a business-level read which matches the previous session-backed value for the operator. - Complements Phase 41's controller-side overlay: the controller now no longer needs to mutate session before delegating to the util, and the util is correct regardless of caller. --- ## Version 8.88.52 **Release Date:** 2026-05-26 ### Module: Cash Register — Register Details / Close-Register Per-Location Settings (Phase 45) #### Bug Fixes - **`CashRegisterController::show()`, `getRegisterDetails()` and `getCloseRegister()` now honour the register's branch `pos_settings`** instead of the operator's session. Whichever branch the register was opened against drives `enable_product_sold_details_register`, `enable_product_stock_details_register`, `enable_drafts_details_register` and `cash_denominations` in the register details and close-register screens — so admins reviewing a branch's register no longer see another branch's product-sold/draft/denomination configuration. #### Technical Updates - Injected `App\Utils\BusinessUtil` into `CashRegisterController` and added a per-location overlay using `BusinessUtil::getDetails($business_id, $register_details->location_id)` ahead of every `$pos_settings = json_decode(session('business.pos_settings'), ...)` read in the three register-detail entry points. Falls back to the session value when the location lookup yields nothing (defensive). - No schema changes; reuses the per-request memoised overlay shipped in earlier phases. #### Notes - Overlay only applies on register screens that have a concrete `register_details->location_id`. Open/store/initial-form paths remain on session values (`create()` is a fresh form). --- ## Version 8.88.51 **Release Date:** 2026-05-26 ### Module: Purchase — Sell-to-Purchase Conversion Per-Location Settings (Phase 44) #### Bug Fixes - **`getSellLinesToPurchaseLines()` now honours the destination branch's `common_settings`** when generating purchase lines from a sell. The `supplier_based_cost_price` flag (which decides whether the supplier-specific cost price is preloaded) is now read from the chosen branch instead of the operator's session. #### Technical Updates - `App\Http\Controllers\PurchaseController::getSellLinesToPurchaseLines()` (~L2267): added per-request overlay `$_b_det_slpl = $this->businessUtil->getDetails($business_id, (int) $location_id)` when `location_id` is supplied, with session fallback retained for the unfiltered case. #### Notes - `BusinessUtil` was already wired in this controller. --- ## Version 8.88.50 **Release Date:** 2026-05-26 ### Module: Customer Dropdown Autocomplete — Per-Location Settings (Phase 43) #### Bug Fixes - **`getCustomers()` autocomplete now honours the selected branch's `common_settings`** when a `location_id` filter is supplied. The `hide_customer_id_from_search_field` flag (which decides whether the contact ID is appended to the display text in the customer dropdown) is now read from the chosen branch instead of the operator's session. #### Technical Updates - `App\Http\Controllers\ContactController::getCustomers()` (~L1856): added per-request overlay `$_b_det_gc = $this->businessUtil->getDetails($business_id, (int) $location_id)` when `location_id` is non-empty, with session fallback retained for the unfiltered case. #### Notes - `BusinessUtil` was wired in Phase 41 — no DI changes. --- ## Version 8.88.49 **Release Date:** 2026-05-26 ### Module: Contact Ledger PDF Download — Per-Location Settings (Phase 42) #### Bug Fixes - **`downloadLedgerPdf($id)` now honours the selected branch's `common_settings`** when a `location_id` filter is supplied. The combined ledger PDF's cheque-posting filter (`cheque_posting_ledger`) and ageing block now follow the chosen branch instead of the operator's session. #### Technical Updates - `App\Http\Controllers\ContactController::downloadLedgerPdf($id)` (~L2986): added per-request overlay `$_b_det_dlp = $this->businessUtil->getDetails($business_id, (int) $location_id)` when `location_id` is present, with session fallback retained for the “all locations” case. #### Notes - `BusinessUtil` was wired in Phase 41 — no DI changes. --- ## Version 8.88.48 **Release Date:** 2026-05-26 ### Module: Contact Ledger — Per-Location Settings (Phase 41) #### Bug Fixes - **Contact Ledger (`getLedger`) now honours the selected branch's `common_settings`** when a `location_id` filter is supplied. The `cheque_posting_ledger` flag consumed by all ledger formats (`format_2`…`format_6`, default ledger view, cheque-clearance report, and ageing block) and by `TransactionUtil::getLedgerClearing()` is now read from the chosen branch instead of the operator's session. #### Technical Updates - `App\Http\Controllers\ContactController`: - Added `use App\Utils\BusinessUtil;`, `protected $businessUtil;`, and constructor parameter `BusinessUtil $businessUtil`. - `getLedger()` (~L2581): when `request()->location_id` is non-empty, overlays `$common_settings` via `$this->businessUtil->getDetails($business_id, (int) $location_id)`. When `location_id` is empty (“all locations” ledger), session common_settings is kept. #### Notes - The ledger view's other compact() fields (currency, ageing, contact) are unaffected. - Other `$common_settings` reads in `ContactController` (index/edit/etc.) are page-level / business-scoped and were intentionally left as-is. --- ## Version 8.88.47 **Release Date:** 2026-05-26 ### Module: Contact-Due Payments — Per-Location `cheque_posting_ledger` (Phase 40) #### Bug Fixes - **`getPayContactDue($contact_id)` now resolves `cheque_posting_ledger` from the resolved payment branch's `common_settings`** instead of the cashier session, so the `$cheque_condition` SQL clause that filters cheques by `posting_date` vs. `clearance_date` follows the branch driving the dues view (`$location->id`). #### Technical Updates - `App\Http\Controllers\TransactionPaymentController::getPayContactDue($contact_id)` (~L759): added `$_b_det_pcd = $this->businessUtil->getDetails($business_id, ! empty($location) ? (int) $location->id : null)` and derived `$common_settings` from it with safe session fallback. #### Notes - `$location` is the cashier's permitted/selected branch resolved earlier in the method, so the overlay key is well-defined. - `BusinessUtil` was already injected on this controller — no DI changes. --- ## Version 8.88.46 **Release Date:** 2026-05-26 ### Module: Gym Subscription Show — Per-Location Settings (Phase 39) #### Bug Fixes - **Gym Subscription `show($id)` now loads `$business_details` for the subscription's branch**, so the exported `$pos_settings` (used by the subscription detail view) reflects the branch the subscription belongs to instead of the operator session's POS settings. #### Technical Updates - `Modules\Gym\Http\Controllers\SubscriptionController::show()` (~L545): `$business_details = $this->businessUtil->getDetails($business_id, (int) $subscription->location_id)`. `$common_settings` also switched to the overlay with safe session fallback. #### Notes - `BusinessUtil` was already injected on the controller — no DI changes. - `$common_settings` is currently not exported via `compact(...)`; the overlay is set defensively in case future view additions reference it. --- ## Version 8.88.45 **Release Date:** 2026-05-26 ### Module: Repair Show / Edit — Per-Location Settings (Phase 38) #### Bug Fixes - **Repair `show($id)` now resolves `is_warranty_enabled` from the repair sell's branch `common_settings`** instead of the cashier session, so the warranty section visibility follows the branch the repair belongs to. - **Repair `edit($id)` now loads `$business_details` for the repair's branch**, so the derived `$pos_settings` (POS toggles consumed by the edit form) and `$business_details->sales_cmsn_agnt` (commission-agent dropdown source) honour the branch on the transaction rather than the operator's session. #### Technical Updates - `Modules\Repair\Http\Controllers\RepairController::show($id)` (~L654): added `$_b_det_rs = $this->businessUtil->getDetails($business_id, (int) $sell->location_id)` and read `common_settings` from it with safe fallback. - `Modules\Repair\Http\Controllers\RepairController::edit($id)` (~L706): reordered to load the `Transaction` first, then call `$this->businessUtil->getDetails($business_id, (int) $transaction->location_id)`. Downstream `$pos_settings`, `$commsn_agnt_setting`, etc. naturally pick up the branch overlay. #### Notes - `BusinessUtil` was already injected on the controller — no DI changes. - Other Repair endpoints that operate on fresh forms (`create`, etc.) were intentionally left session-based. --- ## Version 8.88.44 **Release Date:** 2026-05-26 ### Module: Truckmate Invoice Edit — Per-Location Settings (Phase 37) #### Bug Fixes - **Editing a Truckmate invoice now applies the invoice's branch settings** for `pos_settings` and `common_settings` instead of the cashier's session-scoped values. Branch-specific POS toggles (currency precision, keyboard shortcuts, default-tax behaviour, payment-line defaults) and common-settings flags consumed by the Truckmate edit form now honour `transactions.location_id`. #### Technical Updates - `Modules\Truckmate\Http\Controllers\TruckmateController::edit($id)` (~L1015): added per-request overlay via `$_b_det_te = $this->businessUtil->getDetails($business_id, (int) $invoice->location_id)` to derive `$pos_settings` (JSON → array) and `$common_settings` with safe fallbacks to the previous business-level / session values when the branch overlay is empty. #### Notes - The pre-existing `$business_details = $this->businessUtil->getDetails($business_id)` call is preserved as-is for non-overlayed downstream view bindings; only `pos_settings` and `common_settings` are switched to the branch overlay. - `show($id)` and `showDriverInvoice($id)` were inspected; their local `$common_settings` is not exported via `compact(...)` and was intentionally left untouched. --- ## Version 8.88.43 **Release Date:** 2026-05-26 ### Module: Manufacturing Production / Reverse Production — Per-Location Settings (Phase 36) #### Bug Fixes - **Production finalisation now passes `pos_settings` from the production's branch** into the synthetic `$business` array used by `TransactionUtil::mapPurchaseSell`. Previously the session's `pos_settings` was used, so FIFO/LIFO-tied policies could be applied with the wrong branch's accounting toggles. - **Reverse Production finalisation** uses the same per-branch overlay for its `mapPurchaseSell` call. #### Technical Updates - `Modules\Manufacturing\Http\Controllers\ProductionController` (~L1031): `$_b_det_mp = $this->businessUtil->getDetails($business_id, (int) $production_sell->location_id)` drives the `pos_settings` value inside the `$business` payload (session fallback). - `Modules\Manufacturing\Http\Controllers\ReverseProductionController` (~L904): same overlay using `$_b_det_rmp` (session fallback). #### Notes - `BusinessUtil` already injected on both controllers — no DI changes. - A second `mapPurchaseSell` block in `ReverseProductionController` (~L1085) is inside an existing `/* ... */` commented-out region and was intentionally not touched. --- ## Version 8.88.42 **Release Date:** 2026-05-26 ### Module: Warehouse Stock Transfer Edit — Per-Location Settings (Phase 35) #### Bug Fixes - **Warehouse Stock Transfer edit screen now resolves `pos_settings` and `common_settings` from the transfer's source branch** instead of session. The overselling check (`allow_overselling`) used to compute `$check_quantity` for each sell-line now matches the source branch's POS policy, so opening the same transfer from a different branch's session no longer flips the overselling behaviour. #### Technical Updates - `Modules\Warehouse\Http\Controllers\StockTransferController`: added `use App\Utils\BusinessUtil;`, `protected $businessUtil;`, constructor parameter `BusinessUtil $businessUtil`, and assignment. - `edit($id)`: `$_b_det_wte = $this->businessUtil->getDetails($business_id, (int) $sell_transfer->location_id)` drives both `$pos_settings` and `$common_settings` (session fallbacks). #### Notes - `create()` and `index()` remain session-based — fresh form / cross-branch listing. - Warehouse stock adjustment create form (`StockController::create`) also remains session-based for the same reason; its store/edit paths will be addressed in a later phase. --- ## Version 8.88.41 **Release Date:** 2026-05-26 ### Module: Restaurant POS Table Dropdown — Per-Location Settings (Phase 34) #### Bug Fixes - **Restaurant `getPosDetails` AJAX now overlays `pos_settings` from the selected POS branch** before rendering the table/waiter dropdown partial. The `is_service_staff_required` flag now reflects the branch the cashier is currently switching the POS to, not the session's default branch — so changing the POS branch correctly toggles whether a waiter must be assigned. #### Technical Updates - `Restaurant\DataController`: added `use App\Utils\BusinessUtil;`, `protected $businessUtil;`, constructor parameter `BusinessUtil $businessUtil`, and assignment. - `Restaurant\DataController::getPosDetails(Request $request)`: `$_b_det_rd = $this->businessUtil->getDetails($business_id, (int) $location_id)` drives `$pos_settings` (session fallback). #### Notes - Kitchen-display endpoints in `Restaurant\KitchenController` remain session-based — they don't receive a `location_id` and would require deriving an effective branch from the user's open register, which is out of scope here. --- ## Version 8.88.40 **Release Date:** 2026-05-26 ### Module: Stock Transfer Store & Stock Adjustment Product Row — Per-Location Settings (Phase 33) #### Bug Fixes - **Stock Transfer `store` now resolves `pos_settings` from the transfer's source branch** before passing the synthetic `$business` array into `TransactionUtil::mapPurchaseSell`. New transfers honour the source branch's POS policy (overselling, mapping behaviour) instead of the cashier's session, matching the Phase 30 treatment of `update` / `updateStatus`. - **Stock Adjustment product-row AJAX now overlays `pos_settings` from the selected `location_id`** before rendering the inline row, so per-branch POS toggles (overselling, lot/expiry visibility) reflect the chosen branch even when the cashier is logged into a different one. #### Technical Updates - `StockTransferController::store(Request $request)`: `$_b_det_st = $this->businessUtil->getDetails($business_id, (int) $input_data['location_id'])` drives `$pos_settings` (session fallback) used in the `mapPurchaseSell` payload. - `StockAdjustmentController` product-row block (~L681): `$_b_det_pr = $this->businessUtil->getDetails($business_id, (int) $location_id)` drives `$pos_settings` (session fallback). #### Notes - `BusinessUtil` already injected on both controllers — no DI changes. - The `create()` form pages for both controllers remain session-based since no branch context exists until the user picks one. --- ## Version 8.88.39 **Release Date:** 2026-05-26 ### Module: Product Stock History — Per-Location Settings (Phase 32) #### Bug Fixes - **Single-location Stock History panel now resolves `pos_settings` and `common_settings` from the selected branch** instead of session. Branch-specific toggles that drive the stock-history view (and `pos_settings` flags consumed by the partial) now match the location chosen in the filter rather than the cashier's session. #### Technical Updates - `ProductController`: added `use App\Utils\BusinessUtil;`, `protected $businessUtil;`, constructor parameter `BusinessUtil $businessUtil`, and assignment. - `ProductController::productStockHistory($id)` (ajax single-location branch, ~L4626): `$_b_det_sh = $this->businessUtil->getDetails($business_id, (int) $location_id)` drives `$pos_settings` and overrides `$common_settings` when present (session fallback). #### Notes - The all-locations tabbed branch (~L4596) intentionally leaves `$pos_settings` session-based — that view aggregates across every branch, so a single branch's overlay would be misleading. - `BusinessUtil` was newly injected on `ProductController`; existing static `session()->get('business.common_settings')` reads elsewhere in this controller remain untouched and can be migrated incrementally in later phases. --- ## Version 8.88.38 **Release Date:** 2026-05-26 ### Module: Combined Purchase Return — Per-Location Settings (Phase 31) #### Bug Fixes - **Edit screen for a Combined Purchase Return now reads `common_settings` from the return's branch** instead of session. Branch-specific toggles (e.g. ledger-discount visibility, supplier-cost behaviour) now match where the return was filed. - **Product-row AJAX (`getProductRow`) now overlays both `common_settings` and `pos_settings` from the requested `location_id`** before rendering the inline row partial, so the row reflects the selected branch's policy even when the cashier is logged into a different branch. #### Technical Updates - `CombinedPurchaseReturnController`: added `use App\Utils\BusinessUtil;`, `protected $businessUtil;`, constructor parameter `BusinessUtil $businessUtil`, and assignment. - `edit($id)`: `$_b_det_e = $this->businessUtil->getDetails($business_id, (int) $purchase_return->location_id)` drives `$common_settings` (session fallback). - `getProductRow(Request $request)`: `$_b_det_pr` driven by request `$location_id`; supplies both `$common_settings` and `$pos_settings` (session fallbacks). #### Notes - `create()` is intentionally left session-based — it is a fresh form with no branch context until the user picks one. - This mirrors the Phase 29 treatment of `PurchaseReturnController`. --- ## Version 8.88.37 **Release Date:** 2026-05-26 ### Module: Purchase Print & Stock Transfer Update — Per-Location Settings (Phase 30) #### Bug Fixes - **Purchase → Print Invoice now resolves `common_settings.purchase_invoice_design_id` from the purchase's branch.** Previously read from session, so a branch with a custom Invoice Designer template configured could fall back to the legacy layout when printed from a foreign-branch session (or vice versa). - **Stock Transfer update (`update`) resolves `pos_settings` from the transfer's source branch.** The unified reverse / re-apply flow honours the source branch's POS toggles (overselling, mapping behaviour) instead of the cashier's session. - **Stock Transfer status update (`updateStatus`) also resolves `pos_settings` from the source branch** before passing the synthetic `$business` array into `TransactionUtil::mapPurchaseSell`, so destination-side purchase→sell mapping uses the source branch's POS policy. #### Technical Updates - `PurchaseController::printInvoice($id)`: replaces session-based `$common_settings` with `$this->businessUtil->getDetails($business_id, (int) $purchase->location_id)->common_settings` (session fallback). - `StockTransferController::update($id, $request)`: replaces `json_decode(session('business.pos_settings'), true)` with overlay sourced from `$sell_transfer->location_id`. - `StockTransferController::updateStatus(...)`: same overlay pattern for the post-`adjustStockOverSelling` mapping step. #### Notes - `BusinessUtil` already injected on both controllers — no DI changes. - Print receipts that already use `BusinessLocation->loc_settings['*_layout_id']` are unaffected; this fix is specifically about the Invoice Designer cross-cutting toggle. --- ## Version 8.88.36 **Release Date:** 2026-05-26 ### Module: Purchase Return & Purchase Order — Per-Location Settings (Phase 29) #### Bug Fixes - **Purchase Return Add screen now resolves `common_settings` and `keyboard_shortcuts` from the source purchase's branch** instead of the viewing user's session. Cross-branch admins returning a foreign-branch purchase now see the correct keyboard shortcuts and the correct branch-level policy toggles. - **Purchase Order Edit screen resolves `keyboard_shortcuts` and `common_settings.enable_purchase_requisition` from the PO's branch.** Previously called `getDetails($business_id)` without the location and read `common_settings` from session, so per-branch overrides were ignored when an admin edited a foreign-branch PO. #### Technical Updates - `PurchaseReturnController`: inject `App\Utils\BusinessUtil` (added `use`, `protected $businessUtil`, constructor parameter, assignment). - `PurchaseReturnController::add($id)`: replaces the direct `Business::find($business_id)` + `session('business.common_settings')` reads with `$this->businessUtil->getDetails($business_id, (int) $purchase->location_id)` (session fallback for `common_settings`). - `PurchaseOrderController::edit($id)`: passes `(int) $purchase->location_id` into `getDetails(...)`; sources `$common_settings` from `business_details->common_settings` (session fallback). #### Notes - `BusinessUtil` was already injected on `PurchaseOrderController`; only `PurchaseReturnController` required DI changes. - Create / index / store paths intentionally remain session-based (no transaction-level location yet). --- ## Version 8.88.35 **Release Date:** 2026-05-26 ### Module: Ledger Discount — Per-Location Settings (Phase 28) #### Bug Fixes - **Ledger Discount 2 / 3 Edit screens now resolve `common_settings` from the discount transaction's branch** instead of the viewing user's session. Cross-branch admins editing a foreign-branch ledger-discount now see the right policy (e.g. `ld3_calculate_discount_on_new_cost`, supplier-search column visibility). - **Ledger Discount 3 Store (`store3`) and Update (`update3`) resolve `common_settings.ld3_calculate_discount_on_new_cost` from the form's selected branch.** Previously read from the cashier's session, so a discount saved against branch B from a branch-A session calculated against the wrong cost basis. - **Ledger Discount 3 Edit (`edit3`) removed a stale duplicate `$common_settings` re-read** that was overwriting the per-location overlay just before render. #### Technical Updates - `LedgerDiscountController`: inject `App\Utils\BusinessUtil` (added `use`, `protected $businessUtil`, constructor parameter, assignment). - `store3(Request $request)`: source `$common_settings` via `$this->businessUtil->getDetails($business_id, (int) $input['location_id'])` with session fallback. - `edit2($id)` / `edit3($id)`: source `$common_settings` via `getDetails(...,$discount->location_id)` with session fallback; `edit3` now loads `$discount` before resolving `$common_settings`, and the trailing duplicate read is dropped. - `update3(Request $request, $id)`: same per-location overlay as `store3`. #### Notes - Ledger Discount index endpoints (`index`/`index2`/`index3`) are by-contact lists spanning branches — intentionally remain session-based. - No view changes required; `$common_settings` shape is unchanged. --- ## Version 8.88.34 **Release Date:** 2026-05-26 ### Module: Purchase — Per-Location Settings (Phase 27) #### Bug Fixes - **Purchase Show screen now resolves `common_settings` from the purchase's branch** instead of the viewing user's session. Cross-branch admins viewing a purchase from another branch now see the correct policy for activities/order-status rendering. - **Purchase → Supplier autocomplete (`getSuppliers`) honours the selected branch's `hide_supplier_id_from_search_field`** instead of the cashier's session, so suppliers searched against a foreign branch return the right column set. - **Purchase → Product autocomplete (`getProducts`) resolves `common_settings.change_search_filtering_sales` (and related search policies) from the selected branch** so cross-branch purchase entry uses the branch's product-search behaviour. - **Purchase → `getPurchaseEntryRow` resolves `common_settings.supplier_based_cost_price` from the selected branch.** Previously read from session, so a supplier-based cost branch could fall back to flat pricing when the request originated from a non-matching session. #### Technical Updates - `PurchaseController::show($id)`: adds `$_b_det_show = $this->businessUtil->getDetails($business_id, (int) $purchase->location_id)` and sources `$common_settings` from it with session fallback. - `PurchaseController::getSuppliers()`: moves `$common_settings` load below `$location_id` resolution and routes it through `getDetails(...)` overlay. - `PurchaseController::getProducts()`: same reorder + overlay (`$_b_det_gp`). - `PurchaseController::getPurchaseEntryRow()`: reuses the Phase 18 `$_b_det` to drive `$common_settings` (session fallback when no location). #### Notes - All four callsites already had a `location_id` (transaction or request input) in scope — no new "effective location" resolution required. - `BusinessUtil` was already injected; no DI changes. - Purchase index Datatables and `create()` intentionally remain session-based (cross-branch list / fresh form). --- ## Version 8.88.33 **Release Date:** 2026-05-26 ### Module: Reports & Sales Order — Per-Location Settings (Phase 26) #### Bug Fixes - **Profit / Loss report (AJAX details) now resolves `common_settings` from the report's selected branch** instead of the viewing user's session. Cross-branch admins viewing a branch's P&L now see the policy that governs that branch's figures. - **Sales Representative Total Commission report now resolves `pos_settings.cmmsn_calculation_type` from the selected branch.** Previously called `getDetails($business_id)` without the location, so a branch configured for `payment_received` commission could be reported as `invoice_value` (or vice versa) depending on which business-level fallback the JSON resolved to. - **Sales Order → `getPurchasesForLedgerDiscount3` endpoint resolves `common_settings.ld3_calculate_discount_on_new_cost` from the branch in the URL** instead of the cashier's session, so the Ledger Discount 3 dropdown joins the correct discount ledger for cross-branch lookups. #### Technical Updates - `ReportController::getProfitLoss` AJAX path: replaces `session('business.common_settings')` with `$this->businessUtil->getDetails($business_id, (int) $location_id)->common_settings` (session fallback). - `ReportController::getSalesRepresentativeTotalCommission`: passes `(int) $location_id` into `getDetails(...)` so `pos_settings` reflects the per-branch overlay. - `SalesOrderController::getPurchasesForLedgerDiscount3($location_id)`: switches `common_settings` source to `getDetails(...,$location_id)` with session fallback. #### Notes - No DI changes — `BusinessUtil` was already injected on both controllers. - All three sites already had `location_id` in scope (request filter or route parameter), so no "effective location" resolution is required. - Other report endpoints without a specific branch context (e.g. opening-stock report, register report) intentionally remain session-based. --- ## Version 8.88.32 **Release Date:** 2026-05-26 ### Module: Stock Transfer & Stock Adjustment — Per-Location Settings (Phase 25) #### Bug Fixes - **Stock Transfer show/print/edit screens now resolve `common_settings.enable_stock_issue_receive` (which gates the Stock Category dropdown) against the transfer's source branch.** Previously read from `session('business.common_settings')`, so cross-branch admins saw the wrong categorisation policy. - **Stock Transfer edit now resolves `pos_settings.allow_overselling` from the source branch.** A branch that disallows overselling could be edited from a session that allowed it (or vice versa), leading to wrong quantity validation. - **Stock Adjustment `getProductRow` endpoint now resolves `pos_settings` and `common_settings.disable_sa_product_reindex` from the selected branch.** The product-reindex (mismatch repair) and overselling guard previously followed the cashier's session instead of the branch the adjustment was being made for. - **Stock Adjustment Excel import resolves `pos_settings` / `common_settings` from the selected branch** instead of the cashier's session. #### Technical Updates - [app/Http/Controllers/StockTransferController.php](app/Http/Controllers/StockTransferController.php) `show()`, `printInvoice()`, `edit()` derive `$common_settings` (and `edit()` derives `$pos_settings` for `allow_overselling`) from `BusinessUtil::getDetails($business_id, $sell_transfer->location_id)` — reusing the `$_b_det` already loaded in Phase 19 for lot/expiry policy. - [app/Http/Controllers/StockAdjustmentController.php](app/Http/Controllers/StockAdjustmentController.php) `getProductRow()` and `importStockAdjustmentProducts()` derive `$pos_settings` and `$common_settings` from `BusinessUtil::getDetails($business_id, $location_id)`. #### Notes - `create()` and `index()` paths intentionally left session-based — no transaction/branch context exists yet (create) or list spans multiple branches. - Session fallback preserved at every site. --- ## Version 8.88.31 **Release Date:** 2026-05-26 ### Module: Transaction Payments — Per-Location Overlay (Phase 24) #### Bug Fixes - **Payment view modals now honour the transaction/payment's branch when resolving `common_settings`.** Four payment-related screens (transaction payment list/show, payment-ref-no view, and advance-deposit view) read `session('business.common_settings')` directly — so per-location custom field labels and cheque/voucher policy flags were always the cashier's session values regardless of which branch the underlying payment was posted at. - **`payContact` save-and-print path now resolves `pos_settings.enable_cash_denomination_for_payment_methods` from the payment's branch.** Cash-denomination capture on "Save & Print" previously used the session's POS settings, so denomination prompts disappeared / appeared incorrectly when paying against a transaction belonging to a different branch. #### Technical Updates - [app/Http/Controllers/TransactionPaymentController.php](app/Http/Controllers/TransactionPaymentController.php) injected `BusinessUtil` via constructor (new `use App\Utils\BusinessUtil;` + `protected $businessUtil`). - `show($id)` (∼L242), `viewPayment` ref-no modal (∼L1960), and `viewAdPayment` modal (∼L2039) now derive `$common_settings` from `BusinessUtil::getDetails($business_id, $transaction_or_payment->location_id)` with session fallback. - `postPayContactDue` save-and-print branch (∼L1358) derives `$pos_settings` from the payment's branch via `BusinessUtil::getDetails($business_id, $tp->location_id)` with session fallback. #### Notes - Contact ledger query (∼L752) intentionally left session-based for this phase — it spans `$location` filter context and only reads `cheque_posting_ledger`, a business-wide setting. A future phase may revisit if cheque-posting policy becomes per-location. --- ## Version 8.88.30 **Release Date:** 2026-05-26 ### Module: Sell Return Add/Edit — Per-Location Overlay (Phase 23) #### Bug Fixes - **Sell return `add` screen now scopes `business_details` (including `sales_cmsn_agnt`, `pos_settings.is_commission_agent_required`, and `keyboard_shortcuts`) to the sale's branch.** Previously the screen called `BusinessUtil::getDetails($business_id)` with no location, so the commission-agent dropdown and shortcut map were always business-defaults — ignoring per-location overrides set on the sale's branch. - **Sell return `add` + `edit` screens now resolve `common_settings` (return-policy gates, custom field labels, etc.) from the sale/return's branch.** Both views previously read `session('business.common_settings')` directly, so cross-branch admins saw the wrong per-location custom-field labels and return policy flags. #### Technical Updates - [app/Http/Controllers/SellReturnController.php](app/Http/Controllers/SellReturnController.php) `add()` now loads `$sell` first, then calls `BusinessUtil::getDetails($business_id, $sell->location_id)` so the subsequent commission-agent and pos_settings resolution honours the sale's branch. - [app/Http/Controllers/SellReturnController.php](app/Http/Controllers/SellReturnController.php) `add()` derives `$common_settings` from `$business_details->common_settings` with session fallback. - [app/Http/Controllers/SellReturnController.php](app/Http/Controllers/SellReturnController.php) `edit()` derives `$common_settings` from `$business_details->common_settings` (already loaded for `$sell_return->location_id`) with session fallback. #### Notes - `index()` (Datatables list) is intentionally left session-based — a list page spans all branches and the only setting it reads is the Dojo card-terminal API key, which is a business-wide credential. --- ## Version 8.88.29 **Release Date:** 2026-05-26 ### Module: Sale Show/Edit + FBR DI — Per-Location Overlay (Phase 22) #### Bug Fixes - **Sale show + sale edit screens now resolve `common_settings.enable_product_warranty` against the sale's own branch.** Previously the warranty section / dropdown was driven by `session('business.common_settings')`, so an admin viewing or editing a sale from another branch saw warranty hidden/shown by their session’s policy instead of the sale’s. - **FBR DI invoice push now resolves `pos_settings` from the transaction's branch.** The Pakistan FBR Digital Invoicing push path already loaded `business_details` per-location but still pulled `pos_settings` from the session; cross-branch admins/cron triggers could push with the wrong POS profile. #### Technical Updates - [app/Http/Controllers/SellController.php](app/Http/Controllers/SellController.php) `show()` derives `$common_settings` from `$business_details->common_settings` (already loaded for `$sell->location_id`) with session fallback. - [app/Http/Controllers/SellController.php](app/Http/Controllers/SellController.php) `edit()` derives `$common_settings` from `$business_details->common_settings` (already loaded for `$transaction->location_id`) with session fallback. - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) `postFbrDiInvoice` flow derives `$pos_settings` from `$business_details->pos_settings` with session fallback. #### Notes - All three callsites preserve the previous session-based behaviour as a fallback when the overlay produces no value, so single-branch businesses see no behaviour change. --- ## Version 8.88.28 **Release Date:** 2026-05-26 ### Module: Purchase Edit — Per-Location Overlay (Phase 21) #### Bug Fixes - **Purchase edit screen now resolves `enable_purchase_status`, keyboard shortcuts, and `common_settings` (incl. `enable_purchase_order`) against the purchase's own branch.** Editing a purchase belonging to a branch with different settings than the cashier's session previously rendered the wrong default status, the wrong keyboard shortcut map, and an incorrectly visible/hidden Purchase Order dropdown. #### Technical Updates - [app/Http/Controllers/PurchaseController.php](app/Http/Controllers/PurchaseController.php) `edit()` now calls `BusinessUtil::getDetails($business_id, $purchase->location_id)` once and derives `$default_purchase_status`, `$shortcuts`, and `$common_settings` from that overlay (with session fallback preserved for `common_settings`). #### Notes - `create()` (new purchase) intentionally remains session-driven — no transaction exists yet; the user picks the branch in the form, and the create-time default mirrors their current session. --- ## Version 8.88.27 **Release Date:** 2026-05-26 ### Module: Sale & Purchase Lot/Expiry — Per-Location Overlay (Phase 20) #### Bug Fixes - **Sale-edit and POS row-fetch endpoints now honour the transaction's branch for lot/expiry visibility.** Three remaining write/render paths used `session('business.enable_lot_number')` / `session('business.enable_product_expiry')` only — a multi-branch cashier loading a sale belonging to a different branch (or punching a row against a non-session branch) saw the lot dropdown appear/disappear against the wrong policy. - **Purchase-delete lot-usage guard now uses the purchase's own branch.** Before deleting a purchase the system checks whether its lot numbers are referenced by sale lines (`isLotUsed`); the guard fired only when the *session* branch had lot tracking enabled, so a cross-branch admin could bypass the check when their session was bound to a branch with lot tracking disabled. #### Technical Updates - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) `edit()` (“add available lot numbers for dropdown to sell lines” block) resolves overlay via `$location_id` (the transaction's branch). - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) `getProductRow()`-style endpoint resolves overlay via the row's `$location_id`. - [app/Http/Controllers/SellController.php](app/Http/Controllers/SellController.php) `edit()` lot-dropdown branch resolves via the transaction's `$location_id`. - [app/Http/Controllers/PurchaseController.php](app/Http/Controllers/PurchaseController.php) `destroy()` lot-usage guard resolves via `$transaction->location_id`. #### Notes - Backwards-compatible: when `BusinessUtil::getDetails()` returns no row for the given location, the original session-based fallback is implicit through the cached result. All controllers already had `BusinessUtil` injected (no DI changes). --- ## Version 8.88.26 **Release Date:** 2026-05-26 ### Module: Stock Transfer & Adjustment Lot/Expiry — Per-Location Overlay (Phase 19) #### Bug Fixes - **Lot-number and product-expiry visibility on stock transfers and stock adjustments now follow the document's branch.** Five endpoints rendered the lot/expiry dropdowns based on `session('business.enable_lot_number')` / `session('business.enable_product_expiry')` only. A user with a session bound to a different branch viewing/printing/editing a transfer or adjustment from another branch saw the wrong lot/expiry UI — fields appeared or disappeared against the cashier's branch instead of the document's branch. #### Technical Updates - [app/Http/Controllers/StockTransferController.php](app/Http/Controllers/StockTransferController.php) `show()`, `printInvoice()`, and the edit row-building loop now resolve `enable_lot_number` / `enable_product_expiry` from `BusinessUtil::getDetails($business_id, $sell_transfer->location_id)` (overlay-aware, request-cached). - [app/Http/Controllers/StockTransferController.php](app/Http/Controllers/StockTransferController.php) `BusinessUtil` dependency injection added (constructor + import + property). - [app/Http/Controllers/StockAdjustmentController.php](app/Http/Controllers/StockAdjustmentController.php) `show()` resolves via `$stock_adjustment->location_id`. - [app/Http/Controllers/StockAdjustmentController.php](app/Http/Controllers/StockAdjustmentController.php) row-builder endpoint resolves via the request's `$location_id`. #### Notes - Backwards-compatible: the lot/expiry boolean is still computed identically; only its source changed from session-only to overlay (location-aware) with session fallback when no location resolves. - `StockAdjustmentController` already had `BusinessUtil` injected (no DI changes needed there). --- ## Version 8.88.25 **Release Date:** 2026-05-26 ### Module: Purchase Inline-Tax — Per-Location Overlay (Phase 18) #### Bug Fixes - **`enable_inline_tax` (show/hide tax column on purchase entry rows) now follows the target branch.** Four purchase helper endpoints rendered the tax column visibility from `session('business.enable_inline_tax')` only. Adding/importing/reloading purchase lines for a branch other than the cashier's session branch could show or hide the tax column against the wrong branch's policy. #### Technical Updates - [app/Http/Controllers/PurchaseController.php](app/Http/Controllers/PurchaseController.php) `getPurchaseEntryRow()` — resolves `enable_inline_tax` from `BusinessUtil::getDetails($business_id, $request->input('location_id'))` (overlay-aware, request-cached) when a location_id is supplied; session fallback otherwise. - [app/Http/Controllers/PurchaseController.php](app/Http/Controllers/PurchaseController.php) imported purchase product rows endpoint — same overlay against `$request->input('location_id')`. - [app/Http/Controllers/PurchaseController.php](app/Http/Controllers/PurchaseController.php) `getPurchaseOrderLines()` — overlay against `$purchase_order->location_id`. - [app/Http/Controllers/PurchaseRequisitionController.php](app/Http/Controllers/PurchaseRequisitionController.php) `getPurchaseRequisitionLines()` — overlay against `$purchase_requisition->location_id`; added `BusinessUtil` dependency injection (constructor + import). #### Notes - Backwards-compatible: when no location_id can be resolved, the original `session('business.enable_inline_tax')` value is used unchanged. --- ## Version 8.88.24 **Release Date:** 2026-05-26 ### Module: Sales Commission Agent — Per-Location Overlay (Phase 17) #### Bug Fixes - **`sales_cmsn_agnt` ("logged-in user as commission agent" policy) now follows the transaction's branch.** Four sale write paths in `SellPosController` resolved the policy from `session('business.sales_cmsn_agnt')` only, so: - A POS / direct-sale `store()` saved to a non-cashier branch could fail to auto-assign the commission agent that *that* branch requires. - An `update()` of an existing sale belonging to a different branch could silently re-apply the cashier's branch policy instead of the sale's own branch policy. - The autosave draft create + update paths had the same issue. #### Technical Updates - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) `store()` — after the session lookup, if `$input['location_id']` is present, the policy is refreshed from `BusinessUtil::getDetails($business_id, $location_id)` (already overlay-aware and request-cached). - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) `update()` — refreshed using `$transaction_before->location_id`. - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) autosave create path — refreshed using `$input['location_id']`. - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) autosave update path — refreshed using `$transaction_before->location_id`. #### Notes - Session fallback is preserved when no `location_id` can be resolved (no behaviour change for existing single-branch businesses). - The `index()` filter UI guard at L159 intentionally remains session-based — it's a global affordance for whether to render the commission-agent dropdown, not a per-transaction policy decision. - Per-transaction reads in `SellReturnController` (lines ~369, ~433, ~935, ~1616) already pull `sales_cmsn_agnt` from `$business_details` (which is built via `BusinessUtil::getDetails($business_id, $location_id)` in Phase 8 callers), so they were already correct. --- ## Version 8.88.23 **Release Date:** 2026-05-26 ### Module: Edit Window & Product Expiry — Per-Location Overlay (Phase 16) #### Bug Fixes - **`transaction_edit_days` now follows the transaction's branch, not the cashier's session branch.** Editing a sale/SO/purchase or deleting a stock transfer belonging to a different branch was always validated against the cashier's session value of `transaction_edit_days`. With the per-location overlay, each branch can have its own edit window; this fix makes the check honour the transaction's own branch policy. - **Product-expiry "stop selling" rule now follows the transaction's branch.** Inside `mapPurchaseSell()` the flags `enable_product_expiry`, `on_product_expiry` and `stop_selling_before` were read from `session('business')` only. Backend mapping triggered from queues, console commands, or a cashier session bound to a different branch could therefore apply the wrong expiry rule for stock at the actual transaction branch. #### New Features - New helper `TransactionUtil::getEffectiveEditDays($business_id, $transaction_or_id)` resolves the per-location `transaction_edit_days` value by loading the transaction's `location_id` and applying `setLocationContext()` on a fresh `Business::find()`; falls back to the session value when no transaction/location is resolvable. #### Technical Updates - [app/Utils/TransactionUtil.php](app/Utils/TransactionUtil.php) added `getEffectiveEditDays()` next to `canBeEdited()`. - [app/Utils/TransactionUtil.php](app/Utils/TransactionUtil.php) `mapPurchaseSell()` overlay refresh block (Phase 14) now also exposes `enable_product_expiry`, `on_product_expiry` and `stop_selling_before` on the `$business` array; the `$stop_selling_expired` flag and `$stop_before` look-up now prefer those overlay values over `session('business')`. - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) `edit()` — `transaction_edit_days` now resolved via `getEffectiveEditDays()`. - [app/Http/Controllers/SellController.php](app/Http/Controllers/SellController.php) `edit()` — same. - [app/Http/Controllers/PurchaseController.php](app/Http/Controllers/PurchaseController.php) `edit()` and `updateStatus()` — same. - [app/Http/Controllers/StockTransferController.php](app/Http/Controllers/StockTransferController.php) `destroy()` — same. #### Notes - Backwards-compatible: all 5 callsites still receive an `int` `$edit_days`; only the source of that value changed. The `canBeEdited()` signature is unchanged. - The `StockTransferController::index()` datatable still resolves `$edit_days` from the session (used inside row closures); it is not referenced inside the rendered action HTML, so no per-row overlay is required there. --- ## Version 8.88.22 **Release Date:** 2026-05-26 ### Module: Reward Points — Per-Location Overlay for Earn & Redeem (Phase 15) #### Bug Fixes - **Reward-point earning and redemption now respect per-location settings.** `TransactionUtil::calculateRewardPoints()` and `TransactionUtil::getRewardRedeemDetails()` previously read `enable_rp`, `min_order_total_for_rp`, `amount_for_unit_rp`, `max_rp_per_order`, `min_redeem_point`, `max_redeem_point`, and `redeem_amount_per_unit_rp` from `session('business')` (cashier's active branch) or a flat `Business::find()` fallback. A multi-branch cashier ringing up an order for a different branch (or any code path without session) would always get the cashier's branch's RP rules — not the transaction's branch's rules — even though all of these keys are in `PER_LOCATION_SETTINGS`. - Both methods now accept an optional `$location_id` argument; when supplied, a fresh `Business::find()` is loaded with `setLocationContext($location_id)` applied so per-branch RP rules win. #### Technical Updates - [app/Utils/TransactionUtil.php](app/Utils/TransactionUtil.php) `calculateRewardPoints($business_id, $total, $location_id = null)` and `getRewardRedeemDetails($business_id, $customer_id, $location_id = null)` — new optional parameter, overlay applied when provided; falls back to existing session/flat behaviour otherwise (backwards-compatible). - [app/Utils/TransactionUtil.php](app/Utils/TransactionUtil.php) internal callers in `createSellTransaction()`, the update path, and the sell-return RP recalculation now pass `$input['location_id']` / `$sell->location_id` to the calculator. - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) `getRewardDetails()` AJAX endpoint resolves the cashier's effective branch (open register → user `default_location`) and passes it to `getRewardRedeemDetails()` so the POS reward-redeem prompt reflects the active branch's rules. - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) and [app/Http/Controllers/SellController.php](app/Http/Controllers/SellController.php) edit-redeem paths now pass `$transaction->location_id` so a reload of an existing transaction uses *that* transaction's branch rules. #### Notes - Backwards-compatible: all existing callers continue to work with their original 2-argument signature; the third parameter defaults to null and the legacy session-based path is preserved. --- ## Version 8.88.21 **Release Date:** 2026-05-26 ### Module: Inventory Mapping — Per-Location Overlay for mapPurchaseSell (Phase 14) #### Bug Fixes - **Per-branch `allow_overselling` and `is_serial_number_required_*` policies are now honoured by `TransactionUtil::mapPurchaseSell()`.** Every call site (StockTransfer, StockAdjustment, SellPos, RecurringInvoice command, MapPurchaseSell command, and the two internal adjust-mapping helpers) was passing a flat `Business::find()->toArray()` array — which bypasses the `Business::getAttribute()` overlay and therefore always used the global `pos_settings` and `common_settings`. Branches that disabled overselling or enforced serial-number capture on POS/Purchase via the location overlay were being silently overridden by the global flat values during stock allocation. #### Technical Updates - [app/Utils/TransactionUtil.php](app/Utils/TransactionUtil.php) `mapPurchaseSell()` — added a centralized overlay refresh at the top of the method: if the incoming `$business` array carries both `id` and `location_id`, refresh `pos_settings` and `common_settings` from a `Business::find()` model with `setLocationContext($location_id)` applied. This fixes every caller at once without touching call sites. - [app/Utils/TransactionUtil.php](app/Utils/TransactionUtil.php) `adjustMappingPurchaseSell()` and `adjustMappingPurchaseSellAfterEditingPurchase()` — also defensively apply `setLocationContext()` and inject the overlayed `pos_settings` / `common_settings` into the `toArray()` result before passing to `mapPurchaseSell()`. (Redundant with the centralized fix but keeps the array correct for any future inline reads inside these methods.) #### Notes - The centralized fix is the operative change — it covers every caller in `StockTransferController` (3 sites), `StockAdjustmentController` (2 sites), `SellPosController` (3 sites), `Console\Commands\RecurringInvoice`, `Console\Commands\MapPurchaseSell` (2 sites), and internal TransactionUtil callers — with a single edit. - Guarded by `method_exists($_overlay_business, 'setLocationContext')` so it's safe for any future Business stub used in tests. --- ## Version 8.88.20 **Release Date:** 2026-05-26 ### Module: TransactionUtil — Receipt & Payment Overlay Coverage (Phase 13) #### Bug Fixes - **Cash-denomination toggles now respect per-location overlay.** `TransactionUtil::addCashDenominations()` and `TransactionUtil::updateCashDenominations()` previously read `pos_settings.enable_cash_denomination_for_payment_methods` / `enable_cash_denomination_on` from a flat `Business::findOrFail()` result, ignoring any per-branch overlay. Both methods now resolve the payment's transaction location and apply `Business::setLocationContext()` so denomination capture matches the branch where the payment was actually taken. - **Receipt detail builders now reuse the already-overlayed business model.** `getReceiptDetails()`, `getReceiptPurchaseDetails()`, and `getReceiptExpenseDetails()` each re-fetched a flat `$business = Business::find($transaction->business_id)` even though their caller already passed in `$business_details` (which `BusinessUtil::getDetails($business_id, $location_id)` had overlayed). They now reuse `$business_details`, so per-location overrides for `common_settings.serial_number_label`, `imei1_number_label` … `imei4_number_label`, and `hide_invoice_branding` actually appear on sale, purchase, and expense receipts when the originating branch has them set. #### Technical Updates - [app/Utils/TransactionUtil.php](app/Utils/TransactionUtil.php) `addCashDenominations()` & `updateCashDenominations()` — added a tx-id → location resolution that calls `setLocationContext()` on the loaded Business model before decoding `pos_settings`. - [app/Utils/TransactionUtil.php](app/Utils/TransactionUtil.php) `getReceiptDetails()`, `getReceiptPurchaseDetails()`, `getReceiptExpenseDetails()` — replaced the local `Business::find()` re-fetch with `$business = $business_details`, eliminating a redundant query and restoring overlay correctness for the receipt label fields. #### Notes - No view or schema changes. The `setLocationContext()` guard uses `method_exists()` so the path is safe even if a future Business stub is swapped in for testing. - Combined with Phase 7 (BusinessUtil::getDetails calls in receipt controllers) and Phase 12 (session-derived pos/common_settings reads), the receipt-rendering surface area is now fully overlay-aware: cashier flows get the right branch via session priming, and admin reprints get the originating branch via the explicit `$location_id` argument. --- ## Version 8.88.19 **Release Date:** 2026-05-26 ### Module: POS — Receipt & FBR Overlay Correctness (Phase 12) #### Bug Fixes - **Reprinting another branch's receipt now uses *that* branch's per-location settings.** Previously, `receiptContent()` read `pos_settings` and `common_settings` from `session('business.*')`, which Phase 10 overlays to the **cashier's** active location. When an admin (or any user with multi-location access) reprinted a receipt for a different branch's transaction, the Invoice Designer selection and per-branch overrides came from the cashier's branch instead of the transaction's branch. - **POS receipts:** `SellPosController::receiptContent()` now sources both `pos_settings` and `common_settings` from `$business_details` (already overlayed for `$location_id` via `BusinessUtil::getDetails()`). The Invoice Designer bypass branch (`sale_invoice_design_id` for direct sales, `pos_settings[{location_id}]['invoice_design_id']` for POS) now resolves against the correct branch. - **Sell-return receipts:** `SellReturnController::receiptContent()` likewise sources `pos_settings` from `$business_details` so the originating branch's per-location settings render regardless of who reprints it. - **FBR receipt path:** `SellPosController::receiptContentForFbrInvoice()` now sources `pos_settings` from `$business_details` so per-branch FBR-relevant POS overrides are honoured. #### Technical Updates - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) — `receiptContent()` and FBR receipt method: replaced `session('business.pos_settings')` / `session('business.common_settings')` reads with `$business_details->pos_settings` / `$business_details->common_settings` (the overlayed values). - [app/Http/Controllers/SellReturnController.php](app/Http/Controllers/SellReturnController.php) — `receiptContent()`: same swap. - No view or schema changes. Cashier-side flows already get the correct overlay via Phase 10's session priming, so this hardens the cross-branch reprint path without altering hot-path behaviour. #### Notes - This completes the per-location overlay coverage for receipt rendering: Phase 7 fixed `BusinessUtil::getDetails()` calls in receipt code, and Phase 12 now removes the remaining session-derived overlay reads that bypassed it. --- ## Version 8.88.18 **Release Date:** 2026-05-26 ### Module: POS — Customer-Facing Display Screen Restored (Phase 11) #### Bug Fixes - **Fixed broken `/customer-display` route.** The `pos_display` route was wired to `SellPosController@posDisplay`, but that method did not exist — every click on the *Customer Display Screen* button in the POS header produced a `BadMethodCallException: Method posDisplay does not exist`. The route is now backed by a real controller method and renders the existing `sale_pos/display.blade.php` view. #### New Features - **Customer Display Screen now respects per-location Business Settings.** The display heading (`display_screen_heading`) and the carousel images (`carousel_image_1` … `carousel_image_10`) are resolved against the cashier's active branch overlay, so each location can run its own carousel and heading on the customer-facing screen. - Resolution follows the established POS chain: open cash register → user `default_location` → flat global fallback. A user with no register and no default location sees the flat global carousel/heading. #### Technical Updates - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) `posDisplay()` — new method. Resolves the effective POS location id via `cashRegisterUtil->getCurrentCashRegister()` and `user_settings.default_location`, calls `BusinessUtil::getDetails($business_id, $effective_loc_id)` to apply the per-location overlay, decodes `pos_settings` (falling back to `defaultPosSettings()` when null), and returns `view('sale_pos.display', compact('pos_settings'))`. - No changes to the existing display view, route, or header link — the missing endpoint is the only thing this version adds. #### Notes - The carousel image upload flow added in v8.88.12 (`public/uploads/carousel_images/loc{id}_c{slot}_{ts}.{ext}`) is what makes this end-to-end — uploads recorded against each branch now appear on that branch's customer display. - The display.blade.php JavaScript already streams the live order summary from `localStorage` written by the POS create screen, so reopening the customer display in a separate browser/window picks up the cashier's current order automatically; no per-location coordination is needed there. --- ## Version 8.88.17 **Release Date:** 2026-05-26 ### Module: Business Settings — Phase 10 Session Overlay (session('business') made location-aware) #### New Features - **`session('business')` now carries the per-location Business Settings overlay** for the active user. Every legacy callsite that reads `session('business.pos_settings')` or `session('business.common_settings')` directly (across receipts, printing, payment popups, customer-display feeds, and dozens of view partials) now transparently sees the active branch's overlay rather than the flat global record — no per-callsite change required. - Resolution priority for the session overlay: **open cash register location → user's `default_location` → flat global**. This matches POS create() and Direct Sale create() resolution exactly. #### Improvements - Opening a cash register **immediately refreshes** `session('business')` so the very next request (the POS create screen) reads the per-location overlay without having to wait for a session expiry. - Closing a cash register **resets** `session('business')` back to the flat global record, ensuring no stale per-location values bleed into screens that are accessed after the register is closed (cash register close report, dashboard, etc.). - Login bootstrap (`SetSessionData` middleware) also applies the overlay when the user already has an open register, so re-authenticating after a session timeout restores per-location settings. #### Technical Updates - [app/Http/Middleware/SetSessionData.php](app/Http/Middleware/SetSessionData.php) — added effective-location resolver after `Business::findOrFail()`; when a location is resolved, `$business->setLocationContext($effective_loc_id)` is applied before `session()->put('business', $business)`. - [app/Http/Controllers/CashRegisterController.php](app/Http/Controllers/CashRegisterController.php) `store()` — after register creation, refetches `Business`, applies `setLocationContext($location_id)`, and re-puts it into `session('business')`. - [app/Http/Controllers/CashRegisterController.php](app/Http/Controllers/CashRegisterController.php) `postCloseRegister()` — after closing the register, refetches the flat `Business` and re-puts it into `session('business')` so subsequent reads return the global record. #### Notes - This phase **does not change** any per-callsite code that reads `session('business.*')`. The overlay is applied on the *write* side (when `session('business')` is set), so every existing read benefits automatically. - Behaviour is unchanged for businesses that have no per-location overlay configured — the flat values are returned in both cases. - The earlier per-controller `getDetails($business_id, $location_id)` threading (Phases 6–9) and the session-level overlay introduced here are complementary: controllers that *explicitly know* the transaction's location keep using the explicit path; everything else falls back to the session overlay. --- ## Version 8.88.16 **Release Date:** 2026-05-26 ### Module: Business Settings — Phase 9 Runtime Overlay Activation (Direct Sale + Sell Return Create/Edit) #### New Features - **Direct Sale create form** (`SellController@create`) now applies the per-location Business Settings overlay using the same resolution as POS create(): open cash register → user's `default_location` → flat global fallback. Per-branch `pos_settings` / `common_settings` (commission-agent requirement, payment-method visibility, customer header/footer, etc.) shown on the direct-sale form now reflect the branch the user is operating from. - **Sell Return create form** (`SellReturnController@create`) uses the same priority chain and overlays the active cash-register / default-location branch. - **Sell Return edit form** (`SellReturnController@edit`) now overlays the *return's own location*, so reopening an existing return from any workstation produces the same per-location commission-agent rules and pos_settings the originating branch would have used. #### Improvements - Resolution helper logic mirrors POS create() exactly (`register_details->location_id` first, then `user_settings.default_location`, then `null`) keeping behaviour consistent across the three sale-creation surfaces (POS, Direct Sale, Sell Return). - Sell Return edit no longer relies on the user's session location to decide whether the commission-agent dropdown is required — it now reads `sales_cmsn_agnt` and `is_commission_agent_required` from the return's branch overlay. #### Technical Updates - [app/Http/Controllers/SellController.php](app/Http/Controllers/SellController.php) `create()` — inserted effective-location resolver (cash register first, then `user_settings.default_location`); call is now `getDetails($business_id, $effective_loc_id)`. - [app/Http/Controllers/SellReturnController.php](app/Http/Controllers/SellReturnController.php) `create()` — same effective-location resolver and overlay call. - [app/Http/Controllers/SellReturnController.php](app/Http/Controllers/SellReturnController.php) `edit($id)` — `Transaction::find($id)` (the sell return) is now loaded *before* `getDetails()` so the per-location overlay for the return's branch can be applied: `getDetails($business_id, $sell_return ? $sell_return->location_id : null)`. #### Notes - These were the last "creation/edit form" callsites of `getDetails($business_id)` that materially affected sale-flow rendering. The remaining `getDetails($business_id)` callsites (StockAdjustmentController keyboard-shortcut lookup, etc.) read flat-only settings and were intentionally left untouched. No data migrations or schema changes; flat-record behaviour is unchanged for legacy callers. --- ## Version 8.88.15 **Release Date:** 2026-05-26 ### Module: Business Settings — Phase 8 Runtime Overlay Activation (Sale Lifecycle & FBR) #### New Features - **Per-location Business Settings now apply through the full sale lifecycle.** In addition to the POS create screen (Phase 6) and receipt/PDF rendering (Phase 7), the per-location overlay is now applied during sale store, sale update, sale edit, sale show, sell-line lookup, multipay payment section, and FBR/FBR DI invoice posting. The same branch-specific `pos_settings` / `common_settings` are seen everywhere a single transaction is being processed. - **FBR and FBR Digital Invoicing** posts now use the per-location overlay, so per-branch `pos_settings` toggles (e.g. payment method exposure, tax behaviour) and `common_settings` (header/footer text used in invoice payloads) are honoured for the branch the sale belongs to rather than the global business defaults. - **`getSellLineRow()` reads per-location pos_settings** — toggles such as `allow_overselling` and `restrict_sale_of_so_qty` now resolve per the location the line is being added against. #### Improvements - Editing an existing sale (POS or direct sale) now overlays the transaction's location: `pos_settings`, `common_settings`, and any per-location flags read by the edit screen come from the sale's branch rather than the user's current session location. - Showing a direct sale (`SellController@show`) overlays the sale's location so the **Show Sale** screen mirrors what the originating branch would render. - Multipay payment section overlays the location supplied in the request so per-location payment-method toggles render correctly inside the popup. #### Technical Updates - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php): - Sale **store** flow (~L1137) — `getDetails($business_id, $input['location_id'] ?? null)` before `mapPurchaseSell()`. - **FBR** posting (~L1843) — `getDetails($business_id, $location_id)`. - **FBR DI** posting (~L2315) — `getDetails($business_id, $location_id)`. - Sale **edit** view (~L2557) — `Transaction::findorfail($id)` fetched *before* `getDetails($business_id, $transaction->location_id)` so the edit form's `pos_settings` / `common_settings` match the sale's branch. - Sale **update** flow (~L3274) — `getDetails($business_id, $input['location_id'] ?? null)` before `adjustMappingPurchaseSell()`. - **`getSellLineRow()`** (~L3707) — reuses its `$location_id` parameter: `getDetails($business_id, $location_id)`. - Sale **refresh / stock-decrement** flow (~L6155) — `getDetails($business_id, $transaction->location_id)`. - [app/Http/Controllers/SellController.php](app/Http/Controllers/SellController.php): - **show()** (~L1330) — `getDetails($business_id, $sell->location_id)`. - **edit()** (~L1399) — `Transaction::findorfail($id)` fetched *before* `getDetails($business_id, $transaction->location_id)`. - **multipayPaymentSection()** (~L2371) — `$location_id` resolved from the request first, then `getDetails($business_id, $location_id)`. #### Notes - Direct-sale **create()** form in `SellController` and Sell Return **create()** / **edit()** flows are intentionally left for follow-up phases (they need careful default-location resolution similar to POS create()). All callsites that did *not* receive a location id continue to read the flat global record — no behavioural change for legacy callers. - Per-location runtime activation remains fully transparent for businesses that have no per-location overlay configured: in that case the per-location and flat reads return identical values. --- ## Version 8.88.14 **Release Date:** 2026-05-26 ### Module: Business Settings — Phase 7 Runtime Overlay Activation (Receipt & PDF Generation) #### New Features - **Receipt printing now honours per-location Business Settings.** When a sale receipt is rendered for printing (POS thermal/browser preview) or as a PDF (email/download), the per-location overlay for that *transaction's* location is now applied — so customer payment header/footer, invoice-related toggles, payment-method visibility, and other per-location `common_settings` / `pos_settings` values come from the branch that recorded the sale, not from the flat global record. - **Sale Return receipts** follow the same rule: the return slip is rendered using the overlay of the location the return belongs to. #### Improvements - Receipt and PDF rendering no longer depend on the cashier's current session location — they always overlay using the *transaction's* `location_id`, so reprinting an old sale from any workstation produces the same per-location header/footer/payment configuration it would have produced at the original branch. #### Technical Updates - [app/Utils/TransactionUtil.php](app/Utils/TransactionUtil.php) `getPdfContentsForGivenTransaction()` — `Transaction::findOrFail($transaction_id)` is now resolved *before* `BusinessUtil::getDetails()` so the call becomes `getDetails($business_id, $transaction->location_id)` and the resulting `$business_details` carries the per-location overlay for receipt/PDF rendering. - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) `receiptContent()` — `getDetails($business_id, $location_id)`; the existing `$location_id` parameter is reused. - [app/Http/Controllers/SellReturnController.php](app/Http/Controllers/SellReturnController.php) `receiptContent()` — same change for sale-return receipts. #### Notes - Scope is intentionally limited to the **receipt/PDF rendering paths** (`receiptContent`, `getPdfContentsForGivenTransaction`). The other `getDetails($business_id)` callsites in sale create/store/show/print flows continue to read the flat global record and will be wired in follow-up phases. No data migrations or schema changes; behaviour for businesses that have no per-location overlay is unchanged. --- ## Version 8.88.13 **Release Date:** 2026-05-26 ### Module: Business Settings — Phase 6 Runtime Overlay Activation (POS Create Screen) #### New Features - **POS sale screen now reads per-location Business Settings at runtime.** When a cashier opens a POS screen, the per-location overlay for that cash register's location is applied to `$business_details` — so values such as customer display screen toggle, display screen heading, carousel images (slots 1–10), payment-method toggles, customer payment header/footer, cash-pull limit, reward-point block, etc. are sourced from that branch's own overlay rather than the flat global record. - The user's `user_settings.default_location` preference is honoured as a fallback when no cash register is bound, so a user with a fixed branch sees their branch's overlay even before opening a register. #### Improvements - `BusinessUtil::getDetails()` now accepts an optional second argument (`$location_id`). The internal request-cache is keyed per `(business_id, location_id)` pair, so callers that pass a location id always get an overlayed copy and callers that pass no id continue to receive the flat global record. Existing callsites are unaffected. - Smoke verified end-to-end: `getDetails(1)` returns the flat global record (no overlay leak); `getDetails(1, 13)` returns a Business whose `common_settings` and decoded `pos_settings` reflect the location 13 overlay values. #### Technical Updates - [app/Utils/BusinessUtil.php](app/Utils/BusinessUtil.php) `getDetails($business_id, $location_id = null)` — extended signature; cache key is now `"{business_id}:{location_id|flat}"`; when a location id is supplied the fetched `Business` is wrapped with `setLocationContext((int) $location_id)` so subsequent attribute reads go through the per-location overlay machinery. - [app/Http/Controllers/SellPosController.php](app/Http/Controllers/SellPosController.php) `create()` — resolves an *effective location id* from `$register_details->location_id` (preferred) or the authenticated user's `user_settings.default_location`, and passes it to `getDetails()`. The rest of the method is unchanged; `$pos_settings = json_decode($business_details->pos_settings, true)` (around line 338) now transparently receives the per-location merged JSON. #### Notes - Scope is intentionally limited to the **POS create() view**. Sale persistence, payment processing, checkout, and other controllers continue to call `getDetails($business_id)` without a location id and see no behavioural change. Per-location runtime activation for other surfaces (receipt printing, customer-facing display, reward-point earn/redeem) will be addressed in follow-up phases. --- ## Version 8.88.12 **Release Date:** 2026-05-26 ### Module: Business Settings — Display Screen Carousel Images Per-Location #### New Features - **Display Screen carousel images (slots 1–10) are now stored per location.** Previously the file inputs on the Display Screen tab had no backend handler at all — uploads were silently discarded. Each branch can now upload its own set of carousel images and the page-level *Business Location* dropdown switches between them. - The Display Screen tab now shows the **filename of the currently saved image** for each slot (clickable, opens the image in a new tab), so admins can see what is configured for the active location before deciding whether to replace it. #### Improvements - Uploaded carousel images are saved to `public/uploads/carousel_images/` using a filename prefixed with the location id (`loc{id}_c{slot}_{timestamp}.{ext}`) to avoid collisions between branches. - Saving from a non-primary location only updates that location's overlay — the primary location's carousel filenames remain in the flat `pos_settings` JSON untouched. Saving from the primary location updates both the flat column and the primary's overlay (kept in sync). - Empty slots are preserved on save: if a slot's file input is left blank, the existing filename for that slot is retained rather than being wiped. #### Technical Updates - Model: `App\Business::PER_LOCATION_POS_SETTINGS_KEYS` extended with `carousel_image_1` … `carousel_image_10` so the existing overlay machinery routes them to per-location storage. - Controller: [app/Http/Controllers/BusinessController.php](app/Http/Controllers/BusinessController.php) `postBusinessSettings()` gained a carousel-image upload block before `pos_settings` is JSON-encoded. The block resolves the active location id from the posted hidden field (falling back to session, then primary), creates the destination directory if missing, validates mime type, and writes new filenames into `$pos_settings`. - Partial: [resources/views/business/partials/settings_display_pos.blade.php](resources/views/business/partials/settings_display_pos.blade.php) now renders a link to the currently saved image filename beneath each slot's file input when one exists for the active location. #### Notes or Important Considerations - Old carousel image files are **not** auto-deleted when replaced. The previous file is simply orphaned in `public/uploads/carousel_images/`. Cleanup can be added in a follow-up if storage growth becomes a concern. - The runtime POS customer-display screen (`resources/views/sale_pos/display.blade.php`) still reads `pos_settings['carousel_image_$i']` from whatever Business instance the controller loads. Until the runtime controller is threaded with the transaction's `location_id` and calls `$business->setLocationContext($location_id)`, the display screen will continue to show the primary location's carousel images at every terminal. This runtime threading remains the next planned phase. --- ## Version 8.88.11 **Release Date:** 2026-05-26 ### Module: Business Settings — Date Range Tab Relocation #### UI / UX Changes - The **Date Range** tab has moved from the *Global Settings* card to the *Location-based Settings* card. Its values were already stored per location internally, but living under *Global* was misleading. - The in-tab *Business Location* dropdown has been removed from the Date Range tab. The tab now follows the page-level **Business Location** selector at the top of the Location-based Settings card, matching every other per-location tab. #### Improvements - Selecting a different location from the page-level dropdown now reloads the Date Range tab with that location's saved Sales/Ledger filter values. - Saving from a non-primary location updates only that location's entry inside `business.date_settings` and preserves all other locations' values (existing controller behaviour, now reachable through the unified location selector). #### Technical Updates - View: [resources/views/business/settings.blade.php](resources/views/business/settings.blade.php) — moved the `date_range` `` and `@include('business.partials.settings_date')` from the Global section into the Location-based section. - Partial: [resources/views/business/partials/settings_date.blade.php](resources/views/business/partials/settings_date.blade.php) — removed the visible `date_tab_location` select; replaced with a hidden input bound to `$active_settings_location`. Value bindings for Sales and Ledger selects now read `$date_settings[$__date_loc]` instead of `$date_settings[$default_location]`. - Controller: no changes — `BusinessController@postBusinessSettings` continues to read `date_tab_location` from the request and write only that location's slice into `business.date_settings`. --- ## Version 8.88.10 **Release Date:** 2026-05-26 ### Module: Business Settings — Phase 3 Per-Location Expansion (Display Screen + Payment) #### New Features - **Display Screen tab is now per-location.** Each branch can enable/disable its customer display screen independently and carry its own *Display Screen Heading*. Switching the **Business Location** dropdown in `Settings → Business Settings` reloads Display Screen with that branch's saved values; saves from a non-primary location update the overlay only and never alter the global defaults. - **Payment tab is now per-location.** All pos_settings + common_settings fields on the Payment tab — cash denominations, denomination-on screen + payment-methods + strict-check, quick cash buttons, sold/stock/drafts/expense/paid-purchase register toggles, cash register sync with workstations, payment-modal-amount-zero, payment note, hide pay+print on multipay, multipay-modal-enter action, cash pull + limit + warn interval, cheque posting ledger, customer/supplier/expense payment hide-address toggles, and customer/supplier/expense payment header + footer textareas — are all stored per location. #### Improvements - The two tabs were already grouped under *Location-based Settings* in the UI (8.88.9); this release makes the backend storage match the UI grouping so the values shown for each location actually persist as that location's values. #### Technical Updates - **Model:** `App\Business::PER_LOCATION_POS_SETTINGS_KEYS` extended with the Display Screen subset (`customer_display_screen`, `display_screen_heading`) and the Payment-tab pos_settings subset (~18 keys). - **Model:** `App\Business::PER_LOCATION_COMMON_SETTINGS_KEYS` extended with the Payment-tab common_settings subset (`cheque_posting_ledger`, three `*_payment_hide_address` toggles, three `*_payment_header` + two `*_payment_footer` textareas). - **Controller:** No changes — `BusinessController@postBusinessSettings` already iterates `PER_LOCATION_POS_SETTINGS_KEYS` and `PER_LOCATION_COMMON_SETTINGS_KEYS` so adding to the whitelists is sufficient. #### Notes or Important Considerations - **Carousel images (`carousel_image_1` … `carousel_image_10`) are NOT yet per-location.** They are uploaded as file fields rather than stored in the `pos_settings` JSON and currently overwrite a single shared image per slot. Making them per-location requires dedicated file-path storage and is planned for a follow-up phase. - Runtime consumers (the actual customer-display screen rendering at the POS terminal, payment modals at checkout, cash register flows) continue to read the flat business columns; until those callsites are threaded with the transaction's `location_id`, only the primary location's values take effect at runtime. The Business Settings page itself does load and save per-location values correctly. --- ## Version 8.88.9 **Release Date:** 2026-05-26 ### Module: Business Settings — Move Display Screen & Payment to Location-based #### UI / UX Changes - **Display Screen** and **Payment** tabs moved from the *Global Settings* section to the *Location-based Settings* section in `Settings → Business Settings`. Both are closely tied to the POS terminal at each branch (customer-facing display, payment gateway keys / methods), so grouping them with the rest of the POS-related per-location tabs improves discoverability and matches how merchants think about them. - New tab order inside the Location-based section: *Tax → Product → Contact → Sale → POS → Display Screen → Payment → Purchase → Reward Point*. - Global Settings section now contains only truly business-wide tabs: *Business, Expenses, Dashboard, System, Date Range, SMS, Modules, Custom Labels*. #### Technical Updates - `resources/views/business/settings.blade.php` — swapped the two `@include('business.partials.settings_display_pos')` and `@include('business.partials.settings_payment')` calls (and their menu entries) from the Global section's `.pos-tab-container` into the Location-based section's `.pos-tab-container`. #### Notes or Important Considerations - This release moves the **UI placement only**. The Display Screen and Payment field-level per-location overlay (writing their values into `loc_settings['business_settings']`) is not yet wired — those fields continue to save to the flat business columns as before. A follow-up phase will extend `PER_LOCATION_SETTINGS` / `PER_LOCATION_POS_SETTINGS_KEYS` to cover Display Screen and Payment field whitelists so each location can carry its own values. --- ## Version 8.88.8 **Release Date:** 2026-05-26 ### Module: Business Settings — UI Reorganisation (Global vs Location-based) #### UI / UX Changes - **`Settings → Business Settings` is now split into two clearly-labelled sections, each with its own tab navigation:** - **Global Settings** (top section) — contains tabs whose values apply business-wide across every location: *Business, Display Screen, Payment, Expenses, Dashboard, System, Date Range, SMS, Modules, Custom Labels*. The location dropdown does **not** affect this section. - **Location-based Settings** (bottom section) — contains tabs whose values are stored per location and overlay the global defaults: *Tax, Product, Contact (Merchant), Sale, POS, Purchase, Reward Point*. The Business Location dropdown and "Copy settings from another location" button now live inside this section's header so it's visually clear they only apply here. - Each section is rendered as a card with a header, icon, and one-line description so admins can tell at a glance which settings are global and which are per-location. - Tabs are now grouped by scope rather than by historical ordering, making it easier to find related options and reducing the chance of saving a per-location setting while assuming it was global (or vice versa). #### Improvements - The Location dropdown banner is now embedded inside the Location-based Settings card, with its helper text removed from the page top and moved next to the dropdown — this removes confusion for single-location businesses (where the dropdown is still hidden) and clarifies the scope of the selector for multi-location businesses. #### Technical Updates - **View:** `resources/views/business/settings.blade.php` rebuilt into two `.settings-section-card` blocks, each containing its own `.pos-tab-container` (menu + content). The `active_settings_location` hidden field still drives both sections from the single form so saves continue to write the full payload in one POST. - **JS scoping:** `public/js/common.js` tab-switch handler is now scoped to the nearest `.pos-tab-container` ancestor, so clicking a tab in the Global section no longer toggles a pane in the Location-based section (and vice versa). Backward compatible — pages with a single container still behave exactly as before. - **View bootstrap:** A small inline script in `settings.blade.php` ensures the first `.pos-tab-content` of every container receives the `active` class on load, so the Location-based section opens on the *Tax* tab by default. - **Lang keys added:** `global_settings`, `global_settings_help`, `location_based_settings` in `resources/lang/en/lang_v1.php`. #### Notes or Important Considerations - No data model or save-path changes — all per-location overlay logic introduced in 8.88.6 (Phase 1) and 8.88.7 (Phase 2) continues to operate unchanged. This release is presentation-only. --- ## Version 8.88.7 **Release Date:** 2026-05-26 ### Module: Business Settings — Phase 2 Per-Location Expansion #### New Features - **POS tab, Sale tab, Purchase tab, and Product tab settings are now per-location.** Following the Phase 1 foundation (Tax / Reward Point / Weighing Scale), Phase 2 extends the per-location overlay to cover the bulk of operational toggles across POS, Sale, Purchase, and Product tabs. Switching the **Business Location** dropdown at the top of `Settings → Business Settings` now reloads these tabs with location-specific values; saving from a non-primary location writes only to that location's overlay and leaves the global defaults intact. - **POS tab pos_settings overlay** — per-location coverage for the entire POS-section pos_settings group (display toggles, takeaway 1/2/3, customer display, KOT printing, weighing scale link, prompt token, restrict-sale-total-zero, ask-deletion-reason, default types of service, default POS customer, inline-tax/discount columns, etc.). - **Sale tab pos_settings overlay** — per-location coverage for sale-specific pos_settings (allow overselling, amount rounding, commission calculation type, customer-based sell price, MSP, sales orders, quotations, payment links, Razorpay/Stripe/Dojo gateway keys, default sale customer, default types of service for sales, etc.). - **Sale tab common_settings overlay** — per-location coverage for sale common_settings (default invoice/item discount types & values 1+2, default sale status, bulk add serial numbers, change-search-filtering, disable bulk FBR sync, disable change-return-on-sale, additional expense, direct sale return, draft auto-save, inline discounts/tax/profit/product-note, layby + due days, scheme quantity, shipping details, total discount/tax 1+2, hide address info / pay term / SKU / customer-id, is-tax-inclusive, sale invoice design id, show invoice layout/scheme, last-customer-sold-price search, etc.). - **Purchase tab common_settings overlay** — per-location coverage for purchase common_settings (default purchase status, bulk add serial numbers, default invoice/inline discount types & values 1+2, additional expense, direct purchase return, inline discounts/tax/product-note, load products from quotation, purchase auto-save, purchase orders, purchase rack details, purchase requisition, scheme quantity, shipping details, total discount/tax 1+2, hide attach document / supplier-id / SKU, is-tax-inclusive, lot number label, purchase default supplier, purchase invoice design id, purchase item addition method, show invoice layout, supplier-based cost price, etc.). - **Product tab common_settings overlay** — per-location coverage for product common_settings (default product tax type, booking hourly services, custom fields, discount, drugs class, generic name + label, IMEI 1-4 + labels, prepration time, other product name + label, potency, prices, product brochure/description/image/warranty/weight, prompt msg, purchase price for purchased, secondary unit, serial number + label, stock issue/receive, hide brand/categories/custom fields/import/Not_for_selling/print labels/description/image/variations/selling price group/warranty/weight/Woocommerce, is-product-image-required, product custom labels textarea, ps_page_length, variation SKU suffix length, warn negative profit / same product name, etc.). - **Product / Purchase flat-column toggles per-location** — coverage extended for `enable_brand`, `enable_sub_brand`, `enable_category`, `enable_sub_category`, `enable_sub2_category`, `enable_gender`, `enable_sub_gender`, `enable_pct_code`, `enable_position`, `enable_price_tax`, `enable_procurement_source`, `enable_sub_procurement_source`, `enable_racks`, `enable_row`, `enable_sub_units`, `enable_lot_number`, `enable_editing_product_from_purchase`, `enable_purchase_status`, `p_exchange_rate`, `purchase_currency_id`, `purchase_in_diff_currency`, and `enable_inline_tax`. #### Improvements - Existing businesses are unaffected: the overlay is read on top of the flat business columns, so any location that has never been customised continues to see the global defaults. Saves from the **primary location** still write to both the flat columns and the overlay; saves from **non-primary locations** restore the flat pos_settings / common_settings values for the per-location keys before persisting so the global JSON stays anchored to the primary location. #### Technical Updates - **Model:** `App\Business` gains a new `PER_LOCATION_POS_SETTINGS_KEYS` constant (~100 keys covering POS + Sale tab pos_settings) and extends `PER_LOCATION_COMMON_SETTINGS_KEYS` with the Product, Sale, POS, and Purchase tab common_settings subsets. `getAttribute()` adds a special-case merge branch for `pos_settings` that decodes the flat JSON, merges the per-location overlay subset on top, and returns the result as a JSON-encoded string so existing callers (`json_decode($business->pos_settings, true)`) keep working unchanged. - **Controller:** `BusinessController@postBusinessSettings` now extracts the per-location `pos_settings` subset into the overlay alongside the existing flat + `common_settings` extraction. On non-primary saves, the controller restores per-location pos_settings keys from `getRawOriginal('pos_settings')` before re-encoding so the flat column keeps the primary location's values. - No database changes — the Phase 1 migration (`2026_05_26_140000_backfill_per_location_business_settings.php`) already provisions the `loc_settings['business_settings']` overlay container for every existing location. #### Notes or Important Considerations - Phase 2 still only writes overrides via the Business Settings UI. Runtime consumers (POS screen, Sales/Purchase forms, reports) continue to read the flat business columns, so the primary location's values remain authoritative for everyday transaction flows. A follow-up phase will thread the transaction's `location_id` into those consumers so per-location overrides take effect at runtime. --- ## Version 8.88.6 **Release Date:** 2026-05-26 ### Module: Business Locations — Location ID Auto-Generation #### Bug Fixes - **New Business Location IDs no longer restart from `BL0001`.** Previously, after creating locations `BL0001`, `BL0002`, `BL0003`, the next saved location could be assigned `BL0001` again (causing duplicate location codes in the list). The next code is now always one higher than the highest existing BL code stored for the business — so the next location after `BL0003` is correctly issued as `BL0004`, then `BL0005`, etc. #### Technical Updates - `BusinessLocationController@store` and `BusinessUtil::addLocation` now reconcile the `reference_counts` row for `business_location` against the actual maximum numeric suffix found in `business_locations.location_id` for the business before generating the new code. If the counter has drifted behind the data (for example after a migration that nulled out the per-location/year columns), it is fast-forwarded to `max(existing) + 1` and the corrected value is persisted back to `reference_counts`, so subsequent inserts continue from the right point. --- ## Version 8.88.6 **Release Date:** 2026-05-26 ### Module: Business Settings — Location-based Settings #### New Features - **Business Settings are now per-location.** A new **Business Location** dropdown appears at the top of `Settings → Business Settings`, above all tabs. Changing it instantly reloads every tab below (Tax, Product, Sale, POS, Purchase, Reward Point, Weighing Scale, etc.) with the values saved for that specific location. The banner is automatically hidden when a business has only a single location, so single-location customers see no UI change. - **Copy settings from another location.** A *Copy settings from another location* button next to the dropdown opens a modal where superadmins can pick a source location and a target location and copy the whole per-location settings overlay in one click. Useful when opening a new branch that should mirror an existing one. #### Improvements - Saving the Business Settings form now writes per-location overrides for the active location only. Saving from the **primary (first) location** continues to update the global business defaults (flat columns) so runtime callers that have not yet been migrated to per-location reads keep working exactly as before. Saving from any **non-primary location** only updates that location's overlay and leaves the global defaults untouched — so non-primary edits never silently change behaviour for other locations. - Tax tab, Product tab (SKU prefix, default unit, profit %, product-expiry block, code labels), Sale tab (default sales tax, default sales discount, sell-price tax, commission agent, item addition method, transaction edit days), POS / Sale / Purchase *allow currency change* toggles, Reward Point block, and Weighing Scale block all now support per-location overrides. The whitelist is centralised in `App\Business::PER_LOCATION_SETTINGS`. #### Bug Fixes - Fixed a 500 error on `Settings → Business Settings` for sessions without an active business row (e.g. fresh superadmin contexts). The new per-location overlay call is now guarded so the page renders safely when no business is bound to the session. #### Technical Updates - **New column reuse:** Per-location overrides are stored in the existing `business_locations.loc_settings` JSON column under a new sub-key `business_settings`. No new database column was introduced. - **Model:** `App\Business` gains `PER_LOCATION_SETTINGS` constant, `setLocationContext($locationId)` and an overridden `getAttribute()` that overlays per-location values for whitelisted keys while honouring existing casts (boolean / array). - **Helpers:** `App\Utils\BusinessUtil` gains `getLocationBusinessSetting()`, `setLocationBusinessSettings()` and `copyLocationBusinessSettings()`. - **Controller:** `BusinessController@getBusinessSettings` resolves the active location from session and calls `setLocationContext()` so existing tab partials need no changes. `BusinessController@postBusinessSettings` extracts whitelisted keys into the active location's overlay. Two new endpoints: `POST /business/set-active-settings-location` and `POST /business/copy-location-settings` (named `business.setActiveSettingsLocation` and `business.copyLocationSettings`). - **Migration:** `2026_05_26_140000_backfill_per_location_business_settings.php` seeds every existing location's `loc_settings['business_settings']` with a snapshot taken from the business's primary (first) location's existing overlay, or — if absent — from the business's flat columns. Locations that already carry a non-empty `business_settings` overlay are preserved (re-run safe). This guarantees zero behavioural change for existing customers on the main domain and all sub-domains. #### Notes or Important Considerations - This release covers the **Business Settings page** end-to-end (read overlay + per-location save + copy-between-locations). Runtime consumers across modules (POS, Sales, Purchase, Reports, etc.) continue to read flat business columns for now, which means they still see the primary location's values — exactly as they did before this change. A follow-up phase will thread the active transaction's location into those consumers so per-location overrides take effect at runtime as well. - The location dropdown banner persists its selection in session (`active_settings_location`), so navigating away and coming back keeps you on the same location. --- **Release Date:** 2026-05-26 ### Module: Sales — Add Sale (F10 Product Search) #### Bug Fixes - **The F10 Product Search popup on the Add Sale screen no longer gets stuck on "Processing…".** Opening the popup now loads your products list straight away so you can pick items and continue the sale without the page freezing. --- ### Module: Stock Transfer — Load Ingredients from Manufacturing Production #### New Features - **Load Ingredients from a Manufacturing Production transaction directly into a Stock Transfer.** On both the Add Stock Transfer and Edit Stock Transfer screens, a new *Production (Manufacturing)* dropdown lists recent Production transactions by reference number (and the produced product/variation). After selecting *Location From* and a production, click **Load Ingredients** to automatically add every consumed ingredient line from that production into the stock transfer item table. - Each ingredient row is added with the same quantity (already converted to the base unit) that was consumed by the selected production, so the stock transfer mirrors what the destination location needs to replenish what production used. #### Improvements - The existing **Load Ingredients from Demand Order** option is now also available on the Edit Stock Transfer screen (previously only on Add). #### Technical Updates - New route `GET /stock-transfers/production-ingredients/{id}` returns aggregated ingredient quantities (variation_id + quantity) from the paired `production_sell` transaction of a `production_purchase` (linked via `mfg_parent_production_purchase_id`). - New controller methods `StockTransferController@getProductionIngredients` and a private `getProductionsDropdown()` helper. Both Stock Transfer `create()` and `edit()` now pass `$productions` (and `$demand_orders`) to the views. - New JS handler `#load_production_ingredients` in `public/js/stock_transfer.js` reuses the existing `stock_transfer_product_row_with_qty()` row-insert path used by the demand-order loader. --- ## Version 8.89.3 **Release Date:** 2026-05-22 ### Module: Reference Numbers — Legacy Data Safety Pass #### Bug Fixes - **Contact, Warehouse, Username and Subscription package codes no longer reset to 1 after upgrading.** After upgrading to v8.89.2, businesses were seeing their next contact code start again from 1 instead of continuing from the previous number. The numbering now continues from where it left off (for example, a business with 46 existing contacts correctly starts the next one at 47). - Old, unused counter entries from previous versions are now tidied up automatically during the upgrade, so the system stays clean. #### Improvements - **All existing sales, purchases, payments, returns, transfers and other transaction numbers are kept exactly as they are.** The new numbering only applies to new transactions created after the upgrade. Nothing in your historical records is rewritten or changed in any way. - Old and new format transaction numbers will appear side-by-side in your ledger after the upgrade. This is normal — both formats are fully supported across receipts, reports and tax exports. #### Notes or Important Considerations - **Your existing transactions, payments, ledger entries and account postings are not touched in any way.** Only the next-number counters used for future transactions were tidied up. - If you ever set a *different* Contact Payment prefix on a single location's Prefixes tab, contact payments created there may show the regular Edit button instead of the bulk Contact Payment edit option. To avoid this, keep the Contact Payment prefix the same across business and locations (which is the default after upgrade). --- ## Version 8.89.2 **Release Date:** 2026-05-22 ### Module: Reference Numbers — Per-Location Transaction Numbering #### New Features - **Transaction numbers are now generated per business location.** New numbers follow the format *Prefix + Location Code + Year + 6-digit sequence* — for example, the first Purchase Invoice of 2026 at Location 01 is `PI012026000001`, and the first at Location 02 is `PI022026000001`. This works for every prefix on the *Business Location Settings → Prefixes* tab: Purchase, Purchase Order, Purchase Return, Sell Return, Payments, Stock Transfer, Stock Adjustment, Expense, Subscription, Token, Cash Register, Voucher prints and more. - **Numbering restarts on January 1st each year for every location, independently of other locations.** So each branch always starts a fresh sequence at `000001` at the start of every year. - **Each location can have its own prefix.** If a location has its own prefix set on the Prefixes tab, that prefix is used; otherwise the business-wide prefix is used. This lets you keep one prefix scheme globally while overriding individual branches when needed. #### Improvements - **Contact codes, Warehouse codes, Usernames and Subscription package codes stay on the existing global format.** These are not branch-specific by design. - **The system picks the right location automatically** based on the location you're working in. No screens or workflows need to change to benefit from the new numbering. #### Notes or Important Considerations - **Already-issued transaction numbers are untouched.** Only new transactions use the new format. - **Each location starts at `000001` for each transaction type.** If a branch already had purchases under the previous numbering, the first new-format purchase will be `PI012026000001` even if an older number like `PI2026/0042` exists. The two numbering schemes simply run side by side. - **Locations beyond 99 get a 3-digit code automatically** (`100`, `101`, and so on). --- ## Version 8.89.1 **Release Date:** 2026-05-22 ### Module: Business Location Settings — Per-Location Prefixes #### New Features - **Reference number prefixes are now set per business location.** A new **Prefixes** tab has been added inside *Business Location Settings* (Settings → Business Locations → Settings on any location). Every prefix that used to live on the global *Business Settings → Prefixes* tab — Purchase, Purchase Order, Purchase Return, Sell Payment, Sell Return, Stock Transfer, Stock Adjustment, Expense, Contact, Token, Cash Register and all voucher labels — can now be set per location so each branch can have its own prefix scheme. #### Improvements - The global **Prefixes** tab has been removed from *Business Settings*. - During the upgrade, each location is automatically filled with the prefixes you previously had at the business level, so no prefix is lost. #### Notes or Important Considerations - This release moves the **storage and editing** of prefixes to the location level. The prefix shown on a freshly issued reference number is still based on the business-level value in this release. A follow-up release routes the generator to read each location's own prefix and per-location counters, completing the `PI012026000001` / `PI022026000001` / `PI032026000001` numbering scheme. ### Module: User Profile — Email (SMTP) Settings #### New Features - **Email (SMTP) settings are now configured per user.** Each staff member can set their own outgoing mail server from **My Profile → Email Settings (SMTP)**, with fields for Mail Driver, Host, Port, Username, Password, Encryption, From Address, From Name, and a *Verify SMTP certificate* option. A **Test email configuration** button lets you send a test message before saving. #### Improvements - The **Email Settings** tab has been removed from *Business Settings*. - Outgoing notification emails now use the logged-in user's own email settings instead of a single shared business setting. #### Notes or Important Considerations - Existing business-level SMTP details are no longer used. Re-enter your SMTP credentials under **My Profile → Email Settings** on first login. - For automatic/background emails (such as scheduled payment reminders) the system uses the **business owner's** email settings, so make sure the business owner account has valid SMTP credentials configured. --- ## Version 8.89.0 **Release Date:** 2026-05-22 ### Module: Sales — Layby (Lay-by-away) #### New Features - **Layby sale workflow added.** Cashiers can now mark a sale as a **Layby** at the point of sale. A new **Sub Status** dropdown appears on the Add Sale screen — choose **Layby** to reserve stock for a customer who pays in instalments. When Layby is chosen, a new **Layby Due Date** field appears (auto-filled with today + the default number of days set in Sales settings) so the agreed final-payment date is captured up front. - **Stock reservation while the customer pays.** Selecting **Layby** behaves like a normal final sale for stock: the goods are deducted from `Available Stock` immediately so they cannot be sold to anyone else while the layby is active. The invoice is created in the normal way and the outstanding balance is tracked as a regular Due / Partial payment. - **Automatic stock release after the due date.** If the customer has not paid the balance in full by the **Layby Due Date**, the system automatically releases the reserved items back into stock so they are available for sale again. The invoice itself stays in the system marked as **Layby Released** — the outstanding balance remains so any further payments / refunds can still be processed manually, and the customer history is fully preserved. - **Feature is opt-in per business.** Layby is disabled by default. Enable it from **Settings → Business Settings → Sales** with the new toggle **Enable Layby sales**, and configure **Default Layby Due Days** (default 30) on the same screen. #### UI / UX Changes - **Sub Status** dropdown shown next to **Sale Status** on the Add Sale screen, only when Layby is enabled in Sales settings and the form is not a draft / quotation. Selecting **Layby** reveals the **Layby Due Date** picker. --- ### Module: POS — Quick Menu Buttons & Product Suggestion #### Bug Fixes - **Quick menu product buttons now show the correct price for each business location.** If a business location has a **Default Selling Price Group** set (configured under *Business Locations → Edit → Default Selling Price Group*), the price shown on each product button in the quick menu panel now comes from that location's price group — not the product's default selling price. Previously, every location always showed the default selling price on the buttons, regardless of which price group was assigned to that location. - **Product suggestion tiles also now show the correct location price.** The same fix applies to the **Show Product Suggestion** POS layout — product tiles in the suggestion panel now display the price from the current location's price group when one is set, falling back to the default price only when no price group is configured for the location. --- ### Module: User Management — Roles & Permissions #### New Features - **Control which business locations a staff member can see suppliers from.** On the Role create and edit pages, inside the **Contacts** tab under the Supplier section, two new radio button options are now available: **View all Locations supplier** — the user can see suppliers from every business location; and **View Locations own supplier** — the user can only see suppliers linked to their own location. Select whichever option fits the role. - **Control which business locations a staff member can see customers from.** In the same **Contacts** tab under the Customer section, two matching options are now available: **View all Locations Customer** — the user can see customers from every location; and **View Locations own Customer** — the user can only see customers belonging to their own location. Use this to prevent staff from one branch viewing another branch's customer list. --- ### Module: Offline Sync — Download #### Improvements - **Selling price groups are now downloaded as part of the Products Sync.** When you press **Sync Products** on the **Synchronization → Download** tab, the system now also downloads all your **Selling Price Groups** (your named pricing tiers, e.g. "Wholesale", "VIP", "Retail") into the offline terminal. Previously, price group names could be missing after a fresh sync, which caused price-group dropdowns to appear empty on the POS. - **Group / tier prices on each product are now fully synced.** Every special price set per price group on a product (for example, a lower wholesale price or a VIP price) is now downloaded and saved alongside the product. After a sync, cashiers can correctly apply any price group to a sale — and the right price will appear — without needing an internet connection. Previously, only the default selling price was saved; price-group prices were silently skipped. --- ## Version 8.88.0 **Release Date:** 2026-05-21 ### Module: Reports — Product Sale Report & Combo Items Report #### Bug Fixes - **Product search now shows clean names in the filter bar.** On both the **Product Sale Report** and the **Combo Items Report** filter panels, typing in the **Search Product** box now shows a clean, readable list of matching products. Previously the dropdown suggestions contained broken-looking text with extra code symbols (such as `
Price:`) mixed into the product name. Selecting a product from the list also fills the search box with the plain product name only — no stray symbols or extra text. --- ### Module: Products — Categories #### New Features - **"Not for selling" option added to product categories.** A new **Not for selling** checkbox now appears on the Add Category and Edit Category pop-ups (under Products → Categories). It is unticked by default. When you tick it for a category, that category is hidden from the POS Sale screen — it will no longer show in the **Product Suggestion** category dropdown or as a tile on the **Big Buttons** touchscreen layout. The category continues to appear normally everywhere else, including the product list, reports, and purchase screens, so the products inside it stay categorised as before. This is useful for back-office-only categories (such as raw materials or internal-use items) that you do not want cashiers to see during a sale. --- ### Module: POS — Big Buttons Touchscreen Layout #### New Features - **New "Big Buttons" POS screen layout.** A fourth option has been added to *Settings → Business Settings → POS → POS Screen Interface*, alongside *Simple*, *Show Product Suggestion*, and *Enable Quick Buttons*. When you choose **Big Buttons**, the POS Sale screen turns into a full touchscreen till designed for 15-inch shop counter screens, with everything visible in one window — no page scrolling needed. - **Large category tiles** for quick item lookup, automatically built from your product categories. Tap a category to load its products. - **Built-in numpad and quick-cash buttons** — full 1–9 / 0 / 00 / CE pad with £5, £10, £20, £30, £40, £50, and £100 quick-cash buttons. - **Helper buttons** — **Misc. Item**, **EXACT** (auto-fills Tendered with the Total Payable), and **Subtotal**. - **Tendered and Last Change fields** so cashiers can see the cash given and change due at a glance. - **Large action buttons** — colour-coded **PAY** (cash), **CARD**, and **Voucher** buttons, sized for easy touch. - **Top header bar** showing the cashier name, business location, **HOME** shortcut, a big search field, **Clear** button, customer selector, and a live clock. - **Footer utility bar** with **EXIT**, **Logout**, **Setup**, **Sales**, **Open Till**, **Payouts**, **Fullscreen**, **Lookup Item**, and **Show/Hide Keyboard** shortcuts. - **Hold and Resume** buttons for parking a sale and bringing it back later. #### Improvements - The Big Buttons screen uses the same underlying sale form as the regular POS, so all existing features — autocomplete search, taxes, discounts, customer group pricing, suspend / draft, multi-payment, offline sync, and printing — continue to work exactly as before. - **PAY** opens the standard Multi-Pay finalize flow, **CARD** runs the express card payment flow, and **Lookup Item** opens the existing product search pop-up — so there is one consistent payment process across all interfaces. - The other three layouts (**Simple**, **Show Product Suggestion**, **Enable Quick Buttons**) are unchanged. Big Buttons only activates when it is selected for a business location. #### UI / UX Changes - High-contrast UK till colour scheme — navy header and footer, yellow search field, red **PAY**, blue **CARD**, and amber **Payouts** — for clear visibility under shop lighting. - All buttons are sized for finger touch, with primary **PAY** and **CARD** buttons made extra large for accurate tapping. - The full till fits in one screen so cashiers do not need to scroll. On tablets and phones, the layout switches to a single column so it remains usable. --- ### Module: Products — Stock Maintenance #### New Features - **New "Stock Maintenance" button at the bottom of the Products list.** Tick one or more products in the list, then click **Stock Maintenance** to apply a bulk action to all of them at once. - **Bulk Tax Assignment.** Inside Stock Maintenance, choose **Tax** as the maintenance type, pick the tax rate from the dropdown, and click **Apply** — the selected tax is set on all chosen products in one step. - **Bulk Tax Removal.** The same Tax dropdown also has a **None (Remove Tax)** option. Pick it and click **Apply** to remove the tax from all selected products in one go. --- ### Module: Stock Transfer #### Improvements - **Editing a stock transfer now updates stock at both locations correctly.** When you save changes to a transfer, the system first cancels the previous stock movement at both the From and To locations, then re-applies the movement based on your updated products and quantities. Adding, removing, or changing the quantity of any item is reflected accurately at both ends — with no double-counting and no leftover stock. - **Destination cost is now worked out from the source location's real cost.** The purchase price recorded at the destination is calculated automatically from the oldest stock at the source location (using FIFO), instead of using the price typed in the form. This keeps your cost-of-goods and profit reports accurate after a transfer. If the source has no purchase history, the system uses the price you entered as a fallback. - **Edits to completed transfers now keep cost history clean.** The internal links between sold items and the source purchase lines they came from are properly rebuilt when you edit, so FIFO / LIFO / Average cost reports continue to match what was actually moved. #### Bug Fixes - Fixed an issue where editing a stock transfer and adding or removing products could leave leftover (orphaned) records at the destination. - Fixed an issue where changing the quantity on an in-transit transfer and then completing it could move the wrong amount of stock. - Fixed a small warning message on the Stock Transfer Edit page when loading the "added by" user list. #### UI / UX Changes - On the Stock Transfer Edit page, the **Stock Type**, **Category**, and **Load Products** controls are no longer locked when a transfer is marked **Completed** — so you can revise them as part of an edit. --- ### Module: Stock Transfer — List #### Bug Fixes - Fixed an issue on the Stock Transfers list where the **Update Status** pop-up's dropdown options were appearing behind the pop-up. The status dropdown now opens correctly on top. - The **Edit** button on the Stock Transfers list now also appears for transfers in the **Completed** status. Previously it was hidden for completed transfers, even though the Edit page itself supported editing them. --- ### Module: User Management — Roles & Permissions #### New Features - **New "Edit Stock Transfer" permission added to the Stock Transfers tab on the Role create/edit page.** You can now grant the ability to edit existing stock transfers separately from the "Add Stock Transfer" permission. Go to **Roles → Edit a role → Stock Transfers tab** and tick **Edit Stock Transfer** for the roles that need it. #### Improvements - The **Edit** button on the Stock Transfers list and the Edit Stock Transfer page now check the new dedicated permission. Existing roles that already had **Add Stock Transfer** continue to work as before, so nothing needs to be reconfigured. --- ### Module: Manufacturing — Recipe #### Bug Fixes - **Ingredient cost now shows correctly when a manufactured product is used inside another recipe.** If a product has its own recipe (for example, "Sada Barfi" is itself manufactured), and you use that product as an ingredient inside another recipe, the Price column for that ingredient was showing Rs 0.00. It now correctly shows the cost calculated from its own recipe. #### UI / UX Changes - **Product SKU is now shown in brackets next to the product name on the Recipe edit page.** For example, the heading now reads "Product: Yellow Cham Cham - Only Demand (1096)" — so you can confirm at a glance which product you are editing without going back to the recipe list. --- ### Module: Manufacturing — Productions Report #### New Features - **Productions Report redesigned with three tabs.** Instead of one long table, the report is now split into three focused views you can switch between with a single click: - **Totals** — a day-by-day summary showing how many productions ran, how many were finalised vs. draft, and the combined labour cost, overhead, and total value for each day. - **Production Detail** — one row per production, showing the batch number, status, priority, expected and actual quantities, yield efficiency, due date, and all cost figures. - **Raw Materials Used** — a breakdown of every ingredient used across the selected productions, with quantities, waste, net quantity, unit cost, and total cost. #### Improvements - **Quantity columns now follow your Quantity Decimals setting.** All quantity fields (Expected Qty, Actual Qty, Total Qty, Waste Qty, Net Qty) display the same number of decimal places set in **Business Settings → Business → Quantity Decimals**. - **Currency symbol shown only in the column header, not on every row.** Cost columns (Labour Cost, Overhead Cost, Total Cost, Unit Cost) show clean numbers in each row; the currency symbol appears once in the header — making tables easier to read. - **All number columns are right-aligned** across the three tabs for cleaner reading. - **The date filter now defaults to Today** when you first open the report. - **The Raw Materials tab has the same standard controls as other reports** — choose how many rows to show, search or filter the list, and export to CSV, Excel, or PDF. #### UI / UX Changes - Removed the **Print** button from the filter bar where it was incorrectly placed. --- ### Module: Manufacturing — Production #### Improvements - **Change a production's status straight from the Production list — no need to open the record.** Each status badge (Planned, In Progress, Quality Check, On Hold, Cancelled) in the list is now clickable. Click it to open a small pop-up, choose the new status, and save in one click. The list refreshes automatically after saving. Productions that are already **Completed** cannot be changed from the list, and their badge stays non-clickable. --- ### Module: Reports — Product Purchase Report #### New Features - **Two new tabs added: "By Sub-Category" and "By Sub2-Category".** The Product Purchase Report now has two additional grouped views alongside the existing "By Category" tab. - **By Sub-Category** — purchases grouped by the second level of your categories. For each sub-category you can see the total quantity purchased and the total purchase value — useful for comparing spend at the sub-category level. - **By Sub2-Category** — the same view grouped by the third level, giving a more detailed breakdown if your business uses three category levels. These tabs appear automatically when Sub-Categories and Sub2-Categories are turned on in business settings. All filters in the report — date range, location, supplier, brand, category, and the sub-category dropdowns — apply to these tabs in the same way. --- ## Version 8.87.6 **Release Date:** 2026-05-18 ### Module: Reports — Report 607 (Sale) #### Bug Fixes - **Footer totals on the Report 607 (Sale) page no longer show stale values when a filter returns no transactions.** Previously, after a filter (such as a date range with no matching sales) was applied, the Total (Exc. Tax), Discount, Tax, and Total (Inc. Tax) row in the footer kept displaying the amounts from the previous result instead of resetting to 0. The footer is now recomputed from the server's response on every filter change, so the totals always match the rows currently shown — including showing all zeros when "No data available in table" is displayed. --- ## Version 8.87.6 **Release Date:** 2026-05-18 ### Module: Manufacturing — Dashboard #### New Features - **Manufacturing Dashboard has a completely new modern look.** The dashboard has been redesigned with a clean, professional style. Key numbers such as Total Productions, Total Production Value, QC Pass Rate, and Overdue Productions are now displayed as large, colour-coded cards at the top of the page so you can see the most important information at a glance. - **Production Status chart added to the dashboard.** A visual doughnut chart now shows how your productions are spread across all statuses — Planned, In Progress, Quality Check, Completed, On Hold, and Cancelled — so you can instantly see the overall picture without reading rows of numbers. - **Priority breakdown chart added to the dashboard.** A horizontal bar chart now shows how many active productions are in each priority level (Urgent, High, Normal, Low), making it easy to spot if there are too many urgent or overdue items piling up. - **Quality Control summary now includes a pass-rate progress bar.** The QC section now shows Passed, Failed, and Pending counts side by side with a colour-coded progress bar that visually indicates the overall pass rate percentage. - **"Added By" column added to the Production list.** The Production list now shows who created each production record in the last column, so you can easily track which team member added each entry. - **"Added By" column added to the Demand Order list.** The Demand Order list now shows who created each demand order in the last column, making it easier to follow up with the right person. #### Improvements - **Business Location filter and Date Range filter on the dashboard now apply immediately.** Previously, you had to click the Refresh button after selecting a location or date range for the data to update. Now, as soon as you pick a date range or choose a location, the dashboard automatically reloads and shows the filtered results — no extra button click needed. - **The selected Business Location is remembered after filtering.** After filtering the dashboard by a specific location, the dropdown now stays set to that location when the page reloads, instead of resetting back to "All". --- ## Version 8.87.6 **Release Date:** 2026-05-17 ### Module: Manufacturing — Security & Permissions #### Bug Fixes - **Manufacturing Reports were visible to users who had no report permission.** Users such as cashiers who only had production or dashboard access could still see the full Reports section (Manufacturing Report, Recipe Report, Demand Order Report, Demand Ingredient Report) in the Manufacturing menu. The Reports section now only appears if at least one report permission — "Access Manufacturing Reports", "View Manufacturing Report", "View Recipe Report", "View Demand Order Report", or "View Demand Ingredient Report" — is specifically enabled in the user's security role. - **Demand Ingredient Report was accessible to any user with Demand Order access.** A user who had the "Access Demand Orders" permission could open the Demand Ingredient Report even without the "View Demand Ingredient Report" permission. These two permissions are now fully independent. Opening the Demand Ingredient Report now requires either "View Demand Ingredient Report" or "Access Manufacturing Reports" to be enabled. - **Demand order status could be changed by users without the Approve permission.** Cashier users could click the status badge on the Demand Order list and move a demand order to any status — including "Approved" — even though the "Approve Demand Order" permission was not enabled in their security role. Now, changing a demand order's status (to any value, including Approved, In Production, or Completed) requires the "Approve Demand Order" permission. The "Edit Demand Order" permission continues to cover editing the order's content — items, quantities, dates, and notes — but no longer controls status changes. --- ## Version 8.87.6 **Release Date:** 2026-05-17 ### Module: Manufacturing — Production #### Improvements - **Production status now automatically changes to "Completed" when you tick Finalize.** Previously, if you had manually set the production status to something other than "Completed" (for example "In Progress" or "Quality Check"), ticking the Finalize checkbox and saving would finalize the stock — but the status badge on the list would still show the old status. Now, whenever you tick **Finalize** and save (on both the Add Production and Edit Production pages), the production status is automatically set to **Completed** regardless of what was selected in the status field. This keeps the status badge and the actual finalized state in sync without any extra steps. --- ## Version 8.87.6 **Release Date:** 2026-05-17 ### Module: Manufacturing — Production #### Bug Fixes - **Recipe Instructions now appear when you select a product on the Production Create page.** Previously, the Recipe Instructions field would always stay blank even after choosing a product. It now correctly fills in with the instructions saved on the recipe as soon as a product is selected. - **Recipe Instructions on the Production Edit page now load correctly.** Opening an existing production record will now show the instructions that were saved with it, instead of showing a blank field. - **Switching products no longer leaves old instructions behind.** If you change the selected product (or clear the product field) on the Production Create page, the Recipe Instructions field now clears automatically. Previously, it would keep showing the previous product's instructions. #### Improvements - **Recipe Instructions field is now editable on both Create and Edit pages.** You can now type, paste, or update the instructions directly in the field — for example, to add notes specific to this production run. Previously the field was locked (read-only) and could not be typed in. - **Instructions you enter are saved with the production record.** Whatever you type in the Recipe Instructions field is now saved when you submit the form. When you later open the same record to edit it, your instructions will be shown exactly as you entered them. --- ## Version 8.87.5 **Release Date:** 2026-05-16 ### Module: Manufacturing — Production List #### New Features - **"Selling Price" column added to the Production List.** The Production list now shows a **Selling Price** column next to the Total Cost column. This displays the total expected selling value for each production run — calculated by multiplying the product's selling price by the quantity produced — so you can immediately compare what a batch costs to make versus what it can sell for. - **Footer totals now appear at the bottom of the Production List.** The list now shows running totals at the bottom of the page. You can see the combined **Total Cost** and combined **Total Selling Price** for all production entries currently on screen — without having to add them up manually. #### UI / UX Changes - **Numeric value columns are now right-aligned in the Production List.** The **Quantity**, **Total Cost**, and **Selling Price** columns now display their values aligned to the right, making it easier to read and compare numbers down the column at a glance. --- ### Module: Manufacturing — Recipe Report #### New Features - **Filter bar added to the Recipe Report.** The Recipe Report now has a filter panel at the top — just like other reports in the system. You can narrow down the recipes shown on screen before viewing or exporting. - **Filter by Category.** Select a product category from the dropdown to show only the recipes that belong to that category. - **Filter by Sub Category.** After choosing a category, a Sub Category dropdown appears so you can drill down further. The sub-category list automatically updates to match the selected category. - **Filter by Sub2 Category.** If your business uses a third level of categories, a Sub2 Category dropdown also appears after you select a sub category. - **Search by product name.** Type any part of a product name in the Search Product box. The autocomplete will suggest matching products as you type — select one to show only that product's recipe. - **Searching an ingredient now shows the recipes it belongs to.** If the product you search is used as an ingredient in a recipe (not the final product), the report will still show you every recipe that uses it — so you can see which recipes depend on that ingredient. - **Rows-per-page selector added to the table.** You can now choose how many rows to show at a time (10, 25, 50, 100, or All) directly above the table, matching the layout of other reports in the system. #### UI / UX Changes - **Numeric value columns are now right-aligned in the Recipe List.** The **Quantity**, **Price**, and **Unit Price** columns now display their values aligned to the right for easier reading and comparison. --- ### Module: Manufacturing — Demand Orders #### UI / UX Changes - **Numeric value columns are now right-aligned in the Demand Orders list.** The **Total Items**, **Estimated Cost**, and **Selling Price** columns now display their values aligned to the right. - **Currency symbol moved to column headers for cost and selling price columns.** The currency symbol (e.g. Rs) now appears only in the **Estimated Cost** and **Selling Price** column headers instead of repeating on every row — making the list cleaner and easier to scan. - **Footer totals now appear at the bottom of the Demand Orders list.** The list now shows running totals at the bottom of the page. You can see the combined **Total Items**, **Estimated Cost**, and **Total Selling Price** for all entries currently on screen — without adding them up manually. --- ### Module: Manufacturing — Demand Ingredient Report #### Improvements - **Category, Sub Category, and Sub2 Category columns are now shown on all report tabs.** Every tab in the Demand Ingredient Report — Product-wise Summary, Category-wise Summary, All Ingredients Summary, All Ingredients Detail, and Batch Ingredients Summary — now includes three separate columns showing the Category, Sub Category, and Sub2 Category of each product or ingredient, so you can clearly see which category level each item belongs to. - **The Category / Sub Category / Sub2 Category filters now correctly narrow down the report.** Selecting a category or sub-category in the report filters now limits all tabs to only show products that belong to the selected category. Previously, all products appeared regardless of the filter chosen. - **Sub Category and Sub2 Category columns now display the correct values.** The Sub Category and Sub2 Category columns were previously empty for all products. They now correctly show the sub-category and sub2-category names as saved on each product, matching what you see in the product list. #### UI / UX Changes - **Currency symbol moved to column headers for the Selling Price column across all report tabs.** The currency symbol (e.g. Rs) now appears only in the **Selling Price** column header instead of repeating inside every row — keeping the numbers clean and easy to read. This applies to all five report tabs: Product-wise Summary, Category-wise Summary, All Ingredients Summary, All Ingredients Detail, and Batch Ingredients Summary. --- ### Module: Reports — Sale Invoices Report #### New Features - **Two new filter options added to the "Type" dropdown in the Sale Invoices Report.** You can now filter the report by **Sales Order** or **Quotation** in addition to Sales Invoices and Sales Return. - **Sales Order** — Select this to view all products and quantities listed on Sales Orders. This option only appears if Sales Orders are enabled in **Business Settings → Sales**. - **Quotation** — Select this to view all products and quantities listed on Quotations. This option only appears if Quotations are enabled in **Business Settings → Sales**. --- ### Module: Reports — Types of Service Report #### New Features - **A new "Types of Service Report" has been added under Reports.** This report gives you a full breakdown of all sales that were placed using a Type of Service (such as Dine In, Take Away, Delivery, etc.). You can find it under **POS Reports** if the POS module is turned on, or under **Sales Reports** if it is not. - **Filter the report by date range, business location, and type of service.** Use the filter bar at the top to narrow down results — choose a date range, a specific business location, or a particular type of service to focus on exactly what you need. - **Three report views in one page — Total, Summary, and Detail.** - **Total tab** — Shows a day-by-day breakdown. For each date, you can see how many orders were placed using a type of service and the total sales amount for that day. - **Summary tab** — Shows a grouped view by type of service name. For each service type, you can see the total number of orders, the total amount collected, and the average order value. Useful for comparing which service type brings in the most business. - **Detail tab** — Shows every individual transaction. Each row displays the date, invoice number, customer name, invoice total, the type of service used, and the service charge amount collected for that order. - **Footer totals appear at the bottom of every tab.** Each tab automatically adds up the quantities and amounts shown on screen so you can see the running totals without manually adding them up. - **Access controlled by role permission.** Go to **Settings → Security Roles**, open a role, and look under the **Reports** section. Enable **View Types of Service Report** to allow a user to access this report. A second option, **View Types of Service Report (All Locations)**, lets you allow selected users to see data across all business locations. --- ### Module: Reports — Sell Payment Report #### Improvements - **Payment Method filter dropdown now shows the exact names you set for each business location.** The list of payment methods in the filter now matches the names configured in your Business Location's Payment Options — for example, if you named a custom method "E-Wallet" or "Online Transfer", that exact name now appears in the filter instead of a generic label. --- ### Module: Reports — Purchase Payment Report #### New Features - **Payment Method filter added to the Purchase Payment Report.** You can now filter the Purchase Payment Report by payment method — the same way you can on the Sell Payment Report. Select a specific method from the new dropdown to show only payments made using that method. The dropdown shows the exact method names set in your Business Location's Payment Options. --- ### Module: Labels #### New Features - **You can now print the Product Category on labels.** In **Labels → Information to show in Labels**, a new **Product Category** option has been added. Tick it before previewing or printing, and the category name assigned to the product will appear on each printed label. You can also set the font size for it, just like the other label fields. --- ### Module: Product Catalogue #### Bug Fixes - **Discount badge no longer appears on all products when only one product has a discount.** Previously, if you set a discount for a specific product (or a specific brand/category), the discount badge was incorrectly showing on every product in the catalogue. This is now fixed — the badge only appears on the product or products the discount actually applies to. #### Improvements - **Product cards now show the discounted price when a discount is active.** When a product has an active discount, its card in the catalogue now displays the original price with a strikethrough and the discounted price highlighted in red below it. This makes it easy for customers to see the saving at a glance before opening the product details. --- ### Module: Accounting — Journal Entry #### Improvements - **"Narration" column now appears on the Journal Entry list.** The Journal Entry list now shows a dedicated Narration column (placed just before the Additional Notes column). This displays the description you entered for each account line when creating or editing a journal entry, so you can read the purpose of each entry at a glance — without having to open it. --- ## Version 8.87.4 **Release Date:** 2026-05-15 ### Module: Accounting — Bank Reconciliation #### New Features - **A new "Bank Reconciliation" section has been added to the Accounting module.** You can find it in the Accounting menu under **Bank Reconciliation**. This feature lets you compare your bank statement with the transactions recorded in the system — and tick off the ones that match — so you can confirm your books are accurate at the end of each period. - **Start a new reconciliation in seconds.** Click **+ New Reconciliation**, choose the bank account, enter the closing balance shown on your bank statement, and set the statement date. The system automatically fills in the opening balance from your previous reconciliation (if one exists) so you do not have to enter it manually. - **Mark transactions as cleared directly on screen.** The reconciliation worksheet shows two columns side by side — **Deposits / Credits** on the left and **Payments / Debits** on the right. Tick the checkbox next to each transaction that appears on your bank statement. The totals and the outstanding difference update instantly as you tick. - **Live difference indicator shows whether your books balance.** A summary bar at the top of the worksheet shows the bank statement balance, cleared totals, and the current difference. When the difference reaches zero, a green "Balanced ✓" indicator appears and the **Complete Reconciliation** button becomes active. - **Add bank-only entries without leaving the reconciliation.** If your bank statement includes a charge, fee, or deposit that has not yet been entered into the system (such as a bank service fee), click **Add Bank-Only Entry**, enter the amount, date, and description, and it will be included in the reconciliation and automatically ticked as cleared. - **Outstanding transactions are shown at a glance.** Below the worksheet, the system lists all transactions that were not ticked — these are deposits or payments recorded in the system but not yet appearing on the bank statement. This helps you spot anything that may need follow-up. - **Finalise and lock completed reconciliations.** Once balanced, click **Complete Reconciliation** to mark it as done. You can then **Lock** it to prevent any further changes, keeping your records secure and auditable. - **Print or save a formal Reconciliation Statement.** Every completed reconciliation has a printable report showing the statement period, opening and closing balances, all cleared deposits and payments, outstanding items, and signature lines for authorisation. Open any reconciliation from the list and click **Print**. - **Full history of past reconciliations.** The Bank Reconciliation list shows all previous reconciliations with their status (Draft, Completed, or Locked), the bank account, statement date, and whether they balanced. You can filter by account, status, or date range. - **Access controlled by role permission.** Go to **Settings → Security Roles** and look under the **Accounting** section to enable **Manage Bank Reconciliation** for the roles that need it. --- ### Module: Dashboard #### Improvements - **"Top 10 Selling Products" widget no longer includes items marked as "Not for Selling".** Any product you have flagged as "Not for Selling" on its product page will no longer appear in this dashboard list, keeping it accurate and limited to what you actually sell. --- ### Module: Reports #### New Features - **Each report now has its own separate permission to allow staff to see data for all locations.** Previously, a staff member linked to one location could only see that location's data in reports. You can now grant permission per individual report — for example, let a user see all locations in the Profit & Loss report while keeping them restricted to their own location in the Stock report. Go to **Settings → Security Roles**, open a role, and look under the **Reports** section — each report's "View for All Locations" option appears directly below its main "View" option. Reports that now have this per-report control: | Section | Reports included | |---|---| | Admin Reports | Profit & Loss, Purchase & Sell, Tax, Expense | | POS Reports | Register Report, Summary Income Report, Sales Representative Report | | Sales Reports | Sale Invoices, Sales Returns, Product Sell, Sales Analysis, Trending Products | | Stock Reports | All stock reports (Stock Quantity, Stock Value, Reorder, Expiry, Transfers, Adjustments, etc.) | | Purchase Reports | Purchase Invoices, Purchase Returns, Product Purchase, Purchase Analysis | | General Reports | Contacts (Supplier & Customer) Report | --- ### Module: Point of Sale (POS) #### Improvements - **POS screen is faster when you scan or tap several products quickly one after another.** Products now load into the sale with less delay, so you can keep adding items without waiting. - **Customer group pricing and discounts are applied without any pause.** If a customer belongs to a group with special prices, those prices now appear immediately — no noticeable delay during the sale. - **Product unit choices (e.g. Piece, Box, Dozen) appear faster during a sale.** Selecting a unit on any product row is quicker, especially when the same unit is used more than once in the same transaction. - **Service staff list in POS appears faster.** The list of staff available to assign to a table or order loads more quickly each time it is needed on the same screen. --- ### Module: User Management #### New Features - **The Users page is now divided into two separate sections: "All Users" and "All Employees".** - **All Users** — lists only staff who have a system login (those with "Allow Login" turned on). Their username, role, and login-related actions are shown here. - **All Employees** — lists staff who do **not** have a system login (those with "Allow Login" turned off). These are typically field staff or workers tracked in the system but not given access to sign in. This makes it much easier to manage login-access staff and non-login employees separately without them being mixed together in one long list. This split also appears on the Superadmin → Business detail page. --- ### Module: Navigation Bar (Top Bar) #### UI / UX Changes - **"Add Sale" shortcut icon in the top bar is now hidden for users who do not have the Add Sale permission.** The icon now only appears for users whose role includes permission to add a sale. - **"Add Product" shortcut icon in the top bar is now correctly shown or hidden based on the user's permission.** Only users with the "Create Product" permission in their role will see this icon. --- ### Module: Manufacturing — Demand Orders #### New Features - **A "Batch Quantity" field has been added to each product line in demand orders.** When creating or editing a demand order, you can now enter a batch quantity per line to specify how many batches are needed — making production planning clearer at a glance. - **Batch Quantity is now shown when viewing or printing a demand order.** The batch quantity column appears in the demand order detail view and on printed copies, so nothing is missing from your records. - **A new "Batch Ingredients Summary" tab has been added to the Demand Order Report.** This tab shows a combined summary of how much of each ingredient is needed across all demand orders for the selected period, grouped by batch — without having to check each order separately. #### Improvements - **SKU search in Manufacturing now finds all product types.** Scanning or typing a product SKU in the manufacturing search now correctly finds both weight-code products and regular simple products, so you can add any product to a recipe or demand order without browsing manually. #### Bug Fixes - **Recipe Report page was showing a "Page Not Found" error — now fixed.** The Recipe Report under Manufacturing → Reports is now accessible again and displays recipe information as expected. --- ### Module: Manufacturing — Demand Ingredient Report #### Bug Fixes - **Quantity values in the Demand Ingredient Report now display the correct number of decimal places.** All quantity columns across all tabs (Product-wise Summary, Category-wise Summary, All Ingredients Summary, All Ingredients Detail, and Batch Ingredients Summary) now respect the **Quantity Decimal** setting configured in **Settings → Business Settings → Business tab**. Previously, quantities were always displayed using the currency decimal setting regardless of how many decimal places were set for quantities. --- ### Module: Layout / Display #### UI / UX Changes - **The Save and Update buttons on several pages have been moved to the fixed bottom bar at the bottom of the screen.** Instead of appearing at the bottom of the page content — where you had to scroll down to reach them — these buttons now sit in the footer bar that is always visible regardless of how far down the page you have scrolled. This applies to the following pages: - **Barcode Settings → Add New Setting** — the **Save** button is now in the bottom bar. - **Barcode Settings → Edit Setting** — the **Update** button is now in the bottom bar. - **Users → User Settings** — the **Update** button is now in the bottom bar. - **HRM → Settings** — the **Update** button is now in the bottom bar. - **Manufacturing → Settings** — the **Update** button is now in the bottom bar. - **Manufacturing → Demand Orders → Create** — the **Save** and **Save & Print** buttons are now in the bottom bar. - **Manufacturing → Demand Orders → Edit** — the **Update** and **Update & Print** buttons are now in the bottom bar. --- ## Version 8.87.3 **Release Date:** 2026-05-14 ### Module: Reports — General Reports #### New Features - **New Bookings Report added under Reports → General Reports.** View all restaurant/table bookings in one place. The report shows booking start and end time, customer name, phone number, table, business location, service staff, booking status (Waiting, Booked, Completed, or Cancelled), and any notes. Use the filters at the top to narrow results by date range, location, status, or customer, then print with one click. --- ### Module: Layout / Display #### UI / UX Changes - **Empty space on the right side of pages on large or widescreen monitors has been removed.** On extra-large screens and LED displays, pages now stretch to fill the full width instead of leaving a blank gap on the right side. --- ### Module: Manufacturing — Demand Orders #### New Features - **Selling Price column added to the Demand Order list.** Each demand order in the list now shows the total selling value of the finished products alongside the estimated cost. - **Selling Price column added to the Demand Order detail view and print.** When you open or print a demand order, each product line now shows its selling price next to the estimated cost, with a total selling price in the footer. #### Improvements - **Filters can now be saved on the Demand Order list page.** Use the new **Save** button in the filter bar to remember your selected Business Location, Date Range, and Status. Your saved filters will be applied automatically the next time you open the Demand Order list. Click **Reset** to clear all filters back to default. #### UI / UX Changes - **The Action button (View / Print / Edit / Delete / Approve) is now the first column in the Demand Order list.** You no longer need to scroll to the right to take action on a record. - **Date range filter opens on Today automatically.** When you open the Demand Orders list, the date is already set to today so any order you just created appears straight away without needing to change the date. - **"Demand Order" is now a direct link in the Manufacturing sidebar menu.** The previous "+ Add Demand Order" shortcut has been replaced with a "Demand Order" link that opens the full Demand Order list. From there you can view, search, filter, add, edit, approve, and print demand orders — all in one place. The "Add Demand Order" button is still available inside the list page. #### Bug Fixes - **Demand Order list now loads correctly for all users who have access — not just Admin.** Non-admin users with the "Access Demand Order" permission were seeing a blank, empty table. The list now shows all demand orders for the business, as expected. - **The Edit button on the Demand Order list is now only shown to users who have edit permission.** Previously, the Edit button appeared for all users, but clicking it caused a "not allowed" error for those without the permission. The button is now hidden for those users. - **Demand Order link no longer appears twice in the menu.** It was showing up in both the main navigation bar and the Reports dropdown at the same time for some users. It now appears only in one place based on the user's permissions. - **Orders created today now appear in the list immediately.** Previously, because the date filter defaulted to yesterday, any order added today would not show up until the following day. The filter now defaults to today so newly created orders are visible right away. - **Clicking a status in the Demand Order list now shows all available status options.** Previously, only 2 options appeared — Pending and Cancelled — regardless of the order's current status. The full list of statuses is now shown so you can move an order to any stage directly without going through each step one at a time. --- ### Module: Manufacturing — Demand Ingredient Report #### New Features - **Selling Price column added to all four report tabs.** The Demand Ingredient Report now shows a Selling Price column across the Product-wise Summary, Category-wise Summary, All Ingredients Summary, and All Ingredients Detail tabs — so you can compare ingredient cost against selling value on one screen. #### Improvements - **Filters can now be saved on the Demand Ingredient Report.** Use the new **Save** button to remember your selected Business Location, Date Range, Demand Orders, Category, Sub Category, Sub2 Category, and Status filters. They will be restored automatically next time you open the report. Click **Reset** to clear all filters. #### UI / UX Changes - **Date range filter opens on Yesterday automatically.** When you open the Demand Ingredient Report, the date is already set to yesterday. --- ### Module: Manufacturing — Recipe #### Improvements - **Filters can now be saved on the Recipe list page.** Use the new **Save** button to remember your selected Category, Sub Category, and Sub2 Category filters. They will be applied automatically the next time you open the Recipe page. Click **Reset** to clear all filters back to default. --- ### Module: Manufacturing — Production #### Improvements - **Filters can now be saved on the Production list page.** Use the new **Save** button to remember your selected Business Location, Date Range, Production Status, Category, Sub Category, and Sub2 Category filters. They will be restored automatically the next time you open the Production page. Click **Reset** to clear all filters at once. - **Recipe instructions are now shown directly on the production form.** When you select a recipe while adding or editing a production entry, the recipe instructions appear automatically on screen — no need to open the recipe separately to check them. --- ### Module: Manufacturing — Dashboard #### UI / UX Changes - **Date filter opens on Today automatically.** When you open the Manufacturing Dashboard, today's date is already selected — no need to manually pick a date before viewing the day's activity. --- ### Module: Manufacturing #### Bug Fixes - **Deleting a recipe now works correctly.** The delete button on a recipe was not doing anything — no confirmation appeared and nothing was removed. It now shows a confirmation prompt and removes the recipe as expected. - **Product stock history no longer includes quantities from unfinished production batches.** The "Manufacturing (In)" quantity shown in a product's stock history was previously counting production batches that had not yet been completed, making stock figures appear higher than they should. Only fully completed batches are now counted. --- ### Module: Reports — Stock Value Report #### New Features - **Manufacturing quantities and values now appear as separate columns in the Stock Value Report.** Two new columns — Manufacturing (In) and Manufacturing Value — have been added, giving a complete picture of how stock was built up through production. #### Bug Fixes - **Manufactured stock was being counted twice in the Purchase columns — now fixed.** Produced quantities were incorrectly showing up in both the Manufacturing and Purchase columns. Purchase columns now show only actual supplier purchases; manufactured stock appears only in the Manufacturing columns. - **Opening Stock showed 0 for products with more sales than purchases — now fixed.** Products that had been sold more than they were ever purchased were displaying 0 in the Opening Stock column instead of the correct value. The correct figure (which may be negative) is now shown. --- ### Module: Contacts — Contact Payment #### UI / UX Changes - **"Outstanding" heading removed from the Contact Payment window.** The bold label above the due invoices section has been removed to keep the layout clean and uncluttered. - **Location filter renamed to "Outstanding Invoices by".** The filter that narrows the due invoices list by business location now has a clearer, self-explanatory label. - **Date range filters now sit next to the location filter.** The From and To date fields are now shown in the same row as the location filter, making it faster to set your filters without scrolling. - **Location and User fields now sit side by side.** These two fields are now displayed in one row instead of stacked on top of each other, saving vertical space in the payment form. --- ## Version 8.87.1 **Release Date:** 2026-05-13 ### Module: Reports / Products #### Improvements - **Product Stock Details section now shows a Total row at the bottom.** When viewing a product's stock details, a new totals row shows the combined Current Stock Quantity, Total Stock Price, Total Units Sold, Total Units Transferred, and Total Units Adjusted across all variations and locations. - **Opening Stock Report footer totals now show the correct grand total across all pages.** Previously these totals only added up the rows visible on screen. They now always reflect the full filtered result, no matter how many pages the report spans. - **Add / Edit Opening Stock now shows footer totals for Quantity and Quantity Remaining.** Each location table in the Opening Stock form now has a totals row that updates automatically as you enter values. #### Bug Fixes - **Stock Quantity Report and Product Stock Details modal were showing inflated quantities for products with multiple variations — now fixed.** For example, a product with 9 variations was showing a stock total of 450 instead of the correct 50. The Product list, the Stock Quantity Report, and the Product Stock Details modal now all show the same correct figures. --- ## Version 8.87.2 **Release Date:** 2026-05-05 ### Module: Business Location Settings #### New Features - **New "Map & Location" tab added to Business Location settings.** Administrators can now set a precise map location for each business location. Search for an address, click anywhere on the map to drop a pin, or tap "Use My Current Location" to fill in the coordinates automatically. The saved location is used as the starting point on the live delivery map. --- ### Module: Delivery Management #### Improvements - **Live Map now opens centred on your business location.** Each business location with saved coordinates appears as a store pin on the live tracking map. The map no longer opens on a random point on the world map. --- ### Module: HRM — Attendance (Biometric Push Devices) #### New Features - **Newer ZKTeco biometric devices can now push attendance records directly to the system in real time.** Models such as SenseFace 2A, 4A, 7C, ProFace X, SpeedFace M5, G4 and similar can now send attendance records automatically — no extra connector software or scheduled sync is required. - **New "ADMS / SenseFace Devices" management page** added under HRM → Attendance → Import Attendance. Administrators can register devices by serial number, manage security keys, monitor the last-seen time and IP address, and enable or disable any device. - **Each device has its own security key** that is checked on every attendance push, preventing unauthorised records from being submitted. - **Step-by-step Live Push Setup guide** is shown directly on the Import Attendance page with the system's address already filled in, so you can configure the device without leaving the screen. #### UI / UX Changes - **Import Attendance page now groups compatible devices into four clear categories:** Fingerprint/RFID, Multi-bio, iClock/SpeedFace, and ADMS Push — with a note indicating which models are officially tested. - **Quick-access "ADMS / SenseFace Devices" button** added to the Import Attendance page alongside the existing Download buttons. --- ## Version 8.87.1 **Release Date:** 2026-05-05 ### Module: Business Settings — Modules #### New Features - **Delivery Management module can now be turned on or off.** A new "Delivery Management (Riders & Live Map)" option has been added under Settings → Business Settings → Modules tab. When turned off, the Delivery menu and all delivery pages are hidden from all users. When turned on, the full Delivery suite is available. --- ## Version 8.87.0 **Release Date:** 2026-05-05 ### Module: Delivery Management (New Module) #### New Features - **A complete Delivery Management module is now available** under a new Delivery menu (shown to users who have delivery access). - **Live Map:** Real-time map showing every active rider's current position with colour-coded status pins (Available / On Delivery / On Break / Offline). Click any rider pin to see their name, phone number, vehicle, current speed, last-seen time, and the details of their active delivery. The map refreshes automatically every 10 seconds. - **Dashboard summary cards:** A quick overview showing Total Riders, Available, On Delivery, Today's Orders, Active Assignments, and Delivered Today. - **Riders directory:** Add and manage delivery riders. Capture vehicle type, plate number, colour, driving licence number and expiry date, emergency contact, maximum load, base delivery fee, per-km rate, and a photo. View the full list with each rider's current status and last-seen time. - **Per-rider Track screen:** View a 24-hour map trail of GPS location updates for any individual rider. - **Assignments:** Create and manage delivery tasks linked to a sale invoice (the customer's address fills in automatically from the contact record) or as a standalone delivery. Filter by status, rider, and date range. - **Automatic distance and fee calculation:** Drop-off distance is calculated automatically. The delivery fee is computed as base fee + (distance × per-km rate) and can be overridden manually for each assignment. - **Delivery status tracking:** Pending → Accepted → Picked Up → On The Way → Delivered (with Failed and Cancelled options available). Each step is recorded with a timestamp. - **Performance Report:** Per-rider summary over any date range — showing total assignments, delivered, cancelled, success rate, total km travelled, total fees earned, and average delivery time. #### UI / UX Changes - **New Delivery sidebar menu** (truck icon) with four sections: Live Map, Riders, Assignments, and Performance Report. --- ## Version 8.86.3 **Release Date:** 2026-05-04 ### Module: Purchase Returns #### Bug Fixes - **Purchase Return list was showing Rs 0.00 for every entry — now fixed.** Each purchase return in the list now shows its correct grand total amount. - **Purchase Return footer totals were showing Rs 0.00 — now fixed.** The Grand Total and Payment Due amounts at the bottom of the Purchase Return list now correctly show the combined total across all matching records. --- ### Module: Dashboard — Today at a Glance #### Bug Fixes - **Today's Revenue and Total Due Amount now correctly subtract returns.** Today's Revenue was previously showing gross sales without deducting sale returns, and Total Due was not offsetting outstanding return amounts. Both figures are now correct net amounts. --- ### Module: Sales — Sale Returns #### Bug Fixes - **Sale Return detail view was showing an empty product list — now fixed.** Opening the details for a sale-return record now shows the correct returned products, quantities, unit prices, and subtotals. - **Sale Return list footer totals now cover all pages — not just the visible page.** The Grand Total and Payment Due amounts in the footer now show the correct combined total across all records, regardless of how many pages the list has. --- ### Module: Reports — Profit & Loss #### Bug Fixes - **Total Sale Return figure was overstated in the Profit & Loss report — now fixed.** The Total Sale Return amount now matches the actual figure shown on the Sale Return list. --- ### Module: Reports — Sales & Returns Report #### Bug Fixes - **Footer totals on the Sales & Returns Report were overstated — now fixed.** Sale-return rows now appear as negative values so the footer correctly shows net sales (sales minus returns) instead of adding returns on top of sales. --- ### Module: Reports — Sale Invoices Report #### Bug Fixes - **"Item Quantity" column was showing 0 for Sale Returns on the Totals tab — now fixed.** The correct returned quantities are now shown in this column. --- ### Module: Settings — Modules #### New Features - **New "Custom Designer" toggle** added under Settings → Business Settings → Modules tab. When turned on, the Invoice Designer and Label Designer options appear in the sidebar. When turned off, these options are hidden. This toggle is off by default. --- ### Module: Products #### Bug Fixes - **Group Price column was blank in the Product list — now fixed.** Products that have selling group prices assigned now display those prices correctly in the list. --- ### Module: Manufacturing — Sidebar Menu #### UI / UX Changes - **Manufacturing sidebar menu reordered for a clearer, step-by-step workflow.** The menu now follows the natural production lifecycle: Dashboard → Recipe → Production → Add Demand Order → Reports → Settings. - **New "Reports" group added to the Manufacturing sidebar.** All reporting screens (Demand Order Report, Demand Ingredient Report, Manufacturing Report, and Recipe Report) are now grouped together under a single Reports menu item. - **"Add Demand Order" is now a top-level shortcut in the sidebar.** You can create a new demand order in one click directly from the sidebar. --- ## Version 8.86.2 **Release Date:** 2026-05-03 ### Module: Settings — Invoice / Receipt Design #### New Features - **New receipt layout "Slim 4" added for 80mm thermal printers.** Available under Settings → Invoice Settings → Layout. Each product is displayed across two lines — the first line shows the item number and product name, and the second line shows the quantity, unit price, discount, and subtotal — making items easier to read on narrow 80mm receipt paper. --- ### Module: HRM — Payroll #### Bug Fixes - **Employee list was not refreshing when a location was selected in the Advance Payment form — now fixed.** When opening the Add Advance Payment form and choosing a location, the Employee dropdown now correctly updates to show only the employees at that location. --- ## Version 8.85.2 **Release Date:** 2026-05-02 ### Module: Manufacturing — Recipe Import #### New Features - **"Download Excel" button added to the Recipe list page.** Clicking this button exports all your existing recipes in the same spreadsheet format used by the Recipe Importer. You can edit the downloaded file and re-upload it to update existing recipes or add new ones. - **Simpler recipe import spreadsheet format.** Each ingredient now has its own row. Simply repeat the same Product SKU for every ingredient that belongs to the same recipe — no complex coding or special formatting is required. - **Recipe-level details only need to be entered on the first row.** Fields such as Total Quantity, Recipe Unit, Extra Cost, and Instructions only need to be filled in on the first row of each recipe. The rows that follow will automatically use the same recipe-level values. - **Blank fields use sensible defaults.** If you leave Total Quantity blank it defaults to 1. Production Cost Type defaults to Fixed. Units default to the product's base unit. This means you can create a working import file with minimal effort. - **Improved downloadable template.** The Excel template now includes a styled header row, three worked examples (a cake recipe, a juice recipe, and a single-ingredient pack), and a built-in instructions section inside the sheet. - **"Download Sample (with example data)" button added.** This downloads a fully populated sample workbook with 5 realistic recipes (Chocolate Cake, Vanilla Cupcake, Mango Juice, Veg Burger, Sugar Pack) that you can use as a reference when building your own import file. #### UI / UX Changes - **The Import Recipes page now clearly labels which columns are required and which only apply to the first row.** A short tip box at the top of the page summarises the format in three simple bullet points. --- ### Module: Sales / POS / Discounts #### Bug Fixes - **"Buy For Quantity" discount now charges the correct total at POS — now fixed.** For example, a "2 for £9.99" deal now correctly charges £9.99 for two units. If a customer buys 3 items under a "2 for £9.99" deal, the system correctly charges one bundle price (£9.99) plus one unit at the standard price. --- ### Module: Fiji FRCS Integration (New Module) #### New Features - **New Fiji FRCS module** added to help businesses in Fiji send sales receipts to the Fiji Revenue & Customs Service (FRCS) in real time. - **Register your fiscal device (EFD).** A dedicated screen lets you enrol your shop's device with FRCS using the activation code from the FRCS portal. Switch between Sandbox mode (for testing) and Production mode (for live sales) with a single click. - **Sales receipts are sent to FRCS automatically.** Every sale and refund processed at the POS is submitted to FRCS automatically. Supported types include Normal Sale, Refund / Credit Note, Training, and Proforma. - **Choose how receipts are sent.** Select the mode that suits your business — Instant (sent at the moment of sale), Queued (sent in the background), Daily (sent once a day), or Manual (you click a button to send). - **Works even when the internet is down.** If FRCS cannot be reached, receipts are saved locally and sent automatically once the connection is restored. - **X-Reports and Z-Reports.** Generate the daily X-Report (read-only summary) and the end-of-day Z-Report (closes the business day and sends the data to FRCS). Z-Reports can also be generated automatically each night at a set time. - **FRCS QR code printed on every receipt.** Once a receipt is accepted by FRCS, the official verification code and QR are stored and printed on the customer's copy so customers can verify it directly with FRCS. - **Settings page.** From one screen you can configure your TIN, VAT number, sending mode, whether a buyer's TIN is required, QR code on/off, automatic Z-Report time, and an email address for error notifications. - **Submission history and audit trail.** A dedicated page lists every receipt sent to FRCS with its current status (Pending / Submitted / Accepted / Failed). Search, filter, view details, and re-send any failed receipt with a single click. - **"Submit All Pending" button.** Pushes all unsent receipts to FRCS in one go. - **Separate staff permissions for FRCS:** Access the Fiji FRCS module, Manage EFD device onboarding, Submit fiscal receipts, and Generate X / Z Reports. --- ### Module: Accounting — Chart of Accounts #### Bug Fixes - **Parent Account dropdown was empty when adding a new account — now fixed.** The dropdown now correctly lists all available parent accounts. - **Non-posting accounts were missing from the Parent Account dropdown — now fixed.** All active non-posting accounts now appear as selectable parents when creating or editing an account. --- ### Module: POS — Quick Menu Buttons #### Bug Fixes - **Same product was being added as a new row instead of increasing the existing quantity — now fixed.** When "Increase item quantity if it already exists" was turned on, clicking a quick menu button rapidly was sometimes creating a separate new row for the same product. Rapid clicks now always increase the quantity on the existing row. - **Quick menu button was sometimes adding a blank quantity — now fixed.** If a quick menu button had no quantity configured, it would occasionally add the product with no quantity. It now always defaults to quantity 1. --- ### Module: Purchases #### Improvements - **Purchase details popup now shows Gross Profit % and Sell Price.** When these fields are enabled in settings, the purchase detail view shows GP% and Sell Price alongside the Subtotal column, so you can review pricing without opening the edit screen. --- ### Module: Accounting — Chart of Account Report #### New Features - **Chart of Account Report added under Accounting → Reports.** Lists all accounts organised by type (Asset, Liability, Equity, Income, Expenses) with columns for GL Code, Account Name, Account Sub Type, and Status. - **"Show Balances" option.** Tick the Show Balances checkbox and click Apply Filters to add a live balance column showing the current balance for each account, plus totals grouped by sub-type and account type.
Need Help?

If something on your Dashboard doesn't look right, use the Contact Superadmin tab in the Documentation section to get help from your system administrator.