);
}
+ /**
+ * Get billing fields required for this processor.
+ *
+ * We apply the existing default of returning fields only for payment processor type 1. Processors can override to
+ * alter.
+ *
+ * @param int $billingLocationID
+ *
+ * @return array
+ */
+ public function getBillingAddressFields($billingLocationID) {
+ if ($this->_paymentProcessor['billing_mode'] != 1 && $this->_paymentProcessor['billing_mode'] != 3) {
+ return array();
+ }
+ return array(
+ 'first_name' => 'billing_first_name',
+ 'middle_name' => 'billing_middle_name',
+ 'last_name' => 'billing_last_name',
+ 'street_address' => "billing_street_address-{$billingLocationID}",
+ 'city' => "billing_city-{$billingLocationID}",
+ 'country' => "billing_country_id-{$billingLocationID}",
+ 'state_province' => "billing_state_province_id-{$billingLocationID}",
+ 'postal_code' => "billing_postal_code-{$billingLocationID}",
+ );
+ }
+
+ /**
+ * Get form metadata for billing address fields.
+ *
+ * @param int $billingLocationID
+ *
+ * @return array
+ * Array of metadata for address fields.
+ */
+ public function getBillingAddressFieldsMetadata($billingLocationID) {
+ $metadata = array();
+ $metadata['billing_first_name'] = array(
+ 'htmlType' => 'text',
+ 'name' => 'billing_first_name',
+ 'title' => ts('Billing First Name'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 30,
+ 'maxlength' => 60,
+ 'autocomplete' => 'off',
+ ),
+ 'is_required' => TRUE,
+ );
+
+ $metadata['billing_middle_name'] = array(
+ 'htmlType' => 'text',
+ 'name' => 'billing_middle_name',
+ 'title' => ts('Billing Middle Name'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 30,
+ 'maxlength' => 60,
+ 'autocomplete' => 'off',
+ ),
+ 'is_required' => FALSE,
+ );
+
+ $metadata['billing_last_name'] = array(
+ 'htmlType' => 'text',
+ 'name' => 'billing_last_name',
+ 'title' => ts('Billing Last Name'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 30,
+ 'maxlength' => 60,
+ 'autocomplete' => 'off',
+ ),
+ 'is_required' => TRUE,
+ );
+
+ $metadata["billing_street_address-{$billingLocationID}"] = array(
+ 'htmlType' => 'text',
+ 'name' => "billing_street_address-{$billingLocationID}",
+ 'title' => ts('Street Address'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 30,
+ 'maxlength' => 60,
+ 'autocomplete' => 'off',
+ ),
+ 'is_required' => TRUE,
+ );
+
+ $metadata["billing_city-{$billingLocationID}"] = array(
+ 'htmlType' => 'text',
+ 'name' => "billing_city-{$billingLocationID}",
+ 'title' => ts('City'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 30,
+ 'maxlength' => 60,
+ 'autocomplete' => 'off',
+ ),
+ 'is_required' => TRUE,
+ );
+
+ $metadata["billing_state_province_id-{$billingLocationID}"] = array(
+ 'htmlType' => 'chainSelect',
+ 'title' => ts('State/Province'),
+ 'name' => "billing_state_province_id-{$billingLocationID}",
+ 'cc_field' => TRUE,
+ 'is_required' => TRUE,
+ );
+
+ $metadata["billing_postal_code-{$billingLocationID}"] = array(
+ 'htmlType' => 'text',
+ 'name' => "billing_postal_code-{$billingLocationID}",
+ 'title' => ts('Postal Code'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 30,
+ 'maxlength' => 60,
+ 'autocomplete' => 'off',
+ ),
+ 'is_required' => TRUE,
+ );
+
+ $metadata["billing_country_id-{$billingLocationID}"] = array(
+ 'htmlType' => 'select',
+ 'name' => "billing_country_id-{$billingLocationID}",
+ 'title' => ts('Country'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ '' => ts('- select -'),
+ ) + CRM_Core_PseudoConstant::country(),
+ 'is_required' => TRUE,
+ );
+ return $metadata;
+ }
+
/**
* Get base url dependent on component.
*
*/
/**
+ * Class for constructing the payment processor block.
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2015
*/
static public function setPaymentFieldsByProcessor(&$form, $processor, $forceBillingFieldsForPayLater = FALSE, $isBackOffice = FALSE) {
$form->billingFieldSets = array();
- if ($processor != NULL) {
- // ie it is pay later
- $paymentFields = self::getPaymentFields($processor);
- $paymentTypeName = self::getPaymentTypeName($processor);
- $paymentTypeLabel = self::getPaymentTypeLabel($processor);
- //@todo if we switch to iterating through $form->billingFieldSets we won't need to assign these directly
- $form->assign('paymentTypeName', $paymentTypeName);
- $form->assign('paymentTypeLabel', $paymentTypeLabel);
-
- $form->billingFieldSets[$paymentTypeName]['fields'] = $form->_paymentFields = array_intersect_key(self::getPaymentFieldMetadata($processor), array_flip($paymentFields));
- $form->assign('paymentFields', $paymentFields);
- }
-
- // @todo - replace this section with one similar to above per discussion - probably use a manual processor shell class to stand in for that capability
- //return without adding billing fields if billing_mode = 4 (@todo - more the ability to set that to the payment processor)
- // or payment processor is NULL (pay later)
- if (($processor == NULL && !$forceBillingFieldsForPayLater) || CRM_Utils_Array::value('billing_mode', $processor) == 4) {
+ if (empty($processor)) {
+ self::hackyHandlePayLaterInPaymentProcessorFunction($form, $forceBillingFieldsForPayLater);
return;
}
- //@todo setPaymentFields defines the billing fields - this should be moved to the processor class & renamed getBillingFields
- // potentially pay later would also be a payment processor
- //also set the billingFieldSet to hold all the details required to render the fieldset so we can iterate through the fieldset - making
- // it easier to re-order in hooks etc. The billingFieldSets param is used to determine whether to show the billing pane
- CRM_Core_Payment_Form::setBillingDetailsFields($form);
+
+ $paymentTypeName = self::getPaymentTypeName($processor);
+ $paymentTypeLabel = self::getPaymentTypeLabel($processor);
+ $form->assign('paymentTypeName', $paymentTypeName);
+ $form->assign('paymentTypeLabel', $paymentTypeLabel);
+ $form->_paymentFields = $form->billingFieldSets[$paymentTypeName]['fields'] = self::getPaymentFieldMetadata($processor);
+ $form->_paymentFields = array_merge($form->_paymentFields, self::getBillingAddressMetadata($processor, $form->_bltID));
+ $form->assign('paymentFields', self::getPaymentFields($processor));
+ self::setBillingAddressFields($form, $processor);
+ // @todo - this may be obsolete - although potentially it could be used to re-order things in the form.
$form->billingFieldSets['billing_name_address-group']['fields'] = array();
}
/**
* Add general billing fields.
- * @todo set these like processor fields & let payment processors alter them
*
* @param CRM_Core_Form $form
+ * @param CRM_Core_Payment $processor
*
* @return void
*/
+ static protected function setBillingAddressFields(&$form, $processor) {
+ $billingID = $form->_bltID;
+ $smarty = CRM_Core_Smarty::singleton();
+ $smarty->assign('billingDetailsFields', self::getBillingAddressFields($processor, $billingID));
+ }
+
+ /**
+ * Add pay later billing fields
+ *
+ * @deprecated
+ *
+ * This is here to preserve the old flow for pay-later requiring billing as I am unsure how to replicate it or what to
+ * expect from it/ whether it even works.
+ *
+ * Including the pay-later flow in this form is pretty hacky unless we adopt the proposed process of adding
+ * an offline / pay later processor (CRM_Core_Payment_Offline). In which case it would either be implemented
+ * (preferably) like other processors or (possibly) as a pseudo-processor with the Civi\Payment\System->getById
+ * turning that class if $id === 0 or getByProcessor returning it when $processor === array(); If we go down the path
+ * we probably also want to add the default pay-later text into the signature field of the pay later processor and
+ * implement a function similar to the dummy class where the payment processor outcome class can be set.
+ *
+ * Then doPayment could be called regardless of whether the flow is paylater or not - it wouldn't do much although
+ * people might leverage it's hook - but it would simplify the main postProcess flow as it would look like
+ *
+ * if ($paymentStatus === Completed) {
+ * $processor->setPaymentResult = array('payment_status_id', 1);
+ * }
+ * $processor->doDirectPayment();
+ * etc
+ *
+ * And the postProcess code would not need to distinguish between pay later/ offline & online payments.
+ *
+ * Alternatively enforcing certain fields for pay later in some cases would be a candidate for an extension.
+ *
+ * @param CRM_Core_Form $form
+ */
static protected function setBillingDetailsFields(&$form) {
$bltID = $form->_bltID;
}
/**
+ * Get the payment fields that apply to this processor.
+ *
* @param array $paymentProcessor
- * @todo it will be necessary to set details that affect it - mostly likely take Country as a param. Should we add generic
- * setParams on processor class or just setCountry which we know we need?
+ *
+ * @todo sometimes things like the country alter the required fields (e.g direct debit fields). We should possibly
+ * set these before calling getPaymentFormFields (as we identify them).
*
* @return array
*/
*/
public static function getPaymentFieldMetadata($paymentProcessor) {
$paymentProcessorObject = Civi\Payment\System::singleton()->getByProcessor($paymentProcessor);
- return $paymentProcessorObject->getPaymentFormFieldsMetadata();
+ return array_intersect_key($paymentProcessorObject->getPaymentFormFieldsMetadata(), array_flip(self::getPaymentFields($paymentProcessor)));
+ }
+
+ /**
+ * Get the billing fields that apply to this processor.
+ *
+ * @param array $paymentProcessor
+ * @param int $billingLocationID
+ * ID of billing location type.
+ *
+ * @todo sometimes things like the country alter the required fields (e.g postal code). We should possibly
+ * set these before calling getPaymentFormFields (as we identify them).
+ *
+ * @return array
+ */
+ public static function getBillingAddressFields($paymentProcessor, $billingLocationID) {
+ $paymentProcessorObject = Civi\Payment\System::singleton()->getByProcessor($paymentProcessor);
+ return $paymentProcessorObject->getBillingAddressFields($billingLocationID);
+ }
+
+ /**
+ * @param array $paymentProcessor
+ *
+ * @param int $billingLocationID
+ *
+ * @return array
+ * @throws \CRM_Core_Exception
+ */
+ public static function getBillingAddressMetadata($paymentProcessor, $billingLocationID) {
+ $paymentProcessorObject = Civi\Payment\System::singleton()->getByProcessor($paymentProcessor);
+ return $paymentProcessorObject->getBillingAddressFieldsMetadata($billingLocationID);
}
/**
return CRM_Utils_Array::value('Y', $src['credit_card_exp_date']);
}
+ /**
+ * Set billing fields for pay later.
+ *
+ * This is considered hacky because pay later has basically been cludged onto the payment processor form.
+ *
+ * See notes on the deprecated function as to how this could be restructured. Alternatively this pay later
+ * handling could be moved out of the payment processor form all together.
+ *
+ * @param CRM_Core_Form $form
+ * @param int $forceBillingFieldsForPayLater
+ */
+ protected static function hackyHandlePayLaterInPaymentProcessorFunction(&$form, $forceBillingFieldsForPayLater) {
+ if ($forceBillingFieldsForPayLater) {
+ CRM_Core_Payment_Form::setBillingDetailsFields($form);
+ $form->billingFieldSets['billing_name_address-group']['fields'] = array();
+ }
+ }
+
}