Forex Investment 6.1.8
Latest11 August 2026
This release has upgrade notes. Read them before updating — they describe behaviour changes that need your attention.
Forex Investment v6.1.8
Release Date: August 11, 2026 Tags: INVESTMENTS, SETTLEMENT, ADMIN, ACCOUNTING, RELIABILITY, BUG-FIXES
Overview
A money-safety release for the administrative side of the add-on, drawn from a line-by-line audit of every place an operator's click moves a customer's money.
Four of those clicks could pay a customer twice or destroy their principal outright: one forex withdrawal decided by two operators at once applied both decisions, recovering an admin-cancelled investment paid its principal a second time, reversing a deposit handed the customer back a fee the platform kept, and deleting an account or a plan duration took the balance and the settled records with it. On the customer's side, the deposit and withdrawal wizards quoted a fee of zero on every spot transfer while the real percentage was charged, and a completed losing investment reported its return as a gain.
Read Upgrade Notes before you update: figures on existing records change, one dashboard figure stays wrong until you correct it, and the admin tables now refuse deletes they used to accept. Update Core first, or this add-on will not load its routes. Requires Core v6.6.3.
Update Instructions
pnpm updatorNothing to configure and no setting changes. There is one optional data correction, described below.
Upgrade Notes
- If you have ever deleted a forex account that still held a balance, look for it among the deleted rows in the admin account table and restore it. The balance comes back with it, and so does the ability to settle any withdrawal that was already debited from it. Restoring is never refused, including for an account that was deleted long before this release. An account that was deleted permanently cannot be recovered this way — nothing in this release brings one back, so reconcile those against your transaction history instead.
- Check the forex withdrawal queue for any request that two operators decided at the same time, or that one operator submitted twice. A double rejection returned the gross amount to the forex account twice; an approval racing a rejection both credited the wallet and refunded the account. Either leaves that forex account holding more than the deposits and settlements behind it can explain.
- Completed losing investments now show a negative return in the investment table. No stored figure was rewritten and no money moved — the sign had never been stored at all, and the table now reads it from whether the investment was recorded as a win or a loss. The Average ROI tile on the dashboard is averaged inside the database, which cannot do that, so it still reads higher than the truth wherever a loss was settled before this release. Correcting the stored figures is a single database update that flips the sign on completed losing investments; it rewrites settled money history, so it is deliberately not part of this update.
- Reversing a forex deposit now debits the platform wallet by the fee that deposit collected, and posts a matching negative entry in the revenue report. Reversals performed before this release were not corrected: the platform wallet still holds each of those fees and still reports them as income, while the customer was also refunded them.
- Customers will now see the real fee on forex deposits and withdrawals, where every screen previously showed zero. What is charged has not changed. Review the per-currency fee rates you have configured before you update, because until now customers were agreeing to a total that did not include them.
Added
A forex account with money riding on it can no longer be deleted
Both the single and the bulk delete in the admin account table handed straight to the generic delete routine with no business rule of any kind — the only delete in this add-on without one, and the one that holds the balance. An ordinary delete hid the account from every lookup that pays money into it, so the balance became unreachable and a pending withdrawal already debited from it could no longer be approved or rejected; a permanent delete destroyed it outright. Active investments were left with nowhere to return their principal, and the settlement job would have logged an alert and left them running for ever.
- Added a refusal on both account deletes when the account still holds a balance, has a pending withdrawal that was already debited from it, or has active investments due to settle back into it. The refusal names each account and each reason, and says what to clear first — reject the withdrawals, settle or cancel the investments, withdraw the remainder, then delete.
- Restoring an account is never refused, because restoring is the remedy for one deleted before this release. That also means an account already sitting in the deleted rows can no longer be destroyed permanently while it is still funded.
Changed
Public totals no longer carry a currency symbol they cannot justify
The performance figures on the forex landing page add up every investment on the platform regardless of the currency each one was made in, so the result is a magnitude rather than an amount of anything. Two sections stamped a $ on it anyway, in front of every visitor. The hero on the same page had already been corrected; these were missed.
- Changed the performance history and top plan sections to print those totals without a currency mark. The numbers themselves are unchanged.
- Changed the minimum and maximum investment on the spotlight card to show the plan's own currency, which was already in the data and was being replaced by a literal dollar sign.
Fixed
Two operators deciding one withdrawal both got their way
The withdrawal screen checked that a request was still pending using a read taken before its database transaction started. Two operators acting at once, one operator double-clicking, or a retried request all saw "pending" and all went through. The account and wallet rows are locked while the decision is applied, which puts the two callers in a queue — but queued is not the same as ignored, and the second still applied its own outcome on top of the first.
- Fixed the second decision being applied. The request is now re-read under a lock inside the transaction and its status checked there, so the second caller waits and is then told the withdrawal has already been approved or rejected. Before this, a double rejection refunded the gross amount to the forex account twice, and an approval racing a rejection both credited the customer's wallet and refunded the forex account for the same withdrawal.
The forex withdrawal screen accepted transactions that were not forex withdrawals
The route that settles a forex withdrawal looked its record up by identifier alone and never checked what kind of record it was. A pending spot withdrawal, a deposit or an investment could be passed to it and would be run through the forex approval path — crediting the customer's wallet with money that had never left a forex account. The matching deposit screen had always made that check; this one was the exception.
- Fixed the withdrawal decision refusing anything that is not a forex withdrawal, naming what the record actually is.
Recovering a cancelled investment paid the principal a second time
When an administrator moves an active investment to cancelled or rejected, the principal is returned to the customer's forex account. That refund was never recorded on the investment itself — only in the server log. The Recover action re-arms a cancelled investment so it can settle again, and decides whether that is safe by looking for exactly that record — which only the settlement job's own failure path ever wrote. So an administrator's cancellation was invisible to it: Recover concluded nothing had been paid, re-armed the investment, and it settled at maturity and paid the principal out again.
- Fixed the administrative cancellation recording its refund, so the Recover action can see it. The safety check itself was already correct; it simply could not see half the refunds.
Reversing a forex deposit created the fee out of nothing
A forex deposit charges its fee on top of the amount and pays that fee into the platform wallet, with a revenue entry to match. Reversing the deposit refunded the amount and the fee to the customer, but reversed only the amount — the platform kept the fee, the customer got it back, and the revenue report went on showing income from a deposit that no longer existed.
- Fixed the reversal debiting the platform wallet by the fee and writing the offsetting revenue entry, so the pair nets to zero. A deposit made by the platform account itself is skipped, because no fee was collected from it in the first place. A thin platform wallet cannot make a reversal fail; the debit is capped at what it actually holds.
Deleting a plan duration destroyed the record of settled investments
Plans and durations both cascade to the investments that reference them at the database level, which pays no attention to the add-on's "soft delete" behaviour. Plans are soft-deleted, so a plan delete is reversible; durations are not, so every duration delete is permanent and cascades. The existing guard treated that difference as the operator's choice and only refused a duration delete while investments on it were still active — so a duration whose investments had all completed was deleted, and the cascade quietly took the settled rows, the record of money that had actually moved, with them.
- Fixed the guard refusing a duration delete while any investment references it, active or completed, and saying how many of each. Plan deletes are unchanged: an ordinary one is refused while an investment on the plan is still active, and a permanent one while any investment references it at all.
A 25% loss reported as a 25% gain
Settlement stored the return percentage as an unsigned magnitude while storing profit as a signed figure, so a completed loss was recorded as a positive return. The investment table rendered "ROI +25.00%" directly beside "Profit/Loss −250.00" on the same card.
- Fixed settlement writing the sign, so newly settled investments are internally consistent; a draw is recorded as zero.
- Fixed the investment table taking the sign from whether the investment was recorded as a win or a loss, which reads correctly for records settled before this release as well as after it. The Average ROI tile on the dashboard cannot be repaired the same way — see Upgrade Notes.
Every fee quote on a forex transfer read zero
The deposit and withdrawal wizards looked the selected currency up in the list they had already fetched, using a name that list has never used. The lookup missed every time, so the fee read as zero and the confirmation step promised "Fee $0.00". The backend charged the configured percentage regardless: a customer moving 1,000 at 0.5% was shown a total of 1,000.00 and had 1,005.00 taken.
- Fixed the quote finding the currency, so the fee shown on the confirmation step is the fee that is charged and the total is the total. The list itself now carries the fee rate and precision, which is why Core v6.6.3 is required.
- Applies to spot forex transfers. Fiat movements are unaffected, because no fee is configurable on them.
Plan pages advertised a profit range of 0.00% – 0.00%
The plan detail page renders a "Profit Range" tile from the plan's minimum and maximum profit, and the page's data never included them. Every plan on the platform therefore advertised 0.00% – 0.00%, immediately beside a non-zero headline profit badge fed by the same record: two figures about the same thing on one card, one of them structurally unable to be right.
- Fixed the plan page returning both figures, so the range shows the plan's advertised terms.
The settlement job logged a database state instead of the real cause
The job credits an investor and then keeps working — writing the record, notifying them. When anything went wrong, its error handler ran a cleanup step against a transaction that may already have been committed or already cleaned up. That step fails on its own, and its failure replaced the real error before it was logged. So the log named a database transaction state instead of the reason a settlement had not completed, on a run whose work may in fact have gone through.
- Fixed the cleanup step standing aside when there is nothing left to clean up, so the log now names the reason a settlement did not complete instead of the complaint that step raised. A run whose settlement had already gone through is still reported as failed — that has not changed, and no investor record was written incorrectly by any of it. What was lost was the ability to find out what had happened.