From cbc830123a17338596d659d930828ba5dce595c2 Mon Sep 17 00:00:00 2001 From: Colin Kuskie Date: Sun, 7 Sep 2008 23:14:42 +0000 Subject: [PATCH] RFE: Add workflow that checks all products to see if they are close to a user configured level, and email a group to let them know that they are close to being out of stock. --- docs/changelog/7.x.x.txt | 1 + .../Workflow/Activity/NotifyAboutLowStock.pm | 141 ++++++++++++++++ .../Workflow_Activity_NotifyAboutLowStock.pm | 38 +++++ t/Workflow/Activity/NotifyAboutLowStock.t | 153 ++++++++++++++++++ 4 files changed, 333 insertions(+) create mode 100644 lib/WebGUI/Workflow/Activity/NotifyAboutLowStock.pm create mode 100644 lib/WebGUI/i18n/English/Workflow_Activity_NotifyAboutLowStock.pm create mode 100644 t/Workflow/Activity/NotifyAboutLowStock.t diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 0e8d4e8ed..d318109d7 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -22,6 +22,7 @@ - fixed: DataForm Integer value zero does not pass validation - added: Page range (start-finish) to available paginator text - rfe: view profile + - rfe: Shop: workflow warning for almost out of stock - fixed: Show Message On Login continue link - fixed: Show Message On Login doesn't show after anon registration - fixed: Settings - Show Message On Login behaviour diff --git a/lib/WebGUI/Workflow/Activity/NotifyAboutLowStock.pm b/lib/WebGUI/Workflow/Activity/NotifyAboutLowStock.pm new file mode 100644 index 000000000..b00f59d4c --- /dev/null +++ b/lib/WebGUI/Workflow/Activity/NotifyAboutLowStock.pm @@ -0,0 +1,141 @@ +package WebGUI::Workflow::Activity::NotifyAboutLowStock; + + +=head1 LEGAL + + ------------------------------------------------------------------- + WebGUI is Copyright 2001-2008 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 base 'WebGUI::Workflow::Activity'; +use WebGUI::International; +use WebGUI::Asset::Sku::Product; +use WebGUI::Inbox; + +=head1 NAME + +Package WebGUI::Workflow::Activity::NotifyAboutUser + +=head1 DESCRIPTION + +Takes a user object and sends out a message. Can use macros in message, to and subject +fields. + +=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 ( session, definition ) + +See WebGUI::Workflow::Activity::defintion() for details. + +=cut + +sub definition { + my $class = shift; + my $session = shift; + my $definition = shift; + my $i18n = WebGUI::International->new($session, "Workflow_Activity_NotifyAboutLowStock"); + push(@{$definition}, { + name=>$i18n->get("activityName"), + properties=> { + warningLimit => { + fieldType=>"integer", + label=>$i18n->get("warning limit"), + defaultValue=>42, + hoverHelp=>$i18n->get("warning limit help"), + }, + toGroup => { + fieldType=>"group", + label=>$i18n->get("group to notify"), + defaultValue=>3, + hoverHelp=>$i18n->get("group to notify help"), + }, + subject => { + fieldType=>"text", + label=>$i18n->get("subject", 'Asset_DataForm'), + defaultValue=>'', + hoverHelp=>$i18n->get("subject help", 'Asset_DataForm'), + }, + } + }); + return $class->SUPER::definition($session,$definition); +} + + +#------------------------------------------------------------------- + +=head2 execute ( [ object ] ) + +See WebGUI::Workflow::Activity::execute() for details. + +=cut + +sub execute { + my ($self, undef, $instance) = @_; + my $message = $instance->getScratch('LowStockMessage') || ''; + my $counter = $instance->getScratch('LowStockLast') || 0; + my $belowThreshold = $instance->getScratch('LowStockBelow') || 0; + my $productIterator = WebGUI::Asset::Sku::Product->getIsa($self->session, $counter); + my $warningLimit = $self->get('warningLimit'); + my $finishTime = time() + $self->getTTL; + my $expired = 0; + PRODUCT: foreach my $product ($productIterator->()) { + VARIANT: foreach my $collateral ( @{ $product->getAllCollateral('variantsJSON') }) { + if ($collateral->{quantity} <= $warningLimit) { + ##Build message + $belowThreshold = 1; + $message .= $product->getUrl(sprintf 'func=editVariant;vid=%s', $collateral->{variantId}) + . "\n"; + } + } + $counter++; + ##Time check and set flag + if (time() > $finishTime) { + $expired = 1; + last PRODUCT; + } + } + ##If timer expired, then store message and limit and release + if ($expired) { + $instance->setScratch('LowStockMessage', $message); + $instance->setScratch('LowStockLast', $counter); + $instance->setScratch('LowStockBelow', $belowThreshold); + return $self->WAITING; + } + + $instance->deleteScratch('LowStockMessage'); + $instance->deleteScratch('LowStockLast'); + $instance->deleteScratch('LowStockBelow'); + if ($belowThreshold) { + my $inbox = WebGUI::Inbox->new($self->session); + $inbox->addMessage({ + status => 'completed', + subject => $self->get('subject'), + groupId => $self->get('toGroup'), + message => $message, + }); + } + + return $self->COMPLETE; +} + +1; diff --git a/lib/WebGUI/i18n/English/Workflow_Activity_NotifyAboutLowStock.pm b/lib/WebGUI/i18n/English/Workflow_Activity_NotifyAboutLowStock.pm new file mode 100644 index 000000000..e1770c950 --- /dev/null +++ b/lib/WebGUI/i18n/English/Workflow_Activity_NotifyAboutLowStock.pm @@ -0,0 +1,38 @@ +package WebGUI::i18n::English::Workflow_Activity_NotifyAboutLowStock; +use strict; + +our $I18N = { + + 'activityName' => { + message => q|Notify About Low Stock|, + context => q|The name of this workflow activity.|, + lastUpdated => 0, + }, + + 'warning limit' => { + message => q|Warning Limit|, + context => q|Field label in the edit Workflow Activity screen.|, + lastUpdated => 0, + }, + + 'warning limit help' => { + message => q|When a variant of a product has less than this amount, you will be warned.|, + context => q|Hover help in the edit Workflow Activity screen.|, + lastUpdated => 0, + }, + + 'group to notify' => { + message => q|Group to notify|, + context => q|Label in the edit Workflow Activity screen.|, + lastUpdated => 0, + }, + + 'group to notify help' => { + message => q|Group to notify|, + context => q|Hover help in the edit Workflow Activity screen.|, + lastUpdated => 0, + }, + +}; + +1; diff --git a/t/Workflow/Activity/NotifyAboutLowStock.t b/t/Workflow/Activity/NotifyAboutLowStock.t new file mode 100644 index 000000000..a6f6dfc4d --- /dev/null +++ b/t/Workflow/Activity/NotifyAboutLowStock.t @@ -0,0 +1,153 @@ +#------------------------------------------------------------------- +# WebGUI is Copyright 2001-2008 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 +#------------------------------------------------------------------- + +use FindBin; +use strict; +use lib "$FindBin::Bin/../../lib"; + +use WebGUI::Test; +use WebGUI::Asset; +use WebGUI::Asset::Sku::Product; +use WebGUI::Workflow::Activity::NotifyAboutLowStock; +use WebGUI::Inbox; + +use Data::Dumper; +use Test::More; +use URI; + +plan tests => 15; # increment this value for each test you create + +my $session = WebGUI::Test->session; +$session->user({userId => 3}); +my $admin = $session->user; +my $inbox = WebGUI::Inbox->new($session); + +my $import = WebGUI::Asset->getImportNode($session); + +my $posters = $import->addChild({ + className => 'WebGUI::Asset::Sku::Product', + url => 'cell_posters', + title => "Red's Posters", +}); + +my $ritaVarId = $posters->setCollateral('variantsJSON', 'variantId', 'new', + { + shortdesc => 'Rita Hayworth', + varSku => 'rita-1', + price => 10, + weight => 1, + quantity => 25, + }, +); + +my $raquelVarId = $posters->setCollateral('variantsJSON', 'variantId', 'new', + { + shortdesc => 'Raquel Welch', + varSku => 'fuzzy-britches', + price => 20, + weight => 1, + quantity => 500, + }, +); + +my $marilynVarId = $posters->setCollateral('variantsJSON', 'variantId', 'new', + { + shortdesc => 'Marilyn Monroe', + varSku => 'subway-skirt', + price => 50, + weight => 1, + quantity => 5, + }, +); + +my $workflow = WebGUI::Workflow->create($session, + { + enabled => 1, + objectType => 'None', + mode => 'realtime', + }, +); + +my $threshold = $workflow->addActivity('WebGUI::Workflow::Activity::NotifyAboutLowStock'); +$threshold->set('className' , 'WebGUI::Activity::NotifyAboutLowStock'); +$threshold->set('toGroup' , 3); +$threshold->set('subject' , 'Threshold=10'); +$threshold->set('warningLimit' , 10); + +my $instance1 = WebGUI::Workflow::Instance->create($session, + { + workflowId => $workflow->getId, + skipSpectreNotification => 1, + } +); + +my $retVal; + +$retVal = $instance1->run(); +is($retVal, 'complete', 'First workflow was run'); +$retVal = $instance1->run(); +is($retVal, 'done', 'Workflow is done'); + +is($instance1->getScratch('LowStockMessage'), undef, 'No scratch data for message'); +is($instance1->getScratch('LowStockLast'), undef, 'No scratch data for last index'); + +my $messages = $inbox->getMessagesForUser($admin); +is(scalar @{$messages}, 1, 'Received one message'); + +my $message = $messages->[0]; + +my $body = $message->get('message'); +is($message->get('subject'), 'Threshold=10', 'Message has the right subject'); +my @urls = split /\n/, $body; +is (scalar @urls, 1, 'Only one variant is below the threshold'); +my $url = pop @urls; +my $uri = URI->new($url); +is($uri->path, $posters->getUrl, 'Link in message has correct URL path'); +is($uri->query, 'func=editVariant;vid='.$marilynVarId, 'Link in message has function and variant id'); + +wipeMessages($inbox, $admin); +is(scalar @{$inbox->getMessagesForUser($admin)}, 0, 'All messages deleted'); +$instance1->delete; + +##Now, change the threshold and make sure that we get no messages +$threshold->set('warningLimit', 2); +is($threshold->get('warningLimit'), 2, 'Reset warningLimit to 2'); + +my $instance2 = WebGUI::Workflow::Instance->create($session, + { + workflowId => $workflow->getId, + skipSpectreNotification => 1, + } +); + +$retVal = $instance2->run(); +is($retVal, 'complete', 'The workflow was run the second time'); +$retVal = $instance2->run(); +is($retVal, 'done', 'Workflow is done the second time'); +is(scalar @{$inbox->getMessagesForUser($admin)}, 0, 'No messages sent since threshold is below quantity of all products'); + +$message = $inbox->getMessagesForUser($admin)->[0]; + +END { + $workflow->delete; + $posters->purge; + my $i = 0; + wipeMessages($inbox, $admin); + $messages = $inbox->getMessagesForUser($admin); + is(scalar @{$messages}, 0, 'Inbox cleaned up'); +} + +sub wipeMessages { + my ($inbox, $user) = @_; + foreach my $message (@{ $inbox->getMessagesForUser($user) }) { + $message->delete; + } + +}