From 447501fb23f4f8cf5397892d1298e72e106f8b58 Mon Sep 17 00:00:00 2001 From: Matthew Wire Date: Fri, 5 Jun 2020 10:46:45 +0100 Subject: [PATCH] Convert event cart to use standard payment forms --- ext/eventcart/CRM/Event/Cart/BAO/Cart.php | 24 + .../CRM/Event/Cart/BAO/MerParticipant.php | 19 - ext/eventcart/CRM/Event/Cart/Form/Cart.php | 25 - .../CRM/Event/Cart/Form/Checkout/Payment.php | 563 ++++++------------ ext/eventcart/eventcart.php | 15 + ext/eventcart/settings/Eventcart.setting.php | 60 +- .../CRM/Event/Cart/Form/Checkout/Payment.tpl | 86 ++- ext/eventcart/xml/Menu/Eventcart.xml | 6 + 8 files changed, 308 insertions(+), 490 deletions(-) diff --git a/ext/eventcart/CRM/Event/Cart/BAO/Cart.php b/ext/eventcart/CRM/Event/Cart/BAO/Cart.php index 11111711547e..8bb437486415 100644 --- a/ext/eventcart/CRM/Event/Cart/BAO/Cart.php +++ b/ext/eventcart/CRM/Event/Cart/BAO/Cart.php @@ -343,4 +343,28 @@ public function adopt_participants($from_cart_id) { CRM_Core_DAO::executeQuery($sql, $params); } + /** + * Get payment processors. + * + * This differs from the option value in that we append description for disambiguation. + * + * @return array + * @throws \CiviCRM_API3_Exception + */ + public static function getPaymentProcessors(): array { + $results = civicrm_api3('PaymentProcessor', 'get', [ + 'is_test' => 0, + 'return' => ['id', 'name', 'description', 'domain_id'], + ]); + + $processors = []; + foreach ($results['values'] as $processorID => $details) { + $processors[$processorID] = $details['name']; + if (!empty($details['description'])) { + $processors[$processorID] .= ' : ' . $details['description']; + } + } + return $processors; + } + } diff --git a/ext/eventcart/CRM/Event/Cart/BAO/MerParticipant.php b/ext/eventcart/CRM/Event/Cart/BAO/MerParticipant.php index 4cdf4e341b9c..c2129a192bca 100644 --- a/ext/eventcart/CRM/Event/Cart/BAO/MerParticipant.php +++ b/ext/eventcart/CRM/Event/Cart/BAO/MerParticipant.php @@ -153,25 +153,6 @@ public function get_participant_index() { return $index + 1; } - /** - * @param $contact - * - * @return null - */ - public static function billing_address_from_contact($contact) { - foreach ($contact->address as $loc) { - if ($loc['is_billing']) { - return $loc; - } - } - foreach ($contact->address as $loc) { - if ($loc['is_primary']) { - return $loc; - } - } - return NULL; - } - /** * @return CRM_Event_Cart_Form_MerParticipant */ diff --git a/ext/eventcart/CRM/Event/Cart/Form/Cart.php b/ext/eventcart/CRM/Event/Cart/Form/Cart.php index 048c2ba5b9cc..07709ff8fa04 100644 --- a/ext/eventcart/CRM/Event/Cart/Form/Cart.php +++ b/ext/eventcart/CRM/Event/Cart/Form/Cart.php @@ -10,15 +10,12 @@ class CRM_Event_Cart_Form_Cart extends CRM_Core_Form { */ public $cart; - public $_action; public $contact; public $event_cart_id = NULL; - public $_mode; public $participants; public function preProcess() { $this->_action = CRM_Utils_Request::retrieveValue('action', 'String'); - $this->_mode = 'live'; $this->loadCart(); $this->checkWaitingList(); @@ -96,28 +93,6 @@ public function checkEventCapacity($event_id) { } } - /** - * @return int - * @throws \CRM_Core_Exception - */ - public function getContactID() { - $tempID = CRM_Utils_Request::retrieveValue('cid', 'Positive'); - - //check if this is a checksum authentication - $userChecksum = CRM_Utils_Request::retrieveValue('cs', 'String'); - if ($userChecksum) { - //check for anonymous user. - $validUser = CRM_Contact_BAO_Contact_Utils::validChecksum($tempID, $userChecksum); - if ($validUser) { - return $tempID; - } - } - - // check if the user is registered and we have a contact ID - $session = CRM_Core_Session::singleton(); - return $session->get('userID'); - } - /** * @param $fields * diff --git a/ext/eventcart/CRM/Event/Cart/Form/Checkout/Payment.php b/ext/eventcart/CRM/Event/Cart/Form/Checkout/Payment.php index 5f0aa4100cbb..84b51328f0ca 100644 --- a/ext/eventcart/CRM/Event/Cart/Form/Checkout/Payment.php +++ b/ext/eventcart/CRM/Event/Cart/Form/Checkout/Payment.php @@ -4,6 +4,8 @@ * Class CRM_Event_Cart_Form_Checkout_Payment */ class CRM_Event_Cart_Form_Checkout_Payment extends CRM_Event_Cart_Form_Cart { + use CRM_Financial_Form_FrontEndPaymentFormTrait; + public $all_participants; public $financial_type_id; public $description; @@ -12,197 +14,53 @@ class CRM_Event_Cart_Form_Checkout_Payment extends CRM_Event_Cart_Form_Cart { public $_paymentProcessor; public $total; public $sub_total; - public $payment_required = TRUE; public $payer_contact_id; - public $is_pay_later = FALSE; public $pay_later_receipt; /** - * @var array - */ - protected $_values = []; - - /** - * Register a participant. - * - * @param array $params - * @param CRM_Event_BAO_Participant $participant - * @param CRM_Event_BAO_Event $event - * - * @return mixed - * @throws \CiviCRM_API3_Exception + * @var \Civi\Payment\PropertyBag */ - public function registerParticipant($params, &$participant, $event) { - $participantParams = [ - 'id' => $participant->id, - 'event_id' => $event->id, - 'register_date' => date('YmdHis'), - 'source' => CRM_Utils_Array::value('participant_source', $params, $this->description), - 'is_pay_later' => $this->is_pay_later, - 'fee_amount' => CRM_Utils_Array::value('amount', $params, 0), - 'fee_currency' => $params['currencyID'] ?? NULL, - ]; - - if ($participant->must_wait) { - $participant_status = 'On waitlist'; - } - elseif (!empty($params['is_pay_later'])) { - $participant_status = 'Pending from pay later'; - } - else { - $participant_status = 'Registered'; - } - $participantParams['status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Event_BAO_Participant', 'status_id', $participant_status); - $participantParams['participant_status'] = CRM_Core_PseudoConstant::getLabel('CRM_Event_BAO_Participant', 'status_id', $participantParams['status_id']); - - $this->assign('isOnWaitlist', $participant->must_wait); - - $participantParams['is_test'] = 0; - if ($this->_action & CRM_Core_Action::PREVIEW || CRM_Utils_Array::value('mode', $params) == 'test') { - $participantParams['is_test'] = 1; - } - - $transaction = new CRM_Core_Transaction(); - - $participant->copyValues($participantParams); - $participant->save(); - - if (!empty($params['contributionID'])) { - $participantPaymentParams = [ - 'participant_id' => $participant->id, - 'contribution_id' => $params['contributionID'], - ]; - civicrm_api3('ParticipantPayment', 'create', $participantPaymentParams); - } - - $transaction->commit(); - - $event_values = []; - CRM_Core_DAO::storeValues($event, $event_values); - - $location = []; - if (CRM_Utils_Array::value('is_show_location', $event_values) == 1) { - $locationParams = [ - 'entity_id' => $participant->event_id, - 'entity_table' => 'civicrm_event', - ]; - $location = CRM_Core_BAO_Location::getValues($locationParams, TRUE); - CRM_Core_BAO_Address::fixAddress($location['address'][1]); - } - - list($pre_id, $post_id) = CRM_Event_Cart_Form_MerParticipant::get_profile_groups($participant->event_id); - $payer_values = [ - 'email' => '', - 'name' => '', - ]; - if ($this->payer_contact_id) { - $payer_contact_details = CRM_Contact_BAO_Contact::getContactDetails($this->payer_contact_id); - $payer_values = [ - 'email' => $payer_contact_details[1], - 'name' => $payer_contact_details[0], - ]; - } - $values = [ - 'params' => [$participant->id => $participantParams], - 'event' => $event_values, - 'location' => $location, - 'custom_pre_id' => $pre_id, - 'custom_post_id' => $post_id, - 'payer' => $payer_values, - ]; - CRM_Event_BAO_Event::sendMail($participant->contact_id, $values, $participant->id); - - return $participant; - } + protected $paymentPropertyBag; /** - * Build payment fields. + * @var array */ - public function buildPaymentFields() { - $payment_processor_id = NULL; - $can_pay_later = TRUE; - $pay_later_text = ""; - $this->pay_later_receipt = ""; - foreach ($this->cart->get_main_events_in_carts() as $event_in_cart) { - if ($payment_processor_id === NULL && $event_in_cart->event->payment_processor !== NULL) { - $payment_processor_id = $event_in_cart->event->payment_processor; - $this->financial_type_id = $event_in_cart->event->financial_type_id; - $this->_values['currency'] = $event_in_cart->event->currency; - } - else { - if ($event_in_cart->event->payment_processor !== NULL && $event_in_cart->event->payment_processor !== $payment_processor_id) { - CRM_Core_Error::statusBounce(ts('When registering for multiple events all events must use the same payment processor. ')); - } - } - if ($payment_processor_id) { - $can_pay_later = FALSE; - } - elseif ($event_in_cart->event->is_pay_later) { - //XXX - $pay_later_text = $event_in_cart->event->pay_later_text; - $this->pay_later_receipt = $event_in_cart->event->pay_later_receipt; - } - else { - CRM_Core_Error::statusBounce(ts('A payment processor must be selected for this event registration page, or the event must be configured to give users the option to pay later (contact the site administrator for assistance).')); - } - } - - if ($can_pay_later) { - $this->addElement('checkbox', 'is_pay_later', $pay_later_text); - $this->addElement('checkbox', 'payment_completed', ts('Payment Completed')); - $this->assign('pay_later_instructions', $this->pay_later_receipt); - } - else { - $this->_paymentProcessorIDs = [$payment_processor_id]; - $this->assignPaymentProcessor(FALSE); - CRM_Core_Payment_Form::buildPaymentForm($this, $this->_paymentProcessor, FALSE, FALSE); - } - $this->assign('currency', $this->getCurrency()); - } + protected $_values = []; /** * Build QuickForm. */ public function buildQuickForm() { - $this->line_items = []; - $this->sub_total = 0; - $this->_price_values = $this->getValuesForPage('ParticipantsAndPrices'); - - // iterate over each event in cart - foreach ($this->cart->get_main_events_in_carts() as $event_in_cart) { - $this->process_event_line_item($event_in_cart); - foreach ($this->cart->get_events_in_carts_by_main_event_id($event_in_cart->event_id) as $subevent) { - $this->process_event_line_item($subevent, 'subevent'); - } - } - - $this->total = $this->sub_total; - $this->payment_required = ($this->total > 0); - $this->assign('payment_required', $this->payment_required); - $this->assign('line_items', $this->line_items); - $this->assign('sub_total', $this->sub_total); - $this->assign('total', $this->total); - $buttons = []; - $buttons[] = [ - 'name' => ts('Go Back'), - 'type' => 'back', - ]; - $buttons[] = [ - 'isDefault' => TRUE, - 'name' => ts('Complete Transaction'), - 'type' => 'next', + $buttons = [ + [ + 'name' => ts('Go Back'), + 'type' => 'back', + ], + [ + 'isDefault' => TRUE, + 'name' => ts('Complete Transaction'), + 'type' => 'next', + ] ]; - if ($this->total) { - $this->add('text', 'billing_contact_email', 'Billing Email', '', TRUE); - $this->assign('collect_billing_email', TRUE); - } + // @todo we should replace this with an optional profile + $this->add('text', 'first_name', 'First Name', '', TRUE); + $this->add('text', 'last_name', 'Last Name', '', TRUE); + $this->add('text', 'email', 'Billing Email', '', TRUE); $this->addButtons($buttons); $this->addFormRule(['CRM_Event_Cart_Form_Checkout_Payment', 'formRule'], $this); - if ($this->payment_required) { - $this->buildPaymentFields(); + if ($this->isPaymentRequired()) { + CRM_Core_Payment_ProcessorForm::buildQuickForm($this); + $this->addPaymentProcessorFieldsToForm(); + } + + // Add reCAPTCHA + if (count($this->_paymentProcessors) >= 1) { + if (!$this->getLoggedInUserContactID()) { + CRM_Utils_ReCAPTCHA::enableCaptchaOnForm($this); + } } } @@ -293,6 +151,7 @@ public function add_line_item($event_in_cart, $class = NULL) { /** * Send email receipt. + * @fixme: Check if this works and does what we want * * @param array $events_in_cart * @param array $params @@ -338,7 +197,7 @@ public function emailReceipt($events_in_cart, $params) { 'name' => $contact_details[0], 'transaction_id' => $params['trxn_id'], 'transaction_date' => $params['trxn_date'], - 'is_pay_later' => $this->is_pay_later, + 'is_pay_later' => $this->isPayLater(), 'pay_later_receipt' => $this->pay_later_receipt, ], 'valueName' => 'event_registration_receipt', @@ -374,7 +233,7 @@ public function emailReceipt($events_in_cart, $params) { public static function formRule($fields, $files, $form) { $errors = []; - if ($form->payment_required && empty($form->_submitValues['is_pay_later'])) { + if ($form->isPaymentRequired() && empty($form->_submitValues['is_pay_later'])) { CRM_Core_Form::validateMandatoryFields($form->_fields, $fields, $errors); // validate payment instrument values (e.g. credit card number) @@ -388,10 +247,20 @@ public static function formRule($fields, $files, $form) { * Pre-process form. */ public function preProcess() { - $params = $this->_submitValues; - $this->is_pay_later = CRM_Utils_Array::value('is_pay_later', $params, FALSE) && !CRM_Utils_Array::value('payment_completed', $params); - parent::preProcess(); + + $this->paymentPropertyBag = new \Civi\Payment\PropertyBag(); + $this->setPaymentMode(); + + // Setup payment processors if required + if ($this->isPaymentRequired()) { + $this->_paymentProcessorIDs = \Civi::settings()->get('eventcart_payment_processors'); + $this->setIsPayLater(\Civi::settings()->get('eventcart_paylater')); + if ($this->isPayLater()) { + $this->setPayLaterLabel(\Civi::settings()->get('eventcart_paylater_text')); + } + $this->assignPaymentProcessor($this->isPayLater()); + } } /** @@ -400,85 +269,54 @@ public function preProcess() { public function postProcess() { $trxnDetails = NULL; $params = $this->_submitValues; + //$transaction = new CRM_Core_Transaction(); - $main_participants = $this->cart->get_main_event_participants(); - - $transaction = new CRM_Core_Transaction(); - - foreach ($main_participants as $participant) { - $defaults = []; - $ids = ['contact_id' => $participant->contact_id]; - $contact = CRM_Contact_BAO_Contact::retrieve($ids, $defaults); - $contact->is_deleted = 0; - $contact->save(); - } - - $trxn_prefix = 'VR'; - if (array_key_exists('billing_contact_email', $params)) { - $this->payer_contact_id = self::find_or_create_contact([ - 'email' => $params['billing_contact_email'], - 'first_name' => $params['billing_first_name'], - 'last_name' => $params['billing_last_name'], - 'is_deleted' => FALSE, - ]); - - $ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', - $this->payer_contact_id, - 'contact_type' - ); - $billing_fields = [ - "billing_first_name" => 1, - "billing_middle_name" => 1, - "billing_last_name" => 1, - "billing_street_address-{$this->_bltID}" => 1, - "billing_city-{$this->_bltID}" => 1, - "billing_state_province_id-{$this->_bltID}" => 1, - "billing_postal_code-{$this->_bltID}" => 1, - "billing_country_id-{$this->_bltID}" => 1, - "address_name-{$this->_bltID}" => 1, - "email-{$this->_bltID}" => 1, - ]; + $contactID = $this->getContactID(); + $ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactID, 'contact_type'); + $params = $this->prepareParamsForPaymentProcessor($params); + foreach($params as $key => $value) { + $fields[$key] = 1; + } + CRM_Contact_BAO_Contact::createProfileContact( + $params, + $fields, + $this->getContactID(), + NULL, + NULL, + $ctype, + TRUE + ); + $params['contact_id'] = $contactID; - $params["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $params) . ' ' . CRM_Utils_Array::value('billing_middle_name', $params) . ' ' . CRM_Utils_Array::value('billing_last_name', $params); + $params['now'] = date('YmdHis'); - $params["email-{$this->_bltID}"] = $params['billing_contact_email']; - CRM_Contact_BAO_Contact::createProfileContact( - $params, - $billing_fields, - $this->payer_contact_id, - NULL, - NULL, - $ctype, - TRUE - ); + $params['financial_type_id'] = $this->financial_type_id; + if ($this->isPaymentRequired() && empty($params['is_pay_later'])) { + $order = $this->createOrder($params)['id']; + $this->paymentPropertyBag->setContactID($contactID); + $this->paymentPropertyBag->setContributionID($order['id']); + $this->paymentPropertyBag->mergeLegacyInputParams($params); + + $payment = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor); + try { + $result = $payment->doPayment($this->paymentPropertyBag); + } + catch (\Civi\Payment\Exception\PaymentProcessorException $e) { + Civi::log()->error('Payment processor exception: ' . $e->getMessage()); + CRM_Core_Session::singleton()->setStatus($e->getMessage()); + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/event/cart_checkout', "_qf_Payment_display=1&qfKey={$this->controller->_key}", TRUE, NULL, FALSE)); + } - $params['contact_id'] = $this->payer_contact_id; + $params['trxn_id'] = $result['trxn_id']; + $params['trxn_date'] = $result['now']; } - $params['now'] = date('YmdHis'); - $params['invoiceID'] = md5(uniqid(rand(), TRUE)); - $params['amount'] = $this->total; - $params['financial_type_id'] = $this->financial_type_id; - if ($this->payment_required && empty($params['is_pay_later'])) { - $trxnDetails = $this->make_payment($params); - $params['trxn_id'] = $trxnDetails['trxn_id']; - $params['trxn_date'] = $trxnDetails['trxn_date']; - $params['currencyID'] = $trxnDetails['currency']; - } $this->cart->completed = TRUE; $this->cart->save(); $this->set('last_event_cart_id', $this->cart->id); $contribution_statuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); - $params['payment_instrument_id'] = NULL; - if (!empty($params['is_pay_later'])) { - $params['payment_instrument_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check'); - $trxn_prefix = 'CK'; - } - else { - $params['payment_instrument_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Credit Card'); - } - if ($this->is_pay_later && empty($params['payment_completed'])) { + if ($this->isPayLater() && empty($params['payment_completed'])) { $params['contribution_status_id'] = array_search('Pending', $contribution_statuses); } else { @@ -486,15 +324,21 @@ public function postProcess() { $params['participant_status'] = 'Registered'; $params['is_pay_later'] = 0; } - if ($trxnDetails == NULL) { - $params['trxn_id'] = $trxn_prefix . strftime("%Y%m%d%H%M%S"); - $params['trxn_date'] = $params['now']; - } - if ($this->payment_required) { + if ($this->isPaymentRequired()) { + // @fixme This is probably not getting the right params, and who is it sending to? $this->emailReceipt($this->cart->events_in_carts, $params); } + $this->trxn_id = $params['trxn_id']; + $this->trxn_date = $params['trxn_date']; + $this->saveDataToSession(); + $transaction->commit(); + } + + private function createOrder($params) { + $params['invoiceID'] = md5(uniqid(rand(), TRUE)); + // n.b. we need to process the subparticipants before main event // participants so that session attendance can be included in the email $main_participants = $this->cart->get_main_event_participants(); @@ -504,114 +348,33 @@ public function postProcess() { } $this->all_participants = array_merge($this->all_participants, $main_participants); - $this->sub_trxn_index = 0; foreach ($this->all_participants as $mer_participant) { $event_in_cart = $this->cart->get_event_in_cart_by_event_id($mer_participant->event_id); - $this->sub_trxn_index += 1; + $lineItem['params'] = [ + 'event_id' => $event_in_cart->event_id, + 'contact_id' => $mer_participant->contact_id, + 'role_id' => $mer_participant->role_id, + ]; - unset($params['contributionID']); - if ($mer_participant->must_wait) { - $this->registerParticipant($params, $mer_participant, $event_in_cart->event); - } - else { - $params['amount'] = $mer_participant->cost - $mer_participant->discount_amount; - - if ($event_in_cart->event->financial_type_id && $mer_participant->cost) { - $params['financial_type_id'] = $event_in_cart->event->financial_type_id; - $params['participant_contact_id'] = $mer_participant->contact_id; - $contribution = $this->record_contribution($mer_participant, $params, $event_in_cart->event); - // Record civicrm_line_item - CRM_Price_BAO_LineItem::processPriceSet($mer_participant->id, $mer_participant->price_details, $contribution, $entity_table = 'civicrm_participant'); + // @todo maybe handle waitList: $mer_participant->must_wait + foreach ($mer_participant->price_details as $priceSetID => $priceSetFieldValues) { + foreach ($priceSetFieldValues as $priceSetFieldValueID => $priceSetFieldValueDetail) { + $lineItem['line_item'][] = $priceSetFieldValueDetail; } - $this->registerParticipant($params, $mer_participant, $event_in_cart->event); } - } - $this->trxn_id = $params['trxn_id']; - $this->trxn_date = $params['trxn_date']; - $this->saveDataToSession(); - $transaction->commit(); - } - - /** - * Make payment. - * - * @param array $params - * - * @return array - * @throws Exception - */ - public function make_payment(&$params) { - $params = $this->prepareParamsForPaymentProcessor($params); - $params['currencyID'] = CRM_Core_Config::singleton()->defaultCurrency; - - $payment = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor); - CRM_Core_Payment_Form::mapParams($this->_bltID, $params, $params, TRUE); - - try { - $result = $payment->doPayment($params); - } - catch (\Civi\Payment\Exception\PaymentProcessorException $e) { - CRM_Core_Error::displaySessionError($result); - CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/event/cart_checkout', "_qf_Payment_display=1&qfKey={$this->controller->_key}", TRUE, NULL, FALSE)); + $lineItems[] = $lineItem; } - $trxnDetails = [ - 'trxn_id' => $result['trxn_id'], - 'trxn_date' => $result['now'], - 'currency' => $result['currencyID'] ?? NULL, + $orderParams = [ + 'contact_id' => $this->getContactID(), + 'total_amount' => $this->total, + 'financial_type_id' => 'Event fee', + 'contribution_status_id' => 'Pending', + 'line_items' => $lineItems, ]; - return $trxnDetails; - } - - /** - * Record contribution. - * - * @param CRM_Event_BAO_Participant $mer_participant - * @param array $params - * @param CRM_Event_BAO_Event $event - * - * @return object - * @throws Exception - */ - public function record_contribution(&$mer_participant, &$params, $event) { - if ($this->payer_contact_id) { - $payer = $this->payer_contact_id; - } - elseif (self::getContactID()) { - $payer = self::getContactID(); - } - else { - $payer = $params['participant_contact_id']; - } - - $contribParams = [ - 'contact_id' => $payer, - 'financial_type_id' => $params['financial_type_id'], - 'receive_date' => $params['now'], - 'total_amount' => $params['amount'], - 'amount_level' => $mer_participant->fee_level, - 'net_amount' => $params['amount'], - 'invoice_id' => "{$params['invoiceID']}-{$this->sub_trxn_index}", - 'trxn_id' => "{$params['trxn_id']}-{$this->sub_trxn_index}", - 'currency' => $params['currencyID'] ?? NULL, - 'source' => $event->title, - 'is_pay_later' => CRM_Utils_Array::value('is_pay_later', $params, 0), - 'contribution_status_id' => $params['contribution_status_id'], - 'payment_instrument_id' => $params['payment_instrument_id'], - 'check_number' => $params['check_number'] ?? NULL, - 'skipLineItem' => 1, - ]; - - if (is_array($this->_paymentProcessor)) { - $contribParams['payment_processor'] = $this->_paymentProcessor['id']; - } - - $contribution = CRM_Contribute_BAO_Contribution::add($contribParams); - $mer_participant->contribution_id = $contribution->id; - $params['contributionID'] = $contribution->id; - - return $contribution; + $result = civicrm_api3('Order', 'create', $orderParams); + return reset($result['values']); } /** @@ -627,8 +390,8 @@ public function saveDataToSession() { $session_line_items[] = $session_line_item; } $this->set('line_items', $session_line_items); - $this->set('payment_required', $this->payment_required); - $this->set('is_pay_later', $this->is_pay_later); + $this->set('payment_required', $this->isPaymentRequired()); + $this->set('is_pay_later', $this->isPayLater()); $this->set('pay_later_receipt', $this->pay_later_receipt); $this->set('trxn_id', $this->trxn_id); $this->set('trxn_date', $this->trxn_date); @@ -641,52 +404,32 @@ public function saveDataToSession() { * @return array */ public function setDefaultValues() { - $defaults = parent::setDefaultValues(); - - $default_country = new CRM_Core_DAO_Country(); - $default_country->iso_code = CRM_Core_BAO_Country::defaultContactCountry(); - $default_country->find(TRUE); - $defaults["billing_country_id-{$this->_bltID}"] = $default_country->id; - - if (self::getContactID()) { - $params = ['id' => self::getContactID()]; - $contact = CRM_Contact_BAO_Contact::retrieve($params, $defaults); - - foreach ($contact->email as $email) { - if ($email['is_billing']) { - $defaults["billing_contact_email"] = $email['email']; - } - } - if (empty($defaults['billing_contact_email'])) { - foreach ($contact->email as $email) { - if ($email['is_primary']) { - $defaults["billing_contact_email"] = $email['email']; - } - } - } - - $defaults["billing_first_name"] = $contact->first_name; - $defaults["billing_middle_name"] = $contact->middle_name; - $defaults["billing_last_name"] = $contact->last_name; - - $billing_address = CRM_Event_Cart_BAO_MerParticipant::billing_address_from_contact($contact); - - if ($billing_address != NULL) { - $defaults["billing_street_address-{$this->_bltID}"] = $billing_address['street_address']; - $defaults["billing_city-{$this->_bltID}"] = $billing_address['city']; - $defaults["billing_postal_code-{$this->_bltID}"] = $billing_address['postal_code']; - $defaults["billing_state_province_id-{$this->_bltID}"] = $billing_address['state_province_id']; - $defaults["billing_country_id-{$this->_bltID}"] = $billing_address['country_id']; - } - } - - $defaults["source"] = $this->description; - - return $defaults; + $contactID = $this->getContactID(); + CRM_Core_Payment_Form::setDefaultValues($this, $contactID); + + // @todo replace this with a profile + $contact = \Civi\Api4\Contact::get() + ->addSelect('first_name', 'last_name') + ->addWhere('id', '=', $contactID) + ->execute() + ->first(); + $this->_defaults['first_name'] = $contact['first_name'] ?? ''; + $this->_defaults['last_name'] = $contact['last_name'] ?? ''; + $email = \Civi\Api4\Email::get() + ->addSelect('email') + ->addWhere('contact_id', '=', $contactID) + ->addOrderBy('is_billing', 'DESC') + ->addOrderBy('is_primary', 'DESC') + ->execute() + ->first(); + $this->_defaults['email'] = $email['email'] ?? ''; + + return $this->_defaults; } /** * Apply discount. + * @fixme Check this still works! * * @param string $discountCode * @param array $price_set_amount @@ -756,4 +499,38 @@ protected function apply_discount($discountCode, &$price_set_amount, &$cost, $ev return $stat; } + public function isPaymentRequired() { + if (!isset(\Civi::$statics[__CLASS__]['is_payment_required'])) { + $this->setPaymentParameters(); + \Civi::$statics[__CLASS__]['is_payment_required'] = ($this->total > 0 ? TRUE : FALSE); + $this->assign('payment_required', \Civi::$statics[__CLASS__]['is_payment_required']); + } + return \Civi::$statics[__CLASS__]['is_payment_required']; + } + + private function setPaymentParameters() { + $this->line_items = []; + $this->sub_total = 0; + $this->_price_values = $this->getValuesForPage('ParticipantsAndPrices'); + + // iterate over each event in cart + foreach ($this->cart->get_main_events_in_carts() as $event_in_cart) { + $this->process_event_line_item($event_in_cart); + foreach ($this->cart->get_events_in_carts_by_main_event_id($event_in_cart->event_id) as $subevent) { + $this->process_event_line_item($subevent, 'subevent'); + } + } + + $this->total = $this->sub_total; + $this->assign('line_items', $this->line_items); + $this->assign('sub_total', $this->sub_total); + $this->assign('total', $this->total); + + // @fixme: This will always use the currency of the "last" event. + // That's probably ok because they should all use the same currency. + $this->assign('currency', $event_in_cart->event->currency); + $this->paymentPropertyBag->setCurrency($event_in_cart->event->currency); + $this->paymentPropertyBag->setAmount($this->total); + } + } diff --git a/ext/eventcart/eventcart.php b/ext/eventcart/eventcart.php index dec2a977e5d9..a978f36a07e8 100644 --- a/ext/eventcart/eventcart.php +++ b/ext/eventcart/eventcart.php @@ -146,3 +146,18 @@ function eventcart_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) { function eventcart_civicrm_entityTypes(&$entityTypes) { _eventcart_civix_civicrm_entityTypes($entityTypes); } + +/** + * Implements hook_civicrm_navigationMenu(). + */ +function eventcart_civicrm_navigationMenu(&$menu) { + _eventcart_civix_insert_navigation_menu($menu, 'Administer/CiviEvent', array( + 'label' => E::ts('Event Cart Settings'), + 'name' => 'eventcart_settings', + 'url' => 'civicrm/admin/setting/eventcart', + 'permission' => 'administer CiviCRM', + 'operator' => 'OR', + 'separator' => 0, + )); + _eventcart_civix_navigationMenu($menu); +} diff --git a/ext/eventcart/settings/Eventcart.setting.php b/ext/eventcart/settings/Eventcart.setting.php index d52892d25cf2..184375030707 100644 --- a/ext/eventcart/settings/Eventcart.setting.php +++ b/ext/eventcart/settings/Eventcart.setting.php @@ -21,11 +21,11 @@ return [ 'enable_cart' => [ 'name' => 'enable_cart', - 'group_name' => 'Event Preferences', - 'settings_pages' => ['event' => ['weight' => 10]], - 'group' => 'event', + 'group_name' => 'Event Cart Preferences', + 'settings_pages' => ['eventcart' => ['weight' => 10]], + 'group' => 'eventcart', 'type' => 'Boolean', - 'quick_form_type' => 'CheckBox', + 'html_type' => 'checkbox', 'default' => '0', 'add' => '4.1', 'title' => ts('Use Shopping Cart Style Event Registration'), @@ -35,4 +35,56 @@ 'help_text' => '', 'documentation_link' => ['page' => 'CiviEvent Cart Checkout', 'resource' => 'wiki'], ], + 'eventcart_payment_processors' => [ + 'name' => 'eventcart_payment_processors', + 'group_name' => 'Event Cart Preferences', + 'group' => 'eventcart', + 'type' => 'Array', + 'add' => '5.28', + 'is_domain' => 1, + 'is_contact' => 0, + 'description' => ts('Payment processors that will be available for the checkout'), + 'help_text' => '', + 'title' => ts('Payment processors for event cart checkout'), + 'html_type' => 'select', + 'default' => [], + 'html_attributes' => [ + 'class' => 'crm-select2', + 'multiple' => TRUE, + ], + 'pseudoconstant' => [ + 'callback' => 'CRM_Event_Cart_BAO_Cart::getPaymentProcessors', + ], + 'settings_pages' => ['eventcart' => ['weight' => 15]], + ], + 'eventcart_paylater' => [ + 'name' => 'eventcart_paylater', + 'group_name' => 'Event Cart Preferences', + 'settings_pages' => ['eventcart' => ['weight' => 20]], + 'group' => 'eventcart', + 'type' => 'Boolean', + 'html_type' => 'checkbox', + 'default' => '0', + 'add' => '5.28', + 'title' => ts('Allow pay later for event cart'), + 'is_domain' => 1, + 'is_contact' => 0, + 'description' => ts('Enable the pay later option for the event cart checkout'), + 'help_text' => '', + ], + 'eventcart_paylater_text' => [ + 'name' => 'eventcart_paylater_text', + 'group_name' => 'Event Cart Preferences', + 'settings_pages' => ['eventcart' => ['weight' => 25]], + 'group' => 'eventcart', + 'type' => 'Text', + 'html_type' => 'text', + 'default' => 'Pay later', + 'add' => '5.28', + 'title' => ts('The text to display for pay later option'), + 'is_domain' => 1, + 'is_contact' => 0, + 'description' => ts('This is the text that will be displayed on the payment processor selector'), + 'help_text' => '', + ], ]; diff --git a/ext/eventcart/templates/CRM/Event/Cart/Form/Checkout/Payment.tpl b/ext/eventcart/templates/CRM/Event/Cart/Form/Checkout/Payment.tpl index fba3a4770c45..2b1967759518 100644 --- a/ext/eventcart/templates/CRM/Event/Cart/Form/Checkout/Payment.tpl +++ b/ext/eventcart/templates/CRM/Event/Cart/Form/Checkout/Payment.tpl @@ -93,66 +93,54 @@ -{if $payment_required == true} - {if $form.is_pay_later.label} -
-
{$form.is_pay_later.label}
-
{$form.is_pay_later.html} -
-
-
-