Appearance
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
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
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
- The Logidav operator submits
POST /sale/cancel-salewithidandaction=salefor the whole order, oraction=productplusidspfor one line.SaleController::cancelSaleAction()applies access checks and callsSaleService::cancelSaleOrSaleProduct(). - For a Menzzo whole-order cancellation,
SaleService::cancelSale()first callsSaleApi::changeOrderStatus()with the Magento order ID andstatus=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 becomescanceledand active lines are marked canceled withisShipped=0. - For a partial cancellation with other active lines remaining, Logidav records a
cancelProductquantity-log action and marks only that local sale-product row canceled. It creates a product SAV unless thedo_not_create_savoption 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. - 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.
- Whole-sale options
cancel_sale_and_create_pre_refundandcancel_sale_and_sav_and_create_pre_refundcan 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-sendaction.
SAV case creation
- The chatbot backend declares an authenticated
POST /api/v2/sav/requestsrequiringorder-read,sav-createabilities. Its UI caller was not established. SavController::createSavV2validates a v2 request and delegates ordinary ticket creation tohandleSavCreation.LogidavService::createSavTicket()normalizes files, custom fields, and allowed propositions, then calls the configured Logidav base URL plus/sav.- Logidav's
MenzzoChatbotWrapperApiController::createSavAction()receivesPOST /api/sav, requiresincrement_idandsav_type, resolves the sale, and routes cancellation, forgotten-coupon, and delivery-info-update cases through separate workflows. SaleSavService::addSav()/addSavFromApi()records an API-created SAV case and filters products.communicationType=ai_chatbotmarks chatbot-created records. This is case persistence, not a guarantee of payment reversal.- Logidav's
/api/customer/sav-statusendpoint 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
- A pre-refund is a staged Logidav
Refundrow, not proof that a provider was contacted. ThePOST /refund/add-pre-refundhandler checks CSRF plus admin orPRE_REFUND_FROM_ORDERaccess, persists a row withstatus=0andautorisation=1, creates a SAV, and logs the request. Whole-order cancellation options can also create one throughRefundService::addPreRefund(), which calculates the remaining amount as grand total less previously recorded refunds and stores those pending status/authorization values. 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.- Provider outcomes differ. For example, a successful Payline response stores a completed refund (
status=1), while a successful Hipay submission storesstatus=3for 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. - The
menzzo:refund:check --action=hipaycommand selects rows withmethod_payment=Hipay,autorisation=0, andstatus=3. It queries the transaction and marks the matchingRefund(and its linked SAV when present) complete only if the returned transaction ID matches and the provider message isRefundedorPartially Refunded. It sends the refund email; it is reconciliation, not submission. The command source does not establish its installed schedule. RefundAlertCommand::execute()marks authorized refunds pastdate_limitas alert. It does not issue a refund. The installed schedule is not established by the command source.- Revolut has a provider-specific persistence safeguard:
RevolutRefundPersistenceService::persist()locks the refund row in a transaction, treats status1as already completed, and applies SAV/email side effects once. Do not generalize this guarantee to other providers. - The source review does not establish a physical-return-to-stock increment.
ProductQtyLogServicehas no verifiedreturnaction path or caller in this audit.
Data ownership and contracts
| Record/action | Owner and path | Evidence limit |
|---|---|---|
| SAV case | Backend 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 status | Logidav /api/customer/sav-status. | The controller filters by email or order and returns named SAV/order details; active callers/configuration are unknown. |
| Whole-order cancellation | Logidav 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 cancellation | Logidav 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 request | Cancellation 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 submission | Authorized 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 reconciliation | RefundCheckCommand 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 alert | RefundAlertCommand marks authorized records after date_limit as alert. | Alert state is not proof of provider submission, completion, or a configured schedule. |
| Physical return and stock | No 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=1records a pending pre-refund request. It is not provider confirmation. Hipaystatus=3,autorisation=0is 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=3are selected in this path. A non-success provider status is not proof of refund completion; alert/check schedules are unverified. - Stock: the former
returnmutation claim is unsupported. Do not manually increase stock based solely on a refund or SAV status.
Diagnosis
- 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.
- For a chatbot SAV request, compare the authenticated backend request/result with the Logidav
/savresponse and the persisted case. Verify the specificsav_typebefore retrying. - 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.
- For Hipay, distinguish the admin submission from the status-3 check.
Refunded/Partially Refundedis the reviewed completion condition in that check path; the command's configured schedule remains unknown. - Treat
alertas an operational follow-up signal, not as a provider result. - 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.