File Coverage

blib/lib/Interchange6/Role/Costs.pm
Criterion Covered Total %
statement 48 48 100.0
branch 20 20 100.0
condition n/a
subroutine 10 10 100.0
pod 1 1 100.0
total 79 79 100.0


line stmt bran cond sub pod time code
1             package Interchange6::Role::Costs;
2              
3 5     5   8461 use Carp;
  5         5  
  5         274  
4 5     5   1317 use Interchange6::Cart::Cost;
  5         9  
  5         194  
5 5     5   34 use Interchange6::Types -types;
  5         5  
  5         46  
6              
7 5     5   19251 use Moo::Role;
  5         11  
  5         43  
8 5     5   2262 use MooX::HandlesVia;
  5         508  
  5         33  
9 5     5   759 use MooseX::CoverableModifiers;
  5         4522  
  5         34  
10              
11             =head1 ATTRIBUTES
12              
13             =head2 costs
14              
15             Holds an array reference of L items.
16              
17             When called without arguments returns an array reference of all costs associated with the object. Costs are ordered according to the order they were applied.
18              
19             =cut
20              
21             has costs => (
22             is => 'ro',
23             isa => ArrayRef[CartCost],
24             coerce => 1,
25             default => sub { [] },
26             handles_via => 'Array',
27             handles => {
28             apply_cost => 'push',
29             clear_costs => 'clear',
30             cost_get => 'get',
31             cost_set => 'set',
32             cost_count => 'count',
33             get_costs => 'elements',
34             },
35             init_arg => undef,
36             );
37              
38             after 'clear_costs', 'cost_set', 'apply_cost' => sub {
39 16     16   8850 shift->clear_total;
40             };
41              
42             =head2 total
43              
44             Returns the sum of the objects L added to its C.
45              
46             =cut
47              
48             has total => (
49             is => 'lazy',
50             isa => Num,
51             clearer => 1,
52             predicate => 1,
53             );
54              
55             sub _build_total {
56 64     64   13501 my $self = shift;
57              
58 64         127 my @costs = $self->get_costs;
59 64         5767 my $subtotal = $self->subtotal;
60              
61 64         1478 my $sum = 0;
62 64         173 foreach my $i ( 0 .. $#costs ) {
63              
64 27 100       55 if ( $costs[$i]->relative ) {
65 14         215 $costs[$i]->set_current_amount( $subtotal * $costs[$i]->amount );
66             }
67             else {
68 13         172 $costs[$i]->set_current_amount( $costs[$i]->amount );
69             }
70              
71 27 100       516 if ( $costs[$i]->compound ) {
    100          
72 11         31 $subtotal += $costs[$i]->current_amount;
73             }
74             elsif ( !$costs[$i]->inclusive ) {
75 11         32 $sum += $costs[$i]->current_amount;
76             }
77             }
78              
79 64         1225 return sprintf( "%.2f", $subtotal + $sum );
80             }
81              
82             =head1 METHODS
83              
84             =head2 clear_costs
85              
86             Removes all the costs previously applied (using apply_cost). Used typically if you have free shipping or something similar, you can clear the costs.
87              
88             This method also calls L.
89              
90             =head2 clear_total
91              
92             Clears L.
93              
94             =head2 cost_get($index)
95              
96             Returns an element of the array of costs for the object by its index. You can also use negative index numbers, just as with Perl's core array handling.
97              
98             =head2 cost_count
99              
100             Returns the number of cost elements for the object.
101              
102             =head2 get_costs
103              
104             Returns all of the cost elements for the object as an array (not an arrayref).
105              
106             =head2 cost_set($index, $cost)
107              
108             Sets the cost at C<$index> to <$cost>.
109              
110             This method also calls L.
111              
112             =head2 has_total
113              
114             predicate on L.
115              
116             =head2 apply_cost
117              
118             Apply cost to object. L is a generic method typicaly used for taxes, discounts, coupons, gift certificates, etc.
119              
120             B This method also calls L.
121              
122             B Absolute cost
123              
124             Uses absolute value for amount. Amount 5 is 5 units of currency used (i.e. $5).
125              
126             $cart->apply_cost(amount => 5, name => 'shipping', label => 'Shipping');
127              
128             B Relative cost
129              
130             Uses percentage instead of value for amount. Relative is a boolean value (0/1).
131              
132             Add 19% German VAT:
133              
134             $cart->apply_cost(
135             amount => 0.19, name => 'tax', label => 'VAT', relative => 1
136             );
137              
138             Add 10% discount (negative amount):
139              
140             $cart->apply_cost(
141             amount => -0.1, name => 'discount', label => 'Discount', relative => 1
142             );
143              
144              
145             B Inclusive cost
146              
147             Same as relative cost, but it assumes that tax was included in the subtotal already, and only displays it (19% of subtotal value in example). Inclusive is a boolean value (0/1).
148              
149             $cart->apply_cost(amount => 0.19, name => 'tax', label => 'Sales Tax', relative => 1, inclusive => 1);
150              
151             =cut
152              
153             around apply_cost => sub {
154 15     15   12704 my ( $orig, $self, @args ) = @_;
155              
156 15 100       54 croak "argument to apply_cost undefined" unless defined $args[0];
157              
158 14 100       32 my $cost = CartCost->check( $args[0] ) ? $args[0] : CartCost->coerce(@args);
159              
160 13         4756 $orig->($self, $cost);
161             };
162              
163             =head2 cost
164              
165             Returns particular cost by position or by name.
166              
167             B Return tax value by name
168              
169             $cart->cost('tax');
170              
171             Returns value of the tax (absolute value in your currency, not percentage)
172              
173             B Return tax value by position
174              
175             $cart->cost(0);
176              
177             Returns the cost that was first applied to subtotal. By increasing the number you can retrieve other costs applied.
178              
179             =cut
180              
181             sub cost {
182 24     24 1 5266 my ( $self, $loc ) = @_;
183 24         25 my ( $cost, $ret );
184              
185 24 100       36 if ( defined $loc ) {
186 23 100       96 if ( $loc =~ /^\d+$/ ) {
    100          
187              
188             # cost by position
189 11         33 $cost = $self->cost_get($loc);
190             }
191             elsif ( $loc =~ /\S/ ) {
192              
193             # cost by name
194 11         26 for my $c ( $self->get_costs ) {
195 18 100       668 if ( $c->name eq $loc ) {
196 10         16 $cost = $c;
197             }
198             }
199             }
200             }
201             else {
202 1         17 croak "Either position or name required as argument to cost";
203             }
204              
205 23 100       897 if ( defined $cost ) {
206             # calculate total in order to reset all costs
207 20         37 $self->total;
208             }
209             else {
210 3         31 croak "Bad argument to cost: " . $loc;
211             }
212              
213 20         412 return $cost->current_amount;
214             }
215              
216             1;