bee-8.x-1.1/bee.module

bee.module
<?php

/**
 * @file
 * Contains bee.module features.
 */

use Drupal\bat_booking\Entity\Booking;
use Drupal\Component\Utility\Html;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Render\Markup;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\views\ViewExecutable;
use Drupal\office_hours\OfficeHoursDateHelper;
use Drupal\commerce_price\Price;
use Drupal\commerce_product\Entity\ProductType;
use Drupal\commerce_product\Entity\ProductVariationType;
use Drupal\commerce_product\Entity\Product;
use Drupal\commerce_product\Entity\ProductVariation;
use Drupal\commerce_order\Entity\OrderItemType;
use Drupal\commerce_order\Entity\OrderItemInterface;
use Drupal\commerce_store\Entity\Store;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;

function bee_page_attachments(array &$page) {
}


/**
 * Theme function for FullCalendar.
 */
function bee_preprocess_bat_fullcalendar(&$variables) {

  $data = [];

  // Feb25: get site wide preferences from BAT config page.
  $data['config'] = \Drupal::config('bat_fullcalendar.settings');
  // $data['variables_before'] = $variables;
  $data['requestRouteName'] = \Drupal::requestStack()->getCurrentRequest()->attributes->get('_route');
  $data['eventType'] = $variables['calendar_settings']['fc_settings']['batCalendar'][0]['eventType'];

  if ($data['requestRouteName'] == 'bee.node.availability') {
    if ($data['eventType'] == 'availability_hourly') {
      // // https://fullcalendar.io/docs/timeline-standard-view-demo
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['initialView'] = $data['config']->get('bat_fullcalendar_calendar_edit_hourly');
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['defaultView'] = $variables['calendar_settings']['fc_settings']['batCalendar'][0]['defaultView'];
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['Swe3r'] = "1.1";
      $data['bat_library'] = "bat_fullcalendar/bat-fullcalendar-scheduler";
    }
    else {
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['initialView'] = $data['config']->get('bat_fullcalendar_calendar_edit_daily');
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['defaultView'] = $variables['calendar_settings']['fc_settings']['batCalendar'][0]['initialView'];
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['Swe3r'] = "1.2";
      $data['bat_library'] = "bat_fullcalendar/bat-fullcalendar";
    }
  }
  elseif ($data['requestRouteName'] == 'entity.node.canonical') {
    if ($data['eventType'] == 'availability_hourly') {
      // https://fullcalendar.io/docs/timeline-standard-view-demo
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['initialView'] = $data['config']->get('bat_fullcalendar_calendar_view_hourly');
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['defaultView'] = $variables['calendar_settings']['fc_settings']['batCalendar'][0]['defaultView'];
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['Swe3r'] = "2.1";
      $data['bat_library'] = "bat_fullcalendar/bat-fullcalendar-scheduler";
    }
    else {
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['initialView'] = $data['config']->get('bat_fullcalendar_calendar_view_daily');
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['defaultView'] = $variables['calendar_settings']['fc_settings']['batCalendar'][0]['initialView'];
      $variables['calendar_settings']['fc_settings']['batCalendar'][0]['Swe3r'] = "2.2";
      $data['bat_library'] = "bat_fullcalendar/bat-fullcalendar";
    }
  }
  else {
    // Base library for teaser etc. Do we need more here?
    $data['bat_library'] = "bat_fullcalendar/bat-fullcalendar";
  }

  // Attributes.
  if (!empty($variables['attributes'])) {
    $attributes = $variables['attributes'];
  }
  else {
    $attributes = [
      'id' => Html::getUniqueId('calendar'),
      'class' => [
        'calendar-set',
        'clearfix',
      ],
    ];

    if (isset($variables['calendar_settings']['class']) && !empty($variables['calendar_settings']['class'])) {
      $attributes['class'] = array_merge($attributes['class'], $variables['calendar_settings']['class']);
    }
  }
  // Override default settings with ones coming from BAT.
  $settings = bat_fullcalendar_configure($variables['calendar_settings']['fc_settings']);
  // Apr25: Override settings with UI settings.
  $settings = bat_fullcalendar_ui_settings($settings);
  $settings['batCalendar'][0]['id'] = $attributes['id'];
  $attributes = new Attribute($attributes);
  $variables['#attached'] = [
    'library' => [
      $data['bat_library'],
      // 'core/drupal.ajax',
      // 'core/jquery.form',
    ],
    'drupalSettings' => $settings,
  ];
  $variables['content'] = ['#markup' => '<div' . $attributes->__toString() . '></div>'];
}

/**
 * Implements hook_form_alter().
 */
function bee_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  $data = [];
  $current_path = \Drupal::service('path.current')->getPath();
  $route_name = Url::fromUserInput($current_path)->getRouteName();

  if ($form_id == 'node_type_edit_form' || $form_id == 'node_type_add_form') {

    if (\Drupal::currentUser()->hasPermission('administer bee settings')) {
      $node_type = $form_state->getFormObject()->getEntity();
      assert($node_type instanceof NodeType);

      $bee_settings = $node_type->getThirdPartySetting('bee', 'bee');

      $form['bee'] = [
        '#type' => 'details',
        '#title' => t('BEE'),
        '#group' => 'additional_settings',
        '#tree' => TRUE,
      ];
      $form['bee']['bookable'] = [
        '#type' => 'checkbox',
        '#title' => t('Make this entity type bookable'),
        '#default_value' => $bee_settings['bookable'] ?? 0,
      ];
      $form['bee']['bookable_type'] = [
        '#type' => 'container',
        'radios' => [
          '#type' => 'radios',
          '#title' => t('Booking Length'),
          '#options' => [
            'daily' => t('Daily Bookings (allows bookings of 1 or more full days)'),
            'hourly' => t('Flexible Bookings (allows bookings of any length)'),
          ],
          '#default_value' => $bee_settings['bookable_type'] ?? 'daily',
          '#disabled' => isset($bee_settings['bookable_type']),
        ],
        '#states' => [
          'visible' => [
            ':input[name="bee[bookable]"]' => ['checked' => TRUE],
          ],
        ],
      ];
      $form['bee']['availability'] = [
        '#type' => 'container',
        'radios' => [
          '#type' => 'radios',
          '#title' => t('Availability'),
          '#options' => [
            'available' => t('Generally available (Use for resources that are usually available unless there is a booking. Examples are meeting rooms and equipment)'),
            'unavailable' => t('Periodically available (Use for resources that are only available on certain days or times. Examples are tours and open mic nights)'),
          ],
          '#default_value' => $bee_settings['availability'] ?? 'available',
          '#disabled' => isset($bee_settings['availability']),
        ],
        '#states' => [
          'visible' => [
            ':input[name="bee[bookable]"]' => ['checked' => TRUE],
          ],
        ],
      ];
      $form['bee']['payment'] = [
        '#type' => 'checkbox',
        '#title' => t('Enable payment for bookings'),
        '#default_value' => $bee_settings['payment'] ?? 0,
        '#states' => [
          'visible' => [
            ':input[name="bee[bookable]"]' => ['checked' => TRUE],
          ],
        ],
      ];

      if (!(\Drupal::moduleHandler()->moduleExists('commerce_checkout') &&
            \Drupal::moduleHandler()->moduleExists('commerce_payment'))) {
        $form['bee']['payment']['#disabled'] = TRUE;
        $form['bee']['payment']['#description'] = t('To enable payments for bookings, install and enable the Drupal Commerce checkout and payment modules and configure a Commerce Store.');
      }
      elseif (\Drupal::moduleHandler()->moduleExists('commerce')) {
        if (empty(Store::loadMultiple())) {
          $form['bee']['payment']['#disabled'] = TRUE;
          $form['bee']['payment']['#description'] = t('To enable payments for bookings, install and enable the Drupal Commerce checkout and payment modules and configure a Commerce Store.');
        }
      }

      if (isset($bee_settings['type_id'])) {
        $form['bee']['type_id'] = [
          '#type' => 'hidden',
          '#value' => $bee_settings['type_id'],
        ];
      }

      $form['actions']['submit']['#submit'][] = 'bee_node_type_edit_form_submit';

      $form['#attached']['library'][] = 'bee/bee';
    }
  }
  elseif ($route_name == 'bee.node.availability') {

    $form['#attached']['library'][] = 'bee/bee';
    $form['#attached']['library'][] = 'bat_fullcalendar/bat-fullcalendar-scheduler';
  }

  elseif (preg_match('/^node_.*_edit_form$/', $form_id)) {

    $node = $form_state->getFormObject()->getEntity();
    $node_type = NodeType::load($node->bundle());
    assert($node_type instanceof NodeType);
    $bee_settings = $node_type->getThirdPartySetting('bee', 'bee');

    if (!isset($form['field_open_hours'])) {
      $form['field_open_hours']['#weight'] = 0;
      $form['field_open_hours']['#access'] = FALSE;
    }

    if (isset($bee_settings['bookable']) && $bee_settings['bookable']) {
      $units_count = count($node->get('field_availability_' . $bee_settings['bookable_type'])->getValue());

      $form['bee'] = [
        '#type' => 'details',
        '#title' => t('BEE'),
        '#tree' => TRUE,
        '#prefix' => '<div id="bee-node-wrapper">',
        '#suffix' => '</div>',
        '#weight' => 9000,
      ];

      $form['bee']['units_count'] = [
        '#type' => 'item',
        '#title' => t('Number of referenced units'),
        '#markup' => $units_count,
        '#prefix' => '<div class="container-inline">',
        '#suffix' => '</div>',
        '#weight' => $form['field_open_hours']['#weight'] + 1,
      ];

      $form['bee']['number_units'] = [
        '#type' => 'number',
        '#title' => t('Number of units to add'),
        '#min' => 1,
        '#step' => 1,
        '#weight' => $form['field_open_hours']['#weight'] + 1,
      ];

      $form['bee']['add_more'] = [
        '#type' => 'submit',
        '#value' => t('Add units'),
        '#limit_validation_errors' => [
          ['bee', 'number_units'],
          ['changed'],
        ],
        '#submit' => ['bee_node_add_more_units_submit'],
        '#ajax' => [
          'callback' => 'bee_node_add_more_units_ajax_callback',
          'wrapper' => 'bee-node-wrapper',
        ],
        '#weight' => $form['field_open_hours']['#weight'] + 1,
      ];

      if ($bee_settings['payment']) {
        $form['payments'] = [
          '#type' => 'details',
          '#title' => t('Payments'),
          '#open' => TRUE,
          '#group' => 'bee',
          '#weight' => $form['field_open_hours']['#weight'] + 1,
        ];

        if ($bee_settings['bookable_type'] == 'daily') {
          $form['field_price']['#group'] = 'payments';
          $form['field_price']['widget'][0]['#title'] = t('Price per day');

          $form['field_price_frequency']['#access'] = FALSE;

          $form['field_price']['#prefix'] = '<div class="container-inline">';
          $form['field_price']['#suffix'] = '</div>';
        }
        else {
          $form['field_price']['#group'] = 'payments';
          $form['field_price']['widget'][0]['#title'] = t('Price');

          $form['field_price_frequency']['#group'] = 'payments';
          $form['field_price_frequency']['widget']['#default_value'] = 'hour';
          $form['field_price_frequency']['widget']['#title'] = t('per');
          unset($form['field_price_frequency']['widget']['#options']['_none']);

          $form['field_price']['#prefix'] = '<div class="container-inline">';
          $form['field_price_frequency']['#suffix'] = '</div>';
        }
      }
      else {
        $form['field_price']['#access'] = FALSE;
        $form['field_price_frequency']['#access'] = FALSE;
      }

      if ($bee_settings['bookable_type'] == 'hourly') {
        $form['field_use_open_hours']['#group'] = 'bee';
        $form['field_use_open_hours']['#weight'] = $form['field_open_hours']['#weight'] - 1;

        $form['field_open_hours']['#group'] = 'bee';
        $form['field_open_hours']['#states'] = [
          'visible' => [
            ':input[name="field_use_open_hours[value]"]' => ['checked' => TRUE],
          ],
        ];
      }
      else {
        $form['field_use_open_hours']['#access'] = FALSE;
        $form['field_open_hours']['#access'] = FALSE;
      }
    }
    else {
      if (isset($form['field_use_open_hours'])) {
        $form['field_use_open_hours']['#access'] = FALSE;
      }

      $form['field_open_hours']['#access'] = FALSE;

    }
  }
  elseif (preg_match('/^node_.*_form$/', $form_id)) {

    if (isset($form['field_price'])) {
      $form['field_price']['#access'] = FALSE;
    }

    if (isset($form['field_price_frequency'])) {
      $form['field_price_frequency']['#access'] = FALSE;
    }

    if (isset($form['field_use_open_hours'])) {
      $form['field_use_open_hours']['#access'] = FALSE;
    }

    if (isset($form['field_open_hours'])) {
      $form['field_open_hours']['#access'] = FALSE;
    }
  }
}

/**
 * Submit function for the "Add units" button.
 */
function bee_node_add_more_units_submit($form, FormStateInterface $form_state) {
  $number_units = $form_state->getValue(['bee', 'number_units']);

  if (is_numeric($number_units) && $number_units > 0) {
    $node = $form_state->getFormObject()->getEntity();
    $node_type = NodeType::load($node->bundle());
    assert($node_type instanceof NodeType);
    $bee_settings = $node_type->getThirdPartySetting('bee', 'bee');

    $units_ids = $node->get('field_availability_' . $bee_settings['bookable_type'])->getValue();

    for ($i = 0; $i < $number_units; $i++) {
      $index = count($units_ids) + 1;

      $bat_unit = bat_unit_create(
        [
          'name' => mb_substr($node->label(), 0, 49 - mb_strlen($index)) . ' ' . $index,
          'type' => 'default',
          'unit_type_id' => $bee_settings['type_id'],
        ]
      );
      bat_unit_save($bat_unit);

      $units_ids[]['target_id'] = $bat_unit->id();
    }

    $node->set('field_availability_' . $bee_settings['bookable_type'], $units_ids);
    $node->changed_time = $form_state->getValue('changed');
    $node->setNewRevision(FALSE);
    $node->save();

    $units_count = count($node->get('field_availability_' . $bee_settings['bookable_type'])->getValue());

    $form['bee']['units_count']['#markup'] = $units_count;

    $form['bee']['number_units']['#value'] = '';

    \Drupal::messenger()->addMessage(t('@number Units added.', ['@number' => $number_units]));
  }
  elseif ($number_units === '') {
    \Drupal::messenger()->addError(t('Number of units is required.'));
  }
  else {
    \Drupal::messenger()->addError(t('Number of units must be a positive integer.'));
  }

  $form['bee']['#open'] = TRUE;
}

/**
 * Ajax callback for the "Add units" button.
 */
function bee_node_add_more_units_ajax_callback($form, FormStateInterface $form_state) {
  return $form['bee'];
}

/**
 * Custom submit function for the node_type_edit_form and node_type_add_form.
 */
