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

[City OFN Voucher] A shopper can use a VINE voucher #12949

Merged
merged 33 commits into from
Dec 3, 2024

Conversation

rioug
Copy link
Collaborator

@rioug rioug commented Oct 29, 2024

⚠️ When working on this use the Clockify code: Citi Food Vouchers: #1A. #11922 Citi OFN Voucher - VINE Integration ⚠️

What? Why?

It lets a customer use a VINE voucher on their order. OFN will communicate with the VINE Api :

  • First, to validate a voucher when it's added to the order
  • Then on checkout, to redeem the voucher
    VINE voucher are managed on the VINE platform : https://vine-staging.openfoodnetwork.org.au/login , as such they won't show on the voucher admin page.

What should we test?

Set up:
!! Make sure "connected_apps" feature is turned on
Logged as an enterprise to VINE, in the backoffice as an enterprise manager :

  • Visit the enterprise setting and click on "connected apps" in the left hand side menu
  • Enter you api key and associated secret in the "Voucher Integration Engine (VINE)" section

Log into VINE https://vine-staging.openfoodnetwork.org.au/ :

  • set your team to "OFN test - service" by clicking on your name in the top right hand side choosing "OFN test - service"
  • Click on "Voucher sets" on the top right hand side menu, you should now see a voucher set ( NOTE: the two last voucher set have $1 voucher, I would recommend using those ones for testing, unless testing partial redemption/redemption by multiple enterprises)
  • Clicking on the voucher set, you'll get access to a list of voucher you can use for testing
Normal checkout

Make sure you have an order cycle set up with the enterprise you connected to VINE set as a distributor, set your team in VINE to "OFN test - merchant"

  • start an order and proceed to checkout
  • advance to payment method
    --> you should see a voucher input
    • try adding a random code
      --> you should get a not found error
    • try adding a voucher using the short code
      --> the 1$ voucher should be added to the order
    • switch to a different team in VINE, and try adding a voucher using the short code
      --> you should get There was an error while adding the voucher
  • with a voucher added to the order, proceed to order summary
    --> you should see the voucher applied to the order in the right hand side
  • Complete the order
    --> you should see the voucher on the order confirmation page
    --> you should see the voucher in the confirmation email
  • Login in VINE, set your team to "OFN test - service",
  • Navigate to the voucher you used
    --> you should see "0$ Remaining value" and " 1 # Redemptions"
Same voucher used by multiple enterprise

Same as above, but this time use a $50 voucher from the first voucher set and place order under $50 so we can use the voucher with another enterprise.

  • Connect a different enterprise to VINE, you can use the same credentials for multiple enterprises.
  • Make sure you have an order cycle set up with the enterprise you just connected to VINE
  • Set your team in VINE to "OFN test - merchant 2"
  • Place an order with the same voucher you used above
    --> you should see the voucher on the order confirmation page
    --> you should see the voucher in the confirmation email
  • Login in VINE, set your team to "OFN test - service",
  • Navigate to the voucher you used
    --> you should see " 2 # Redemptions" and under the "Voucher Redemptions" section, you should see a redemption for each "OFN test - merchant" and OFN test - mechant 2"
Failed redemption :
  • same as before, start an order, proceed to checkout, add a voucher and proceed to "Order summary"
  • Login in VINE and switch your team "OFN test - service"
  • Complete your order
    --> you should get "Redeeming the voucher failed" error
Admin - capture a payment
  • same as before , start an order, proceed to checkout, add a voucher and proceed to "Order summary"
  • go to the backoffice Orders screen
  • Select the order you just created, it should be in the "confirmation" state
    --> you should see the voucher as an "Order Adjustments"
  • Click on "payments" on the right hand side menu
  • Capture and complete the order by clicking on the ✅ button
    --> The payment status should be "Complete" and order status on the right hand side should also be "Compete"
Failed redemption:
  • Same as before up to the payment screen
  • Capture and complete the order by clicking on the ✅ button
    --> you should get "Redeeming the voucher failed" error
