Creating a checkout flow plugin may solve your problem. Create a Plugin in your custom module like an example shown below:
namespace Drupal\my_checkout_flow\Plugin\Commerce\CheckoutFlow;
use Drupal\commerce_checkout\Plugin\Commerce\CheckoutFlow\CheckoutFlowWithPanesBase;
use Drupal\Core\Form\FormStateInterface;
/**
* @CommerceCheckoutFlow(
* id = "custom_checkout_flow",
* label = @Translation("Custom checkout flow"),
* )
*/
class CustomCheckoutFlow extends CheckoutFlowWithPanesBase {
/**
* {@inheritdoc}
*/
public function getSteps() {
return [
'login' => [
'label' => $this->t('Login'),
'previous_label' => $this->t('Return to login'),
'has_order_summary' => FALSE,
],
'card_info' => [
'label' => $this->t('Card information'),
'previous_label' => $this->t('Return to Card information'),
'next_label' => $this->t('Continue to Card information'),
'has_order_summary' => FALSE,
],
'address_information' => [
'label' => $this->t('Address information'),
'previous_label' => $this->t('Return to Address information'),
'next_label' => $this->t('Continue to Address information'),
'has_order_summary' => FALSE,
],
'review' => [
'label' => $this->t('Review'),
'has_order_summary' => TRUE,
],
] + parent::getSteps();
}
}
After creating a plugin, you need to change the checkout flow settings for your order type.
For more information visit: https://docs.drupalcommerce.org/commerce2/developer-guide/checkout/create-custom-checkout-flow
Update
CustomCheckoutFlow
<?php
namespace Drupal\my_checkout_flow\Plugin\Commerce\CheckoutFlow;
use Drupal\commerce_checkout\Plugin\Commerce\CheckoutFlow\CheckoutFlowWithPanesBase;
/**
* @CommerceCheckoutFlow(
* id = "custom_checkout_flow",
* label = @Translation("Custom checkout flow"),
* )
*/
class CustomCheckoutFlow extends CheckoutFlowWithPanesBase {
/**
* {@inheritdoc}
*/
public function getSteps() {
return [
'login' => [
'label' => $this->t('Login'),
'previous_label' => $this->t('Go back'),
'has_sidebar' => FALSE,
],
'card_information' => [
'label' => $this->t('Card information'),
'previous_label' => $this->t('Go back'),
'has_sidebar' => TRUE,
],
'order_information' => [
'label' => $this->t('Order information'),
'has_sidebar' => TRUE,
'next_label' => $this->t('Continue to Order information'),
'previous_label' => $this->t('Go back'),
],
'review' => [
'label' => $this->t('Review'),
'next_label' => $this->t('Continue to review'),
'previous_label' => $this->t('Go back'),
'has_sidebar' => TRUE,
],
] + parent::getSteps();
}
}
Then create CheckoutPanes as shown below:
BillingInformation
<?php
namespace Drupal\my_checkout_flow\Plugin\Commerce\CheckoutPane;
use \Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane\BillingInformation;
/**
* Provides the billing information pane.
*
* @CommerceCheckoutPane(
* id = "custom_billing_information",
* label = @Translation("Billing information"),
* default_step = "order_information",
* wrapper_element = "fieldset",
* )
*/
class CustomBillingInformation extends BillingInformation {
}
PaymentInformation
<?php
namespace Drupal\my_checkout_flow\Plugin\Commerce\CheckoutPane;
use Drupal\commerce_payment\Plugin\Commerce\CheckoutPane\PaymentInformation as PaymentInformationBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
/**
* Provides the payment information pane.
*
* @CommerceCheckoutPane(
* id = "custom_commerce_payment_information",
* label = @Translation("Custom Payment information"),
* display_label = @Translation("Payment information"),
* default_step = "order_information",
* wrapper_element = "fieldset",
* )
*/
class PaymentInformation extends PaymentInformationBase {
/**
* {@inheritdoc}
*/
public function buildPaneForm(array $pane_form, FormStateInterface $form_state, array &$complete_form) {
$pane_form = parent::buildPaneForm($pane_form, $form_state, $complete_form);
// Add an after build callback in order to make modifications on the address form.
$pane_form['#after_build'][] = [$this, 'paneFormAfterBuild'];
return $pane_form;
}
/**
* After build callback for the pane form.
*/
public function paneFormAfterBuild(array $pane_form, FormStateInterface $form_state) {
// Get billing form element. Where it is located depends on the payment method that is chosen.
if (isset($pane_form['add_payment_method']['billing_information'])) {
$billing_form = &$pane_form['add_payment_method']['billing_information'];
}
elseif (isset($pane_form['billing_information'])) {
$billing_form = &$pane_form['billing_information'];
}
else {
// No billing information found.
return $pane_form;
}
// Get the address form element.
$address_form = &$billing_form['address']['widget']['0']['address'];
// Add element validation callback to autofill the address.
$billing_form['#element_validate'] = array_merge(
[[$this, 'profileSelectValidate']],
\Drupal::service('element_info')->getInfoProperty('commerce_profile_select', '#element_validate', [])
);
// Set all address fields to non-required.
foreach (Element::children($address_form) as $key) {
$address_form[$key]['#required'] = FALSE;
}
// Hide the address form.
$address_form['#access'] = FALSE;
return $pane_form;
}
/**
* Element validation callback for the profile select element.
*/
public function profileSelectValidate(array &$element, FormStateInterface $form_state) {
$billing_profile = $this->order->getBillingProfile()->get('address')->getValue();
$form_state->setValue($element['address']['widget'][0]['address']['#parents'], $billing_profile[0]);
}
}
PaymentProcess
<?php
namespace Drupal\my_checkout_flow\Plugin\Commerce\CheckoutPane;
use Drupal\commerce_payment\Plugin\Commerce\CheckoutPane\PaymentProcess as BasePaymentProcess;
/**
* Provides the payment process pane.
*
* @CommerceCheckoutPane(
* id = "custom_payment_process",
* label = @Translation("Custom Payment process"),
* default_step = "payment",
* wrapper_element = "container",
* )
*/
class PaymentProcess extends BasePaymentProcess {
/**
* {@inheritdoc}
*/
public function isVisible() {
// This pane can't be used without the PaymentInformation pane.
$payment_info_pane = $this->checkoutFlow->getPane('custom_commerce_payment_information');
return $payment_info_pane->isVisible() && $payment_info_pane->getStepId() != '_disabled';
}
}
After this set checkout panes for your custom checkout flow as shown in the image below:

Find full code at https://github.com/patilvishalvs/my_checkout_flow