commercetools-8.x-1.2-alpha1/modules/commercetools_content/src/Form/OrderSubmissionForm.php
modules/commercetools_content/src/Form/OrderSubmissionForm.php
<?php
namespace Drupal\commercetools_content\Form;
use Drupal\commercetools\CommercetoolsApiServiceInterface;
use Drupal\commercetools\CommercetoolsCarts;
use Drupal\commercetools\CommercetoolsCustomers;
use Drupal\commercetools\CommercetoolsLocalization;
use Drupal\commercetools\CommercetoolsService;
use Drupal\commercetools\Routing\UiModulesRouteProviderBase;
use Drupal\commercetools_content\Routing\RouteProvider;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides order submission form.
*/
class OrderSubmissionForm extends FormBase {
/**
* The Commercetools service.
*
* @var \Drupal\commercetools\CommercetoolsService
*/
protected CommercetoolsService $ct;
/**
* The Commercetools API service.
*
* @var \Drupal\commercetools\CommercetoolsApiServiceInterface
*/
protected CommercetoolsApiServiceInterface $ctApi;
/**
* The commercetools cart service.
*
* @var \Drupal\commercetools\CommercetoolsCarts
*/
protected CommercetoolsCarts $ctCart;
/**
* The commercetools customers service.
*
* @var \Drupal\commercetools\CommercetoolsCustomers
*/
protected CommercetoolsCustomers $ctCustomers;
/**
* The customers addresses.
*
* @var array
*/
protected array $customerAddresses = [
CommercetoolsCustomers::SHIPPING_ADDRESS_KEY => NULL,
CommercetoolsCustomers::BILLING_ADDRESS_KEY => NULL,
];
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
$instance = parent::create($container);
$instance->ctApi = $container->get('commercetools.api');
$instance->ct = $container->get('commercetools');
$instance->ctCart = $container->get('commercetools.carts');
$instance->ctCustomers = $container->get('commercetools.customers');
return $instance;
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'commercetools_content_order_submission';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $install_state = NULL) {
$cart = $this->buildCartWithCustomerAddresses();
$addressTypes = [
CommercetoolsCustomers::SHIPPING_ADDRESS_KEY => $this->t('Shipping address'),
CommercetoolsCustomers::BILLING_ADDRESS_KEY => $this->t('Billing address'),
];
foreach ($addressTypes as $key => $label) {
$addressValues = $cart[$key];
$form[$key] = [
'#type' => 'fieldset',
'#tree' => TRUE,
'#weight' => 1,
'#attributes' => [
'class' => ['shadow', 'p-3', 'bg-primary', 'bg-opacity-10'],
],
'label' => [
'#type' => 'html_tag',
'#tag' => 'h2',
'#value' => $label,
'#weight' => -10,
'#attributes' => [
'class' => ['pb-3', 'mb-4', 'border-bottom'],
],
],
];
$addressFields = [];
if (!$this->currentUser()->isAuthenticated()) {
$addressFields['new'] = $this->addressFields($addressValues);
}
else {
$selectAddressSelector = ':input[name="' . $key . '[selected]"]';
$stateNewAddress = [$selectAddressSelector => ['value' => 'new']];
// Build fields for new addresses or address in cart that not saved.
$addressFields['new'] = ['#type' => 'container'];
$addressFields['new']['#states']['visible'][] = $stateNewAddress;
$addressFields['new'] += $this->addressFields($addressValues && empty($addressValues['id']) ? $addressValues : []);
array_walk($addressFields['new'], function (&$field) use ($stateNewAddress) {
if (isset($field['#required'])) {
$field['#required'] = FALSE;
$field['#states']['required'][] = $stateNewAddress;
}
});
// Build fields all addresses.
if ($this->customerAddresses[$key]) {
foreach ($this->customerAddresses[$key] as $addressKey => $address) {
$existedAddressFields = $this->addressFields($address);
array_walk($existedAddressFields, function (&$field) {
$field['#disabled'] = TRUE;
unset($field['#required']);
});
$addressFields[$addressKey] = ['#type' => 'container'];
$addressFields[$addressKey]['#states']['visible'][] = [$selectAddressSelector => ['value' => $addressKey]];
$addressFields[$addressKey] += $existedAddressFields;
}
}
$addressFields['save'] = [
'#type' => 'checkbox',
'#title' => $this->t('Save this new address to reuse in the next orders'),
'#attributes' => ['class' => ['saveAddress']],
'#states' => [
'visible' => $stateNewAddress,
],
];
$addressFields['title'] = [
'#type' => 'textfield',
'#title' => $this->t('Fill the title to name this address in the list of saved addresses'),
'#states' => [
'visible' => [
':input[name="' . $key . '[save]"]' => ['checked' => TRUE],
],
],
];
$addressFields['set_default'] = [
'#type' => 'checkbox',
'#title' => $this->t('Use this address as default for the next orders'),
'#states' => [
'visible' => [
':input[name="' . $key . '[save]"]' => ['checked' => TRUE],
],
],
];
if ($this->customerAddresses[$key]) {
$addressFields['selected'] = [
'#type' => 'select',
'#title' => $this->t('Fill a new address or choose from saved'),
'#options' => ['new' => $this->t('Add a new address')] + array_filter(array_column($this->customerAddresses[$key], 'title', 'id')),
'#default_value' => $addressValues['id'] ?? 'new',
'#weight' => -9,
];
}
}
$form[$key] += $addressFields;
}
$form['same_address'] = [
'#prefix' => '<div class="mt-4 mb-4 shadow p-3 bg-primary bg-opacity-10">',
'#suffix' => '</div>',
'#type' => 'checkbox',
'#title' => $this->t('Billing address same as shipping address'),
'#default_value' => empty($cart['billingAddress']),
'#weight' => 2,
];
$form['billingAddress']['#weight'] = 3;
foreach ($form['billingAddress']['new'] as &$element) {
if (isset($element['#required'])) {
$element['#required'] = FALSE;
$element['#states'] = [
'required' => [
':input[name="same_address"]' => ['checked' => FALSE],
':input[name="billingAddress[selected]"]' => ['value' => 'new'],
],
];
}
}
$form['billingAddress']['#states'] = [
'invisible' => [
':input[name="same_address"]' => ['checked' => TRUE],
],
];
$form['actions'] = [
'#type' => 'actions',
'submit' => [
'#type' => 'submit',
'#value' => $this->t('Save & Continue'),
],
];
$form_state->setValue('test', 'test1');
return $form;
}
/**
* Add fields with values to each address.
*/
protected function addressFields(?array $addressValues): array {
return [
'firstName' => [
'#type' => 'textfield',
'#title' => $this->t('First name'),
'#default_value' => $addressValues['firstName'] ?? NULL,
'#required' => TRUE,
],
'lastName' => [
'#type' => 'textfield',
'#title' => $this->t('Last name'),
'#default_value' => $addressValues['lastName'] ?? NULL,
'#required' => TRUE,
],
'email' => [
'#type' => 'email',
'#title' => $this->t('Email'),
'#default_value' => $addressValues['email'] ?? $this->currentUser()->getEmail() ?? NULL,
'#disabled' => $this->currentUser()->isAuthenticated(),
'#attributes' => ['class' => [$this->currentUser()->isAuthenticated() ? 'disabled' : '']],
'#required' => TRUE,
],
'country' => [
'#type' => 'textfield',
'#title' => $this->t('Country'),
'#default_value' => $this->config(CommercetoolsLocalization::CONFIGURATION_NAME)
->get(CommercetoolsLocalization::CONFIG_COUNTRY),
'#disabled' => TRUE,
'#attributes' => ['class' => ['disabled']],
],
'streetName' => [
'#type' => 'textfield',
'#title' => $this->t('Street Address'),
'#default_value' => $addressValues['streetName'] ?? NULL,
'#required' => TRUE,
],
'streetNumber' => [
'#type' => 'textfield',
'#title' => $this->t('Street number'),
'#default_value' => $addressValues['streetNumber'] ?? NULL,
],
'state' => [
'#type' => 'textfield',
'#title' => $this->t('State'),
'#default_value' => $addressValues['state'] ?? NULL,
'#required' => TRUE,
],
'city' => [
'#type' => 'textfield',
'#title' => $this->t('City'),
'#default_value' => $addressValues['city'] ?? NULL,
'#required' => TRUE,
],
'postalCode' => [
'#type' => 'textfield',
'#title' => $this->t('ZIP code'),
'#default_value' => $addressValues['postalCode'] ?? NULL,
'#required' => TRUE,
],
'phone' => [
'#type' => 'textfield',
'#title' => $this->t('Phone number'),
'#default_value' => $addressValues['phone'] ?? NULL,
],
];
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$cart = $this->ctCart->getCurrentCart()->getData();
$formValues = $form_state->getValues();
$isAnonymous = !$this->currentUser()->isAuthenticated();
$resolveAddress = function ($type) use ($formValues, $isAnonymous) {
if ($isAnonymous) {
return $formValues[$type]['new'];
}
$addressKey = $formValues[$type]['selected'] ?? 'new';
$isNewAddress = $addressKey === 'new';
$address = $isNewAddress
? $formValues[$type]['new']
: $this->customerAddresses[$type][$addressKey];
if ($isNewAddress && $formValues[$type]['save']) {
$address['title'] = $formValues[$type]['title'];
$address = $this->ctCustomers->addAddress($address, $type, $formValues[$type]['set_default']);
}
return $address;
};
$shippingAddress = $resolveAddress(CommercetoolsCustomers::SHIPPING_ADDRESS_KEY);
$billingAddress = $formValues['same_address']
? $shippingAddress
: $resolveAddress(CommercetoolsCustomers::BILLING_ADDRESS_KEY);
try {
$response = $this->ctCart->updateCart($cart['id'], $cart['version'], [
[
'setShippingAddress' => [
'address' => $shippingAddress,
],
],
[
'setBillingAddress' => [
'address' => $billingAddress,
],
],
]);
$order = $this->ctCart->createOrderFromCart($response->getData())->getData();
$this->ctCart->deleteCurrentCart();
$form_state->setRedirect(RouteProvider::ROUTE_PREFIX . UiModulesRouteProviderBase::PAGE_USER_ORDER_ROUTE, [
'user' => $this->currentUser()->id(),
'orderId' => $order['id'],
]);
}
catch (\Exception $e) {
$this->logger('commercetools_content')->error('OrderSubmissionForm: ' . $e->getMessage());
$form_state->setRebuild();
}
}
/**
* Build the cart payload by merging in the authenticated user’s addresses.
*/
protected function buildCartWithCustomerAddresses() {
$billingSame = FALSE;
$cart = $this->ctCart->getCurrentCart()->getData();
if (!empty($cart['shippingAddress']['id']) && !empty($cart['billingAddress']['id']) &&
$cart['shippingAddress']['id'] === $cart['billingAddress']['id']) {
$cart['billingAddress'] = NULL;
$billingSame = TRUE;
}
if (!$this->currentUser()->isAuthenticated()) {
return $cart;
}
$addressData = $this->ctCustomers->getAddressDataByCustomer();
$fillTitle = function (array $addr) {
$addr['title'] ??= $addr['id'];
return $addr;
};
foreach ([CommercetoolsCustomers::SHIPPING_ADDRESS_KEY, CommercetoolsCustomers::BILLING_ADDRESS_KEY] as $type) {
$multiKey = CommercetoolsCustomers::ADDRESSES_MULTIPLE_KEYS[$type];
$addresses = array_column($addressData[$multiKey], NULL, 'id');
$this->customerAddresses[$type] = array_map($fillTitle, $addresses);
if (empty($cart[$type]) && ($type !== CommercetoolsCustomers::BILLING_ADDRESS_KEY || !$billingSame)) {
$cart[$type] = $addresses[$addressData['default' . ucfirst($type) . 'Id']] ?? NULL;
}
}
return $cart;
}
}
