webgui/lib/WebGUI/Asset/Sku/Ad.pm
2011-12-28 11:30:38 -08:00

625 lines
20 KiB
Perl

package WebGUI::Asset::Sku::Ad;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2012 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 Moose;
use WebGUI::Definition::Asset;
extends 'WebGUI::Asset::Sku';
define assetName => ['assetName', 'Asset_WikiMaster'];
define icon => 'adsku.gif';
define tableName => 'AdSku';
property purchaseTemplate => (
tab => "display",
fieldType => "template",
namespace => "AdSku/Purchase",
default => 'AldPGu0u-jm_5xK13atCSQ',
label => ["property purchase template", 'Asset_WikiMaster'],
hoverHelp => ["property purchase template help", 'Asset_WikiMaster'],
);
property manageTemplate => (
tab => "display",
fieldType => "template",
namespace => "AdSku/Manage",
default => 'ohjyzab5i-yW6GOWTeDUHg',
label => ["property manage template", 'Asset_WikiMaster'],
hoverHelp => ["property manage template help", 'Asset_WikiMaster'],
);
property adSpace => (
tab => "properties",
fieldType => "AdSpace",
label => ["property ad space", 'Asset_WikiMaster'],
hoverHelp => ["property ad Space help", 'Asset_WikiMaster'],
);
property priority => (
tab => "properties",
default => '1',
fieldType => "integer",
label => ["property priority", 'Asset_WikiMaster'],
hoverHelp => ["property priority help", 'Asset_WikiMaster'],
);
property pricePerClick => (
tab => "shop",
default => '0.00',
fieldType => "float",
label => ["property price per click", 'Asset_WikiMaster'],
hoverHelp => ["property price per click help", 'Asset_WikiMaster'],
);
property pricePerImpression => (
tab => "shop",
default => '0.00',
fieldType => "float",
label => ["property price per impression", 'Asset_WikiMaster'],
hoverHelp => ["property price per impression help", 'Asset_WikiMaster'],
);
property clickDiscounts => (
tab => "shop",
fieldType => 'textarea',
label => ['property click discounts', 'Asset_WikiMaster'],
hoverHelp => ['property click discounts help', 'Asset_WikiMaster'],
default => '',
);
property impressionDiscounts => (
tab => "shop",
fieldType => 'textarea',
label => ['property impression discounts', 'Asset_WikiMaster'],
hoverHelp => ['property impression discounts help', 'Asset_WikiMaster'],
default => '',
);
property karma => (
fieldType => 'integer',
noFormPost => \&_karma_noFormPost,
label => ['property adsku karma', 'Asset_WikiMaster'],
hoverHelp => ['property adsku karma description', 'Asset_WikiMaster'],
defaultvalue => 0,
);
sub _karma_noFormPost {
my $session = shift->session;
return ! $session->setting->get('useKarma');
}
use WebGUI::Asset::Template;
use WebGUI::Form;
use WebGUI::Storage;
use WebGUI::AssetCollateral::Sku::Ad::Ad;
use WebGUI::AdSpace;
use WebGUI::AdSpace::Ad;
=head1 NAME
Package WebGUI::Asset::Sku::Ad
=head1 DESCRIPTION
This Asset allows ads to be purchased via WebGUI shopping
=head1 SYNOPSIS
use WebGUI::Asset::Sku::Ad;
=head1 METHODS
These methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 getAddToCartForm
Returns an empty string, since the add to cart form is complex.
=cut
sub getAddToCartForm {
return '';
}
#-------------------------------------------------------------------
=head2 getAdSpace
Returns an AdSpace object for this Ad Sku.
=cut
sub getAdSpace {
my $self = shift;
my $adSpace = WebGUI::AdSpace->new($self->session,$self->adSpace);
return $adSpace;
}
#-------------------------------------------------------------------
=head2 getClickDiscountText
returns the text to display the number of clicks purchasaed where discounts apply
=cut
sub getClickDiscountText {
my $self = shift;
return getDiscountText($self->i18n->get('click discount'),
$self->clickDiscounts);
}
#-------------------------------------------------------------------
=head2 getConfiguredTitle
combines the adSKu title with the customers ad title
=cut
sub getConfiguredTitle {
my $self = shift;
return $self->title . ' (' . $self->getOptions->{'adtitle'} . ')';
}
#-------------------------------------------------------------------
=head2 getDiscountAmount -- class level function
returns the amount of discount to apply to this purchase
=cut
sub getDiscountAmount {
my($discounts,$count) = @_;
my @discounts = parseDiscountText( $discounts );
my $previousDiscount = 0;
foreach my $discountSet ( @discounts ) {
last if $count < $discountSet->[1];
$previousDiscount = $discountSet->[0];
}
return $previousDiscount;
}
#-------------------------------------------------------------------
=head2 getDiscountText -- class level function
returns a string with a coma seperated list of counts from the discount text
=cut
sub getDiscountText {
my($format,$discounts) = @_;
return sprintf( $format, join( ',', (map { $_->[1] } ( parseDiscountText( $discounts ) ) ) ) );
}
#-------------------------------------------------------------------
=head2 getImpressionDiscountText
returns the text to display the number of impressions purchased where discounts apply
=cut
sub getImpressionDiscountText {
my $self = shift;
return getDiscountText($self->i18n->get('impression discount'),
$self->impressionDiscounts);
}
#-------------------------------------------------------------------
=head2 getPrice
get the price for this purchase
=cut
sub getPrice {
my $self = shift;
my $options = $self->getOptions;
my $impressionCount = $options->{impressions} || $self->{formImpressions};
my $clickCount = $options->{clicks};
my $impressionDiscount = getDiscountAmount($self->impressionDiscounts,$impressionCount );
my $clickDiscount = getDiscountAmount($self->clickDiscounts,$clickCount );
my $impressionPrice = $self->pricePerImpression * ( 100 - $impressionDiscount ) / 100 ;
my $clickPrice = $self->pricePerClick * ( 100 - $clickDiscount ) / 100 ;
return sprintf "%.2f", $impressionPrice * $impressionCount + $clickPrice * $clickCount;
}
#-------------------------------------------------------------------
=head2 i18n
returns an internationalization object for this class
=cut
sub i18n {
my $self = shift;
return WebGUI::International->new($self->session, "Asset_AdSku");
}
#-------------------------------------------------------------------
=head2 manage
generate template vars for manage page
=cut
sub manage {
my ($self) = @_;
my $session = $self->session;
my $i18n = WebGUI::International->new($session, "Asset_AdSku");
my %var;
$var{purchaseLink} = $self->getUrl;
my $iterator = WebGUI::AssetCollateral::Sku::Ad::Ad->getAllIterator($session,{
constraints => [ { "adSkuPurchase.userId = ?" => $self->session->user->userId } ],
orderBy => 'dateOfPurchase',
});
my %ads;
OBJECT: while( my $object = $iterator->() ) {
next OBJECT if $object->get('isDeleted');
next OBJECT if exists $ads{$object->get('adId')};
my $ad = $ads{$object->get('adId')} = WebGUI::AdSpace::Ad->new($session,$object->get('adId'));
push @{$var{myAds}}, {
rowTitle => $ad->get('title'),
rowClicks => $ad->get('clicks') . '/' . $ad->get('clicksBought'),
rowImpressions => $ad->get('impressions') . '/' . $ad->get('impressionsBought'),
rowRenewLink => $self->getUrl('func=renew;Id=' . $object->get('adSkuPurchaseId') ),
};
}
return $self->processTemplate(\%var,undef,$self->{_viewTemplate});
}
#-------------------------------------------------------------------
=head2 onCompletePurchase
inserts the ad into the adspace...
=cut
sub onCompletePurchase {
my $self = shift;
my $session = $self->session;
my $item = shift;
my $options = $self->getOptions;
my $ad;
# LATER: if we use Temp Storage for the image we need to move it to perm storage
my $userId = $item->transaction->get('userId');
if( $options->{adId} ne '' ) {
$ad = WebGUI::AdSpace::Ad->new($session, $options->{adId});
my $clicks = $options->{clicks} + $ad->get('clicksBought');
my $impressions = $options->{impressions} + $ad->get('impressionsBought');
$ad->set({
title => $options->{'adtitle'},
clicksBought => $clicks,
impressionsBought => $impressions,
url => $options->{'link'},
storageId => $options->{'image'},
});
}
else {
$ad = WebGUI::AdSpace::Ad->create($session, $self->adSpace, {
title => $options->{'adtitle'},
clicksBought => $options->{'clicks'},
impressionsBought => $options->{'impressions'},
url => $options->{'link'},
storageId => $options->{'image'},
ownerUserId => $userId,
isActive => 1,
type => 'image',
priority => $self->priority,
adSpace => $self->adSpace,
});
}
WebGUI::AssetCollateral::Sku::Ad::Ad->new($session, {
userId => $userId,
transactionItemId => $item->getId,
adId => $ad->getId,
clicksPurchased => $options->{'clicks'},
impressionsPurchased => $options->{'impressions'},
dateOfPurchase => $item->transaction->get('dateOfPurchase'),
storedImage => $options->{'image'},
isDeleted => 0,
});
}
#-------------------------------------------------------------------
=head2 onRemoveFromCart
deletes the image if it gets removed from the cart
LATER: if we switch to using Temp Storage we do not need to do this.
=cut
sub onRemoveFromCart {
my $self = shift;
my $item = shift;
my $options = $self->getOptions;
WebGUI::Storage->get($self->session,$options->{'image'})->delete;
}
#-------------------------------------------------------------------
=head2 onRefund
delete the add if it gets refunded
=cut
sub onRefund {
my $self = shift;
my $item = shift;
my $iterator = WebGUI::AssetCollateral::Sku::Ad::Ad->getAllIterator($self->session,{
constraints => [ { "transactionItemId = ?" => $item->getId } ],
});
my $crud = $iterator->();
my $ad = WebGUI::AdSpace::Ad->new($self->session,$crud->get('adId'));
my $clicks = $ad->get('clicksBought') - $crud->get('clicksPurchased');
my $impressions = $ad->get('impressionsBought') - $crud->get('impressionsPurchased') ;
$ad->set({
clicksBought => $clicks,
impressionsBought => $impressions,
});
$crud->delete;
}
#-------------------------------------------------------------------
=head2 parseDiscountText -- class level function
returns an array of array ref's that are extracted from the discount description text
=cut
sub parseDiscountText {
my $discountDescription = shift;
my @lines = split "\n", $discountDescription;
my @discounts;
foreach my $line ( @lines ) {
if( $line =~ /^(\d+)\@(\d+)/ ) {
push @discounts, [ $1, $2 ];
}
}
return sort { $a->[1] <=> $b->[1] } @discounts;
}
#-------------------------------------------------------------------
=head2 prepareView
Prepares the template for both www_view and www_manage
=cut
around prepareView => sub {
my $orig = shift;
my $self = shift;
$self->$orig();
my $templateId = shift || $self->purchaseTemplate;
my $template = WebGUI::Asset::Template->newById($self->session, $templateId);
$template->prepare($self->getMetaDataAsTemplateVariables);
$self->{_viewTemplate} = $template;
};
#-------------------------------------------------------------------
=head2 view
Displays the purchase adspace form
=cut
sub view {
my ($self) = @_;
my $session = $self->session;
my $options = $self->getOptions();
my $form = $session->form;
my $i18n = WebGUI::International->new($session, "Asset_AdSku");
my $adSpace = $self->getAdSpace;
my %var = (
formHeader => WebGUI::Form::formHeader($session, { action=>$self->getUrl })
. WebGUI::Form::hidden( $session, { name=>"func", value=>"addToCart" }),
formFooter => WebGUI::Form::formFooter($session),
formSubmit => WebGUI::Form::submit( $session, { value => $i18n->get("form purchase button") }),
error_msg => $options->{error_msg},
hasAddedToCart => $self->{_hasAddedToCart},
continueShoppingUrl => $self->getUrl,
manageLink => $self->getUrl("func=manage"),
adSkuTitle => $self->title,
adSkuDescription => $self->description,
formTitle => WebGUI::Form::text($session, {
-name => "formTitle",
-value => $options->{adtitle},
-size => 40
-defaultValue => 'untitled',
}),
formLink => WebGUI::Form::Url($session, {
-name=>"formLink",
-value=>$options->{link},
-size=>40
}),
formImage => WebGUI::Form::Image($session, {
-name => "formImage",
-value => $options->{image} || $form->get('formImage','image'),
-size => 40
-forceImageOnly => 1,
}),
formClicks => WebGUI::Form::Integer($session, {
-name=>"formClicks",
-value=>$options->{clicks} || $adSpace->get('minimumClicks'),
-size=>40
}),
formImpressions => WebGUI::Form::Integer($session, {
-name=>"formImpressions",
-value=>$options->{impressions} || $adSpace->get('minimumImpressions'),
-size=>40
}),
formAdId => WebGUI::Form::Hidden($session, {
-name=>"formAdId",
-value=>$options->{adId} || '',
}),
clickPrice => $self->pricePerClick,
impressionPrice => $self->pricePerImpression,
minimumClicks => $adSpace->get('minimumClicks'),
minimumImpressions => $adSpace->get('minimumImpressions'),
clickDiscount => $self->getClickDiscountText,
impressionDiscount => $self->getImpressionDiscountText,
);
return $self->processTemplate(\%var,undef,$self->{_viewTemplate});
}
#-------------------------------------------------------------------
=head2 www_addToCart
Add this subscription to the cart.
=cut
sub www_addToCart {
my $self = shift;
return $self->session->privilege->insufficient() unless $self->canView;
my $session = $self->session;
my $i18n = $self->i18n;
my $form = $session->form;
my @errors;
#my $imageStorage = $self->getOptions->{image} || WebGUI::Storage->create($session); # LATER should be createTemp
my $imageStorageId = $form->process('formImage', 'image'); # , $self->getOptions->{image});
my $imageStorage = WebGUI::Storage->get($session,$imageStorageId);
my $code;
if( not defined $imageStorage ) {
$code = 1;
}
elsif( $imageStorage->getErrorCount > 0 ) {
$code = 2;
}
elsif( scalar(@{$imageStorage->getFiles}) == 0 ) {
$code = 3;
}
elsif( $imageStorage->isImage((@{$imageStorage->getFiles})[0]) ) {
$code = 4;
}
if( not defined $imageStorage
or $imageStorage->getErrorCount > 0
or scalar(@{$imageStorage->getFiles}) == 0) {
push @errors, $i18n->get('form error no image') . $code . eval { (@{$imageStorage->getFiles})[0] } ;
}
my $title = $form->process('formTitle');
if($title eq '' ) {
push @errors, $i18n->get('form error no title');
}
my $link = $form->process('formLink','url');
if($link eq '' ) {
push @errors, $i18n->get('form error no link');
}
my $adSpace = $self->getAdSpace;
my $adId = $self->adId;
my $clicks = $form->process('formClicks','integer');
if($clicks < $adSpace->get('minimumClicks') ) {
push @errors, sprintf($i18n->get('form error min clicks'), $adSpace->get('minimumClicks'));
}
my $impressions = $form->process('formImpressions','integer');
if($impressions < $adSpace->get('minimumImpressions') ) {
push @errors, sprintf($i18n->get('form error min impressions'), $adSpace->get('minimumImpressions'));
}
if( @errors == 0 ) {
$self->{_hasAddedToCart} = 1;
$self->addToCart({
adtitle => $title,
link => $link,
clicks => $clicks,
impressions => $impressions,
adId => $adId,
image => $imageStorageId,
});
}
else {
$self->applyOptions({
adtitle => $title,
link => $link,
clicks => $clicks,
impressions => $impressions,
adId => $adId,
image => $imageStorageId,
error_msg => join( '<br />', @errors ),
});
##Since Sku Options do not persist until an item is created, we need a way to persist the storageId through the
##form generation, and back into www_addToCart.
}
return $self->www_view;
}
#-------------------------------------------------------------------
=head2 www_manage
manage previously purchased ads
=cut
sub www_manage {
my $self = shift;
my $check = $self->checkView;
return $check if (defined $check);
$self->session->response->setLastModified($self->getContentLastModified);
$self->session->response->sendHeader;
$self->prepareView($self->manageTemplate);
my $style = $self->processStyle($self->getSeparator);
my ($head, $foot) = split($self->getSeparator,$style);
$self->session->output->print($head, 1);
$self->session->output->print($self->manage);
$self->session->output->print($foot, 1);
return "chunked";
}
#-------------------------------------------------------------------
=head2 www_renew
renew an ad
=cut
sub www_renew {
my $self = shift;
my $session = $self->session;
my $id = $session->form->get('Id');
my $crud = WebGUI::AssetCollateral::Sku::Ad::Ad->new($session,$id);
my $ad = WebGUI::AdSpace::Ad->new($session,$crud->get('adId'));
$self->applyOptions({
adtitle => $ad->get('title'),
clicks => $crud->get('clicksPurchased'),
impressions => $crud->get('impressionsPurchased'),
link => $ad->get('url'),
image => $ad->get('storageId'),
adId => $crud->get('adId'),
});
return $self->www_view;
}
__PACKAGE__->meta->make_immutable;
1;