openfoodnetwork icon indicating copy to clipboard operation
openfoodnetwork copied to clipboard

Let people customise which shipping methods are available to customers on order cycles

Open cillian opened this issue 2 years ago • 16 comments

What? Why?

Closes #8974

This adds a new step 4. Checkout options to editing order cycles. This only applies to order cycles for distributors e.g. sells = 'any'. For 'simple', direct sales, order cycles where :sells = 'own' all shipping methods are to be available by default like they are currently.

checkout-options

This is a bit different from the spec because updating step 3. Outgoing would have be done in Angular and that would have taken a lot longer. I believe the plan is to convert the edit order cycle form to StimulusJs as soon as possible anyway so it was quicker and easier to do this in plain Rails.

Note, the screenshot includes a 'back office only' shipping method which is disabled and cannot be selected. It also includes a shared shipping method which is shared by two enterprises.

The 'Ready for' and 'Customer instructions' fields haven't been moved yet. It might be best to do those in separate PRs are this one is already big enough.

~This adds a :shipping_methods_customisable flag to the order cycles table in order to have a record of which order cycles which were created before this feature i.e. order cycles on which it was not possible to customise shipping methods. This excludes active or upcoming order cycles at the time of the migration because shipping methods on these should be customisable so the :shipping_methods_customisable flag will be set to true for these.~

What should we test?

See Acceptance criteria & tests in https://github.com/openfoodfoundation/openfoodnetwork/issues/8974

It would be good to test the migration on a staging instance too.

Release notes

Changelog Category: User facing changes

Documentation updates

The Order Cycles (for hubs) page in the user guide will probably need to be updated.

cillian avatar Jun 05 '22 15:06 cillian

So exciting to see this awesome work @cillian :tada:

lin-d-hop avatar Jun 14 '22 07:06 lin-d-hop

:wave: @mkllnk I have changed things so all shipping methods are available if none are specifically selected in the database, it's a lot simpler now. I broke it up into smaller commits too, but it might be good to squash some of them again later.

cillian avatar Jun 17 '22 13:06 cillian

@mkllnk :+1: definitely nice to see the size of this PR has been chopped down a good bit since the first draft.

cillian avatar Jun 29 '22 14:06 cillian

@mkllnk great, thank you :tada:

cillian avatar Jul 08 '22 13:07 cillian

Hi @cillian, I have started to test this amazing pull request. I know that many user are waiting for this functionality. 💪

This is a big and complex one. So I decided to take separate testing notes in a document here: https://docs.google.com/document/d/1UhiVRpqWcOZ0HvwDdTBVoGxSS0iiwSL1czd_lBkJE_M/edit?usp=sharing

So far everything seems good. I only was confused by the way the shared payment methods are displayed (see no. 4 in the document). I am asking our @openfoodfoundation/train-drivers-product-owners team to comment on this one.

I have to stop for now, there is still a lot more to test. This is just to let you know your contribution is very much appreciated and we are working on testing it! 👍

drummer83 avatar Jul 11 '22 21:07 drummer83

Thanks for all the dev, review and testing on this.

I'm afraid that when the spec changed half way through this introduced some differences in understanding between the spec and what was developed. This is totally my fault.

I'm going to go through the PR now to better understand where we are at and what's possible and then have a chat with @cillian to work out the best route forward. For now, let's pause.

Sorry to delay this everyone.

lin-d-hop avatar Jul 12 '22 09:07 lin-d-hop

Added 'feedback-needed' until @lin-d-hop comes back to us with her thoughts.

drummer83 avatar Jul 12 '22 14:07 drummer83

Okay I have updated this to the simpler layout now. Order cycles with multiple distributors will look something like this....

checkout-options-multiple-distributors

And order cycles with a single distributor...

checkout-options-single-distributor

cillian avatar Jul 15 '22 15:07 cillian

@cillian I did a bit of work on this but I'm running out of time to finish it. Here are the outstanding issues I found:

  • The new organisation of the spec file means that our usual code style metrics apply. We can do a better job at splitting it all up.
  • I found a bug with disabled fields. When you click on a disabled field then it's treated like a click on the field above, toggling the checkbox. We should add to the JS spec and solve that.

mkllnk avatar Jul 19 '22 05:07 mkllnk

@filipefurtad0 I did a bit of spec work on this. Maybe you like to have a quick review.

mkllnk avatar Jul 19 '22 07:07 mkllnk

@mkllnk thanks for fixing those bits up. I have added that extra JS spec and reworked the spec to remove the Metrics/AbcSize Rubocop errors now.

