File Coverage

blib/lib/Dancer2/Plugin/Cart.pm
Criterion Covered Total %
statement 289 316 91.4
branch 45 78 57.6
condition 7 36 19.4
subroutine 30 31 96.7
pod 12 14 85.7
total 383 475 80.6


line stmt bran cond sub pod time code
1             package Dancer2::Plugin::Cart;
2             # ABSTRACT: Cart Plugin for Dancer2 app.
3 8     8   5696822 use strict;
  8         23  
  8         242  
4 8     8   46 use warnings;
  8         21  
  8         255  
5 8     8   3947 use Dancer2::Plugin;
  8         281754  
  8         85  
6 8     8   72984 use Dancer2::Plugin::Cart::InlineViews;
  8         31  
  8         253  
7 8     8   4945 use JSON;
  8         59587  
  8         68  
8             our $VERSION = '1.0001'; #Version
9              
10              
11             BEGIN{
12             has 'product_list' => (
13             is => 'ro',
14             from_config => 1,
15 1         50 default => sub { [] }
16 8     8   3422 );
17              
18             has 'products_view_template' => (
19             is => 'ro',
20             from_config => 'views.products',
21             default => sub {}
22 8         10134 );
23              
24             has 'cart_view_template' => (
25             is => 'ro',
26             from_config => 'views.products',
27             default => sub {}
28 8         7492 );
29              
30             has 'cart_receipt_template' => (
31             is => 'ro',
32             from_config => 'views.receipt',
33             default => sub {}
34 8         7470 );
35              
36             has 'shipping_view_template' => (
37             is => 'ro',
38             from_config => 'views.shipping',
39             default => sub {}
40 8         8271 );
41              
42             has 'billing_view_template' => (
43             is => 'ro',
44             from_config => 'views.billing',
45             default => sub {}
46 8         8462 );
47              
48             has 'review_view_template' => (
49             is => 'ro',
50             from_config => 'views.review',
51             default => sub {}
52 8         8555 );
53              
54             has 'receipt_view_template' => (
55             is => 'ro',
56             from_config => 'views.receipt',
57             default => sub {}
58 8         8918 );
59              
60             has 'default_routes' => (
61             is => 'ro',
62             from_config => 1,
63 7         441 default => sub { '1' }
64 8         8177 );
65              
66             has 'excluded_routes' => (
67             is => 'ro',
68             from_config => 1,
69 7         922 default => sub { [] }
70 8         7946 );
71              
72 8         7580 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         8606 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 30542 my $self = shift;
117             #Create a session
118 7         240 my $settings = $self->app->config;
119 7         248 my $excluded_routes = $self->excluded_routes;
120              
121 7 50       217 if( $self->default_routes ){
122             $self->app->add_route(
123             method => 'get',
124             regexp => '/products',
125             code => sub {
126 2     2   390492 my $app = shift;
127             #generate session if didn't exists
128 2         50 $app->session;
129 2   50     22374 my $template = $self->products_view_template || 'products' ;
130 2 50       81 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         95 _products_view({ product_list => $self->products });
140             }
141             },
142 7 50       25 )if !grep { $_ eq 'products' }@{$excluded_routes};
  0         0  
  7         134  
143              
144             $self->app->add_route(
145             method => 'get',
146             regexp => '/cart',
147             code => sub {
148 3     3   40556 my $app = shift;
149 3         20 my $cart = $self->cart;
150             #Generate session if didn't exists
151 3         45 $app->session;
152 3   50     57 my $template = $self->cart_view_template || 'cart/cart' ;
153 3         31 my $page = "";
154 3 50       49 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         193 $page = _cart_view({ ec_cart => $app->session->read('ec_cart') });
164             }
165 3         52 my $ec_cart = $app->session->read('ec_cart');
166 3 50       80 delete $ec_cart->{add}->{error} if $ec_cart->{add}->{error};
167 3         38 $app->session->write( 'ec_cart', $ec_cart );
168 3         185 $page;
169             }
170 7 50       39027 )if !grep { $_ eq 'cart' }@{$excluded_routes};
  0         0  
  7         195  
