262 lines
7.9 KiB
Perl
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;
|
|
|