File Coverage

blib/lib/Interchange6/Schema/Result/PriceModifier.pm
Criterion Covered Total %
statement 13 13 100.0
branch 4 4 100.0
condition n/a
subroutine 4 4 100.0
pod 2 2 100.0
total 23 23 100.0


line stmt bran cond sub pod time code
1 2     2   1266 use utf8;
  2         6  
  2         14  
2              
3             package Interchange6::Schema::Result::PriceModifier;
4              
5             =head1 NAME
6              
7             Interchange6::Schema::Result::PriceModifier
8              
9             =head1 DESCRIPTION
10              
11             Use cases:
12              
13             =over
14              
15             =item * group pricing based on L<roles|Interchange6::Schema::Result::Role>
16              
17             =item * tier pricing (volume discounts)
18              
19             =item * promotion/action pricing using L</start_date> and L</end_date>
20              
21             =back
22              
23             =cut
24              
25             use Interchange6::Schema::Candy
26 2     2   117 -components => [qw(InflateColumn::DateTime Helper::Row::OnColumnChange)];
  2         6  
  2         16  
27              
28             =head1 ACCESSORS
29              
30             =head2 price_modifiers_id
31              
32             Primary key.
33              
34             =cut
35              
36             primary_column price_modifiers_id => {
37             data_type => "integer",
38             is_auto_increment => 1,
39             };
40              
41             =head2 sku
42              
43             FK on L<Interchange6::Schema::Result::Product/sku>.
44              
45             =cut
46              
47             column sku =>
48             { data_type => "varchar", size => 64 };
49              
50             =head2 quantity
51              
52             Minimum quantity at which price modifier applies (tier pricing).
53              
54             Defaults to 0.
55              
56             =cut
57              
58             column quantity =>
59             { data_type => "integer", default_value => 0 };
60              
61             =head2 roles_id
62              
63             FK on L<Interchange6::Schema::Result::Role/roles_id>.
64              
65             Can be used for role-based pricing.
66              
67             Is nullable.
68              
69             =cut
70              
71             column roles_id =>
72             { data_type => "integer", is_nullable => 1 };
73              
74             =head2 price
75              
76             Price.
77              
78             =cut
79              
80             column price => {
81             data_type => "numeric",
82             size => [ 21, 3 ],
83             };
84              
85             =head2 discount
86              
87             Percent rate of discount. This is an alternative to setting L</price> directly.
88              
89             B<NOTE:> It is not possible to create a new C<PriceModifier> record with both
90             L</price> and </percent> set in new/insert.
91              
92             When L</discount> is set or updated the value of L</price> will be updated
93             accordingly based on the related L<Interchange6::Schema::Result::Product/price>.This is done using the method C<discount_changed>.
94              
95             If related L<Interchange6::Schema::Result::Product/price> changes then the
96             modified L</price> will be updated.
97              
98             Is nullable.
99              
100             =cut
101              
102             column discount => {
103             data_type => "numeric",
104             size => [ 7, 4 ],
105             is_nullable => 1,
106             keep_storage_value => 1
107             };
108              
109             before_column_change discount => {
110             method => 'discount_changed',
111             txn_wrap => 1,
112             };
113              
114             =head2 start_date
115              
116             The first date from which this modified price is valid.
117             Automatic inflation/deflation to/from L<DateTime>.
118              
119             Is nullable.
120              
121             =cut
122              
123             column start_date => {
124             data_type => "date",
125             is_nullable => 1,
126             };
127              
128             =head2 end_date
129              
130             The last date on which this modified price is valid.
131             Automatic inflation/deflation to/from L<DateTime>.
132              
133             Is nullable.
134              
135             =cut
136              
137             column end_date => {
138             data_type => "date",
139             is_nullable => 1,
140             };
141              
142             =head1 RELATIONS
143              
144             =head2 role
145              
146             Type: belongs_to
147              
148             Related object: L<Interchange6::Schema::Result::Role>
149              
150             =cut
151              
152             belongs_to
153             role => "Interchange6::Schema::Result::Role",
154             "roles_id", { join_type => 'left', is_deferrable => 1 };
155              
156             =head2 product
157              
158             Type: belongs_to
159              
160             Related object: L<Interchange6::Schema::Result::Product>
161              
162             =cut
163              
164             belongs_to
165             product => "Interchange6::Schema::Result::Product",
166             "sku", { is_deferrable => 1 };
167              
168             =head1 METHODS
169              
170             =head2 insert
171              
172             Throw exception if both L</price> and L</discount> have been supplied.
173              
174             If L</discount> has been supplied then set L</price> based on related
175             <Interchange6::Schema::Result::Product/price>.
176              
177             =cut
178              
179             sub insert {
180 71     71 1 225854 my ( $self, @args ) = @_;
181              
182 71 100       1515 if ( defined $self->discount ) {
183 2 100       99 $self->throw_exception("Cannot set both price and discount")
184             if defined $self->price;
185              
186 1         35 $self->price(
187             sprintf( "%.2f",
188             $self->product->price -
189             ( $self->product->price * $self->discount / 100 ) )
190             );
191             }
192              
193 70         10568 $self->next::method(@args);
194             }
195              
196             =head2 discount_changed
197              
198             Called when L</discount> is updated.
199              
200             =cut
201              
202             sub discount_changed {
203 1     1 1 2298 my ( $self, $old_value, $new_value ) = @_;
204              
205 1         23 $self->price(
206             sprintf( "%.2f",
207             $self->product->price -
208             ( $self->product->price * $new_value / 100 ) )
209             );
210             }
211              
212             1;