webgui/lib/WebGUI/Workflow/Activity/PayoutVendors.pm
2010-02-24 09:59:30 -08:00

262 lines
7.9 KiB
Perl

package WebGUI::Workflow::Activity::PayoutVendors;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2009 Plain Black Corporation.
-------------------------------------------------------------------
Please read the legal notices (docs/legal.txt) and the license
(docs/license.txt) that came with this distribution before using
this software.
-------------------------------------------------------------------
http://www.plainblack.com info@plainblack.com
-------------------------------------------------------------------
=cut
use strict;
use Business::PayPal::API qw{ MassPay };
use Data::Dumper;
use WebGUI::Mail::Send;
use base 'WebGUI::Workflow::Activity';
=head1 NAME
Package WebGUI::Workflow::Activity::PayoutVendors
=head1 DESCRIPTION
Pays profits to vendors, currently via paypal, but others may be added in the future.
=head1 SYNOPSIS
See WebGUI::Workflow::Activity for details on how to use any activity.
=head1 METHODS
These methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 definition ()
See WebGUI::Workflow::Activity for details.
=cut
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift;
my $i18n = WebGUI::International->new($session, "Workflow_Activity_PayoutVendors");
tie my %properties, 'Tie::IxHash', (
paypalUsername => {
fieldType => 'text',
label => $i18n->get('PayPal username'),
},
paypalPassword => {
fieldType => 'password',
label => $i18n->get('PayPal password'),
},
paypalSignature => {
fieldType => 'text',
label => $i18n->get('PayPal signature'),
},
useSandbox => {
fieldType => 'yesNo',
label => $i18n->get('Use in Sandbox (test-mode)'),
defaultValue => 0,
},
currencyCode => {
fieldType => 'text',
label => $i18n->get('Currency code'),
maxlength => 3,
size => 3,
defaultValue => 'USD',
},
paypalSubject => {
fieldType => 'text',
label => $i18n->get('Subject for vendor notification email'),
defaultValue => $i18n->get('Vendor payout from').' ' . $session->setting->get('companyUrl'),
},
notificationGroupId => {
fieldType => 'group',
label => $i18n->get('Notify on error'),
},
);
push @{ $definition }, {
name => $i18n->get('Vendor Payout'),
properties => \%properties,
};
return $class->SUPER::definition( $session, $definition );
}
#-------------------------------------------------------------------
=head2 payoutVendor (vendorId)
Sends unsent vendor payouts to paypal.
=head3 vendorId
The vendor to be sent his payouts.
=cut
sub payoutVendor {
my $self = shift;
my $vendorId = shift;
my $db = $self->session->db;
my $payoutId = $self->session->id->generate;
# Instanciate vendor and check if he exists.
my $vendor = WebGUI::Shop::Vendor->new( $self->session, $vendorId );
unless ( $vendor ) {
$self->session->log->error( "Could not instanciate vendor with id [$vendorId] for payout" );
return undef;
}
# check to see that the vendor has a payout address
if ($vendor->get('paymentInformation') eq '') {
$self->session->log->warn("Vendor ".$vendor->getId." hasn't specified a payout address.");
return undef;
}
# Fetch all transactionItems that are scheduled for payout to the vendor.
my $sth = $db->read(
'select itemId, vendorPayoutAmount from transactionItem '
. ' where vendorId=? and vendorPayoutStatus=? and vendorPayoutAmount > 0',
[
$vendorId,
'Scheduled',
]
);
# Process all transaction items and log them in the db.
my $totalAmount = 0;
while ( my $item = $sth->hashRef ) {
$totalAmount += $item->{ vendorPayoutAmount };
$db->write( 'insert into vendorPayoutLog_items (payoutId, transactionItemId, amount) values (?,?,?)', [
$payoutId,
$item->{ itemId },
$item->{ vendorPayoutAmount },
] );
}
my $itemCount = $sth->rows;
$sth->finish;
# Do PayPal MassPay request
my $pp = new Business::PayPal::API(
Username => $self->get('paypalUsername'),
Password => $self->get('paypalPassword'),
Signature => $self->get('paypalSignature'),
sandbox => $self->get('useSandbox'),
);
my %response = $pp->MassPay(
EmailSubject => $self->get('paypalSubject'),
currencyID => $self->get('currencyCode'),
MassPayItems => [ {
ReceiverEmail => $vendor->get('paymentInformation'),
Amount => $totalAmount,
UniqueID => $payoutId,
Note => "Payout for $itemCount sold items",
} ],
);
# Process paypal response
my $payoutDetails = {
payoutId => $payoutId,
isSuccessful => $response{ Ack } eq 'Success' ? 1 : 0,
paypalTimestamp => $response{ Timestamp },
correlationId => $response{ CorrelationID },
amount => $totalAmount,
currency => $self->get('currencyCode'),
paymentInformation => $vendor->get('paymentInformation'),
};
if ( $response{ Ack } ne 'Success' ) {
# An error occurred, keep the error codes
my $errorCode = $response{ Error }->[ 0 ]->{ ErrorCode };
my $errorMessage = $response{ Error }->[ 0 ]->{ LongMessage };
# TODO: Send out email.
my $mail = WebGUI::Mail::Send->create($self->session, {
toGroup => $self->get('notificationGroupId'),
subject => 'Vendor payout error',
});
$mail->addText(
"An error occurred during an automated vendor payout attempt. Response details:\n"
. Dumper( \%response )
. "\n\nVendor information:\n"
. Dumper( $vendor->get )
);
$mail->queue;
$payoutDetails->{ errorCode } = $errorCode;
$payoutDetails->{ errorMessage } = $errorMessage;
}
else {
# The transaction was successful, so change the state of the transactionItems to Paid.
$db->write(
'update transactionItem set vendorPayoutStatus=? where itemId in ( '
.' select transactionItemId from vendorPayoutLog_items where payoutId=? '
.')',
[
'Paid',
$payoutId,
]
);
}
# Persist response data to db
$db->setRow( 'vendorPayoutLog', 'payoutId', $payoutDetails, $payoutId );
};
#-------------------------------------------------------------------
=head2 execute ()
See WebGUI::Workflow::Activity for details.
=cut
sub execute {
my $self = shift;
my $object = shift;
my $instance = shift;
my $start = time;
my $ttl = $self->getTTL;
# Fetch vendors eligible for payout.
my $sth = $self->session->db->read(
"select distinct vendorId from transactionItem where vendorPayoutStatus='Scheduled' and vendorPayoutAmount > 0"
);
# Pay on a vendor by vendor basis.
while ( (my $vendorId) = $sth->array ) {
$self->payoutVendor( $vendorId );
# Make sure we won't run longer than allowed.
if ( ( time - $start + 1 ) >= $ttl ) {
$sth->finish;
return $self->WAITING( 1 );
}
}
$sth->finish;
return $self->COMPLETE;
}
1;