Skip to content

Conversation

@samiuelson
Copy link
Contributor

@samiuelson samiuelson commented Dec 23, 2025

WOOMOB-1855

Description

This PR allows creating a full refund in Woo POS in a happy path refund scenario.

💡 The UI of the loading states, error, and success states is not in scope of this PR-it will be updated in the next iteration.

Test Steps

  1. Create order in POS and try creating a full refund through the POS Orders screen. To test:
    a) order containing a single item
    b) order containing multiple items
    c) order containing multiple quantities of the same item
  2. Verify that the network request and server response look as expected.
  3. Verify the order is properly refunded in wp-admin.

Images/gif

demo-19-dec.mp4
  • I have considered if this change warrants release notes and have added them to RELEASE-NOTES.txt if necessary. Use the "[Internal]" label for non-user-facing changes.

@samiuelson samiuelson added the type: task An internally driven task. label Dec 23, 2025
@samiuelson samiuelson added this to the 23.9 milestone Dec 23, 2025
@dangermattic
Copy link
Collaborator

dangermattic commented Dec 23, 2025

1 Warning
⚠️ This PR is larger than 300 lines of changes. Please consider splitting it into smaller PRs for easier and faster reviews.

Generated by 🚫 Danger

@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Dec 23, 2025

📲 You can test the changes from this Pull Request in WooCommerce-Wear Android by scanning the QR code below to install the corresponding build.
App NameWooCommerce-Wear Android
Platform⌚️ Wear OS
FlavorJalapeno
Build TypeDebug
Commit0c891a8
Direct Downloadwoocommerce-wear-prototype-build-pr15135-0c891a8.apk

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements full refund functionality in the Woo POS by adding refund processing capabilities, new UI states for handling loading/success/error scenarios, and calculation logic for refund amounts including taxes. The implementation follows a happy path refund flow where all items in an order can be refunded at once.

Key changes include:

  • Addition of refund calculation utilities (subtotal, tax, and item grouping)
  • Integration with WCRefundStore API to create refunds
  • New state machine transitions for processing, success, and error states

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
RefundRequestItem.kt Made refundTotal and refundTax fields nullable with default null values to support optional refund data
WooPosRefundViewModel.kt Added refund processing logic, state management for Processing/Success/Error states, and changed data source method from getOrderById to refreshOrderById
WooPosRefundState.kt Added Processing, RefundSuccess, and RefundError states to handle refund operation lifecycle
WooPosIssueRefundDialog.kt Added UI handling for Processing state with loading indicator and RefundSuccess/RefundError states with appropriate content
WooPosGroupRefundItems.kt New utility class to group refundable items by order item ID and calculate refund totals and taxes
WooPosCalculateRefundTax.kt New utility class to calculate proportional tax amounts for refunded items
WooPosCalculateRefundSubtotal.kt New utility class to calculate refund subtotals by summing unit prices
WooPosRefundableItem.kt Removed lineTotal and lineTax computed properties (calculation moved to dedicated utilities)
WooPosRefundViewModelTest.kt Updated all test mocks to use refreshOrderById instead of getOrderById and added new dependencies to test setup
WooPosGroupRefundItemsTest.kt Comprehensive test coverage for item grouping logic including edge cases
WooPosCalculateRefundTaxTest.kt Test coverage for tax calculation including partial and full refunds
WooPosCalculateRefundSubtotalTest.kt Test coverage for subtotal calculation with various item combinations

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Dec 23, 2025

📲 You can test the changes from this Pull Request in WooCommerce Android by scanning the QR code below to install the corresponding build.

App NameWooCommerce Android
Platform📱 Mobile
FlavorJalapeno
Build TypeDebug
Commit0c891a8
Direct Downloadwoocommerce-prototype-build-pr15135-0c891a8.apk

@codecov-commenter
Copy link

codecov-commenter commented Dec 23, 2025

Codecov Report

❌ Patch coverage is 53.84615% with 102 lines in your changes missing coverage. Please review.
✅ Project coverage is 38.67%. Comparing base (d875427) to head (0c891a8).
⚠️ Report is 15 commits behind head on trunk.

Files with missing lines Patch % Lines
...ndroid/ui/woopos/orders/WooPosIssueRefundDialog.kt 0.00% 73 Missing ⚠️
.../android/ui/woopos/orders/WooPosRefundViewModel.kt 69.01% 8 Missing and 14 partials ⚠️
...android/ui/woopos/orders/WooPosGroupRefundItems.kt 86.66% 2 Missing and 2 partials ⚠️
.../android/ui/woopos/orders/WooPosOrdersViewModel.kt 57.14% 1 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##              trunk   #15135      +/-   ##
============================================
+ Coverage     38.65%   38.67%   +0.02%     
- Complexity    10513    10534      +21     
============================================
  Files          2189     2192       +3     
  Lines        124277   124450     +173     
  Branches      17170    17199      +29     
============================================
+ Hits          48039    48137      +98     
- Misses        71397    71457      +60     
- Partials       4841     4856      +15     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@samiuelson samiuelson marked this pull request as ready for review January 5, 2026 14:55
@samiuelson samiuelson requested a review from malinajirka January 5, 2026 14:55
@malinajirka malinajirka self-assigned this Jan 6, 2026
Copy link
Contributor

@malinajirka malinajirka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @samiuelson!

I found some potential issues. Some of them are likely not bugs, but simply parts of the feature that aren't implemented yet.

  1. The refund total was one cent off. There is a chance the same happens even in store management or even wpadmin, I haven't tested that.
Screenshot 2026-01-06 at 11 55 05 Screenshot 2026-01-06 at 11 55 14 Screenshot 2026-01-06 at 11 56 41 Screenshot 2026-01-06 at 12 02 37