171              
172             $self->app->add_route(
173             method => 'post',
174             regexp => '/cart/add',
175             code => sub {
176 3     3   59028 my $app = shift;
177 3         24 $self->cart_add;
178 3         192 $app->redirect('/cart');
179             }
180 7 50       2331 )if !grep { $_ eq 'cart/add' }@{$excluded_routes};
  0         0  
  7         121  
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       2227 )if !grep { $_ eq 'cart/clear' }@{$excluded_routes};
  0         0  
  7         114  
192              
193             $self->app->add_route(
194             method => 'get',
195             regexp => '/cart/shipping',
196             code => sub {
197 1     1   20333 my $app = shift;
198 1         7 my $cart = $self->cart;
199 1   50     18 my $template = $self->shipping_view_template || 'shipping';
200 1         3 my $page = "";
201 1 50       23 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         50 $page = _shipping_view({ ec_cart => $app->session->read('ec_cart') });
211             }
212 1         21 my $ec_cart = $app->session->read('ec_cart');
213 1 50       31 delete $ec_cart->{shipping}->{error} if $ec_cart->{shipping}->{error};
214 1         15 $app->session->write( 'ec_cart', $ec_cart );
215 1         61 $page;
216             }
217 7 50       2391 )if !grep { $_ eq 'cart/shipping' }@{$excluded_routes};
  0         0  
  7         123  
218            
219             $self->app->add_route(
220             method => 'post',
221             regexp => '/cart/shipping',
222             code => sub {
223 2     2   32421 my $app = shift;
224 2         15 $self->shipping;
225 1         175 $app->redirect('/cart/billing');
226             }
227 7 50       2298 )if !grep { $_ eq 'cart/shipping' }@{$excluded_routes};
  0         0  
  7         116  
228              
229             $self->app->add_route(
230             method => 'get',
231             regexp => '/cart/billing',
232             code => sub {
233 1     1   20126 my $app = shift;
234 1         7 my $cart = $self->cart;
235 1   50     31 my $template = $self->billing_view_template || 'billing' ;
236 1         5 my $page = "";
237 1 50       32 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         81 $page = _billing_view({ ec_cart => $app->session->read('ec_cart') });
248             }
249 1         30 my $ec_cart = $app->session->read('ec_cart');
250 1 50       50 delete $ec_cart->{billing}->{error} if $ec_cart->{billing}->{error};
251 1         25 $app->session->write( 'ec_cart', $ec_cart );
252 1         113 $page;
253             }
254 7 50       2269 )if !grep { $_ eq 'cart/billing' }@{$excluded_routes};
  0         0  
  7         125  
255              
256             $self->app->add_route(
257             method => 'post',
258             regexp => '/cart/billing',
259             code => sub {
260 1     1   16553 my $app = shift;
261 1         8 $self->billing;
262 1         171 $app->redirect('/cart/review');
263             }
264 7 50       2257 )if !grep { $_ eq 'cart/billing' }@{$excluded_routes};
  0         0  
  7         112  
265            
266             $self->app->add_route(
267             method => 'get',
268             regexp => '/cart/review',
269             code => sub {
270 1     1   18264 my $app = shift;
271 1         7 my $cart = $self->cart;
272 1         3 my $page = "";
273 1   50     18 my $template = $self->review_view_template || 'review' ;
274 1 50       17 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         50 $page = _review_view( { ec_cart => $app->session->read('ec_cart') } );
284             }
285 1         21 my $ec_cart = $app->session->read('ec_cart');
286 1 50       31 delete $ec_cart->{checkout}->{error} if $ec_cart->{checkout}->{error};
287 1         14 $app->session->write('ec_cart',$ec_cart);
288 1         73 $page;
289             }
290 7 50       2267 )if !grep { $_ eq 'cart/review' }@{$excluded_routes};
  0         0  
  7         127  
291              
292             $self->app->add_route(
293             method => 'post',
294             regexp => '/cart/checkout',
295             code => sub {
296 1     1   18342 my $app = shift;
297 1         8 $self->checkout;
298 1         166 $app->redirect('/cart/receipt');
299             }
300 7 50       2349 )if !grep { $_ eq 'cart/receipt' }@{$excluded_routes};
  0         0  
  7         127  
301              
302             $self->app->add_route(
303             method => 'get',
304             regexp => '/cart/receipt',
305             code => sub {
306 1     1   16802 my $app = shift;
307 1   50     36 my $template = $self->receipt_view_template || 'receipt' ;
308 1         2 my $page = "";
309 1         20 my $ec_cart = $app->session->read('ec_cart');
310 1 50       982 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         36 $page = _receipt_view({ ec_cart => $ec_cart });
321             }
322 1         19 $app->session->delete('ec_cart');
323 1         81 $page;
324             }
325 7 50       2167 )if !grep { $_ eq 'cart/receipt' }@{$excluded_routes};
  0         0  
  7         129  
326             }
327             };
328              
329              
330             sub products {
331 9     9 1 30 my ( $self ) = @_;
332 9         36 my $app = $self->app;
333 9         33 my $ec_cart = $self->cart;
334 9 50       172 if ( $self->product_list ){
335 9         488 $ec_cart->{products} = $self->product_list;
336 9         242 $app->session->write( 'ec_cart', $ec_cart );
337             }
338 9         725 $app->execute_hook('plugin.cart.products');
339 9         3146 $ec_cart = $self->cart;
340 9         72 return $ec_cart->{products};
341             }
342              
343             sub cart_add_item {
344 11     11 1 369355 my ( $self, $product ) = @_;
345 11         73 my $app = $self->app;
346 11         30 my $index = 0;
347 11         63 my $ec_cart = $self->cart;
348 11 50       58 $ec_cart->{cart}->{items} = [] unless $ec_cart->{cart}->{items};
349 11         32 foreach my $cart_product ( @{$ec_cart->{cart}->{items}} ){
  11         50  
350 7 100       47 if( $cart_product->{ec_sku} eq $product->{ec_sku} ){
351 4         15 $cart_product->{ec_quantity} += $product->{ec_quantity};
352 4         27 $cart_product->{ec_subtotal} = $cart_product->{ec_quantity} * $cart_product->{ec_price};
353 4 100       21 if( $cart_product->{ec_quantity} <= 0 ){
354 1         3 splice @{$ec_cart->{cart}->{items}}, $index, 1;
  1         4  
355             }
356 4         85 $app->session->write( 'ec_cart', $ec_cart );
357 4         294 return $cart_product;
358             }
359 3         8 $index++;
360             }
361            
362 7         28 foreach my $product_item ( @{$self->products} ){
  7         41  
363 21 100       96 if( $product_item->{ec_sku} eq $product->{ec_sku} ){
364 6         14 foreach my $k (keys %{ $product_item }) {
  6         69  
365 12         43 $product->{$k} = $product_item->{$k};
366             }
367 6         33 $product->{ec_subtotal} = $product->{ec_quantity} * $product->{ec_price};
368             }
369             }
370 7         18 push @{$ec_cart->{cart}->{items}}, $product;
  7         25  
371 7         112 $app->session->write( 'ec_cart', $ec_cart );
372            
373 7         428 return $product;
374             };
375              
376             sub cart {
377 46     46 1 686024 my ( $self ) = @_;
378 46         183 my $app = $self->app;
379 46         926 $app->execute_hook('plugin.cart.before_cart');
380 46         9715 my $ec_cart = $app->session->read('ec_cart');
381 46 100       67692 $ec_cart->{cart}->{items} = [] unless $ec_cart->{cart}->{items};
382 46         769 $app->session->write('ec_cart', $ec_cart);
383 46         3628 $self->subtotal;
384 46         211 $self->adjustments;
385 46         9741 $self->total;
386 46         763 $ec_cart = $app->session->read('ec_cart');
387 46         2145 $app->execute_hook('plugin.cart.after_cart');
388 46         9615 $ec_cart = $app->session->read('ec_cart');
389 46         1351 return $ec_cart;
390             };
391              
392             sub quantity {
393 1     1 1 12287 my ($self, $params) = @_;
394 1         6 my $app = $self->app;
395              
396 1         8 $self->execute_hook ('plugin.cart.before_quantity');
397 1         88 my $ec_cart = $app->session->read('ec_cart');
398 1         1359 my $quantity = 0;
399 1         3 foreach my $item_quantity ( @{ $ec_cart->{cart}->{items} } ){
  1         7  
400 1 50       9 $quantity += $item_quantity->{ec_quantity} if $item_quantity->{ec_quantity};
401             }
402 1         6 $ec_cart->{cart}->{quantity} = $quantity;
403 1         22 $app->session->write('ec_cart',$ec_cart);
404 1         96 $self->execute_hook ('plugin.cart.after_quantity');
405 1         91 $ec_cart = $app->session->read('ec_cart');
406 1         37 $ec_cart->{cart}->{quantity};
407             }
408              
409             sub subtotal{
410 46     46 1 127 my ($self, $params) = @_;
411 46         166 my $app = $self->app;
412              
413 46         244 $self->execute_hook ('plugin.cart.before_subtotal');
414 46         4326 my $ec_cart = $app->session->read('ec_cart');
415 46         1340 my $subtotal = 0;
416 46         128 foreach my $item_subtotal ( @{ $ec_cart->{cart}->{items} } ){
  46         168  
417 35 100       161 $subtotal += $item_subtotal->{ec_subtotal} if $item_subtotal->{ec_subtotal};
418             }
419 46         134 $ec_cart->{cart}->{subtotal} = $subtotal;
420 46         729 $app->session->write('ec_cart',$ec_cart);
421 46         3079 $self->execute_hook ('plugin.cart.after_subtotal');
422 46         3394 $ec_cart = $app->session->read('ec_cart');
423 46         1350 $ec_cart->{cart}->{subtotal};
424             }
425              
426              
427             sub clear_cart {
428 1     1 1 19507 my ($self, $params ) = @_;
429 1         9 $self->execute_hook ('plugin.cart.before_clear_cart');
430 1         93 $self->app->session->delete('ec_cart');
431 1         1100 $self->execute_hook ('plugin.cart.after_clear_cart');
432             }
433              
434              
435             sub cart_add {
436 3     3 1 9 my ($self, $params) = @_;
437              
438 3         15 my $app = $self->app;
439 3         19 my $form_params = { $app->request->params };
440 3         54 my $product = undef;
441            
442             #Add params to ec_cart session
443 3         53 my $ec_cart = $app->session->read( 'ec_cart' );
444 3         3110 $ec_cart->{add}->{form} = $form_params;
445 3         40 $app->session->write( 'ec_cart', $ec_cart );
446              
447             #Param validation
448 3         253 $app->execute_hook( 'plugin.cart.validate_cart_add_params' );
449 3         572 $ec_cart = $app->session->read('ec_cart');
450            
451 3 50       83 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         49 $app->execute_hook( 'plugin.cart.before_cart_add' );
457 3         2937 $ec_cart = $app->session->read('ec_cart');
458              
459 3 50       111 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         28 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         1261 $ec_cart = $app->session->read('ec_cart');
471 3         100 delete $ec_cart->{add};
472 3         52 $app->session->write( 'ec_cart', $ec_cart );
473             }
474             }
475             }
476              
477             sub shipping {
478 2     2 1 7 my $self = shift;
479 2         11 my $app = $self->app;
480 2         17 my $params = { $app->request->params };
481             #Add params to ec_cart session
482 2         132 my $ec_cart = $app->session->read( 'ec_cart' );
483 2         2589 $ec_cart->{shipping}->{form} = $params;
484 2         40 $app->session->write( 'ec_cart', $ec_cart );
485 2         221 $app->execute_hook( 'plugin.cart.validate_shipping_params' );
486 2         3241 $ec_cart = $app->session->read('ec_cart');
487 2 100       55 if ( $ec_cart->{shipping}->{error} ){
488 1   33     20 $app->redirect( $app->request->referer || $app->request->uri );
489             }
490             else{
491 1         18 $app->execute_hook( 'plugin.cart.before_shipping' );
492 1         239 my $ec_cart = $app->session->read('ec_cart');
493              
494 1 50       29 if ( $ec_cart->{shipping}->{error} ){
495            
496 0   0     0 $app->redirect( ''.$app->request->referer || $app->request->uri );
497             }
498 1         28 $app->execute_hook( 'plugin.cart.after_shipping' );
499             }
500             }
501              
502             sub billing{
503 1     1 1 3 my $self = shift;
504 1         6 my $app = $self->app;
505 1         7 my $params = { $app->request->params };
506             #Add params to ec_cart session
507 1         32 my $ec_cart = $app->session->read( 'ec_cart' );
508 1         1237 $ec_cart->{billing}->{form} = $params;
509 1         15 $app->session->write( 'ec_cart', $ec_cart );
510 1         121 $app->execute_hook( 'plugin.cart.validate_billing_params' );
511 1         192 $ec_cart = $app->session->read('ec_cart');
512 1 50       29 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         178 my $ec_cart = $app->session->read('ec_cart');
518              
519 1 50       51 if ( $ec_cart->{billing}->{error} ){
520 0   0     0 $app->redirect( $app->request->referer || $app->request->uri );
521             }
522 1         22 $app->execute_hook( 'plugin.cart.after_billing' );
523             }
524             }
525              
526             sub checkout{
527 1     1 1 2 my $self = shift;
528 1         7 my $app = $self->app;
529 1         7 my $params = ($app->request->params);
530 1         29 my $ec_cart = $app->session->read( 'ec_cart' );
531 1         1026 $ec_cart->{checkout}->{form} = $params;
532 1         14 $app->session->write( 'ec_cart', $ec_cart );
533 1         86 $app->execute_hook( 'plugin.cart.validate_checkout_params' );
534 1         184 $ec_cart = $app->session->read('ec_cart');
535 1 50       29 if ( $ec_cart->{checkout}->{error} ){
536 0   0     0 $app->redirect( $app->request->referer || $app->request->uri );
537             }
538             else{
539 1         17 $app->execute_hook( 'plugin.cart.checkout' );
540 1         174 $ec_cart = $app->session->read('ec_cart');
541 1 50       27 if ( $ec_cart->{checkout}->{error} ){
542 0   0     0 $app->redirect( $app->request->referer || $app->request->uri );
543             }
544             else{
545 1         5 $self->close_cart;
546             }
547             }
548             }
549              
550             sub close_cart{
551 1     1 1 4 my ($self, $params) = @_;
552 1         3 my $app = $self->app;
553 1         6 my $ec_cart = $self->cart;
554 1 50       4 return { error => 'Cart without items' } unless @{$ec_cart->{cart}->{items}} > 0;
  1         8  
555 1         30 $app->execute_hook( 'plugin.cart.before_close_cart' );
556 1         256 $ec_cart->{cart}->{session} = $app->session->id;
557 1         26 $ec_cart->{cart}->{status} = 1;
558 1         15 $app->session->write('ec_cart', $ec_cart );
559 1         74 $app->execute_hook( 'plugin.cart.after_close_cart' );
560             }
561              
562             sub adjustments {
563 46     46 1 133 my ($self, $params) = @_;
564 46         137 my $app = $self->app;
565 46         739 my $ec_cart = $app->session->read('ec_cart');
566 46         1552 my $default_adjustments = [
567             {
568             description => 'Discounts',
569             value => '0'
570             },
571             {
572             description => 'Shipping',
573             value => '0'
574             },
575             {
576             description => 'Taxes',
577             value => '0'
578             },
579             ];
580 46         135 $ec_cart->{cart}->{adjustments} = $default_adjustments;
581 46         816 $app->session->write( 'ec_cart', $ec_cart );
582 46         3632 $app->execute_hook('plugin.cart.adjustments');
583             }
584              
585              
586             sub total {
587 46     46 0 140 my ($self) = shift;
588 46         140 my $app = $self->app;
589 46         885 $app->execute_hook('plugin.cart.before_total');
590 46         9237 my $ec_cart = $app->session->read('ec_cart');
591 46         1419 my $total = 0;
592 46         134 $total += $ec_cart->{cart}->{subtotal};
593 46         101 foreach my $adjustment ( @{$ec_cart->{cart}->{adjustments}}){
  46         156  
594 138         354 $total += $adjustment->{value};
595             }
596 46         115 $ec_cart->{cart}->{total} = $total;
597 46         742 $app->session->write('ec_cart', $ec_cart );
598 46         3863 $app->execute_hook('plugin.cart.after_total');
599 46         9413 return $ec_cart->{cart}->{total};
600             }
601              
602              
603              
604             1;
605             __END__