From ad04e6902d3b157c6a29614dbe70ba46302fe62c Mon Sep 17 00:00:00 2001 From: Jens Schuppe Date: Fri, 10 May 2024 11:45:16 +0200 Subject: [PATCH] (WIP) Add price fields to form definition --- CRM/Remoteevent/RegistrationProfile.php | 129 ++++++++++++++++++++++++ remoteevent.php | 3 + 2 files changed, 132 insertions(+) diff --git a/CRM/Remoteevent/RegistrationProfile.php b/CRM/Remoteevent/RegistrationProfile.php index 17bfc91..33ae4d5 100644 --- a/CRM/Remoteevent/RegistrationProfile.php +++ b/CRM/Remoteevent/RegistrationProfile.php @@ -102,6 +102,107 @@ public function getLabel() */ abstract public function getFields($locale = null); + /** + * @param array $event + * @param string|null $locale + * + * @return array> + * @throws \CRM_Core_Exception + */ + public function getPriceFields(array $event, ?string $locale = NULL): array + { + $fields = []; + + if (!(bool) $event['is_monetary']) { + return $fields; + } + + $priceFields = \Civi\Api4\Event::get(FALSE) + ->addSelect('price_field.*') + ->addJoin( + 'PriceSetEntity AS price_set_entity', + 'INNER', + ['price_set_entity.entity_table', '=', '"civicrm_event"'], + ['price_set_entity.entity_id', '=', 'id'] + ) + ->addJoin( + 'PriceSet AS price_set', + 'INNER', + ['price_set.id', '=', 'price_set_entity.price_set_id'], + ['price_set.is_active', '=', 1] + ) + ->addJoin( + 'PriceField AS price_field', + 'LEFT', + ['price_field.price_set_id', '=', 'price_set.id'] + ) + ->addWhere('id', '=', $event['id']) + ->execute(); + + if (count($priceFields) === 0) { + return $fields; + } + + $l10n = CRM_Remoteevent_Localisation::getLocalisation($locale); + $fields['price'] = [ + 'type' => 'fieldset', + 'name' => 'price', + // TODO: Is the label correctly localised with the requested $locale? + 'label' => $event['fee_label'], + ]; + foreach ($priceFields as $priceField) { + $priceFieldValues = \Civi\Api4\PriceFieldValue::get(FALSE) + ->addSelect('id', 'label', 'amount') + ->addWhere('price_field_id', '=', $priceField['price_field.id']) + ->execute() + ->indexBy('id'); + $field = [ + // TODO: Validate types. + 'type' => $priceField['price_field.html_type'], + 'name' => $priceField['price_field.name'], + // TODO: Localize label with given $locale. + 'label' => $priceField['price_field.label'], + 'weight' => $priceField['price_field.weight'], + 'required' => (bool) $priceField['price_field.is_required'], + 'parent' => 'price', + 'options' => $priceFieldValues->column('label'), + ]; + + // Append price field value amounts in option labels. + if ($priceField['price_field.is_display_amounts']) { + array_walk($field['options'], function(&$label, $id, $context) { + $label .= sprintf( + ' (%s)', + CRM_Utils_Money::format( + $context['priceFieldValues'][$id]['amount'], + $context['event']['currency'] + ) + ); + }, ['priceFieldValues' => $priceFieldValues, 'event' => $event]); + } + + // Add prefixed help text. + if (isset($priceField['price_field.help_pre'])) { + // TODO: Localize with given $locale. + $field['prefix'] = $priceField['price_field.help_pre']; + $field['prefix_display'] = 'inline'; + } + + // Add suffixed help text. + if (isset($priceField['price_field.help_post'])) { + // TODO: Localize with given $locale. + $field['suffix'] = $priceField['price_field.help_post']; + $field['suffix_display'] = 'inline'; + } + + // TODO: Ids the price field name unique across all price fields for + // this event? + $fields['price_' . $priceField['price_field.name']] = $field; + } + + return $fields; + } + public function getAdditionalParticipantsFields(array $event, ?int $maxParticipants = NULL, ?string $locale = NULL): array { $fields = []; @@ -114,6 +215,7 @@ public function getAdditionalParticipantsFields(array $event, ?int $maxParticipa $event['event_remote_registration.remote_registration_additional_participants_profile'] ); $additional_fields = $additional_participants_profile->getFields($locale); + $additional_fields += $additional_participants_profile->getPriceFields($event, $locale); $fields['additional_participants'] = [ 'type' => 'fieldset', 'name' => 'additional_participants', @@ -269,6 +371,32 @@ function(int $carry, string $item) { } } } + + // Validate price fields. + if ((bool) $event['is_monetary']) { + foreach ($this->validatePriceFields($event, $data) as $field_name => $error) { + $validationEvent->addValidationError($field_name, $error); + } + } + } + + /** + * @param array $event + * @param array $submission + * @param \CRM_Remoteevent_Localisation $l10n + * + * @return array + * An array with field names as keys and corresponding localised error + * messages as values. + * @throws \CRM_Core_Exception + */ + protected function validatePriceFields(array $event, array $submission, CRM_Remoteevent_Localisation $l10n): array + { + $errors = []; + foreach ($this->getPriceFields($event) as $priceField) { + // TODO: Validate price field values. + } + return $errors; } /** @@ -396,6 +524,7 @@ public static function addProfileData($get_form_results) $locale = $get_form_results->getLocale(); $fields = $profile->getFields($locale); if ('create' === $get_form_results->getContext()) { + $fields += $profile->getPriceFields($event, $locale); $fields += $profile->getAdditionalParticipantsFields($event, NULL, $locale); } $get_form_results->addFields($fields); diff --git a/remoteevent.php b/remoteevent.php index 75c93a1..3843d7e 100644 --- a/remoteevent.php +++ b/remoteevent.php @@ -155,6 +155,9 @@ function remoteevent_civicrm_config(&$config) $dispatcher->addUniqueListener( RegistrationEvent::NAME, ['CRM_Remoteevent_Registration', 'registerAdditionalParticipants'], CRM_Remoteevent_Registration::STAGE2_PARTICIPANT_CREATION); + + // TODO: Process price fields. + $dispatcher->addUniqueListener( RegistrationEvent::NAME, ['CRM_Remoteevent_EventSessions', 'synchroniseSessions'], CRM_Remoteevent_Registration::AFTER_PARTICIPANT_CREATION);