diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 97860a3a3..d9af29416 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -12,6 +12,7 @@ - Fixed a bug in the YUI simple editor for survey editing which was leaking memory. Also improved the object edit templates. - fixed #10184: Matrix 2.0 - Version Tag Duplicate Type - fixed #10182: Matrix 2.0 - Comparison view broken in IE 6 & 7 + - Added individual shipping requirements to the Sku. 7.7.4 - rfe: Extend DateTime for Week-Nrs (#9151) diff --git a/docs/upgrades/upgrade_7.7.4-7.7.5.pl b/docs/upgrades/upgrade_7.7.4-7.7.5.pl index 2782c1f1e..af9d6840c 100644 --- a/docs/upgrades/upgrade_7.7.4-7.7.5.pl +++ b/docs/upgrades/upgrade_7.7.4-7.7.5.pl @@ -41,6 +41,8 @@ turnOffAdmin($session); correctEventTemplateVariables($session); +addShipsSeparateToSku($session); + finish($session); # this line required #---------------------------------------------------------------------------- @@ -159,7 +161,6 @@ sub correctEventTemplateVariables { }); TEMPLATE: while (my $templateAsset = $getATemplate->()) { - print("\t\t Correcting ". $templateAsset->getTitle. "\n") unless $quiet; my $template = $templateAsset->get('template'); $template =~ s{\?func=edit}{}isg; $template =~ s{\?func=delete}{}isg; @@ -172,6 +173,15 @@ sub correctEventTemplateVariables { print "DONE!\n" unless $quiet; } +sub addShipsSeparateToSku { + my ($session) = @_; + print "\tAdd shipsSeparate property to Sku... " unless $quiet; + $session->db->write(< 'hidden', defaultValue => '{}', }, + shipsSeparately => { + tab => 'shop', + fieldType => 'yesNo', + defaultValue => 0, + label => $i18n->get('shipsSeparate'), + hoverHelp => $i18n->get('shipsSeparate help'), + }, ); push(@{$definition}, { assetName=>$i18n->get('assetName'), @@ -594,6 +602,15 @@ sub processStyle { } #------------------------------------------------------------------- + +=head2 setTaxConfiguration ($namespace, $configuration) + +=head3 $namespace + +=head3 $configuration + +=cut + sub setTaxConfiguration { my $self = shift; my $namespace = shift; @@ -615,6 +632,19 @@ sub setTaxConfiguration { } ); } +#------------------------------------------------------------------- + +=head2 shipsSeparately + +Returns a boolean indicating whether this item must be shipped separately from other items. + +=cut + +sub shipsSeparately { + return shift->get('shipsSeparately'); +} + + #------------------------------------------------------------------- =head2 www_view ( ) diff --git a/lib/WebGUI/Help/Asset_Sku.pm b/lib/WebGUI/Help/Asset_Sku.pm index ad832ab13..c643e6cbc 100644 --- a/lib/WebGUI/Help/Asset_Sku.pm +++ b/lib/WebGUI/Help/Asset_Sku.pm @@ -18,6 +18,7 @@ our $HELP = { { 'name' => 'description', description=>'description help' }, { 'name' => 'displayTitle', description=>'display title help' }, { 'name' => 'vendorId', description=>'vendor help' }, + { 'name' => 'shipsSeparately', description=>'shipsSeparately help' }, ], related => [] }, diff --git a/lib/WebGUI/Shop/ShipDriver/FlatRate.pm b/lib/WebGUI/Shop/ShipDriver/FlatRate.pm index 6ebc4e992..e9a246296 100644 --- a/lib/WebGUI/Shop/ShipDriver/FlatRate.pm +++ b/lib/WebGUI/Shop/ShipDriver/FlatRate.pm @@ -29,9 +29,9 @@ base methods. These methods are customized in this class: Returns a shipping price. Calculates the shipping price using the following formula: total price of shippable items * percentageOfPrice - + flatFee + total weight of shippable items * pricePerWeight + total quantity of shippable items * pricePerItem + + flatFee * numberOfSeparatelyShippedItems =head3 $cart @@ -45,17 +45,31 @@ sub calculate { my ($self, $cart) = @_; my $cost = 0; my $anyShippable = 0; + my $separatelyShipped = 0; + my $looseBundle = 0; foreach my $item (@{$cart->getItems}) { my $sku = $item->getSku; if ($sku->isShippingRequired) { - $cost += ($item->get("quantity") * $sku->getPrice * $self->get("percentageOfPrice") / 100) # cost by price - + ($item->get("quantity") * $sku->getWeight * $self->get("pricePerWeight") / 100) # cost by weight - + ($item->get("quantity") * $self->get("pricePerItem")); # cost by item + my $quantity = $item->get('quantity'); + $cost += ($quantity * $sku->getPrice * $self->get("percentageOfPrice") / 100) # cost by price + + ($quantity * $sku->getWeight * $self->get("pricePerWeight") / 100) # cost by weight + + ($quantity * $self->get("pricePerItem")); # cost by item $anyShippable = 1; + ##Account for items which must be shipped separately, and with those that can be shipped + ##together. + ## Two items shipped separately = two bundles + ## 1 shipped separately plus 1 not = two bundles + ## two items shipped together = one bundle + if ($sku->shipsSeparately) { + $separatelyShipped += $quantity; + } + else { + $looseBundle = 1; + } } } if ($anyShippable) { - $cost += $self->get('flatFee'); + $cost += $self->get('flatFee') * ($separatelyShipped + $looseBundle); } return $cost; } diff --git a/lib/WebGUI/i18n/English/Asset_Sku.pm b/lib/WebGUI/i18n/English/Asset_Sku.pm index 4e2da14ff..8e85ce56b 100644 --- a/lib/WebGUI/i18n/English/Asset_Sku.pm +++ b/lib/WebGUI/i18n/English/Asset_Sku.pm @@ -69,6 +69,18 @@ our $I18N = { context => q|help for vendor field| }, + 'shipsSeparately' => { + message => q|Ships Separately?|, + lastUpdated => 0, + context => q|label in the edit form. Ships, as in ships via post or mail or shipping. Separately, independently of other items in the cart.|, + }, + + 'shipsSeparately help' => { + message => q|If set to yes, then this Sku will incur additional, independent shipping costs, rather than sharing costs with other items in a cart.|, + lastUpdated => 0, + context => q|help for shipsSeparate field in the edit form| + }, + 'add to cart' => { message => q|Add To Cart|, lastUpdated => 0, diff --git a/t/Asset/Sku.t b/t/Asset/Sku.t index f9f854d26..b6ee46ca5 100644 --- a/t/Asset/Sku.t +++ b/t/Asset/Sku.t @@ -30,7 +30,7 @@ my $session = WebGUI::Test->session; #---------------------------------------------------------------------------- # Tests -plan tests => 17; # Increment this number for each test you create +plan tests => 19; # Increment this number for each test you create #---------------------------------------------------------------------------- # put your tests here @@ -63,6 +63,10 @@ is($sku->onRemoveFromCart, undef, "onRemoveFromCart should exist and return unde is($sku->isRecurring, 0, "skus are not recurring by default"); is($sku->isShippingRequired, 0, "skus are not shippable by default"); is($sku->getConfiguredTitle, $sku->getTitle, "configured title and title should be the same by default"); +is($sku->shipsSeparately, 0, 'shipsSeparately return 0 by default'); + +$sku->update({shipsSeparately => 1,}); +is($sku->shipsSeparately, 1, '... tracks shipsSepartely sku property'); isa_ok($sku->getCart, "WebGUI::Shop::Cart", "can get a cart object"); my $item = $sku->addToCart; @@ -72,12 +76,12 @@ $item->cart->delete; my $loadSku = WebGUI::Asset::Sku->newBySku($session, $sku->get("sku")); is($loadSku->getId, $sku->getId, "newBySku() works."); -$sku->purge; - #---------------------------------------------------------------------------- # Cleanup END { +$sku->purge; + } 1; diff --git a/t/Shop/ShipDriver/FlatRate.t b/t/Shop/ShipDriver/FlatRate.t index 580031275..8bb5a0667 100644 --- a/t/Shop/ShipDriver/FlatRate.t +++ b/t/Shop/ShipDriver/FlatRate.t @@ -31,7 +31,7 @@ my $session = WebGUI::Test->session; #---------------------------------------------------------------------------- # Tests -my $tests = 14; +my $tests = 19; plan tests => 1 + $tests; #---------------------------------------------------------------------------- @@ -40,7 +40,7 @@ plan tests => 1 + $tests; my $loaded = use_ok('WebGUI::Shop::ShipDriver::FlatRate'); my $storage; -my ($driver, $cart, $car); +my ($driver, $cart, $car, $key); my $versionTag; SKIP: { @@ -127,8 +127,6 @@ cmp_deeply( # ####################################################################### -$driver; - my $options = { label => 'flat rate, ship weight, items in the cart', enabled => 1, @@ -319,6 +317,60 @@ $options = { $driver->update($options); is($driver->calculate($cart), 30_200, 'calculate by percentage of price'); +$cart->empty(); +$driver->update({ + label => 'flat fee for shipsSeparately test', + enabled => 1, + flatFee => 1, + percentageOfPrice => 0, + pricePerWeight => 0, + pricePerItem => 0, +}); + +$key = WebGUI::Asset->getImportNode($session)->addChild({ + className => 'WebGUI::Asset::Sku::Product', + title => 'Key', + isShippingRequired => 1, + shipsSeparately => 1, +}); + +my $metalKey = $key->setCollateral('variantsJSON', 'variantId', 'new', + { + shortdesc => 'metal key', + varSku => 'metal-key', + price => 1.00, + weight => 1.00, + quantity => 1e9, + } +); + +my $bioKey = $key->setCollateral('variantsJSON', 'variantId', 'new', + { + shortdesc => 'biometric key', + varSku => 'bio-key', + price => 5.00, + weight => 1.00, + quantity => 1e9, + } +); + +my $boughtCar = $car->addToCart($car->getCollateral('variantsJSON', 'variantId', $reallyNiceCar)); +my $firstKey = $key->addToCart($key->getCollateral('variantsJSON', 'variantId', $metalKey)); +is($driver->calculate($cart), 2, 'shipsSeparately: returns two, one for ships separately, one for ships bundled'); + +$boughtCar->adjustQuantity(); +is($driver->calculate($cart), 2, '... returns two, one for ships separately, one for ships bundled, even for two items'); + +$firstKey->adjustQuantity(); +is($driver->calculate($cart), 3, '... returns three, two for ships separately, one for ships bundled, even for two items'); + +$key->update({shipsSeparately => 0}); +is($driver->calculate($cart), 1, '... returns one, since all can be bundled together now'); + +$car->update({shipsSeparately => 1}); +$key->update({shipsSeparately => 1}); +is($driver->calculate($cart), 4, '... returns four, since all must be shipped separately now'); + } #---------------------------------------------------------------------------- @@ -333,6 +385,9 @@ END { if (defined $car && (ref($car) eq 'WebGUI::Asset::Sku::Product')) { $car->purge; } + if (defined $key && (ref($key) eq 'WebGUI::Asset::Sku::Product')) { + $key->purge; + } if (defined $versionTag) { $versionTag->rollback; }