function bee_node_type_edit_form_submit(array &$form, FormStateInterface $form_state) {
  $node_type = $form_state->getFormObject()->getEntity();
  assert($node_type instanceof NodeType);

  $bee_settings = $form_state->getValue('bee');

  $bee_settings['bookable_type'] = $bee_settings['bookable_type']['radios'];
  $bee_settings['availability'] = $bee_settings['availability']['radios'];
  $bee_settings['payment_default_value'] = $form['bee']['payment']['#default_value'];

  bee_set_bee_to_node($node_type, $bee_settings);
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function bee_node_presave(EntityInterface $node) {
  if (isset($node->changed_time)) {
    $node->setChangedTime($node->changed_time);
  }
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 */
function bee_node_insert(EntityInterface $node) {
  $node_type = NodeType::load($node->bundle());
  assert($node_type instanceof NodeType);
  $bee_settings = $node_type->getThirdPartySetting('bee', 'bee');

  if (isset($bee_settings['bookable']) && $bee_settings['bookable']) {
    if ($bee_settings['payment']) {
      $product = bee_create_node_product($node);
      $node->set('field_product', $product->id());
    }

    $bat_unit = bat_unit_create(
      [
        'name' => mb_substr($node->label(), 0, 48) . ' 1',
        'type' => 'default',
        'unit_type_id' => $bee_settings['type_id'],
      ]
    );
    bat_unit_save($bat_unit);

    $node->set('field_availability_' . $bee_settings['bookable_type'], $bat_unit->id());
    $node->setNewRevision(FALSE);
    $node->save();
  }
}

/**
 * Implements hook_ENTITY_TYPE_delete().
 */
function bee_node_delete(EntityInterface $node) {
  $node_type = NodeType::load($node->bundle());
  assert($node_type instanceof NodeType);
  $bee_settings = $node_type->getThirdPartySetting('bee', 'bee');

  if (!empty($bee_settings['bookable_type']) && $node->hasField('field_availability_' . $bee_settings['bookable_type'])) {
    if ($bat_unit = $node->get('field_availability_' . $bee_settings['bookable_type'])->entity) {
      bat_unit_delete($bat_unit);
    }

    if ($bee_settings['payment']) {
      if ($product = $node->get('field_product')->entity) {
        $product->delete();
      }
    }
  }
}

/**
 * Implements hook_ENTITY_TYPE_delete().
 */
function bee_commerce_order_item_delete(OrderItemInterface $order_item) {
  if ($order_item->bundle() == 'bee') {
    if ($booking = $order_item->get('field_booking')->entity) {
      $booking->delete();
    }
  }
}

/**
 * Implements hook_theme_registry_alter().
 */
function bee_theme_registry_alter(&$theme_registry) {
  $theme_registry['field__node__field_availability_hourly'] = [
    'template' => 'field-availability-hourly',
    'path' => \Drupal::service('extension.list.module')->getPath('bee') . '/templates',
    'render element' => 'element',
    'base hook' => 'field',
    'type' => 'module',
    'theme path' => \Drupal::service('extension.list.module')->getPath('bee'),
    'preprocess functions' => [
      'template_preprocess',
      'template_preprocess_field',
    ],
  ];

  $theme_registry['field__node__field_availability_daily'] = [
    'template' => 'field-availability-daily',
    'path' => \Drupal::service('extension.list.module')->getPath('bee') . '/templates',
    'render element' => 'element',
    'base hook' => 'field',
    'type' => 'module',
    'theme path' => \Drupal::service('extension.list.module')->getPath('bee'),
    'preprocess functions' => [
      'template_preprocess',
      'template_preprocess_field',
    ],
  ];
}

/**
 * Implements hook_entity_view_display_alter().
 */
function bee_entity_view_display_alter(EntityViewDisplayInterface $display, $context) {
  if ($context['entity_type'] == 'node') {
    if ($node = \Drupal::routeMatch()->getParameter('node')) {
      if ($display->getComponent('field_open_hours')) {
        if (!($node->get('field_use_open_hours')->value)) {
          $display->removeComponent('field_open_hours');
        }
      }
    }
  }
}

/**
 * Implements hook_entity_view_alter().
 */
function bee_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {

  if ($entity->getEntityTypeId() == 'bat_unit') {
    if ($display->id() == 'bat_unit.default.daily_calendar' || $display->id() == 'bat_unit.default.hourly_calendar') {
      $bat_type = $entity->get('unit_type_id')->entity;

      $unit_type = $bat_type->id();

      $node = $build['#bat_unit']->_referringItem->getEntity();

      $units_ids = [];
      foreach ($node->get('field_availability_' . $bat_type->bundle()) as $unit) {
        if ($unit->entity) {
          $units_ids[] = $unit->entity->id();
        }
      }

      if ($bat_type->bundle() == 'daily') {
        $event_type = 'availability_daily';
        $event_granularity = 'bat_daily';

        $fc_settings = [
          'batCalendar' => [
            [
              'background' => 'hide-book',
              // See https://www.drupal.org/project/bat/issues/3515537
              'defaultView' => 'month',
              'eventType' => $event_type,
              'eventGranularity' => $event_granularity,
              'editable' => FALSE,
              'headerLeft' => 'today',
              'headerCenter' => 'title',
              'headerRight' => 'prev, next',
              'selectable' => FALSE,
              'unitType' => $unit_type,
              'unitIds' => implode(',', $units_ids),
              'views' => 'month',
              'test_da_bee' => '2w3',
            ],
          ],
        ];
      }
      else {
        if ($node->get('field_use_open_hours')) {
          $business_hours = [];

          foreach ($node->get('field_open_hours')->getValue() as $value) {
            $business_hours[] = [
              'dow' => [$value['day']],
              'start' => OfficeHoursDateHelper::format($value['starthours'], 'H:i'),
              'end' => OfficeHoursDateHelper::format($value['endhours'], 'H:i'),
            ];
          }
        }
        else {
          $business_hours = [
            'start' => '00:00',
            'end' => '24:00',
            'dow' => [0, 1, 2, 3, 4, 5, 6],
          ];
        }

        $event_type = 'availability_hourly';
        $event_granularity = 'bat_hourly';

        // See https://www.drupal.org/project/bat/issues/3515537.
        // view
        $fc_settings = [
          'batCalendar' => [
            [
              'background' => 'hide-book',
              'businessHours' => $business_hours,
              // See https://www.drupal.org/project/bat/issues/3515537
              'defaultView' => 'timelineDay',
              'eventType' => $event_type,
              'eventGranularity' => $event_granularity,
              'editable' => FALSE,
              'headerLeft' => 'today',
              'headerCenter' => 'title',
              'headerRight' => 'prev, next',
              'nid' => $node->Id(),
              'selectable' => FALSE,
              'unitType' => $unit_type,
              'unitIds' => implode(',', $units_ids),
              'views' => 'timelineDay',
              'viewsTimelineDaySlotDuration' => '01:00',
              'bee_call' => '2w3w',
            ],
          ],
        ];
      }

      $calendar_settings['fc_settings'] = $fc_settings;
      $calendar_settings['calendar_id'] = 'fullcalendar-scheduler';

      $render_array = [
        'calendar' => [
          '#theme' => 'bat_fullcalendar',
          '#calendar_settings' => $calendar_settings,
          // 'bat_fullcalendar/bat-fullcalendar-scheduler'
          '#attached' => ['library' => ['bat_event_ui/bat_event_ui']],
        ],
      ];

      $build = [
        '#markup' => \Drupal::service('renderer')->render($render_array),
      ];
    }
  }
}

/**
 * Implements hook_bat_api_events_index_calendar_alter().
 */
function bee_bat_api_events_index_calendar_alter(&$events, $context) {

  $data = [];

  foreach ($events as $id => $event) {

    // @todo We may need here nid for current event.
    if (isset($event['type']) && ($event['type'] == 'availability_daily' || $event['type'] == 'availability_hourly')) {
      unset($events[$id]['rendering']);
      if ($event['blocking']) {

        if ($event['type'] == 'availability_daily') {
          $state = bat_event_load_state_by_machine_name('bee_daily_not_available');
        }
        else {
          $state = bat_event_load_state_by_machine_name('bee_hourly_not_available');
        }

        $events[$id]['color'] = $state->getColor();
        $events[$id]['title'] = $state->getCalendarLabel();
      }

      $start_date = new DateTime($event['start']);
      $end_date = new DateTime($event['end']);

      if ($start_date->format('Y-m-d') != $end_date->format('Y-m-d')) {
        $events[$id]['end'] = $end_date->add(new DateInterval('P1D'))->format('Y-m-d') . 'T00:00:00';
      }
    }
  }
}

/**
 * Implements hook_views_pre_render().
 */
function bee_views_pre_render(ViewExecutable $view) {
  if ($view->id() == 'commerce_order_item_table') {
    foreach ($view->result as $id => $result) {
      if ($result->_entity->bundle() == 'bee') {
        if (($booking = $result->_entity->get('field_booking')->entity) &&
            ($node = $result->_entity->get('field_node')->entity)) {
          $url = Url::fromRoute('entity.node.canonical', ['node' => $node->id()]);
          $link = Link::fromTextAndUrl($node->label(), $url)->toString();
          $start_date = $booking->get('booking_start_date')->value;
          $end_date = $booking->get('booking_end_date')->value;
          $title = Markup::create('Booking for ' . $link . ' from ' . $start_date . ' to ' . $end_date);
          $view->result[$id]->_entity->set('title', $title);
        }
      }
    }
  }
}

/**
 * Add "Availability" field to the node type.
 *
 * @param string $field_name
 *   A string.
 * @param \Drupal\node\Entity\NodeType $node_type
 *   A drupal node_type object.
 */
function bee_add_availability_field($field_name, NodeType $node_type) {
  $field_storage = FieldStorageConfig::loadByName('node', $field_name);
  $field = FieldConfig::loadByName('node', $node_type->id(), $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'node',
      'type' => 'entity_reference',
      'cardinality' => -1,
      'locked' => 1,
      'settings' => [
        'target_type' => 'bat_unit',
      ],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'entity_type' => 'node',
      'label' => 'Availability',
      'bundle' => $node_type->id(),
      'required' => FALSE,
      'settings' => [
        'handler' => 'default',
        'handler_settings' => [],
      ],
    ]);
    $field->save();
  }
}

