added scheduled vendor payouts workflow activity
This commit is contained in:
parent
b8b7dc2875
commit
d87d766856
5 changed files with 357 additions and 7 deletions
|
|
@ -7,6 +7,11 @@ upgrading from one version to the next, or even between multiple
|
||||||
versions. Be sure to heed the warnings contained herein as they will
|
versions. Be sure to heed the warnings contained herein as they will
|
||||||
save you many hours of grief.
|
save you many hours of grief.
|
||||||
|
|
||||||
|
7.8.2
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
* WebGUI now requires Business::PayPal::API 0.62 or higher.
|
||||||
|
|
||||||
|
|
||||||
7.8.1
|
7.8.1
|
||||||
--------------------------------------------------------------------
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -32,6 +37,7 @@ save you many hours of grief.
|
||||||
prefix from the filename.
|
prefix from the filename.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
7.8.0
|
7.8.0
|
||||||
--------------------------------------------------------------------
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,18 +35,36 @@ fixTableDefaultCharsets($session);
|
||||||
correctWikiAttachmentPermissions( $session );
|
correctWikiAttachmentPermissions( $session );
|
||||||
transactionsNotifications( $session );
|
transactionsNotifications( $session );
|
||||||
fixBadVarCharColumns ( $session );
|
fixBadVarCharColumns ( $session );
|
||||||
|
addVendorPayouts($session);
|
||||||
|
|
||||||
finish($session); # this line required
|
finish($session); # this line required
|
||||||
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------------
|
#----------------------------------------------------------------------------
|
||||||
# Describe what our function does
|
sub addVendorPayouts {
|
||||||
#sub exampleFunction {
|
my $session = shift;
|
||||||
# my $session = shift;
|
print "\tAdding vendor payouts... " unless $quiet;
|
||||||
# print "\tWe're doing some stuff here that you should know about... " unless $quiet;
|
my $db = $session->db;
|
||||||
# # and here's our code
|
$db->write(" create table if not exists vendorPayoutLog (
|
||||||
# print "DONE!\n" unless $quiet;
|
payoutId char(22) binary not null primary key,
|
||||||
#}
|
isSuccessful tinyint(1) not null,
|
||||||
|
errorCode char(10),
|
||||||
|
errorMessage char(255),
|
||||||
|
paypalTimestamp char(20) not null,
|
||||||
|
amount decimal(7,2) not null,
|
||||||
|
currency char(3) not null,
|
||||||
|
correlationId char(13) not null,
|
||||||
|
paymentInformation char(255) not null
|
||||||
|
)");
|
||||||
|
$db->write(" create table if not exists vendorPayoutLog_items (
|
||||||
|
payoutId char(22) binary not null,
|
||||||
|
transactionItemId char(22) binary not null,
|
||||||
|
amount decimal(7,2) not null,
|
||||||
|
primary key( payoutId, transactionItemId )
|
||||||
|
)");
|
||||||
|
|
||||||
|
print "DONE!\n" unless $quiet;
|
||||||
|
}
|
||||||
|
|
||||||
#----------------------------------------------------------------------------
|
#----------------------------------------------------------------------------
|
||||||
sub fixTableDefaultCharsets {
|
sub fixTableDefaultCharsets {
|
||||||
|
|
|
||||||
262
lib/WebGUI/Workflow/Activity/PayoutVendors.pm
Normal file
262
lib/WebGUI/Workflow/Activity/PayoutVendors.pm
Normal file
|
|
@ -0,0 +1,262 @@
|
||||||
|
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 notication 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->send;
|
||||||
|
|
||||||
|
$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;
|
||||||
|
|
||||||
63
lib/WebGUI/i18n/English/Workflow_Activity_PayoutVendors.pm
Normal file
63
lib/WebGUI/i18n/English/Workflow_Activity_PayoutVendors.pm
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
package WebGUI::i18n::English::Workflow_Activity_PayoutVendors;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
our $I18N = {
|
||||||
|
'PayPal username' => {
|
||||||
|
message => q|PayPal username|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|field label|
|
||||||
|
},
|
||||||
|
|
||||||
|
'PayPal password' => {
|
||||||
|
message => q|PayPal password|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|field label|
|
||||||
|
},
|
||||||
|
|
||||||
|
'PayPal signature' => {
|
||||||
|
message => q|PayPal signature|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|field label|
|
||||||
|
},
|
||||||
|
|
||||||
|
'Use in Sandbox (test-mode)' => {
|
||||||
|
message => q|Use in Sandbox (test-mode)|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|field label|
|
||||||
|
},
|
||||||
|
|
||||||
|
'Currency code' => {
|
||||||
|
message => q|Currency code|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|field label|
|
||||||
|
},
|
||||||
|
|
||||||
|
'Subject for vendor notification email' => {
|
||||||
|
message => q|Subject for vendor notification email|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|field label|
|
||||||
|
},
|
||||||
|
|
||||||
|
'Vendor payout from' => {
|
||||||
|
message => q|Vendor payout from|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|Prefix that goes before company URL to create the default value from Subject for vendor notification email.|
|
||||||
|
},
|
||||||
|
|
||||||
|
'Notify on error' => {
|
||||||
|
message => q|Notify on error|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|field label|
|
||||||
|
},
|
||||||
|
|
||||||
|
'Vendor Payout' => {
|
||||||
|
message => q|Vendor Payout|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|field label|
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
1;
|
||||||
|
#vim:ft=perl
|
||||||
|
|
@ -133,6 +133,7 @@ checkModule('Digest::SHA', '5.47' );
|
||||||
checkModule("CSS::Minifier::XS", "0.03" );
|
checkModule("CSS::Minifier::XS", "0.03" );
|
||||||
checkModule("JavaScript::Minifier::XS", "0.05" );
|
checkModule("JavaScript::Minifier::XS", "0.05" );
|
||||||
checkModule("Readonly", "1.03" );
|
checkModule("Readonly", "1.03" );
|
||||||
|
checkModule("Business::PayPal::API", "0.62" );
|
||||||
|
|
||||||
failAndExit("Required modules are missing, running no more checks.") if $missingModule;
|
failAndExit("Required modules are missing, running no more checks.") if $missingModule;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue