Skip to content

Changelog

What changed in each release of Profitability Copilot, in terms of what it means for you rather than which files moved.

1.2.1 — 3 October 2026

Corrections only, and one of them matters to every store with more than one storefront. No setting was added or changed, nothing new is stored, and the API answers exactly as it did.

A second storefront now records its orders. Every earlier release wrote its default settings for each of your storefronts when it was installed or updated, and the defaults include Status off. A storefront other than the default one then read its own off instead of the default store's on, so its orders were never recorded. Installing or updating now writes nothing for a storefront you never configured separately, and it follows the default store's settings, the way OpenCart resolves them everywhere else. This takes effect when you update; there is nothing to set. Orders such a storefront took before the update were not recorded, and Recalculate from a date over that period is the way to fill them in, at today's costs and labelled backfilled. If you saved a second storefront's own settings in the meantime, what you saved there stands: open its settings and check that Status reads Enabled. A single-store shop has nothing to do.

The cost field is read-only for a group that may see costs but not change them. Such a group was shown an ordinary box, and what it typed was dropped on save without a word. The box is now read-only, with a line saying why. The help under the field also says how to write a cost, as a plain number with a full stop for decimals, and that one it cannot read is ignored when the product saves. See who can see what you pay.

Saving Expenses is all or nothing. A save that failed part way used to leave the rows up to the failure and lose the rest. It now leaves the expenses as they were.

Names from other extensions are shown as text. Payment and shipping method names, order total codes and product names printed on the settings screen, the dashboard and Product profit are now escaped, so markup another extension put in a name is shown rather than run. A name OpenCart stored normally looks exactly as before.

The API refuses a credential with no key. OpenCart's own form will not save an API user with an empty key, but a row emptied by hand used to admit a caller presenting no key at all. It is refused now, whatever is presented. No field or route changed.

An update no longer adds the personal-data screen's permission to your group a second time. Each update appended another copy of it to the installing group's permissions. Harmless, but it grew with every release.

The list of every order fits its card, rather than running past its edge, and on both lists of orders the first column now reads Order rather than Product.

1.2.0 — 2 October 2026

Three additions and nothing changed underneath them: a list of every order with the one that lost most at the top, a button that redoes one order at today's costs, and the margin and markup a price makes, read on the product form as you type it. No setting was added or changed, nothing new is stored, and the API is exactly as it was.

Every order in one list, worst first. Until now an order's figures were reached only through one of its products, so an order that lost money on its fees or its fulfilment, spread across products that each did fine, was named nowhere. Product profit now lists every order of the period on its own, sorted by profit with the lowest first. Each order's profit is its lines' profit plus the shipping and order charges its customer paid, shown in a Charges column of their own. Reach it from Open every order, the one that lost most first on the dashboard, or All orders on Product profit; click an order to see its lines. The list is paged, but its totals and its export cover the whole period. The export from every view gains a last column, charges, filled on this list only, so a spreadsheet built on the old columns keeps them where they were. See find the orders that lost money.

Recalculate this order. Fixing one mistyped cost used to mean Recalculate from a date over every order since. An order's line breakdown now has a button that records that one order again, at today's costs and today's fee and fulfilment rules, and labels its lines backfilled the way the dated run does. No other order changes. It needs the same permission as the other recalculation buttons, and each order it records writes one line to the log. See correct one order after fixing a cost.

Margin and markup on the product form. Under the cost field, a line now reads the margin and markup the product's price makes over its cost, and changes as you type either. A price at or below the cost turns it red with a warning. It is a warning only: the product saves at the price you typed. It reads the Price field alone, not specials, discounts or customer-group prices, and it shows only to users who can see the cost field. See what it does not touch.

1.1.0 — 1 October 2026

Three corrections to figures 1.0.0 got wrong, and one addition that comes with the first: a new row on the dashboard's profit and loss, Shipping and order charges, and a new charges field in the API. Two of the corrections you see on the next page load; one waits for you to recalculate.

What your customers paid for shipping is now counted. 1.0.0 deducted the fulfilment cost of every order and left out the shipping, handling and low-order fees the customer paid towards it, so an order that charged 5.00 to ship under a rule saying fulfilment costs 5.00 read 5.00 short. Those charges now have a row of their own on the dashboard's profit and loss, Shipping and order charges, counted once per order and added into contribution margin. They belong to the order rather than to any product, so no product's profit includes them, and Revenue is still the order lines alone. This shows up at once, on every period, including orders recorded under 1.0.0: the charges are read off the order each time a report is drawn rather than stored with the recorded figures, so there is nothing to recalculate. The API's profit rows gain a charges field carrying the same figure. Nothing was renamed or removed, so an integration built against 1.0.0 keeps working. See shipping and order charges are counted once per order.

A returned line that had a discount no longer loses that discount twice. A returned unit now hands back what the customer paid for it, after the line's share of the discount, where 1.0.0 handed back its price before the discount while still keeping the discount against the product. The payment fee and the fulfilment cost stay spent, because a gateway keeps its fee on a refund and the parcel went out regardless. Returns are read live from OpenCart's return records whenever a report is drawn, so this too shows up at once, on old periods as well as new. The API's returned_revenue is net of the discount in the same way.

