From d650b1459bc41a703f87dc1d338af902a0fe10ef Mon Sep 17 00:00:00 2001 From: Jens Schuppe Date: Tue, 16 Jul 2024 13:05:34 +0200 Subject: [PATCH] (wip) Process price fields --- CRM/Remoteevent/Registration.php | 23 ++++++ CRM/Remoteevent/RegistrationProfile.php | 78 +++++++++++-------- .../Event/RegistrationEvent.php | 43 ++++++++++ remoteevent.php | 3 + 4 files changed, 116 insertions(+), 31 deletions(-) diff --git a/CRM/Remoteevent/Registration.php b/CRM/Remoteevent/Registration.php index a07c71f..f4c5f10 100644 --- a/CRM/Remoteevent/Registration.php +++ b/CRM/Remoteevent/Registration.php @@ -798,6 +798,29 @@ public static function registerAdditionalParticipants(RegistrationEvent $registr $registration->setAdditionalParticipantsData($additionalParticipantsData); } + public static function createOrder(RegistrationEvent $registration): void { + $event = $registration->getEvent(); + if ( + (bool) $event['is_monetary'] + && class_exists('\Civi\Api4\Order') + ) { + $order = \Civi\Api4\Order::create(FALSE) + ->setContributionValues([ + 'contact_id' => $registration->getContactID(), + 'financial_type_id' => $event['financial_type_id'], + ]); + foreach ($registration->getPriceFieldValues() as $value) { + $order->addLineItem([ + 'entity_table' => 'civicrm_participant', + 'entity_id' => $value['participant_id'], + 'price_field_value_id' => $value['price_field_value_id'], + 'qty' => $value['qty'] + ]); + } + $order->execute(); + } + } + /** * Get a (cached version) of ParticipantStatusType.get */ diff --git a/CRM/Remoteevent/RegistrationProfile.php b/CRM/Remoteevent/RegistrationProfile.php index fd6b27b..0df20d9 100644 --- a/CRM/Remoteevent/RegistrationProfile.php +++ b/CRM/Remoteevent/RegistrationProfile.php @@ -96,6 +96,31 @@ public function getLabel() */ abstract public function getFields($locale = null); + public static function getPriceFields(array $event): array { + return \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() + ->getArrayCopy(); + } + /** * @param array $event * @param string|null $locale @@ -103,7 +128,7 @@ abstract public function getFields($locale = null); * @return array> * @throws \CRM_Core_Exception */ - public function getPriceFields(array $event, ?string $locale = NULL): array + public function getProfilePriceFields(array $event, ?string $locale = NULL): array { $fields = []; @@ -111,28 +136,7 @@ public function getPriceFields(array $event, ?string $locale = NULL): array 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(); - + $priceFields = self::getPriceFields($event); if (count($priceFields) === 0) { return $fields; } @@ -153,17 +157,29 @@ public function getPriceFields(array $event, ?string $locale = NULL): array $field = [ // TODO: Validate types. 'type' => $priceField['price_field.html_type'], - 'name' => $priceField['price_field.name'], + 'name' => 'price_' . $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'), ]; + if ($priceField['price_field.is_enter_qty']) { + // Append price per unit. + $field['label'] .= sprintf( + ' (%s)', + CRM_Utils_Money::format( + $priceFieldValues->first()['amount'], + $event['currency'] + ) + ); + } + else { + $field['options'] = $priceFieldValues->column('label'); + } // Append price field value amounts in option labels. - if ($priceField['price_field.is_display_amounts']) { + if (isset($field['options']) && $priceField['price_field.is_display_amounts']) { array_walk($field['options'], function(&$label, $id, $context) { $label .= sprintf( ' (%s)', @@ -189,7 +205,7 @@ public function getPriceFields(array $event, ?string $locale = NULL): array $field['suffix_display'] = 'inline'; } - // TODO: Ids the price field name unique across all price fields for + // TODO: Is the price field name unique across all price fields for // this event? $fields['price_' . $priceField['price_field.name']] = $field; } @@ -209,7 +225,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); + $additional_fields += $additional_participants_profile->getProfilePriceFields($event, $locale); $fields['additional_participants'] = [ 'type' => 'fieldset', 'name' => 'additional_participants', @@ -343,7 +359,7 @@ function(int $carry, string $item) { // Validate price fields. if ((bool) $event['is_monetary']) { - foreach ($this->validatePriceFields($event, $data) as $field_name => $error) { + foreach ($this->validatePriceFields($event, $data, $l10n) as $field_name => $error) { $validationEvent->addValidationError($field_name, $error); } } @@ -362,7 +378,7 @@ function(int $carry, string $item) { protected function validatePriceFields(array $event, array $submission, CRM_Remoteevent_Localisation $l10n): array { $errors = []; - foreach ($this->getPriceFields($event) as $priceField) { + foreach ($this->getProfilePriceFields($event) as $priceField) { // TODO: Validate price field values. } return $errors; @@ -493,7 +509,7 @@ public static function addProfileData($get_form_results) $locale = $get_form_results->getLocale(); $fields = $profile->getFields($locale); if ('create' === $get_form_results->getParams()['context']) { - $fields += $profile->getPriceFields($event, $locale); + $fields += $profile->getProfilePriceFields($event, $locale); $fields += $profile->getAdditionalParticipantsFields($event, NULL, $locale); } $get_form_results->addFields($fields); diff --git a/Civi/RemoteParticipant/Event/RegistrationEvent.php b/Civi/RemoteParticipant/Event/RegistrationEvent.php index 83e9307..bf0345d 100644 --- a/Civi/RemoteParticipant/Event/RegistrationEvent.php +++ b/Civi/RemoteParticipant/Event/RegistrationEvent.php @@ -247,4 +247,47 @@ public function getQueryParameters() { return $this->submission; } + + /** + * @return array + * @throws \CRM_Core_Exception + */ + public function getPriceFieldValues(): array + { + $values = []; + + $event = $this->getEvent(); + if (!(bool) $event['is_monetary']) { + return $values; + } + + foreach (\CRM_Remoteevent_RegistrationProfile::getPriceFields($event) as $priceField) { + $value = $this->submission['price_' . $priceField['price_field.name']] ?? NULL; + if (is_numeric($value)) { + $values[] = [ + 'participant_id' => $this->getParticipantID(), + 'price_field_name' => $priceField['price_field.name'], + 'price_field_value_id' => !(bool) $priceField['price_field.is_enter_qty'] ? $value : NULL, + 'qty' => (bool) $priceField['price_field.is_enter_qty'] ? $value : 1, + ]; + } + } + + $additionalParticipantsPriceFields = \CRM_Remoteevent_RegistrationProfile::getPriceFields($event); + foreach ($this->getAdditionalParticipantsData() as $additionalParticipantNo => $additionalParticipant) { + foreach ($additionalParticipantsPriceFields as $priceField) { + $value = $this->submission['additional_' . $additionalParticipantNo . '_price_' . $priceField['price_field.name']] ?? NULL; + if (is_numeric($value)) { + $values[] = [ + 'participant_id' => $additionalParticipant['id'], + 'price_field_name' => $priceField['price_field.name'], + 'price_field_value_id' => !(bool) $priceField['price_field.is_enter_qty'] ? $value : NULL, + 'qty' => (bool) $priceField['price_field.is_enter_qty'] ? $value : 1, + ]; + } + } + } + + return $values; + } } diff --git a/remoteevent.php b/remoteevent.php index 62ecf1e..a31eea0 100644 --- a/remoteevent.php +++ b/remoteevent.php @@ -154,6 +154,9 @@ function remoteevent_civicrm_config(&$config) ['CRM_Remoteevent_Registration', 'registerAdditionalParticipants'], CRM_Remoteevent_Registration::STAGE2_PARTICIPANT_CREATION); // TODO: Process price fields. + $dispatcher->addUniqueListener( + RegistrationEvent::NAME, + ['CRM_Remoteevent_Registration', 'createOrder'], CRM_Remoteevent_Registration::AFTER_PARTICIPANT_CREATION); $dispatcher->addUniqueListener( RegistrationEvent::NAME,