File Coverage

blib/lib/Dancer2/Plugin/Cart.pm
Criterion Covered Total %
statement 286 313 91.3
branch 45 78 57.6
condition 7 36 19.4
subroutine 30 31 96.7
pod 12 14 85.7
total 380 472 80.5


line stmt bran cond sub pod time code
1             package Dancer2::Plugin::Cart;
2             # ABSTRACT: Cart Plugin for Dancer2 app.
3 8     8   4655557 use strict;
  8         22  
  8         200  
4 8     8   36 use warnings;
  8         19  
  8         172  
5 8     8   3518 use Dancer2::Plugin;
  8         243997  
  8         56  
6 8     8   63775 use Dancer2::Plugin::Cart::InlineViews;
  8         21  
  8         207  
7 8     8   3765 use JSON;
  8         46569  
  8         41  
8             our $VERSION = '1.0000'; #Version
9              
10              
11             BEGIN{
12             has 'product_list' => (
13             is => 'ro',
14             from_config => 1,
15 1         46 default => sub { [] }
16 8     8   2512 );
17              
18             has 'products_view_template' => (
19             is => 'ro',
20             from_config => 'views.products',
21             default => sub {}
22 8         6734 );
23              
24             has 'cart_view_template' => (
25             is => 'ro',
26             from_config => 'views.products',
27             default => sub {}
28 8         5873 );
29              
30             has 'cart_receipt_template' => (
31             is => 'ro',
32             from_config => 'views.receipt',
33             default => sub {}
34 8         5938 );
35              
36             has 'shipping_view_template' => (
37             is => 'ro',
38             from_config => 'views.shipping',
39             default => sub {}
40 8         5998 );
41              
42             has 'billing_view_template' => (
43             is => 'ro',
44             from_config => 'views.billing',
45             default => sub {}
46 8         6056 );
47              
48             has 'review_view_template' => (
49             is => 'ro',
50             from_config => 'views.review',
51             default => sub {}
52 8         6051 );
53              
54             has 'receipt_view_template' => (
55             is => 'ro',
56             from_config => 'views.receipt',
57             default => sub {}
58 8         5996 );
59              
60             has 'default_routes' => (
61             is => 'ro',
62             from_config => 1,
63 7         277 default => sub { '1' }
64 8         6034 );
65              
66             has 'excluded_routes' => (
67             is => 'ro',
68             from_config => 1,
69 7         571 default => sub { [] }
70 8         6128 );
71              
72 8         5814 plugin_keywords qw/
73             adjustments
74             billing
75             cart
76             cart_add
77             cart_add_item
78             checkout
79             clear_cart
80             close_cart
81             products
82             quantity
83             subtotal
84             shipping
85             total
86             /;
87              
88 8         5950 plugin_hooks qw/
89             products
90             before_cart
91             after_cart
92             validate_cart_add_params
93             before_cart_add
94             after_cart_add
95             validate_shipping_params
96             before_shipping
97             after_shipping
98             validate_billing_params
99             before_billing
100             after_billing
101             validate_checkout_params
102             checkout
103             before_close_cart
104             after_close_cart
105             before_clear_cart
106             after_clear_cart
107             before_subtotal
108             after_subtotal
109             before_total
110             after_total
111             adjustments
112             /;
113             }
114              
115             sub BUILD {
116 7     7 0 18857 my $self = shift;
117             #Create a session
118 7         146 my $settings = $self->app->config;
119 7         148 my $excluded_routes = $self->excluded_routes;
120              
121 7 50       115 if( $self->default_routes ){
122             $self->app->add_route(
123             method => 'get',
124             regexp => '/products',
125             code => sub {
126 2     2   344343 my $app = shift;
127             #generate session if didn't exists
128 2         63 $app->session;
129 2   50     18646 my $template = $self->products_view_template || 'products' ;
130 2 50       40 if( -e $self->app->config->{views}.'/'.$template.'.tt' ) {
131 0         0 $app->template( $template, {
132             product_list => $self->products
133             },
134             {
135             layout => 'cart.tt'
136             });
137             }
138             else{
139 2         57 _products_view({ product_list => $self->products });
140             }
141             },
142 7 50       16 )if !grep { $_ eq 'products' }@{$excluded_routes};
  0         0  
  7         81  
143              
144             $self->app->add_route(
145             method => 'get',
146             regexp => '/cart',
147             code => sub {
148 3     3   30996 my $app = shift;
149 3         10 my $cart = $self->cart;
150             #Generate session if didn't exists
151 3         40 $app->session;
152 3   50     55 my $template = $self->cart_view_template || 'cart/cart' ;
153 3         23 my $page = "";
154 3 50       46 if( -e $self->app->config->{views}.'/'.$template.'.tt' ) {
155 0         0 $page = $app->template( $template, {
156             ec_cart => $app->session->read('ec_cart'),
157             },
158             {
159             layout => 'cart.tt'
160             } );
161             }
162             else{
163 3         97 $page = _cart_view({ ec_cart => $app->session->read('ec_cart') });
164             }
165 3         48 my $ec_cart = $app->session->read('ec_cart');
166 3 50       79 delete $ec_cart->{add}->{error} if $ec_cart->{add}->{error};
167 3         41 $app->session->write( 'ec_cart', $ec_cart );
168 3         176 $page;
169             }
170 7 50       26745 )if !grep { $_ eq 'cart' }@{$excluded_routes};
  0         0  
  7         95  
171              
172             $self->app->add_route(
173             method => 'post',
174             regexp => '/cart/add',
175             code => sub {
176 3     3   43397 my $app = shift;
177 3         12 $self->cart_add;
178 3         167 $app->redirect('/cart');
179             }
180 7 50       1577 )if !grep { $_ eq 'cart/add' }@{$excluded_routes};
  0         0  
  7         68  
181              
182              
183             $self->app->add_route(
184             method => 'get',
185             regexp => '/cart/clear',
186             code => sub {
187 0     0   0 my $app = shift;
188 0         0 $self->clear_cart;
189 0         0 $app->redirect('/cart');
190             }
191 7 50       1487 )if !grep { $_ eq 'cart/clear' }@{$excluded_routes};
  0         0  
  7         63  
192              
193             $self->app->add_route(
194             method => 'get',
195             regexp => '/cart/shipping',
196             code => sub {
197 1     1   12732 my $app = shift;
198 1         5 my $cart = $self->cart;
199 1   50     17 my $template = $self->shipping_view_template || 'shipping';
200 1         3 my $page = "";
201 1 50       16 if( -e $app->config->{views}.'/cart/'.$template.'.tt' ) {
202 0         0 $page = $app->template ( 'cart/'.$template, {
203             ec_cart => $app->session->read('ec_cart'),
204             },
205             {
206             layout => 'cart.tt'
207             });
208             }
209             else{
210 1         71 $page = _shipping_view({ ec_cart => $app->session->read('ec_cart') });
211             }
212 1         18 my $ec_cart = $app->session->read('ec_cart');
213 1 50       28 delete $ec_cart->{shipping}->{error} if $ec_cart->{shipping}->{error};
214 1         15 $app->session->write( 'ec_cart', $ec_cart );
215 1         59 $page;
216             }
217 7 50       1499 )if !grep { $_ eq 'cart/shipping' }@{$excluded_routes};
  0         0  
  7         73  
218            
219             $self->app->add_route(
220             method => 'post',
221             regexp => '/cart/shipping',
222             code => sub {
223 2     2   22330 my $app = shift;
224 2         8 $self->shipping;
225 1         167 $app->redirect('/cart/billing');
226             }
227 7 50       1451 )if !grep { $_ eq 'cart/shipping' }@{$excluded_routes};
  0         0  
  7         63  
228              
229             $self->app->add_route(
230             method => 'get',
231             regexp => '/cart/billing',
232             code => sub {
233 1     1   13010 my $app = shift;
234 1         5 my $cart = $self->cart;
235 1   50     17 my $template = $self->billing_view_template || 'billing' ;
236 1         3 my $page = "";
237 1 50       17 if( -e $app->config->{views}.'/cart/'.$template.'.tt' ) {
238 0         0 $page = $app->template( 'cart/'.$template, {
239             ec_cart => $app->session->read('ec_cart'),
240             },
241             {
242             layout => 'cart.tt'
243             }
244             );
245             }
246             else{
247 1         37 $page = _billing_view({ ec_cart => $app->session->read('ec_cart') });
248             }
249 1         18 my $ec_cart = $app->session->read('ec_cart');
250 1 50       29 delete $ec_cart->{billing}->{error} if $ec_cart->{billing}->{error};
251 1         15 $app->session->write( 'ec_cart', $ec_cart );
252 1         59 $page;
253             }
254 7 50       1530 )if !grep { $_ eq 'cart/billing' }@{$excluded_routes};
  0         0  
  7         67  
255              
256             $self->app->add_route(
257             method => 'post',
258             regexp => '/cart/billing',
259             code => sub {
260 1     1   10675 my $app = shift;
261 1         5 $self->billing;
262 1         166 $app->redirect('/cart/review');
263             }
264 7 50       1487 )if !grep { $_ eq 'cart/billing' }@{$excluded_routes};
  0         0  
  7         62  
265            
266             $self->app->add_route(
267             method => 'get',
268             regexp => '/cart/review',
269             code => sub {
270 1     1   12875 my $app = shift;
271 1         6 my $cart = $self->cart;
272 1         4 my $page = "";
273 1   50     16 my $template = $self->review_view_template || 'review' ;
274 1 50       15 if( -e $app->config->{views}.'/cart/'.$template.'.tt' ) {
275 0         0 $page = $app->template( 'cart/'.$template,{
276             ec_cart => $app->session->read('ec_cart'),
277             },
278             {
279             layout => 'cart.tt'
280             });
281             }
282             else{
283 1         36 $page = _review_view( { ec_cart => $app->session->read('ec_cart') } );
284             }
285 1         17 my $ec_cart = $app->session->read('ec_cart');
286 1 50       29 delete $ec_cart->{checkout}->{error} if $ec_cart->{checkout}->{error};
287 1         14 $app->session->write('ec_cart',$ec_cart);
288 1         60 $page;
289             }
290 7 50       1473 )if !grep { $_ eq 'cart/review' }@{$excluded_routes};
  0         0  
  7         72  
291              
292             $self->app->add_route(
293             method => 'post',
294             regexp => '/cart/checkout',
295             code => sub {
296 1     1   13836 my $app = shift;
297 1         5 $self->checkout;
298 1         183 $app->redirect('/cart/receipt');
299             }
300 7 50       1478 )if !grep { $_ eq 'cart/receipt' }@{$excluded_routes};
  0         0  
  7         66  
301              
302             $self->app->add_route(
303             method => 'get',
304             regexp => '/cart/receipt',
305             code => sub {
306 1     1   12364 my $app = shift;
307 1   50     17 my $template = $self->receipt_view_template || 'receipt' ;
308 1         2 my $page = "";
309 1         16 my $ec_cart = $app->session->read('ec_cart');
310 1 50       786 if( -e $app->config->{views}.'/cart/'.$template.'.tt' ) {
311 0         0 $page = $app->template( 'cart/'.$template,
312             {
313             ec_cart => $ec_cart
314             },
315             {
316             layout => 'cart.tt'
317             });
318             }
319             else{
320 1         26 $page = _receipt_view({ ec_cart => $ec_cart });
321             }
322 1         18 $app->session->delete('ec_cart');
323 1         69 $page;
324             }
325 7 50       1440 )if !grep { $_ eq 'cart/receipt' }@{$excluded_routes};
  0         0  
  7         69  
326             }
327             };
328              
329              
330             sub products {
331 9     9 1 23 my ( $self ) = @_;
332 9         29 my $app = $self->app;
333 9         31 my $ec_cart = $self->cart;
334 9 50       132 if ( $self->product_list ){
335 9         365 $ec_cart->{products} = $self->product_list;
336 9         164 $app->session->write( 'ec_cart', $ec_cart );
337             }
338 9         629 $app->execute_hook('plugin.cart.products');
339 9         2261 $ec_cart = $self->cart;
340 9         41 return $ec_cart->{products};
341             }
342              
343             sub cart_add_item {
344 11     11 1 292237 my ( $self, $product ) = @_;
345 11         53 my $app = $self->app;
346 11         22 my $index = 0;
347 11         33 my $ec_cart = $self->cart;
348 11 50       40 $ec_cart->{cart}->{items} = [] unless $ec_cart->{cart}->{items};
349 11         22 foreach my $cart_product ( @{$ec_cart->{cart}->{items}} ){
  11         35  
350 7 100       32 if( $cart_product->{ec_sku} eq $product->{ec_sku} ){
351 4         12 $cart_product->{ec_quantity} += $product->{ec_quantity};
352 4         12 $cart_product->{ec_subtotal} = $cart_product->{ec_quantity} * $cart_product->{ec_price};
353 4 100       24 if( $cart_product->{ec_quantity} <= 0 ){
354 1         2 splice @{$ec_cart->{cart}->{items}}, $index, 1;
  1         3  
355             }
356 4         62 $app->session->write( 'ec_cart', $ec_cart );
357 4         234 return $cart_product;
358             }
359 3         9 $index++;
360             }
361            
362 7         16 foreach my $product_item ( @{$self->products} ){
  7         25  
363 21 100       74 if( $product_item->{ec_sku} eq $product->{ec_sku} ){
364 6         14 foreach my $k (keys %{ $product_item }) {
  6         23  
365 12         32 $product->{$k} = $product_item->{$k};
366             }
367 6         25 $product->{ec_subtotal} = $product->{ec_quantity} * $product->{ec_price};
368             }
369             }
370 7         20 push @{$ec_cart->{cart}->{items}}, $product;
  7         33  
371 7         103 $app->session->write( 'ec_cart', $ec_cart );
372            
373 7         408 return $product;
374             };
375              
376             sub cart {
377 46     46 1 547794 my ( $self ) = @_;
378 46         162 my $app = $self->app;
379 46         773 $app->execute_hook('plugin.cart.before_cart');
380 46         8366 my $ec_cart = $app->session->read('ec_cart');
381 46 100       51222 $ec_cart->{cart}->{items} = [] unless $ec_cart->{cart}->{items};
382 46         593 $app->session->write('ec_cart', $ec_cart);
383 46         2773 $self->subtotal;
384 46         144 $self->adjustments;
385 46         7963 $self->total;
386 46         602 $ec_cart = $app->session->read('ec_cart');
387 46         1757 $app->execute_hook('plugin.cart.after_cart');
388 46         7969 $ec_cart = $app->session->read('ec_cart');
389 46         1181 return $ec_cart;
390             };
391              
392             sub quantity {
393 1     1 1 9698 my ($self, $params) = @_;
394 1         4 my $app = $self->app;
395              
396 1         5 $self->execute_hook ('plugin.cart.before_quantity');
397 1         68 my $ec_cart = $app->session->read('ec_cart');
398 1         772 my $quantity = 0;
399 1         2 foreach my $item_quantity ( @{ $ec_cart->{cart}->{items} } ){
  1         5  
400 1 50       5 $quantity += $item_quantity->{ec_quantity} if $item_quantity->{ec_quantity};
401             }
402 1         3 $ec_cart->{cart}->{quantity} = $quantity;
403 1         14 $app->session->write('ec_cart',$ec_cart);
404 1         59 $self->execute_hook ('plugin.cart.after_quantity');
405 1         64 $ec_cart = $app->session->read('ec_cart');
406 1         28 $ec_cart->{cart}->{quantity};
407             }
408              
409             sub subtotal{
410 46     46 1 93 my ($self, $params) = @_;
411 46         121 my $app = $self->app;
412              
413 46         163 $self->execute_hook ('plugin.cart.before_subtotal');
414 46         3270 my $ec_cart = $app->session->read('ec_cart');
415 46         1125 my $subtotal = 0;
416 46         74 foreach my $item_subtotal ( @{ $ec_cart->{cart}->{items} } ){
  46         116  
417 35 100       108 $subtotal += $item_subtotal->{ec_subtotal} if $item_subtotal->{ec_subtotal};
418             }
419 46         93 $ec_cart->{cart}->{subtotal} = $subtotal;
420 46         583 $app->session->write('ec_cart',$ec_cart);
421 46         2593 $self->execute_hook ('plugin.cart.after_subtotal');
422 46         2858 $ec_cart = $app->session->read('ec_cart');
423 46         1122 $ec_cart->{cart}->{subtotal};
424             }
425              
426              
427             sub clear_cart {
428 1     1 1 14301 my ($self, $params ) = @_;
429 1         5 $self->execute_hook ('plugin.cart.before_clear_cart');
430 1         81 $self->app->session->delete('ec_cart');
431 1         976 $self->execute_hook ('plugin.cart.after_clear_cart');
432             }
433              
434              
435             sub cart_add {
436 3     3 1 7 my ($self, $params) = @_;
437              
438 3         7 my $app = $self->app;
439 3         15 my $form_params = { $app->request->params };
440 3         43 my $product = undef;
441            
442             #Add params to ec_cart session
443 3         59 my $ec_cart = $app->session->read( 'ec_cart' );
444 3         2508 $ec_cart->{add}->{form} = $form_params;
445 3         39 $app->session->write( 'ec_cart', $ec_cart );
446              
447             #Param validation
448 3         229 $app->execute_hook( 'plugin.cart.validate_cart_add_params' );
449 3         569 $ec_cart = $app->session->read('ec_cart');
450            
451 3 50       82 if ( $ec_cart->{add}->{error} ){
452 0   0     0 $self->app->redirect( $app->request->referer || $app->request->uri );
453             }
454             else{
455             #Cart operations before add product to the cart.
456 3         47 $app->execute_hook( 'plugin.cart.before_cart_add' );
457 3         2422 $ec_cart = $app->session->read('ec_cart');
458              
459 3 50       78 if ( $ec_cart->{add}->{error} ){
460 0   0     0 $self->app->redirect( $app->request->referer || $app->request->uri );
461             }
462             else{
463             $product = $self->cart_add_item({
464             ec_sku => $ec_cart->{add}->{form}->{'ec_sku'},
465 3         17 ec_quantity => $ec_cart->{add}->{form}->{'ec_quantity'},
466             }
467             );
468             #Cart operations after adding product to the cart
469 3         48 $app->execute_hook( 'plugin.cart.after_cart_add' );
470 3         1083 $ec_cart = $app->session->read('ec_cart');
471 3         76 delete $ec_cart->{add};
472 3         38 $app->session->write( 'ec_cart', $ec_cart );
473             }
474             }
475             }
476              
477             sub shipping {
478 2     2 1 5 my $self = shift;
479 2         6 my $app = $self->app;
480 2         8 my $params = { $app->request->params };
481             #Add params to ec_cart session
482 2         50 my $ec_cart = $app->session->read( 'ec_cart' );
483 2         1597 $ec_cart->{shipping}->{form} = $params;
484 2         27 $app->session->write( 'ec_cart', $ec_cart );
485 2         139 $app->execute_hook( 'plugin.cart.validate_shipping_params' );
486 2         2239 $ec_cart = $app->session->read('ec_cart');
487 2 100       54 if ( $ec_cart->{shipping}->{error} ){
488 1   33     14 $app->redirect( $app->request->referer || $app->request->uri );
489             }
490             else{
491 1         17 $app->execute_hook( 'plugin.cart.before_shipping' );
492 1         179 my $ec_cart = $app->session->read('ec_cart');
493              
494 1 50       34 if ( $ec_cart->{shipping}->{error} ){
495            
496 0   0     0 $app->redirect( ''.$app->request->referer || $app->request->uri );
497             }
498 1         17 $app->execute_hook( 'plugin.cart.after_shipping' );
499             }
500             }
501              
502             sub billing{
503 1     1 1 3 my $self = shift;
504 1         4 my $app = $self->app;
505 1         5 my $params = { $app->request->params };
506             #Add params to ec_cart session
507 1         26 my $ec_cart = $app->session->read( 'ec_cart' );
508 1         785 $ec_cart->{billing}->{form} = $params;
509 1         16 $app->session->write( 'ec_cart', $ec_cart );
510 1         71 $app->execute_hook( 'plugin.cart.validate_billing_params' );
511 1         182 $ec_cart = $app->session->read('ec_cart');
512 1 50       28 if ( $ec_cart->{billing}->{error} ){
513 0   0     0 $app->redirect( $app->request->referer || $app->request->uri );
514             }
515             else{
516 1         17 $app->execute_hook( 'plugin.cart.before_billing' );
517 1         175 my $ec_cart = $app->session->read('ec_cart');
518              
519 1 50       28 if ( $ec_cart->{billing}->{error} ){
520 0   0     0 $app->redirect( $app->request->referer || $app->request->uri );
521             }
522 1         16 $app->execute_hook( 'plugin.cart.after_billing' );
523             }
524             }
525              
526             sub checkout{
527 1     1 1 2 my $self = shift;
528 1         4 my $app = $self->app;
529              
530 1         6 my $params = ($app->request->params);
531 1         26 $app->execute_hook( 'plugin.cart.validate_checkout_params' );
532 1         179 my $ec_cart = $app->session->read('ec_cart');
533              
534 1 50       795 if ( $ec_cart->{checkout}->{error} ){
535 0   0     0 $app->redirect( $app->request->referer || $app->request->uri );
536             }
537             else{
538 1         18 $app->execute_hook( 'plugin.cart.checkout' );
539 1         179 $ec_cart = $app->session->read('ec_cart');
540 1 50       28 if ( $ec_cart->{checkout}->{error} ){
541 0   0     0 $app->redirect( $app->request->referer || $app->request->uri );
542             }
543             else{
544 1         5 $self->close_cart;
545             }
546             }
547             }
548              
549             sub close_cart{
550 1     1 1 3 my ($self, $params) = @_;
551 1         4 my $app = $self->app;
552 1         4 my $ec_cart = $self->cart;
553 1 50       3 return { error => 'Cart without items' } unless @{$ec_cart->{cart}->{items}} > 0;
  1         5  
554 1         16 $app->execute_hook( 'plugin.cart.before_close_cart' );
555 1         174 $ec_cart->{cart}->{session} = $app->session->id;
556 1         22 $ec_cart->{cart}->{status} = 1;
557 1         13 $app->session->write('ec_cart', $ec_cart );
558 1         70 $app->execute_hook( 'plugin.cart.after_close_cart' );
559             }
560              
561             sub adjustments {
562 46     46 1 104 my ($self, $params) = @_;
563 46         108 my $app = $self->app;
564 46         584 my $ec_cart = $app->session->read('ec_cart');
565 46         1228 my $default_adjustments = [
566             {
567             description => 'Discounts',
568             value => '0'
569             },
570             {
571             description => 'Shipping',
572             value => '0'
573             },
574             {
575             description => 'Taxes',
576             value => '0'
577             },
578             ];
579 46         101 $ec_cart->{cart}->{adjustments} = $default_adjustments;
580 46         630 $app->session->write( 'ec_cart', $ec_cart );
581 46         3177 $app->execute_hook('plugin.cart.adjustments');
582             }
583              
584              
585             sub total {
586 46     46 0 90 my ($self) = shift;
587 46         104 my $app = $self->app;
588 46         737 $app->execute_hook('plugin.cart.before_total');
589 46         7999 my $ec_cart = $app->session->read('ec_cart');
590 46         1156 my $total = 0;
591 46         97 $total += $ec_cart->{cart}->{subtotal};
592 46         70 foreach my $adjustment ( @{$ec_cart->{cart}->{adjustments}}){
  46         109  
593 138         285 $total += $adjustment->{value};
594             }
595 46         88 $ec_cart->{cart}->{total} = $total;
596 46         599 $app->session->write('ec_cart', $ec_cart );
597 46         3138 $app->execute_hook('plugin.cart.after_total');
598 46         7623 return $ec_cart->{cart}->{total};
599             }
600              
601              
602              
603             1;
604             __END__