diff --git a/commerce_webform_order.module b/commerce_webform_order.module index 7632495..4e0c87d 100644 --- a/commerce_webform_order.module +++ b/commerce_webform_order.module @@ -5,6 +5,10 @@ * Code for the Commerce Webform Order module. */ +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Field\FieldStorageDefinitionInterface; + /** * Implements hook_theme(). */ @@ -15,3 +19,58 @@ function commerce_webform_order_theme() { ], ]; } + +/** + * Implements hook_entity_base_field_info(). + */ +function commerce_webform_order_entity_base_field_info(EntityTypeInterface $entity_type) { + $fields = []; + + // Add our base fields, to add relation between webform submissions, orders + // and order items. + if ($entity_type->id() == 'commerce_order_item') { + $fields['commerce_webform_order_submissions'] = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Webform submission')) + ->setDescription(t('The webform submission which has created by this order item.')) + ->setCardinality(1) + ->setRequired(FALSE) + ->setSetting('target_type', 'webform_submission') + ->setSetting('handler', 'default') + ->setTranslatable(FALSE) + ->setDisplayConfigurable('form', FALSE) + ->setDisplayOptions('form', [ + 'region' => 'hidden', + 'weight' => 0, + ]) + ->setDisplayConfigurable('view', TRUE) + ->setDisplayOptions('view', [ + 'region' => 'hidden', + 'weight' => 0, + ]); + + return $fields; + } + elseif ($entity_type->id() == 'webform_submission') { + $fields['commerce_webform_order_orders'] = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Commerce orders')) + ->setDescription(t('The commerce orders which have been created by this webform submission.')) + // One order could be created by multiple submissions. + ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) + ->setRequired(FALSE) + ->setSetting('target_type', 'commerce_order') + ->setSetting('handler', 'default') + ->setTranslatable(FALSE) + ->setDisplayConfigurable('form', FALSE) + ->setDisplayOptions('form', [ + 'region' => 'hidden', + 'weight' => 0, + ]) + ->setDisplayConfigurable('view', TRUE) + ->setDisplayOptions('view', [ + 'region' => 'hidden', + 'weight' => 0, + ]); + + return $fields; + } +} diff --git a/src/Plugin/Field/FieldFormatter/OrderIdLinkFormatter.php b/src/Plugin/Field/FieldFormatter/OrderIdLinkFormatter.php new file mode 100644 index 0000000..4dbc9e8 --- /dev/null +++ b/src/Plugin/Field/FieldFormatter/OrderIdLinkFormatter.php @@ -0,0 +1,78 @@ +getEntitiesToView($items, $langcode) as $delta => $entity) { + $id = $entity->id(); + // If the order has a uri, display a link. + if ($output_as_link && !$entity->isNew()) { + try { + $uri = $entity->toUrl(); + } + catch (UndefinedLinkTemplateException $e) { + // This exception is thrown by \Drupal\Core\Entity\Entity::toUrl() + // and it means that the entity type doesn't have a link template nor + // a valid "uri_callback", so don't bother trying to output a link for + // the rest of the referenced entities. + $output_as_link = FALSE; + } + } + + if ($output_as_link && isset($uri) && !$entity->isNew()) { + $elements[$delta] = [ + '#type' => 'link', + '#title' => $id, + '#url' => $uri, + '#options' => $uri->getOptions(), + ]; + + if (!empty($items[$delta]->_attributes)) { + $elements[$delta]['#options'] += ['attributes' => []]; + $elements[$delta]['#options']['attributes'] += $items[$delta]->_attributes; + // Unset field item attributes since they have been included in the + // formatter output and shouldn't be rendered in the field template. + unset($items[$delta]->_attributes); + } + } + else { + $elements[$delta] = ['#plain_text' => $id]; + } + $elements[$delta]['#cache']['tags'] = $entity->getCacheTags(); + } + + return $elements; + } + + /** + * {@inheritdoc} + */ + protected function checkAccess(EntityInterface $entity) { + return $entity->access('view label', NULL, TRUE); + } + +} diff --git a/src/Plugin/WebformHandler/CommerceWebformOrderHandler.php b/src/Plugin/WebformHandler/CommerceWebformOrderHandler.php index 8b57643..b648735 100644 --- a/src/Plugin/WebformHandler/CommerceWebformOrderHandler.php +++ b/src/Plugin/WebformHandler/CommerceWebformOrderHandler.php @@ -259,6 +259,7 @@ class CommerceWebformOrderHandler extends WebformHandlerBase { 'hide_add_to_cart_message' => FALSE, 'redirect' => TRUE, ], + 'states' => [WebformSubmissionInterface::STATE_COMPLETED], 'debug' => FALSE, ]; } @@ -529,6 +530,31 @@ class CommerceWebformOrderHandler extends WebformHandlerBase { '#default_value' => $this->configuration['checkout']['redirect'], ]; + // Additional. + $results_disabled = $this->getWebform()->getSetting('results_disabled'); + $form['additional'] = [ + '#type' => 'fieldset', + '#title' => $this->t('Additional settings'), + ]; + // Settings: States. + $form['additional']['states'] = [ + '#type' => 'checkboxes', + '#title' => $this->t('Create order'), + '#options' => [ + WebformSubmissionInterface::STATE_DRAFT => $this->t('…when draft is saved.'), + WebformSubmissionInterface::STATE_CONVERTED => $this->t('…when anonymous submission is converted to authenticated.'), + WebformSubmissionInterface::STATE_COMPLETED => $this->t('…when submission is completed.'), + WebformSubmissionInterface::STATE_UPDATED => $this->t('…when submission is updated.'), + WebformSubmissionInterface::STATE_DELETED => $this->t('…when submission is deleted.'), + ], + '#parents' => [ + 'settings', + 'states', + ], + '#access' => $results_disabled ? FALSE : TRUE, + '#default_value' => $results_disabled ? [WebformSubmissionInterface::STATE_COMPLETED] : $this->configuration['states'], + ]; + // Settings: Debug. $form['development'] = [ '#type' => 'details', @@ -567,6 +593,9 @@ class CommerceWebformOrderHandler extends WebformHandlerBase { $values = $form_state->getValues(); + // Cleanup states. + $values['states'] = array_values(array_filter($values['states'])); + foreach ($this->configuration as $name => $value) { if (isset($values[$name])) { $this->configuration[$name] = $values[$name]; @@ -577,117 +606,125 @@ class CommerceWebformOrderHandler extends WebformHandlerBase { /** * {@inheritdoc} */ - public function submitForm(array &$form, FormStateInterface $form_state, WebformSubmissionInterface $webform_submission) { - try { - // Collect data from the handler and the webform submission. - $data = $this->prepareData($webform_submission); - - /** @var \Drupal\commerce_order\OrderStorage $order_item_storage */ - $order_item_storage = $this->entityTypeManager->getStorage('commerce_order_item'); - - // Create the order item. - /** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */ - $order_item = $order_item_storage->create([ - 'type' => $data['order_item_bundle'], - 'title' => $data['title'], - 'unit_price' => $data['price'], - 'overridden_unit_price' => TRUE, - 'quantity' => (string) $data['quantity'], - 'purchased_entity' => $data['product_variation'], - ]); - - // Add non BaseFieldDefinition field values. - foreach ($data['order_item_fields'] as $field => $value) { - $order_item->set($field, $value); - } - - // Create or update the cart. - $order_type_id = $this->orderTypeResolver->resolve($order_item); - $this->cart = $this->cartProvider->getCart($order_type_id, $data['store']); - if (!$this->cart) { - $this->cart = $this->cartProvider->createCart($order_type_id, $data['store']); - } - elseif ($this->configuration['checkout']['empty_cart']) { - $this->cartManager->emptyCart($this->cart); - } - - // Set the owner and the email if the user is not an anonymous user. - if ($this->currentUser->isAuthenticated()) { - $this->cart->setCustomerId($this->currentUser->id()); - $this->cart->setEmail($this->currentUser->getEmail()); - } - // Set the email. - elseif (!empty($data['owner_email'])) { - $this->cart->setEmail($data['owner_email']); - } - - // Add the order item. - $this->cartManager->addOrderItem($this->cart, $order_item); + public function postSave(WebformSubmissionInterface $webform_submission, $update = TRUE) { + $state = $webform_submission->getWebform()->getSetting('results_disabled') ? WebformSubmissionInterface::STATE_COMPLETED : $webform_submission->getState(); + if ($this->configuration['states'] && in_array($state, $this->configuration['states'])) { + try { + // Collect data from the handler and the webform submission. + $data = $this->prepareData($webform_submission); + + /** @var \Drupal\commerce_order\OrderStorage $order_item_storage */ + $order_item_storage = $this->entityTypeManager->getStorage('commerce_order_item'); + + // Create the order item. + /** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */ + $order_item = $order_item_storage->create([ + 'type' => $data['order_item_bundle'], + 'title' => $data['title'], + 'unit_price' => $data['price'], + 'overridden_unit_price' => TRUE, + 'quantity' => (string) $data['quantity'], + 'purchased_entity' => $data['product_variation'], + 'commerce_webform_order_submissions' => $webform_submission->id(), + ]); + + // Add non BaseFieldDefinition field values. + foreach ($data['order_item_fields'] as $field => $value) { + $order_item->set($field, $value); + } - $this->cart->save(); + // Create or update the cart. + $order_type_id = $this->orderTypeResolver->resolve($order_item); + $this->cart = $this->cartProvider->getCart($order_type_id, $data['store']); + if (!$this->cart) { + $this->cart = $this->cartProvider->createCart($order_type_id, $data['store']); + } + elseif ($this->configuration['checkout']['empty_cart']) { + $this->cartManager->emptyCart($this->cart); + } - // Remove the add to cart status message. - if ($this->configuration['checkout']['hide_add_to_cart_message']) { - $messages = $this->messenger()->messagesByType('status'); - $this->messenger()->deleteByType('status'); - /** @var \Drupal\Core\Render\Markup $original_message */ - foreach ($messages as $original_message) { - if ($original_message instanceof Markup) { - $message = $original_message->__toString(); - } - else { - $message = $original_message; - } + // Set the owner and the email if the user is not an anonymous user. + if ($this->currentUser->isAuthenticated()) { + $this->cart->setCustomerId($this->currentUser->id()); + $this->cart->setEmail($this->currentUser->getEmail()); + } + // Set the email. + elseif (!empty($data['owner_email'])) { + $this->cart->setEmail($data['owner_email']); + } - /* @see \Drupal\commerce_cart\EventSubscriber\CartEventSubscriber::displayAddToCartMessage */ - if (!is_string($message) || preg_match('/.* added to your cart<\/a>\./', $message) === FALSE) { - $this->messenger()->addMessage($message, 'status'); + // Add the order item to the order, and save the order. + $this->cartManager->addOrderItem($this->cart, $order_item); + $this->cart->save(); + + // Add the reference to the order and save the submission without + // triggering any hooks or handlers. + $webform_submission->set('commerce_webform_order_orders', [$this->cart]); + $webform_submission->resave(); + + // Remove the add to cart status message. + if ($this->configuration['checkout']['hide_add_to_cart_message']) { + $messages = $this->messenger()->messagesByType('status'); + $this->messenger()->deleteByType('status'); + /** @var \Drupal\Core\Render\Markup $original_message */ + foreach ($messages as $original_message) { + if ($original_message instanceof Markup) { + $message = $original_message->__toString(); + } + else { + $message = $original_message; + } + + /* @see \Drupal\commerce_cart\EventSubscriber\CartEventSubscriber::displayAddToCartMessage */ + if (!is_string($message) || preg_match('/.* added to your cart<\/a>\./', $message) === FALSE) { + $this->messenger()->addMessage($message, 'status'); + } } } - } - - // Log message in Drupal's log. - $context = [ - '@form' => $this->getWebform()->label(), - '@title' => $this->label(), - 'link' => $this->getWebform()->toLink($this->t('Edit'), 'handlers')->toString(), - ]; - $this->getLogger()->notice('@form webform created @title order.', $context); - - // Log message in Webform's submission log. - $context = [ - '@order_id' => $this->cart->get('order_id')->getString(), - '@owner_email' => $this->cart->getEmail(), - 'webform_submission' => $webform_submission, - 'handler_id' => $this->getHandlerId(), - 'data' => [], - ]; - if ($this->cart->getEmail() !== NULL) { - $this->getLogger('webform_submission')->notice("Order #@order_id created to '@owner_email'.", $context); - } - else { - $this->getLogger('webform_submission')->notice("Order #@order_id created.", $context); - } - // Debug by displaying create order onscreen. - if ($this->configuration['debug']) { - $t_args = [ - '%order_id' => $this->cart->get('order_id')->getString(), - '%owner_email' => $this->cart->getEmail(), + // Log message in Drupal's log. + $context = [ + '@form' => $this->getWebform()->label(), + '@title' => $this->label(), + 'link' => $this->getWebform()->toLink($this->t('Edit'), 'handlers')->toString(), + ]; + $this->getLogger()->notice('@form webform created @title order.', $context); + + // Log message in Webform's submission log. + $context = [ + '@order_id' => $this->cart->get('order_id')->getString(), + '@owner_email' => $this->cart->getEmail(), + 'webform_submission' => $webform_submission, + 'handler_id' => $this->getHandlerId(), + 'data' => [], ]; if ($this->cart->getEmail() !== NULL) { - $this->messenger()->addWarning($this->t("Order #%order_id created to '%owner_email'.", $t_args), TRUE); + $this->getLogger('webform_submission')->notice("Order #@order_id created to '@owner_email'.", $context); } else { - $this->messenger()->addWarning($this->t("Order #%order_id created.", $t_args), TRUE); + $this->getLogger('webform_submission')->notice("Order #@order_id created.", $context); + } + + // Debug by displaying create order onscreen. + if ($this->configuration['debug']) { + $t_args = [ + '%order_id' => $this->cart->get('order_id')->getString(), + '%owner_email' => $this->cart->getEmail(), + ]; + if ($this->cart->getEmail() !== NULL) { + $this->messenger()->addWarning($this->t("Order #%order_id created to '%owner_email'.", $t_args), TRUE); + } + else { + $this->messenger()->addWarning($this->t("Order #%order_id created.", $t_args), TRUE); + } + $debug_message = $this->buildDebugMessage($this->cart); + $this->messenger()->addWarning($this->renderer->renderPlain($debug_message), TRUE); } - $debug_message = $this->buildDebugMessage($this->cart); - $this->messenger()->addWarning($this->renderer->renderPlain($debug_message), TRUE); } - } - catch (\Exception $exception) { - watchdog_exception('commerce_webform_order', $exception); - $this->messenger()->addWarning($this->t('There was a problem processing your request. Please, try again.'), TRUE); + catch (\Exception $exception) { + watchdog_exception('commerce_webform_order', $exception); + $this->messenger()->addWarning($this->t('There was a problem processing your request. Please, try again.'), TRUE); + } } } diff --git a/templates/webform-handler-commerce-webform-order-summary.html.twig b/templates/webform-handler-commerce-webform-order-summary.html.twig index 2c3221e..f3bea44 100644 --- a/templates/webform-handler-commerce-webform-order-summary.html.twig +++ b/templates/webform-handler-commerce-webform-order-summary.html.twig @@ -11,6 +11,7 @@ */ #} {% if settings.debug %}{{ 'Debugging is enabled'|t }}
{% endif %} +{% if settings.states %}{{ 'The order will be created when the submission is: '|t }} {{ settings.states|join('; ') }}.
{% endif %} {% if settings.checkout.empty_cart %}{{ 'The cart will be emptied.'|t }}
{% endif %} {% if settings.checkout.hide_add_to_cart_message %}{{ 'The add to cart message will be removed.'|t }}
{% endif %} {% if settings.checkout.rediect %}{{ 'User will be redirected to the checkout.'|t }}{% endif %}