Recalculate, Back-fill and Recheck now use each store's own default margin. On a store with more than one storefront, 1.0.0's three tools priced every uncosted line that falls back on the default margin at the default store's figure, even where the order's own store had saved a different one. They now use the order's store, falling back to the default store's figure where that store saved none, which is what recording an order as it happens always did. Figures already recorded do not change until you run Recalculate from a date over them: a line one of the three tools wrote under 1.0.0 keeps the margin it was written with. A single-store shop, or one whose stores share one margin, has nothing to redo.

1.0.0 — 19 September 2026

The first public release. There is no previous version, so nothing below is a change. This entry is the baseline every later one is measured against.

What ships: the one number OpenCart has no column for, and everything that follows from it. A cost per product, typed on OpenCart's own product form behind a permission of its own so that not every admin sees your buying prices, or loaded in bulk from a CSV and written back out as one. From that, every order line is priced at the moment the order reaches a status you nominated, with payment fees and fulfilment costs from rules you write per method, an order-level discount allocated across the lines, and returns taken off. The result is written down.

Nothing is ever repriced. A supplier putting their prices up next month does not move last month's figures, because each line keeps the cost that was true when the order became real. Recalculate from a date is the one door back, it is explicit, and everything it touches is relabelled so a reader can tell.

Every figure says how much it is worth believing. Each line carries a cost basis (measured, derived from your default margin, filled in afterwards, or never recorded), and every screen, export and API row carries it forward. A product whose lines are mixed reads as the least authoritative of them. A line nobody has costed is excluded from the cost and from the revenue, counted, and its sales value reported separately, because counting revenue with no cost against it makes an uncosted product look like your best one. See how much each figure is worth believing.

A Profitability group appears in the admin menu with five screens, and an entry a user group may not open is absent rather than greyed out:

  • Dashboard: a profit and loss for the period with the coverage figure on it, and a feed of at most five things worth doing something about, ranked by the money at stake. Every line in it drills through to the rows behind it.
  • Product profit: per-product profit and margin, drilling through to the order and then to the line.
  • Cost book: the whole catalogue's costs as one CSV, downloaded and uploaded back.
  • Expenses: rent, software, one row per advertising channel; recurring or one-off, amortised across the days they cover, with blended ROAS off the rows you marked as advertising.
  • Settings: which order statuses count, which return statuses and reasons come off, the default margin, the fee and fulfilment rules, and the API switch. Every one of them is on settings, together with what this extension deliberately does not let you change and why.

Both reports export to CSV. Returns are read live from OpenCart's own return records rather than copied, so a return filed in the admin, in the storefront or by another extension counts identically, and editing one corrects the figures on the next page load.

A read-only JSON API, off until you switch it on, serving the same figures one day at a time so a reporting tool can aggregate them itself. Read the API before switching it on. Its first disclosure is the most important: an OpenCart API credential cannot be scoped, so turning this on shows every purchase price to every holder of a key to the installation.

It stores nothing about a person, and a check in our build keeps that true: a new column that is not classified fails it. See what this holds about a person.

It adds nothing to your storefront: no template edit, no theme change, and nothing here runs on a page a customer loads. It arrives switched off, and while it is off nothing is recorded. That period stays empty unless you recalculate over it, because the figures are frozen forward from the day you switch it on rather than reconstructed from today's prices afterwards.

It runs on OpenCart 4.0.2.0 and later. Below 4.0.2.0, or on PHP older than 8.1, it refuses to install rather than half-installing, and writes a line saying why to the store's logs. The releases a full install-to-uninstall pass has been run against are listed on requirements and install.

What an update keeps

Every cost you typed, every expense and every profit line already recorded survives it. Removing Profitability Copilot deliberately leaves its four tables and everything in them alone, so reinstalling puts the extension back over the figures it left behind. An update is never a recalculation job, and a closed month does not move because you updated the extension. Nothing in the extension empties those tables.

Your settings come back, with the exceptions below. An update is an uninstall and then an install, and OpenCart deletes an extension's settings at the uninstall step. Profitability Copilot keeps its own copy of them and puts them back afterwards. They are one set for the whole installation rather than one per store, apart from module_profitability_copilot_status and module_profitability_copilot_default_cogs_margin, which each store keeps its own of.

These are asked for again rather than put back:

  • module_profitability_copilot_diary_verbose_until — Detailed logging comes back off after an update, the way a fresh install does. An upgrade is an uninstall and a reinstall, and putting a diagnostic window back is how a store ends up verbose months after the support exchange that asked for it ended.

A setting a release adds does not change what your store does. Its default is what Profitability Copilot did before the setting existed, so an update never asks you to go and set something to get back the behaviour you already had.

What this cannot tell you is whether a release changed how a setting behaves, as against whether it survives. Nothing derives that from the code, so it is written by hand: a release that changes an answer you relied on says so in its own entry above, as its own paragraph and never among what is new.