cillian avatar Jul 29 '22 10:07 cillian

Hey @cillian @mkllnk ,

I've split this into the migration and the behavior in the app, so first:

Testing the migration

image

Some observations: The new table establishes a correspondence between the order_cycle_id and the shipping_method_id :+1: On this screen, you cannot not select at least one shipping method :+1: Selecting all shipping methods -> empty table :+1:

Testing the behavior

For an order cycle with

  • more than one distributor (below, left)
  • and selecting some shipping methods, other than those provided by the respective distributors (below, middle)
  • leads to a scenario similar to #8219 and #6137 :exclamation: (below, right)

image

I think this might derive from:

The 'Ready for' and 'Customer instructions' fields haven't been moved yet. It might be best to do those in separate PRs are this one is already big enough.

I'm not sure we're ready to push this into prod. What do you think @openfoodfoundation/train-drivers-product-owners ?

filipefurtad0 avatar Aug 04 '22 15:08 filipefurtad0

I think that this needs fixing.

mkllnk avatar Aug 05 '22 00:08 mkllnk

Great catch @filipefurtad0!

This does need fixing but the logic of the best fix for this needs a little more thinking time. Curly.... :woozy_face:

lin-d-hop avatar Aug 05 '22 09:08 lin-d-hop

Okay, here is another round of design for this. Again I'm so sorry for not spotting all of this when the implementation changed from settings within the distribution to settings on the Order Cycle. I think this will be the last round to get the feature through testing....

So this is specifically for the case of multiple distributors on one order cycle:

Acceptance Criteria:

  • So we need to split this per Distributor after all :/
  • When there is only one shipping method for a distributor the option should be greyed out.
  • When there are multiple options but none is select the user should be prevented from saving - save buttons greyed out
  • Ideally we will communicate the error to the user if they can't save, however error messaging in the order cycles is not very easy to understand. Since having multiple distributors is an edge case anyway I would say that just preventing saving is sufficient and we can come back to this error messaging when we remove Angular from OCs as we'll be re-implementing this UI then anyway. If anyone has a better suggestion please do share!

ocshipping

@cillian Thanks for your patience in getting this tricky feature through! Let me know if there is anything else I can help with :)

lin-d-hop avatar Aug 05 '22 17:08 lin-d-hop

@lin-d-hop no problem, I'll make those adjustments. What should we do if a shipping method is shared between multiple distributors? Should we have a shared section like we had before? i.e.

shared-shipping-method

Or should the shared shipping method be displayed in the row for each distributor it belongs to, so it would be repeated? And if the checkbox is checked for one distributor, the checkbox for the other distributor(s) it belongs is automatically checked/unchecked to match? Maybe that's not the cleanest solution.

cillian avatar Aug 12 '22 10:08 cillian

Hi @cillian If the pick up method is shared by multiple distributors it should be repeated. So it should be possible for the same distribution method to be available for one distributor and not for another. Does that make sense? Does it fit with the data model you've created for this?

lin-d-hop avatar Aug 30 '22 08:08 lin-d-hop

@lin-d-hop that makes sense, I have updated things now. I had to change the data model a bit. Instead of a table which links OrderCycles to Spree::ShippingMethods, there is now a table which links OrderCycles to DistributorPaymentMethods but it was almost a straight swap.

order-cycle-checkout-options

When there are multiple options but none is select the user should be prevented from saving - save buttons greyed out

I left this part a bit differently because previously when no shipping methods were selected it would default to automatically selecting all shipping methods as suggested by Maikel. It's neat because then any currently active order cycles at the time this PR gets deployed will automatically have all shipping methods selected on the order cycle rather than having none selected and appearing as invalid if someone presses save. Let me know if that doesn't work though.

cillian avatar Sep 09 '22 16:09 cillian

Hi @cillian, Thanks for your continued work on this!

I started testing again and realized that I can't checkout with this PR staged (error 500). This seems independent from Split Checkout being activated and independent from the customer I chose.

There is an entry in Bugsnag which is probably related and I pasted the output of the browser console below. I hope this helps.

If you would like to have a look on our staging server and need support just let me know!

I will move this to In Dev. Thanks!

https://app.bugsnag.com/yaycode/openfoodnetwork-aus/errors/6328b543f90905000a180ad4?event_id=6328b54300973c8e16a30000&i=sk&m=nw

{
	"Status": "500Internal Server Error",
	"Version": "HTTP/2",
	"Transferred": "1.82 KB (1.26 KB size)",
	"Referrer Policy": "strict-origin-when-cross-origin",
	"Request Priority": "Highest"
}
{
	"Response Headers (577 B)": {
		"headers": [
			{
				"name": "cache-control",
				"value": "no-store"
			},
			{
				"name": "content-type",
				"value": "text/html; charset=utf-8"
			},
			{
				"name": "date",
				"value": "Mon, 19 Sep 2022 18:35:13 GMT"
			},
			{
				"name": "expires",
				"value": "Fri, 01 Jan 1990 00:00:00 GMT"
			},
			{
				"name": "pragma",
				"value": "no-cache"
			},
			{
				"name": "referrer-policy",
				"value": "strict-origin-when-cross-origin"
			},
			{
				"name": "server",
				"value": "nginx"
			},
			{
				"name": "strict-transport-security",
				"value": "max-age=63072000; includeSubDomains"
			},
			{
				"name": "x-content-type-options",
				"value": "nosniff"
			},
			{
				"name": "x-content-type-options",
				"value": "nosniff"
			},
			{
				"name": "x-download-options",
				"value": "noopen"
			},
			{
				"name": "X-Firefox-Spdy",
				"value": "h2"
			},
			{
				"name": "x-permitted-cross-domain-policies",
				"value": "none"
			},
			{
				"name": "x-request-id",
				"value": "6a64df22-42bd-4ff9-b9dd-06d37bfeeede"
			},
			{
				"name": "x-runtime",
				"value": "0.504622"
			},
			{
				"name": "x-xss-protection",
				"value": "1; mode=block"
			},
			{
				"name": "x-xss-protection",
				"value": "1; mode=block"
			}
		]
	}
}
{
	"Request Headers (983 B)": {
		"headers": [
			{
				"name": "Accept",
				"value": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
			},
			{
				"name": "Accept-Encoding",
				"value": "gzip, deflate, br"
			},
			{
				"name": "Accept-Language",
				"value": "en-US,en;q=0.5"
			},
			{
				"name": "Connection",
				"value": "keep-alive"
			},
			{
				"name": "Cookie",
				"value": "XSRF-TOKEN=_aJe7icU0rYXauKJo8gp9Y19fCuIPaxKgGggx4is8bYa2SGqRH0ln-nvEKFHKDWyx3zjhsVrRj8KRtNwW4MieA; _ofn_session_id=d82ab77af610170705370f38b64184fe; _pk_id.3.cd81=bbe1c4baa95487b2.1663612282.; _pk_ses.3.cd81=1; __stripe_mid=dea8a258-01eb-4a7c-b9c4-3136ba949d5965ed6a; __stripe_sid=90e40833-72ce-4763-9f8c-24a184541462f09dd8; cookies_consent=cookies_consent; _pk_id.3.32b3=6e76bf6af4f58b73.1663612438.; _pk_ses.3.32b3=1"
			},
			{
				"name": "Host",
				"value": "staging.openfoodnetwork.org.au"
			},
			{
				"name": "Referer",
				"value": "https://staging.openfoodnetwork.org.au/konrad-testhub-staging-au/shop"
			},
			{
				"name": "Sec-Fetch-Dest",
				"value": "document"
			},
			{
				"name": "Sec-Fetch-Mode",
				"value": "navigate"
			},
			{
				"name": "Sec-Fetch-Site",
				"value": "same-origin"
			},
			{
				"name": "Sec-Fetch-User",
				"value": "?1"
			},
			{
				"name": "TE",
				"value": "trailers"
			},
			{
				"name": "Upgrade-Insecure-Requests",
				"value": "1"
			},
			{
				"name": "User-Agent",
				"value": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0"
			}
		]
	}
}

drummer83 avatar Sep 19 '22 18:09 drummer83

Thanks for testing this @drummer83 .

@cillian Unfortunately, we've recently noticed that some specs in our build were not running - this is now fixed.

So, in addition to bugsnag, maybe rebasing this PR onto current master will reveal some failing tests and help you move forward.

filipefurtad0 avatar Sep 20 '22 16:09 filipefurtad0

We prefer a rebase over a merge because it results in a cleaner history and makes sure that we have to resolve merge conflicts only once.

mkllnk avatar Sep 21 '22 04:09 mkllnk

Thanks all. No problem about the rebase, that's done now, I was planning doing a rebase and squashing a lot of this down once we are ready to go.

There were some failures after rebasing but they have been fixed now. I don't have access to that bugsnag to see the backtrace, the tests that were failing were in the admin area rather than at checkout so not sure if that will be fixed or not.