I was able to replicate this on another order on my store:
Screenshot 2026-01-06 at 12 15 51

  1. It seems even when I do a full refund, the order remains in Completed status instead of Refunded.

  2. Edit Reason button doesn't do anything.

  3. I noticed there is a cross/close icon on the 'processing refund' dialog - it doesn't do anything.

  4. The refund VM seems to survive so when it's in a certain state (failed/success) I can't get it out of it:

Screen.Recording.2026-01-06.at.12.05.28.mov
  1. Some orders simply say 'Invalid refund amount`:
Screenshot 2026-01-06 at 12 10 23

Request

{
  "path": "/wc/v3/orders/5413/refunds/\u0026_method\u003dpost",
  "json": "true",
  "body": "{\"reason\":\"\",\"amount\":\"1.311835\",\"api_refund\":\"false\",\"line_items\":[{\"id\":6892,\"quantity\":1,\"refund_tax\":[{\"refund_total\":0.11,\"id\":3}],\"refund_total\":1.201835}],\"restock_items\":true}"
}

Response

{
  "error": "woocommerce_rest_cannot_create_order_refund",
  "message": "Invalid refund amount."
}

@samiuelson
Copy link
Contributor Author

Thanks for catching these, @malinajirka! 🙇

  1. The refund total was one cent off. There is a chance the same happens even in store management or even wpadmin, I haven't tested that.

I could reproduce that in my store. The issue should have been fixed with: 2672896 and 3271365.

  1. It seems even when I do a full refund, the order remains in Completed status instead of Refunded.

This seems to be related to 1. If the refund is not full (e.g., refund amount is off by 0.01 the order is not marked refunded).

  1. Edit Reason button doesn't do anything.

This will be implemented in next iteration: WOOMOB-1775

  1. I noticed there is a cross/close icon on the 'processing refund' dialog - it doesn't do anything.

Thanks, noted; I will address in next PR: WOOMOB-1952

  1. The refund VM seems to survive so when it's in a certain state (failed/success) I can't get it out of it:

Thanks, noted; I will fix this in another PR: WOOMOB-1951

  1. Some orders simply say 'Invalid refund amount`:

Thanks for providing more context! I could reproduce that in my store and believe it's been fixed with: 2672896 and 3271365. In case you encounter such bug in the future, please add me to the store so I can debug it further 🙇.

@samiuelson samiuelson requested a review from malinajirka January 7, 2026 18:36
Copy link
Contributor

@malinajirka malinajirka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates @samiuelson! They look good and some of the issues are gone. However, I'm still able to reproduce the 'one cent off' issue (it more or less works in the store management part of the app). See the attached video with voice description of what's happening.

Screen.Recording.2026-01-08.at.11.36.11.mov

The order detail is not refreshed on successful refund (even refund which doesn't end up in the one cent off issue). This is reproduced and mentioned in the video as well.

I'm reproducing this on https://site-for-woocommerce12a3fasdf45dfs6789.mystagingwebsite.com/ with three Apple Ring products in the order. You are admin on the site. Let me know if I can help somehow.

@samiuelson
Copy link
Contributor Author

I'm still able to reproduce the 'one cent off' issue (it more or less works in the store management part of the app). See the attached video with voice description of what's happening.

Thanks so much for providing a reproducible scenario, @malinajirka. I investigated the discrepancies and found out they are caused by the Prices entered with tax setting. In case the setting is set to Yes, I will enter prices inclusive of tax the price of the item is not being rounded (doesn't respect decimal precision setting). I updated the logic to match the backend logic - the rounding is applied to the total values of items and taxes (instead of unit values). Changed in: dba9693

The order detail is not refreshed on successful refund (even refund which doesn't end up in the one cent off issue). This is reproduced and mentioned in the video as well.

Order refreshing after the refund is going to be implemented as a separate task: WOOMOB-1955

@samiuelson samiuelson requested a review from malinajirka January 8, 2026 12:57
@wpmobilebot wpmobilebot modified the milestones: 23.9, 24.0 Jan 9, 2026
@wpmobilebot
Copy link
Collaborator

Version 23.9 has now entered code-freeze, so the milestone of this PR has been updated to 24.0.

@malinajirka
Copy link
Contributor

malinajirka commented Jan 9, 2026

Thanks @samiuelson!

If it would be possible, I think it'd be great to add specific tests for every bug we fix - just to ensure, we don't re-introduce them later. Ideally, the test would even mention the Yes, I will enter prices inclusive of tax setting so it's possible to do a manual test based on the unit test.

The fix works for the Apple Ring, however, I'm still able to reproduce similar rounding issues. If I recall correctly, there is a setting in Core somewhere which says whether items should be rounded per unit vs per row in the order. It's a random guess, but it could perhaps be related?

You should be able to reproduce these issues on my store except of the first one(https://site-for-woocommerce12a3fasdf45dfs6789.mystagingwebsite.com/):

This one might not be easy to reproduce - I think it might be related to the fact that the missing item has been trashed/deleted from the store.

Screen.Recording.2026-01-09.at.14.17.43.mov
Screen.Recording.2026-01-09.at.14.19.59.mov
Screen.Recording.2026-01-09.at.14.21.44.mov

@malinajirka
Copy link
Contributor

One more thing that could be related - there is a dp (decimal places`) parameter on the API, so might be worth double checking we fetch the orders with enough decimal precision. There is also a chance, fixing all these issues is impossible - I know we have been dealing with these kind of issues in the store management and I'm not sure we ever fixed all of them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: task An internally driven task.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants