# Autogedal_TbiBank

Adds configurable production/UAT selection to TbiBank_FusionPay without editing the vendor module.

In **Stores > Configuration > Fusion Pay RO Settings**, at **Default Config** scope:

- **Autogedal - Connection Environment > Test Mode = No** uses Production Platform URL and the existing Production Account / General Settings credentials.
- **Test Mode = Yes** uses UAT Platform URL and the separate UAT Account credentials. Missing UAT credentials never fall back to production.
- Both platform URLs are editable HTTPS origins (no `/api` suffix, path, credentials, query, or fragment). Defaults: production `https://ro.tbibank.support`, UAT `https://ro.tbi-uat.online`.
- Public UAT reseller identifiers default to `TBI_test` / `tbitest`. Enter the test encryption key from [TBI RO FusionPay documentation](https://tbigroup.atlassian.net/wiki/spaces/TSFMPU/pages/4496752652/API+documentation+-+RO+Fusion+Pay), or credentials supplied for a dedicated test account. The UAT encryption key is stored using Magento's encrypted config backend.
- Save the Fusion Pay settings to synchronize the selected account. UAT activation status and API-derived limits are stored separately from production. UAT Minimum/Maximum Amount fields are also separate.

Both production and UAT encryption-key fields are obscured and use Magento's encrypted storage. Reads decode Magento ciphertext once and preserve already processed values. Existing production keys stored as plaintext remain compatible; re-enter the key once and save to encrypt its stored value. Saving the masked `*****` value preserves the existing key, following Magento behavior. No database migration or live credential update is performed by this implementation. Invalid/undecryptable Magento ciphertext raises a generic error rather than being used as a TBI key.

The switch is installation-wide. Avoid switching while applications are in progress: callbacks use the currently selected account's encryption key. Production credential fields retain the original module's scope behavior.

## TBI approval and courier collection

TBI orders never collect cash through the courier. The companion module clears `repayment_value` on AWB resource save and load, including existing AWBs loaded for retry. Other payment methods keep their existing repayment value. This affects future courier requests; it does not change an AWB already issued by a carrier.

On an `Approved` status passed by the vendor callback handler, the module records the financing as a paid native Magento invoice using offline capture (no TBI capture API call). The order remains in the project state `pending`, with configured approved status `new` by default. Every TBI order starts with `asteptare_plata_tbi` and remains there until approval. The configurable AWB gate controls only whether courier generation is allowed before approval; it never changes the waiting status or releases the order to `new`. The waiting status is assigned to both `new` and `pending` states, matching PayPo (non-default, visible on storefront). The setup patch only registers this new waiting status; it does not change existing `new` status mappings or defaults. It clears `is_in_process` so Magento's native save-time state handler does not automatically move the order to processing. SmartBill generation remains a separate later fulfilment operation.

Approval handling locks the order row and records a marker in payment additional information in the same transaction as the invoice/order/grid writes. Duplicate approvals do not create another invoice or reopen a subsequently fulfilled, canceled or refunded order. Unknown/ambiguous merchant order numbers, non-TBI payments, orders outside the waiting state/status, mismatched invoice totals and existing unpaid invoices requiring reconciliation are rejected. Failures roll back the writes and propagate an error to the vendor callback handler. Approval is local payment accounting, not proof of settlement by TBI.

## TBI callback scenarios

The vendor gateway accepts both the documented callback field names and the legacy names used by older Fusion Pay payloads:

| Documented field | Legacy field | Meaning |
| --- | --- | --- |
| `OrderId` | `order_id` | Merchant order increment ID |
| `Status` | `status` | TBI application status code |
| `ContractNumber` | `contract_id` / `Contract_id` | TBI contract identifier |
| `Message` | `message` | TBI status message |
| `Motive` | `motive` | TBI reason, when provided |

The encrypted status callback is expected to contain `command=update_status`. Status handling is:

| TBI code | TBI meaning | Magento behavior |
| --- | --- | --- |
| `1` | Approved | Records the payment as an offline Magento invoice, sets the configured approved status (default `new`) in the `pending` state, stores the contract, and adds a human-readable history entry. |
| `2` | In Progress | Updates only the TBI status; the order remains `pending / asteptare_plata_tbi`. |
| `0` | Canceled | Keeps the order waiting, updates the TBI status, and adds a cancellation history entry. |
| `3` | Rejected | Keeps the order waiting, updates the TBI status, and adds a rejection history entry containing `Message` and `Motive` when available. |
| `4` | Refund Registered | Not implemented as a dedicated refund flow; the current vendor mapping falls back to `Draft`. |

For `failRedirectURL`, TBI sends no documented status payload or reason. The signed redirect contains the merchant order identifier and signature only. A valid redirect records a neutral history message stating that the application was not finalized and the customer returned without approval; it must not claim that TBI rejected the application. An invalid signature does not update the order.

Callbacks update the canonical `sales_order` through the order model/resource path. Magento's native order-grid synchronization updates `sales_order_grid`; the callback code does not treat the grid as the source of truth. A callback received after the order has left the TBI waiting state may update `tbi_status`, but it cannot reopen or replace the Magento order status. Duplicate approvals do not create another invoice or approval email.

### Local validation

The following scenarios were emulated against `https://agd24.local:8890` using local order `300138800`, then the order was restored to its original state (`cashondelivery`, `pending / new`, `tbi_status=In Progress`, no contract, invoice, or test history):

- **Official approved IPN:** encrypted payload using `OrderId`, `Status=1`, `Message`, `Motive`, and `ContractNumber`. Verified the order update, grid synchronization, invoice creation, and human-readable history entry containing the message, motive, and contract.
- **Failure redirect:** signed `/tbi/failure/` request. Verified `pending / asteptare_plata_tbi`, `tbi_status=Canceled`, grid synchronization, and the neutral abandonment/failure history entry.

The following are covered by the current code paths and unit tests but have not yet been emulated end-to-end locally: official `Rejected`, `Canceled`, and `In Progress` IPNs; duplicate approved IPN; a callback after fulfilment; unknown/non-TBI orders; invalid failure signatures; and payloads with optional fields omitted. The dedicated `Status=4` refund behavior remains an open implementation decision.

The existing callback authentication/integrity finding is not resolved here. Full callback delivery, database concurrency and carrier payloads still need operator-controlled end-to-end verification; no production/live order, invoice, AWB or TBI request was created during implementation.

The module redirects merchant API requests, product calculator JSON URLs, checkout calculator URLs, and the Luma/Hyva iframe message origins. CSP adds the configured active origin. Public CDN/version-check requests remain unchanged. URL replacement matches only the vendor's exact origin, not lookalike hosts or unrelated requests.

No external TBI request was used during implementation; only encrypted local callback payloads and the local failure redirect were emulated. TBI's plugin settings and calculator availability in UAT must be verified before an external end-to-end test. The documented RO callbacks/refund/cancellation availability limitations and the existing payment/order/AWB findings are not resolved by environment configuration.

For Romanian (`ro_RO`) storefronts, the module supplies checkout title, description, repayment-plan link and logo alternative-text translations. A RequireJS template map makes the logo alternative text translatable without modifying FusionPay. Existing static translation assets must be refreshed through the operator's normal deployment workflow for these changes to appear; no deployment/cache commands are run by this implementation.

The module is registered through `registration.php` and `etc/module.xml`. `app/etc/config.php` is not edited by this implementation. Setup, compilation, deployment, and cache commands are left to the operator.

Unit checks against the installed Magento classes:

```sh
/opt/homebrew/opt/php@8.3/bin/php vendor/bin/phpunit --no-configuration --bootstrap dev/tests/unit/framework/bootstrap.php --do-not-cache-result app/code/Autogedal/TbiBank/Test/Unit
```
