Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for monetary events #73

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CRM/Remoteevent/Registration.php
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,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
*/
Expand Down
145 changes: 145 additions & 0 deletions CRM/Remoteevent/RegistrationProfile.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,123 @@ 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
*
* @return array<string,array<string,mixed>>
* @throws \CRM_Core_Exception
*/
public function getProfilePriceFields(array $event, ?string $locale = NULL): array
{
$fields = [];

if (!(bool) $event['is_monetary']) {
return $fields;
}

$priceFields = self::getPriceFields($event);
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' => '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',
];
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 (isset($field['options']) && $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: Is 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 = [];
Expand All @@ -114,6 +231,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->getProfilePriceFields($event, $locale);
$fields['additional_participants'] = [
'type' => 'fieldset',
'name' => 'additional_participants',
Expand Down Expand Up @@ -269,6 +387,32 @@ function(int $carry, string $item) {
}
}
}

// Validate price fields.
if ((bool) $event['is_monetary']) {
foreach ($this->validatePriceFields($event, $data, $l10n) as $field_name => $error) {
$validationEvent->addValidationError($field_name, $error);
}
}
}

/**
* @param array $event
* @param array $submission
* @param \CRM_Remoteevent_Localisation $l10n
*
* @return array<string, string>
* 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->getProfilePriceFields($event) as $priceField) {
// TODO: Validate price field values.
}
return $errors;
}

/**
Expand Down Expand Up @@ -396,6 +540,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->getProfilePriceFields($event, $locale);
$fields += $profile->getAdditionalParticipantsFields($event, NULL, $locale);
}
$get_form_results->addFields($fields);
Expand Down
43 changes: 43 additions & 0 deletions Civi/RemoteParticipant/Event/RegistrationEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,4 +247,47 @@ public function getQueryParameters()
{
return $this->submission;
}

/**
* @return array<string, mixed>
* @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;
}
}
6 changes: 6 additions & 0 deletions remoteevent.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ 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_Registration', 'createOrder'], CRM_Remoteevent_Registration::AFTER_PARTICIPANT_CREATION);

$dispatcher->addUniqueListener(
RegistrationEvent::NAME,
['CRM_Remoteevent_EventSessions', 'synchroniseSessions'], CRM_Remoteevent_Registration::AFTER_PARTICIPANT_CREATION);
Expand Down
Loading