/**
 * Add "Open Hours" field to the node type.
 *
 * @param string $field_name
 *   A string.
 * @param \Drupal\node\Entity\NodeType $node_type
 *   A drupal node_type object.
 */
function bee_add_open_hours_field($field_name, NodeType $node_type) {
  $field_storage = FieldStorageConfig::loadByName('node', $field_name);
  $field = FieldConfig::loadByName('node', $node_type->id(), $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'node',
      'type' => 'office_hours',
      'cardinality' => -1,
      'locked' => 1,
      'settings' => [
        'cardinality_per_day' => 2,
        'time_format' => 'G',
        'element_type' => 'office_hours_datetime',
        'increment' => 60,
        'comment' => FALSE,
        'valhrs' => FALSE,
        'limit_start' => '',
        'limit_end' => '',
      ],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'entity_type' => 'node',
      'label' => 'Open Hours',
      'bundle' => $node_type->id(),
      'required' => FALSE,
      'settings' => [
        'handler' => 'default',
        'handler_settings' => [],
      ],
    ]);
    $field->save();

    $form_display = \Drupal::entityTypeManager()->getStorage('entity_form_display')->load('node.' . $node_type->id() . '.default');
    if ($form_display !== NULL) {
      $form_display->setComponent($field_name, [
        'type' => 'office_hours_default',
        'weight' => 3,
      ]);
      $form_display->save();
    }

    $view_display = \Drupal::entityTypeManager()->getStorage('entity_view_display')->load('node.' . $node_type->id() . '.default');
    if ($view_display !== NULL) {
      $view_display->setComponent($field_name, [
        'type' => 'office_hours_table',
        'region' => 'content',
        'label' => 'above',
        'settings' => [],
      ]);
      $view_display->save();
    }
  }
}

/**
 * Add "Set Open Hours" field to the node type.
 *
 * @param string $field_name
 *   A string.
 * @param \Drupal\node\Entity\NodeType $node_type
 *   A drupal node_type.
 */
function bee_add_use_open_hours_field($field_name, NodeType $node_type) {
  $field_storage = FieldStorageConfig::loadByName('node', $field_name);
  $field = FieldConfig::loadByName('node', $node_type->id(), $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'node',
      'type' => 'boolean',
      'cardinality' => 1,
      'locked' => 1,
      'settings' => [],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'entity_type' => 'node',
      'label' => 'Set Open Hours',
      'bundle' => $node_type->id(),
      'required' => FALSE,
      'settings' => [
        'handler' => 'default',
        'handler_settings' => [],
      ],
    ]);
    $field->save();

    $form_display = \Drupal::entityTypeManager()->getStorage('entity_form_display')->load('node.' . $node_type->id() . '.default');
    if ($form_display !== NULL) {
      $form_display->setComponent($field_name, [
        'type' => 'boolean_checkbox',
        'weight' => 2,
      ]);
      $form_display->save();
    }
  }
}

/**
 * Add "Product" field to the node type.
 *
 * @param string $field_name
 *   A string.
 * @param \Drupal\node\Entity\NodeType $node_type
 *   A drupal node_type object.
 */
function bee_add_product_reference_field($field_name, NodeType $node_type) {
  $field_storage = FieldStorageConfig::loadByName('node', $field_name);
  $field = FieldConfig::loadByName('node', $node_type->id(), $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'node',
      'type' => 'entity_reference',
      'cardinality' => 1,
      'locked' => 1,
      'settings' => [
        'target_type' => 'commerce_product',
      ],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'entity_type' => 'node',
      'label' => 'Product',
      'bundle' => $node_type->id(),
      'required' => FALSE,
      'settings' => [
        'handler' => 'default:commerce_product',
        'handler_settings' => [
          'target_bundles' => [
            'bee_' . $node_type->id() => 'bee_' . $node_type->id(),
          ],
        ],
      ],
    ]);
    $field->save();
  }
}

/**
 * Add "Price" field to the node type.
 *
 * @param string $field_name
 *   A string.
 * @param \Drupal\node\Entity\NodeType $node_type
 *   A drupal node_type object.
 */
function bee_add_price_field($field_name, NodeType $node_type) {
  $field_storage = FieldStorageConfig::loadByName('node', $field_name);
  $field = FieldConfig::loadByName('node', $node_type->id(), $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'node',
      'type' => 'commerce_price',
      'cardinality' => 1,
      'locked' => 1,
      'settings' => [],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $store_storage = \Drupal::entityTypeManager()->getStorage('commerce_store');
    $default_store = $store_storage->loadDefault();

    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'entity_type' => 'node',
      'label' => 'Price',
      'bundle' => $node_type->id(),
      'required' => TRUE,
      'default_value' => [
        'number' => 0,
        'currency_code' => $default_store->getDefaultCurrencyCode(),
      ],
      'settings' => [],
    ]);
    $field->save();

    $form_display = \Drupal::entityTypeManager()->getStorage('entity_form_display')->load('node.' . $node_type->id() . '.default');
    if ($form_display !== NULL) {
      $form_display->setComponent($field_name, [
        'type' => 'commerce_price_default',
        'weight' => 3,
      ]);
      $form_display->save();
    }
  }
}

/**
 * Add "Price frequency" field to the node type.
 *
 * @param string $field_name
 *   A string.
 * @param \Drupal\node\Entity\NodeType $node_type
 *   A drupal node object.
 */
function bee_add_price_frequency_field(string $field_name, NodeType $node_type) {
  $field_storage = FieldStorageConfig::loadByName('node', $field_name);
  $field = FieldConfig::loadByName('node', $node_type->id(), $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'node',
      'type' => 'list_string',
      'cardinality' => 1,
      'locked' => 1,
      'settings' => [
        'allowed_values' => [
          'hour' => 'Hour',
          'minute' => 'Minute',
        ],
      ],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'entity_type' => 'node',
      'label' => 'Price frequency',
      'bundle' => $node_type->id(),
      'required' => FALSE,
      'settings' => [],
    ]);
    $field->save();

    $form_display = \Drupal::entityTypeManager()->getStorage('entity_form_display')->load('node.' . $node_type->id() . '.default');
    if ($form_display !== NULL) {
      $form_display->setComponent($field_name, [
        'type' => 'options_select',
        'weight' => 4,
      ]);
      $form_display->save();
    }
  }
}

