File Coverage

blib/lib/Interchange6/Role/Costs.pm
Criterion Covered Total %
statement 54 54 100.0
branch 22 22 100.0
condition n/a
subroutine 11 11 100.0
pod 2 2 100.0
total 89 89 100.0


line stmt bran cond sub pod time code
1             # Interchange6::Role::Costs - Interchange6 costs role for carts and products
2              
3             package Interchange6::Role::Costs;
4              
5 4     4   13463 use Interchange6::Cart::Cost;
  4         14  
  4         171  
6 4     4   39 use Scalar::Util 'blessed';
  4         7  
  4         220  
7 4     4   21 use Moo::Role;
  4         7  
  4         38  
8 4     4   1973 use MooseX::CoverableModifiers;
  4         6646  
  4         35  
9 4     4   1115 use MooX::HandlesVia;
  4         693  
  4         33  
10 4     4   388 use Types::Standard qw/ArrayRef InstanceOf Num/;
  4         7  
  4         51  
11              
12 4     4   3777 use namespace::clean;
  4         9  
  4         67  
13              
14             =head1 ATTRIBUTES
15              
16             =head2 costs
17              
18             Holds an array reference of L items.
19              
20             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.
21              
22             =cut
23              
24             has costs => (
25             is => 'ro',
26             isa => ArrayRef [ InstanceOf ['Interchange::Cart::Cost'] ],
27             default => sub { [] },
28             handles_via => 'Array',
29             handles => {
30             clear_costs => 'clear',
31             cost_get => 'get',
32             cost_set => 'set',
33             cost_count => 'count',
34             cost_push => 'push',
35             get_costs => 'elements',
36             },
37             init_arg => undef,
38             );
39              
40             after 'clear_costs', 'cost_set', 'cost_push' => sub {
41 16     16   10150 shift->clear_total;
42             };
43              
44             =head2 total
45              
46             Returns the sum of the objects L added to its C.
47              
48             =cut
49              
50             has total => (
51             is => 'lazy',
52             isa => Num,
53             clearer => 1,
54             predicate => 1,
55             );
56              
57             sub _build_total {
58 74     74   14197 my $self = shift;
59              
60 74         238 my @costs = $self->get_costs;
61 74         9329 my $subtotal = $self->subtotal;
62              
63 74         2856 my $sum = 0;
64 74         216 foreach my $i ( 0 .. $#costs ) {
65              
66 27 100       77 if ( $costs[$i]->relative ) {
67 14         307 $costs[$i]->set_current_amount( $subtotal * $costs[$i]->amount );
68             }
69             else {
70 13         220 $costs[$i]->set_current_amount( $costs[$i]->amount );
71             }
72              
73 27 100       742 if ( $costs[$i]->compound ) {
    100          
74 11         41 $subtotal += $costs[$i]->current_amount;
75             }
76             elsif ( !$costs[$i]->inclusive ) {
77 11         35 $sum += $costs[$i]->current_amount;
78             }
79             }
80              
81 74         1803 return sprintf( "%.2f", $subtotal + $sum );
82             }
83              
84             =head1 METHODS
85              
86             =head2 clear_costs
87              
88             Removes all the costs previously applied (using apply_cost). Used typically if you have free shipping or something similar, you can clear the costs.
89              
90             This method also calls L.
91              
92             =head2 clear_total
93              
94             Clears L.
95              
96             =head2 cost_get($index)
97              
98             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.
99              
100             =head2 cost_count
101              
102             Returns the number of cost elements for the object.
103              
104             =head2 cost_push($cost)
105              
106             Like Perl's normal C this adds the supplied L
107             to L.
108              
109             This method also calls L.
110              
111             =head2 get_costs
112              
113             Returns all of the cost elements for the object as an array (not an arrayref).
114              
115             =head2 cost_set($index, $cost)
116              
117             Sets the cost at C<$index> to <$cost>.
118              
119             This method also calls L.
120              
121             =head2 has_total
122              
123             predicate on L.
124              
125             =head2 apply_cost
126              
127             Apply cost to object. L is a generic method typicaly used for taxes, discounts, coupons, gift certificates, etc.
128              
129             The cost is added using L.
130              
131             B Absolute cost
132              
133             Uses absolute value for amount. Amount 5 is 5 units of currency used (i.e. $5).
134              
135             $cart->apply_cost(amount => 5, name => 'shipping', label => 'Shipping');
136              
137             B Relative cost
138              
139             Uses percentage instead of value for amount. Relative is a boolean value (0/1).
140              
141             Add 19% German VAT:
142              
143             $cart->apply_cost(
144             amount => 0.19, name => 'tax', label => 'VAT', relative => 1
145             );
146              
147             Add 10% discount (negative amount):
148              
149             $cart->apply_cost(
150             amount => -0.1, name => 'discount', label => 'Discount', relative => 1
151             );
152              
153              
154             B Inclusive cost
155              
156             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).
157              
158             $cart->apply_cost(amount => 0.19, name => 'tax', label => 'Sales Tax', relative => 1, inclusive => 1);
159              
160             =cut
161              
162             sub apply_cost {
163 14     14 1 14001 my $self = shift;
164 14         25 my $cost = $_[0];
165              
166 14 100       75 die "argument to apply_cost undefined" unless defined($cost);
167              
168 13 100       47 if ( blessed($cost) ) {
169 2 100       26 die( "Supplied cost not an Interchange6::Cart::Cost : " . ref($cost) )
170             unless $cost->isa('Interchange6::Cart::Cost');
171             }
172             else {
173 11         256 $cost = Interchange6::Cart::Cost->new(@_);
174             }
175              
176 12         7761 $self->cost_push($cost);
177             }
178              
179             =head2 cost
180              
181             Returns particular cost by position or by name.
182              
183             B Return tax value by name
184              
185             $cart->cost('tax');
186              
187             Returns value of the tax (absolute value in your currency, not percentage)
188              
189             B Return tax value by position
190              
191             $cart->cost(0);
192              
193             Returns the cost that was first applied to subtotal. By increasing the number you can retrieve other costs applied.
194              
195             =cut
196              
197             sub cost {
198 24     24 1 6084 my ( $self, $loc ) = @_;
199 24         36 my ( $cost, $ret );
200              
201 24 100       60 if ( defined $loc ) {
202 23 100       156 if ( $loc =~ /^\d+$/ ) {
    100          
203              
204             # cost by position
205 11         45 $cost = $self->cost_get($loc);
206             }
207             elsif ( $loc =~ /\S/ ) {
208              
209             # cost by name
210 11         53 for my $c ( $self->get_costs ) {
211 18 100       1090 if ( $c->name eq $loc ) {
212 10         22 $cost = $c;
213             }
214             }
215             }
216             }
217             else {
218 1         11 die "Either position or name required as argument to cost";
219             }
220              
221 23 100       1279 if ( defined $cost ) {
222             # calculate total in order to reset all costs
223 20         72 $self->total;
224             }
225             else {
226 3         22 die "Bad argument to cost: " . $loc;
227             }
228              
229 20         627 return $cost->current_amount;
230             }
231              
232             1;