- Issue created by @john pitcairn
- πͺπΈSpain qtarant
Hello. I have exactly the same issue. As a collateral effect subscriptions are never canceled, because the "draft" order is canceled because there is no order items on order, and after that cron is searching draft orders and the order (related with a canceled subscription) was canceled so cron not applies changes on subscription state.
I fixed checking if there are charges before create new order items and delete previous order items on the order. - π¬π§United Kingdom code-brighton
Hi qtarant, can you post the code you changed? Or supply a patch? Many thanks
- πΊπΈUnited States sapiusenator
I don't know if this is 100% or not, but worth a gander I suppose.
namespace Drupal\my_custom use Drupal\commerce_recurring\RecurringOrderManager as BaseRecurringOrderManager; use Drupal\commerce_order\Entity\OrderInterface; use Drupal\commerce_recurring\Entity\SubscriptionInterface; use Drupal\commerce_recurring\BillingPeriod; /** * Extends RecurringOrderManager to preserve order items when subscriptions are canceled. * * The default behavior deletes all order items when a canceled subscription has no charges. * This override preserves those items by skipping the deletion process and transitioning * draft/needs_payment orders to canceled state instead. */ class MyCustomRecurringOrderManager extends BaseRecurringOrderManager { /** * {@inheritdoc} */ protected function applyCharges(OrderInterface $order, SubscriptionInterface $subscription, BillingPeriod $billing_period, BillingPeriod $trial_period = NULL) { // Collect charges to see what we're dealing with $charges = []; if ($subscription->getState()->getId() == 'trial') { $charges = $subscription->getType()->collectTrialCharges($subscription, $billing_period); } else { $charges = $subscription->getType()->collectCharges($subscription, $billing_period); } // If subscription is canceled and there are no charges, preserve items if (empty($charges) && $subscription->getState()->getId() === 'canceled') { // Check if order should be canceled $order_state = $order->getState()->getId(); if (in_array($order_state, ['draft', 'needs_payment']) && $order->hasItems()) { // Apply cancel transition $transitions = $order->getState()->getTransitions(); if (isset($transitions['cancel'])) { $order->getState()->applyTransitionById('cancel'); } } // Skip processing - this preserves the items return; } // For all other cases, use the parent's normal logic parent::applyCharges($order, $subscription, $billing_period, $trial_period); } }