Admin - create a payment
  • same as before , start an order, proceed to checkout, add a voucher and proceed to "Order summary"
  • go to the backoffice Orders screen
  • Select the order you just created, it should be in the "confirmation" state
  • Click on "payments" on the right hand side menu
  • Click on "+ New Payment" button
  • Enter details and click on "Update"
    --> you should get redirected to the payment page and the new payment should be listed, order status should be "complete"
Failed redemption:
  • Same as before up to the new payment screen
  • Enter details and click on "Update"
    --> should get redirected to the payment page and get "Redeeming the voucher failed" error
Report

Report will be available via Metabase and/or VINE.
Check the voucher are showing up correctly on the following reports:
- Order Cycle Customer Totals
- Enterprise Fees With Tax Report By Order
- Revenues By Hub
- Sales Tax Totals By Order

Release notes

Changelog Category (reviewers may add a label for the release notes):

  • User facing changes
  • API changes (V0, V1, DFC or Webhook)
  • Technical changes only
  • Feature toggled

The title of the pull request will be included in the release notes.

@rioug rioug force-pushed the 12859-use-VINE-voucher branch 2 times, most recently from 84c1dfd to 0a0ae42 Compare October 29, 2024 01:08
@rioug rioug changed the title [City OFN Voucher] Use vine voucher [City OFN Voucher] A shopper can use a VINE voucher Oct 29, 2024
@rioug rioug marked this pull request as ready for review October 29, 2024 05:20
Comment on lines 110 to 106
render cable_ready: cable_car.replace(
selector: "#checkout-payment-methods",
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I didn't replace this by turbo, as it will be done in this PR #12896

@dacook dacook self-requested a review October 30, 2024 01:15
Copy link
Member

@dacook dacook left a comment

Choose a reason for hiding this comment

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

Partial review, up to and including "Add VineVoucherValidatorService and spec"

spec/services/vine_api_service_spec.rb Outdated Show resolved Hide resolved
config/locales/en.yml Outdated Show resolved Hide resolved
app/services/vine_voucher_validator_service.rb Outdated Show resolved Hide resolved
app/services/vine_voucher_validator_service.rb Outdated Show resolved Hide resolved
app/models/voucher.rb Outdated Show resolved Hide resolved
spec/services/vine_voucher_validator_service_spec.rb Outdated Show resolved Hide resolved
spec/services/vine_voucher_validator_service_spec.rb Outdated Show resolved Hide resolved
spec/services/vine_voucher_validator_service_spec.rb Outdated Show resolved Hide resolved
spec/services/vine_voucher_validator_service_spec.rb Outdated Show resolved Hide resolved
spec/services/vine_voucher_validator_service_spec.rb Outdated Show resolved Hide resolved
Copy link
Member

@dacook dacook left a comment

Choose a reason for hiding this comment

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

Forgot to include a couple of thoughts on the data model:

Copy link
Member

@dacook dacook left a comment

Choose a reason for hiding this comment

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

Also reviewed "Handle adding a VINE voucher to an order".
I will pause until we can discuss next week.

app/controllers/voucher_adjustments_controller.rb Outdated Show resolved Hide resolved
app/controllers/voucher_adjustments_controller.rb Outdated Show resolved Hide resolved
@rioug rioug force-pushed the 12859-use-VINE-voucher branch from 572271e to 544dcfc Compare November 4, 2024 05:25
@dacook dacook self-requested a review November 6, 2024 03:29
Copy link
Member

@dacook dacook left a comment

Choose a reason for hiding this comment

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

Big effort! 💪

I have lots of comments sorry. I think because my brain is averse to complexity and tries to find simpler ways. I think you put it well when you said:

we are trying to shoehorn VINE voucher into a model that wasn't really design for that, on top of voucher already been shoehorned into adjustments

So I'm cautious about creating tech debt that we will have to pay for in the future.

spec/system/consumer/checkout/payment_spec.rb Outdated Show resolved Hide resolved
fill_in "Enter voucher code", with: "KM1891"
click_button("Apply")

expect(page).to have_content("There was an error while adding the voucher")
Copy link
Member

Choose a reason for hiding this comment

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

Are we able to say why there was an error? Does the invalid_voucher or not_found_voucher message appear here?

app/services/vine/voucher_validator_service.rb Outdated Show resolved Hide resolved
app/services/vine/api_service.rb Show resolved Hide resolved
app/services/vine_voucher_redeemer_service.rb Outdated Show resolved Hide resolved
Comment on lines +85 to +89
flash[:error] = if vine_voucher_redeemer.errors.keys.include?(:redeeming_failed)
vine_voucher_redeemer.errors[:redeeming_failed]
else
I18n.t('checkout.errors.voucher_redeeming_error')
end
Copy link
Member

Choose a reason for hiding this comment

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

Can't we rely on vine_voucher_redeemer to give us the error we need to know about? IE:

Suggested change
flash[:error] = if vine_voucher_redeemer.errors.keys.include?(:redeeming_failed)
vine_voucher_redeemer.errors[:redeeming_failed]
else
I18n.t('checkout.errors.voucher_redeeming_error')
end
flash[:error] = vine_voucher_redeemer.errors.first

Or if not, maybe we can use optional chaining like so:

Suggested change
flash[:error] = if vine_voucher_redeemer.errors.keys.include?(:redeeming_failed)
vine_voucher_redeemer.errors[:redeeming_failed]
else
I18n.t('checkout.errors.voucher_redeeming_error')
end
flash[:error] = vine_voucher_redeemer.errors&[:redeeming_failed] ||
I18n.t('checkout.errors.voucher_redeeming_error')

spec/requests/spree/admin/payments_spec.rb Show resolved Hide resolved
spec/requests/spree/admin/payments_spec.rb Outdated Show resolved Hide resolved
spec/requests/spree/admin/payments_spec.rb Show resolved Hide resolved
@rioug rioug force-pushed the 12859-use-VINE-voucher branch 3 times, most recently from 9907b82 to d1be702 Compare November 13, 2024 03:41
@rioug
Copy link
Collaborator Author

rioug commented Nov 13, 2024

I am yet to address all the review comments, but I had to do a bit more work to handle this requirement:

  • a voucher to be able to be redeemed by multiple merchants

I ended up creating Vouchers::Vine because in the end it is different enough from Vouchers::FlatRate to have its' own class, mainly because we now have different requirement on the uniqueness of a voucher code.

@dacook I started looking into handling API error with exception, and you are right it should be a bit cleaner than the current solution.

Moving back into code review because I think it's worth Maikel having a look even if it's not totally finished

@RachL RachL added pr-staged-au staging.openfoodnetwork.org.au and removed pr-staged-au staging.openfoodnetwork.org.au labels Nov 15, 2024
Copy link
Member

@dacook dacook left a comment

Choose a reason for hiding this comment

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

Great, thanks for trying that, I think it looks simpler now. What do you think?

@rioug rioug added pr-staged-au staging.openfoodnetwork.org.au feature toggled These pull requests' changes are invisible by default and are grouped in release notes and removed pr-staged-au staging.openfoodnetwork.org.au labels Nov 19, 2024
Copy link
Member

@mkllnk mkllnk left a comment

Choose a reason for hiding this comment

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

Great work, @rioug!

And sorry that it took me so long to review. There are some minor style issues we could address but I don't really want to add to this epic pull request. We can work on it in follow-up pull requests.

The only big questions for me now are:

  • Is the data model right?
  • Are we doing the correct validations?

Adding the external vine attributes is definitely not ideal. And I think that we could get around it by calling the validation API before redemption. That's maybe how it was intended. But those fields are also not in the way of anything. We could get rid of them quite easily in the future. So no need to act right now.

Those fields are also used in a find method. And just for my own clarification, this is how I read the code:

  • User enters code.
  • We can't find it locally and ask Vine.
  • We get the set id etc and store the voucher locally.
  • This info is used for redemption at checkout.
  • The same voucher could be used again.
  • Again, we don't find it locally and ask Vine.
  • We get the same ids back and find it locally to update.
  • Now the voucher value changed. If we ran reports about redemptions in OFN, we would only see the last remaining value of the voucher and not its initial value. Potential issue later?

Just thinking about alternatives:

  • We don't need to store the short code because we never use it for redemption, just to display to the user.
  • We could use "#{voucher_set_id}/#{voucher_id}" as local voucher id which would always be unique per enterprise. We wouldn't need to soften the validations.
  • Is the short code part of the long id? Can we derive it or do we need to store it separately?

Downside of the above would be that we need to change all the views to not display a really long voucher id.

  • Should we always create a new voucher instead of finding a previous use of the same code?

That could avoid race conditions if the same code is used by two people. But that's unlikely. We would be able to track the value at the time of each redemption though.

What do you think?

Comment on lines +81 to +85
voucher = Voucher.find_by(code: voucher_params[:voucher_code],
enterprise: @order.distributor)
return voucher unless voucher.nil? || voucher.is_a?(Vouchers::Vine)

vine_voucher
Copy link
Member

Choose a reason for hiding this comment

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

No need to change now but generally I find this pattern more flexible:

local_voucher || vine_voucher

Then you can implement the parts on their own and test them independently.

app/controllers/checkout_controller.rb Show resolved Hide resolved
app/services/vine/api_service.rb Show resolved Hide resolved
@mkllnk mkllnk force-pushed the 12859-use-VINE-voucher branch from 063ff57 to 5852708 Compare November 26, 2024 01:02
@RachL RachL added pr-staged-au staging.openfoodnetwork.org.au and removed pr-staged-au staging.openfoodnetwork.org.au labels Nov 28, 2024
@RachL RachL self-assigned this Nov 28, 2024
It is used to validate a voucher using the given short code
rioug added 10 commits November 28, 2024 13:35
A Vine voucher is really a specific type of FlatRate voucher but because
a Vine voucher can be used by mutiple enterprise, it can be considered
different enough to warrant it's own class.
It still share a lot of the behaviour of a FlatRate voucher, so to avoid
duplication, all the shared functionality have been moved to a
Vouchers::FlatRatable concern.
Plus optimise code with `find_or_initialize_by` as suggested in review
Paranoia doesn't support unique validation including deleted records:
  rubysherpas/paranoia#333
We use a custom validator, ScopedUniquenessValidator to avoid the issue
Log Client and Server error, and re raise exception for the caller
to handle
@RachL RachL force-pushed the 12859-use-VINE-voucher branch from 5852708 to f5b9ca3 Compare November 28, 2024 12:35
@RachL RachL added pr-staged-au staging.openfoodnetwork.org.au and removed pr-staged-au staging.openfoodnetwork.org.au labels Nov 28, 2024
@RachL
Copy link
Contributor

RachL commented Nov 28, 2024

@rioug thanks for the detailed testing notes, it's really helpfull!

Main testing scenario passed successfully 💪 A few screenshots I might reuse later:

image

image

image

however for the reports sections, only one report mentioned displayed vouchers

  • Order Cycle Customer Totals ✔️
  • Enterprise Fees With Tax Report By Order 🚫
  • Revenues By Hub 🚫
  • Sales Tax Totals By Order 🚫

Is this list still accurate? I'm surprised to see the revenues by hub here given it's a report that is only accessible to super admins.

I'm ok to merge this as is and focus on reports in another issue, what do you think @rioug ? there are failing check also to consider before merging.

I also noticed something I've missed in my preview testing:

image

the sentence above the link should not appear once the API key is settled. Also the link does not redirect to VINE. I've opened this issue about it: #13006

@RachL RachL added feedback-needed no-staging-FR A tag which does not trigger deployments, indicating a server is being used pr-staged-fr staging.coopcircuits.fr and removed pr-staged-au staging.openfoodnetwork.org.au no-staging-FR A tag which does not trigger deployments, indicating a server is being used labels Nov 28, 2024
@RachL
Copy link
Contributor

RachL commented Nov 28, 2024

@rioug I also have a question about the test scenario: why do we need to "Set your team in VINE to "OFN test - merchant 2" ?

I know staying login as OFN - test service will throw an error at checkout, but staying logout of VINE works as well (and that's correct as the shopper won't have a VINE account).
Do you remember why switching to the merchant account was important?

@filipefurtad0 filipefurtad0 added pr-staged-uk staging.openfoodnetwork.org.uk and removed pr-staged-uk staging.openfoodnetwork.org.uk labels Nov 29, 2024
@RachL RachL removed the pr-staged-fr staging.coopcircuits.fr label Nov 29, 2024
@rioug
Copy link
Collaborator Author

rioug commented Dec 2, 2024

  • Now the voucher value changed. If we ran reports about redemptions in OFN, we would only see the last remaining value of the voucher and not its initial value. Potential issue later?

That could be an issue indeed, that said I would expect VINE related report to be handled in VINE itself, or metabase. We need to update the value here as we need it in OFN to calculate the voucher adjustment amount ie :

https://github.com/openfoodfoundation/openfoodnetwork/pull/12949/files#diff-e239f12abad049acb9fbe978f1c7aff5303f2bd384d766a98c688678d64c3ae7R21-R23

If we keep the original value, we could potentially try to redeem more than what's available and the customer won't be able to place the order.

Just thinking about alternatives:

  • We don't need to store the short code because we never use it for redemption, just to display to the user.

I still think it's good to store it, it might be useful for debugging purposes I'd assume customer will only have access to the short code.

  • We could use "#{voucher_set_id}/#{voucher_id}" as local voucher id which would always be unique per enterprise. We wouldn't need to soften the validations.
  • Is the short code part of the long id? Can we derive it or do we need to store it separately?

I am not sure how the short code is generated, as far as I can tell it's not part of the long id. We could have a look at the VINE implementation, but I don't think it's a good idea to copy the functionality.

It's true we don't actually need the short code from a technical stand point, but we need it for customer feedback, ie we need to be able to display the code used to the customer on the checkout screen and order confirmation email.

  • Should we always create a new voucher instead of finding a previous use of the same code?

That could avoid race conditions if the same code is used by two people. But that's unlikely. We would be able to track the value at the time of each redemption though.

I guess we could but wouldn't we have the same issue you raised above if we were to run reports about redemption in OFN ? We also would not have a unique voucher_set_id/voucher_id per enterprise any more.

My understanding is for VINE to cover functionalities originally included in phase 2 of vouchers, so I am not expecting to see redemption report in OFN. But still it's good to keep this in mind.

@mkllnk hopefully this answers your questions. I don't think we need to action anything for now.

@rioug
Copy link
Collaborator Author

rioug commented Dec 2, 2024

@RachL for voucher in report see : #11763
That said my understanding is voucher related report will be available through VINE/Metabase.

@rioug
Copy link
Collaborator Author

rioug commented Dec 2, 2024

@rioug I also have a question about the test scenario: why do we need to "Set your team in VINE to "OFN test - merchant 2" ?

I know staying login as OFN - test service will throw an error at checkout, but staying logout of VINE works as well (and that's correct as the shopper won't have a VINE account). Do you remember why switching to the merchant account was important?

This to test a voucher can actually be redeemed by multiple enterprise. The test note don't exactly reflect a real life scenario, in reality each enterprise would be using their own set of credentials and would be linked to their own team in VINE. To make testing easier and not having to set up another set of credentials, you can just switch your team to a different Merchant to simulate that.

@RachL
Copy link
Contributor

RachL commented Dec 2, 2024

@rioug yes that was my understanding as well for reports, I was confused by the reports section of the testing section of the PR. I think we can remove it?

In that case and if Maikel's comments are all addressed, it looks like we can merge? I won't be at delivery circle tomorrow (that's the time slot I can't make) but feel free to merge if we are all aligned. Kudos :)

@mkllnk mkllnk merged commit de938f6 into openfoodfoundation:master Dec 3, 2024
60 of 61 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature toggled These pull requests' changes are invisible by default and are grouped in release notes
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

[Citi OFN Vouchers] As a shopper I can use a voucher created with VINE
5 participants