/**
 * Create "Product variation" type for BEE.
 */
function bee_create_bee_product_variation_type() {
  if (ProductVariationType::load('bee') === NULL) {
    $variation_type = ProductVariationType::create([
      'id' => 'bee',
      'label' => 'BEE',
      'orderItemType' => 'default',
      'generateTitle' => TRUE,
    ]);
    $variation_type->save();

    $view_display = \Drupal::entityTypeManager()->getStorage('entity_view_display')->load('commerce_product_variation.bee.default');
    if (!$view_display) {
      $view_display = EntityViewDisplay::create([
        'targetEntityType' => 'commerce_product_variation',
        'bundle' => 'bee',
        'mode' => 'default',
        'status' => TRUE,
      ]);
    }
    $view_display->setComponent('price', ['type' => 'commerce_price_calculated']);
    $view_display->save();
  }
}

/**
 * Create a "Product" type for each node type in BEE.
 *
 * @param \Drupal\node\Entity\NodeType $node_type
 *   A drupal node type object.
 */
function bee_create_node_product_type(NodeType $node_type) {
  $id = 'bee_' . $node_type->id();

  if (ProductType::load($id) === NULL) {
    $product_type = ProductType::create([
      'id' => $id,
      'label' => $node_type->label(),
      'variationType' => 'bee',
    ]);
    $product_type->save();
  }
}

/**
 * Create "Order item" type for BEE.
 */
function bee_create_bee_order_item_type() {
  $id = 'bee';

  if (OrderItemType::load($id) === NULL) {
    OrderItemType::create([
      'id' => $id,
      'label' => 'BEE',
      'purchasableEntityType' => 'commerce_product_variation',
      'orderType' => 'default',
    ])->save();

    $view_display = \Drupal::entityTypeManager()->getStorage('entity_view_display')->load('commerce_order_item.bee.default');
    if (!$view_display) {
      $view_display = EntityViewDisplay::create([
        'targetEntityType' => 'commerce_order_item',
        'bundle' => 'bee',
        'mode' => 'default',
        'status' => TRUE,
      ]);
      $view_display->setComponent('total_price', [
        'type' => 'commerce_price_default',
        'region' => 'content',
        'label' => 'above',
        'settings' => [
          'strip_trailing_zeroes' => FALSE,
          'display_currency_code' => FALSE,
        ],
      ]);
      $view_display->setComponent('purchased_entity', [
        'type' => 'entity_reference_entity_view',
        'region' => 'content',
        'label' => 'above',
        'settings' => [
          'view_mode' => 'default',
          'link' => FALSE,
        ],
      ]);
      $view_display->setComponent('quantity', [
        'type' => 'number_decimal',
        'region' => 'content',
        'label' => 'above',
        'settings' => [
          'thousand_separator' => '',
          'decimal_separator' => '.',
          'scale' => 2,
          'prefix_suffix' => TRUE,
        ],
      ]);
      $view_display->setComponent('unit_price', [
        'type' => 'commerce_price_default',
        'region' => 'content',
        'label' => 'above',
        'settings' => [
          'strip_trailing_zeroes' => FALSE,
          'display_currency_code' => FALSE,
        ],
      ]);
      $view_display->save();
    }
  }

  $field_name = 'field_booking';

  $field_storage = FieldStorageConfig::loadByName('commerce_order_item', $field_name);
  $field = FieldConfig::loadByName('commerce_order_item', 'bee', $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'commerce_order_item',
      'type' => 'entity_reference',
      'cardinality' => 1,
      'locked' => 1,
      'settings' => [
        'target_type' => 'bat_booking',
      ],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'entity_type' => 'commerce_order_item',
      'label' => 'Booking',
      'bundle' => 'bee',
      'required' => FALSE,
      'settings' => [
        'handler' => 'default:bat_booking',
        'handler_settings' => [
          'target_bundles' => [
            'bee' => 'bee',
          ],
        ],
      ],
    ]);
    $field->save();
  }

  $field_name = 'field_node';

  $field_storage = FieldStorageConfig::loadByName('commerce_order_item', $field_name);
  $field = FieldConfig::loadByName('commerce_order_item', 'bee', $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'commerce_order_item',
      'type' => 'entity_reference',
      'cardinality' => 1,
      'locked' => 1,
      'settings' => [
        'target_type' => 'node',
      ],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'entity_type' => 'commerce_order_item',
      'label' => 'Node',
      'bundle' => 'bee',
      'required' => FALSE,
      'settings' => [
        'handler' => 'default:node',
        'handler_settings' => [
          'target_bundles' => [],
        ],
      ],
    ]);
    $field->save();
  }
}

/**
 * Create "Booking" type for BEE.
 */
function bee_create_bee_booking_type() {
  $id = 'bee';

  if (bat_booking_type_load($id) === NULL) {
    $booking_type = bat_booking_type_create([
      'name' => 'BEE',
      'type' => $id,
    ]);
    $booking_type->save();

    bee_set_booking_event_reference_field_cardinality();
    bee_create_booking_capacity_field();
    bee_create_booking_repeat_frequency_field();
    bee_create_booking_repeat_until_field();
    bee_create_booking_event_series_reference_field();
  }
}

/**
 * Set cardinality as unlimited for the "booking_event_reference" field.
 */
function bee_set_booking_event_reference_field_cardinality() {
  $field_storage = FieldStorageConfig::loadByName('bat_booking', 'booking_event_reference');
  $field_storage->setCardinality(-1);
  $field_storage->save();
}

/**
 * Add booking "Repeat frequency" field.
 */
function bee_create_booking_repeat_frequency_field() {
  $field_name = 'booking_repeat_frequency';

  $field_storage = FieldStorageConfig::loadByName('bat_booking', $field_name);
  $field = FieldConfig::loadByName('bat_booking', 'bee', $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'bat_booking',
      'type' => 'list_string',
      'cardinality' => 1,
      'locked' => 1,
      'settings' => [
        'allowed_values' => [
          'daily' => 'Daily',
          'weekly' => 'Weekly',
          'monthly' => 'Monthly',
        ],
        'allowed_values_function' => '',
      ],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'entity_type' => 'bat_booking',
      'label' => 'Repeat frequency',
      'bundle' => 'bee',
      'required' => FALSE,
    ]);
    $field->save();
  }
}

/**
 * Add booking "Repeat until" field.
 */
