Skip to content

Support and Refunds ​

Business outcome ​

This page connects order cancellation, after-sales (SAV), and payment refunds while keeping their states separate. A cancellation can create a local pre-refund request, but that request is not a provider payment reversal. A SAV case, a provider submission, a reconciliation result, and a physical return each have separate boundaries. The source review does not establish one universal path from customer request through approval, payment reversal, physical return, stock increase, and notification.

Source-backed sequence ​

View diagram source
sequenceDiagram
  participant C as SAV request caller
  participant B as Chatbot backend
  participant L as Logidav SAV API and service
  participant DB as SaleSav records
  participant A as Authorized Logidav admin action
  participant R as RefundController
  participant P as Payment provider
  participant H as Hipay refund check

  C->>B: POST /api/v2/sav/requests (caller not verified)
  B->>L: POST configured base URL + /sav
  L->>DB: Validate request, resolve sale, record SAV case
  A->>R: Admin-authorized refund action
  R->>P: Provider-specific refund submission
  P-->>R: Provider response
  R->>DB: Persist response/status and action log
  H->>P: Check eligible Hipay transaction
  P-->>H: Refunded / Partially Refunded / other status
  H->>DB: Mark matching Refund and SaleSav complete on the two success values

Diagram

The SAV and payment paths are shown together to clarify the boundary, not to assert that one always triggers the other. The Hipay check is a reconciliation path; the reviewed command does not issue the refund.

Logidav’s operator cancellation path uses the sale controller prefix. The refund actions below use the refund prefix; AppBundle’s annotation import adds no further prefix in the reviewed routing configuration. The operator path is separate from chatbot SAV creation:

View diagram source
sequenceDiagram
  participant O as Logidav operator
  participant C as SaleController
  participant S as SaleService
  participant M as Magento SaleApi
  participant DB as Logidav sale and line records
  participant R as RefundService
  participant A as SAV service

  O->>C: POST /sale/cancel-sale (id, action, optional idsp / option)
  C->>S: cancelSaleOrSaleProduct(local sale ID, action, local line ID)
  alt Whole sale, Menzzo source
    S->>M: POST /V1/logidav-api/change-order-status/{Magento sale ID} status=canceled
    M-->>S: API status
    alt API status is successful
      S->>DB: mark active lines canceled and sale status canceled
      opt option requests pre-refund and/or SAV
        S->>R: addPreRefund(status=0, autorisation=1)
        S->>A: create SAV when selected
      end
    else API status is unsuccessful
      Note over S,DB: Local cancellation state is not applied
    end
  else Partial line with other active lines remaining
    S->>DB: record cancelProduct quantity-log and mark local line canceled
    opt SAV creation is enabled
      S->>A: create product SAV
    end
    Note over S,M: No Magento item-cancel call in this path
  end

Diagram

The id submitted to /sale/cancel-sale is the Logidav sale ID; idsp is the Logidav sale-product ID. Whole-order status writeback uses the Magento order ID stored on the sale. If the requested line is the last active line, or is the only line, Logidav escalates to the whole-sale path.

Numbered handoffs ​

Whole-order and partial-item cancellation ​

  1. The Logidav operator submits POST /sale/cancel-sale with id and action=sale for the whole order, or action=product plus idsp for one line. SaleController::cancelSaleAction() applies access checks and calls SaleService::cancelSaleOrSaleProduct().
  2. For a Menzzo whole-order cancellation, SaleService::cancelSale() first calls SaleApi::changeOrderStatus() with the Magento order ID and status=canceled. Magento's /V1/logidav-api/change-order-status/{orderId} updates order state/status, the order grid status, and writes a status-history row. Logidav changes the local sale and active lines only when the API response reports success; the local order becomes canceled and active lines are marked canceled with isShipped=0.
  3. For a partial cancellation with other active lines remaining, Logidav records a cancelProduct quantity-log action and marks only that local sale-product row canceled. It creates a product SAV unless the do_not_create_sav option is selected. No Magento item-cancel API call was found in this handler path; this is not a provider refund or a Magento per-item cancellation.
  4. When the selected product is the last active product, or is the only product, the service routes through the whole-sale cancellation path above. A failed Magento status response leaves local cancellation state unapplied; compare Magento and Logidav before retrying.
  5. Whole-sale options cancel_sale_and_create_pre_refund and cancel_sale_and_sav_and_create_pre_refund can add a pre-refund row. The second option also creates a SAV. Neither option itself proves that a payment provider has been contacted; submission remains the separate /refund/pre-refund-send action.

