I'm using Datatrans module as payment gateway. Module does not fully support recurring payment, so I had to add some missing functionality. I added method createPayment:

  public function createPayment(PaymentInterface $payment, $capture = TRUE) {

    // Allowing only new payments
    $this->assertPaymentState($payment, ['new']);

    $payment_method = $payment->getPaymentMethod();
    $amount = strval(floor(floatval($payment->getAmount()->getNumber())*100));

    // Calling Datatrans API and handling response
    $transaction_data = [
      'apiUrl' => $this->configuration['r_api_url'],
      'errorEmail' => $this->configuration['r_error_email'],
      'successEmail' => $this->configuration['r_success_email'],
      'transactionRefNo' => $payment->getOrderId(),
      'merchantAccountId' => $this->configuration['r_merchant_id'],
      'merchantAccountPassword' => $this->configuration['r_merchant_password'],
      'sign' => $this->configuration['r_sign'],
      'req_type' => $this->configuration['req_type'],
      'expm' => $payment_method->expm->getValue()[0]['value'],
      'expy' => $payment_method->expy->getValue()[0]['value'],
      'amount' => $amount,
      'currencyCode' => $payment->getAmount()->getCurrencyCode(),
      'aliasCC' => $payment_method->getRemoteId(),

    $transaction = DatatransHelper::makeTransaction($transaction_data);

    // Saving payment locally

    $next_state = $capture ? 'completed' : 'authorization';
    $payment->setExpiresTime(strtotime('+5 days'));


And it works, but problem I have is that all recurring orders created by recurring module do not have billing addresses.

Looked at database and condition for an order to have billing address (table "commerce_order") it must have id of user profile set in fields "billing_profile__target_id" and "billing_profile__target_revision_id". If I put some billing profile ids there directly, by editing database billing profile for that order appear and everything works as expected.

What (and where) should I add to my code to set that billing address?

Inside RecurringOrderManager() , refreshOrder() and createOrder() methods I saw row like:

 $billing_profile = $payment_method ? $payment_method->getBillingProfile() : NULL;

and that getBillingProfile() may be the method I'm missing (I do have null instead of billing profile id in database), but what confuses me is that it's defined in PaymentMethodInterface and Datatrans module is not implementing it at all?!

Is it up to Datatrans module to do something in order to set billing profile? How can I do that? I'm not very familiar with this and any hint is welcome.

  • 1
    As the project page says, This module is not production ready! Expect pain.. You should read through all the issues. There are some BIG ones like "Subscription with end date does not expire" and "Provide a button for cancelling an active subscription". So expect alot more work!
    – No Sssweat
    Oct 29, 2020 at 10:10
  • Yes, I saw the warning, very encouraging. :) Also implemented custom subscription cancellation functionality.
    – MilanG
    Oct 29, 2020 at 11:43

1 Answer 1


Some workaround:

  // For unknown reason recurring orders are not getting billing profiles.
  // This method is checking of order has billing profile and if not
  // it finds it's initial order over subscription and copies it's
  // billing profile.
  public static function addMissingBillingAddress (Order $order)
    if ($order->getBillingProfile() == null) {
      $subscriptions = self::collectSubscriptions($order);
      $subscription = array_shift($subscriptions);
      $initialOrder = $subscription->getInitialOrder();
      $billingProfile = $initialOrder->getBillingProfile();

  public static function collectSubscriptions($order) {
    $subscriptions = [];
    foreach ($order->getItems() as $order_item) {
      if ($order_item->get('subscription')->isEmpty()) {
        // A recurring order item without a subscription ID is malformed.
      /** @var \Drupal\commerce_recurring\Entity\SubscriptionInterface $subscription */
      $subscription = $order_item->get('subscription')->entity;
      // Guard against deleted subscription entities.
      if ($subscription) {
        $subscriptions[$subscription->id()] = $subscription;
    return $subscriptions;

When I'm processing recurring order I'm checking if billing address is missing and if it does I'm collecting one from initial order (over subscription) and injecting that one.

Of course, I would like to know why it's not added at first place.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.