created baseline emsbadge and emsticket added completePurchase() and denyPurchase() utility methods for transaction
594 lines
21 KiB
Perl
594 lines
21 KiB
Perl
package WebGUI::Shop::Transaction;
|
||
|
||
use strict;
|
||
|
||
use Class::InsideOut qw{ :std };
|
||
use JSON;
|
||
use WebGUI::Asset::Template;
|
||
use WebGUI::Exception::Shop;
|
||
use WebGUI::Form;
|
||
use WebGUI::International;
|
||
use WebGUI::Paginator;
|
||
use WebGUI::Shop::Admin;
|
||
use WebGUI::Shop::AddressBook;
|
||
use WebGUI::Shop::TransactionItem;
|
||
|
||
=head1 NAME
|
||
|
||
Package WebGUI::Shop::Transaction
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
This package keeps records of every puchase made.
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
use WebGUI::Shop::Transaction;
|
||
|
||
my $transaction = WebGUI::Shop::Transaction->new($session, $id);
|
||
|
||
# typical transaction goes like this:
|
||
my $transaction = WebGUI::Shop::Transaction->create({ cart=>$cart, paymentMethod=>$paymentMethod, paymentAddress=>$address});
|
||
my ($transactionNumber, $status, $message) = $paymentMethod->tryTransaction;
|
||
if ($status eq "somekindofsuccess") {
|
||
$transaction->completePurchase($cart, $transactionNumber, $status, $message);
|
||
}
|
||
else {
|
||
$transaction->denyPurchase($transactionNumber, $status, $message);
|
||
}
|
||
|
||
|
||
=head1 METHODS
|
||
|
||
These subroutines are available from this package:
|
||
|
||
=cut
|
||
|
||
readonly session => my %session;
|
||
private properties => my %properties;
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 addItem ( cartitem )
|
||
|
||
Adds an item to the transaction. Returns a reference to the newly added item.
|
||
|
||
=head3 cartitem
|
||
|
||
A reference to a subclass of WebGUI::Shop::CartItem.
|
||
|
||
=cut
|
||
|
||
sub addItem {
|
||
my ($self, $cartItem) = @_;
|
||
my $item = WebGUI::Shop::TransactionItem->create( $self, $cartItem);
|
||
return $item;
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 completePurchase ( cart, transactionCode, statusCode, statusMessage )
|
||
|
||
See also denyPurchase(). Completes a purchase by updating the transaction as a success, and clearing the cart of it's items.
|
||
|
||
=head3 cart
|
||
|
||
A reference to the current cart that's full of items just purchased.
|
||
|
||
=head3 transactionCode
|
||
|
||
The transaction id or code given by the payment gateway.
|
||
|
||
=head3 statusCode
|
||
|
||
The status code that came back from the payment gateway when trying to process the payment.
|
||
|
||
=head3 statusMessage
|
||
|
||
The extended status message that came back from the payment gateway when trying to process the payment.
|
||
|
||
=cut
|
||
|
||
sub completePurchase {
|
||
my ($self, $cart, $transactionCode, $statusCode, $statusMessage) = @_;
|
||
$cart->completePurchase;
|
||
$self->update({
|
||
transactionCode => $transactionCode,
|
||
isSuccessful => 1,
|
||
statusCode => $statusCode,
|
||
statusMessage => $statusMessage,
|
||
});
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 create ( session, properties )
|
||
|
||
Constructor. Creates a new transaction object. Returns a reference to the object.
|
||
|
||
=head3 session
|
||
|
||
A reference to the current session.
|
||
|
||
=head3 properties
|
||
|
||
See update().
|
||
|
||
=cut
|
||
|
||
sub create {
|
||
my ($class, $session, $properties) = @_;
|
||
unless (defined $session && $session->isa("WebGUI::Session")) {
|
||
WebGUI::Error::InvalidObject->throw(expected=>"WebGUI::Session", got=>(ref $session), error=>"Need a session.");
|
||
}
|
||
my $transactionId = $session->id->generate;
|
||
$session->db->write('insert into transaction (transactionId, userId, username, dateOfPurchase) values (?,?,?,now())',
|
||
[$transactionId, $session->user->userId, $session->user->username]);
|
||
my $self = $class->new($session, $transactionId);
|
||
$self->update($properties);
|
||
return $self;
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 delete ()
|
||
|
||
Deletes this transaction and all transactionItems contained in it.
|
||
|
||
=cut
|
||
|
||
sub delete {
|
||
my ($self) = @_;
|
||
foreach my $item (@{$self->getItems}) {
|
||
$item->delete;
|
||
}
|
||
$self->session->db->write("delete from transaction where transactionId=?",[$self->getId]);
|
||
undef $self;
|
||
return undef;
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 denyPurchase ( transactionCode, statusCode, statusMessage )
|
||
|
||
Completes a purchase as a failure. It could be that the user didn't enter their credit cart correctly, or they may have insufficient funds.
|
||
|
||
=head3 transactionCode
|
||
|
||
The transaction id or code given by the payment gateway.
|
||
|
||
=head3 statusCode
|
||
|
||
The status code that came back from the payment gateway when trying to process the payment.
|
||
|
||
=head3 statusMessage
|
||
|
||
The extended status message that came back from the payment gateway when trying to process the payment.
|
||
|
||
=cut
|
||
|
||
sub denyPurchase {
|
||
my ($self, $transactionCode, $statusCode, $statusMessage) = @_;
|
||
$self->update({
|
||
isSuccessful => 0,
|
||
transactionCode => $transactionCode,
|
||
statusCode => $statusCode,
|
||
statusMessage => $statusMessage
|
||
});
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 formatCurrency ( amount )
|
||
|
||
Formats a number as a float with two digits after the decimal like 0.00.
|
||
|
||
=head3 amount
|
||
|
||
The number to format.
|
||
|
||
=cut
|
||
|
||
sub formatCurrency {
|
||
my ($self, $amount) = @_;
|
||
return sprintf("%.2f", $amount);
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 get ( [ property ] )
|
||
|
||
Returns a duplicated hash reference of this object<63>s data.
|
||
|
||
=head3 property
|
||
|
||
Any field ? returns the value of a field rather than the hash reference.
|
||
|
||
=cut
|
||
|
||
sub get {
|
||
my ($self, $name) = @_;
|
||
if (defined $name) {
|
||
return $properties{id $self}{$name};
|
||
}
|
||
my %copyOfHashRef = %{$properties{id $self}};
|
||
return \%copyOfHashRef;
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 getId ()
|
||
|
||
Returns the unique id for this transaction.
|
||
|
||
=cut
|
||
|
||
sub getId {
|
||
my ($self) = @_;
|
||
return $self->get("transactionId");
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 getItem ( itemId )
|
||
|
||
Returns a reference to a WebGUI::Shop::TransactionItem object.
|
||
|
||
=head3 itemId
|
||
|
||
The id of the item to retrieve.
|
||
|
||
=cut
|
||
|
||
sub getItem {
|
||
my ($self, $itemId) = @_;
|
||
return WebGUI::Shop::TransactionItem->new($self, $itemId);
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 getItems ( )
|
||
|
||
Returns an array reference of WebGUI::Shop::TransactionItem objects that are in the transaction.
|
||
|
||
=cut
|
||
|
||
sub getItems {
|
||
my ($self) = @_;
|
||
my @itemsObjects = ();
|
||
my $items = $self->session->db->read("select itemId from transactionItem where transactionId=?",[$self->getId]);
|
||
while (my ($itemId) = $items->array) {
|
||
push(@itemsObjects, $self->getItem($itemId));
|
||
}
|
||
return \@itemsObjects;
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 new ( session, transactionId )
|
||
|
||
Constructor. Instanciates a transaction based upon a transactionId.
|
||
|
||
=head3 session
|
||
|
||
A reference to the current session.
|
||
|
||
=head3 transactionId
|
||
|
||
The unique id of a transaction to instanciate.
|
||
|
||
=cut
|
||
|
||
sub new {
|
||
my ($class, $session, $transactionId) = @_;
|
||
unless (defined $session && $session->isa("WebGUI::Session")) {
|
||
WebGUI::Error::InvalidObject->throw(expected=>"WebGUI::Session", got=>(ref $session), error=>"Need a session.");
|
||
}
|
||
unless (defined $transactionId) {
|
||
WebGUI::Error::InvalidParam->throw(error=>"Need a transactionId.");
|
||
}
|
||
my $transaction = $session->db->quickHashRef('select * from transaction where transactionId=?', [$transactionId]);
|
||
if ($transaction->{transactionId} eq "") {
|
||
WebGUI::Error::ObjectNotFound->throw(error=>"No such transaction.", id=>$transactionId);
|
||
}
|
||
my $self = register $class;
|
||
my $id = id $self;
|
||
$session{ $id } = $session;
|
||
$properties{ $id } = $transaction;
|
||
return $self;
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 update ( properties )
|
||
|
||
Sets properties in the transaction.
|
||
|
||
=head3 properties
|
||
|
||
A hash reference that contains one of the following:
|
||
|
||
=head4 cart
|
||
|
||
A reference to a cart object. Will pull shipping method, shipping address, tax, items, total, and coupon from
|
||
it. Alternatively you can set manually any of the following properties that are set by cart automatically:
|
||
amount shippingAddressId shippingAddressName shippingAddress1 shippingAddress2 shippingAddress3 shippingCity
|
||
shippingState shippingCountry shippingCode shippingPhoneNumber shippingDriverId shippingDriverLabel shippingPrice
|
||
couponId couponTitle couponDiscount taxes
|
||
|
||
You can also use the addItem() method to manually add items to the transaction rather than passing a cart full of items.
|
||
|
||
=head4 paymentAddress
|
||
|
||
A reference to a WebGUI::Shop::Address that contains the payment address. Alternatively you can set manually
|
||
any of the properties that are set by payment address automatically: paymentAddressId paymentAddressName
|
||
paymentAddress1 paymentAddress2 paymentAddress3 paymentCity paymentState paymentCountry paymentCode
|
||
paymentPhoneNumber
|
||
|
||
=head4 paymentMethod
|
||
|
||
A reference to a WebGUI::Shop::PayDriver subclass that is used to make payment. Alternatively you can set
|
||
manually any of the properties that are set by payment method automatically: paymentDriverId paymentDriverLabel
|
||
|
||
=head4 isSuccessful
|
||
|
||
A boolean indicating whether the transaction was completed successfully.
|
||
|
||
=head4 transactionCode
|
||
|
||
The transaction id or code given by the payment gateway.
|
||
|
||
=head4 statusCode
|
||
|
||
The status code that came back from the payment gateway when trying to process the payment.
|
||
|
||
=head4 statusMessage
|
||
|
||
The extended status message that came back from the payment gateway when trying to process the payment.
|
||
|
||
=cut
|
||
|
||
sub update {
|
||
my ($self, $newProperties) = @_;
|
||
my $id = id $self;
|
||
if (exists $newProperties->{cart}) {
|
||
my $cart = $newProperties->{cart};
|
||
$newProperties->{taxes} = $cart->getTaxes;
|
||
my $address = $cart->getShippingAddress;
|
||
$newProperties->{shippingAddressId} = $address->getId;
|
||
$newProperties->{shippingAddressName} = $address->get('name');
|
||
$newProperties->{shippingAddress1} = $address->get('address1');
|
||
$newProperties->{shippingAddress2} = $address->get('address2');
|
||
$newProperties->{shippingAddress3} = $address->get('address3');
|
||
$newProperties->{shippingCity} = $address->get('city');
|
||
$newProperties->{shippingState} = $address->get('state');
|
||
$newProperties->{shippingCountry} = $address->get('country');
|
||
$newProperties->{shippingCode} = $address->get('code');
|
||
$newProperties->{shippingPhoneNumber} = $address->get('phoneNumber');
|
||
my $shipper = $cart->getShipper;
|
||
$newProperties->{shippingDriverId} = $shipper->getId;
|
||
$newProperties->{shippingDriverLabel} = $shipper->get('label');
|
||
$newProperties->{shippingPrice} = $shipper->calculate($cart);
|
||
$newProperties->{couponId} = $cart->get('couponId');
|
||
$newProperties->{couponTitle} = '';
|
||
$newProperties->{couponDiscount} = '';
|
||
$newProperties->{amount} = $cart->getSubtotal + $newProperties->{couponDiscount} + $newProperties->{shippingPrice} + $newProperties->{taxes};
|
||
foreach my $item (@{$cart->getItems}) {
|
||
$self->addItem({item=>$item});
|
||
}
|
||
}
|
||
if (exists $newProperties->{paymentAddress}) {
|
||
my $address = $newProperties->{paymentAddress};
|
||
$newProperties->{paymentAddressId} = $address->getId;
|
||
$newProperties->{paymentAddressName} = $address->get('name');
|
||
$newProperties->{paymentAddress1} = $address->get('address1');
|
||
$newProperties->{paymentAddress2} = $address->get('address2');
|
||
$newProperties->{paymentAddress3} = $address->get('address3');
|
||
$newProperties->{paymentCity} = $address->get('city');
|
||
$newProperties->{paymentState} = $address->get('state');
|
||
$newProperties->{paymentCountry} = $address->get('country');
|
||
$newProperties->{paymentCode} = $address->get('code');
|
||
$newProperties->{paymentPhoneNumber} = $address->get('phoneNumber');
|
||
}
|
||
if (exists $newProperties->{paymentMethod}) {
|
||
my $pay = $newProperties->{paymentMethod};
|
||
$newProperties->{paymentDriverId} = $pay->getId;
|
||
$newProperties->{paymentDriverLabel} = $pay->get('label');
|
||
}
|
||
my @fields = (qw( isSuccessful transactionCode statusCode statusMessage amount shippingAddressId
|
||
shippingAddressName shippingAddress1 shippingAddress2 shippingAddress3 shippingCity shippingState
|
||
shippingCountry shippingCode shippingPhoneNumber shippingDriverId shippingDriverLabel
|
||
shippingPrice paymentAddressId paymentAddressName
|
||
paymentAddress1 paymentAddress2 paymentAddress3 paymentCity paymentState paymentCountry paymentCode
|
||
paymentPhoneNumber paymentDriverId paymentDriverLabel couponId couponTitle couponDiscount taxes ));
|
||
foreach my $field (@fields) {
|
||
$properties{$id}{$field} = (exists $newProperties->{$field}) ? $newProperties->{$field} : $properties{$id}{$field};
|
||
}
|
||
$self->session->db->setRow("transaction","transactionId",$properties{$id});
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 www_getTransactionsAsJson ()
|
||
|
||
Retrieves a list of transactions for the www_manage() method.
|
||
|
||
=cut
|
||
|
||
sub www_getTransactionsAsJson {
|
||
my ($class, $session) = @_;
|
||
my $admin = WebGUI::Shop::Admin->new($session);
|
||
return $session->privilege->insufficient() unless $admin->canManage;
|
||
my ($db, $form) = $session->quick(qw(db form));
|
||
my $startIndex = $form->get('startIndex') || 0;
|
||
my $numberOfResults = $form->get('results') || 25;
|
||
my @placeholders = ();
|
||
my $sql = 'select SQL_CALC_FOUND_ROWS orderNumber, transactionId, transactionCode, paymentDriverLabel,
|
||
dateOfPurchase, username, amount, isSuccessful, statusCode, statusMessage
|
||
from transaction';
|
||
my $keywords = $form->get("keywords");
|
||
if ($keywords ne "") {
|
||
($sql, @placeholders) = $db->buildSearchQuery($sql, $keywords, [qw{amount username orderNumber shippingAddressName shippingAddress1 paymentAddressName paymentAddress1}])
|
||
}
|
||
push(@placeholders, $startIndex, $numberOfResults);
|
||
$sql .= ' order by dateOfPurchase desc limit ?,?';
|
||
my %results = $db->buildDataTableStructure($sql, \@placeholders);
|
||
$results{'startIndex'} = $startIndex;
|
||
$results{'sort'} = undef;
|
||
$results{'dir'} = "desc";
|
||
$session->http->setMimeType('text/json');
|
||
return JSON::to_json(\%results);
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 www_manage ()
|
||
|
||
Displays a list of all transactions in the system along with management tools for them.
|
||
|
||
=cut
|
||
|
||
sub www_manage {
|
||
my ($class, $session) = @_;
|
||
my $admin = WebGUI::Shop::Admin->new($session);
|
||
return $session->privilege->insufficient() unless $admin->canManage;
|
||
my $i18n = WebGUI::International->new($session, 'Shop');
|
||
my ($style, $url) = $session->quick(qw(style url));
|
||
|
||
# set up all the files that we need
|
||
$style->setLink($url->extras('/yui/build/fonts/fonts-min.css'), {rel=>'stylesheet', type=>'text/css'});
|
||
$style->setLink($url->extras('/yui/build/datatable/assets/skins/sam/datatable.css'), {rel=>'stylesheet', type=>'text/css'});
|
||
$style->setScript($url->extras('/yui/build/utilities/utilities.js'), {type=>'text/javascript'});
|
||
$style->setScript($url->extras('/yui/build/json/json-min.js'), {type=>'text/javascript'});
|
||
$style->setScript($url->extras('/yui/build/datasource/datasource-beta-min.js'), {type=>'text/javascript'});
|
||
$style->setScript($url->extras('/yui/build/datatable/datatable-beta-min.js'), {type=>'text/javascript'});
|
||
|
||
# draw the html markup that's needed
|
||
$style->setRawHeadTags('<style type="text/css"> #paging a { color: #0000de; } #search form { display: inline; } </style>');
|
||
my $output = q|
|
||
|
||
<div class=" yui-skin-sam">
|
||
<div id="search"><form id="keywordSearchForm"><input type="text" name="keywords" id="keywordsField" /><input type="submit" value="Search" /></form></div>
|
||
<div id="paging"></div>
|
||
<div id="dt"></div>
|
||
</div>
|
||
|
||
<script type="text/javascript">
|
||
YAHOO.util.Event.onDOMReady(function () {
|
||
var DataSource = YAHOO.util.DataSource,
|
||
Dom = YAHOO.util.Dom,
|
||
DataTable = YAHOO.widget.DataTable,
|
||
Paginator = YAHOO.widget.Paginator;
|
||
|;
|
||
|
||
# the datasource deals with the stuff returned from www_getTransactionsAsJson
|
||
$output .= "var mySource = new DataSource('".$url->page('shop=transaction;method=getTransactionsAsJson')."');";
|
||
$output .= <<STOP;
|
||
mySource.responseType = DataSource.TYPE_JSON;
|
||
mySource.responseSchema = {
|
||
resultsList : 'records',
|
||
totalRecords: 'totalRecords',
|
||
fields : [ 'transactionCode', 'orderNumber', 'paymentDriverLabel',
|
||
'transactionId', 'dateOfPurchase', 'username', 'amount', 'isSuccessful', 'statusCode', 'statusMessage']
|
||
};
|
||
STOP
|
||
|
||
# paginator does the cool ajaxy pagination and makes the requests as needed
|
||
$output .= <<STOP;
|
||
var buildQueryString = function (state,dt) {
|
||
return ";startIndex=" + state.pagination.recordOffset +
|
||
";keywords=" + Dom.get('keywordsField').value +
|
||
";results=" + state.pagination.rowsPerPage;
|
||
};
|
||
|
||
var myPaginator = new Paginator({
|
||
containers : ['paging'],
|
||
pageLinks : 5,
|
||
rowsPerPage : 25,
|
||
rowsPerPageOptions : [10,25,50,100],
|
||
template : "<strong>{CurrentPageReport}</strong> {PreviousPageLink} {PageLinks} {NextPageLink} {RowsPerPageDropdown}"
|
||
});
|
||
STOP
|
||
|
||
# create the data table, and a special formatter for the view transaction urls
|
||
$output .= <<STOP;
|
||
var myTableConfig = {
|
||
initialRequest : ';startIndex=0',
|
||
generateRequest : buildQueryString,
|
||
paginationEventHandler : DataTable.handleDataSourcePagination,
|
||
paginator : myPaginator
|
||
};
|
||
YAHOO.widget.DataTable.formatViewTransaction = function(elCell, oRecord, oColumn, orderNumber) {
|
||
STOP
|
||
$output .= q{elCell.innerHTML = '<a href="}.$url->page(q{shop=transaction;method=viewTransaction})
|
||
.q{;transactionId=' + oRecord.getData('transactionId') + '">' + orderNumber + '</a>'; };
|
||
$output .= '
|
||
};
|
||
var myColumnDefs = [
|
||
';
|
||
$output .= '{key:"orderNumber", label:"'.$i18n->get('order number').'", formatter:YAHOO.widget.DataTable.formatViewTransaction},';
|
||
$output .= '{key:"dateOfPurchase", label:"'.$i18n->get('date').'",formatter:YAHOO.widget.DataTable.formatDate},';
|
||
$output .= '{key:"username", label:"'.$i18n->get('username').'"},';
|
||
$output .= '{key:"amount", label:"'.$i18n->get('price').'",formatter:YAHOO.widget.DataTable.formatCurrency},';
|
||
$output .= '{key:"statusCode", label:"'.$i18n->get('status code').'"},';
|
||
$output .= '{key:"statusMessage", label:"'.$i18n->get('status message').'"},';
|
||
$output .= '{key:"paymentDriverLabel", label:"'.$i18n->get('payment method').'"},';
|
||
$output .= <<STOP;
|
||
];
|
||
var myTable = new DataTable('dt', myColumnDefs, mySource, myTableConfig);
|
||
STOP
|
||
|
||
# add the necessary event handler to the search button that sends the search request via ajax
|
||
$output .= <<STOP;
|
||
Dom.get('keywordSearchForm').onsubmit = function () {
|
||
mySource.sendRequest(';keywords=' + Dom.get('keywordsField').value + ';startIndex=0',
|
||
myTable.onDataReturnInitializeTable, myTable);
|
||
return false;
|
||
};
|
||
|
||
});
|
||
</script>
|
||
STOP
|
||
# render everything to a web page
|
||
return $admin->getAdminConsole->render($output, $i18n->get('transactions'));
|
||
}
|
||
|
||
#-------------------------------------------------------------------
|
||
|
||
=head2 www_viewTransaction ()
|
||
|
||
Displays the admin view of an individual transaction.
|
||
|
||
=cut
|
||
|
||
sub www_viewTransaction {
|
||
my ($class, $session) = @_;
|
||
my $admin = WebGUI::Shop::Admin->new($session);
|
||
return $session->privilege->insufficient() unless $admin->canManage;
|
||
my $i18n = WebGUI::International->new($session, 'Shop');
|
||
my ($style, $url) = $session->quick(qw(style url));
|
||
my $transaction = $class->new($session, $session->form->get('transactionId'));
|
||
my $output = q{
|
||
<table>
|
||
<tr>
|
||
<th>}. $i18n->get("transaction id") .q{</th><td>}. $transaction->getId .q{</td>
|
||
</tr>
|
||
<tr>
|
||
<th>}. $i18n->get("order number") .q{</th><td>}. $transaction->get('orderNumber') .q{</td>
|
||
</tr>
|
||
<tr>
|
||
<th>}. $i18n->get("shipping address") .q{</th><td>}. join(" ",$transaction->get('shippingAddressName'),$transaction->get('shippingAddress1'),$transaction->get('shippingAddress2'),$transaction->get('shippingAddress3'),$transaction->get('shippingCity'),$transaction->get('shippingState'),$transaction->get('shippingCode'),$transaction->get('shippingCountry'),$transaction->get('shippingPhoneNumber')) .q{</td>
|
||
</tr>
|
||
<tr>
|
||
<th>}. $i18n->get("payment address") .q{</th><td>}. join(" ",$transaction->get('paymentAddressName'),$transaction->get('paymentAddress1'),$transaction->get('paymentAddress2'),$transaction->get('paymentAddress3'),$transaction->get('paymentCity'),$transaction->get('paymentState'),$transaction->get('paymentCode'),$transaction->get('paymentCountry'),$transaction->get('paymentPhoneNumber')) .q{</td>
|
||
</tr>
|
||
<tr>
|
||
<th>}. $i18n->get("price") .q{</th><td>}. $transaction->get('amount') .q{</td>
|
||
</tr>
|
||
</table>
|
||
};
|
||
|
||
return $admin->getAdminConsole->render($output, $i18n->get('transactions'));
|
||
}
|
||
|
||
1;
|