SAV case creation ​

  1. The chatbot backend declares an authenticated POST /api/v2/sav/requests requiring order-read,sav-create abilities. Its UI caller was not established.
  2. SavController::createSavV2 validates a v2 request and delegates ordinary ticket creation to handleSavCreation.
  3. LogidavService::createSavTicket() normalizes files, custom fields, and allowed propositions, then calls the configured Logidav base URL plus /sav.
  4. Logidav's MenzzoChatbotWrapperApiController::createSavAction() receives POST /api/sav, requires increment_id and sav_type, resolves the sale, and routes cancellation, forgotten-coupon, and delivery-info-update cases through separate workflows.
  5. SaleSavService::addSav() / addSavFromApi() records an API-created SAV case and filters products. communicationType=ai_chatbot marks chatbot-created records. This is case persistence, not a guarantee of payment reversal.
  6. Logidav's /api/customer/sav-status endpoint can return SAV status, product, planning, and refund details filtered by email or order. The endpoint's caller is not established.

Payment refund submission and reconciliation ​

  1. A pre-refund is a staged Logidav Refund row, not proof that a provider was contacted. The POST /refund/add-pre-refund handler checks CSRF plus admin or PRE_REFUND_FROM_ORDER access, persists a row with status=0 and autorisation=1, creates a SAV, and logs the request. Whole-order cancellation options can also create one through RefundService::addPreRefund(), which calculates the remaining amount as grand total less previously recorded refunds and stores those pending status/authorization values.
  2. POST /refund/pre-refund-send (RefundController::refundAction()) loads the saved row by refund ID and is the provider-submission step. It rejects missing rows, loyalty vouchers on this path, manual/unsupported payment methods, and non-Menzzo orders; the permitted admin/refund roles are checked before the provider-specific branch runs.
  3. Provider outcomes differ. For example, a successful Payline response stores a completed refund (status=1), while a successful Hipay submission stores status=3 for later verification. A provider response or local pending row must not be collapsed into one generic “refunded” state. The reviewed controller branches do not establish one shared duplicate-submission guard for every provider.
  4. The menzzo:refund:check --action=hipay command selects rows with method_payment=Hipay, autorisation=0, and status=3. It queries the transaction and marks the matching Refund (and its linked SAV when present) complete only if the returned transaction ID matches and the provider message is Refunded or Partially Refunded. It sends the refund email; it is reconciliation, not submission. The command source does not establish its installed schedule.
  5. RefundAlertCommand::execute() marks authorized refunds past date_limit as alert. It does not issue a refund. The installed schedule is not established by the command source.
  6. Revolut has a provider-specific persistence safeguard: RevolutRefundPersistenceService::persist() locks the refund row in a transaction, treats status 1 as already completed, and applies SAV/email side effects once. Do not generalize this guarantee to other providers.
  7. The source review does not establish a physical-return-to-stock increment. ProductQtyLogService has no verified return action path or caller in this audit.

Data ownership and contracts ​

Record/actionOwner and pathEvidence limit
SAV caseBackend request → Logidav SAV controller/service and SaleSav records.Case creation and API marking are source-backed; caller and configured base URL prefix are not.
SAV statusLogidav /api/customer/sav-status.The controller filters by email or order and returns named SAV/order details; active callers/configuration are unknown.
Whole-order cancellationLogidav SaleController → SaleService → Magento change-order-status/{orderId} → local sale/lines.Magento response gates the local cancellation update; Magento receives the stored Magento order ID.
Partial-item cancellationLogidav SaleController → SaleService → local sale-product and optional SAV.Last/only active line escalates to whole-order cancellation. A per-item Magento cancellation call was not found in this path.
Pre-refund requestCancellation option or Logidav POST /refund/add-pre-refund → Refund row and, for the admin route, SAV/log entry.Pending state is status=0, autorisation=1; it is a local request awaiting the separate provider action.
Refund submissionAuthorized Logidav admin controller → provider-specific client → local refund response/status.Eligibility checks and provider branches are source-backed; common idempotency/retry behavior is not.
Hipay reconciliationRefundCheckCommand queries Hipay for pending status-3 records.Success results update linked local Refund/SaleSav state and send email. It does not establish who initiated the refund.
Refund alertRefundAlertCommand marks authorized records after date_limit as alert.Alert state is not proof of provider submission, completion, or a configured schedule.
Physical return and stockNo complete producer/path was verified.Do not describe productChangeLog(..., 'return') as an implemented path based on current evidence.

Failures, retries, and duplicates ​

  • SAV base URL: backend configuration determines whether the Logidav URL includes /api; the runtime prefix was not inspected. A source path alone does not establish deployed URL configuration.
  • Forgotten coupon: this case path checks Logidav history before local reservation and fails closed with 503 if history is unavailable. Its idempotency safeguard is specific to this type.
  • Other SAV types: the reviewed code does not establish one universal idempotency guard. Do not replay an uncertain create request until the specific type's behavior is confirmed.
  • Provider submission: the admin controller handles multiple provider responses, but the audit did not establish a common duplicate guard, timeout policy, or retry rule. Revolut's persistence safeguard is provider-specific.
  • Pre-refund vs payment: status=0,autorisation=1 records a pending pre-refund request. It is not provider confirmation. Hipay status=3,autorisation=0 is a submitted refund awaiting reconciliation; only the provider check's matching transaction and success message moves the reviewed path to complete.
  • Whole-order cancellation: Logidav waits for a successful Magento status API response before persisting its local cancellation. A false/failed remote result is a cross-system boundary; compare both owners before retrying.
  • Partial cancellation: this path updates the Logidav line and optionally creates SAV. It does not show a Magento item-level cancel request or a provider refund. The last-active-item case escalates to whole-order cancellation.
  • Hipay check: only rows meeting autorisation=0,status=3 are selected in this path. A non-success provider status is not proof of refund completion; alert/check schedules are unverified.
  • Stock: the former return mutation claim is unsupported. Do not manually increase stock based solely on a refund or SAV status.

Diagnosis ​

  1. Determine whether the issue is a case-creation failure, a case-status lookup, a provider refund submission, or a refund-status reconciliation. These use different handlers and owners.
  2. For a chatbot SAV request, compare the authenticated backend request/result with the Logidav /sav response and the persisted case. Verify the specific sav_type before retrying.
  3. For a refund, use the owning operator's approved reconciliation procedure to compare Logidav's refund status with the provider result. Do not submit a second refund merely because the local status is pending.
  4. For Hipay, distinguish the admin submission from the status-3 check. Refunded/Partially Refunded is the reviewed completion condition in that check path; the command's configured schedule remains unknown.
  5. Treat alert as an operational follow-up signal, not as a provider result.
  6. If a returned physical item needs stock adjustment, stop at the evidence gap and ask for the actual inventory path. Do not assume a refund triggers a stock increment.

For the chatbot request/response chain, see Chatbot to Business API. Existing project notes include Logidav refund/SAV workflows, refund runbooks, and stock flow evidence; follow their corrected limits below.

Evidence and open questions ​

Source-verified at pinned commits: authenticated SAV route, backend-to-Logidav case-creation call, Logidav SAV route and persistence; and, at axelites/logidav@88d9180215a5d489407498fe4905fdd38efd756d, operator whole/partial cancellation, Magento whole-order status handoff, pre-refund persistence, provider submission, and Hipay reconciliation. Earlier Logidav SAV, alert, and Revolut details retain their cited e0b7a25c1912039c1520eb04c1b4c242d74b6d1e review pin.

Still unknown: source UI caller for the SAV route and status lookup; active base URL prefix; complete provider preconditions and retries; common idempotency across providers; schedules; notification coverage outside the inspected paths; refund-to-physical-return stock path; and end-to-end owner acceptance.

Source references: backend SAV route, SAV controller, forgotten-coupon safeguard, and Logidav SAV client; Logidav SAV API, status API, and SAV persistence; plus Logidav refund controller, Hipay check, refund alert, and Revolut persistence safeguard.

Internal developer documentation for Menzzo systems.