Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Woo POS] Always create a new order when checking out #15427

Merged

Conversation

staskus
Copy link
Contributor

@staskus staskus commented Mar 26, 2025

Closes: #15426
Discussion: woocommerce/woocommerce-android#12385

Description

Always create a new order when checking out. This matches the Android solution. Updating the order requires additional diffing logic on the mobile side and sometimes it introduces issues when remote and local orders become out-of-sync.

auto-draft orders are removed by WordPress once 7 days..

We could consider creating checkout-draft orders, that are removed once a day by a cron job.

Steps to reproduce

The original issue I was addressing

Prerequisites: Enable enableCouponsInPointOfSale feature flag in DefaultFeatureFlagService

  1. Add 2 products
  2. Check out so the order would be created
  3. Come back
  4. Remove one of the producs
  5. Add one invalid coupon
  6. Check out
  7. Get error
  8. Come back
  9. Remove an invalid coupon (the Cart should contain only one product now)
  10. Check out again
  11. Confirm order is created successfully

Regression

The changes affect the checkout flow, which could be triggered in two ways:

  1. Tapping Check Out
  2. Tapping 'Try Again' if order creation fails

Test with various types of products:

  1. Select products -> Check out -> Come back -> Make Changes -> Card Payment
  2. Select products -> Check out -> Order creation failure (e.g. no network connection) -> Address Issue (Enable network) -> Try Again -> Card Payment
  3. Select products -> Check out -> Come back -> Checkout -> Order is not loading since it remains unchanged

Testing information

I tested various scenarios with different types of products, variations, and coupons. Also, cash payment and emails.

The order creation logic is not changed, I use the same method for adding order items to the order. Order editing works as order creation now.

Screenshots


  • I have considered if this change warrants user-facing release notes and have added them to RELEASE-NOTES.txt if necessary.

Reviewer (or Author, in the case of optional code reviews):

Please make sure these conditions are met before approving the PR, or request changes if the PR needs improvement:

  • The PR is small and has a clear, single focus, or a valid explanation is provided in the description. If needed, please request to split it into smaller PRs.
  • Ensure Adequate Unit Test Coverage: The changes are reasonably covered by unit tests or an explanation is provided in the PR description.
  • Manual Testing: The author listed all the tests they ran, including smoke tests when needed (e.g., for refactorings). The reviewer confirmed that the PR works as expected on all devices (phone/tablet) and no regressions are added.

@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Mar 26, 2025

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

App NameWooCommerce iOS Prototype
Build Number29038
VersionPR #15427
Bundle IDcom.automattic.alpha.woocommerce
Commit003e42e
Installation URL2ec46a9gecvmo
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@staskus staskus added the type: task An internally driven task. label Mar 27, 2025
@staskus staskus added this to the 22.1 milestone Mar 27, 2025
@staskus staskus marked this pull request as ready for review March 27, 2025 14:05
@joshheald
Copy link
Contributor

joshheald commented Mar 27, 2025

The repro steps don't always work. When I come back at step 11, it sometimes still shows the invalid coupons error. Is that expected at this point, and unrelated to the PR?

I'm guessing that removing the coupon isn't noticed as a change to the cart, so the order isn't recalculated... but it has worked sometimes. Adding a coupon to the cart is reliably noticed as a change, but not removing it.

coupon-error-remains.mp4

Edit: I guess that the coupon.matches(order) check would return true after the coupon is removed – the API removes the coupon from the order itself, right?

Copy link
Contributor

@joshheald joshheald 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 this – It's a nice simplification of the logic. Other than the issue mentioned about not reliably recognising invalid coupon removal, I found it worked well in my testing...

return order
private extension Order {
func addItems(_ cartItems: [POSCartItem]) -> Order {
let itemsToAdd = Array(cartItems.createGroupedOrderSyncProductInputs().values)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to call sanitizingLocalItems on these, or is that only relevant for updates?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

😨 I missed it.

Great observation. We do need it. As the comment in the sanitizingLocalItems says, not applying it breaks the calculations if prices_include_tax is true.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, glad I spotted it then! I wasn't sure because it could have been something only required on update... though, our products are all added as an update, aren't they? Rather than in the initial POST request?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

though, our products are all added as an update, aren't they? Rather than in the initial POST request?

No. We add them as initial request when creating an order. createGroupedOrderSyncProductInputs turns products into order items. sanitize makes sure totals and subtotals are cleared and don't influence backend calculations.

Copy link
Contributor

@joshheald joshheald Mar 28, 2025

Choose a reason for hiding this comment

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

Ah, makes sense! Yeah, I'm all for just sending up an ID and a quantity as our input. Factors in to the line/cart-level discount/taxes discussion as well.

Ideally, if we ever allow merchants to add line-level discounts like they can in IPP, we could make a change in the API that lets us specify a discount directly, and whether that's before or after tax.

staskus added 2 commits March 28, 2025 09:34
Sanitizing removes order item totals and subtotals, allowing the backend to calculate it. It's critical for correct calculations when prices are inputted with taxes.
@staskus
Copy link
Contributor Author

staskus commented Mar 28, 2025

The repro steps don't always work. When I come back at step 11, it sometimes still shows the invalid coupons error. Is that expected at this point, and unrelated to the PR?

I'm guessing that removing the coupon isn't noticed as a change to the cart, so the order isn't recalculated... but it has worked sometimes. Adding a coupon to the cart is reliably noticed as a change, but not removing it.

Good catch. Why it happens:

  1. Create and persist order (Add Product -> Check out -> Sync -> Come Back).
  2. Add invalid coupon, API returns error, order doesn't change (Add Invalid Coupon -> Check out -> Sync -> Error -> Come Back).
  3. Remove invalid coupon, cart state is equal to order state, sync is not initialized (Remove Coupon -> Check out -> Error).

The way to get around this cleanly is to always sync the next time after an error is returned from the API.

@staskus staskus merged commit 5aa8624 into trunk Mar 28, 2025
13 checks passed
@staskus staskus deleted the task/15326-pos-always-create-a-new-order-during-checkout branch March 28, 2025 09:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature: POS type: task An internally driven task.
Projects
None yet
3 participants