When adding/updating a subscription through the UI (/admin/braintree-cashier/subscription/add), and the subscription's period_end_date field is left empty, that field is always set to the current time. Looks like this is due to what happens in TimestampDatetimeWidget::massageFormValues. See https://drupal.stackexchange.com/a/220961 for more background. The other timestamp fields on the subscription entity don't have this issue, since they're currently not exposed in the form.
Looks like proper way to resolve this is to switch the Timestamp fields to Date fields, since they do support empty values, and have built-in formatters. We could also implement our own timestamp form widget (so we can avoid setting a default timestamp value), but that seems like a temporary fix.
What do you think?
Comments
Comment #2
brunodboComment #3
shaundychkoYes, Drupal's timestamp field UI is a pain. From what I understand, changing it to a
Datefield would involve an update hook thatDatefieldAm I missing anything? Since this is a fair bit of hassle, would it suffice to do this only for the "Period end date" field that has a user facing UI? The other date fields are set only programmatically. Since I'm accustomed to working with timestamps, and the code already assumes the period end date is a timestamp, I'm considering keeping the getter/setter for this field as giving/providing timestamps, and just changing the implementation of those methods to consume and emit timestamps for
Datefields. This would avoid having to test and modify code elsewhere, and takes advantage of one of the main reasons for using getter/setter functions, no?If I'm missing anything, please let me know.
Comment #5
shaundychkoThe commit here updates the
period_end_datefield to the core base typedatetime, copying all old values to the new field using the expirable key-value store.Comment #6
brunodboThanks for this!
Yep, I think we can leave the non-exposed timestamp fields for now. If one day we end up needing to show those in the form, we can deal with it then. Though I can't think of a reason to expose them right now, since they are meant to track things internally.
One thing I was wondering about this change:
Instead of checking whether
$subscription->getPeriodEndDate() < time()in theforeachloop, would it make sense to comparetime()formatted asDateTimeItemInterface::DATETIME_STORAGE_FORMATwith theperiod_end_datevalue in the entity query condition, in order to minimize the amount of entities to load? Though you would need to have a lot of subscriptions for this to become a scalability problem...Comment #7
shaundychkoThanks for the review!
Regarding the
period_end_datecondition, I would agree with your suggestion, but I don't understand well enough how the database query does the string comparison. So long asDateTimeItemInterface::DATETIME_STORAGE_FORMATis the same as ISO8601 format, I suppose string comparison works, but does the DB query do this the way we expect? I have no hesitation comparing integers, which is why I went with the$subscription->getPeriodEndDate() < time()solution, despite having to process that on every cron run for every active subscription set to cancel at period end. If this might need changing, let's please open a new issue and someone can perform due diligence on the concept.