diff --git a/lib/Interchange6/Cart.pm b/lib/Interchange6/Cart.pm index 3315b00..7fa3c71 100644 --- a/lib/Interchange6/Cart.pm +++ b/lib/Interchange6/Cart.pm @@ -516,18 +516,25 @@ the zero-based index of the product within L. sub update { my ( $self, @args ) = @_; - my @products; + $self->_update_cart_item(quantity => @args); +} +sub _update_cart_item { + my ($self, $key, @args) = @_; + croak "Missing attribute" unless $key; + my $accessor = $key; + my $mutator = "set_" . $key; + my @products; ARGS: while ( @args > 0 ) { - my ( $product, $sku, $qty ); + my ( $product, $sku, $attr ); if ( ref( $args[0] ) eq '' ) { # original API expecting list of sku/qty pairs $sku = shift @args; - $qty = shift @args; + $attr = shift @args; croak "sku not defined in arg to update" unless defined $sku; @@ -554,7 +561,7 @@ sub update { my %selectors = %{ shift @args }; - $qty = delete $selectors{quantity}; + $attr = delete $selectors{$key}; if ( defined $selectors{index} ) { @@ -602,18 +609,20 @@ sub update { croak "Product not found for update" unless $product; - defined($qty) && ref($qty) eq '' - or croak "quantity argument to update must be defined"; + defined($attr) && ref($attr) eq '' + or croak "$key argument to update must be defined"; - if ( $qty == 0 ) { + if ($key eq 'quantity' and $attr == 0 ) { $self->remove( $product->sku ); next; } - # jump to next product if quantity stays the same - next ARGS if $qty == $product->quantity; + # jump to next product if the attribute stays the same + if (defined $product->$accessor and $attr eq $product->$accessor) { + next ARGS; + } - $product->set_quantity($qty); + $product->$mutator($attr); push @products, $product; } @@ -622,6 +631,42 @@ sub update { return @products; } +=head2 update_sku + +Change the sku of a product already in the cart (the first argument). + +The API for the arguments are the same as C + +=head2 update_canonical_sku + +Change the canonical sku of a product already in the cart. + +The API for the arguments are the same as C + +=head2 update_name + +Change the name of a product already in the cart. + +The API for the arguments are the same as C + +=cut + +sub update_sku { + my ($self, @args) = @_; + $self->_update_cart_item(sku => @args); +} + +sub update_canonical_sku { + my ($self, @args) = @_; + $self->_update_cart_item(canonical_sku => @args); +} + +sub update_name { + my ($self, @args) = @_; + $self->_update_cart_item(name => @args); +} + + =head1 AUTHORS Stefan Hornburg (Racke), diff --git a/lib/Interchange6/Cart/Product.pm b/lib/Interchange6/Cart/Product.pm index e7b725c..b7a84a4 100644 --- a/lib/Interchange6/Cart/Product.pm +++ b/lib/Interchange6/Cart/Product.pm @@ -65,6 +65,7 @@ has name => ( is => 'ro', isa => NonEmptyStr, required => 1, + writer => 'set_name', ); =head2 price @@ -133,10 +134,6 @@ sub _build_discount_percent { return int( ( $self->price - $self->selling_price ) / $self->price * 100 ); } -after 'set_price', 'set_selling_price' => sub { - shift->clear_discount_percent; -}; - =head2 quantity Product quantity is optional and has to be a natural number greater @@ -160,12 +157,6 @@ has quantity => ( writer => 'set_quantity', ); -after set_quantity => sub { - my $self = shift; - $self->clear_subtotal; - $self->clear_total; -}; - =head2 sku Unique product identifier is required. @@ -176,6 +167,7 @@ has sku => ( is => 'ro', isa => NonEmptyStr, required => 1, + writer => 'set_sku', ); =head2 canonical_sku @@ -188,6 +180,7 @@ is the sku of the parent product. has canonical_sku => ( is => 'ro', default => undef, + writer => 'set_canonical_sku', ); =head2 subtotal @@ -372,17 +365,27 @@ sub should_combine_by_sku { return $self->combine; } +after 'set_price', 'set_selling_price', 'set_sku' => sub { + shift->clear_discount_percent; +}; + +after qw/set_quantity set_name set_sku set_canonical_sku set_quantity/ => sub { + my $self = shift; + $self->clear_subtotal; + $self->clear_total; +}; + # after cost changes we need to clear the cart subtotal/total # our own total is handled by the Costs role -after 'clear_costs', 'cost_set', 'apply_cost', 'set_quantity' => sub { +after 'clear_costs', 'cost_set', 'apply_cost', 'set_quantity', 'set_name', 'set_sku', 'set_canonical_sku' => sub { my $self = shift; if ( $self->cart ) { $self->cart->clear_subtotal; $self->cart->clear_total; } }; -after 'set_quantity', 'set_weight' => sub { +after 'set_quantity', 'set_weight', 'set_name', 'set_sku', 'set_canonical_sku' => sub { my $self = shift; if ( $self->cart ) { $self->cart->clear_weight; diff --git a/t/unit/cart.t b/t/unit/cart.t index be134dc..c7d792d 100644 --- a/t/unit/cart.t +++ b/t/unit/cart.t @@ -629,4 +629,28 @@ cmp_ok( $cart->subtotal, '==', 5, "subtotal is 5" ); cmp_ok( $cart->total, '==', 5, "total is 5" ); cmp_ok( $cart->weight, '==', 10, "weight is 10" ); +lives_ok { $cart->update_sku(ONE => 'THREE') }; +{ + my $product = $cart->products->[0]; + is $product->sku, 'THREE'; +} +lives_ok { $cart->update_sku(THREE => 'ONE') }; + +lives_ok { $cart->update_canonical_sku(ONE => 'Hello') }; +lives_ok { $cart->update_name(ONE => 'Bau') }; + +{ + my $product = $cart->products->[0]; + is ($product->sku, 'ONE'); + is ($product->canonical_sku, 'Hello'); + is ($product->name, 'Bau'); +} + +cmp_ok( $cart->count, '==', 2, "count is 2" ); +cmp_ok( $cart->quantity, '==', 3, "quantity is 3" ); +cmp_ok( $cart->subtotal, '==', 5, "subtotal is 5" ); +cmp_ok( $cart->total, '==', 5, "total is 5" ); +cmp_ok( $cart->weight, '==', 10, "weight is 10" ); + + done_testing; diff --git a/t/unit/cart_product.t b/t/unit/cart_product.t index d644909..16985b1 100644 --- a/t/unit/cart_product.t +++ b/t/unit/cart_product.t @@ -195,4 +195,11 @@ ok( !$product->defined_extra('undef'), "!defined_extra('undef')" ); lives_ok { $product->clear_extra } "ok clear_extra"; cmp_ok( $product->keys_extra, '==', 0, "keys_extra has 0 keys" ); +dies_ok { $product->set_name('') } "fail set_name with empty string"; +dies_ok { $product->set_sku('') } "fail set_sku with empty string"; +dies_ok { $product->set_name(undef) } "fail set_name with undef"; +dies_ok { $product->set_sku(undef) } "fail set_sku with undef"; +lives_ok { $product->set_canonical_sku(undef) } "fail set_sku with empty string"; +is $product->canonical_sku, undef, "canonical sku can be undef"; + done_testing;