_paymentProcessor = [
'payment_type' => 0,
'billing_mode' => 0,
'id' => 0,
'url_recur' => '',
'is_recur' => 0,
];
}
/**
* 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 = NULL) {
if (!$billingLocationID) {
// Note that although the billing id is passed around the forms the idea that it would be anything other than
// the result of the function below doesn't seem to have eventuated.
// So taking this as a param is possibly something to be removed in favour of the standard default.
$billingLocationID = CRM_Core_BAO_LocationType::getBilling();
}
// Only handle pseudo-profile billing for now.
if ($this->billingProfile == 'billing') {
// @todo - use profile api to retrieve this - either as pseudo-profile or (better) set up billing
// as a reserved profile in the DB and (even better) allow the profile to be selected
// on the form instead of just 'billing for pay=later bool'
return [
'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}",
];
}
else {
return [];
}
}
/**
* Get array of fields that should be displayed on the payment form.
*
* @return array
*/
public function getPaymentFormFields() {
if (!$this->isBackOffice()) {
return [];
}
$paymentInstrument = CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', $this->getPaymentInstrumentID());
if ($paymentInstrument === 'Credit Card') {
return ['credit_card_type', 'pan_truncation'];
}
elseif ($paymentInstrument === 'Check') {
return ['check_number'];
}
return [];
}
/**
* Process payment.
*
* The function ensures an exception is thrown & moves some of this logic out of the form layer and makes the forms
* more agnostic.
*
* @param array $params
*
* @param string $component
*
* @return array
* Result array
*
* @throws \Civi\Payment\Exception\PaymentProcessorException
*/
public function doPayment(&$params, $component = 'contribute') {
$result['payment_status_id'] = $this->getResult();
if ($result['payment_status_id'] == CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending')) {
$result = $this->setStatusPaymentPending($result);
}
elseif ($result['payment_status_id'] == CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed')) {
$result = $this->setStatusPaymentCompleted($result);
}
else {
throw new \Civi\Payment\Exception\PaymentProcessorException('Result from doPayment MUST be one of Completed|Pending');
}
return $result;
}
/**
* Get the result of the payment.
*
* Usually this will be pending but the calling layer has a chance to set the result.
*
* This would apply in particular when the form accepts status id.
*
* Note that currently this payment class is only being used to manage the 'billing block' aspect
* of pay later. However, a longer term idea is that by treating 'pay-later' as 'just another processor'
* will allow code simplification.
*
* @return int
*/
protected function getResult() {
if (!$this->result) {
$this->setResult(CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending'));
}
return $this->result;
}
/**
* Set the result to be returned.
*
* This would be set from outside the function where we want to pass on the status from the form.
*
* @param int $result
*/
public function setResult($result) {
$this->result = $result;
}
/**
* Set payment instrument id.
*
* @param int $paymentInstrumentID
*/
public function setPaymentInstrumentID($paymentInstrumentID) {
$this->paymentInstrumentID = $paymentInstrumentID;
}
/**
* Get the name of the payment type.
*
* @return string
*/
public function getPaymentTypeName() {
return 'pay-later';
}
/**
* Get the name of the payment type.
*
* @return string
*/
public function getPaymentTypeLabel() {
return CRM_Core_PseudoConstant::getLabel('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', $this->getPaymentInstrumentID());
}
/**
* Are live payments supported - e.g dummy doesn't support this.
*
* @return bool
*/
protected function supportsLiveMode() {
return TRUE;
}
/**
* Are test payments supported.
*
* @return bool
*/
protected function supportsTestMode() {
return TRUE;
}
/**
* Declare that more than one payment can be processed at once.
*
* @return bool
*/
protected function supportsMultipleConcurrentPayments() {
return TRUE;
}
/**
* Checks if backoffice recurring edit is allowed
*
* @return bool
*/
public function supportsEditRecurringContribution() {
return TRUE;
}
/**
* Does the processor support the user having a choice as to whether to cancel the recurring with the processor?
*
* If this returns TRUE then there will be an option to send a cancellation request in the cancellation form.
*
* This would normally be false for processors where CiviCRM maintains the schedule.
*
* @return bool
*/
protected function supportsCancelRecurringNotifyOptional() {
return FALSE;
}
/**
* Are back office payments supported.
*
* @return bool
*/
protected function supportsBackOffice() {
return TRUE;
}
/**
* Does the processor work without an email address?
*/
protected function supportsNoEmailProvided() {
return TRUE;
}
/**
* Should a receipt be sent out for a pending payment.
*
* e.g for traditional pay later & ones with a delayed settlement a pending receipt makes sense.
*/
public function isSendReceiptForPending() {
return TRUE;
}
/**
* Get help text information (help, description, etc.) about this payment,
* to display to the user.
*
* @param string $context
* Context of the text.
* Only explicitly supported contexts are handled without error.
* Currently supported:
* - contributionPageRecurringHelp (params: is_recur_installments, is_email_receipt)
*
* @param array $params
* Parameters for the field, context specific.
*
* @return string
*/
public function getText($context, $params) {
switch ($context) {
case 'contributionPageContinueText':
if ($params['amount'] <= 0) {
return ts('To complete this transaction, click the Continue button below.');
}
return ts('To complete your contribution, click the Continue button below.');
default:
return parent::getText($context, $params);
}
}
/**
* Does this processor support cancelling recurring contributions through code.
*
* @return bool
*/
protected function supportsCancelRecurring() {
return TRUE;
}
}