============================== POS CashDro Payment Flow Fixes ============================== .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta .. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 |badge1| |badge2| ``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. **Table of contents** .. contents:: :local: Usage ===== There is nothing to configure: installing the module is enough. Before anything else, check the payment method ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18.0 added the ``payment_method_type`` field (*Integration*) to ``pos.payment.method``, and core clears ``use_payment_terminal`` whenever it is saved as *None required*. On **Point of Sale ‣ Configuration ‣ Payment Methods**, the CashDro method must have: * **Integration** = *Terminal* * **Integrate with** = *Cashdro* * the terminal host, user and password filled in With *Integration* left at *None required* the terminal is not wired at all: clicking the payment method just adds a plain cash line, and nothing is ever sent to the drawer — no dialog, no error, no traffic. On site ~~~~~~~ #. Open a PoS session, add a product and go to the payment screen. #. Select the CashDro payment method. The payment line must show **0**, not the due amount (that one comes from ``pos_payment_method_cashdro_fix``). #. The drawer must start the operation and ask for the amount. If it still fails, the dialog now carries the reason instead of the generic sentence, and the browser console has the full error under ``[CASHDRO]``. What to expect: ``The CashDro payment method '...' has no terminal host configured.`` The credentials did not reach the front end. Either the fields are empty on the payment method, or ``pos_payment_method_cashdro_fix`` is not installed. ``TypeError: Failed to fetch`` / ``NetworkError`` The browser cannot reach ``cashdro_host``. Check the host and that the till is on the same network as the drawer. A PoS served over HTTPS also blocks a plain ``http://`` drawer as mixed content, which shows up here. ``The CashDro answered 401/403/500 ...`` The drawer is reachable and answering: wrong user or password, or the CashDro3WS service is failing. ``The CashDro did not return an operation id: ...`` The drawer refused ``startOperation``. Its own envelope is in the message — usually a busy drawer with an operation still open from a previous failure. ``The CashDro did not finish the operation in time.`` ``startOperation`` was accepted but the drawer never reached the finished state within five minutes. There are no automated tests: the flow needs a CashDro terminal answering on the network, which is also why none of this is caught by the OCA CI. Known issues / Roadmap ====================== Split from ``pos_payment_method_cashdro_fix`` on purpose: that module is a temporary patch for three migration leftovers, meant to disappear as soon as its ``upstream/*.patch`` is merged in ``OCA/pos``. This one has a longer life — only the ``pos_session`` fix is a migration leftover, the rest are problems the module has carried since 17.0 — so it should not go away with it. It supersedes the ``_cashdro_url()`` patch of ``pos_payment_method_cashdro_fix`` (same method, resolved from the terminal instead of the selected line, raising instead of returning ``false``). Once the upstream patch is merged, the dependency has to be moved to ``pos_payment_method_cashdro`` and the ``_load_pos_data_fields`` override checked, as it is the only part of the other module this one really needs. Still open: * The success path leaves the operation open on the drawer, as upstream does. Whether the CashDro3WS expects a ``finishOperation`` after a finished operation could not be checked without a machine, so the behaviour was left untouched. * ``_cashdro_url()`` does not escape the user and the password, again as upstream does: credentials containing ``&``, ``=`` or ``#`` break the query string. * The whole thing wants a tour with a mocked CashDro3WS endpoint, which would also let the OCA CI catch this class of breakage. Contributors ============ * `Criptomart `_: * Criptomart