function bee_create_booking_repeat_until_field() {
  $field_name = 'booking_repeat_until';

  $field_storage = FieldStorageConfig::loadByName('bat_booking', $field_name);
  $field = FieldConfig::loadByName('bat_booking', 'bee', $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'bat_booking',
      'type' => 'datetime',
      'cardinality' => 1,
      'locked' => 1,
      'settings' => [
        'datetime_type' => 'date',
      ],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'entity_type' => 'bat_booking',
      'label' => 'Repeat until',
      'bundle' => 'bee',
      'required' => FALSE,
    ]);
    $field->save();
  }
}

/**
 * Add booking "Capacity" field.
 *
 *  Description: Capacity can be seats or persons involved in the same booking.
 *
 *  @todo Verify description.
 */
function bee_create_booking_capacity_field() {
  $field_name = 'booking_capacity';

  $field_storage = FieldStorageConfig::loadByName('bat_booking', $field_name);
  $field = FieldConfig::loadByName('bat_booking', 'bee', $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'bat_booking',
      'type' => 'integer',
      'cardinality' => 1,
      'locked' => 1,
      'settings' => [
        'unsigned' => TRUE,
        'size' => 'normal',
      ],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'entity_type' => 'bat_booking',
      'label' => 'Capacity',
      'bundle' => 'bee',
      'required' => FALSE,
      'settings' => [
        'min' => NULL,
        'max' => NULL,
        'prefix' => '',
        'suffix' => '',
      ],
    ]);
    $field->save();
  }
}

/**
 * Add booking "Event series" reference field.
 */
function bee_create_booking_event_series_reference_field() {
  $field_name = 'booking_event_series_reference';

  $field_storage = FieldStorageConfig::loadByName('bat_booking', $field_name);
  $field = FieldConfig::loadByName('bat_booking', 'bee', $field_name);

  if (empty($field_storage)) {
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'bat_booking',
      'type' => 'entity_reference',
      'cardinality' => 1,
      'locked' => 1,
      'settings' => [
        'target_type' => 'bat_event_series',
      ],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'bat_booking',
      'label' => 'Event series',
      'bundle' => 'bee',
      'required' => FALSE,
    ]);
    $field->save();
  }
}

/**
 * Create a Product instance for this node.
 */
function bee_create_node_product($node) {
  $store_storage = \Drupal::entityTypeManager()->getStorage('commerce_store');
  $default_store = $store_storage->loadDefault();

  $variation = ProductVariation::create([
    'type' => 'bee',
    'sku' => 'bee_' . $node->bundle() . '_' . $node->id(),
    'price' => [
      'number' => 0,
      'currency_code' => $default_store->getDefaultCurrencyCode(),
    ],
  ]);
  $variation->save();
  $product = Product::create([
    'type' => 'bee_' . $node->bundle(),
    'title' => $node->label(),
    'variations' => [$variation],
    'stores' => Store::loadMultiple(),
  ]);
  $product->save();

  return $product;
}

/**
 * Add fields to event serie type.
 */
function bee_event_series_types_add_fields() {
  bat_event_series_type_add_event_dates_field('availability_daily');
  bat_event_series_type_add_target_entity_field('availability_daily', 'bat_unit');
  bat_event_series_type_add_event_state_reference('availability_daily');
  bat_event_series_type_add_event_dates_field('availability_hourly');
  bat_event_series_type_add_target_entity_field('availability_hourly', 'bat_unit');
  bat_event_series_type_add_event_state_reference('availability_hourly');
}

/**
 * Implements template_preprocess_bat_event_series().
 */
function bee_preprocess_bat_event_series(array &$variables) {
  // Fetch Event series Entity Object.
  $event_series = $variables['elements']['#bat_event_series'];

  if (!in_array($event_series->bundle(), [
    'availability_daily',
    'availability_hourly',
  ])) {
    return;
  }

  $bat_unit = $event_series->get('event_bat_unit_reference')->entity;

  $node_storage = \Drupal::entityTypeManager()->getStorage('node');

  $query = \Drupal::entityQuery('node')->accessCheck(FALSE);
  if ($event_series->bundle() == 'availability_daily') {
    $query->condition('field_availability_daily', $bat_unit->id());
  }
  else {
    $query->condition('field_availability_hourly', $bat_unit->id());
  }

  $query->accessCheck(FALSE);

  $nids = $query->execute();

  $node = $node_storage->load(reset($nids));

  $variables['content']['add_reservation'] = [
    '#theme' => 'menu_local_action',
    '#link' => [
      'title' => t('Add reservation'),
      'url' => Url::fromRoute('bee.bat_event_series.add_reservation', [
        'node' => $node->id(),
        'bat_event_series' => $event_series->id(),
      ]),
    ],
    '#prefix' => '<div class="action-links">',
    '#suffix' => '</div>',
    '#weight' => -100,
  ];
}

/**
 * Get unit price.
 *
 * @param \Drupal\node\Entity\Node $node
 *   A node object.
 * @param \Drupal\bat_booking\Entity\Booking $booking
 *   A Booking object.
 * @param DateTime $start_date
 *   A drupal date object.
 * @param DateTime $end_date
 *   A drupal date object.
 *
 * @return \Drupal\commerce_price\Price
 *   A Commerce price object.
 */
function bee_get_unit_price(Node $node, Booking $booking, DateTime $start_date, DateTime $end_date) {
  $node_type = NodeType::load($node->bundle());
  assert($node_type instanceof NodeType);
  $bee_settings = $node_type->getThirdPartySetting('bee', 'bee');

  $interval = $start_date->diff($end_date);

  $reservation_context = [
    'booking' => $booking,
    'node' => $node,
  ];

  $base_price = $node->get('field_price')->number;
  $currency_code = $node->get('field_price')->currency_code;

  if ($bee_settings['bookable_type'] == 'daily') {
    $days = $interval->days;
    $amount = number_format($base_price * $days, 2, '.', '');
  }
  else {
    $field_price_frequency = $node->get('field_price_frequency')->value;

    if ($field_price_frequency == 'hour') {
      $hours = ($interval->days * 24) + $interval->h;
      $amount = number_format($base_price * $hours, 2, '.', '');
    }
    else {
      $minutes = ($interval->days * 24 * 60) + ($interval->h * 60) + $interval->i;
      $amount = number_format($base_price * $minutes, 2, '.', '');
    }
  }

  $price = new Price($amount, $currency_code);

  \Drupal::moduleHandler()->alter('bee_reservation_price', $price, $reservation_context);

  return $price;
}

