650 lines
17 KiB
Perl
650 lines
17 KiB
Perl
package WebGUI::Commerce::Transaction;
|
|
|
|
use strict;
|
|
use WebGUI::Session;
|
|
use WebGUI::Id;
|
|
use WebGUI::SQL;
|
|
use WebGUI::Commerce::Payment;
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 addItem ( item, quantity )
|
|
|
|
Add's an item to the transaction.
|
|
|
|
=head3 item
|
|
|
|
An WebGUI::Commerce::Item object of the item you want to add.
|
|
|
|
=head3 quantity
|
|
|
|
The number of items that are tobe added.
|
|
|
|
=cut
|
|
|
|
sub addItem {
|
|
my ($self, $item, $quantity);
|
|
$self = shift;
|
|
$item = shift;
|
|
$quantity = shift;
|
|
|
|
WebGUI::SQL->write("insert into transactionItem ".
|
|
"(transactionId, itemName, amount, quantity, itemId, itemType) values ".
|
|
"(".quote($self->{_transactionId}).",".quote($item->name).",".quote($item->price).",".quote($quantity).",".
|
|
quote($item->id).",".quote($item->type).")");
|
|
# Adjust total amount in the transaction table.
|
|
WebGUI::SQL->write("update transaction set amount=amount+".($item->price * $quantity)." where transactionId=".quote($self->{_transactionId}));
|
|
$self->{_properties}{amount} += ($item->price * $quantity);
|
|
push @{$self->{_items}}, {
|
|
transactionId => $self->{_transactionId},
|
|
itemName => $item->name,
|
|
amount => $item->price,
|
|
quantity => $quantity,
|
|
itemId => $item->id,
|
|
itemType => $item->type,
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 cancelTransaction
|
|
|
|
Cancels a recurring transaction. This is done by trying to cancel the subscription at the gateway
|
|
using a Payment plugin. If this is succesfull the transaction is marked as canceled.
|
|
|
|
=cut
|
|
|
|
sub cancelTransaction {
|
|
my ($self, $item, $plugin);
|
|
$self = shift;
|
|
|
|
return "Not a recurring transaction" unless ($self->isRecurring);
|
|
|
|
# Recurring transactions can only have one item, so our items must be the first
|
|
$item = $self->getItems->[0];
|
|
|
|
$plugin = WebGUI::Commerce::Payment->load($self->gateway);
|
|
$plugin->cancelRecurringPayment({
|
|
id => $self->gatewayId,
|
|
transaction => $self,
|
|
});
|
|
return $plugin->resultMessage.' (code: '.$plugin->errorCode.')' if ($plugin->errorCode);
|
|
|
|
$self->status('Canceled');
|
|
|
|
return undef;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 completeTransaction
|
|
|
|
Sets the status of a transaction to 'Completed' and executes the handler for every item attached to
|
|
the transction.
|
|
|
|
=cut
|
|
|
|
sub completeTransaction {
|
|
my ($self, $item);
|
|
$self = shift;
|
|
|
|
foreach (@{$self->getItems}) {
|
|
$item = WebGUI::Commerce::Item->new($_->{itemId}, $_->{itemType});
|
|
$item->handler;
|
|
}
|
|
|
|
$self->status('Completed');
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 delete
|
|
|
|
Deletes the transaction from the database;
|
|
|
|
=cut
|
|
|
|
sub delete {
|
|
my ($self) = shift;
|
|
|
|
WebGUI::SQL->write("delete from transaction where transactionId=".quote($self->{_transactionId}));
|
|
WebGUI::SQL->write("delete from transactionItem where transactionId=".quote($self->{_transactionId}));
|
|
|
|
undef $self;
|
|
}
|
|
|
|
sub deleteItem {
|
|
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 deleteItem ( itemId, itemType )
|
|
|
|
Deletes an item from a transaction. This will purge the record from the database, and
|
|
updates the amount of the transaction. It doesn't change the shipping cost however.
|
|
|
|
Also if you want to credit the user (you'll probably want to) for the amount of the
|
|
removed items, you must do this yourself.
|
|
|
|
=head3 itemId
|
|
|
|
The id of the item you want to remove.
|
|
|
|
=head3 itemType
|
|
|
|
The type of the item you want to remove.
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------
|
|
sub deleteItem {
|
|
my ($self, $itemId, $itemType, $amount, @items);
|
|
$self = shift;
|
|
$itemId = shift;
|
|
$itemType = shift;
|
|
|
|
WebGUI::ErrorHandler::fatal('No itemId') unless ($itemId);
|
|
WebGUI::ErrorHandler::fatal('No itemType') unless ($itemType);
|
|
|
|
$amount = $self->get('amount');
|
|
|
|
foreach (@{$self->getItems}) {
|
|
|
|
if (($_->{itemId} eq $itemId) && ($_->{itemType} eq $itemType)) {
|
|
$amount = $amount - ($_->{quantity} * $_->{amount});
|
|
} else {
|
|
push(@items, $_);
|
|
}
|
|
}
|
|
|
|
WebGUI::SQL->write("delete from transactionItem where transactionId=".quote($self->get('transactionId')).
|
|
" and itemId=".quote($itemId)." and itemType=".quote($itemType));
|
|
|
|
WebGUI::SQL->write("update transaction set amount=".quote($amount)." where transactionId=".quote($self->get('transactionId')));
|
|
|
|
$self->{_properties}{amount} = $amount;
|
|
|
|
$self->{_items} = \@items;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 gateway ( gatewayName )
|
|
|
|
Returns the gateway connected to the transaction. If gatewayName is given the gateway property is set to that.
|
|
|
|
=head3 gatewayName
|
|
|
|
The name to which to set the gateway.
|
|
|
|
=cut
|
|
|
|
sub gateway {
|
|
my ($self, $gateway);
|
|
$self = shift;
|
|
$gateway = shift;
|
|
|
|
if ($gateway) {
|
|
$self->{_properties}{gateway} = $gateway;
|
|
WebGUI::SQL->write("update transaction set gateway=".quote($gateway)." where transactionId=".quote($self->{_transactionId}));
|
|
}
|
|
|
|
return $self->{_properties}{gateway};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 gatewayId ( id )
|
|
|
|
Returns the gateway ID of the transaction. If id is given the gateway ID is set to it.
|
|
|
|
=head3 id
|
|
|
|
The ID which to set the gatewayId to.
|
|
|
|
=cut
|
|
|
|
sub gatewayId {
|
|
my ($self, $gatewayId);
|
|
$self = shift;
|
|
$gatewayId = shift;
|
|
|
|
if ($gatewayId) {
|
|
$self->{_properties}{gatewayId} = $gatewayId;
|
|
WebGUI::SQL->write("update transaction set gatewayId=".quote($gatewayId)." where transactionId=".quote($self->{_transactionId}));
|
|
}
|
|
|
|
return $self->{_properties}{gatewayId};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 get ( property )
|
|
|
|
Returns the property requested. If no property is specified this method returns a hashref
|
|
containing all properties.
|
|
|
|
=head3 property
|
|
|
|
The name of the property you want.
|
|
|
|
=cut
|
|
|
|
sub get {
|
|
my ($self, $key);
|
|
$self = shift;
|
|
$key = shift;
|
|
|
|
return $self->{_properties}{$key} if ($key);
|
|
return $self->{_properties};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getByGatewayId ( id, gateway )
|
|
|
|
Constructor. Return a transaction object that is identified by the given id and payment gateway.
|
|
Returns undef if no match is found.
|
|
|
|
=head3 id
|
|
|
|
The gateway ID of the transaction.
|
|
|
|
=head3 gateway
|
|
|
|
The payment gateway which the transaction is tied to.
|
|
|
|
=cut
|
|
|
|
sub getByGatewayId {
|
|
my ($self, $gatewayId, $paymentGateway, $transactionId);
|
|
$self = shift;
|
|
$gatewayId = shift;
|
|
$paymentGateway = shift;
|
|
|
|
($transactionId) = WebGUI::SQL->quickArray("select transactionId from transaction where gatewayId=".quote($gatewayId).
|
|
" and gateway=".quote($paymentGateway));
|
|
|
|
return WebGUI::Commerce::Transaction->new($transactionId) if $transactionId;
|
|
return undef;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getItems
|
|
|
|
=cut
|
|
|
|
sub getItems {
|
|
my ($self);
|
|
$self = shift;
|
|
|
|
return $self->{_items};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getTransactions ( constraints )
|
|
|
|
Returns an array consisting of WebGUI::Commerce::Transaction objects complying to
|
|
the passed constraints.
|
|
|
|
=head3 constraints
|
|
|
|
A hashref containing the contrains by which the transactions are selected. These can be:
|
|
|
|
* initStart
|
|
Epoch that specifies the lower bounds on the initialisation date.
|
|
|
|
* initStop
|
|
Epoch that specifies the upper bound on the initialisation date.
|
|
|
|
* completionStart
|
|
Epoch specifying the lower bound on the completion date.
|
|
|
|
* completionStop
|
|
Epoch specifying the upper bound on the completion date.
|
|
|
|
* status
|
|
The status of the transaction. Can be: Pending, Completed or Canceled
|
|
|
|
* shippingStatus
|
|
The shipping status of the transaction. Can be: NotShipped, Shipped or Delivered
|
|
|
|
=cut
|
|
|
|
sub getTransactions {
|
|
my ($self, $criteria, @constraints, $sql, @transactionIds, @transactions);
|
|
|
|
$self = shift;
|
|
$criteria = shift;
|
|
|
|
push (@constraints, 'initDate >= '.quote($criteria->{initStart})) if (defined $criteria->{initStart});
|
|
push (@constraints, 'initDate <= '.quote($criteria->{initStop})) if (defined $criteria->{initStop});
|
|
push (@constraints, 'completionDate >= '.quote($criteria->{completionStart})) if (defined $criteria->{completionStart});
|
|
push (@constraints, 'completionDate <= '.quote($criteria->{completionStop})) if (defined $criteria->{completionStop});
|
|
push (@constraints, 'status='.quote($criteria->{paymentStatus})) if (defined $criteria->{paymentStatus});
|
|
push (@constraints, 'shippingStatus='.quote($criteria->{shippingStatus})) if (defined $criteria->{shippingStatus});
|
|
|
|
$sql = 'select transactionId from transaction';
|
|
$sql .= ' where '.join(' and ', @constraints) if (@constraints);
|
|
|
|
@transactionIds = WebGUI::SQL->buildArray($sql);
|
|
|
|
foreach (@transactionIds) {
|
|
push(@transactions, WebGUI::Commerce::Transaction->new($_));
|
|
}
|
|
|
|
return @transactions;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 isRecurring ( recurring )
|
|
|
|
Returns a boolean indcating whether the transaction is recurring. If recurring is given, the isRecurring flag
|
|
will be set to it.
|
|
|
|
=head3 recurring
|
|
|
|
A boolean which sets the transaction as recurring if true.
|
|
|
|
=cut
|
|
|
|
sub isRecurring {
|
|
my ($self, $recurring);
|
|
$self = shift;
|
|
$recurring = shift;
|
|
|
|
if (defined $recurring) {
|
|
$self->{_properties}{recurring} = $recurring;
|
|
WebGUI::SQL->write("update transaction set recurring=".quote($recurring)." where transactionId=".quote($self->{_transactionId}));
|
|
}
|
|
|
|
return $self->{_properties}{recurring};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 lastPayedTerm ( term )
|
|
|
|
Returns the last term number that has been paid. If term is given this number will be set to it.
|
|
|
|
-head3 term
|
|
|
|
The number which to set tha last payed term to.
|
|
|
|
=cut
|
|
|
|
sub lastPayedTerm {
|
|
my ($self, $lastPayedTerm);
|
|
$self = shift;
|
|
$lastPayedTerm = shift;
|
|
|
|
if (defined $lastPayedTerm) {
|
|
$self->{_properties}{lastPayedTerm} = $lastPayedTerm;
|
|
WebGUI::SQL->write("update transaction set lastPayedTerm=".quote($lastPayedTerm)." where transactionId=".quote($self->{_transactionId}));
|
|
}
|
|
|
|
return $self->{_properties}{lastPayedTerm};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 new ( transactionId, [ gateway, [ userId ] ] )
|
|
|
|
Constructor. Returns a transaction object. If transactionId is set to 'new' a new transaction is created.
|
|
|
|
=head3 transactionId
|
|
|
|
The transaction ID of the transaction you want. Set to 'new' for a new transaction.
|
|
|
|
=head3 gateway
|
|
|
|
The payment gateway to use for this transaction. Only needed for new transactions.
|
|
|
|
=head3 userId
|
|
|
|
The userId of the user for whom to create this transaction. Defaults to the current user. Only optional for
|
|
new transactions.
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my ($class, $transactionId, $gatewayId, $userId, $properties, $sth, $row, @items);
|
|
|
|
$class = shift;
|
|
$transactionId = shift;
|
|
$gatewayId = shift;
|
|
$userId = shift || $session{user}{userId};
|
|
|
|
if ($transactionId eq 'new') {
|
|
$transactionId = WebGUI::Id::generate;
|
|
|
|
WebGUI::SQL->write("insert into transaction ".
|
|
"(transactionId, userId, amount, gatewayId, initDate, completionDate, status) values ".
|
|
"(".quote($transactionId).",".quote($userId).",0,".quote($gatewayId).",".quote(time).",NULL,'Pending')");
|
|
}
|
|
|
|
$properties = WebGUI::SQL->quickHashRef("select * from transaction where transactionId=".quote($transactionId));
|
|
$sth = WebGUI::SQL->read("select * from transactionItem where transactionId=".quote($transactionId));
|
|
while ($row = $sth->hashRef) {
|
|
push(@items, $row);
|
|
}
|
|
|
|
bless {_transactionId => $transactionId, _properties => $properties, _items => \@items}, $class;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 pendingTransactions
|
|
|
|
Returns a reference to an array which contains transaction objects of all pending transactions.
|
|
|
|
=cut
|
|
|
|
sub pendingTransactions {
|
|
my (@transactionIds, @transactions);
|
|
@transactionIds = WebGUI::SQL->buildArray("select transactionId from transaction where status = 'Pending'");
|
|
|
|
foreach (@transactionIds) {
|
|
push(@transactions, WebGUI::Commerce::Transaction->new($_));
|
|
}
|
|
|
|
return \@transactions;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 shippingCost ( [amount] )
|
|
|
|
Returns the shipping cost for this transaction. If amount is supplied the sipping cost will
|
|
be set to that value.
|
|
|
|
=head3 amount
|
|
If supplied the shipping cost of the transaction will be set to this value.
|
|
|
|
=cut
|
|
|
|
sub shippingCost {
|
|
my ($self, $shippingCost);
|
|
$self = shift;
|
|
$shippingCost = shift;
|
|
|
|
if ($shippingCost) {
|
|
$self->{_properties}{shippingCost} = $shippingCost;
|
|
WebGUI::SQL->write("update transaction set shippingCost=".quote($shippingCost)." where transactionId=".quote($self->{_transactionId}));
|
|
}
|
|
|
|
return $self->{_properties}{shippingCost};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 shippingMethod ( [ method ] )
|
|
|
|
Returns the shipping method for this transaction. If amount is supplied the shipping method will
|
|
be set to it.
|
|
|
|
=head3 method
|
|
If supplied the shipping method of the transaction will be set to this value.
|
|
|
|
=cut
|
|
|
|
sub shippingMethod {
|
|
my ($self, $shippingMethod);
|
|
$self = shift;
|
|
$shippingMethod = shift;
|
|
|
|
if ($shippingMethod) {
|
|
$self->{_properties}{shippingMethod} = $shippingMethod;
|
|
WebGUI::SQL->write("update transaction set shippingMethod=".quote($shippingMethod)." where transactionId=".quote($self->{_transactionId}));
|
|
}
|
|
|
|
return $self->{_properties}{shippingMethod};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 shippingOptions ( [ options ] )
|
|
|
|
Returns the shipping options for this transaction. If options is supplied the shipping options will
|
|
be set to it.
|
|
|
|
=head3 options
|
|
If supplied the shipping options of the transaction will be set to this value. This should probably
|
|
be some serialized datastructure.
|
|
|
|
=cut
|
|
|
|
sub shippingOptions {
|
|
my ($self, $shippingOptions);
|
|
$self = shift;
|
|
$shippingOptions = shift;
|
|
|
|
if ($shippingOptions) {
|
|
$self->{_properties}{shippingOptions} = $shippingOptions;
|
|
WebGUI::SQL->write("update transaction set shippingOptions=".quote($shippingOptions)." where transactionId=".quote($self->{_transactionId}));
|
|
}
|
|
|
|
return $self->{_properties}{shippingOptions};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 shippingStatus ( [ status ] )
|
|
|
|
Returns the shipping status for this transaction. If status is supplied the shipping status will
|
|
be set to it.
|
|
|
|
=head3 status
|
|
If supplied the shipping status of the transaction will be set to this value.
|
|
|
|
=cut
|
|
|
|
sub shippingStatus {
|
|
my ($self, $shippingStatus);
|
|
$self = shift;
|
|
$shippingStatus = shift;
|
|
|
|
if ($shippingStatus) {
|
|
$self->{_properties}{shippingStatus} = $shippingStatus;
|
|
WebGUI::SQL->write("update transaction set shippingStatus=".quote($shippingStatus)." where transactionId=".quote($self->{_transactionId}));
|
|
}
|
|
|
|
return $self->{_properties}{shippingStatus};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 status ( status )
|
|
|
|
Returns the status of the transaction. If status is given the transaction status will be set to it.
|
|
|
|
=head3 status
|
|
|
|
The value to set the transaction status to.
|
|
|
|
=cut
|
|
|
|
sub status {
|
|
my ($self, $status);
|
|
$self = shift;
|
|
$status = shift;
|
|
|
|
if ($status) {
|
|
$self->{_properties}{status} = $status;
|
|
WebGUI::SQL->write("update transaction set status=".quote($status)." where transactionId=".quote($self->{_transactionId}));
|
|
}
|
|
|
|
return $self->{_properties}{status};
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 trackingNumber ( [ number ] )
|
|
|
|
Returns the tracking number of the shipped transaction. If numer is supplied the tracking number will
|
|
be set to it.
|
|
|
|
=head3 number
|
|
If supplied the tracking number of the transaction will be set to this value.
|
|
|
|
=cut
|
|
|
|
sub trackingNumber {
|
|
my ($self, $trackingNumber);
|
|
$self = shift;
|
|
$trackingNumber = shift;
|
|
|
|
if ($trackingNumber) {
|
|
$self->{_properties}{trackingNumber} = $trackingNumber;
|
|
WebGUI::SQL->write("update transaction set trackingNumber=".quote($trackingNumber)." where transactionId=".quote($self->{_transactionId}));
|
|
}
|
|
|
|
return $self->{_properties}{trackingNumber};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 transactionId
|
|
|
|
Returns the transactionId of the transaction.
|
|
|
|
=cut
|
|
|
|
sub transactionId {
|
|
my $self = shift;
|
|
return $self->{_transactionId};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 transactionsByUser ( userId )
|
|
|
|
Returns a reference to an array containing transaction objects of all tranactions by the user corresponding to userId.
|
|
|
|
=head3 userId
|
|
|
|
The ID of the user you want the transaction of.
|
|
|
|
=cut
|
|
|
|
sub transactionsByUser {
|
|
my ($self, @transactionIds, @transactions, $userId);
|
|
my $self = shift;
|
|
my $userId = shift;
|
|
|
|
@transactionIds = WebGUI::SQL->buildArray("select transactionId from transaction where userId =".quote($userId));
|
|
foreach (@transactionIds) {
|
|
push (@transactions, WebGUI::Commerce::Transaction->new($_));
|
|
}
|
|
|
|
return \@transactions;
|
|
}
|
|
|
|
1;
|
|
|