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

Remember post-print notification checkbox state #2300

Open
wants to merge 7 commits into
base: trunk
Choose a base branch
from

Conversation

waclawjacek
Copy link
Contributor

Description

Currently, the Mark this order as complete and notify the customer and Notify the customer with shipment details checkboxes in the Create shipping label modal are always set to a default state (unchecked). This is problematic for users who have workflows that do not match this behavior.

This PR introduces a new option post_print_notification_settings in WC_Connect_Options which stores the state of both checkboxes.

The settings can be manipulated via a REST controller which automatically happens when a label is printed (automatically or after Print is clicked) in the Create shipping label modal.

Important changes

Relying on functions rather than state when sending

Previously, the state values fulfillOrder and emailDetails were set to a result calculated from checkbox state and order status:

const onFulfillAndEmailOrderChange = ( value ) => {
	// Don't change order status if already finished.
	props.setFulfillOrderOption( orderId, siteId, value && ! isOrderFinished( order.status ) );
	// Email only if order is already complete.
	props.setEmailDetailsOption( orderId, siteId, value && isOrderFinished( order.status ) );
};

This PR repurposes these values to only contain the user preference of whether to send the notification if applicable.

Instead of relying on the state directly, the shouldFulfillOrder() and shouldEmailDetails() functions should be used instead.

Naming

The name is pretty long. :) I was also considering "Post-Print Actions" or just "Notification Settings" but for now settled for the most verbose "Post-Print Notification Settings".

Default state removal

I have removed the default state for the emailDetails and fulfillOrder fields from /client/extensions/woocommerce/woocommerce-services/lib/initialize-labels-state/index.js. I believe it was not used anywhere. If someone more familiar with the inner workings of the plugin could please let me know if this might be problematic, that would be great!

Related issue(s)

Fixes #2005

Steps to reproduce & screenshots/GIFs

Markup on 2021-01-13 at 18:50:41

Markup on 2021-01-13 at 18:24:23

The screenshot shows an order that is not completed yet. The Notify the customer with shipment details checkbox is presented in the same modal for completed orders.

Checklist

  • unit tests
  • changelog.txt entry added

To store the post-print notification settings, a new WC_Connect_Options
option "post_print_notification_settings" is introduced with a setter
and getter in WC_Connect_Service_Settings_Store.
Add a REST controller to allow manipulating the post-print notification
settings via the REST API.
Output the post-print notification settings currently stored
in the database so the front-end scripts can pick them up.
Previously the state values `emailDetails` and `fulfillOrder` were
set based on whether a checkbox is checked and if `isOrderFinished()`
returns true.

These values are now set based on the user preference stored in the
back-end at page load and are only changed when the checkbox is
checked or unchecked. `isOrderFinished()` is no longer checked here.

To check if a specific email should actually be sent, use
`shouldEmailDetails()` and `shouldFulfillOrder()` that do include
this check rather than relying on the state values directly.
The test failed when ran in a timezone UTC+N where N > 0.

Added code checking what the expected result in the current timezone
should be.
Instead of "value", "enabled" is used to indicate whether a notification
is enabled by the back-end.
@waclawjacek
Copy link
Contributor Author

There is currently a delay between when the checkbox state is loaded as opposed to paperSize which is implemented in a similar way. This might have to be improved.

@harriswong
Copy link
Contributor

👀


/*
* WC_Connect_Options::update_option() returns `false` if the new value is the same as the old one.
* As this is not an issue in this case, we return `true` here and leave the option unchanged.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice comment!

@@ -0,0 +1,34 @@
<?php
Copy link
Contributor

Choose a reason for hiding this comment

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

I see we use classes/class-wc-rest-connect-shipping-label-preview-controller.php (connect/label/preview) when we save the paper_size preference. I am a little surprised that I can't find an existing end point to update settings. So this new end point makes sense.

Were you also not able to find any existing end point to update settings?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes!

I was considering adding the notification-settings-saving logic to an existing endpoint but:

  1. Saving when shipping rates are requested or purchased is too early because the checkbox might be toggled afterward.
  2. Saving when the label PDF is requested (this happens automatically after a request to purchase a label is made) was another option I considered but:
    1. the notifications are not yet sent at this point so again, this is too early;
    2. this is a GET request. The paper size setting is saved upon this request, but this makes more sense than saving notification settings here - the paper size has to be provided anyway so a label can be printed in the selected size.
  3. Saving when the label PDF is displayed (either after "Print" is clicked or the PDF is opened automatically) sometimes triggers another request. This will be either a request to mark an order as completed, to send the email with details, but can also be no request at all. In such cases, a separate call would have to be made anyway.

Based on the above, I decided that placing the logic in a separate REST endpoint accessed after the "Print" button is clicked would be the cleanest solution.

Copy link
Contributor

@harriswong harriswong Jan 18, 2021

Choose a reason for hiding this comment

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

The choice of the new end point makes a lot of sense now. Thank you!

* @return true|WP_Error WP_Error if an error occurred, `true` otherwise.
*/
public function set_post_print_notification_setting( $name, $enabled ) {
$allowed_names = array(
Copy link
Contributor

@harriswong harriswong Jan 15, 2021

Choose a reason for hiding this comment

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

We can't trust the user input and I like how you add the check here instead of the controller's level. 💯

return $error;
}

return new WP_REST_Response( array( 'success' => true ), 200 );
Copy link
Contributor

@harriswong harriswong Jan 15, 2021

Choose a reason for hiding this comment

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

Nice! There are a few different ways in our existing code to return a response/error. I am glad you picked WP_REST_Response :D 👍 💯

@@ -94,7 +95,9 @@ describe( 'ShippingRate', () => {
} );

it( 'renders the delivery date', () => {
expect( shippingRateWrapper ).to.contain( <div className="rates-step__shipping-rate-delivery-date">January 1</div> ); // eslint-disable-line
const expectedDate = moment( shippingRateWrapper.props().rateObject.delivery_date ).format( 'LL' ).split( ',' )[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this the timezone issue? :D

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes! The issue was that the time provided in createShippingRateWrapper() (which is 2020-01-01T23:59:00.000Z) can, in some timezones, not match the test's expectation of January 1. :)

} else {
// Don't change order status if already finished.
props.setFulfillOrderOption( orderId, siteId, value );
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of updating both all the time, now it updates either or based on order.status. I think this is fine since we have defaults and we don't need to update both every time.

Copy link
Contributor

@harriswong harriswong left a comment

Choose a reason for hiding this comment

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

Tested locally. I checked "Mark this order as complete and notify the customer" and print a label. It refreshed with the "Notify the customer with shipment details" unchecked.

I opened up another order and "Mark this order as complete and notify the customer" is checked by default.

Thanks for adding all the tests! LGTM! 👍

@c-shultz
Copy link
Contributor

Nice work pushing this forward and digging so deep into a new codebase, @waclawjacek 🥳

@c-shultz
Copy link
Contributor

Let's go ahead and hold off on this until we can give WCShip more focus, and do so more thorough testing.

@waclawjacek
Copy link
Contributor Author

The implementation here should be complete. I didn't merge this yet because I wasn't sure if the Redux state + respective React components are managed in a reliable and backward-compatible way, taking into account all the possible contexts the app can be initialized and run in.

If someone with more knowledge than me in this field could give it a look, that would be fantastic!

If #2367 is implemented, the approach taken here might need to change. The assumption in this PR was that things happen after printing. If they happen after purchase instead, maybe an additional REST endpoint will not be necessary, etc.

@brezocordero brezocordero changed the base branch from develop to trunk April 21, 2021 17:00
@harriswong
Copy link
Contributor

@waclawjacek Bump! I stumbled upon this when I am looking at cleaning up the Calypso stuff. I think we can take a look at this again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Option to deselect the mark this order complete checkbox by default
3 participants