- Added Cashier/Point of Sale mode for the Shop.

- Added the notion of a default address to the Shop's address book.
This commit is contained in:
JT Smith 2008-11-15 01:26:16 +00:00
parent 47419b9602
commit 16bd779fd4
9 changed files with 263 additions and 24 deletions

View file

@ -2,6 +2,8 @@
- Brand new Survey system. Make sure to export your old results as they will - Brand new Survey system. Make sure to export your old results as they will
not be imported, only the surveys themselves. not be imported, only the surveys themselves.
- Made syndicated content asset use cache. - Made syndicated content asset use cache.
- Added Cashier/Point of Sale mode for the Shop.
- Added the notion of a default address to the Shop's address book.
- fixed #8837: When you move an asset to a new version, only the current version is moved, instead of all of them. - fixed #8837: When you move an asset to a new version, only the current version is moved, instead of all of them.
- Added version tag modes: multiple tags per user, single tag per user, site wide version tag and auto commit (thanks to Long Term Results B.V.) - Added version tag modes: multiple tags per user, single tag per user, site wide version tag and auto commit (thanks to Long Term Results B.V.)
- fixed #9076: Thingy broken in latest beta, Save and Close buttons missing - fixed #9076: Thingy broken in latest beta, Save and Close buttons missing

View file

@ -32,10 +32,29 @@ my $session = start(); # this line required
migrateSurvey($session); migrateSurvey($session);
addVersionTagMode($session); addVersionTagMode($session);
addPosMode($session);
finish($session); # this line required finish($session); # this line required
#----------------------------------------------------------------------------
sub addPosMode {
my $session = shift;
print qq{\tAdding Point of Sale mode to the Shop...} if !$quiet;
my $db = $session->db();
my $setting = $session->setting();
$setting->add("groupIdCashier","3");
$db->write(q{ALTER TABLE cart drop column couponId});
$db->write(q{ALTER TABLE cart add column posUserId char(22) binary});
$db->write(q{ALTER TABLE transaction add column cashierUserId char(22) binary});
$db->write(q{update transaction set cashierUserId=userId});
$db->write(q{ALTER TABLE addressBook add column defaultAddressId char(22) binary});
print qq{Finished\n} if !$quiet;
}
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
# This method add support for versionTagMode # This method add support for versionTagMode
@ -43,7 +62,7 @@ finish($session); # this line required
sub addVersionTagMode { sub addVersionTagMode {
my $session = shift; my $session = shift;
print q{Adding support for versionTagMode...} if !$quiet; print qq{\tAdding support for versionTagMode...} if !$quiet;
my $db = $session->db(); my $db = $session->db();
my $setting = $session->setting(); my $setting = $session->setting();
@ -75,12 +94,11 @@ sub addVersionTagMode {
# #
sub migrateSurvey{ sub migrateSurvey{
my $session = shift; my $session = shift;
print "Migrating surveys to new survey system..." unless $quiet; print "\tMigrating surveys to new survey system..." unless $quiet;
_moveOldSurveyTables($session); _moveOldSurveyTables($session);
_addSurveyTables($session); _addSurveyTables($session);
print "\n";
my $surveys = $session->db->buildArrayRefOfHashRefs( my $surveys = $session->db->buildArrayRefOfHashRefs(
"SELECT * FROM Survey_old s "SELECT * FROM Survey_old s

View file

@ -114,6 +114,18 @@ our $HELP = {
name => "shippingAddress", name => "shippingAddress",
description => "shippingAddress help", description => "shippingAddress help",
}, },
{
name => "isCashier",
},
{
name => "posLookupForm",
},
{
name => "posUsername",
},
{
name => "posUserId",
},
], ],
}, },
{ {
@ -226,6 +238,11 @@ our $HELP = {
description => "editButton help", description => "editButton help",
required => 1, required => 1,
}, },
{
name => "defaultButton",
description => "defaultButton help",
required => 1,
},
{ {
name => "deleteButton", name => "deleteButton",
description => "deleteButton help", description => "deleteButton help",
@ -278,6 +295,10 @@ our $HELP = {
name => "state", name => "state",
description => "state help", description => "state help",
}, },
{
name => "organization",
description => "organization help",
},
{ {
name => "city", name => "city",
description => "city help", description => "city help",

View file

@ -174,6 +174,34 @@ sub getAddresses {
#------------------------------------------------------------------- #-------------------------------------------------------------------
=head2 getDefaultAddress ()
Returns the default address for this address book if there is one. Otherwise throws a WebGUI::Error::ObjectNotFound exception.
=cut
sub getDefaultAddress {
my ($self) = @_;
my $id = $self->get('defaultAddressId');
if ($id ne '') {
my $address = eval { $self->getAddress($id) };
my $e;
if ($e = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) {
$self->update({defaultAddressId=>''});
$e->rethrow;
}
elsif ($e = WebGUI::Error->caught) {
$e->rethrow;
}
else {
return $address;
}
}
return undef;
}
#-------------------------------------------------------------------
=head2 getId () =head2 getId ()
Returns the unique id for this cart. Returns the unique id for this cart.
@ -288,12 +316,16 @@ Assign the user that owns this address book.
Assign the session, by id, that owns this address book. Will automatically be set to "" if a user owns it. Assign the session, by id, that owns this address book. Will automatically be set to "" if a user owns it.
=head4 defaultAddressId
The id of the address to be made the default for this address book.
=cut =cut
sub update { sub update {
my ($self, $newProperties) = @_; my ($self, $newProperties) = @_;
my $id = id $self; my $id = id $self;
foreach my $field (qw(userId sessionId)) { foreach my $field (qw(userId sessionId defaultAddressId)) {
$properties{$id}{$field} = (exists $newProperties->{$field}) ? $newProperties->{$field} : $properties{$id}{$field}; $properties{$id}{$field} = (exists $newProperties->{$field}) ? $newProperties->{$field} : $properties{$id}{$field};
} }
##Having both a userId and sessionId will confuse create. ##Having both a userId and sessionId will confuse create.
@ -319,6 +351,20 @@ sub www_deleteAddress {
#------------------------------------------------------------------- #-------------------------------------------------------------------
=head2 www_defaultAddress ( )
Makes an address be the default.
=cut
sub www_defaultAddress {
my $self = shift;
$self->update({defaultAddressId=>$self->session->form->get("addressId")});
return $self->www_view;
}
#-------------------------------------------------------------------
=head2 www_editAddress () =head2 www_editAddress ()
Allows a user to edit an address in their address book. Allows a user to edit an address in their address book.
@ -467,6 +513,7 @@ sub www_view {
push(@addresses, { push(@addresses, {
%{$address->get}, %{$address->get},
address => $address->getHtmlFormatted, address => $address->getHtmlFormatted,
isDefault => ($self->get('defaultAddressId') eq $address->getId),
deleteButton => WebGUI::Form::formHeader($session) deleteButton => WebGUI::Form::formHeader($session)
.WebGUI::Form::hidden($session, {name=>"shop", value=>"address"}) .WebGUI::Form::hidden($session, {name=>"shop", value=>"address"})
.WebGUI::Form::hidden($session, {name=>"method", value=>"deleteAddress"}) .WebGUI::Form::hidden($session, {name=>"method", value=>"deleteAddress"})
@ -481,6 +528,13 @@ sub www_view {
.$self->formatCallbackForm($form->get('callback')) .$self->formatCallbackForm($form->get('callback'))
.WebGUI::Form::submit($session, {value=>$i18n->get("edit")}) .WebGUI::Form::submit($session, {value=>$i18n->get("edit")})
.WebGUI::Form::formFooter($session), .WebGUI::Form::formFooter($session),
defaultButton => WebGUI::Form::formHeader($session)
.WebGUI::Form::hidden($session, {name=>"shop", value=>"address"})
.WebGUI::Form::hidden($session, {name=>"method", value=>"defaultAddress"})
.WebGUI::Form::hidden($session, {name=>"addressId", value=>$address->getId})
.$self->formatCallbackForm($form->get('callback'))
.WebGUI::Form::submit($session, {value=>$i18n->get("default")})
.WebGUI::Form::formFooter($session),
useButton => WebGUI::Form::formHeader($session,{action=>$callback->{url}}) useButton => WebGUI::Form::formHeader($session,{action=>$callback->{url}})
.$callbackForm .$callbackForm
.WebGUI::Form::hidden($session, {name=>"addressId", value=>$address->getId}) .WebGUI::Form::hidden($session, {name=>"addressId", value=>$address->getId})

View file

@ -74,6 +74,24 @@ sub getAdminConsole {
#------------------------------------------------------------------- #-------------------------------------------------------------------
=head2 isCashier ( [ $user ] )
Determine whether or not a user is a cashier
=head3 $user
An optional WebGUI::User object. If this is not used, it uses the current session user object.
=cut
sub isCashier {
my $self = shift;
my $user = shift || $self->session->user;
return $user->isInGroup( $self->session->setting->get('groupIdCashier'));
}
#-------------------------------------------------------------------
=head2 new ( session ) =head2 new ( session )
Constructor. Constructor.
@ -127,6 +145,12 @@ sub www_editSettings {
label => $i18n->get('who can manage'), label => $i18n->get('who can manage'),
hoverHelp => $i18n->get('who can manage help'), hoverHelp => $i18n->get('who can manage help'),
); );
$form->group(
name => "groupIdCashier",
value => $setting->get("groupIdCashier"),
label => $i18n->get('who is a cashier'),
hoverHelp => $i18n->get('who is a cashier help'),
);
$form->template( $form->template(
name => "shopCartTemplateId", name => "shopCartTemplateId",
value => $setting->get("shopCartTemplateId"), value => $setting->get("shopCartTemplateId"),
@ -182,7 +206,9 @@ sub www_editSettingsSave {
shopCartTemplateId shopAddressBookTemplateId shopAddressTemplateId)) { shopCartTemplateId shopAddressBookTemplateId shopAddressTemplateId)) {
$setting->set($template, $form->get($template, "template")); $setting->set($template, $form->get($template, "template"));
} }
$setting->set("groupIdAdminCommerce", $form->get("groupIdAdminCommerce", "group")); foreach my $group (qw(groupIdCashier groupIdAdminCommerce)) {
$setting->set($group, $form->get($group, "group"));
}
return $self->www_editSettings(); return $self->www_editSettings();
} }

View file

@ -13,6 +13,7 @@ use WebGUI::Shop::CartItem;
use WebGUI::Shop::Credit; use WebGUI::Shop::Credit;
use WebGUI::Shop::Ship; use WebGUI::Shop::Ship;
use WebGUI::Shop::Tax; use WebGUI::Shop::Tax;
use WebGUI::User;
=head1 NAME =head1 NAME
@ -83,7 +84,7 @@ sub calculateShopCreditDeduction {
unless (defined $total) { unless (defined $total) {
$total = $self->calculateTotal $total = $self->calculateTotal
} }
return $self->formatCurrency(WebGUI::Shop::Credit->new($self->session)->calculateDeduction($total)); return $self->formatCurrency(WebGUI::Shop::Credit->new($self->session, $self->get('posUserId'))->calculateDeduction($total));
} }
#------------------------------------------------------------------- #-------------------------------------------------------------------
@ -344,6 +345,22 @@ sub getItemsByAssetId {
#------------------------------------------------------------------- #-------------------------------------------------------------------
=head2 getPosUser
Returns the userId of the user making a purchase. If there is a cashier and the cashier has specified a user, then that user will be returned. Otherwise, if it's a direct sale then $session->user will be returned.
=cut
sub getPosUser {
my $self = shift;
if ($self->get('posUserId') ne "") {
return WebGUI::User->new($self->session, $self->get('posUserId'));
}
return $self->session->user;
}
#-------------------------------------------------------------------
=head2 getShipper () =head2 getShipper ()
Returns the WebGUI::Shop::ShipDriver object that is attached to this cart for shipping. Returns the WebGUI::Shop::ShipDriver object that is attached to this cart for shipping.
@ -365,7 +382,13 @@ Returns the WebGUI::Shop::Address object that is attached to this cart for shipp
sub getShippingAddress { sub getShippingAddress {
my $self = shift; my $self = shift;
return $self->getAddressBook->getAddress($self->get("shippingAddressId")); my $book = $self->getAddressBook;
if ($self->get("shippingAddressId")) {
return $book->getAddress($self->get("shippingAddressId"));
}
my $address = $book->getDefaultAddress;
$self->update({shippingAddressId=>$address->getId});
return $address;
} }
#------------------------------------------------------------------- #-------------------------------------------------------------------
@ -533,6 +556,10 @@ The unique id for a shipping address attached to this cart.
The unique id of the configured shipping driver that will be used to ship these goods. The unique id of the configured shipping driver that will be used to ship these goods.
=head4 posUserId
The ID of a user being checked out, if they're being checked out by a cashier.
=cut =cut
sub update { sub update {
@ -541,7 +568,7 @@ sub update {
WebGUI::Error::InvalidParam->throw(error=>"Need a properties hash ref."); WebGUI::Error::InvalidParam->throw(error=>"Need a properties hash ref.");
} }
my $id = id $self; my $id = id $self;
foreach my $field (qw(shippingAddressId shipperId)) { foreach my $field (qw(shippingAddressId posUserId shipperId)) {
$properties{$id}{$field} = (exists $newProperties->{$field}) ? $newProperties->{$field} : $properties{$id}{$field}; $properties{$id}{$field} = (exists $newProperties->{$field}) ? $newProperties->{$field} : $properties{$id}{$field};
} }
$self->session->db->setRow("cart","cartId",$properties{$id}); $self->session->db->setRow("cart","cartId",$properties{$id});
@ -616,6 +643,31 @@ sub www_continueShopping {
#------------------------------------------------------------------- #-------------------------------------------------------------------
=head2 www_lookupPosUser ( )
Adds a Point of Sale user to the cart.
=cut
sub www_lookupPosUser {
my $self = shift;
my $session = $self->session;
my $email = $session->form->get('posEmail','email');
my $user = WebGUI::User->newByEmail($session, $email);
unless (defined $user) {
$user = WebGUI::User->newByUsername($session, $email);
unless (defined $user) {
$user = WebGUI::User->new($session, "new");
$user->username($email);
$user->profileField('email', $email);
}
}
$self->update({posUserId=>$user->userId});
return $self->www_view;
}
#-------------------------------------------------------------------
=head2 www_removeItem ( ) =head2 www_removeItem ( )
Remove an item from the cart and then display the cart again. Remove an item from the cart and then display the cart again.
@ -756,7 +808,7 @@ sub www_view {
my $address = eval { $self->getShippingAddress }; my $address = eval { $self->getShippingAddress };
if (WebGUI::Error->caught("WebGUI::Error::ObjectNotFound")) { if (WebGUI::Error->caught("WebGUI::Error::ObjectNotFound")) {
# choose another address cuz we've got a problem # choose another address cuz we've got a problem
$self->update({shippingAddressId=>""}); $self->update({shippingAddressId=>''});
} }
# if there is no shipping address we can't check out # if there is no shipping address we can't check out
@ -782,9 +834,18 @@ sub www_view {
$var{shippingPrice} = $self->formatCurrency($var{shippingPrice}); $var{shippingPrice} = $self->formatCurrency($var{shippingPrice});
} }
# POS variables
$var{isCashier} = WebGUI::Shop::Admin->new($session)->isCashier;
$var{posLookupForm} = WebGUI::Form::email($session, {name=>"posEmail"})
.WebGUI::Form::submit($session, {value=>$i18n->get('search for email'),
extras=>q|onclick="this.form.method.value='lookupPosUser';this.form.submit;"|});
my $posUser = $self->getPosUser;
$var{posUsername} = $posUser->username;
$var{posUserId} = $posUser->userId;
# calculate price adjusted for in-store credit # calculate price adjusted for in-store credit
$var{totalPrice} = $var{subtotalPrice} + $var{shippingPrice} + $var{tax}; $var{totalPrice} = $var{subtotalPrice} + $var{shippingPrice} + $var{tax};
my $credit = WebGUI::Shop::Credit->new($session); my $credit = WebGUI::Shop::Credit->new($session, $posUser->userId);
$var{inShopCreditAvailable} = $credit->getSum; $var{inShopCreditAvailable} = $credit->getSum;
$var{inShopCreditDeduction} = $credit->calculateDeduction($var{totalPrice}); $var{inShopCreditDeduction} = $credit->calculateDeduction($var{totalPrice});
$var{totalPrice} = $self->formatCurrency($var{totalPrice} + $var{inShopCreditDeduction}); $var{totalPrice} = $self->formatCurrency($var{totalPrice} + $var{inShopCreditDeduction});

View file

@ -105,7 +105,18 @@ Optionally supply this variable which will set the payment address to this addre
sub www_getCredentials { sub www_getCredentials {
my ($self, $addressId) = @_; my ($self, $addressId) = @_;
my $session = $self->session; my $session = $self->session;
$addressId = $session->form->process('addressId') if ($addressId eq "");
# Process address from address book if passed
$addressId = $session->form->process( 'addressId' );
my $address;
if ( $addressId ) {
$address = eval{ $self->getAddress( $addressId ) };
}
else {
$address = $self->getCart->getShippingAddress;
}
my $billingAddressHtml = $address->getHtmlFormatted;
# Generate the json string that defines where the address book posts the selected address # Generate the json string that defines where the address book posts the selected address
my $callbackParams = { my $callbackParams = {
url => $session->url->page, url => $session->url->page,
@ -126,18 +137,11 @@ sub www_getCredentials {
. WebGUI::Form::submit( $session, { value => 'Choose billing address' } ) . WebGUI::Form::submit( $session, { value => 'Choose billing address' } )
. WebGUI::Form::formFooter( $session); . WebGUI::Form::formFooter( $session);
# Get billing address
my $billingAddress = eval { $self->getAddress($addressId) };
my $billingAddressHtml;
if ($billingAddress) {
$billingAddressHtml = $billingAddress->getHtmlFormatted;
}
# Generate 'Proceed' button # Generate 'Proceed' button
my $proceedButton = WebGUI::Form::formHeader( $session ) my $proceedButton = WebGUI::Form::formHeader( $session )
. $self->getDoFormTags('pay') . $self->getDoFormTags('pay')
. WebGUI::Form::hidden($session, {name=>"addressId", value=>$addressId}) . WebGUI::Form::hidden($session, {name=>"addressId", value=>$address->getId})
. WebGUI::Form::submit( $session, { value => 'Pay' } ) . WebGUI::Form::submit( $session, { value => 'Pay' } )
. WebGUI::Form::formFooter( $session); . WebGUI::Form::formFooter( $session);

View file

@ -15,6 +15,7 @@ use WebGUI::Shop::AddressBook;
use WebGUI::Shop::Credit; use WebGUI::Shop::Credit;
use WebGUI::Shop::TransactionItem; use WebGUI::Shop::TransactionItem;
use WebGUI::Shop::Pay; use WebGUI::Shop::Pay;
use WebGUI::User;
=head1 NAME =head1 NAME
@ -154,8 +155,14 @@ sub create {
WebGUI::Error::InvalidObject->throw(expected=>"WebGUI::Session", got=>(ref $session), error=>"Need a session."); WebGUI::Error::InvalidObject->throw(expected=>"WebGUI::Session", got=>(ref $session), error=>"Need a session.");
} }
my $transactionId = $session->id->generate; my $transactionId = $session->id->generate;
$session->db->write('insert into transaction (transactionId, userId, username, dateOfPurchase) values (?,?,?,now())', my $cashier = $session->user;
[$transactionId, $session->user->userId, $session->user->username]); my $posUser = $cashier;
my $cart = $properties->{cart};
if (defined $cart) {
$posUser = $cart->getPosUser;
}
$session->db->write('insert into transaction (transactionId, userId, username, cashierUserId, dateOfPurchase) values (?,?,?,?,now())',
[$transactionId, $posUser->userId, $posUser->username, $cashier->userId]);
my $self = $class->new($session, $transactionId); my $self = $class->new($session, $transactionId);
$self->update($properties); $self->update($properties);
return $self; return $self;
@ -917,6 +924,7 @@ sub www_view {
} }
$output .= q{</div>}; $output .= q{</div>};
} }
my $cashier = WebGUI::User->new($session, $transaction->get('cashierUserId'));
$output .= q{ $output .= q{
<table class="transactionDetail"> <table class="transactionDetail">
<tr> <tr>
@ -931,6 +939,9 @@ sub www_view {
<tr> <tr>
<th>}. $i18n->get("username") .q{</th><td><a href="}.$url->page('op=editUser;uid='.$transaction->get('userId')).q{">}. $transaction->get('username') .q{</a></td> <th>}. $i18n->get("username") .q{</th><td><a href="}.$url->page('op=editUser;uid='.$transaction->get('userId')).q{">}. $transaction->get('username') .q{</a></td>
</tr> </tr>
<tr>
<th>}. $i18n->get("cashier") .q{</th><td><a href="}.$url->page('op=editUser;uid='.$cashier->userId).q{">}. $cashier->username .q{</a></td>
</tr>
<tr> <tr>
<th>}. $i18n->get("amount") .q{</th><td><b>}. sprintf("%.2f", $transaction->get('amount')) .q{</b></td> <th>}. $i18n->get("amount") .q{</th><td><b>}. sprintf("%.2f", $transaction->get('amount')) .q{</b></td>
</tr> </tr>
@ -1121,7 +1132,7 @@ sub www_viewMy {
unless (defined $transaction) { unless (defined $transaction) {
$transaction = $class->new($session, $session->form->get('transactionId')); $transaction = $class->new($session, $session->form->get('transactionId'));
} }
return $session->insufficient unless ($transaction->get('userId') eq $session->user->userId); return $session->privilege->insufficient unless ($transaction->get('userId') eq $session->user->userId || WebGUI::Shop::Admin->new($session)->isCashier);
my $i18n = WebGUI::International->new($session, 'Shop'); my $i18n = WebGUI::International->new($session, 'Shop');
my ($style, $url) = $session->quick(qw(style url)); my ($style, $url) = $session->quick(qw(style url));
my %var = ( my %var = (

View file

@ -9,6 +9,36 @@ our $I18N = {
context => q|vendor label|, context => q|vendor label|,
}, },
'cashier' => {
message => q|Cashier|,
lastUpdated => 0,
context => q|transaction label|,
},
'order for' => {
message => q|Order For|,
lastUpdated => 0,
context => q|cart label, as in "This is an order for John Smith"|,
},
'search for email' => {
message => q|Search for Email Address|,
lastUpdated => 0,
context => q|cart button label|,
},
'who is a cashier' => {
message => q|Who is a cashier?|,
lastUpdated => 0,
context => q|shop admin setting|,
},
'who is a cashier help' => {
message => q|Cashiers are able to make purchases on behalf of another user by typing the email address of the user into the cart.|,
lastUpdated => 0,
context => q|help for shop admin setting|,
},
'organization' => { 'organization' => {
message => q|Organization|, message => q|Organization|,
lastUpdated => 0, lastUpdated => 0,
@ -309,6 +339,12 @@ our $I18N = {
context => q|a help description|, context => q|a help description|,
}, },
'defaultButton help' => {
message => q|A button that will allow the user to set an address as a default.|,
lastUpdated => 0,
context => q|a help description|,
},
'deleteButton help' => { 'deleteButton help' => {
message => q|A button that will allow the user to delete an existing address.|, message => q|A button that will allow the user to delete an existing address.|,
lastUpdated => 0, lastUpdated => 0,
@ -765,6 +801,12 @@ our $I18N = {
context => q|a button in the address book| context => q|a button in the address book|
}, },
'default' => {
message => q|Set Default|,
lastUpdated => 0,
context => q|a button in the address book|
},
'edit' => { 'edit' => {
message => q|Edit|, message => q|Edit|,
lastUpdated => 0, lastUpdated => 0,