`_cashdro_payment_url()` builds the startOperation url with `this.pos.pos_session.name`. 18.0 replaced that accessor by the `session` getter of PosStore, so reading `.name` on the resulting `undefined` raises a TypeError on every single payment, before any request leaves the browser. `cashdro_send_payment_request` catches it with a bare `catch` that neither logs nor rethrows and shows the generic "error connecting to the cashdro", which is why the failure looked like a problem with the machine. `pos_payment_method_cashdro_fix` only covers the data loading, so this goes in a module of its own: it has a longer life than that temporary patch, and it supersedes its `_cashdro_url()` override. Along with the blocking one, the flow gets: * the real error logged and shown in the dialog, so a wrong host, a busy drawer and a dead network stop being the same sentence, * a missing host raised instead of the boolean `false` travelling into `fetch`, where it resolves against the Odoo server, * `finishOperation` always sent on failure, or the drawer keeps the operation open and refuses every later payment of the session, * polling on a 700ms interval with a 5 minute deadline, stopped by a cancel or by leaving the payment screen, instead of a tight unbounded loop, * `send_payment_cancel()` returning whether the drawer took it, so the line no longer sticks in `waitingCard`, * reversals sending the amount of the line negated: `get_due()` only discounts the payments already done, so the base module asked the drawer to collect the money a second time instead of dispensing it, * the `uuid` of the line honoured instead of the selected one, * the CashDro answers validated (HTTP status, JSON body, operation id). `_cashdro_amount()` is split out as the single hook for the amount, which `pos_payment_method_cashdro_rounding` uses. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
54 lines
3.4 KiB
ReStructuredText
54 lines
3.4 KiB
ReStructuredText
``pos_payment_method_cashdro_fix`` patches the three 17.0 leftovers that the
|
|
18.0 migration of ``pos_payment_method_cashdro`` left in the *data loading*.
|
|
This module takes care of the *payment flow* itself, which stays broken after
|
|
them.
|
|
|
|
**The blocking one.** ``_cashdro_payment_url()`` builds the ``startOperation``
|
|
url with ``this.pos.pos_session.name``. 18.0 replaced that accessor by the
|
|
``session`` getter of ``PosStore``, so ``this.pos.pos_session`` is ``undefined``
|
|
and reading ``.name`` on it raises a ``TypeError`` **on every single payment,
|
|
before any request leaves the browser**.
|
|
``cashdro_send_payment_request`` catches it with a bare ``catch`` that neither
|
|
logs nor rethrows, and shows *"An error occurred while connecting to the
|
|
cashdro"* — the same message a network failure or an unplugged drawer produce.
|
|
That is why the failure looks like a communication problem with the machine,
|
|
and why it happens with any other module of ours enabled or disabled.
|
|
|
|
**The rest.** Once the payment goes through, the flow still has these problems,
|
|
all of them fixed here:
|
|
|
|
#. **Failures are invisible.** The ``catch`` has no error binding, so nothing
|
|
reaches the browser console. Every cause — a wrong host, a busy drawer, a
|
|
bad password, an API mistake — reads as the same sentence. The error is now
|
|
logged and its message shown in the dialog.
|
|
#. **A missing host is not reported.** ``_cashdro_url()`` returns the boolean
|
|
``false``, which the callers concatenate into ``"false&operation=..."``;
|
|
``fetch`` resolves that against the Odoo server, gets a 404 page back and the
|
|
operator sees a connection error. It now raises with the method name.
|
|
#. **A started operation is never closed on failure.** If the acknowledge or the
|
|
polling fails after ``startOperation`` succeeded, the CashDro keeps the
|
|
operation open and refuses the next one: every later payment of the session
|
|
fails until the drawer is power cycled. ``finishOperation`` is now always
|
|
sent.
|
|
#. **The polling has no interval, no bound and no way to stop.** The base
|
|
implementation re-asks the drawer as fast as the network allows for as long
|
|
as the customer is inserting coins, and keeps going after a cancel. It is now
|
|
a 700 ms interval with a 5 minute deadline, stopped by a cancel or by leaving
|
|
the payment screen.
|
|
#. **A cancel is reported as failed.** ``send_payment_cancel()`` resolves to
|
|
``undefined``, which ``payment_screen`` reads as "the cancel failed" and
|
|
leaves the line stuck in ``waitingCard``, re-entering the cancel on every
|
|
click. It now returns whether the drawer took it.
|
|
#. **A reversal asks the drawer to collect the money again.**
|
|
``order.get_due()`` only discounts the payments that are already done, and
|
|
the line being reversed is not one of them, so the amount comes out positive
|
|
and the operation type is 4 (payment) instead of 3 (refund). The reversal
|
|
now uses the amount of the line, negated.
|
|
#. **The uuid of the line is ignored.** The three ``PaymentInterface`` entry
|
|
points receive the uuid of the line to act on and the base module works on
|
|
the selected one instead. The per-line *Send* and *Reverse* buttons do not
|
|
select the line first, so with two payment lines on the order the CashDro
|
|
works on the wrong one.
|
|
#. **The answers are not validated.** An HTTP error page or an envelope without
|
|
``data`` are taken as valid: the module acknowledges an empty operation id
|
|
and polls it forever. Both are now checked.
|