diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index ac10bd8c7..96e7669a6 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -3,6 +3,7 @@ - fixed #12206: Bad Subscription Groups in Duplicated Threads - fixed #12208: replacements don't work - fixed #12213: Unable to view cart when an asset is deleted. + - added: Better integration between User Profile fields, the Shop address book and the EMS. 7.10.21 - added #9668 extension template variable to attachment loops for the following assets: diff --git a/docs/upgrades/packages-7.10.22/default_emsbadge.wgpkg b/docs/upgrades/packages-7.10.22/default_emsbadge.wgpkg new file mode 100644 index 000000000..ad0fee1ac Binary files /dev/null and b/docs/upgrades/packages-7.10.22/default_emsbadge.wgpkg differ diff --git a/docs/upgrades/upgrade_7.10.21-7.10.22.pl b/docs/upgrades/upgrade_7.10.21-7.10.22.pl index 1ee778a94..41f41d697 100644 --- a/docs/upgrades/upgrade_7.10.21-7.10.22.pl +++ b/docs/upgrades/upgrade_7.10.21-7.10.22.pl @@ -33,6 +33,9 @@ my $session = start(); # this line required # upgrade functions go here addAuthorizePaymentDriver($session); +createAddressField($session); +addLinkedProfileAddress($session); + finish($session); # this line required @@ -55,6 +58,67 @@ sub addAuthorizePaymentDriver { print "DONE!\n" unless $quiet; } +#---------------------------------------------------------------------------- +sub addLinkedProfileAddress { + my $session = shift; + print "\tAdding linked profile addresses for existing users... " unless $quiet; + + my $users = $session->db->buildArrayRef( q{ + select userId from users where userId not in ('1','3') + } ); + + foreach my $userId (@$users) { + #check to see if there is user profile information available + my $u = WebGUI::User->new($session,$userId); + #skip if user does not have any homeAddress fields filled in + next unless ( + $u->profileField("homeAddress") + || $u->profileField("homeCity") + || $u->profileField("homeState") + || $u->profileField("homeZip") + || $u->profileField("homeCountry") + || $u->profileField("homePhone") + ); + + #Get the address book for the user (one is created if it does not exist) + my $addressBook = WebGUI::Shop::AddressBook->newByUserId($session,$userId); + + #Add the profile address for the user + $addressBook->addAddress({ + label => "Profile Address", + firstName => $u->profileField("firstName"), + lastName => $u->profileField("lastName"), + address1 => $u->profileField("homeAddress"), + city => $u->profileField("homeCity"), + state => $u->profileField("homeState"), + country => $u->profileField("homeCountry"), + code => $u->profileField("homeZip"), + phoneNumber => $u->profileField("homePhone"), + email => $u->profileField("email"), + isProfile => 1, + }); + } + + print "DONE!\n" unless $quiet; +} + +#---------------------------------------------------------------------------- +sub createAddressField { + my $session = shift; + + #skip if field exists + my $columns = $session->db->buildArrayRef("show columns from address where Field='isProfile'"); + return if(scalar(@$columns)); + + print "\tAdding profile link to Address... " unless $quiet; + + $session->db->write( q{ + alter table address add isProfile tinyint default 0 + } ); + + print "DONE!\n" unless $quiet; +} + # -------------- DO NOT EDIT BELOW THIS LINE -------------------------------- diff --git a/lib/WebGUI/Account/Profile.pm b/lib/WebGUI/Account/Profile.pm index 2daed6b2e..6e2924cbd 100644 --- a/lib/WebGUI/Account/Profile.pm +++ b/lib/WebGUI/Account/Profile.pm @@ -432,16 +432,67 @@ sub www_editSave { unless(scalar(@{$retHash->{errors}})) { my $profile = $retHash->{profile}; + my $privacy = {}; $session->user->update($profile); + + my $address = {}; + my $address_mappings = WebGUI::Shop::AddressBook->getProfileAddressMappings; foreach my $fieldName (keys %{$profile}) { + #set the shop address fields + my $address_key = $address_mappings->{$fieldName}; + $address->{$address_key} = $profile->{ $fieldName } if ($address_key); + + #set the privacy settings my $privacySetting = $session->form->get("privacy_".$fieldName); next unless $privacySetting; $privacy->{$fieldName} = $privacySetting; } + $session->user->setProfileFieldPrivacySetting($privacy); + + #Update or create and update the shop address + if ( keys %$address ) { + $address->{'isProfile' } = 1; + + #Get the address book for the user (one is created if it does not exist) + my $addressBook = WebGUI::Shop::AddressBook->newByUserId($session,$self->uid); + my $profileAddress = eval { $addressBook->getProfileAddress() }; + + my $e; + if($e = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) { + #Get home address only mappings to avoid creating addresses with just firstName, lastName, email + my %home_address_map = %{$address_mappings}; + foreach my $exclude ( qw{ firstName lastName email } ) { + delete $home_address_map{$exclude}; + } + #Add the profile address for the user if there are homeAddress fields + if( grep { $address->{$_} } values %home_address_map ) { + $address->{label} = "Profile Address"; + my $new_address = $addressBook->addAddress($address); + #Set this as the default address if one doesn't already exist + my $defaultAddress = eval{ $addressBook->getDefaultAddress }; + if(WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) { + $addressBook->update( { + defaultAddressId => $new_address->getId + } ); + } + } + } + elsif ($e = WebGUI::Error->caught) { + #Bad stuff happened - log an error but don't fail since this isn't a vital function + $session->log->error( + q{Could not update Shop Profile Address for user } + .$self->username.q{ : }.$e->error + ); + } + else { + #Update the profile address for the user + $profileAddress->update($address); + } + } } - + #Store the category the error occurred in the object for reference $self->store->{selected} = $retHash->{errorCategory}; diff --git a/lib/WebGUI/Asset/Sku/EMSBadge.pm b/lib/WebGUI/Asset/Sku/EMSBadge.pm index 751c9321d..45729d33f 100644 --- a/lib/WebGUI/Asset/Sku/EMSBadge.pm +++ b/lib/WebGUI/Asset/Sku/EMSBadge.pm @@ -20,6 +20,7 @@ use base 'WebGUI::Asset::Sku'; use JSON; use WebGUI::HTMLForm; use WebGUI::International; +use WebGUI::Shop::Admin; use WebGUI::Shop::AddressBook; use WebGUI::Utility; @@ -212,6 +213,28 @@ sub getMaxAllowedInCart { return 1; } +#---------------------------------------------------------------------------- + +=head2 getPostPurchaseActions ( item ) + +Return a hash reference of "label" => "url" to do things with this item after +it is purchased. C is the WebGUI::Shop::TransactionItem for this item + +=cut + +sub getPostPurchaseActions { + my ( $self, $item ) = @_; + my $session = $self->session; + my $opts = $self->SUPER::getPostPurchaseActions(); + if($self->getParent->isRegistrationStaff) { + my $i18n = WebGUI::International->new( $session, "Asset_EventManagementSystem" ); + my $badgeId = $item->get('options')->{badgeId}; + + $opts->{ $i18n->get('print') } = $self->getParent->getUrl( "func=printBadge;badgeId=$badgeId" ); + } + return $opts; +} + #------------------------------------------------------------------- =head2 getPrice @@ -404,11 +427,19 @@ sub view { ; # instanciate address - my $address = WebGUI::Shop::AddressBook->newByUserId($self->session)->getAddress($form->get("addressId")) if ($form->get("addressId")); + my $address = undef; + my $address_book = WebGUI::Shop::AddressBook->newByUserId($self->session); + if ($form->get("addressId")) { + $address = $address_book->getAddress($form->get("addressId")); + } + else { + $address = eval{ $address_book->getDefaultAddress } + } # build the form that the user needs to fill out with badge holder information $vars{formHeader} = WebGUI::Form::formHeader($session, {action => $self->getUrl}) - . WebGUI::Form::hidden($session, {name=>"func", value =>'addToCart'}); + . WebGUI::Form::hidden($session, {name=>"func", value =>'addToCart'}) + . WebGUI::Form::hidden($session, {name=>"addressId", value=>(defined $address ? $address->getId : "" )});; $vars{formFooter} = WebGUI::Form::formFooter($session); $vars{name} = WebGUI::Form::text($session, { name => 'name', @@ -457,9 +488,20 @@ sub view { if($self->getQuantityAvailable() > 0){ $vars{submitAddress} = WebGUI::Form::submit($session, {value => $i18n->get('add to cart'),}); } + $vars{resetButton} = q{}; $vars{title} = $self->getTitle; $vars{description} = $self->get('description'); - + $vars{search_url } = $self->getUrl("shop=address;method=ajaxSearch"); + + my $shopAdmin = WebGUI::Shop::Admin->new($session); + my $isStaff = $self->getParent->isRegistrationStaff; + my $canManageShop = $shopAdmin->canManage; + my $isCashier = $shopAdmin->isCashier; + + if($isStaff && ($canManageShop || $isCashier)) { + $vars{canSearch} = 1; + } + # render the page; return $self->processTemplate(\%vars, undef, $self->{_viewTemplate}); } @@ -495,13 +537,46 @@ sub www_addToCart { if ($badgeInfo{name} eq "") { $error = sprintf $i18n->get('is required'), $i18n->get('name','Shop'); } - + # return them back to the previous screen if they messed up if ($error) { $self->{_errorMessage} = $error; return $self->www_view($error); } - + + #check to see if address has changed - if so, create a new address and set it to the default + my $address_id = $form->get("addressId"); + if($address_id) { + my $address = undef; + my $address_book = WebGUI::Shop::AddressBook->newByUserId($self->session); + $address = $address_book->getAddress($address_id); + my $has_changes = 0; + my $new_address = {}; + foreach my $field_name (qw/name address1 address2 address3 city state country code phoneNumber organization email/) { + my $form_field_name = $field_name; + $form_field_name = "zipcode" if ($field_name eq "code"); + if($field_name eq "name") { + if($address->get('firstName')." ".$address->get('lastName') ne $badgeInfo{name}) { + $has_changes = 1; + } + ($new_address->{firstName},$new_address->{lastName}) = split(" ",$badgeInfo{name}); + next; + } + elsif($address->get($field_name) ne $badgeInfo{$form_field_name}) { + $has_changes = 1; + } + $new_address->{$field_name} = $badgeInfo{$form_field_name}; + } + + if($has_changes) { + my $address_book = WebGUI::Shop::AddressBook->newByUserId($self->session); + $new_address->{label} = $form->get("label")." New"; + my $new_address = $address_book->addAddress($new_address); + $address_book->update({defaultAddressId => $new_address->getId }); + } + + } + # add it to the cart $self->addToCart(\%badgeInfo); return $self->getParent->www_buildBadge($self->getOptions->{badgeId}); diff --git a/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm b/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm index c5c1911fe..6fb847c6c 100644 --- a/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm +++ b/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm @@ -2594,15 +2594,52 @@ sub www_printBadge { my $session = $self->session; return $session->privilege->insufficient unless ($self->isRegistrationStaff); my $form = $session->form; - my $registrant = $self->getRegistrant($form->get('badgeId')); + my $badgeId = $form->get('badgeId'); + my $registrant = $self->getRegistrant($badgeId); my $badge = WebGUI::Asset::Sku::EMSBadge->new($session, $registrant->{badgeAssetId}); $registrant->{badgeTitle} = $badge->getTitle; - # Add badge metadata - my $meta = $badge->getMetaDataAsTemplateVariables; - for my $key ( keys %{$meta} ) { - $registrant->{ "badgeMeta_" . $key } = $meta->{ $key }; - } + # Add badge metadata + my $meta = $badge->getMetaDataAsTemplateVariables; + for my $key ( keys %{$meta} ) { + $registrant->{ "badgeMeta_" . $key } = $meta->{ $key }; + } + + #Add tickets + my @tickets = $session->db->buildArray( + q{select ticketAssetId from EMSRegistrantTicket where badgeId=?}, + [$badgeId] + ); + + $registrant->{ticket_loop} = []; + foreach my $ticketId (@tickets) { + my $ticket = WebGUI::Asset::Sku::EMSTicket->new($session, $ticketId); + push (@{$registrant->{ticket_loop}}, $ticket->get); + } + + #Add ribbons + my @ribbons = $session->db->buildArray( + q{select ribbonAssetId from EMSRegistrantRibbon where badgeId=?}, + [$badgeId] + ); + + $registrant->{ribbon_loop} = []; + foreach my $ribbonId (@ribbons) { + my $ribbon = WebGUI::Asset::Sku::EMSRibbon->new($session, $ribbonId); + push (@{$registrant->{ribbon_loop}}, $ribbon->get); + } + + ## Add tokens + my @tokens = $session->db->buildArray( + q{select tokenAssetId from EMSRegistrantToken where badgeId=?}, + [$badgeId] + ); + + $registrant->{token_loop} = []; + foreach my $tokenId (@tokens) { + my $token = WebGUI::Asset::Sku::EMSRibbon->new($session, $tokenId); + push (@{$registrant->{token_loop}}, $token->get); + } return $self->processTemplate($registrant,$self->get('printBadgeTemplateId')); } diff --git a/lib/WebGUI/Auth.pm b/lib/WebGUI/Auth.pm index 17d2dda38..acf003d03 100644 --- a/lib/WebGUI/Auth.pm +++ b/lib/WebGUI/Auth.pm @@ -29,6 +29,7 @@ use WebGUI::User; use WebGUI::Operation::Shared; use WebGUI::Operation::Profile; use WebGUI::Workflow::Instance; +use WebGUI::Shop::AddressBook; use WebGUI::Inbox; use WebGUI::Friends; @@ -315,6 +316,35 @@ sub createAccountSave { } $u->karma($self->session->setting->get("karmaPerLogin"),"Login","Just for logging in.") if ($self->session->setting->get("useKarma")); $u->updateProfileFields($profile) if ($profile); + #Update the shop address + my $address = {}; + my $address_mappings = WebGUI::Shop::AddressBook->getProfileAddressMappings; + foreach my $fieldId (keys %$profile) { + #set the shop address fields + my $address_key = $address_mappings->{$fieldId}; + $address->{$address_key} = $profile->{$fieldId} if ($address_key); + } + + #Update or create and update the shop address + if ( keys %$address ) { + $address->{'isProfile' } = 1; + + #Get home address only mappings to avoid creating addresses with just firstName, lastName, email + my %home_address_map = %{$address_mappings}; + foreach my $exclude ( qw{ firstName lastName email } ) { + delete $home_address_map{$exclude}; + } + #Add the profile address for the user if there are homeAddress fields + if( grep { $address->{$_} } values %home_address_map ) { + #Create the address book for the user + my $addressBook = WebGUI::Shop::AddressBook->newByUserId($self->session,$userId); + $address->{label} = "Profile Address"; + my $new_address = $addressBook->addAddress($address); + #Set this as the default address if one doesn't already exist + $addressBook->update( { defaultAddressId => $new_address->getId } ); + } + } + $self->saveParams($userId,$self->authMethod,$properties); if ($self->getSetting("sendWelcomeMessage")){ diff --git a/lib/WebGUI/Operation/User.pm b/lib/WebGUI/Operation/User.pm index 30ebbb93e..88e3e6a42 100644 --- a/lib/WebGUI/Operation/User.pm +++ b/lib/WebGUI/Operation/User.pm @@ -805,7 +805,7 @@ sub www_editUserSave { return $session->privilege->adminOnly() unless ($isAdmin || $isSecondary) && $session->form->validToken; - # Check to see if + # Check to see if # 1) the userId associated with the posted username matches the posted userId (we're editing an account) # or that the userId is new and the username selected is unique (creating new account) # or that the username passed in isn't assigned a userId (changing a username) @@ -816,11 +816,11 @@ sub www_editUserSave { my $postedUsername = $session->form->process("username"); $postedUsername = WebGUI::HTML::filter($postedUsername, "all"); - if (($existingUserId eq $postedUserId || ($postedUserId eq "new" && !$existingUserId) || $existingUserId eq '') + if (($existingUserId eq $postedUserId || ($postedUserId eq "new" && !$existingUserId) || $existingUserId eq '') && $postedUsername ne '') { - # Create a user object with the id passed in. If the Id is 'new', the new method will return a new user, - # otherwise return the existing users properties + # Create a user object with the id passed in. If the Id is 'new', the new method will return a new user, + # otherwise return the existing users properties my $u = WebGUI::User->new($session,$postedUserId); $actualUserId = $u->userId; @@ -838,10 +838,58 @@ sub www_editUserSave { } # Loop through all profile fields, and update them with new values. - foreach my $field (@{WebGUI::ProfileField->getFields($session)}) { + my $address = {}; + my $address_mappings = WebGUI::Shop::AddressBook->getProfileAddressMappings; + foreach my $field (@{WebGUI::ProfileField->getFields($session)}) { next if $field->getId =~ /contentPositions/; - $u->profileField($field->getId,$field->formProcess($u)); + my $field_value = $field->formProcess($u); + $u->profileField($field->getId,$field_value); + + #set the shop address fields + my $address_key = $address_mappings->{$field->getId}; + $address->{$address_key} = $field_value if ($address_key); } + + #Update or create and update the shop address + if ( keys %$address ) { + $address->{'isProfile' } = 1; + + #Get the address book for the user (one is created if it does not exist) + my $addressBook = WebGUI::Shop::AddressBook->newByUserId($session,$actualUserId); + my $profileAddress = eval { $addressBook->getProfileAddress() }; + + my $e; + if($e = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) { + #Get home address only mappings to avoid creating addresses with just firstName, lastName, email + my %home_address_map = %{$address_mappings}; + foreach my $exclude ( qw{ firstName lastName email } ) { + delete $home_address_map{$exclude}; + } + #Add the profile address for the user if there are homeAddress fields + if( grep { $address->{$_} } values %home_address_map ) { + $address->{label} = "Profile Address"; + my $new_address = $addressBook->addAddress($address); + #Set this as the default address if one doesn't already exist + my $defaultAddress = eval{ $addressBook->getDefaultAddress }; + if(WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) { + $addressBook->update( { + defaultAddressId => $new_address->getId + } ); + } + } + } + elsif ($e = WebGUI::Error->caught) { + #Bad stuff happened - log an error but don't fail since this isn't a vital function + $session->log->error( + q{Could not update Shop Profile Address for user } + .$u->username.q{ : }.$e->error + ); + } + else { + #Update the profile address for the user + $profileAddress->update($address); + } + } # Update group assignements my @groups = $session->form->group("groupsToAdd"); diff --git a/lib/WebGUI/Shop/Address.pm b/lib/WebGUI/Shop/Address.pm index 8448a6f85..395c75b53 100644 --- a/lib/WebGUI/Shop/Address.pm +++ b/lib/WebGUI/Shop/Address.pm @@ -153,6 +153,19 @@ sub getId { return $self->get("addressId"); } +#------------------------------------------------------------------- + +=head2 isProfile () + +Returns 1 if the address is linked to the user's profile. + +=cut + +sub isProfile { + my $self = shift; + return ($self->get("isProfile") eq 1); +} + #------------------------------------------------------------------- @@ -192,7 +205,6 @@ sub new { return $self; } - #------------------------------------------------------------------- =head2 update ( properties ) @@ -259,16 +271,20 @@ The organization or company that this user is a part of. The address book that this address belongs to. +=head4 isProfile + +Whether or not this address is linked to the user profile. Defaults to 0 + =cut sub update { my ($self, $newProperties) = @_; my $id = id $self; - foreach my $field (qw(addressBookId email organization address1 address2 address3 state code city label firstName lastName country phoneNumber)) { + + foreach my $field (qw(addressBookId email organization address1 address2 address3 state code city label firstName lastName country phoneNumber isProfile)) { $properties{$id}{$field} = (exists $newProperties->{$field}) ? $newProperties->{$field} : $properties{$id}{$field}; } $self->addressBook->session->db->setRow("address","addressId",$properties{$id}); } - 1; diff --git a/lib/WebGUI/Shop/AddressBook.pm b/lib/WebGUI/Shop/AddressBook.pm index 1b31050f8..bae1e2f70 100644 --- a/lib/WebGUI/Shop/AddressBook.pm +++ b/lib/WebGUI/Shop/AddressBook.pm @@ -8,6 +8,7 @@ use WebGUI::Asset::Template; use WebGUI::Exception::Shop; use WebGUI::Form; use WebGUI::International; +use WebGUI::Shop::Admin; use WebGUI::Shop::Address; use Scalar::Util qw/blessed/; @@ -195,6 +196,11 @@ C method. sub get { my ($self, $name) = @_; + if($name eq "profileAddressId" && !$properties{id $self}{$name}) { + $properties{id $self}{$name} = $self->session->db->quickScalar(q{ + select addressId from address where addressBookId=? and isProfile=1 + },[$self->getId]); + } if (defined $name) { return $properties{id $self}{$name}; } @@ -295,6 +301,55 @@ sub getDefaultAddress { #------------------------------------------------------------------- +=head2 getProfileAddress () + +Returns the profile address for this address book if there is one. Otherwise throws a WebGUI::Error::ObjectNotFound exception. + +=cut + +sub getProfileAddress { + my ($self) = @_; + my $id = $self->get('profileAddressId'); + if ($id ne '') { + my $address = eval { $self->getAddress($id) }; + my $e; + if ($e = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) { + $e->rethrow; + } + elsif ($e = WebGUI::Error->caught) { + $e->rethrow; + } + else { + return $address; + } + } + WebGUI::Error::ObjectNotFound->throw(error=>"No profile address."); +} + +#------------------------------------------------------------------- + +=head2 getProfileAddressMappings ( ) + +Class or object method which returns the profile address field mappings + +=cut + +sub getProfileAddressMappings { + return { + homeAddress => 'address1', + homeCity => 'city', + homeState => 'state', + homeZip => 'code', + homeCountry => 'country', + homePhone => 'phoneNumber', + email => 'email', + firstName => 'firstName', + lastName => 'lastName' + } +} + +#------------------------------------------------------------------- + =head2 getId () Returns the unique id for this addressBook. @@ -419,7 +474,7 @@ sub newByUserId { } else { # nope create one for the user - return $class->create($session); + return $class->create($session,$userId); } } @@ -442,19 +497,19 @@ sub processAddressForm { $prefix ||= ''; my $form = $self->session->form; my %addressData = ( - label => $form->get($prefix . "label"), - firstName => $form->get($prefix . "firstName"), - lastName => $form->get($prefix . "lastName"), - address1 => $form->get($prefix . "address1"), - address2 => $form->get($prefix . "address2"), - address3 => $form->get($prefix . "address3"), - city => $form->get($prefix . "city"), - state => $form->get($prefix . "state"), - code => $form->get($prefix . "code", "zipcode"), - country => $form->get($prefix . "country", "country"), - phoneNumber => $form->get($prefix . "phoneNumber", "phone"), - email => $form->get($prefix . "email", "email"), - organization => $form->get($prefix . "organization"), + label => $form->get($prefix . "label") || '', + firstName => $form->get($prefix . "firstName") || '', + lastName => $form->get($prefix . "lastName") || '', + address1 => $form->get($prefix . "address1") || '', + address2 => $form->get($prefix . "address2") || '', + address3 => $form->get($prefix . "address3") || '', + city => $form->get($prefix . "city") || '', + state => $form->get($prefix . "state") || '', + code => $form->get($prefix . "code", "zipcode") || '', + country => $form->get($prefix . "country", "country") || '', + phoneNumber => $form->get($prefix . "phoneNumber", "phone") || '', + email => $form->get($prefix . "email", "email") || '', + organization => $form->get($prefix . "organization") || '', ); ##Label is optional in the form, but required for the UI and API. @@ -489,9 +544,26 @@ sub update { foreach my $field (qw(userId defaultAddressId)) { $properties{$id}{$field} = (exists $newProperties->{$field}) ? $newProperties->{$field} : $properties{$id}{$field}; } - $self->session->db->setRow("addressBook","addressBookId",$properties{$id}); + + my %postProperties = %{$properties{$id}}; + delete $postProperties{profileAddressId}; + $self->session->db->setRow("addressBook","addressBookId",\%postProperties); } +#------------------------------------------------------------------- + +=head2 uncache ( ) + +Deletes the addressBook cache + +=cut + +sub uncache { + my $self = shift; + delete $addressCache{id $self}; +} + + #------------------------------------------------------------------- =head2 www_ajaxGetAddress ( ) @@ -536,6 +608,80 @@ sub www_ajaxSave { #------------------------------------------------------------------- +=head2 www_ajaxSearch ( ) + +Gets a JSON object with addresses returned based on the search +parameters from the form. + +=cut + +sub www_ajaxSearch { + my $self = shift; + my $session = $self->session; + my $form = $session->form; + + my $name = $form->get('name'); + my $fields = { + firstName => (split(" ",$name))[0] || "", + lastName => (split(" ",$name))[1] || "", + organization => $form->get('organization') || "", + address1 => $form->get('address1') || "", + address2 => $form->get('address2') || "", + address3 => $form->get('address3') || "", + city => $form->get('city') || "", + state => $form->get('state') || "", + code => $form->get('zipcode') || "", + country => $form->get('country') || "", + email => $form->get('email') || "", + phoneNumber => $form->get('phone') || "", + }; + + my $clause = []; + my $params = []; + + foreach my $field (keys %$fields) { + my $field_value = $fields->{$field}; + if($field_value) { + $field = $session->db->dbh->quote_identifier($field); + $field_value = $field_value."%"; + push(@$clause,qq{$field like ?}); + push(@$params,$field_value); + } + } + + my $admin = WebGUI::Shop::Admin->new($session); + unless ($session->user->isAdmin || $admin->canManage || $admin->isCashier) { + push(@$clause,qq{users.userId=?}); + push(@$params,$session->user->getId); + } + + my $where = ""; + $where = "where ".join(" and ",@$clause) if scalar(@$clause); + + my $query = qq{ + select + address.*, + users.username + from + address + join addressBook on address.addressBookId = addressBook.addressBookId + join users on addressBook.userId = users.userId + $where + limit 3 + }; + + my $sth = $session->db->read($query,$params); + my $var = []; + while (my $hash = $sth->hashRef) { + push(@$var,$hash); + } + + $session->http->setMimeType('text/plain'); + return JSON->new->encode($var); +} + +#------------------------------------------------------------------- + =head2 www_deleteAddress ( ) Deletes an address from the book. @@ -544,7 +690,10 @@ Deletes an address from the book. sub www_deleteAddress { my $self = shift; - $self->getAddress($self->session->form->get("addressId"))->delete; + my $address = $self->getAddress($self->session->form->get("addressId")); + if (defined $address && !$address->isProfile) { + $address->delete; + } return $self->www_view; } @@ -700,8 +849,20 @@ sub www_editAddressSave { $self->addAddress(\%addressData); } else { - $self->getAddress($form->get('addressId'))->update(\%addressData); + my $addressId = $form->get('addressId'); + my $address = $self->getAddress($addressId); + $address->update(\%addressData); + if($address->isProfile) { + my $u = WebGUI::User->new($self->session, $self->get("userId")); + my $address_mappings = $self->getProfileAddressMappings; + foreach my $field (keys %$address_mappings) { + my $addr_field = $address_mappings->{$field}; + $u->profileField($field,$address->get($addr_field)); + } + } } + + #profile fields updated in WebGUI::Shop::Address->update return $self->www_view; } @@ -732,12 +893,12 @@ sub www_view { return $self->www_editAddress; } foreach my $address (@availableAddresses) { + push(@addresses, { %{$address->get}, address => $address->getHtmlFormatted, isDefault => ($self->get('defaultAddressId') eq $address->getId), - deleteButton => - WebGUI::Form::formHeader( $session ) + deleteButton => $address->get("isProfile") ? undef : WebGUI::Form::formHeader( $session ) . WebGUI::Form::hidden( $session, { name => 'shop', value => 'address' } ) . WebGUI::Form::hidden( $session, { name => 'method', value => 'deleteAddress' } ) . WebGUI::Form::hidden( $session, { name => 'addressId', value => $address->getId } ) diff --git a/lib/WebGUI/Shop/Cart.pm b/lib/WebGUI/Shop/Cart.pm index a8a31e230..90c244e73 100644 --- a/lib/WebGUI/Shop/Cart.pm +++ b/lib/WebGUI/Shop/Cart.pm @@ -1054,6 +1054,13 @@ sub www_view { $self->update({shippingAddressId=>''}); } + #get the billing address + my $billingAddress = eval { $self->getBillingAddress }; + if (my $e = WebGUI::Error->caught("WebGUI::Error::ObjectNotFound") && $self->get('billingAddressId')) { + # choose another address cuz we've got a problem + $self->update({billingAddressId=>''}); + } + # generate template variables for the items in the cart my @items = (); tie my %addressOptions, 'Tie::IxHash'; @@ -1215,9 +1222,11 @@ sub www_view { $addressBook->appendAddressFormVars(\%var, 'shipping_', $shippingAddressData); $addressBook->appendAddressFormVars(\%var, 'billing_', $billingAddressData); + my $has_billing_addr - $self->get('billingAddressId') ? 1 : 0; + $var{sameShippingAsBilling} = WebGUI::Form::yesNo($session, { name => 'sameShippingAsBilling', - value => $self->get('billingAddressId') && $self->get('billingAddressId') eq $self->get('shippingAddressId'), + value => (($has_billing_addr && $self->get('billingAddressId') eq $self->get('shippingAddressId')) || !$has_billing_addr), }); } diff --git a/lib/WebGUI/User.pm b/lib/WebGUI/User.pm index 09a7820e3..46134683a 100644 --- a/lib/WebGUI/User.pm +++ b/lib/WebGUI/User.pm @@ -1422,27 +1422,28 @@ sub update { delete $properties->{wg_privacySettings}; # $self->{_user} contains all fields in `users` table - my @userFields = (); - my @userValues = (); + my @userFields = (); + my @userValues = (); for my $key ( keys %{$self->{_user}} ) { if ( exists $properties->{$key} ) { # Delete the value because it's not a profile field - my $value = delete $properties->{$key}; + my $value = delete $properties->{$key}; push @userFields, $db->dbh->quote_identifier( $key ) . " = ?"; push @userValues, $value; $self->{_user}->{$key} = $value; } } # No matter what we update properties - my $userFields = join ", ", @userFields; + my $userFields = join ", ", @userFields; $db->write( "UPDATE users SET $userFields WHERE userId=?", [@userValues, $self->{_userId}] ); # Everything else must be a profile field - my @profileFields = (); - my @profileValues = (); + my @profileFields = (); + my @profileValues = (); + for my $key ( keys %{$properties} ) { if (!exists $self->{_profile}{$key} && !WebGUI::ProfileField->exists($session,$key)) { $self->session->errorHandler->warn("No such profile field: $key"); @@ -1453,7 +1454,7 @@ sub update { $self->{_profile}->{$key} = $properties->{ $key }; } if ( @profileFields ) { - my $profileFields = join ", ", @profileFields; + my $profileFields = join ", ", @profileFields; $db->write( "UPDATE userProfileData SET $profileFields WHERE userId=?", [@profileValues, $self->{_userId}] diff --git a/lib/WebGUI/i18n/English/Asset_EventManagementSystem.pm b/lib/WebGUI/i18n/English/Asset_EventManagementSystem.pm index 5c1426ece..f601b1674 100644 --- a/lib/WebGUI/i18n/English/Asset_EventManagementSystem.pm +++ b/lib/WebGUI/i18n/English/Asset_EventManagementSystem.pm @@ -2307,6 +2307,12 @@ normal templates.|, context => q{Error message when trying to add too many tickets to a badge}, }, + 'clear form' => { + message => q|Clear|, + lastUpdated => 0, + context => q|a button on the add badge to clear the form|, + }, + }; 1; diff --git a/t/Account/Profile.t b/t/Account/Profile.t new file mode 100644 index 000000000..8b56538d1 --- /dev/null +++ b/t/Account/Profile.t @@ -0,0 +1,218 @@ +# vim:syntax=perl +#------------------------------------------------------------------- +# 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 +#------------------------------------------------------------------ + +# This tests the operation of WebGUI::Account modules. You can use +# as a base to test your own modules. + +use FindBin; +use strict; +use lib "$FindBin::Bin/../lib"; +use Test::More; +use Test::Deep; +use Exception::Class; + +use WebGUI::Test; # Must use this before any other WebGUI modules +use WebGUI::Session; + +#---------------------------------------------------------------------------- +# Init +my $session = WebGUI::Test->session; + +my $andy = WebGUI::User->new($session, "new"); +WebGUI::Test->addToCleanup($andy); +$session->user({userId => $andy->getId}); + +#---------------------------------------------------------------------------- +# Tests + +plan tests => 17; # Increment this number for each test you create + +#---------------------------------------------------------------------------- +# Test the creation of WebGUI::Account::Profile + +# Can we load it? +use_ok( "WebGUI::Account::Profile" ); + +SKIP: { # Not everyone has Test::Exception yet + eval { require Test::Exception; import Test::Exception }; + # Skip 1 test if Test::Exception couldn't be loaded + skip 1, 'Test::Exception not found' if $@; + throws_ok( sub { WebGUI::Account::Profile->new }, 'WebGUI::Error::InvalidObject', + 'new() throws exception without session object' + ); +}; + +my $profile; +ok( $profile = WebGUI::Account::Profile->new( $session ), + "WebGUI::Account::Profile object created successfully" +); + +# Test $profile->isa +isa_ok( $profile, "WebGUI::Account", 'Blessed into the right class' ); + +#---------------------------------------------------------------------------- +# Test getUrl + +is( $profile->getUrl, $session->url->page('op=account;module=;do='.$profile->method), + 'getUrl adds op, module, and do since no method has been set' +); + +is( $profile->getUrl( 'foo=bar' ), $session->url->page( 'op=account;foo=bar' ), + 'getUrl adds op if passed other parameters' +); + +is( $profile->getUrl( 'op=account' ), $session->url->page( 'op=account' ), + 'getUrl doesnt add op=account if already exists' +); + +####################################################################### +# +# www_editSave +# +####################################################################### + +tie my %profile_info, "Tie::IxHash", ( + firstName => "Andy", + lastName => "Dufresne", + homeAddress => "123 Shank Ave.", + homeCity => "Shawshank", + homeState => "PA", + homeZip => "11223", + homeCountry => "US", + homePhone => "111-111-1111", + email => 'andy@shawshank.com' +); + +$session->request->setup_body( \%profile_info ); + +$profile->www_editSave; + +#Reset andy to the session users since stuff has changed +$andy = $session->user; + +#Test that the address was saved to the profile +cmp_bag( + [ map { $andy->profileField($_) } keys %profile_info ], + [ values %profile_info ], + 'Profile fields were saved' +); + +#Test that the addressBook was created +my $bookId = $session->db->quickScalar( + q{ select addressBookId from addressBook where userId=? }, + [$andy->getId] +); + +ok( ($bookId ne ""), "Address Book was created"); + +my $book = WebGUI::Shop::AddressBook->new($session,$bookId); + +my @addresses = @{ $book->getAddresses() }; + +is(scalar(@addresses), 1 , "One address was created in the address book"); + +my $address = $addresses[0]; + +tie my %address_info, "Tie::IxHash", ( + firstName => $address->get("firstName"), + lastName => $address->get("lastName"), + homeAddress => $address->get("address1"), + homeCity => $address->get("city"), + homeState => $address->get("state"), + homeZip => $address->get("code"), + homeCountry => $address->get("country"), + homePhone => $address->get("phoneNumber"), + email => $address->get("email") +); + +#Test that the address was saved properly to shop +cmp_bag( + [ values %profile_info ], + [ values %address_info ], + 'Shop address was has the right information' +); + +#Test that the address is returned as the profile address +my $profileAddress = $book->getProfileAddress; +is($profileAddress->getId, $address->getId, "Profile linked properly to address"); + +#Test that the address is the default address +my $defaultAddress = $book->getDefaultAddress; +is( + $defaultAddress->getId, + $address->getId, + "Profile address properly set to default address when created" +); + +#Test updates to existing addresses +%profile_info = ( + firstName => "Andy", + lastName => "Dufresne", + homeAddress => "123 Seaside Ave.", + homeCity => "Zihuatanejo", + homeState => "Guerrero", + homeZip => "40880", + homeCountry => "MX", + homePhone => "222-222-2222", + email => 'andy@freeman.com' +); + +$session->request->setup_body( \%profile_info ); + +$profile->www_editSave; + +$andy = $session->user; + +#Test that the address was saved to the profile +cmp_bag ( + [ map { $andy->profileField($_) } keys %profile_info ], + [ values %profile_info ], + 'Profile fields were updated' +); + +#Test that there is still only one address book and one address +my @bookIds = $session->db->quickArray( + q{ select addressBookId from addressBook where userId=? }, + [$andy->getId] +); + +is( scalar(@bookIds), 1, "Only one address book exists after update" ); + +$bookId = $bookIds[0]; +$book = WebGUI::Shop::AddressBook->new($session,$bookId); +@addresses = @{ $book->getAddresses() }; + +is( scalar(@addresses), 1 , "Only one address exists after update"); + +my $address = $addresses[0]; + +%address_info = ( + firstName => $address->get("firstName"), + lastName => $address->get("lastName"), + homeAddress => $address->get("address1"), + homeCity => $address->get("city"), + homeState => $address->get("state"), + homeZip => $address->get("code"), + homeCountry => $address->get("country"), + homePhone => $address->get("phoneNumber"), + email => $address->get("email") +); + +#Test that the address was saved properly to shop +cmp_bag( + [ values %profile_info ], + [ values %address_info ], + 'Shop address was has the right information' +); + + + +#vim:ft=perl diff --git a/t/Auth.t b/t/Auth.t index 32b9ef6fe..cd5175dbf 100644 --- a/t/Auth.t +++ b/t/Auth.t @@ -17,6 +17,9 @@ use FindBin; use strict; use lib "$FindBin::Bin/lib"; use Test::More; +use Test::Deep; +use Exception::Class; + use WebGUI::Test; # Must use this before any other WebGUI modules use WebGUI::Auth; use WebGUI::Session; @@ -33,7 +36,7 @@ my ($request, $oldRequest, $output); #---------------------------------------------------------------------------- # Tests -plan tests => 4; # Increment this number for each test you create +plan tests => 11; # Increment this number for each test you create #---------------------------------------------------------------------------- # Test createAccountSave and returnUrl together @@ -65,9 +68,21 @@ WebGUI::Test->addToCleanup(sub { "SELECT userId FROM users WHERE username=?", [ $username ] ); - + + my $addressBookId = $session->db->quickScalar( + "select addressBookId from addressBook where userId=?", + [ $userId ] + ); + + if($addressBookId) { + $session->db->write( + "delete from address where addressBookId=?", + [$addressBookId] + ); + } + my @tableList - = qw{authentication users userProfileData groupings inbox userLoginLog}; + = qw{authentication users userProfileData groupings inbox userLoginLog addressBook}; for my $table ( @tableList ) { $session->db->write( @@ -89,6 +104,8 @@ $session->scratch->delete('language'); ##Remove language override # Session Cleanup $session->{_request} = $oldRequest; + + #---------------------------------------------------------------------------- # Test login and returnUrl together # Set up request @@ -114,6 +131,104 @@ is $output, undef, 'login returns undef when showMessageOnLogin is false'; # Session Cleanup $session->{_request} = $oldRequest; + +#---------------------------------------------------------------------------- +# Test createAccountSave +$username = $session->id->generate; +push @cleanupUsernames, $username; + +#Test updates to existing addresses +tie my %profile_info, "Tie::IxHash", ( + firstName => "Andy", + lastName => "Dufresne", + homeAddress => "123 Shank Ave.", + homeCity => "Shawshank", + homeState => "PA", + homeZip => "11223", + homeCountry => "US", + homePhone => "111-111-1111", + email => 'andy@shawshank.com' +); + +$auth->createAccountSave( $username, { }, "PASSWORD", \%profile_info ); + +#Reset andy to the session users since stuff has changed +my $andy = $session->user; + +#Test that the address was saved to the profile +cmp_bag( + [ map { $andy->profileField($_) } keys %profile_info ], + [ values %profile_info ], + 'Profile fields were saved' +); + +#Test that the addressBook was created +my $bookId = $session->db->quickScalar( + q{ select addressBookId from addressBook where userId=? }, + [$andy->getId] +); + +ok( ($bookId ne ""), "Address Book was created"); + +my $book = WebGUI::Shop::AddressBook->new($session,$bookId); + +my @addresses = @{ $book->getAddresses() }; + +is(scalar(@addresses), 1 , "One address was created in the address book"); + +my $address = $addresses[0]; + +tie my %address_info, "Tie::IxHash", ( + firstName => $address->get("firstName"), + lastName => $address->get("lastName"), + homeAddress => $address->get("address1"), + homeCity => $address->get("city"), + homeState => $address->get("state"), + homeZip => $address->get("code"), + homeCountry => $address->get("country"), + homePhone => $address->get("phoneNumber"), + email => $address->get("email") +); + +#Test that the address was saved properly to shop +cmp_bag( + [ values %profile_info ], + [ values %address_info ], + 'Shop address was has the right information' +); + +#Test that the address is returned as the profile address +my $profileAddress = $book->getProfileAddress; +is($profileAddress->getId, $address->getId, "Profile linked properly to address"); + +#Test that the address is the default address +my $defaultAddress = $book->getDefaultAddress; +is( + $defaultAddress->getId, + $address->getId, + "Profile address properly set to default address when created" +); + +$username = $session->id->generate; +push @cleanupUsernames, $username; + +#Test updates to existing addresses +%profile_info = ( + firstName => "Andy", + lastName => "Dufresne", + email => 'andy@shawshank.com' +); + +$auth->createAccountSave( $username, { }, "PASSWORD", \%profile_info ); + +#Test that the addressBook was not created +my $bookCount = $session->db->quickScalar( + q{ select count(addressBookId) from addressBook where userId=? }, + [$session->user->getId] +); + +is( $bookCount, 0, "Address Book was not created for user without address fields"); + sub installPigLatin { use File::Copy; mkdir File::Spec->catdir(WebGUI::Test->lib, 'WebGUI', 'i18n', 'PigLatin'); diff --git a/t/Operation/User.t b/t/Operation/User.t new file mode 100644 index 000000000..e9a919e7d --- /dev/null +++ b/t/Operation/User.t @@ -0,0 +1,194 @@ +# vim:syntax=perl +#------------------------------------------------------------------- +# 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 +#------------------------------------------------------------------ + +# This tests the operation of Authentication +# +# + +use FindBin; +use strict; +use lib "$FindBin::Bin/../lib"; +use Test::More; +use Test::Deep; +use Exception::Class; + +use WebGUI::Test; # Must use this before any other WebGUI modules +use WebGUI::Session; +use WebGUI::User; +use WebGUI::Operation::User; + +#---------------------------------------------------------------------------- +# Init +my $session = WebGUI::Test->session; +$session->user({ userId => 3 }); + +my $andy = WebGUI::User->new($session, "new"); +WebGUI::Test->addToCleanup($andy); +$andy->username("andydufresne"); + +#---------------------------------------------------------------------------- +# Tests + +plan tests => 10; # Increment this number for each test you create + +#---------------------------------------------------------------------------- + + +####################################################################### +# +# www_editUserSave +# +####################################################################### + +tie my %profile_info, "Tie::IxHash", ( + firstName => "Andy", + lastName => "Dufresne", + homeAddress => "123 Shank Ave.", + homeCity => "Shawshank", + homeState => "PA", + homeZip => "11223", + homeCountry => "US", + homePhone => "111-111-1111", + email => 'andy@shawshank.com' +); + +$session->request->setup_body({ + uid => $andy->getId, + username => $andy->username, + webguiCsrfToken => $session->scratch->get('webguiCsrfToken'), + %profile_info +}); +$session->request->method('POST'); + +WebGUI::Operation::User::www_editUserSave($session); + +$andy = WebGUI::User->new($session,$andy->getId); + +#Test that the address was saved to the profile +cmp_bag( + [ map { $andy->profileField($_) } keys %profile_info ], + [ values %profile_info ], + 'Profile fields were saved' +); + +#Test that the addressBook was created +my $bookId = $session->db->quickScalar( + q{ select addressBookId from addressBook where userId=? }, + [$andy->getId] +); + +ok( ($bookId ne ""), "Address Book was created"); + +my $book = WebGUI::Shop::AddressBook->new($session,$bookId); + +my @addresses = @{ $book->getAddresses() }; + +is(scalar(@addresses), 1 , "One address was created in the address book"); + +my $address = $addresses[0]; + +tie my %address_info, "Tie::IxHash", ( + firstName => $address->get("firstName"), + lastName => $address->get("lastName"), + homeAddress => $address->get("address1"), + homeCity => $address->get("city"), + homeState => $address->get("state"), + homeZip => $address->get("code"), + homeCountry => $address->get("country"), + homePhone => $address->get("phoneNumber"), + email => $address->get("email") +); + +#Test that the address was saved properly to shop +cmp_bag( + [ values %profile_info ], + [ values %address_info ], + 'Shop address was has the right information' +); + +#Test that the address is returned as the profile address +my $profileAddress = $book->getProfileAddress; +is($profileAddress->getId, $address->getId, "Profile linked properly to address"); + +#Test that the address is the default address +my $defaultAddress = $book->getDefaultAddress; +is( + $defaultAddress->getId, + $address->getId, + "Profile address properly set to default address when created" +); + + +#Test updates to existing addresses +%profile_info = ( + firstName => "Andy", + lastName => "Dufresne", + homeAddress => "123 Seaside Ave.", + homeCity => "Zihuatanejo", + homeState => "Guerrero", + homeZip => "40880", + homeCountry => "MX", + homePhone => "222-222-2222", + email => 'andy@freeman.com' +); + +$session->request->setup_body({ + uid => $andy->getId, + username => $andy->username, + webguiCsrfToken => $session->scratch->get('webguiCsrfToken'), + %profile_info +}); +$session->request->method('POST'); +WebGUI::Operation::User::www_editUserSave($session); + +$andy = WebGUI::User->new($session,$andy->getId); + +#Test that the address was saved to the profile +cmp_bag ( + [ map { $andy->profileField($_) } keys %profile_info ], + [ values %profile_info ], + 'Profile fields were updated' +); + +#Test that there is still only one address book and one address +my @bookIds = $session->db->quickArray( + q{ select addressBookId from addressBook where userId=? }, + [$andy->getId] +); + +is( scalar(@bookIds), 1, "Only one address book exists after update" ); + +$bookId = $bookIds[0]; +$book = WebGUI::Shop::AddressBook->new($session,$bookId); +@addresses = @{ $book->getAddresses() }; + +is( scalar(@addresses), 1 , "Only one address exists after update"); + +my $address = $addresses[0]; + +%address_info = ( + firstName => $address->get("firstName"), + lastName => $address->get("lastName"), + homeAddress => $address->get("address1"), + homeCity => $address->get("city"), + homeState => $address->get("state"), + homeZip => $address->get("code"), + homeCountry => $address->get("country"), + homePhone => $address->get("phoneNumber"), + email => $address->get("email") +); + +#Test that the address was saved properly to shop +cmp_bag( + [ values %profile_info ], + [ values %address_info ], + 'Shop address was has the right information' +); diff --git a/t/Shop/Address.t b/t/Shop/Address.t index c0fc7babc..91aefb480 100644 --- a/t/Shop/Address.t +++ b/t/Shop/Address.t @@ -141,6 +141,7 @@ cmp_deeply( organization => undef, addressId => ignore(), #checked elsewhere addressBookId => $book->getId, + isProfile => 0, }, 'get the whole thing and check a new, blank object' ); diff --git a/t/Shop/AddressBook.t b/t/Shop/AddressBook.t index 52d7947e6..a92789b1d 100644 --- a/t/Shop/AddressBook.t +++ b/t/Shop/AddressBook.t @@ -23,15 +23,21 @@ use Exception::Class; use WebGUI::Test; # Must use this before any other WebGUI modules use WebGUI::Session; use WebGUI::Text; +use JSON; #---------------------------------------------------------------------------- # Init my $session = WebGUI::Test->session; +#Create a temporary admin user +my $tempAdmin = WebGUI::User->create($session); +$tempAdmin->addToGroups(['3']); +WebGUI::Test->addToCleanup($tempAdmin); +$session->user({ userId => $tempAdmin->getId} ); #---------------------------------------------------------------------------- # Tests -plan tests => 26; +plan tests => 42; #---------------------------------------------------------------------------- # put your tests here @@ -114,7 +120,7 @@ cmp_deeply( '... correct error message', ); -$session->user({userId => 3}); +$session->user({userId => $tempAdmin->getId}); $book = WebGUI::Shop::AddressBook->create($session); isa_ok($book, 'WebGUI::Shop::AddressBook', 'create returns the right kind of object'); @@ -124,9 +130,9 @@ is($session->getId, $book->session->getId, 'session method returns OUR session o ok($session->id->valid($book->getId), 'create makes a valid GUID style addressBookId'); -is($book->get('userId'), 3, 'create uses $session->user to get the userid for this book'); +is($book->get('userId'), $tempAdmin->getId, 'create uses $session->user to get the userid for this book'); -my $bookCount = $session->db->quickScalar('select count(*) from addressBook'); +my $bookCount = $session->db->quickScalar('select count(*) from addressBook where addressBookId=?',[$book->getId]); is($bookCount, 1, 'only 1 address book was created'); my $alreadyHaveBook = WebGUI::Shop::AddressBook->create($session); @@ -191,25 +197,188 @@ cmp_deeply( 'update updates the db, too' ); +####################################################################### +# +# getProfileAddress +# +####################################################################### + +eval { $book->getProfileAddress }; + +$e = Exception::Class->caught(); +isa_ok($e, 'WebGUI::Error::ObjectNotFound', 'getProfileAddress takes exception to a profile address not being set'); +cmp_deeply( + $e, + methods( + error => 'No profile address.', + ), + '... correct error message', +); + +$address1->update({ isProfile => 1 }); + +my $profile_address = eval{ $book->getProfileAddress() }; + +is($profile_address->getId,$address1->getId,"getProfileAddress returns addresses tied to profiles"); + +####################################################################### +# +# www_editAddressSave +# +####################################################################### + +#Clear the book address cache +$book->uncache; + +my $address_info = { + label => 'Profile Label', + addressId => $address1->getId, + firstName => 'Andy', + lastName => 'Dufresne', + address1 => '123 Shank Ave', + address2 => 'Cell Block E', + address3 => 'Cell 12', + city => 'Shawshank', + state => 'PA', + code => '11223', + country => 'US', + phoneNumber => '111-111-1111', + email => 'andy@shawshank.com', + organization => 'Shawshank' +}; + +$session->request->setup_body({ + %$address_info, + callback => q|{'url':''}| +}); + +$book->www_editAddressSave; + +$address1 = $book->getAddress($address1->getId); + +cmp_bag( + [ map { $address1->get($_) } keys %$address_info ], + [ values %$address_info ], + 'Address fields were saved' +); + +my $u = WebGUI::User->new($session,$book->get("userId")); + +cmp_bag( + [ map { $u->profileField($_) } keys %{ $book->getProfileAddressMappings } ], + [ map { $address1->get($_) } values %{ $book->getProfileAddressMappings } ], + 'Profile address was updated and matches address fields' +); + +#Test that updates to non profile address does not update the profile +$book->uncache; + +$address_info = { + label => 'Non Profile Label', + addressId => $address2->getId, + firstName => 'Ellis', + lastName => 'Redding', + address1 => '123 Shank Ave', + address2 => 'Cell Block E', + address3 => 'Cell 15', + city => 'Shawshank', + state => 'PA', + code => '11223', + country => 'US', + phoneNumber => '111-111-1111', + email => 'red@shawshank.com', + organization => 'Shawshank' +}; + + +$session->request->setup_body({ + %$address_info, + callback => q|{'url':''}| +}); + +$book->www_editAddressSave; + +$address1 = $book->getAddress($address1->getId); +$address2 = $book->getAddress($address2->getId); + +cmp_bag( + [ map { $address2->get($_) } keys %$address_info ], + [ values %$address_info ], + 'Non Profile Address fields were saved' +); + +cmp_bag( + [ map { $u->profileField($_) } keys %{ $book->getProfileAddressMappings } ], + [ map { $address1->get($_) } values %{ $book->getProfileAddressMappings } ], + 'Profile address was not updated when non profile fields were saved' +); + +####################################################################### +# +# www_deleteAddress +# +####################################################################### + +#clear the cache +$book->uncache; + +$session->request->setup_body({ + 'addressId' => $address2->getId, + 'callback' => q|{'url':''}| +}); +$book->www_deleteAddress; + +@addresses = @{ $book->getAddresses() }; + +cmp_bag( + [ map { $_->getId } @addresses ], + [$address1->getId], + 'Address was deleted properly' +); + + +#clear the cache +$book->uncache; + +$session->request->setup_body({ + 'addressId' => $address1->getId, + 'callback' => q|{'url':''}| +}); +$book->www_deleteAddress; + +@addresses = @{ $book->getAddresses() }; + +cmp_bag( + [ map { $_->getId } @addresses ], + [$address1->getId], + 'Profile Address was not deleted' +); + + ####################################################################### # # delete # ####################################################################### +#clear the cache +$book->uncache; + +my $addressBookId = $alreadyHaveBook->getId; +my $firstCount = $session->db->quickScalar('select count(*) from addressBook where addressBookId=?',[$addressBookId]); $alreadyHaveBook->delete(); -$bookCount = $session->db->quickScalar('select count(*) from addressBook'); -my $addrCount = $session->db->quickScalar('select count(*) from address'); +my $afterCount = $session->db->quickScalar('select count(*) from addressBook where addressBookId=?',[$addressBookId]); +my $addrCount = $session->db->quickScalar('select count(*) from address where addressBookId=?',[$addressBookId]); -is($bookCount, 1, 'delete: one book deleted'); +ok(($firstCount == 1 && $afterCount == 0), 'delete: one book deleted'); +$addressBookId = $bookClone->getId; $bookClone->delete(); -$bookCount = $session->db->quickScalar('select count(*) from addressBook'); -my $addrCount = $session->db->quickScalar('select count(*) from address'); +$bookCount = $session->db->quickScalar('select count(*) from addressBook where addressBookId=?',[$addressBookId]); +my $addrCount = $session->db->quickScalar('select count(*) from address where addressBookId=?',[$addressBookId]); is($bookCount, 0, '... book deleted'); is($addrCount, 0, '... also deletes addresses in the book'); -undef $book; ####################################################################### # @@ -217,7 +386,6 @@ undef $book; # ####################################################################### - my $otherSession = WebGUI::Test->newSession; my $mergeUser = WebGUI::User->create($otherSession); WebGUI::Test->addToCleanup($mergeUser); @@ -235,3 +403,225 @@ cmp_bag( [ $goodAddress->getId, ], 'newByUserId works' ); + +####################################################################### +# +# www_ajaxSearch +# +####################################################################### + +#Create some data to search for +my $andySession = WebGUI::Test->newSession; +my $andy = WebGUI::User->create($andySession); +WebGUI::Test->addToCleanup($andy); +$andySession->user({ userId => $andy->getId }); +my $andyBook = WebGUI::Shop::AddressBook->create($andySession); +WebGUI::Test->addToCleanup($andyBook); + +my $andyAddr1 = $andyBook->addAddress({ + label => 'Andy1', + firstName => 'Andy', + lastName => 'Dufresne', + address1 => '123 Shank Ave', + address2 => 'Cell Block E', + address3 => 'Cell 12', + city => 'Shawshank', + state => 'PA', + code => '11223', + country => 'US', + phoneNumber => '111-111-1111', + email => 'andy@shawshank.com', + organization => 'Shawshank' +}); + +my $andyAddr2 = $andyBook->addAddress({ + label => 'Andy2', + firstName => 'Andy', + lastName => 'Dufresne', + address1 => '123 Seaside Ave', + address2 => '', + address3 => '', + city => 'Zihuatanejo', + state => '', + code => '40880', + country => 'MX', + phoneNumber => '222-222-2222', + email => 'andy@freeman.com', + organization => 'Unaffiliated' +}); + + +my $redSession = WebGUI::Test->newSession; +my $red = WebGUI::User->create($redSession); +WebGUI::Test->addToCleanup($red); +$redSession->user({userId => $red->getId}); +my $redBook = WebGUI::Shop::AddressBook->create($redSession); +WebGUI::Test->addToCleanup($redBook); + +my $redAddr = $redBook->addAddress({ + label => 'Red1', + firstName => 'Ellis', + lastName => 'Redding', + address1 => '123 Shank Ave', + address2 => 'Cell Block E', + address3 => 'Cell 15', + city => 'Shawshank', + state => 'PA', + code => '11223', + country => 'US', + phoneNumber => '111-111-1111', + email => 'red@shawshank.com', + organization => 'Shawshank' +}); + + +my $brooksSession = WebGUI::Test->newSession; +my $brooks = WebGUI::User->create($brooksSession); +WebGUI::Test->addToCleanup($brooks); +$brooksSession->user({userId => $brooks->getId}); +my $brooksBook = WebGUI::Shop::AddressBook->create($brooksSession); +WebGUI::Test->addToCleanup($brooksBook); + +my $brooksAddr = $brooksBook->addAddress({ + label => 'Brooks1', + firstName => 'Brooks', + lastName => 'Hatlen', + address1 => '123 Shank Ave', + address2 => 'Cell Block E', + address3 => 'Cell 22', + city => 'Shawshank', + state => 'PA', + code => '11223', + country => 'US', + phoneNumber => '111-111-1111', + email => 'brooks@shawshank.com', + organization => 'Shawshank' +}); + +#Test search as admin +$session->request->setup_body({ + 'name' => 'Andy Du' +}); + +my $results = JSON->new->decode($book->www_ajaxSearch); + +cmp_bag( + $results, + [ + { %{$andyAddr1->get}, username => $andy->username }, + { %{$andyAddr2->get}, username => $andy->username }, + ], + 'Ajax Address Search matches name correctly for admins' +); + +#Test search for multiple fields +$session->request->setup_body({ + 'name' => 'Andy Du', + 'organization' => 'Shaw', + 'address1' => '123', + 'address2' => 'Cell', + 'address3' => 'Cell', + 'city' => 'Shaw', + 'state' => 'P', + 'zipcode' => '11', + 'country' => 'U', + 'email' => 'andy', + 'phone' => '111', +}); + +$results = JSON->new->decode($book->www_ajaxSearch); + +cmp_bag( + $results, + [{ %{$andyAddr1->get}, username => $andy->username }], + 'Ajax Address Search matches multiple fields correctly' +); + +#Test limiting +$session->request->setup_body({ + 'name' => 'Andy Du', + 'organization' => 'Shaw', + 'address1' => '123', + 'address2' => 'Cell', + 'address3' => 'Cell', + 'city' => 'Shaw', + 'state' => 'Q', #This should cause no results to come back + 'zipcode' => '11', + 'country' => 'U', + 'email' => 'andy', + 'phone' => '111', +}); + +$results = JSON->new->decode($book->www_ajaxSearch); + +cmp_bag( + $results, + [], + 'Ajax Address Search limits results correctly' +); + +#Test searching across users +#Test as admin +$session->request->setup_body({ + 'organization' => 'Shawshank' +}); + +$results = JSON->new->decode($book->www_ajaxSearch); + +cmp_bag( + $results, + [ + { %{$andyAddr1->get}, username => $andy->username }, + { %{$redAddr->get}, username => $red->username }, + { %{$brooksAddr->get}, username => $brooks->username }, + ], + 'Ajax Address Search returns cross user results for admins' +); + +#Test as shop admin +$andy->addToGroups([ $andySession->setting->get('groupIdAdminCommerce') ]); +$andySession->request->setup_body({ + 'organization' => 'Shawshank' +}); +$results = JSON->new->decode($andyBook->www_ajaxSearch); + +cmp_bag( + $results, + [ + { %{$andyAddr1->get}, username => $andy->username }, + { %{$redAddr->get}, username => $red->username }, + { %{$brooksAddr->get}, username => $brooks->username }, + ], + 'Ajax Address Search returns cross user results for shop admins' +); + +#Test search as shop cashier +$red->addToGroups([ $redSession->setting->get('groupIdCashier') ]); +$redSession->request->setup_body({ + 'organization' => 'Shawshank' +}); +$results = JSON->new->decode($redBook->www_ajaxSearch); + +cmp_bag( + $results, + [ + { %{$andyAddr1->get}, username => $andy->username }, + { %{$redAddr->get}, username => $red->username }, + { %{$brooksAddr->get}, username => $brooks->username }, + ], + 'Ajax Address Search returns cross user results for shop cashiers' +); + +#Test search as non privileged +$brooksSession->request->setup_body({ + 'organization' => 'Shawshank' +}); +$results = JSON->new->decode($brooksBook->www_ajaxSearch); + +cmp_bag( + $results, + [{ %{$brooksAddr->get}, username => $brooks->username }], + 'Ajax Address Search returns only current user results for non privileged users' +); + +undef $book; diff --git a/t/Shop/Pay.t b/t/Shop/Pay.t index f0462b42c..7a4e183ea 100644 --- a/t/Shop/Pay.t +++ b/t/Shop/Pay.t @@ -144,6 +144,7 @@ my $defaultPayDrivers = { 'WebGUI::Shop::PayDriver::Ogone' => 'Ogone', 'WebGUI::Shop::PayDriver::PayPal::PayPalStd' => 'PayPal', 'WebGUI::Shop::PayDriver::PayPal::ExpressCheckout' => 'PayPal Express Checkout', + 'WebGUI::Shop::PayDriver::CreditCard::AuthorizeNet' => 'Credit Card (Authorize.net)', }; cmp_deeply( $drivers, $defaultPayDrivers, 'getDrivers returns the default PayDrivers'); diff --git a/www/extras/yui-webgui/build/asset/sku/emsbadge.js b/www/extras/yui-webgui/build/asset/sku/emsbadge.js new file mode 100644 index 000000000..8e13c07a2 --- /dev/null +++ b/www/extras/yui-webgui/build/asset/sku/emsbadge.js @@ -0,0 +1,118 @@ + +// Initialize namespace +if (typeof WebGUI == "undefined") { + var WebGUI = {}; +} +if (typeof WebGUI.Asset == "undefined") { + WebGUI.Asset = {}; +} +if(typeof WebGUI.Asset.Sku == "undefined") { + WebGUI.Asset.Sku = {}; +} +if(typeof WebGUI.Asset.Sku.EMSBadge == "undefined") { + WebGUI.Asset.Sku.EMSBadge = {}; +} + +var timeout = null; +var searchResults = []; + +WebGUI.Asset.Sku.EMSBadge = { + + delayLookup : function( ) { + if(timeout != null) { + clearTimeout(timeout); + } + timeout = setTimeout(WebGUI.Asset.Sku.EMSBadge.lookupAddress,300); + }, + + initForm : function( ) { + var addressCol = document.getElementById("emsbadge_container"); + var divs = addressCol.getElementsByTagName('div'); + for( var i = 0; i < divs.length; i++ ) { + WebGUI.Asset.Sku.EMSBadge.setHoverStates( divs[i] ); + YAHOO.util.Event.addListener( divs[i], "click", WebGUI.Asset.Sku.EMSBadge.setAddress ); + } + + var formTbl = document.getElementById("emsbadge_form_tbl"); + var inputs = formTbl.getElementsByTagName('input'); + for( var i = 0; i < inputs.length; i++ ) { + var inputEl = inputs[i]; + YAHOO.util.Event.addListener(inputEl, "keydown", WebGUI.Asset.Sku.EMSBadge.delayLookup); + } + + }, + + lookupAddress : function( ) { + timeout = null; + var url = searchUrl + ";" + WebGUI.Form.buildQueryString("emsbadge_form",{ name: ['func'] }); + + YAHOO.util.Connect.asyncRequest('GET', url, { + success: function(o) { + searchResults = YAHOO.lang.JSON.parse(o.responseText); + for( var i = 1; i <= 3; i++ ) { + document.getElementById('emsbadge_address_' + i).style.display='none'; + } + + for( var i = 0; i < searchResults.length; i++ ) { + if(i > 3) break; + var addressEl = document.getElementById('emsbadge_address_' + (i+1)); + var address = searchResults[i]; + var addressStr = "" + address.username + "" + + "
"; + addressStr += address.firstName + " " + address.lastName + + "
" + + address.address1 + + "
"; + if(address.state) { + addressStr += address.city + ", " + address.state + " " + address.code; + } + else { + addressStr += address.city + ", " + address.country; + } + if(address.email) { + addressStr += "
" + address.email; + } + addressEl.innerHTML = addressStr; + addressEl.style.display = ''; + } + }, + failure: function(o) {} + }); + + }, + + setAddress : function ( e ) { + var el = YAHOO.util.Event.getTarget(e); + if(el.tagName == "SPAN") { + el = el.parentNode; + } + var divClicked = el.id; + var parts = divClicked.split("_"); + var index = parseInt(parts[2]); + var result = searchResults[(index -1)]; + if( result == null ) return; + document.getElementById('name_formId').value = result.firstName + " " + result.lastName; + document.getElementById('organization_formId').value = result.organization; + document.getElementById('address1_formId').value = result.address1; + document.getElementById('address2_formId').value = result.address2; + document.getElementById('address3_formId').value = result.address3; + document.getElementById('city_formId').value = result.city; + document.getElementById('state_formId').value = result.state; + document.getElementById('zipcode_formId').value = result.code; + document.getElementById('country_formId').value = result.country; + document.getElementById('phone_formId').value = result.phoneNumber; + document.getElementById('email_formId').value = result.email; + }, + + setHoverStates : function( el ) { + el.setAttribute("oldclass", el.className); + el.onmouseover = function() { this.className = this.getAttribute("oldclass") + "_on"; }; + el.onmouseout = function() { this.className = this.getAttribute("oldclass"); }; + } +} + +YAHOO.util.Event.onDOMReady( function () { + WebGUI.Asset.Sku.EMSBadge.initForm(); +}); + + diff --git a/www/extras/yui-webgui/build/form/form.js b/www/extras/yui-webgui/build/form/form.js index 38dad03a0..7bf1610be 100644 --- a/www/extras/yui-webgui/build/form/form.js +++ b/www/extras/yui-webgui/build/form/form.js @@ -96,6 +96,65 @@ WebGUI.Form.buildQueryString = function ( formId, excludes ) { return sFormData; }; +/*********************************************************************************** + * @description This method clears all the values of the form. This is different than reset which will restore default values + * @method clearForm + * @public + * @static + * @param {string || object} id or object of the form element to clear values for. + * @param {object} object containing array of form elements to exclude. { id:[], name:[], classNames:[], type:[] } + */ + +WebGUI.Form.clearForm = function ( oElement, excludes ) { + + var _isInArray = function ( value, array) { + if(!array || !value) return 0; + if(typeof array != 'object') return 0; + + for(var i = 0; i < array.length; i++) { + if(array[i] == value) return 1; + } + return 0; + }; + + if(typeof oElement != 'object') oElement = document.getElementById(oElement); + + for (i = 0; i < oElement.length; i++) { + var oType = oElement[i].type.toLowerCase(); + var oClass = oElement[i].className; + var oName = oElement[i].name; + var oId = oElement[i].id; + + if(_isInArray(oClass,excludes.classNames)) continue; + if(_isInArray(oId,excludes.id)) continue; + if(_isInArray(oName,excludes.name)) continue; + if(_isInArray(oType,excludes.type)) continue; + + switch (oType) { + case "text": + case "password": + case "textarea": + case "hidden": + oElement[i].value = ""; + break; + case "radio": + case "checkbox": + if (oElement[i].checked) { + oElement[i].checked = false; + } + break; + case "select-one": + case "select-multi": + oElement[i].selectedIndex = -1; + break; + default: + break; + } + } + + return; +}; + /*********************************************************************************** * @description This method gets the proper value of the form element passed in * @method getFormValue