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

feat(subscriptions): add cancellation reason metadata #3568

Merged
merged 17 commits into from
Dec 6, 2024

Conversation

chickenn00dle
Copy link
Contributor

@chickenn00dle chickenn00dle commented Nov 22, 2024

All Submissions:

Changes proposed in this Pull Request:

Closes https://app.asana.com/0/1208702687864922/1208702687865961

This PR adds meta data to cancelled woo subscriptions and uses this new meta to sync cancellation reason to ESPs for cancelled subscriptions.

How to test the changes in this Pull Request:

Before testing be sure to set the feature flag in wp-config: define( 'NEWSPACK_SUBSCRIPTIONS_EXPIRATION', true );. Also ensure Newspack logging is active on the site: define( 'WP_NEWSPACK_DEBUG', true )

  1. As admin ensure an ESP is connected and sync is working
  2. Go to Newspack > Engagement > Show Advanced Settings > Sync contacts to ESP and ensure Subscription Cancellation Reason is checked:
    Screenshot 2024-11-22 at 16 21 40
  3. As a reader purchase a new subscription. This should be the only active subscription for the reader since our ESP sync will only sync cancelled subscription data if there are no other active subscriptions
  4. As admin, go to the edit subscription page for the above subscription and cancel (WooCommerce > Subscriptions)
  5. After page reload scroll down to the custom fields section of the edit subscription page and verify a new cancellation reason field exists with a value of manually-cancelled:
    Screenshot 2024-11-22 at 14 36 22
  6. As a reader again, purchase another subscription
  7. Still as reader go to my account and cancel the subscription (My Account > Subscriptions > View then click the cancel button)
  8. Via wp cli, update the pending cancellation subscription end date to one minute from now:
$subscription = wcs_get_subscription( SUBSCRIPTION_ID );
$subscription->update_dates( array( 'end_date' => "2024-11-22 19:35:01" ) );
  1. Wait for the end date time to lapse, then visit the site as the reader to ensure the transition from pending cancel to cancel happens
  2. As admin, visit the edit subscriptions page for the subscription and verify the cancellation reason meta field exists with a value of user-cancelled
    Screenshot 2024-11-22 at 14 35 35
  3. Check the logs and ensure the Subscription Cancellation Reason field with the expected value is present in the normalized ESP sync data:

Screenshot 2024-12-02 at 19 00 37

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes, as applicable?
  • Have you successfully ran tests with your changes locally?

@chickenn00dle chickenn00dle force-pushed the feat/add-cancellation-reason-metadata branch from a4963d1 to 79f9590 Compare November 22, 2024 20:47
@chickenn00dle chickenn00dle marked this pull request as ready for review November 22, 2024 21:22
@chickenn00dle chickenn00dle requested a review from a team as a code owner November 22, 2024 21:22
@chickenn00dle chickenn00dle added the [Status] Needs Review The issue or pull request needs to be reviewed label Nov 22, 2024
@chickenn00dle chickenn00dle force-pushed the feat/add-cancellation-reason-metadata branch from c09ba1b to 6deebfd Compare November 25, 2024 19:09
return;
}
if ( 'cancelled' === $to_status && ! in_array( $from_status, [ 'cancelled', 'expired' ], true ) ) {
$meta_value = is_admin() ? self::CANCELLATION_REASON_ADMIN_CANCELLED : self::CANCELLATION_REASON_USER_CANCELLED;
Copy link
Contributor

Choose a reason for hiding this comment

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

We want a third expired option here

Copy link
Contributor

Choose a reason for hiding this comment

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

As we discussed, let's leave this for another PR, but I left another comment because it didn't work for me

@@ -285,6 +285,12 @@ private static function get_order_metadata( $order, $payment_page_url = false )
$metadata['product_name'] = reset( $subscription_order_items )->get_name();
}
}

// Record the cancellation reason if the subscription was cancelled.
$cancellation_reason = $current_subscription->get_meta( WooCommerce_Subscriptions::CANCELLATION_REASON_META_KEY, '' );
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm getting an error that I believe is coming from this line

Class "Newspack\Reader_Activation\Sync\WooCommerce_Subscriptions" not found

The meta was not added neither to the subscription nor to the ESP

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah. Good catch! Fixed in 2a51cf4

The meta was not added neither to the subscription nor to the ESP

Strange that the meta was not being added to the subscription though. I just updated the testing instructions, but make sure you've defined the ff constant to see the changes at work.

Also, I've run into this problem in the past so thought I'd mention it here as well, but if you have a contact with too many meta fields in MC, the newer fields will simply not be added. You can still check the logs for what will be synced with Newspack logging enabled in these cases:

Screenshot 2024-11-26 at 16 52 16

Copy link
Contributor

Choose a reason for hiding this comment

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

make sure you've defined the ff constant to see the changes at work.

I'd never make such a mistake........ 😬

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, I've run into this problem in the past so thought I'd mention it here as well, but if you have a contact with too many meta fields in MC, the newer fields will simply not be added.

Yes. This is a known issue. It's a limitation we have to deal with Mailchimp, that's why we can choose which fields we want. If you scroll the logs up a little you will see that there was an attempt to create the merge field and it failed because it reached the limit.

Copy link
Contributor

@leogermani leogermani left a comment

Choose a reason for hiding this comment

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

@chickenn00dle I'm not getting an infinite loop when I cancel the subscription.

I added some logging and I can see the maybe_record_cancelled_subscription_meta method being called over and over again...

the woo_meta was added successfully though

class Subscriptions_Meta {
const CANCELLATION_REASON_META_KEY = 'newspack_subscriptions_cancellation_reason';
const CANCELLATION_REASON_USER_CANCELLED = 'user-cancelled';
const CANCELLATION_REASON_ADMIN_CANCELLED = 'manually-cancelled';
Copy link
Contributor

Choose a reason for hiding this comment

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

Every time I see this value I have to ask myself if manually means by the admin or by the user. Why not call this admin-cancelled?

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 used the names @kmwilkerson decided on here. But am happy to change this if there is a strong preference otherwise.

I will say that from the perspective of a non-technical publisher, I think manual probably makes more sense than admin.

@chickenn00dle
Copy link
Contributor Author

I added some logging and I can see the maybe_record_cancelled_subscription_meta method being called over and over again...

That's odd. I can't reproduce this on my end when I cancel as admin or as the user. This hook should only trigger when a subscription status is actually updated and once a subscription is cancelled it should no longer be possible to update the status again?

That said, I went ahead and added a preliminary check for cancellation reason meta before updating in the method in 7c582fb. Maybe this can help resolve things on your end? If not, would you mind sharing your steps to reproduce.

@leogermani
Copy link
Contributor

Wait for the end date time to lapse, then visit the site as the reader to ensure the transition from pending cancel to cancel happens

This will be triggered by any request. If I close the reader window and navigate as an admin, it will trigger the cancellation and store manually-cancelled as the meta. We need a better strategy to make sure we capture the original intent at the moment the reader clicks the cancel button

@chickenn00dle
Copy link
Contributor Author

This will be triggered by any request. If I close the reader window and navigate as an admin, it will trigger the cancellation and store manually-cancelled as the meta. We need a better strategy to make sure we capture the original intent at the moment the reader clicks the cancel button

Hmm, the scheduled cancellation uses action scheduler which uses WP_Cron. I thought that is_admin only returned true if the request comes from an admin screen? If so, wouldn't is_admin resolve to false for scheduled actions? (I could be misunderstanding this though)

I tested this and when I am on an admin screen at the time a subscription is cancelled by a user reaches its end date, the meta still shows user-cancelled:
Screenshot 2024-11-27 at 17 01 06

Are you seeing otherwise?

@leogermani
Copy link
Contributor

Are you seeing otherwise?

Yes. As I user, I cancelled the subscription and then closed the window... did everything else having only the admin tab active

@chickenn00dle chickenn00dle force-pushed the feat/add-cancellation-reason-metadata branch 2 times, most recently from b13e91f to c531e69 Compare December 2, 2024 23:28
@chickenn00dle chickenn00dle force-pushed the feat/add-cancellation-reason-metadata branch from c531e69 to 558d515 Compare December 2, 2024 23:45
*/
public function test_is_enabled() {
$is_enabled = WooCommerce_Subscriptions::is_enabled();
$this->assertTrue( $is_enabled, 'WooCommerce Subscriptions integration should be enabled when Feature Flag is present.' );
Copy link
Contributor Author

@chickenn00dle chickenn00dle Dec 2, 2024

Choose a reason for hiding this comment

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

I wanted to test the case where FF is not defined, as well as when Reader Activation is not enabled, but could not find a way to modify globally defined constants between test runs. I tried @preserveGlobalState paired with @runInSeparateProcess, but this ended up removing other globals the tested method relied on.

Would love any advice on how to approach this if possible

Copy link
Contributor

Choose a reason for hiding this comment

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

there's no good way to test constants... The best we could do would be to change the approach we use for Feature Flags and use something else to handle these things

@chickenn00dle
Copy link
Contributor Author

This is now ready for another round of review @leogermani.

I updated the strategy for determining admin vs. reader cancellations by adding an additional set of meta values for the pending-cancel state (manually-pending-cancel and user-pending-cancel, both ignored by ESP sync logic). These are checked when the subscription reaches the cancelled state to determine which cancelled meta value to use.

This means that if a reader "cancels" to pending-cancel and then the admin fully cancels prior to the end date, the meta value will still show user-cancelled. I think this is alright though since the users decision to cancel is what I think we want to capture here.

Copy link
Contributor

@leogermani leogermani left a comment

Choose a reason for hiding this comment

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

I've pushed a commit to avoid that infinite loop again. Everything looks good now :)

@github-actions github-actions bot added [Status] Approved The pull request has been reviewed and is ready to merge and removed [Status] Needs Review The issue or pull request needs to be reviewed labels Dec 6, 2024
@chickenn00dle chickenn00dle merged commit de83e02 into trunk Dec 6, 2024
7 checks passed
Copy link

github-actions bot commented Dec 6, 2024

Hey @chickenn00dle, good job getting this PR merged! 🎉

Now, the needs-changelog label has been added to it.

Please check if this PR needs to be included in the "Upcoming Changes" and "Release Notes" doc. If it doesn't, simply remove the label.

If it does, please add an entry to our shared document, with screenshots and testing instructions if applicable, then remove the label.

Thank you! ❤️

@leogermani leogermani deleted the feat/add-cancellation-reason-metadata branch December 6, 2024 18:41
chickenn00dle added a commit that referenced this pull request Dec 12, 2024
This PR adds meta data to cancelled woo subscriptions and uses this new meta to sync cancellation reason to ESPs for cancelled subscriptions.
matticbot pushed a commit that referenced this pull request Dec 12, 2024
# [5.10.0-alpha.1](v5.9.1...v5.10.0-alpha.1) (2024-12-12)

### Bug Fixes

* duplicate orders save on cron ([#3604](#3604)) ([ec69167](ec69167))
* **ras-acc:** re-add recaptcha to the WooCommerce checkout ([#3605](#3605)) ([f42a75b](f42a75b))
* **ras:** do not require Woo plugins if using NRH ([#3614](#3614)) ([363a834](363a834))
* **wcs:** remove subscriptions expiration feature flag ([#3618](#3618)) ([7c175d9](7c175d9))
* **wcs:** update subscription expiration feature ([#3613](#3613)) ([ebf6e6d](ebf6e6d))
* **wcs:** update subscriptions expiration cli behavior ([#3617](#3617)) ([07e768c](07e768c))

### Features

* **subscriptions:** add cancellation reason metadata ([#3568](#3568)) ([de83e02](de83e02))
* **wc:** duplicate orders admin notice ([#3555](#3555)) ([cb764e3](cb764e3))
* **wcs:** add expired subscription cli tool ([#3593](#3593)) ([5d39398](5d39398))
* **webhooks:** filter request priority ([#3587](#3587)) ([1928a6a](1928a6a))
* **woocommerce-subscriptions:** add url redirect for wc subscription renewals ([#3525](#3525)) ([5b14aeb](5b14aeb))

### Reverts

* Revert "feat: command to initialize cron job to slowly backfill CAP term data (#3425)" (#3620) ([c9a9d45](c9a9d45)), closes [#3425](#3425) [#3620](#3620)
@matticbot
Copy link
Contributor

🎉 This PR is included in version 5.10.0-alpha.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

matticbot pushed a commit that referenced this pull request Dec 16, 2024
# [5.10.0](v5.9.2...v5.10.0) (2024-12-16)

### Bug Fixes

* dont load textdomain too early ([#3629](#3629)) ([76c1f97](76c1f97))
* duplicate orders save on cron ([#3604](#3604)) ([ec69167](ec69167))
* hide duplicate notices if all was dismissed ([#3630](#3630)) ([cf48188](cf48188))
* **ras-acc:** re-add recaptcha to the WooCommerce checkout ([#3605](#3605)) ([f42a75b](f42a75b))
* **ras:** do not require Woo plugins if using NRH ([#3614](#3614)) ([363a834](363a834))
* **wcs:** remove subscriptions expiration feature flag ([#3618](#3618)) ([7c175d9](7c175d9))
* **wcs:** update subscription expiration feature ([#3613](#3613)) ([ebf6e6d](ebf6e6d))
* **wcs:** update subscriptions expiration cli behavior ([#3617](#3617)) ([07e768c](07e768c))

### Features

* **subscriptions:** add cancellation reason metadata ([#3568](#3568)) ([de83e02](de83e02))
* **wc:** duplicate orders admin notice ([#3555](#3555)) ([cb764e3](cb764e3))
* **wcs:** add expired subscription cli tool ([#3593](#3593)) ([5d39398](5d39398))
* **webhooks:** filter request priority ([#3587](#3587)) ([1928a6a](1928a6a))
* **woocommerce-subscriptions:** add url redirect for wc subscription renewals ([#3525](#3525)) ([5b14aeb](5b14aeb))

### Reverts

* Revert "feat: command to initialize cron job to slowly backfill CAP term data (#3425)" (#3620) ([c9a9d45](c9a9d45)), closes [#3425](#3425) [#3620](#3620)
@matticbot
Copy link
Contributor

🎉 This PR is included in version 5.10.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
released on @alpha released [Status] Approved The pull request has been reviewed and is ready to merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants