<?php
/*
+--------------------------------------------------------------------+
- | CiviCRM version 5 |
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2019 |
- +--------------------------------------------------------------------+
- | This file is a part of CiviCRM. |
- | |
- | CiviCRM is free software; you can copy, modify, and distribute it |
- | under the terms of the GNU Affero General Public License |
- | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
- | |
- | CiviCRM is distributed in the hope that it will be useful, but |
- | WITHOUT ANY WARRANTY; without even the implied warranty of |
- | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
- | See the GNU Affero General Public License for more details. |
+ | Copyright CiviCRM LLC. All rights reserved. |
| |
- | You should have received a copy of the GNU Affero General Public |
- | License and the CiviCRM Licensing Exception along |
- | with this program; if not, contact CiviCRM LLC |
- | at info[AT]civicrm[DOT]org. If you have questions about the |
- | GNU Affero General Public License or the licensing of CiviCRM, |
- | see the CiviCRM license FAQ at http://civicrm.org/licensing |
+ | This work is published under the GNU AGPLv3 license with some |
+ | permitted exceptions and without any warranty. For full license |
+ | and copyright information, see https://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
use Civi\Payment\System;
use Civi\Payment\Exception\PaymentProcessorException;
+use Civi\Payment\PropertyBag;
/**
* Class CRM_Core_Payment.
protected $backOffice = FALSE;
/**
- * Contribution that is being paid.
- *
- * @var int
- */
- protected $contributionID;
-
- /**
- * Contact ID for payment.
- *
- * @var int
- */
- protected $contactID;
-
- /**
- * Recurring contribution that is being paid.
- *
- * @var int
- */
- protected $contributionRecurID;
-
- /**
- * Description of purchase.
- *
- * @var string
- */
- protected $description;
-
- /**
- * CiviCRM generated Invoice ID.
- *
- * @var string
- */
- protected $invoiceID;
-
- /**
- * Is this a recurring contribution.
- *
- * @var bool
- */
- protected $isRecur;
-
- /**
- * Payment processor generated string for charging.
- *
- * A payment token could be a single use token (e.g generated by
- * a client side script) or a token that permits recurring or on demand charging.
- *
- * The key thing is it is passed to the processor in lieu of card details to
- * initiate a payment.
- *
- * Generally if a processor is going to pass in a payment token generated through
- * javascript it would add 'payment_token' to the array it returns in it's
- * implementation of getPaymentFormFields. This will add a hidden 'payment_token' field to
- * the form. A good example is client side encryption where credit card details are replaced by
- * an encrypted token using a gateway provided javascript script. In this case the javascript will
- * remove the credit card details from the form before submitting and populate the payment_token field.
- *
- * A more complex example is used by paypal checkout where the payment token is generated
- * via a pre-approval process. In that case the doPreApproval function is called on the processor
- * class to get information to then interact with paypal via js, finally getting a payment token.
- * (at this stage the pre-approve api is not in core but that is likely to change - we just need
- * to think about the permissions since we don't want to expose to anonymous user without thinking
- * through any risk of credit-card testing using it.
- *
- * If the token is not totally transient it would be saved to civicrm_payment_token.token.
- *
- * @var string
- */
- protected $paymentToken;
-
- /**
- * Three digit currency code.
- *
- * @var string
- */
- protected $currency;
-
- /**
- * Payment processor generated string for the transaction ID.
- *
- * Note some gateways generate a reference for the order and one for the
- * payment. This is for the payment reference and is saved to
- * civicrm_financial_trxn.trxn_id.
- *
- * @var string
- */
- protected $transactionID;
-
- /**
- * Amount of money charged in fees by the payment processor.
- *
- * This is notified by (some) payment processers.
- *
- * @var float
- */
- protected $feeAmount;
-
- /**
- * Additional information returned by the payment processor regarding the payment outcome.
+ * This is only needed during the transitional phase. In future you should
+ * pass your own PropertyBag into the method you're calling.
*
- * This would normally be saved in civicrm_financial_trxn.trxn_result_code.
+ * New code should NOT use $this->propertyBag.
*
- * @var string
- */
- protected $trxnResultCode;
-
- /**
- * Combined with recurFrequencyUnit this gives how often billing will take place.
- *
- * e.g every if this is 1 and recurFrequencyUnit is 'month' then it is every 1 month.
- *
- * @var int
+ * @var Civi\Payment\PropertyBag
*/
- protected $recurFrequencyInterval;
+ protected $propertyBag;
/**
- * Combined with recurFrequencyInterval this gives how often billing will take place.
- *
- * e.g every if this is 'month' and recurFrequencyInterval is 1 then it is every 1 month.
+ * Return the payment instrument ID to use.
*
- * @var string
- * month|day|year
- */
- protected $recurFrequencyUnit;
-
- /**
- * Passed in parameters.
- *
- * Using individual getters & setters is preferred but these will be used if
- * they are not available.
- *
- * @var array
- */
- protected $inputParams = [];
-
- /**
- * @return int
- */
- public function getContactID(): int {
- return $this->contactID ?? $this->inputParams['contactID'];
- }
-
- /**
- * @param int $contactID
- */
- public function setContactID(int $contactID) {
- $this->contactID = $contactID;
- }
-
- /**
- * Getter for contributionRecurID.
+ * Note:
+ * We normally SHOULD be returning the payment instrument of the payment processor.
+ * However there is an outstanding case where this needs overriding, which is
+ * when using CRM_Core_Payment_Manual which uses the pseudoprocessor (id = 0).
*
- * Ideally this would always be set by the calling function using the setting
- * but we need to fall back to the historical passing on inputParams as a transition.
+ * i.e. If you're writing a Payment Processor you should NOT be using
+ * setPaymentInstrumentID() at all.
*
- * In time we can add a notice if it's set in input params & not via a setter.
+ * @todo
+ * Ideally this exception-to-the-rule should be handled outside of this class
+ * i.e. this class's getPaymentInstrumentID method should return it from the
+ * payment processor and CRM_Core_Payment_Manual could override it to provide 0.
*
* @return int
*/
- public function getContributionRecurID(): int {
- return $this->contributionRecurID ?? $this->inputParams['contributionRecurID'];
- }
-
- /**
- * @param int $contributionRecurID
- */
- public function setContributionRecurID(int $contributionRecurID) {
- $this->contributionRecurID = $contributionRecurID;
- }
-
- /**
- * Getter for Payment Token.
- *
- * @return string
- */
- public function getPaymentToken(): string {
- return $this->paymentToken ?? $this->inputParams['token'];
- }
-
- /**
- * Setter for Payment Token.
- *
- * @param string $paymentToken
- */
- public function setPaymentToken(string $paymentToken) {
- $this->paymentToken = $paymentToken;
- }
-
- /**
- * Get gateway generated transaction ID.
- *
- * @return string
- */
- public function getTransactionID(): string {
- return $this->transactionID;
- }
-
- /**
- * Set gateway generated transaction ID for the payment.
- *
- * Note some gateways generate a reference for the order and one for the
- * payment. This is for the payment reference and is saved to
- * civicrm_financial_trxn.trxn_id.
- *
- * @param string $transactionID
- */
- public function setTransactionID(string $transactionID) {
- $this->transactionID = $transactionID;
- }
-
- /**
- * Get additional result information received from gateway.
- *
- * This is saved to civicrm_financial_trxn.trxn_result_code.
- *
- * @return string
- */
- public function getTrxnResultCode(): string {
- return $this->trxnResultCode;
- }
-
- /**
- * Set additional result information from gateway.
- *
- * This is saved to civicrm_financial_trxn.trxn_result_code.
- *
- * @param string $resultCode
- */
- public function setTrxnResultCode(string $resultCode) {
- $this->trxnResultCode = $resultCode;
+ public function getPaymentInstrumentID() {
+ return isset($this->paymentInstrumentID)
+ ? $this->paymentInstrumentID
+ : (int) ($this->_paymentProcessor['payment_instrument_id'] ?? 0);
}
/**
- * Get recurring frequency interval.
+ * Getter for the id Payment Processor ID.
*
* @return int
*/
- public function getRecurFrequencyInterval(): int {
- return $this->recurFrequencyInterval ?? $this->inputParams['frequency_interval'];
- }
-
- /**
- * Set recurring frequency interval.
- *
- * @param int $recurFrequencyInterval
- */
- public function setRecurFrequencyInterval(int $recurFrequencyInterval) {
- $this->recurFrequencyInterval = $recurFrequencyInterval;
- }
-
- /**
- * Get recurring frequency unit.
- *
- * @return string
- */
- public function getRecurFrequencyUnit(): string {
- return $this->recurFrequencyUnit;
- }
-
- /**
- * Set recurring frequency unit.
- *
- * @param string $recurFrequencyUnit
- */
- public function setRecurFrequencyUnit(string $recurFrequencyUnit) {
- $this->recurFrequencyUnit = $recurFrequencyUnit ?? $this->inputParams['frequency_unit'];
- }
-
- /**
- * Get invoice ID (CiviCRM generated invoice reference).
- *
- * @return string
- */
- public function getInvoiceID(): string {
- return $this->invoiceID ?? $this->inputParams['invoiceID'];
- }
-
- /**
- * Set invoice ID (CiviCRM generated invoice reference).
- *
- * @param string $invoiceID
- */
- public function setInvoiceID(string $invoiceID) {
- $this->invoiceID = $invoiceID;
- }
-
- /**
- * Get whether the payment is recurring.
- *
- * @return bool
- */
- public function isRecur(): bool {
- return $this->isRecur;
- }
-
- /**
- * Set whether the payment is recurring.
- *
- * @param bool $isRecur
- */
- public function setIsRecur(bool $isRecur) {
- $this->isRecur = $isRecur ?? $this->inputParams['is_recur'];
- }
-
- /**
- * Get the description.
- *
- * This generates a description string from params if one has been passed in but
- * ideally calling functions would use the setDescription function.
- *
- * @return string
- */
- public function getDescription(): string {
- if ($this->description) {
- return $this->description;
- }
- if (isset($this->inputParams['description'])) {
- $uninformativeStrings = [
- ts('Online Event Registration: '),
- ts('Online Contribution: '),
- ];
- $this->description = str_replace($uninformativeStrings, '', $this->inputParams['description']);
- }
- return $this->description;
- }
-
- /**
- * Set description.
- *
- * Generally this should be called when instantiating the processor to override
- * getPaymentDescription, if desired.
- *
- * @param string $description
- */
- public function setDescription(string $description) {
- $this->description = $description;
- }
-
- /**
- * Get fee amount returned by processor.
- *
- * @return float
- */
- public function getFeeAmount(): float {
- return $this->feeAmount;
- }
-
- /**
- * Set fee amount returned by processor.
- *
- * @param float $feeAmount
- */
- public function setFeeAmount(float $feeAmount) {
- $this->feeAmount = $feeAmount;
+ public function getID() {
+ return (int) $this->_paymentProcessor['id'];
}
/**
- * Get the contribution ID.
+ * @deprecated Set payment Instrument id - see note on getPaymentInstrumentID.
*
- * We prefer the one set by the setter but traditional forms just pass in 'contributionID'.
+ * By default we actually ignore the form value. The manual processor takes
+ * it more seriously.
*
- * @return int
- */
- public function getContributionID(): int {
- return $this->contributionID ?? $this->inputParams['contributionID'];
- }
-
- /**
- * @param int $contributionID
+ * @param int $paymentInstrumentID
*/
- public function setContributionID(int $contributionID) {
- $this->contributionID = $contributionID;
+ public function setPaymentInstrumentID($paymentInstrumentID) {
+ $this->paymentInstrumentID = (int) $paymentInstrumentID;
+ // See note on getPaymentInstrumentID().
+ return $this->getPaymentInstrumentID();
}
/**
$this->backOffice = $isBackOffice;
}
- /**
- * Get payment instrument id.
- *
- * @return int
- */
- public function getPaymentInstrumentID() {
- return $this->paymentInstrumentID ? $this->paymentInstrumentID : $this->_paymentProcessor['payment_instrument_id'];
- }
-
- /**
- * Getter for the id.
- *
- * @return int
- */
- public function getID() {
- return (int) $this->_paymentProcessor['id'];
- }
-
- /**
- * Set payment Instrument id.
- *
- * By default we actually ignore the form value. The manual processor takes it more seriously.
- *
- * @param int $paymentInstrumentID
- */
- public function setPaymentInstrumentID($paymentInstrumentID) {
- $this->paymentInstrumentID = $this->_paymentProcessor['payment_instrument_id'];
- }
-
/**
* Set base return path (offsite processors).
*
*
* @return array
* field metadata
- *
- * @throws \Exception
*/
public function getPaymentFormFieldsMetadata() {
//@todo convert credit card type into an option value
}
/**
- * Get the currency for the transaction.
+ * Get the currency for the transaction from the params.
+ *
+ * Legacy wrapper. Better for a method to work on its own PropertyBag.
*
- * Handle any inconsistency about how it is passed in here.
+ * This code now uses PropertyBag to allow for old inputs like currencyID.
*
* @param $params
*
* @return string
*/
protected function getCurrency($params = []) {
- $params = array_merge($params, (array) $this->inputParams);
- return $this->currency ?? CRM_Utils_Array::value('currencyID', $params, CRM_Utils_Array::value('currency', $params));
+ $localPropertyBag = new PropertyBag();
+ $localPropertyBag->mergeLegacyInputParams($params);
+ return $localPropertyBag->getCurrency();
}
/**
- * Get the currency for the transaction.
- *
- * Handle any inconsistency about how it is passed in here.
+ * Legacy. Better for a method to work on its own PropertyBag,
+ * but also, this function does not do very much.
*
* @param array $params
*
* @throws \CRM_Core_Exception
*/
protected function getAmount($params = []) {
- $amount = $this->amount ?? $params['amount'];
- return CRM_Utils_Money::format($amount, NULL, NULL, TRUE);
+ return CRM_Utils_Money::format($params['amount'], NULL, NULL, TRUE);
}
/**
return $params;
}
+ /**
+ * Processors may need to inspect, validate, cast and copy data that is
+ * specific to this Payment Processor from the input array to custom fields
+ * on the PropertyBag.
+ *
+ * @param Civi\Payment\PropertyBag $propertyBag
+ * @param array $params
+ * @param string $component
+ *
+ * @throws \Civi\Payment\Exception\PaymentProcessorException
+ */
+ public function extractCustomPropertiesForDoPayment(PropertyBag $propertyBag, array $params, $component = 'contribute') {
+ // example
+ // (validation and casting goes first)
+ // $propertyBag->setCustomProperty('myprocessor_customPropertyName', $value);
+ }
+
/**
* Process payment - this function wraps around both doTransferCheckout and doDirectPayment.
* Any processor that still implements the deprecated doTransferCheckout() or doDirectPayment() should be updated to use doPayment().
* For the current status see: https://lab.civicrm.org/dev/financial/issues/53
* If we DO have a contribution ID, then the payment processor can (and should) update parameters on the contribution record as necessary.
*
- * @param array $params
+ * @param array|PropertyBag $params
*
* @param string $component
*
* @throws \Civi\Payment\Exception\PaymentProcessorException
*/
public function doPayment(&$params, $component = 'contribute') {
- $this->inputParams = $params;
$this->_component = $component;
$statuses = CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'validate');
* @return string
*/
protected function getPaymentDescription($params = [], $length = 24) {
+ $propertyBag = PropertyBag::cast($params);
$parts = [
- 'contactID',
- 'contributionID',
- 'description',
- 'billing_first_name',
- 'billing_last_name',
+ $propertyBag->getter('contactID', TRUE),
+ $propertyBag->getter('contributionID', TRUE),
+ $propertyBag->getter('description', TRUE) ?: ($propertyBag->getter('isRecur', TRUE) ? ts('Recurring payment') : NULL),
+ $propertyBag->getter('billing_first_name', TRUE),
+ $propertyBag->getter('billing_last_name', TRUE),
];
- $validParts = [];
- $params['description'] = $this->getDescription();
- foreach ($parts as $part) {
- if ((!empty($params[$part]))) {
- $validParts[] = $params[$part];
- }
- }
- return substr(implode('-', $validParts), 0, $length);
+ return substr(implode('-', array_filter($parts)), 0, $length);
}
/**
- * Checks if backoffice recurring edit is allowed
+ * Checks if back-office recurring edit is allowed
*
* @return bool
*/