/**
 * Validate bee settings on nodes.
 *
 * @param \Drupal\node\Entity\NodeType $node_type
 *   A drupal node_type object.
 *
 * @return array
 *   An array.
 */
function bee_validate_thirdpartysetting(NodeType $node_type) {

  $bee_settings = $node_type->getThirdPartySetting('bee', 'bee');

  if (!isset($bee_settings)) {
    \Drupal::messenger()->addwarning(t('@nodetype content type has no valid BEE setting.', ['@nodetype' => $node_type->Id()]));
    $url = URL::fromUserInput('/admin/structure/types/manage/' . $node_type->Id());
    $link = Link::fromTextAndUrl(t('Update BEE  settings'), $url);
    // @todo Add some action.
  }
  return $bee_settings;

}

/**
 * Add BEE features to a given instance of NodeType.
 *
 * @param string $node_type
 *   The node type.
 * @param array $bee_settings
 *   An associative array containing:
 *   - bookable: integer.
 *   - bookable_type: string.
 *   - availability: string.
 *   - payment: integer.
 *   - payment_default_value: integer.
 */
function bee_set_bee_to_node($node_type, array $bee_settings) {

  if ($bee_settings['bookable']) {
    bee_add_use_open_hours_field('field_use_open_hours', $node_type);
    bee_add_open_hours_field('field_open_hours', $node_type);

    bee_add_availability_field('field_availability_' . $bee_settings['bookable_type'], $node_type);

    $view_display = \Drupal::entityTypeManager()->getStorage('entity_view_display')->load('node.' . $node_type->id() . '.default');
    if ($view_display !== NULL) {
      $view_display->setComponent('field_availability_' . $bee_settings['bookable_type'], [
        'type' => 'entity_reference_entity_view',
        'region' => 'content',
        'label' => 'above',
        'settings' => [
          'view_mode' => $bee_settings['bookable_type'] . '_calendar',
        ],
      ]);
      $view_display->save();
    }

    if (!isset($bee_settings['type_id'])) {
      $bat_type = bat_unit_type_create(
        [
          'name' => $node_type->label(),
          'type' => $bee_settings['bookable_type'],
        ]
      );

      if ($bee_settings['availability'] == 'available') {
        $state = bat_event_load_state_by_machine_name('bee_' . $bee_settings['bookable_type'] . '_available');
      }
      else {
        $state = bat_event_load_state_by_machine_name('bee_' . $bee_settings['bookable_type'] . '_not_available');
      }

      $bat_type->set('field_availability_' . $bee_settings['bookable_type'], $state->id());

      bat_unit_type_save($bat_type);

      $bee_settings['type_id'] = $bat_type->id();
    }

    if ($bee_settings['payment']) {
      bee_create_bee_product_variation_type();
      bee_create_bee_order_item_type();
      bee_create_bee_booking_type();

      bee_create_node_product_type($node_type);

      bee_add_product_reference_field('field_product', $node_type);
      bee_add_price_field('field_price', $node_type);
      bee_add_price_frequency_field('field_price_frequency', $node_type);

      if (!$bee_settings['payment_default_value']) {
        $node_storage = \Drupal::entityTypeManager()->getStorage('node');

        $query = \Drupal::entityQuery('node')
          ->accessCheck(FALSE)
          ->condition('type', $node_type->id());

        $nids = $query->execute();
        foreach ($node_storage->loadMultiple($nids) as $node) {
          if (!$node->get('field_product')->entity) {
            $product = bee_create_node_product($node);

            $node->set('field_product', $product->id());
            $node->save();
          }
        }
      }
    }

    $node_type->setThirdPartySetting('bee', 'bee', $bee_settings)->save();
  }
  else {
    if (isset($bee_settings['type_id'])) {
      $node_storage = \Drupal::entityTypeManager()->getStorage('node');

      $query = \Drupal::entityQuery('node')
        ->accessCheck(FALSE)
        ->condition('type', $node_type->id());

      $nids = $query->execute();
      foreach ($node_storage->loadMultiple($nids) as $node) {
        if ($node->hasField('field_availability_' . $bee_settings['bookable_type'])) {
          if ($bat_unit = $node->get('field_availability_' . $bee_settings['bookable_type'])->entity) {
            bat_unit_delete($bat_unit);
          }
        }
      }

      $bat_type = bat_unit_type_load($bee_settings['type_id']);
      $bat_type->delete();
    }

    $node_type->unsetThirdPartySetting('bee', 'bee')->save();
  }
}

/**
 * Create require bat states.
 */
function bee_create_require_bat_states() {

  $states = [
    'bee_daily_available' => [
      'name' => 'Available',
      'color' => '#42f649',
      'calendar_label' => 'AV',
      'blocking' => 0,
      'machine_name' => 'bee_daily_available',
      'event_type' => 'availability_daily',
    ],
    'bee_daily_not_available' => [
      'name' => 'Not available',
      'color' => '#f04b4b',
      'calendar_label' => 'N/A',
      'blocking' => 0,
      'machine_name' => 'bee_daily_not_available',
      'event_type' => 'availability_daily',
    ],
    'bee_daily_booked' => [
      'name' => 'Booked',
      'color' => '#4b3cea',
      'calendar_label' => 'BOOK',
      'blocking' => 1,
      'machine_name' => 'bee_daily_booked',
      'event_type' => 'availability_daily',
    ],
    'bee_hourly_available' => [
      'name' => 'Available',
      'color' => '#42f649',
      'calendar_label' => 'AV',
      'blocking' => 0,
      'machine_name' => 'bee_hourly_available',
      'event_type' => 'availability_hourly',
    ],
    'bee_hourly_not_available' => [
      'name' => 'Not available',
      'color' => '#f04b4b',
      'calendar_label' => 'N/A',
      'blocking' => 0,
      'machine_name' => 'bee_hourly_not_available',
      'event_type' => 'availability_hourly',
    ],
    'bee_hourly_booked' => [
      'name' => 'Booked',
      'color' => '#4b3cea',
      'calendar_label' => 'BOOK',
      'blocking' => 1,
      'machine_name' => 'bee_hourly_booked',
      'event_type' => 'availability_hourly',
    ],
  ];

  foreach ($states as $state) {
    bat_event_create_state($state)->save();
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc