array(
'title' => t('Administer receipt settings'),
'description' => t(''),
),
'refund receipts' => array(
'title' => t('Refund receipts'),
'description' => t(''),
),
'view receipts' => array(
'title' => t('View receipts'),
'description' => t(''),
),
'view own receipts' => array(
'title' => t('View own receipts'),
'description' => t(''),
),
'complete receipts' => array(
'title' => t('Complete receipts'),
'description' => t(''),
),
);
}
/**
* Implements hook_menu().
*/
function ec_receipt_menu() {
$items = array();
$items['admin/store/receipts/%ec_receipt/refund'] = array(
'title' => 'Refund Receipt',
'page callback' => 'drupal_get_form',
'page arguments' => array('ec_receipt_refund', 3),
'access arguments' => array('refund receipts'),
'type' => MENU_CALLBACK,
'file' => 'ec_receipt.admin.inc',
);
$items['admin/store/receipts/%ec_receipt/complete'] = array(
'title' => 'Complete receipt',
'page callback' => 'drupal_get_form',
'page arguments' => array('ec_receipt_complete_form', 3),
'access arguments' => array('complete receipts'),
'type' => MENU_CALLBACK,
'file' => 'ec_receipt.admin.inc',
);
$rtypes = ec_receipt_get_types();
$items['admin/config/store/rtypes'] = array(
'title' => 'Receipts',
'page callback' => 'drupal_get_form',
'page arguments' => array('ec_receipt_settings'),
'access arguments' => array('administer receipt settings'),
'description' => 'Maintain receipt types.',
'file' => 'ec_receipt.admin.inc',
);
$items['admin/config/store/rtypes/settings'] = array(
'title' => 'Settings',
'page callback' => 'drupal_get_form',
'page arguments' => array('ec_receipt_settings'),
'access arguments' => array('administer receipt settings'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'file' => 'ec_receipt.admin.inc',
'weight' => -10,
);
$items['admin/config/store/rtypes/list'] = array(
'title' => 'Types',
'page callback' => 'drupal_get_form',
'page arguments' => array('ec_receipt_admin_rtypes_form'),
'access arguments' => array('administer receipt settings'),
'description' => 'Maintain receipt types.',
'type' => MENU_LOCAL_TASK,
'file' => 'ec_receipt.admin.inc',
);
$rtypes = ec_receipt_get_types('names');
foreach ($rtypes as $type => $name) {
$items['admin/config/store/rtypes/' . $type] = array(
'title' => t($name),
'page callback' => 'drupal_get_form',
'page arguments' => array('ec_receipt_admin_type_form', 4),
'access arguments' => array('administer receipt settings'),
'type' => MENU_CALLBACK,
'file' => 'ec_receipt.admin.inc',
);
$items['admin/config/store/rtypes/' . $type . '/options'] = array(
'title' => t($name) ." ". t('Options'),
'page callback' => 'drupal_get_form',
'page arguments' => array('ec_receipt_admin_type_form', 4),
'access arguments' => array('administer receipt settings'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
'file' => 'ec_receipt.admin.inc',
);
}
$items['admin/config/store/rtypes/alloc'] = array(
'title' => 'Allocation',
'page callback' => 'drupal_get_form',
'page arguments' => array('ec_receipt_admin_atypes_form'),
'access arguments' => array('administer receipt settings'),
'description' => 'Maintain and configure allocations types',
'file' => 'ec_receipt.admin.inc',
'type' => MENU_LOCAL_TASK,
);
$items['store/receipt/%ec_receipt/view'] = array(
'title' => 'View Receipt',
'page callback' => 'drupal_get_form',
'page arguments' => array('ec_receipt_view_form', 2, TRUE),
'access callback' => 'ec_customer_check_access',
'access arguments' => array('receipt', 2),
'type' => MENU_CALLBACK,
'file' => 'ec_receipt.admin.inc',
);
$items['store/receipt/%ec_receipt/reverse/%'] = array(
'title' => 'Reverse Allocation',
'page callback' => 'drupal_get_form',
'page arguments' => array('ec_receipt_reverse_allocation_form', 2, 4),
'access arguments' => array('refund receipts'),
'type' => MENU_CALLBACK,
'file' => 'ec_receipt.admin.inc',
);
return $items;
}
/**
* Implements hook_entity_info().
*/
function ec_receipt_entity_info() {
return array(
'ec_receipt' => array(
'label' => t('Receipt'),
'base table' => 'ec_receipt',
'entity keys' => array(
'id' => 'erid',
),
'load hook' => 'entity_receipt_load',
),
);
}
/**
* Implements hook_theme().
*/
function ec_receipt_theme() {
return array(
'ec_receipt_checkout_types' => array(
'variables' => array('rtype' => NULL),
'template' => 'ec_receipt_checkout_types',
'path' => drupal_get_path('module', 'ec_receipt') . '/templates',
),
'ec_receipt_admin_atypes_form' => array(
'render element' => 'form',
'file' => 'ec_receipt.theme.inc',
),
'ec_receipt_admin_rtypes_form' => array(
'render element' => 'form',
'file' => 'ec_receipt.theme.inc',
),
'ec_receipt_icon' => array(
'variables' => array('icon' => NULL),
'file' => 'ec_receipt.theme.inc',
),
'ec_receipt_review_form' => array(
'render element' => 'form',
'file' => 'ec_receipt.theme.inc',
),
);
}
/**
* @todo Please document this function.
* @see http://drupal.org/node/1354
*/
function ec_receipt_preprocess_ec_receipt_checkout_types(&$variables) {
if (isset($variables['rtype']) && $variables['rtype']) {
$variables['template_files'][] = 'ec_receipt_checkout_types_' . $variables['rtype']->type;
$variables += (array) $variables['rtype'];
}
else {
$variables['name'] = '';
}
if (isset($variables['icon']) && $variables['icon']) {
$variables['icon'] = theme('ec_receipt_icon', array('icon' => $variables['icon']));
}
}
/**
* @todo Please document this function.
* @see http://drupal.org/node/1354
*/
function ec_receipt_access_receipt() {
if ($customer = ec_customer_get_by_uid(arg(1))) {
return (user_access(EC_PERM_MANAGE) || arg(1) == $user->uid);
}
return FALSE;
}
/**
* Implements hook_views_api().
*/
function ec_receipt_views_api() {
return array('api' => 2.0);
}
/**
* Implements hook_checkout_info().
*/
function ec_receipt_checkout_info() {
return array(
'receipts' => array(
'name' => t('Receipting'),
'description' => t("If required, display the 'Select Payment Option' page to the customer. This checkout page is skipped if there is only one receipt type (payment gateway) enabled."),
'module' => 'ec_receipt',
'file' => 'ec_receipt.checkout.inc',
),
);
}
/**
* @todo Please document this function.
* @see http://drupal.org/node/1354
*/
function ec_receipt_checkout_types($a) {
return theme('ec_receipt_checkout_types', array('rtype' => $a));
}
/**
* Retrieve Receipt types
*/
function ec_receipt_get_types($op = 'types', $rtype = NULL, $reset = FALSE) {
$_receipt_types = & drupal_static(__FUNCTION__ . '__receipt_types');
$_receipt_names = & drupal_static(__FUNCTION__ . '__receipt_names');
if ($reset || !isset($_receipt_types)) {
$_receipt_types = array();
$_receipt_names = array();
foreach (module_implements('receipt_info') as $module) {
$path = drupal_get_path('module', $module);
$types = module_invoke($module, 'receipt_info');
foreach ($types as $type => $info) {
$_receipt_types[$type] = (object) $info;
$_receipt_types[$type]->type = $type;
$_receipt_names[$type] = $_receipt_types[$type]->name;
if (isset($info['file'])) {
$_receipt_types[$type]->filepath = $path . '/' . $info['file'];
}
}
}
$result = db_query('SELECT * FROM {ec_receipt_types}')
->fetchAll();
foreach ($result as $info) {
if (isset($_receipt_types[$info->type]) && (empty($_receipt_types[$info->type]->internal) || !$_receipt_types[$info->type]->internal)) {
$_receipt_types[$info->type]->name = !empty($info->name) ? $info->name : $_receipt_types[$info->type]->name;
$_receipt_names[$info->type] = $_receipt_types[$info->type]->name;
$_receipt_types[$info->type]->description = !empty($info->description) ? $info->description : $_receipt_types[$info->type]->description;
$_receipt_types[$info->type]->allow_payments = isset($_receipt_types[$info->type]->allow_payments) ? $info->allow_payments : NULL;
$_receipt_types[$info->type]->allow_admin_payments = isset($_receipt_types[$info->type]->allow_admin_payments) ? $info->allow_admin_payments : NULL;
$_receipt_types[$info->type]->allow_refunds = isset($_receipt_types[$info->type]->allow_refunds) ? $info->allow_refunds : NULL;
$_receipt_types[$info->type]->allow_payto = isset($_receipt_types[$info->type]->allow_payto) ? $info->allow_payto : NULL;
$_receipt_types[$info->type]->allow_recurring = isset($_receipt_types[$info->type]->allow_recurring) ? $info->allow_recurring : NULL;
$_receipt_types[$info->type]->weight = $info->weight;
$_receipt_types[$info->type]->in_db = TRUE;
}
else {
ec_receipt_type_delete($info->type);
}
}
if (!empty($_receipt_types)) {
uasort($_receipt_types, 'ec_sort');
asort($_receipt_names);
}
else {
return array();
}
}
if (isset($rtype) && !isset($_receipt_types[$rtype])) {
return FALSE;
}
switch ($op) {
case 'types':
return $_receipt_types;
case 'type':
if (isset($_receipt_types[$rtype])) {
return $_receipt_types[$rtype];
}
break;
case 'module':
if (isset($_receipt_types[$rtype])) {
return $_receipt_types[$rtype]->module;
}
break;
case 'names':
return $_receipt_names;
case 'name':
if (isset($_receipt_names[$rtype])) {
return $_receipt_names[$rtype];
}
break;
}
}
/**
* Get receipting allocation types.
*/
function ec_receipt_get_atypes($op = 'types', $atype = NULL, $reset = FALSE) {
$_types = & drupal_static(__FUNCTION__ . '__types');
$_names = & drupal_static(__FUNCTION__ . '__names');
if ($reset || empty($_types)) {
foreach (module_implements('allocation_info') as $module) {
$path = drupal_get_path('module', $module);
$atypes = module_invoke($module, 'allocation_info');
foreach ($atypes as $type => $info) {
$_types[$type] = (object) $info;
$_types[$type]->type = $type;
$_names[$type] = $_types[$type]->name;
if (isset($info['file'])) {
$_types[$type]->filepath[] = $path . '/' . $info['file'];
}
}
}
asort($_names);
uasort($_types, 'ec_sort');
drupal_alter('ec_receipt_atypes', $_types);
}
if (!empty($atype) && !isset($_types[$atype])) {
return FALSE;
}
switch ($op) {
case 'types':
return $_types;
break;
case 'type':
return $_types[$atype];
break;
case 'module':
return $_types[$atype]->module;
break;
case 'names':
return $_names;
break;
case 'name':
return $_names[$atype];
break;
}
return FALSE;
}
/**
* Process payment for transaction that has not been completed.
*
* This process is used when you have transactions that are going to be created
* very soon, but the need is to get the payment before creating the transaction
* and then after allocating the payment to the transaction.
* This is used in checkout situations where the transaction is not created
* until the money has taken from the customer.
* This also gives the opportunity to pass the error message back to the user
* and then they can edit the cart and make any corrections to the purchase.
* This process will be used with payment gateways like Authorize.net and
* ccard where the interaction with the payment gateway is between the web
* server and the payment gateway.
*/
function ec_receipt_payment_process($type, &$object) {
$rtype = ec_receipt_alloc_invoke($type, 'get_payment_type', $object);
if (ec_receipt_get_invoke_function($rtype, 'process_payment')) {
if ($receipt = ec_receipt_load(ec_receipt_build_receipt($type, $object))) {
return ec_receipt_invoke($rtype, 'process_payment', $receipt, $type, $object);
}
}
}
/**
* Process payments for hosted gateways.
*
* Hosted payment gateways like PayPal process the payment directly with
* payment gateway and then the result is past back the the web server to
* complete the payment.
*/
function ec_receipt_payment_goto($type, $object, $alloc, $erid = NULL) {
$rtype = ec_receipt_alloc_invoke($type, 'get_payment_type', $object);
if (ec_receipt_get_invoke_function($rtype, 'payment_url')) {
if ($erid && !empty($alloc)) {
$receipt = ec_receipt_load($erid);
$receipt->allocation = $alloc;
ec_receipt_save($receipt);
}
if ($receipt = ec_receipt_load($erid ? $erid : ec_receipt_build_receipt($type, $object, $alloc))) {
return ec_receipt_invoke($receipt->type, 'payment_url', $receipt, $type, $object);
}
}
}
/**
* Allocate payment to a transaction.
*/
function ec_receipt_allocate($receipt, $allocations) {
$v = array();
$rows = 0;
$callback = array();
if ($receipt->balance > 0) {
foreach ($allocations as $allocate) {
if ($object = ec_receipt_alloc_invoke($allocate['type'], 'load', $allocate['id'])) {
$currency = ec_receipt_alloc_invoke($allocate['type'], 'get_currency', $object);
if ($currency == $receipt->currency) {
$total = ec_receipt_alloc_invoke($allocate['type'], 'get_total', $object);
$amount_allocated = ec_receipt_get_allocated_total(array('type' => $allocate['type'], 'etid' => $allocate['id']));
$balance = ($total - $amount_allocated) < 0 ? 0 : ($total - $amount_allocated);
if ($balance > 0) {
$amount = isset($allocate['amount']) && $receipt->balance > $allocate['amount'] ? $allocate['amount'] : $receipt->balance;
$amount = $balance > $amount ? $amount : $balance;
$rows++;
$alloc[] = array(
'erid' => $receipt->erid,
'type' => $allocate['type'],
'etid' => $allocate['id'],
'created' => REQUEST_TIME,
'amount' => $amount,
);
$callback[] = array($allocate['type'], 'allocation', $object, end($alloc), ($balance - $amount));
$receipt->allocated += $amount;
$receipt->balance -= $amount;
if ($receipt->balance <= 0) {
break;
}
}
}
else {
watchdog('ec_receipt', 'Unable to allocate receipt %erid (%currency) to %type-%id (%obj-currency) as currencies are not the same.', array('%type' => $allocate['type'], '%id' => $allocate['id'], '%erid' => $receipt->erid, '%currency' => $receipt->currency, '%obj-currency' => $currency));
}
}
else {
watchdog('ec_receipt', 'Unable to load type %type, id %id to allocate to receipt %erid', array('%type' => $allocate['type'], '%id' => $allocate['id'], '%erid' => $receipt->erid));
}
}
if ($rows) {
foreach ($alloc as $record) {
drupal_write_record('ec_receipt_allocation', $record);
}
}
ec_receipt_save($receipt);
foreach ($callback as $args) {
call_user_func_array('ec_receipt_alloc_invoke', $args);
}
}
}
/**
* Create a receipt and submit to the database.
*
* TODO: Maybe we need to enhance this so it will so that it will check all
* parameters and make sure it is a valid receipt.
*/
function ec_receipt_create_receipt($receipt) {
return ec_receipt_save($receipt);
}
/**
* Build receipt from allocation object.
*/
function ec_receipt_build_receipt($type, $object, $alloc = NULL, $amount = NULL) {
$receipt = new StdClass;
$customer = ec_customer_get_customer(ec_receipt_alloc_invoke($type, 'get_customer', $object));
if (empty($customer->ecid)) {
$customer = ec_customer_insert($customer);
}
if (empty($customer->ecid)) {
return FALSE;
}
$receipt->type = ec_receipt_alloc_invoke($type, 'get_payment_type', $object);
$receipt->ecid = $customer->ecid;
$receipt->currency = ec_receipt_alloc_invoke($type, 'get_currency', $object);
$receipt->amount = $receipt->balance = (isset($amount) && is_numeric($amount) ? $amount : ec_receipt_alloc_invoke($type, 'get_total', $object));
$receipt->allocated = 0;
$receipt->status = RECEIPT_STATUS_PENDING;
if (!empty($alloc)) {
$receipt->allocation = $alloc;
}
return ec_receipt_create_receipt($receipt);
}
/**
* Save Receipt to database.
*/
function ec_receipt_save($receipt) {
$new = empty($receipt->erid);
$ret = FALSE;
if ($new) {
if (empty($receipt->created)) {
$receipt->created = REQUEST_TIME;
}
$orig_receipt = NULL;
}
else {
$orig_receipt = ec_receipt_load($receipt->erid);
foreach ($orig_receipt as $key => $value) {
if (!isset($receipt->$key)) {
$receipt->$key = $value;
}
}
}
$receipt->changed = REQUEST_TIME;
if (!$new) {
$ret = drupal_write_record('ec_receipt', $receipt, 'erid');
}
if ($new || !$ret) {
drupal_write_record('ec_receipt', $receipt);
}
ec_receipt_invoke($receipt->type, 'save', $receipt);
$receipt = ec_receipt_load($receipt->erid);
module_invoke_all('ec_receipt_post_save', $receipt, $orig_receipt);
return $receipt->erid;
}
/**
* Load Receipt.
*
* @param $erid
* Receipt id to be loaded.
* @return
* Returns the receipt object or NULL if no receipt is found.
*/
function ec_receipt_load($erid) {
// ERROR: return statement not found in hook_load
if ($receipt = db_query('SELECT * FROM {ec_receipt} WHERE erid = :erid', array(':erid' => $erid))->fetchObject()) {
if (!empty($receipt->allocation)) {
$receipt->allocation = unserialize($receipt->allocation);
}
if ($extra = ec_receipt_invoke($receipt->type, 'load', $receipt)) {
foreach ($extra as $key => $value) {
$receipt->$key = $value;
}
}
return $receipt;
}
}
/**
* Wrapper for ec_receipt_load() to allow it to work with entities.
*/
function ec_receipt_entity_receipt_load($receipts) {
foreach ($receipts as $erid => $receipt) {
$receipts[$erid] = ec_receipt_load($receipt->erid);
}
}
/**
* Filter payment types based upon a criteria.
*
* @param $criteria
* An array of keys/values which allow the filtering of payment gateways.
* @param $type
* Allocation type of the object which is passed. This is passed to the payment
* gateway for more advanced filtering.
* @param $object
* The object which is being passed to the payment gateway for collecting
* information on with what the payment is going to be paid against which may
* or may not impact on the list of payment gateways which are available.
* @return
* Return a list of payment gateways which are available for this object.
*/
function ec_receipt_type_filter($criteria = array(), $type = NULL, $object = NULL) {
_ec_receipt_filter($criteria, 'init', $type, $object);
return array_filter(ec_receipt_get_types(), '_ec_receipt_filter');
}
function _ec_receipt_filter($var, $op = 'process', $itype = NULL, $iobject = NULL) {
$filter = & drupal_static(__FUNCTION__ . '_filter', NULL);
$type = & drupal_static(__FUNCTION__ . '_type', NULL);
$object = & drupal_static(__FUNCTION__ . '_object', NULL);
if ($op == 'init') {
$filter = $var;
$type = $itype;
$object = $iobject;
return;
}
foreach ($filter as $key => $opt) {
if ($opt === TRUE || $opt === FALSE) {
$opt = $opt === TRUE ? 1 : 0;
}
$value = isset($var->$key) ? $var->$key : array();
if ($value === TRUE || $value === FALSE) {
$value = $value === TRUE ? 1 : 0;
}
if (is_array($value)) {
if (!in_array(drupal_strtoupper($opt), $value)) {
return FALSE;
}
}
elseif (is_numeric($value)) {
if ($opt != $value) {
return FALSE;
}
}
else {
if ($opt != $value) {
return FALSE;
}
}
}
$return = ec_receipt_invoke($var->type, 'filter', $type, $object);
if (!is_null($return) && !$return) {
return $return;
}
foreach (module_implements('ec_receipt_type_filter') as $module) {
$return = module_invoke($module, 'ec_receipt_type_filter', $var->type, $type, $object);
if (!is_null($return) && !$return) {
return $return;
}
}
return TRUE;
}
/**
* Return the function that should be called for a receipt invoke.
*/
function ec_receipt_get_invoke_function($ctype, $hook) {
if ($info = ec_receipt_get_types('type', $ctype)) {
if (isset($info->filepath)) {
include_once DRUPAL_ROOT . '/' . $info->filepath;
}
foreach ($info->module as $module) {
$function = $module . '_receipt_' . $hook;
if (function_exists($function)) {
return $function;
}
}
}
}
/**
* Invoke receipt type operations.
*/
function ec_receipt_invoke() {
$args = func_get_args();
$ctype = array_shift($args);
$hook = array_shift($args);
if ($function = ec_receipt_get_invoke_function($ctype, $hook)) {
return call_user_func_array($function, $args);
}
}
/**
* Invoke receipt allocation type operations.
*/
function ec_receipt_alloc_invoke() {
$args = func_get_args();
$atype = array_shift($args);
$hook = array_shift($args);
$info = ec_receipt_get_atypes('type', $atype);
if (isset($info->filepath)) {
array_map('_ec_load_map_inc', $info->filepath);
}
foreach ($info->module as $module) {
$function = $module . '_alloc_' . $hook;
if (function_exists($function)) {
return call_user_func_array($function, $args);
}
}
}
function _ec_load_map_inc($a) {
include_once DRUPAL_ROOT . '/' . $a;
return $a;
}
/**
* Save receipt types.
*/
function ec_receipt_type_save($info) {
$info = (object) array_merge((array) ec_receipt_get_types('type', $info->type), (array) $info);
$existing = db_select('ec_receipt_types', 'ert')
->fields('ert')
->condition('type', $info->type)
->execute()
->fetch();
if ($existing) {
drupal_write_record('ec_receipt_types', $info, 'type');
}
else {
drupal_write_record('ec_receipt_types', $info);
}
}
/**
* Delete receipt types.
*/
function ec_receipt_type_delete($type) {
db_delete('ec_receipt_types')
->condition('type', $type)
->execute();
}
/**
* A list of the world currencies.
*/
function ec_receipt_currency_list($filter = NULL) {
$currency = & drupal_static(__FUNCTION__ . '_currency', NULL);
if (empty($currency)) {
module_load_include('inc', 'ec_receipt', 'currency');
$currency = ec_receipt_get_all_currencies();
}
if (empty($filter)) {
$filter = array();
if ($types = ec_receipt_get_types()) {
foreach ($types as $info) {
if (!empty($info->currencies_supported) && is_array($info->currencies_supported)) {
$filter += $info->currencies_supported;
}
}
}
}
return array_intersect_key($currency, array_flip($filter));
}
/**
* Implements hook_ec_receipt_post_save().
*/
function ec_receipt_ec_receipt_post_save($receipt, $original) {
if (empty($original) || $receipt->status != $original->status) {
module_invoke_all('ec_receipt_status', $receipt, $original);
}
if (!empty($original)) {
db_update('search_dataset')
->fields(array(
'reindex' => REQUEST_TIME,
))
->condition('sid', $receipt->erid)
->condition('type', 'ec_receipt')
->execute();
}
}
/**
* Implements hook_ec_receipt_status().
*
* Once the payment has been completed allocate the payment based on the
* pre-loaded rules. However if the payments status is changed from completed
* to another status like refunded, then reverse the allocations.
*/
function ec_receipt_ec_receipt_status($receipt, $original) {
$completed = array(RECEIPT_STATUS_COMPLETED);
if (in_array($receipt->status, $completed) && !empty($receipt->allocation)) {
ec_receipt_allocate($receipt, $receipt->allocation);
}
elseif (!empty($original) && in_array($original->status, $completed)) {
// TODO: Reverse the Allocations.
}
}
/**
* Get all allocated data for a receipt
*/
function ec_receipt_get_allocations($erid) {
$allocations = array();
$result = db_query('SELECT * FROM {ec_receipt_allocation} WHERE erid = :erid AND reversed = 0', array(':erid' => $erid));
foreach ($result as $allocation) {
$allocations[$allocation->eaid] = $allocation;
}
return $allocations;
}
/**
* Return the total allocated from the filter
*/
function ec_receipt_get_allocated_total($filter) {
$query = db_select('ec_receipt_allocation', 'era');
foreach ($filter as $field => $value) {
$query->condition('era.' . $field, $value, '=');
}
$query->addExpression('SUM(amount)', 'total');
$result = $query->execute();
return $result->fetchField(0);
}
/**
* Reverse Allocation.
* TODO: Convert to use drupal_write_record.
*/
function ec_receipt_reverse_allocation($receipt, $alloc) {
if ($object = ec_receipt_alloc_invoke($alloc->type, 'load', $alloc->etid)) {
if ((ec_receipt_alloc_invoke($alloc->type, 'can_reverse', $object)) === FALSE) {
return FALSE;
}
$total = ec_receipt_alloc_invoke($alloc->type, 'get_total', $object);
$reversal = clone $alloc;
unset($reversal->eaid);
$reversal->created = time();
$reversal->amount*= -1;
$reversal->reversed = $alloc->eaid;
$receipt->allocated+= $reversal->amount;
$receipt->balance-= $reversal->amount;
$params = array(
'amount' => $reversal->amount,
);
ec_receipt_alloc_invoke($alloc->type, 'allocation', $object, $params, $total - $reversal->amount);
drupal_write_record('ec_receipt_allocation', $reversal);
$alloc->reversed = $reversal->eaid;
drupal_write_record('ec_receipt_allocation', $alloc, 'eaid');
ec_receipt_save($receipt);
return TRUE;
}
}
/**
* Implementation hook_link().
*/
function ec_receipt_link($type, $object, $teaser = FALSE) {
$links = array();
if ($type == 'ec_store_transaction' && $object->allocation) {
$links['receipt_search'] = array(
'title' => t('View receipts'),
'href' => 'admin/store/receipts',
'query' => array(
'allocation' => array('' => 'transaction'),
'etid' => $object->txnid,
),
'attributes' => array(
'title' => t('View receipts for transaction @txnid', array('@txnid' => $object->txnid)),
),
);
}
if ($type == 'ec_receipt') {
$links['receipt_details'] = array(
'title' => t('View'),
'href' => 'store/receipt/' . $object->erid . '/view',
);
if (in_array($object->status, array(RECEIPT_STATUS_PENDING, RECEIPT_STATUS_RECEIVED)) && user_access('complete receipts')) {
$links['receipt_complete'] = array(
'title' => t('Complete'),
'href' => 'admin/store/receipts/' . $object->erid . '/complete',
'query' => drupal_get_destination(),
);
}
if ($object->status == RECEIPT_STATUS_COMPLETED && $object->allocated == 0 && user_access(EC_PERM_MANAGE)) {
$links['refund_receipt'] = array(
'title' => t('Refund Receipt'),
'href' => 'admin/store/receipts/' . $object->erid . '/refund',
'query' => drupal_get_destination(),
);
}
}
if ($type == 'ec_receipt' && isset($object->eaid)) {
$links['transaction_search'] = array(
'title' => t('View transactions'),
'href' => 'admin/store/transaction',
'query' => 'erid=' . $object->erid,
'attributes' => array(
'title' => t('View transactions paid by receipt @erid', array('@erid' => $object->erid)),
),
);
}
if ($type == 'ec_receipt_allocation' && user_access(EC_PERM_MANAGE) && !$object->reversed && $object->type != 'refund') {
$links['reverse_allocation'] = array(
'title' => t('Reverse allocation'),
'href' => 'store/receipt/' . $object->erid . '/reverse/' . $object->eaid,
'attributes' => array(
'title' => t('Reverse allocation'),
),
);
}
if ($type == 'ec_customer_list') {
$links['receipts'] = array(
'title' => t('Receipts'),
'href' => 'admin/store/receipts',
'query' => 'ecid=' . $object->ecid,
);
}
return $links;
}
/**
* @todo Please document this function.
* @see http://drupal.org/node/1354
*/
function ec_receipt_get_statuses() {
return array(
RECEIPT_STATUS_PENDING => t('Pending'),
RECEIPT_STATUS_RECEIVED => t('Received'),
RECEIPT_STATUS_COMPLETED => t('Completed'),
RECEIPT_STATUS_FAILED => t('Failed'),
RECEIPT_STATUS_DENIED => t('Denied'),
RECEIPT_STATUS_REFUND_PENDING => t('Refund Pending'),
RECEIPT_STATUS_REFUNDED => t('Refunded'),
RECEIPT_STATUS_CANCELLED => t('Cancelled'),
);
}
/**
* @todo Please document this function.
* @see http://drupal.org/node/1354
*/
function ec_receipt_get_status($status = NULL) {
$statuses = ec_receipt_get_statuses();
return isset($status) && isset($statuses[$status]) ? $statuses[$status] : $status;
}
/**
* Converts an associative array to xml. Useful for creating XML for payment
* gateways. An example array:
*
* array(
* 'Foo' => '1',
* 'Links' => array(
* array(
* 'Link' => array(
* 'Url' => 'http://synerger.com',
* 'Title' => 'Synerger Pty Ltd',
* ),
* ),
* array(
* 'Link' => array(
* 'Url' => 'http://drupal.org',
* 'Title' => 'Drupal: Community Plumbing',
* ),
* ),
* ),
* 'Information' => array(
* 'Name' => 'Sammy Spets',
* 'Gender' => 'Male',
* ),
* );
*
* Will produce the following XML:
*
*