Age | Commit message (Collapse) | Author |
|
solidusio-contrib/nirebu/190/move-subscription-processing-to-background-job
Move subscription processing to its own background job
|
|
solidusio-contrib/kennyadsl/use-new-factories-loading
Load factories using the new standard
|
|
solidusio-contrib/mr/cleanup-duplicated-fields-on-order-finalize
Cleanup the duplicated fields on subscription creation
|
|
|
|
This change moves the processing of individual subscriptions to their
own isolated jobs. The tasks of these individual jobs will be:
- Deactivate/Cancel subscriptions pending one of those operations
- Clear any past failed installment if it's configured to do so
- Create a new installment for the subscription cycle
- Enqueue a job to process any actionable installment for the
subscription
Given we've moved the concern of queueing the installment processing,
that part can be removed safely from the main processor job. The final
part of the change also touches the main processor job, whose task is
now to collect any actionable subscription and any subscription with
an actionable installment to enqueue them for individual processing.
|
|
|
|
|
|
|
|
Solidus 3.0 removes `first_name` and `last_name` from `Spree::Address`
so we should replace them with `name`. The Churn Buster documentation
would suggest it's OK to pass any customer properties we need, but I
have yet to get a developer account to verify.
|
|
These helpers are dangerous: they provide a false sense of assurance
by making you think that the order and the line item they return can
be used to infer the correct total value of future subscription orders.
In reality, order calculation in Solidus is an extremely complex process
that may take a ton of different parameters into account, and each store
is better off calculating the subscription total with their custom logic
rather than this extension trying to provide a solution that works for
everyone.
In the future, we may provide a way to compute a subscription's total,
but for the time being it's better to remove the helpers altogether.
|
|
It wasn't clear why certain business logic should live in `app/services`
while other should live in `lib`. By unifying everything in one directory,
we make it easier for developers to inspect the code and reduce the
cognitive load when implementing new classes.
|
|
Because it's very business-specific, this kind of change should be done
at the application level in a decorator, rather than embedding it in the
extension.
|
|
|
|
Instead of attempting to process multiple installments at a time, which
increases the chances something might go wrong, we are now only processing
one installment at a time.
This also improves the extension's performance, because the installments
can be processed in parallel.
|
|
The processor was way too complicated, taking on too many responsibilities.
As a result, it was complex to reason about and it was a very brittle part
of the extension.
The new processor simply does two things: it finds all actionable
subscriptions and ensures to take the appropriate action on them (e.g.,
cancel, deactivate), including creating the new installment for later.
Then, it finds all the actionable installments (including the ones that
were just created), and schedules them for asynchronous processing.
One side effect of this refactoring is that installments are not grouped
by address and payment method/source anymore: each installment will always
correspond to a new order. Any logistics-related optimizations should be
implemented by the individual store.
|
|
Anyone who cancels their subscription with a failed installment will
still have an order created the next time installments are created.
This is because installments don't check the status of their associated
subscriptions before being processed.
This update will ensure that only installments with active subscriptions
are processed.
|
|
Previously, the cancel method would check if the minimum
cancellation date minus the current day is in the future before
cancelling.
However, that adds one day to whatever minimum cancellation date
that you set - if you set one day, you would expect the user not
to be able to cancel on the day that the subscription ships, but
because the method checks if the date is in the future, the user
can't cancel the day of, or the day before.
This checks if the date is in the future OR if it's today, which
removes the added day from the minimum_cancellation_notice.
Also this sets the default to 0.days, as 1.day is pretty arbitrary
Lastly, this locks canonical-rails down to 0.2.9, because Solidus
still uses the `whitelisted_attributes` method, which was renamed
in 0.2.10
|
|
This changes the logic used to determine whether a subscription should
be canceled after consecutive payment failures. Previously it was based
on a maximum number of attempts per installment, however it makes sense
to have it based on the time passed since the last succesful
installment.
This makes it also play nice with the new configuration [1] to clear
past failed installments, which could render the maximum attempts
useless, since there could have been situations where the maximum
attempts number would never be reached. Switching to time based criteria
makes this simpler and more predictable.
[1] https://github.com/solidusio-contrib/solidus_subscriptions/commit/b3dc679b7056931397820ad333686ef151656ba4
|
|
This implements a configuration to ignore past unfulfilled installments
for subscriptions upon installments creations. Since failed installments
(e.g. because of an expired credit card) are retried indefinitely, they
can overlap and also be retried after another subscription cycle began.
In this particular case, a customer who fixes their payment method after
a new cycle, would be charged for double (or X times as much based on
how long it passed) and sent double the quantity of the same product.
Because in some cases this is not desirable, this adds a switch to skip
any failed past installment when a new installment gets created under
the same subscription.
|
|
|
|
The DefaultCustomer permission set would allow guests to see the
subscriptions list (although they wouldn't be able to see any subscriptions).
|
|
|
|
|
|
CanCan 2 complains about not being able to merge abilities that use
an ActiveRecord scope, so we need to use an SQL string instead.
|
|
|
|
With an AR scope, `#accessible_by` can be properly used.
|
|
|
|
It isn't possible to manage line items through an order anymore, so
we can greatly simplify the permission set.
|
|
Custom abilities are deprecated in favor of the new permission sets
API.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Subscription events
|
|
|
|
classes. Thanks to @ejdraper
|
|
The billing address as well as the interval and end date can now be
set directly on the subscription, so we need to permit those attributes
by default.
|
|
This avoids surprising scenarios where we expect a `create` call to
result in all records being persisted to the DB, while some associated
records are still unsaved.
This was especially problematic when building subscription line items,
because the order is retrieved through a `has_one :through` association
on the `Spree::LineItem` record. If the line item isn't saved, the order
cannot be retrieved, resulting in unexpected errors.
|
|
|
|
Previously, the payment method was set when configuring the gem.
This is not needed, since we can get it directly from the source
we are charging, which is much more flexible since it opens up
the ability to charge sources belonging to different payment methods.
|
|
|
|
|
|
|
|
|
|
|
|
|