-
Notifications
You must be signed in to change notification settings - Fork 56
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
allow importing cancelled date, and fix handling of end_date #278
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @dkoo. Thanks for the PR.
I think the changes generally look good. I left some initial review comments. Let me know what you think. :)
includes/class-wcs-importer.php
Outdated
* @param WC_Subscription $subscription The subscription object created by the importer. | ||
* @param array $result The result of the import. | ||
*/ | ||
do_action( 'woocommerce_subscription_imported_via_csv', $subscription, $result ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do_action( 'woocommerce_subscription_imported_via_csv', $subscription, $result ); | |
do_action( 'woocommerce_subscription_imported_via_csv', $subscription, $result, $data ); |
Passing the data variable (the csv row) might assist with folks who have custom data that they would like to set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea—added in 4bba344
includes/class-wcs-importer.php
Outdated
$result['error'][] = sprintf( __( 'The %s date must occur after the trial end date.', 'wcs-import-export' ), $date_type ); | ||
} | ||
case 'trial_end_date' : | ||
if ( strtotime( $datetime ) <= strtotime( $dates_to_update['start'] ) ) { | ||
if ( 'trial_end_date' === $date_type && strtotime( $datetime ) <= strtotime( $dates_to_update['start'] ) ) { | ||
$result['error'][] = sprintf( __( 'The %s must occur after the start date.', 'wcs-import-export' ), $date_type ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC this switch statement purposefully doesn't have break statements and it is expected to flow through the lower cases. eg cancelled being the top case means that the cancelled date is also validated against the end date, next payment and trial end checks. ie the cancelled date must occur after the next payment date (which is a condition under the end date case).
I've never been a fan of this code though as it's super confusing, hard to follow and is not intuitive at all. I wonder if the csv importer would benefit just not validating the dates relationships at all? 🤔
It calls $subscription->update_dates()
which validates them anyway and throws exceptions if they don't pass the validation rules.
The csv importer/exporter calls update_dates in a try catch block so would be able to catch those exceptions and handle them appropriately anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just realised that removing this section would essentially break an important part of test mode as folks would use test mode to verify that the dates are valid and update_dates()
isn't called while in test mode. 🤔
hmm. How important were these changes for the goal of this PR? It seems from the PR description that you were mostly set on allowing users to set cancelled dates and for the end date issue with regard to when the status is set.
So, can these proposed changes be removed from this PR and we can look into doing a bit more of an overhaul of the validation of dates at a later time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@james-allan you're right—these changes are a bit overzealous. I've reduced their scope to only add validation for checking cancelled_date
vs. end_date
, so the behavior for validating other dates should be intact.
Co-authored-by: James Allan <james@prospress.com>
@james-allan thanks for reviewing and testing these changes! Your feedback helped me narrow down the actual cause of the issue where
So the fix is to retain the Let me know if this is working for you, now! |
This isn't my understanding of how this works. If you don't pass all dates, it will populate the a full set of dates from the incoming changes and the subscription's current dates so it can validate all eventual dates together (link to that code), is this what you meant by automatically calculating? The only thing I can think of where dates are automatically set is when you update the status. So, for example, setting a subscription to active will automatically calculate a next payment date if the existing one is in the past or not set at all. I don't think calling I do think this is the root cause behind #201 though. In the old importer code, the subscription would always go through a status transition. eg start as pending and be updated to the eventual status (expired). Whenever a subscription is cancelled or expired, we always set the end date, irrespective of what was previously set. IIRC creating subscriptions via the REST API had a similar problem. In that case we added a new REST param to enable users to
I don't think this is the case. I can create a 'pending' subscription with a cancelled date and end date with the following code: $subscription = wcs_create_subscription( [
'customer_id' => 1,
'billing_period' => 'month',
'billing_interval' => 1,
] );
$subscription->update_dates( [
'cancelled_date' => '2024-02-12 08:00:00',
'end_date' => '2025-12-25 10:00:00'
] ); In that example the subscription is created correctly as pending with a cancelled and end date. In any case, I think these changes are good now. It resolves #201 because when an imported subscription is cancelled, or expired, it gets created with that status avoiding a status transition which was causing it to override the previously set end date. 👍 This PR also allows importing subscriptions with a cancelled date. 👍 There's a new filter to allow third-parties to set any additional data from the csv row. |
I was misunderstanding how the logic works on the WCS side, but that's more or less what looked like was happening in the import function. So if I understand correctly now, what happened was the end dates were set correctly on the Thanks for clarifying, testing, and approving! |
Adds support for a new
cancelled_date
column to the importer CSV, so that you can set a cancelled date for subscriptions with an "ended"-type status.Also resolves #201, in which
end_date
inputs are ignored for a couple of reasons:WC_Subscription::update_dates()
will reject and discardend_date
andcancelled_date
params if the subscription does not have an ended-type status. Onmaster
,end_date
will never get set becauseupdate_dates
is called before the status is set, meaning imported subscriptions will always have apending
status at the time dates are set. Fixed this by settingstatus
earlier, in the params passed towcs_create_subscription
, instead of in a separate$subscription->update_status()
call after updating the dates.end_date
on a subscription without acancelled_date
or with acancelled_date
before the givenend_date
will result in a fatal error. Fixed this by looking for acancelled_date
input (and throwing an error if the givencancelled_date
is not beforeend_date
, and automatically settingcancelled_date
to matchend_date
if not given.Lastly, adds a
woocommerce_subscription_imported_via_csv
action hook that fires after a subscription has been successfully created and its data updated to match the input CSV data. This could be useful for other devs to extend and customize the importer's behavior after subscriptions are imported.To test: create an import CSV with a
cancelled_date
column inY-m-d H:i:s
format. Test with:end_date
(expected result: import should succeed with no warnings/errors)end_date
(expected result: import should succeed a warning, andcancelled_date
should get set to the same value asend_date
)end_date
value (expected result: import should succeed with no warnings/errors)end_date
(expected result: import should fail with an error)cancelled_date
and/orend_date
with asubscription_status
value ofwc-pending
orwc-active
(expected result: import should fail with an error)To test the new hook, add
add_action( 'woocommerce_subscription_imported_via_csv', 'callback_name', 10, 2 );
somewhere and make sure it passes the expected arguments (theWC_Subscription
object of the imported subscription, and the results array from the import).