move cart access from bse.variables to the request object
[bse.git] / site / cgi-bin / modules / BSE / Cart.pm
CommitLineData
11af7272
TC
1package BSE::Cart;
2use strict;
3use Scalar::Util;
4
5our $VERSION = "1.000";
6
7=head1 NAME
8
9BSE::Cart - abstraction for the BSE cart.
10
11=head1 SYNOPSIS
12
13 use BSE::Cart;
14 my $cart = BSE::Cart->new($req);
15
16 my $items = $cart->items;
17 my $products = $cart->products;
18
19=head1 DESCRIPTION
20
21This class provides a simple abstraction for access to the BSE
22shopping cart.
23
24This is intended for use in templates, but may be expanded further.
25
26=head1 METHODS
27
28=over
29
30=item new()
31
32Create a new cart object based on the session.
33
34=cut
35
36sub new {
37 my ($class, $req) = @_;
38
39 my $self = bless
40 {
41 products => {},
42 req => $req,
43 }, $class;
44 Scalar::Util::weaken($self->{req});
45 my $items = $req->session->{cart} || [];
46 my $myself = $self;
47 Scalar::Util::weaken($myself);
48 my $index = 0;
49 $self->{items} =
50 [
51 map
52 {
53 my $myself = $self;
54 my $myindex = $index++;
55 my %item = %$_;
56 my $id = $item{productId};
57 my $options = $item{options};
58 $item{product} = sub { $myself->_product($id) };
59 $item{extended} = $item{price} * $item{units};
60 $item{link} = sub { $myself->_product_link($id) };
61 $item{option_list} = sub { $myself->_option_list($myindex) };
62 $item{option_text} = sub { $myself->_option_text($myindex) };
63
64 my $session_id = $item{session_id};
65 $item{session} = sub { $myself->_item_session($session_id) };
66
67 \%item;
68 } @$items
69 ];
70
71 return $self;
72}
73
74=item items()
75
76Return an array reference of cart items.
77
78=cut
79
80sub items {
81 return $_[0]{items};
82}
83
84=item products().
85
86Return an array reference of products in the cart, corresponding to
87the array reference returned by items().
88
89=cut
90
91sub products {
92 my $self = shift;
93 return [ map $self->_product($_->{productId}), @{$self->items} ];
94}
95
96=item total_cost
97
98Return the total cost of the items in the cart.
99
100=cut
101
102sub total_cost {
103 my ($self) = @_;
104
105 my $total_cost = 0;
106 for my $item (@{$self->items}) {
107 $total_cost += $item->{extended};
108 }
109
110 return $total_cost;
111}
112
113=item total_units
114
115Return the total number of units in the cart.
116
117=cut
118
119sub total_units {
120 my ($self) = @_;
121
122 my $total_units = 0;
123 for my $item (@{$self->items}) {
124 $total_units += $item->{units};
125 }
126
127 return $total_units;
128}
129
130=item total
131
132Total of items in the cart and any custom extras.
133
134=cut
135
136=back
137
138=head2 Item Members
139
140=over
141
142=item product
143
144Returns the product for that line item.
145
146=cut
147
148sub _product {
149 my ($self, $id) = @_;
150
151 my $product = $self->{products}{$id};
152 unless ($product) {
153 require Products;
154 $product = Products->getByPkey($id)
155 or die "No product $id\n";
156 # FIXME
157 if ($product->generator ne "Generate::Product") {
158 require BSE::TB::Seminars;
159 $product = BSE::TB::Seminars->getByPkey($id)
160 or die "Not a product, not a seminar $id\n";
161 }
162
163 $self->{products}{$id} = $product;
164 }
165 return $product;
166
167}
168
169=item extended
170
171The extended price for the item.
172
173=item link
174
175A link to the product.
176
177=cut
178
179sub _product_link {
180 my ($self, $id) = @_;
181
182 my $product = $self->_product($id);
183 my $link = $product->link;
184 unless ($link =~ /^\w+:/) {
185 $link = BSE::Cfg->single->entryErr("site", "url") . $link;
186 }
187
188 return $link;
189}
190
191=item option_list
192
193Return a list of options for the item, each with:
194
195=over
196
197=item *
198
199id, name - the identifier for the option
200
201=item *
202
203value - the value of the option.
204
205=item *
206
207desc - the description of the option
208
209=item *
210
211display - display of the option value
212
213=back
214
215=cut
216
217sub _option_list {
218 my ($self, $index) = @_;
219
220 my $item = $self->items()->[$index];
221 my $product = $self->_product($item->{productId});
222
223 return [ $product->option_descs(BSE::Cfg->single, $item->{options}) ];
224}
225
226=item option_text
227
228Display text for options for the item.
229
230=cut
231
232sub _option_text {
233 my ($self, $index) = @_;
234
235 my $options = $self->_option_list($index);
236 return join(", ", map "$_->{desc}: $_->{display}", @$options);
237}
238
239=item session
240
241The session object of the seminar session
242
243=cut
244
245sub _item_session {
246 my ($self, $id) = @_;
247
248 $id or return;
249 my $session = $self->{sessions}{$id};
250 unless ($session) {
251 require BSE::TB::SeminarSessions;
252 $session = BSE::TB::SeminarSessions->getByPkey($id);
253 $self->{sessions}{$id} = $session;
254 }
255
256 return $session;
257}
258
2591;
260
261=back
262
263=head1 AUTHOR
264
265Tony Cook <tony@develop-help.com>
266
267=cut