payment.classes.inc in Payment 7
The API and related functions for executing and managing payments.
File
payment.classes.incView source
<?php
/**
* @file
* The API and related functions for executing and managing payments.
*/
/**
* Base class with common functionality.
*/
class PaymentCommon {
function __construct(array $properties = array()) {
foreach ($properties as $property => $value) {
$this->{$property} = $value;
}
}
}
/**
* A single payment. Contains all payment-specific data.
*
* @see PaymentMethod
* @see PaymentMethodController
*/
class Payment extends PaymentCommon {
/**
* The machine name of the context that created this Payment, such as the
* webshop module.
*
* @var string
*/
public $context = '';
/**
* Information about this payment that is specific to the context that
* created it, such as the webshop module.
*
* @var mixed[]
*/
public $context_data = array();
/**
* The ISO 4217 currency code of the payment amount.
*
* @var string
*/
public $currency_code = 'XXX';
/**
* The general description of this payment. Not to be confused with line item
* descriptions.
*
* @var string
*/
public $description = '';
/**
* Arguments to pass on to t() when translating $this->description.
*
* @var string[]
*/
public $description_arguments = array();
/**
* The name of a function to call when payment execution is completed,
* regardless of the payment status. It receives one argument:
* - $payment Payment
* The Payment object.
* The callback does not need to return anything and is free to redirect the
* user or display something.
* Use Payment::context_data to pass on arbitrary data to the finish callback.
*
* @var string
*/
public $finish_callback = '';
/**
* An array with PaymentLineItem objects.
*
* @see Payment::setLineItem()
*
* @var PaymentLineItem[]
*/
public $line_items = array();
/**
* The payment method used for this payment.
*
* @var PaymentMethod
*/
public $method = NULL;
/**
* Information about this payment that is specific to its payment method.
*
* @var mixed[]
*/
public $method_data = array();
/**
* The internal ID of this payment.
*
* @var integer
*/
public $pid = 0;
/**
* The status log. Contains PaymentStatusItem objects ordered by datetime. Do
* not set directly, but use Payment::setStatus() instead.
*
* @see Payment::setStatus()
*
* @var PaymentStatusItem[]
*/
public $statuses = array();
/**
* The UID of the user this payment belongs to.
*
* @var integer
*/
public $uid = NULL;
/**
* Constructor.
*
* @param mixed[] $properties
* An associative array. Keys are property names and values are property
* values.
*/
function __construct(array $properties = array()) {
global $user;
parent::__construct($properties);
if (is_null($this->uid)) {
$this->uid = $user->uid;
}
if (!$this->statuses) {
// We purposefully avoid Payment::setStatus(), because this is the
// payment's first status.
$this->statuses[] = new PaymentStatusItem(PAYMENT_STATUS_NEW);
}
}
/**
* Execute the actual payment.
*/
function execute() {
// Preprocess the payment.
module_invoke_all('payment_pre_execute', $this);
if (module_exists('rules')) {
rules_invoke_event('payment_pre_execute', $this);
}
// Execute the payment.
if ($this->method) {
try {
$this->method
->validate($this);
$this
->setStatus(new PaymentStatusItem(PAYMENT_STATUS_PENDING));
$this->method->controller
->execute($this);
} catch (PaymentValidationException $e) {
$this
->setStatus(new PaymentStatusItem(PAYMENT_STATUS_FAILED));
}
}
else {
$this
->setStatus(new PaymentStatusItem(PAYMENT_STATUS_FAILED));
}
// This is only called if the payment execution didn't redirect the user
// offsite. Otherwise it's the payment method return page's responsibility.
$this
->finish();
}
/**
* Finish the payment after its execution.
*/
function finish() {
entity_save('payment', $this);
module_invoke_all('payment_pre_finish', $this);
if (module_exists('rules')) {
rules_invoke_event('payment_pre_finish', $this);
}
call_user_func($this->finish_callback, $this);
}
/**
* Set a line item.
*
* @see Payment::getLineItems()
*
* @param PaymentLineItem $line_item
*
* @return static
*/
function setLineItem(PaymentLineItem $line_item) {
$this->line_items[$line_item->name] = $line_item;
return $this;
}
/**
* Get line items.
*
* @param string|null $name (optional)
* The requested line item(s)'s machine name, as possibly defined in
* hook_payment_line_item_info(). If $name is NULL, then all line items
* will be returned.
*
* @return PaymentLineItem[]
* An array with matching PaymentLineItem objects.
*/
function getLineItems($name = NULL) {
if (is_null($name)) {
return payment_line_item_get_all($name, $this);
}
elseif ($line_item_info = payment_line_item_info($name)) {
return call_user_func($line_item_info->callback, $name, $this);
}
else {
return payment_line_item_get_specific($name, $this);
}
}
/**
* Get the total payment amount.
*
* @param boolean $tax
* Whether to include taxes or not.
* @param PaymentLineItem[]|null $line_items
* An array with PaymentLineItem objects to calculate the total from.
* Leave empty to use $this->line_items.
*
* @return float
*/
function totalAmount($tax, array $line_items = NULl) {
$total = 0;
if (is_null($line_items)) {
$line_items = $this->line_items;
}
foreach ($line_items as $line_item) {
$total += $line_item
->totalAmount($tax);
}
return $total;
}
/**
* Set the payment status.
*
* @param PaymentStatusItem $status_item
*
* @return static
*/
function setStatus(PaymentStatusItem $status_item) {
$previous_status_item = $this
->getStatus();
$status_item->pid = $this->pid;
$this->statuses[] = $status_item;
foreach (module_implements('payment_status_change') as $module_name) {
call_user_func($module_name . '_payment_status_change', $this, $previous_status_item);
// If a hook invocation has added another log item, a new loop with
// invocations has already been executed and we don't need to continue
// with this one.
if ($this
->getStatus() !== $status_item) {
return $this;
}
}
if (module_exists('rules')) {
rules_invoke_event('payment_status_change', $this, $previous_status_item);
}
return $this;
}
/**
* Get the current payment status.
*
* @return PaymentStatusItem
*/
function getStatus() {
return end($this->statuses);
}
/**
* Get available/valid payment methods for this payment.
*
* @param PaymentMethod[] $payment_methods
* Use an empty array to check the availability of all payment methods.
*
* @return PaymentMethod[]
* An array with payment methods usable for Payment in its current state,
* keyed by PMID.
*/
function availablePaymentMethods(array $payment_methods = array()) {
if (!$payment_methods) {
$payment_methods = entity_load('payment_method', FALSE);
}
$available = array();
foreach ($payment_methods as $payment_method) {
try {
$payment_method
->validate($this, FALSE);
$available[$payment_method->pmid] = $payment_method;
} catch (PaymentValidationException $e) {
}
}
return $available;
}
}
/**
* Entity API controller for payment entities.
*/
class PaymentEntityController extends EntityAPIController {
/**
* {@inheritdoc}
*/
function load($ids = array(), $conditions = array()) {
$entities = parent::load($ids, $conditions);
foreach ($entities as $payment) {
// Cast non-string scalars to their original types, because some backends
// store/return all variables as strings.
$payment->pid = (int) $payment->pid;
$payment->uid = (int) $payment->uid;
}
return $entities;
}
/**
* {@inheritdoc}
*/
function attachLoad(&$queried_entities, $revision_id = FALSE) {
$pids = array_keys($queried_entities);
// Load the payments's payment methods.
$pmids = array();
foreach ($queried_entities as $payment) {
$pmids[] = $payment->pmid;
}
$methods = entity_load('payment_method', $pmids);
// Load line items.
$result = db_select('payment_line_item')
->fields('payment_line_item')
->condition('pid', $pids)
->execute();
$line_items = array();
while ($line_item_data = $result
->fetchAssoc('name', PDO::FETCH_ASSOC)) {
$line_item_data['description_arguments'] = unserialize($line_item_data['description_arguments']);
$line_item_data['amount'] = (double) $line_item_data['amount'];
$line_item_data['tax_rate'] = (double) $line_item_data['tax_rate'];
$line_item_data['quantity'] = (double) $line_item_data['quantity'];
$line_items[$line_item_data['pid']][$line_item_data['name']] = new PaymentLineItem($line_item_data);
}
// Load the payments's status items.
$result = db_select('payment_status_item')
->fields('payment_status_item')
->condition('pid', $pids)
->orderBy('psiid')
->execute();
$status_items = array();
while ($data = $result
->fetchObject()) {
$status_item = new PaymentStatusItem($data->status, $data->created, $data->pid, $data->psiid);
$status_items[$status_item->pid][] = $status_item;
}
// Add all data to the payments.
foreach ($queried_entities as $payment) {
$payment->statuses = $status_items[$payment->pid];
$payment->line_items = isset($line_items[$payment->pid]) ? $line_items[$payment->pid] : array();
$payment->method = $methods[$payment->pmid];
unset($payment->pmid);
}
parent::attachLoad($queried_entities, $revision_id);
}
/**
* {@inheritdoc}
*/
function save($entity, DatabaseTransaction $transaction = NULL) {
$payment = $entity;
// Save the payment.
$payment->pmid = $payment->method->pmid;
$return = parent::save($payment, $transaction);
unset($payment->pmid);
return $return;
}
/**
* Save the line items and payment status items if needed.
*
* @param Payment $payment
* The payment object.
*/
function saveAttachedData($payment) {
// Save line items.
foreach ($payment->line_items as $line_item) {
$schema = drupal_get_schema('payment_line_item');
$fields = $schema['fields'];
$data = array();
foreach ($fields as $column => $spec) {
if (property_exists($line_item, $column)) {
$data[$column] = $line_item->{$column};
if (!empty($spec['serialize'])) {
$data[$column] = serialize($data[$column]);
}
}
}
unset($data['pid']);
unset($data['name']);
$data['amount_total'] = $line_item->amount * $line_item->quantity * ($line_item->tax_rate + 1);
db_merge('payment_line_item')
->key(array(
'name' => $line_item->name,
'pid' => $payment->pid,
))
->fields($data)
->execute();
}
// Save the payment's status items.
$update = empty(reset($payment->statuses)->psiid) || empty(end($payment->statuses)->psiid);
foreach ($payment->statuses as $status_item) {
// Statuses cannot be edited, so only save the ones without a PSIID set.
if (!$status_item->psiid) {
$status_item->pid = $payment->pid;
drupal_write_record('payment_status_item', $status_item);
}
}
if ($update) {
$payment->psiid_first = reset($payment->statuses)->psiid;
$payment->psiid_last = end($payment->statuses)->psiid;
$query = db_update('payment')
->condition('pid', $payment->pid)
->fields(array(
'psiid_first' => reset($payment->statuses)->psiid,
'psiid_last' => end($payment->statuses)->psiid,
));
$query
->execute();
}
}
/**
* {@inheritdoc}
*/
function view($entities, $view_mode = 'full', $langcode = NULL, $page = NULL) {
$build = parent::view($entities, $view_mode, $langcode, $page);
$type = 'payment';
foreach ($build['payment'] as &$payment_build) {
$payment = $payment_build['#entity'];
$payment_build['payment_line_items'] = payment_line_items($payment);
$payment_build['payment_status_items'] = payment_status_items($payment);
$payment_build['payment_method'] = array(
'#type' => 'item',
'#title' => t('Payment method'),
'#markup' => check_plain($payment->method->title_generic),
);
drupal_alter(array(
'payment_view',
'entity_view',
), $payment_build, $type);
}
return $build;
}
/**
* {@inheritdoc}
*/
function delete($ids, DatabaseTransaction $transaction = NULL) {
parent::delete($ids, $transaction);
db_delete('payment_line_item')
->condition('pid', $ids)
->execute();
db_delete('payment_status_item')
->condition('pid', $ids)
->execute();
}
}
/**
* Payment method configuration.
*
* @see Payment
* @see PaymentMethodController
*/
class PaymentMethod extends PaymentCommon {
/**
* The payment method controller this merchant uses.
*
* @var PaymentMethodController
*/
public $controller = NULL;
/**
* Information about this payment method that is specific to its controller.
*
* @var mixed[]
*/
public $controller_data = array();
/**
* Whether this payment method is enabled and can be used.
*
* @var boolean
*/
public $enabled = TRUE;
/**
* The entity's unique machine name.
*
* @var string
*/
public $name = '';
/**
* The machine name of the module that created this payment method.
*
* @var string
*/
public $module = 'payment';
/**
* The unique internal ID.
*
* @var integer
*/
public $pmid = 0;
/**
* One of Entity API's ENTITY_* constants for exportable entities.
*
* @see entity_has_status()
*
* @var integer
*/
public $status = ENTITY_CUSTOM;
/**
* The specific human-readable title, e.g. "Paypal WPS".
*
* @var string
*/
public $title_specific = '';
/**
* The generic human-readable title, e.g. "Paypal".
*
* @var string
*/
public $title_generic = '';
/**
* The UID of the user this payment method belongs to.
*
* @var integer
*/
public $uid = NULL;
/**
* {@inheritdoc}
*/
function __construct(array $properties = array()) {
global $user;
parent::__construct($properties);
if (is_null($this->uid)) {
// Cast non-string scalars to their original types, because some backends
// store/return all variables as strings.
$this->uid = (int) $user->uid;
}
}
/**
* Validate a payment against this payment method.
*
* @param Payment $payment
* @param boolean $strict
* Whether to validate everything a payment method needs or to validate the
* most important things only. Useful when finding available payment methods,
* for instance, which does not require unimportant things to be a 100%
* valid.
*
* @throws PaymentValidationException
*/
function validate(Payment $payment, $strict = TRUE) {
$this->controller
->validate($payment, $this, $strict);
module_invoke_all('payment_validate', $payment, $this, $strict);
if (module_exists('rules')) {
rules_invoke_event('payment_validate', $payment, $this, $strict);
}
}
}
/**
* A payment method that essentially disables payments.
*
* This is a 'placeholder' method that returns defaults and doesn't really do
* anything else. It is used when no working payment method is available, so
* other modules don't have to check for that.
*/
class PaymentMethodUnavailable extends PaymentMethod {
public $enabled = FALSE;
public $name = 'payment_method_unavailable';
public $module = 'payment';
// Use 0, so the payment method can be used for payments, but will never
// collide with existing payment methods.
public $pmid = 0;
/**
* {@inheritdoc}
*/
function __construct() {
$this->title_specific = $this->title_generic = t('Unavailable');
$this->controller = payment_method_controller_load('PaymentMethodControllerUnavailable');
}
}
/**
* Entity API controller for payment_method entities.
*/
class PaymentMethodEntityController extends EntityAPIControllerExportable {
/**
* {@inheritdoc}
*/
function load($ids = array(), $conditions = array()) {
static $unavailable = NULL;
$entities = parent::load($ids, $conditions);
foreach ($entities as $payment_method) {
// Cast non-string scalars to their original types, because some backends
// store/return all variables as strings.
$payment_method->enabled = (bool) $payment_method->enabled;
$payment_method->pmid = (int) $payment_method->pmid;
$payment_method->status = (int) $payment_method->status;
$payment_method->uid = (int) $payment_method->uid;
}
// Load PaymentMethodUnavailable for all requested IDs that did not match
// any existing payment methods.
if (is_array($ids)) {
// If the entities were loaded by PID.
if (is_numeric(reset($ids))) {
$diff = array_diff($ids, array_keys($entities));
}
else {
$names = array();
foreach ($entities as $entity) {
$names[] = $entity->name;
}
$diff = array_diff($ids, $names);
}
if ($diff && is_null($unavailable)) {
$unavailable = new PaymentMethodUnavailable();
}
foreach ($diff as $pmid) {
$entities[$pmid] = $unavailable;
}
ksort($entities);
}
return $entities;
}
/**
* {@inheritdoc}
*/
function attachLoad(&$queries_entities, $revision_id = FALSE) {
foreach ($queries_entities as $entity) {
$entity->controller = payment_method_controller_load($entity->controller_class_name);
if (!$entity->controller) {
$entity->controller = payment_method_controller_load('PaymentMethodControllerUnavailable');
}
unset($entity->controller_class_name);
}
parent::attachLoad($queries_entities, $revision_id);
}
/**
* {@inheritdoc}
*/
function save($entity, DatabaseTransaction $transaction = NULL) {
$entity->controller_class_name = $entity->controller->name;
$return = parent::save($entity, $transaction);
// Cast non-string scalars to their original types, because some backends
// store/return all variables as strings.
$entity->pmid = (int) $entity->pmid;
unset($entity->controller_class_name);
return $return;
}
/**
* {@inheritdoc}
*/
function export($entity, $prefix = '') {
// The payment method controller should not be exported. Instead, we
// temporarily replace it with a property that only stores its class name.
$controller = $entity->controller;
$entity->controller_class_name = $controller->name;
unset($entity->controller);
$export = parent::export($entity, $prefix);
$entity->controller = $controller;
unset($entity->controller_class_name);
return $export;
}
/**
* {@inheritdoc}
*/
function import($export) {
if ($payment = parent::import($export)) {
$payment->controller = payment_method_controller_load($payment->controller_class_name);
unset($payment->controller_class_name);
return $payment;
}
return FALSE;
}
}
/**
* Features controller for payment_method entities.
*/
class PaymentMethodFeaturesController extends EntityDefaultFeaturesController {
/**
* {@inheritdoc}
*/
function export($data, &$export, $module_name = '') {
$pipe = parent::export($data, $export, $module_name);
// Add dependencies for the payment method controller classes.
$controller_class_names = array();
foreach (entity_load_multiple_by_name($this->type, $data) as $method) {
$controller_class_names[] = $method->controller->name;
}
$result = db_select('registry')
->fields('registry', array(
'module',
))
->condition('name', $controller_class_names)
->condition('type', 'class')
->execute();
while ($module = $result
->fetchField()) {
$export['dependencies'][$module] = $module;
}
return $pipe;
}
}
/**
* A payment method controller, e.g. the logic behind a payment method.
*
* @see payment_method_controller_load()
* @see payment_method_controller_load_multiple()
*
* All other payment methods need to extend this class. This is a singleton
* class. See payment_method_controller_load().
*
* @see Payment
* @see PaymentMethod
*/
class PaymentMethodController {
/**
* Default values for the controller_data property of a PaymentMethod that
* uses this controller.
*
* @var mixed[]
*/
public $controller_data_defaults = array();
/**
* An array with ISO 4217 currency codes that this controller supports.
*
* Keys are ISO 4217 currency codes. Values are associative arrays with keys
* "minimum" and "maximum", whose values are the minimum and maximum amount
* supported for the specified currency. Leave empty to allow all currencies.
*
* @var array[]
*/
public $currencies = array();
/**
* A human-readable plain text description of this payment method controller.
*
* @var string
*/
public $description = '';
/**
* The machine name.
*
* This will be set by payment_method_controller_load_multiple() as a
* shorthand for get_class($payment_method_controller).
*
* @see payment_method_controller_load_multiple()
*
* @var string
*/
public $name = '';
/**
* The function name of the payment configuration form elements.
*
* Note that this is not a form ID and because the form will not be called
* using drupal_get_form(), it can only be altered by altering the form
* payment_form(). The validate callback is expected to be a function with
* the same name, but suffixed with "_validate". If this function exists, it
* will be called automatically. $form_state['payment'] contains the Payment
* that is added or edited. All method-specific information should be added
* to it in the validate callback. The payment will be saved automatically
* using entity_save().
*
* The function accepts its parent form element and &$form_state as
* parameters. It should return an array of form elements.
*
* @see payment_element_info()
* @see payment_form_method_process()
* @see payment_form_process_method_controller_payment_configuration()
* @see paymentmethodbasic_payment_configuration_form_elements()
*
* @var string
*/
public $payment_configuration_form_elements_callback = '';
/**
* The function name of the payment method configuration form elements.
*
* Note that this is not a form ID and because the form will not be called
* using drupal_get_form(), it can only be altered by altering the form
* payment_form_payment_method(). The validate callback is expected to be a
* function with the same name, but suffixed with "_validate". If this
* function exists, it will be called automatically.
* $form_state['payment_method'] contains the PaymentMethod that is added or
* edited. All controller-specific information should be added to it in the
* validate callback. The payment method will be saved automatically using
* entity_save().
*
* The function accepts its parent form element and &$form_state as
* parameters. It should return an array of form elements.
*
* @see payment_form_payment_method()
* @see paymentmethodbasic_payment_method_configuration_form_elements()
*
* @var string
*/
public $payment_method_configuration_form_elements_callback = '';
/**
* The human-readable plain text title.
*
* @var string
*/
public $title = '';
/**
* Execute a payment.
*
* Note that payments may be executed even if their owner is not logged into
* the site. This means that if you need to do access control in your
* execute() method, you cannot use global $user.
*
* @param Payment $payment
*
* @return boolean
* Whether the payment was successfully executed or not.
*/
function execute(Payment $payment) {
}
/**
* Validate a payment against a payment method and this controller. Don't
* call directly. Use PaymentMethod::validate() instead.
*
* @see PaymentMethod::validate()
*
* @param Payment $payment
* @param PaymentMethod $payment_method
* @param boolean $strict
* Whether to validate everything a payment method needs or to validate the
* most important things only. Useful when finding available payment methods,
* for instance, which does not require unimportant things to be a 100%
* valid.
*
* @throws PaymentValidationException
*/
function validate(Payment $payment, PaymentMethod $payment_method, $strict) {
// Confirm the payment method is enabled, and thus available in general.
if (!$payment_method->enabled) {
throw new PaymentValidationPaymentMethodDisabledException(t('The payment method is disabled.'));
}
if (!$payment->currency_code) {
throw new PaymentValidationMissingCurrencyException(t('The payment has no currency set.'));
}
$currencies = $payment_method->controller->currencies;
// Confirm the payment's currency is supported.
if (!empty($this->currencies) && !isset($this->currencies[$payment->currency_code])) {
throw new PaymentValidationUnsupportedCurrencyException(t('The currency is not supported by this payment method.'));
}
// Confirm the payment's description is set and valid.
if (empty($payment->description)) {
throw new PaymentValidationDescriptionMissing(t('The payment description is not set.'));
}
elseif (drupal_strlen($payment->description) > 255) {
throw new PaymentValidationDescriptionTooLong(t('The payment description exceeds 255 characters.'));
}
// Confirm the finish callback is set and the function exists.
if (empty($payment->finish_callback) || !function_exists($payment->finish_callback)) {
throw new PaymentValidationMissingFinishCallback(t('The finish callback is not set or not callable.'));
}
// Confirm the payment amount is higher than the supported minimum.
$minimum = isset($currencies[$payment->currency_code]['minimum']) ? $currencies[$payment->currency_code]['minimum'] : PAYMENT_MINIMUM_AMOUNT;
if ($payment
->totalAmount(TRUE) < $minimum) {
throw new PaymentValidationAmountBelowMinimumException(t('The amount should be higher than !minimum.', array(
'!minimum' => payment_amount_human_readable($minimum, $payment->currency_code),
)));
}
// Confirm the payment amount does not exceed the maximum.
if (isset($currencies[$payment->currency_code]['maximum']) && $payment
->totalAmount(TRUE) > $currencies[$payment->currency_code]['maximum']) {
throw new PaymentValidationAmountExceedsMaximumException(t('The amount should be lower than !maximum.', array(
'!maximum' => payment_amount_human_readable($currencies[$payment->currency_code]['maximum'], $payment->currency_code),
)));
}
}
/**
* Returns an array with the names of all available payment method
* controllers that inherit of this one.
*
* return string[]
*/
static function descendants() {
$descendants = array();
foreach (payment_method_controllers_info() as $controller_name) {
if (is_subclass_of($controller_name, get_called_class())) {
$descendants[] = $controller_name;
}
}
return $descendants;
}
}
/**
* A payment method controller that essentially disables payment methods.
*
* This is a 'placeholder' controller that returns defaults and doesn't really
* do anything else. It is used when no working controller is available for a
* payment method, so other modules don't have to check for that.
*/
class PaymentMethodControllerUnavailable extends PaymentMethodController {
/**
* {@inheritdoc}
*/
function __construct() {
$this->title = t('Unavailable');
}
/**
* {@inheritdoc}
*/
function execute(Payment $payment) {
$payment
->setStatus(new PaymentStatusItem(PAYMENT_STATUS_UNKNOWN));
}
/**
* {@inheritdoc}
*/
function validate(Payment $payment, PaymentMethod $payment_method, $strict) {
throw new PaymentValidationException(t('This payment method type is unavailable.'));
}
}
/**
* Payment status information.
*/
class PaymentStatusInfo extends PaymentCommon {
/**
* A US English human-readable plain text description.
*
* @var string
*/
public $description = '';
/**
* This status's parent status.
*
* @var string
*/
public $parent = NULL;
/**
* The status itself.
*
* @var string
*/
public $status = '';
/**
* A US English human-readable plain text title.
*
* @var string
*/
public $title = '';
/**
* Get this payment status's ancestors.
*
* @return string[]
* The machine names of this status's ancestors.
*/
function ancestors() {
$ancestors = array(
$this->parent,
);
if ($this->parent) {
$ancestors = array_merge($ancestors, payment_status_info($this->parent)
->ancestors());
}
return array_unique($ancestors);
}
/**
* Get this payment status's children.
*
* @return string[]
* The machine names of this status's children.
*/
function children() {
$children = array();
foreach (payment_statuses_info() as $status_info) {
if ($status_info->parent == $this->status) {
$children[] = $status_info->status;
}
}
return $children;
}
/**
* Get this payment status's descendants.
*
* @return string[]
* The machine names of this status's descendants.
*/
function descendants() {
$children = $this
->children();
$descendants = $children;
foreach ($children as $child) {
$descendants = array_merge($descendants, payment_status_info($child)
->descendants());
}
return array_unique($descendants);
}
}
/**
* A payment line item.
*
* @see Payment::setLineItem()
*/
class PaymentLineItem extends PaymentCommon {
/**
* The payment amount, excluding tax. The number of decimals depends on the
* ISO 4217 currency used.
*
* @var float
*/
public $amount = 0.0;
/**
* A US English human-readable description for this line item. May contain
* HTML.
*
* @var string
*/
public $description = '';
/**
* Arguments to pass on to t() when translating $this->description.
*
* @var string[]
*/
public $description_arguments = array();
/**
* The unique machine name (for a certain payment).
*
* @var string
*/
public $name = '';
/**
* The tax rate that applies to PaymentLineItem::amount. Should be a float
* between 0 and 1.
*
* @var float
*/
public $tax_rate = 0.0;
/**
* Quantity.
*
* @var float
*/
public $quantity = 1.0;
/**
* Return this line item's unit amount.
*
* @param boolean $tax
* Whether to include taxes or not.
*
* @return float
*/
function unitAmount($tax) {
return $this->amount * ($tax ? $this->tax_rate + 1 : 1);
}
/**
* Return this line item's total amount.
*
* @param boolean $tax
* Whether to include taxes or not.
*
* @return float
*/
function totalAmount($tax) {
return $this->amount * $this->quantity * ($tax ? $this->tax_rate + 1 : 1);
}
}
/**
* A payment status line item.
*/
class PaymentStatusItem {
/**
* The status itself.
*
* @var string
*/
public $status = '';
/**
* The Unix datetime this status was set.
*
* @var integer
*/
public $created = 0;
/**
* The PID of the payment this status item belongs to.
*
* @var integer
*/
public $pid = 0;
/**
* The unique internal ID of this payment status item.
*
* @var integer
*/
public $psiid = 0;
function __construct($status, $created = 0, $pid = 0, $psiid = 0) {
$this->status = $status;
$this->created = $created ? $created : time();
$this->pid = $pid;
$this->psiid = $psiid;
}
}
/**
* Information about a line item type.
*/
class PaymentLineItemInfo extends PaymentCommon {
/**
* The callback function to get this line item from the Payment.
*
* The function accepts the machine name of the line item to get and the
* Payment object to get it from as parameters. It should return an array,
* optionally filled with PaymentLineItem objects.
*
* @see Payment::getLineItems()
* @see payment_line_item_get_all()
*
* @var string
*/
public $callback = 'payment_line_item_get_specific';
/**
* The unique (for this payment) machine name.
*
* @var string
*/
public $name = '';
/**
* The human-readable plain text title.
*
* @var string
*/
public $title = '';
}
/**
* A Payment-related exception.
*/
class PaymentException extends Exception {
/**
* {@inheritdoc}
*/
function __construct($message = '', $code = 0, Exception $previous = NULL) {
parent::__construct($message, $code, $previous);
payment_debug($this
->getMessage(), $this
->getFile(), $this
->getLine());
}
}
/**
* Exception thrown if a payment is not valid.
*/
class PaymentValidationException extends PaymentException {
}
/**
* Exception thrown if a payment's total amount is below the required minimum.
*/
class PaymentValidationAmountBelowMinimumException extends PaymentValidationException {
}
/**
* Exception thrown if a payment's total amount exceeds the supported maximum.
*/
class PaymentValidationAmountExceedsMaximumException extends PaymentValidationException {
}
/**
* Exception thrown if a payment has no currency set.
*/
class PaymentValidationMissingCurrencyException extends PaymentValidationException {
}
/**
* Exception thrown if a payment uses a currency that is unsupported by a
* payment method.
*/
class PaymentValidationUnsupportedCurrencyException extends PaymentValidationException {
}
/**
* Exception thrown if a payment's finish callback is not set or the function
* does not exist.
*/
class PaymentValidationMissingFinishCallback extends PaymentValidationException {
}
/**
* Exception thrown if a payment's description is missing.
*/
class PaymentValidationDescriptionMissing extends PaymentValidationException {
}
/**
* Exception thrown if a payment's description is too long.
*/
class PaymentValidationDescriptionTooLong extends PaymentValidationException {
}
/**
* Exception thrown if a payment method is disabled.
*/
class PaymentValidationPaymentMethodDisabledException extends PaymentValidationException {
}
Classes
Name![]() |
Description |
---|---|
Payment | A single payment. Contains all payment-specific data. |
PaymentCommon | Base class with common functionality. |
PaymentEntityController | Entity API controller for payment entities. |
PaymentException | A Payment-related exception. |
PaymentLineItem | A payment line item. |
PaymentLineItemInfo | Information about a line item type. |
PaymentMethod | Payment method configuration. |
PaymentMethodController | A payment method controller, e.g. the logic behind a payment method. |
PaymentMethodControllerUnavailable | A payment method controller that essentially disables payment methods. |
PaymentMethodEntityController | Entity API controller for payment_method entities. |
PaymentMethodFeaturesController | Features controller for payment_method entities. |
PaymentMethodUnavailable | A payment method that essentially disables payments. |
PaymentStatusInfo | Payment status information. |
PaymentStatusItem | A payment status line item. |
PaymentValidationAmountBelowMinimumException | Exception thrown if a payment's total amount is below the required minimum. |
PaymentValidationAmountExceedsMaximumException | Exception thrown if a payment's total amount exceeds the supported maximum. |
PaymentValidationDescriptionMissing | Exception thrown if a payment's description is missing. |
PaymentValidationDescriptionTooLong | Exception thrown if a payment's description is too long. |
PaymentValidationException | Exception thrown if a payment is not valid. |
PaymentValidationMissingCurrencyException | Exception thrown if a payment has no currency set. |
PaymentValidationMissingFinishCallback | Exception thrown if a payment's finish callback is not set or the function does not exist. |
PaymentValidationPaymentMethodDisabledException | Exception thrown if a payment method is disabled. |
PaymentValidationUnsupportedCurrencyException | Exception thrown if a payment uses a currency that is unsupported by a payment method. |