The last failing spec ./spec/system/admin/order_cycles/complex_creating_specific_time_spec.rb:65 is flaky, it seems like a timing issue when checking the Your order cycle has been created flash notice, not sure what to do there yet :thinking:

cillian avatar Sep 21 '22 21:09 cillian

Hey @cillian ,

I'm getting an error 500 when accessing https://staging.openfoodnetwork.org.uk/admin/order_cycles/3597/checkout_options

This order cycle has some entries on the newly created table order_cycles_shipping_methods; So I've tried on another order cycle (with no entries), but get the same result.

Screenshot from 2022-09-30 12-27-55

The error is:

gems/activerecord-6.1.7/lib/active_record/connection_adapters/postgresql_adapter.rb:672:in `exec_params': PG::UndefinedTable: ERROR:  relation "order_cycles_distributor_shipping_methods" does not exist
LINE 1: ...e FROM "distributors_shipping_methods" INNER JOIN "order_cyc...

Can you access /admin/order_cycles/<order_cycle_id>/checkout_options in your local system? I wonder why did all specs pass here...

filipefurtad0 avatar Sep 30 '22 11:09 filipefurtad0

Hi @filipefurtad0

It looks like staging has the old order_cycles_shipping_methods table from a previous round of testing. The table had to be changed to order_cycles_distributor_shipping_methods in order to handle shipping methods which were shared between multiple distributors. I wonder if migrating will fix this, although we would probably still have to delete the old table from staging, what does a rails db:migrate:status show?

cillian avatar Sep 30 '22 11:09 cillian

Thanks @cillian , I've tried another server and got the same result. The output from rails db:migrate:status:

   up     20220105085729  Split customers name
   up     20220105085730  Migrate customers data
   up     20220112102539  Add mails sent to order cycles
   up     20220114110920  Update order cycle mails
   up     20220118053107  Convert stripe connect to stripe sca
   up     20220221165207  Migrate checkout only to both back office and checkout
   up     20220316055458  Create active storage tablesactive storage
   up     20220407051248  Remove icon from spree taxons
   up     20220410162955  Change visible data type for enterprises
   up     20220425102039  Remove bill addresses with null phone
   up     20220425230907  Add disabled at to spree users
   up     20220429092052  Create order cycles distributor shipping methods
   up     20220602013938  Compute checksum for big files
   up     20220603140943  Add whatsapp phone to enterprises
   up     20220629080906  Add note to orders
   up     20220713195433  Add show api key generation view to spree user
   up     20220907055044  Delete duplicate customers

So, it looks like somehow the migration did not run. Should I delete this entry up 20220429092052 Create order cycles distributor shipping methods and re-stage? I mean, in the psql shell running something like:

delete from schema_migrations where version = '20220429092052'

filipefurtad0 avatar Sep 30 '22 12:09 filipefurtad0

So, it looks like somehow the migration did not run. Should I delete this entry up 20220429092052 Create order cycles distributor shipping methods and re-stage?

@filipefurtad0 yes I think that should work. Although the old order_cycle_shipping_methods table might need to be deleted manually, there is no migration to remove it because the migration changed.

The other option would be to checkout the commit which contained the old migration and roll the migration back, then checkout the latest commit and re-run the migration again. That would remove the old table so you wouldn't need to delete it manually.

cillian avatar Sep 30 '22 12:09 cillian

Yaayy worked :tada:

image

Resuming testing, Thanks for your help :raised_hands:

filipefurtad0 avatar Sep 30 '22 12:09 filipefurtad0

Ok! Everything looks good now:

Migration


openfoodnetwork=> select * from order_cycles_distributor_shipping_methods;
 order_cycle_id | distributor_shipping_method_id 
----------------+--------------------------------
           3805 |                            853
(1 row)

Which corresponds to:

image

Behavior and acceptance criteria

  • After the latest changes it is not possible to de-select all shipping methods, the guard for this works fine :heavy_check_mark:

Screencast from 30-09-2022 14:30:26.webm

  • Tested in both legacy and split-checkout: the selected shipping methods appear on the corresponding sections :heavy_check_mark:
  • The design is resilient in edge cases like de-selecting shipping methods (as admin) during the customer checkout process; Once the customer sees the option to select a shipping method it then "sticks" to the order, checkout proceeds with no issues

I think these were the pending issues!

Thanks so much all the work and patience on this one @cillian Merging.

filipefurtad0 avatar Sep 30 '22 13:09 filipefurtad0