@@ -874,7 +874,7 @@ discard block |
||
874 | 874 | * Deletes ALL children of the passed line item |
875 | 875 | * |
876 | 876 | * @param EE_Line_Item $parent_line_item |
877 | - * @return bool |
|
877 | + * @return integer |
|
878 | 878 | * @throws \EE_Error |
879 | 879 | */ |
880 | 880 | public static function delete_all_child_items(EE_Line_Item $parent_line_item) |
@@ -1138,6 +1138,7 @@ discard block |
||
1138 | 1138 | * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
1139 | 1139 | * @param string $line_item_type one of the EEM_Line_Item constants |
1140 | 1140 | * @param string | NULL $obj_type object model class name (minus prefix) or NULL to ignore object type when searching |
1141 | + * @param string $obj_type |
|
1141 | 1142 | * @return EE_Line_Item[] |
1142 | 1143 | */ |
1143 | 1144 | protected static function _get_descendants_by_type_and_object_type( |
@@ -1,5 +1,5 @@ discard block |
||
1 | 1 | <?php if (!defined('EVENT_ESPRESSO_VERSION')) { |
2 | - exit('No direct script access allowed'); |
|
2 | + exit('No direct script access allowed'); |
|
3 | 3 | } |
4 | 4 | |
5 | 5 | /** |
@@ -23,1703 +23,1703 @@ discard block |
||
23 | 23 | class EEH_Line_Item |
24 | 24 | { |
25 | 25 | |
26 | - //other functions: cancel ticket purchase |
|
27 | - //delete ticket purchase |
|
28 | - //add promotion |
|
29 | - |
|
30 | - |
|
31 | - /** |
|
32 | - * Adds a simple item (unrelated to any other model object) to the provided PARENT line item. |
|
33 | - * Does NOT automatically re-calculate the line item totals or update the related transaction. |
|
34 | - * You should call recalculate_total_including_taxes() on the grant total line item after this |
|
35 | - * to update the subtotals, and EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
36 | - * to keep the registration final prices in-sync with the transaction's total. |
|
37 | - * |
|
38 | - * @param EE_Line_Item $parent_line_item |
|
39 | - * @param string $name |
|
40 | - * @param float $unit_price |
|
41 | - * @param string $description |
|
42 | - * @param int $quantity |
|
43 | - * @param boolean $taxable |
|
44 | - * @param boolean $code if set to a value, ensures there is only one line item with that code |
|
45 | - * @return boolean success |
|
46 | - * @throws \EE_Error |
|
47 | - */ |
|
48 | - public static function add_unrelated_item(EE_Line_Item $parent_line_item, $name, $unit_price, $description = '', $quantity = 1, $taxable = FALSE, $code = NULL) |
|
49 | - { |
|
50 | - $items_subtotal = self::get_pre_tax_subtotal($parent_line_item); |
|
51 | - $line_item = EE_Line_Item::new_instance(array( |
|
52 | - 'LIN_name' => $name, |
|
53 | - 'LIN_desc' => $description, |
|
54 | - 'LIN_unit_price' => $unit_price, |
|
55 | - 'LIN_quantity' => $quantity, |
|
56 | - 'LIN_percent' => null, |
|
57 | - 'LIN_is_taxable' => $taxable, |
|
58 | - 'LIN_order' => $items_subtotal instanceof EE_Line_Item ? count($items_subtotal->children()) : 0, |
|
59 | - 'LIN_total' => (float)$unit_price * (int)$quantity, |
|
60 | - 'LIN_type' => EEM_Line_Item::type_line_item, |
|
61 | - 'LIN_code' => $code, |
|
62 | - )); |
|
63 | - $line_item = apply_filters( |
|
64 | - 'FHEE__EEH_Line_Item__add_unrelated_item__line_item', |
|
65 | - $line_item, |
|
66 | - $parent_line_item |
|
67 | - ); |
|
68 | - return self::add_item($parent_line_item, $line_item); |
|
69 | - } |
|
70 | - |
|
71 | - |
|
72 | - /** |
|
73 | - * Adds a simple item ( unrelated to any other model object) to the total line item, |
|
74 | - * in the correct spot in the line item tree. Automatically |
|
75 | - * re-calculates the line item totals and updates the related transaction. But |
|
76 | - * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
77 | - * should probably change because of this). |
|
78 | - * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
79 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
80 | - * |
|
81 | - * @param EE_Line_Item $parent_line_item |
|
82 | - * @param string $name |
|
83 | - * @param float $percentage_amount |
|
84 | - * @param string $description |
|
85 | - * @param boolean $taxable |
|
86 | - * @return boolean success |
|
87 | - * @throws \EE_Error |
|
88 | - */ |
|
89 | - public static function add_percentage_based_item(EE_Line_Item $parent_line_item, $name, $percentage_amount, $description = '', $taxable = FALSE) |
|
90 | - { |
|
91 | - $line_item = EE_Line_Item::new_instance(array( |
|
92 | - 'LIN_name' => $name, |
|
93 | - 'LIN_desc' => $description, |
|
94 | - 'LIN_unit_price' => 0, |
|
95 | - 'LIN_percent' => $percentage_amount, |
|
96 | - 'LIN_quantity' => 1, |
|
97 | - 'LIN_is_taxable' => $taxable, |
|
98 | - 'LIN_total' => (float)($percentage_amount * ($parent_line_item->total() / 100)), |
|
99 | - 'LIN_type' => EEM_Line_Item::type_line_item, |
|
100 | - 'LIN_parent' => $parent_line_item->ID() |
|
101 | - )); |
|
102 | - $line_item = apply_filters( |
|
103 | - 'FHEE__EEH_Line_Item__add_percentage_based_item__line_item', |
|
104 | - $line_item |
|
105 | - ); |
|
106 | - return $parent_line_item->add_child_line_item($line_item, false); |
|
107 | - } |
|
108 | - |
|
109 | - |
|
110 | - /** |
|
111 | - * Returns the new line item created by adding a purchase of the ticket |
|
112 | - * ensures that ticket line item is saved, and that cart total has been recalculated. |
|
113 | - * If this ticket has already been purchased, just increments its count. |
|
114 | - * Automatically re-calculates the line item totals and updates the related transaction. But |
|
115 | - * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
116 | - * should probably change because of this). |
|
117 | - * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
118 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
119 | - * |
|
120 | - * @param EE_Line_Item $total_line_item grand total line item of type EEM_Line_Item::type_total |
|
121 | - * @param EE_Ticket $ticket |
|
122 | - * @param int $qty |
|
123 | - * @return \EE_Line_Item |
|
124 | - * @throws \EE_Error |
|
125 | - */ |
|
126 | - public static function add_ticket_purchase(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
127 | - { |
|
128 | - if (!$total_line_item instanceof EE_Line_Item || !$total_line_item->is_total()) { |
|
129 | - throw new EE_Error(sprintf(__('A valid line item total is required in order to add tickets. A line item of type "%s" was passed.', 'event_espresso'), $ticket->ID(), $total_line_item->ID())); |
|
130 | - } |
|
131 | - // either increment the qty for an existing ticket |
|
132 | - $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty); |
|
133 | - // or add a new one |
|
134 | - if (!$line_item instanceof EE_Line_Item) { |
|
135 | - $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty); |
|
136 | - } |
|
137 | - $total_line_item->recalculate_total_including_taxes(); |
|
138 | - return $line_item; |
|
139 | - } |
|
140 | - |
|
141 | - |
|
142 | - /** |
|
143 | - * Returns the new line item created by adding a purchase of the ticket |
|
144 | - * @param \EE_Line_Item $total_line_item |
|
145 | - * @param EE_Ticket $ticket |
|
146 | - * @param int $qty |
|
147 | - * @return \EE_Line_Item |
|
148 | - * @throws \EE_Error |
|
149 | - */ |
|
150 | - public static function increment_ticket_qty_if_already_in_cart(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
151 | - { |
|
152 | - $line_item = null; |
|
153 | - if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) { |
|
154 | - $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item); |
|
155 | - foreach ((array)$ticket_line_items as $ticket_line_item) { |
|
156 | - if ( |
|
157 | - $ticket_line_item instanceof EE_Line_Item |
|
158 | - && (int)$ticket_line_item->OBJ_ID() === (int)$ticket->ID() |
|
159 | - ) { |
|
160 | - $line_item = $ticket_line_item; |
|
161 | - break; |
|
162 | - } |
|
163 | - } |
|
164 | - } |
|
165 | - if ($line_item instanceof EE_Line_Item) { |
|
166 | - EEH_Line_Item::increment_quantity($line_item, $qty); |
|
167 | - return $line_item; |
|
168 | - } |
|
169 | - return null; |
|
170 | - } |
|
171 | - |
|
172 | - |
|
173 | - /** |
|
174 | - * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
175 | - * Does NOT save or recalculate other line items totals |
|
176 | - * |
|
177 | - * @param EE_Line_Item $line_item |
|
178 | - * @param int $qty |
|
179 | - * @return void |
|
180 | - * @throws \EE_Error |
|
181 | - */ |
|
182 | - public static function increment_quantity(EE_Line_Item $line_item, $qty = 1) |
|
183 | - { |
|
184 | - if (!$line_item->is_percent()) { |
|
185 | - $qty += $line_item->quantity(); |
|
186 | - $line_item->set_quantity($qty); |
|
187 | - $line_item->set_total($line_item->unit_price() * $qty); |
|
188 | - $line_item->save(); |
|
189 | - } |
|
190 | - foreach ($line_item->children() as $child) { |
|
191 | - if ($child->is_sub_line_item()) { |
|
192 | - EEH_Line_Item::update_quantity($child, $qty); |
|
193 | - } |
|
194 | - } |
|
195 | - } |
|
196 | - |
|
197 | - |
|
198 | - /** |
|
199 | - * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
200 | - * Does NOT save or recalculate other line items totals |
|
201 | - * |
|
202 | - * @param EE_Line_Item $line_item |
|
203 | - * @param int $qty |
|
204 | - * @return void |
|
205 | - * @throws \EE_Error |
|
206 | - */ |
|
207 | - public static function decrement_quantity(EE_Line_Item $line_item, $qty = 1) |
|
208 | - { |
|
209 | - if (!$line_item->is_percent()) { |
|
210 | - $qty = $line_item->quantity() - $qty; |
|
211 | - $qty = max($qty, 0); |
|
212 | - $line_item->set_quantity($qty); |
|
213 | - $line_item->set_total($line_item->unit_price() * $qty); |
|
214 | - $line_item->save(); |
|
215 | - } |
|
216 | - foreach ($line_item->children() as $child) { |
|
217 | - if ($child->is_sub_line_item()) { |
|
218 | - EEH_Line_Item::update_quantity($child, $qty); |
|
219 | - } |
|
220 | - } |
|
221 | - } |
|
222 | - |
|
223 | - |
|
224 | - /** |
|
225 | - * Updates the line item and its children's quantities to the specified number. |
|
226 | - * Does NOT save them or recalculate totals. |
|
227 | - * |
|
228 | - * @param EE_Line_Item $line_item |
|
229 | - * @param int $new_quantity |
|
230 | - * @throws \EE_Error |
|
231 | - */ |
|
232 | - public static function update_quantity(EE_Line_Item $line_item, $new_quantity) |
|
233 | - { |
|
234 | - if (!$line_item->is_percent()) { |
|
235 | - $line_item->set_quantity($new_quantity); |
|
236 | - $line_item->set_total($line_item->unit_price() * $new_quantity); |
|
237 | - $line_item->save(); |
|
238 | - } |
|
239 | - foreach ($line_item->children() as $child) { |
|
240 | - if ($child->is_sub_line_item()) { |
|
241 | - EEH_Line_Item::update_quantity($child, $new_quantity); |
|
242 | - } |
|
243 | - } |
|
244 | - } |
|
245 | - |
|
246 | - |
|
247 | - /** |
|
248 | - * Returns the new line item created by adding a purchase of the ticket |
|
249 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
250 | - * @param EE_Ticket $ticket |
|
251 | - * @param int $qty |
|
252 | - * @return \EE_Line_Item |
|
253 | - * @throws \EE_Error |
|
254 | - */ |
|
255 | - public static function create_ticket_line_item(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
256 | - { |
|
257 | - $datetimes = $ticket->datetimes(); |
|
258 | - $first_datetime = reset($datetimes); |
|
259 | - if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) { |
|
260 | - $first_datetime_name = $first_datetime->event()->name(); |
|
261 | - } else { |
|
262 | - $first_datetime_name = __('Event', 'event_espresso'); |
|
263 | - } |
|
264 | - $event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name); |
|
265 | - // get event subtotal line |
|
266 | - $events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket); |
|
267 | - // add $ticket to cart |
|
268 | - $line_item = EE_Line_Item::new_instance(array( |
|
269 | - 'LIN_name' => $ticket->name(), |
|
270 | - 'LIN_desc' => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event, |
|
271 | - 'LIN_unit_price' => $ticket->price(), |
|
272 | - 'LIN_quantity' => $qty, |
|
273 | - 'LIN_is_taxable' => $ticket->taxable(), |
|
274 | - 'LIN_order' => count($events_sub_total->children()), |
|
275 | - 'LIN_total' => $ticket->price() * $qty, |
|
276 | - 'LIN_type' => EEM_Line_Item::type_line_item, |
|
277 | - 'OBJ_ID' => $ticket->ID(), |
|
278 | - 'OBJ_type' => 'Ticket' |
|
279 | - )); |
|
280 | - $line_item = apply_filters( |
|
281 | - 'FHEE__EEH_Line_Item__create_ticket_line_item__line_item', |
|
282 | - $line_item |
|
283 | - ); |
|
284 | - $events_sub_total->add_child_line_item($line_item); |
|
285 | - //now add the sub-line items |
|
286 | - $running_total_for_ticket = 0; |
|
287 | - foreach ($ticket->prices(array('order_by' => array('PRC_order' => 'ASC'))) as $price) { |
|
288 | - $sign = $price->is_discount() ? -1 : 1; |
|
289 | - $price_total = $price->is_percent() |
|
290 | - ? $running_total_for_ticket * $price->amount() / 100 |
|
291 | - : $price->amount() * $qty; |
|
292 | - $sub_line_item = EE_Line_Item::new_instance(array( |
|
293 | - 'LIN_name' => $price->name(), |
|
294 | - 'LIN_desc' => $price->desc(), |
|
295 | - 'LIN_quantity' => $price->is_percent() ? null : $qty, |
|
296 | - 'LIN_is_taxable' => false, |
|
297 | - 'LIN_order' => $price->order(), |
|
298 | - 'LIN_total' => $sign * $price_total, |
|
299 | - 'LIN_type' => EEM_Line_Item::type_sub_line_item, |
|
300 | - 'OBJ_ID' => $price->ID(), |
|
301 | - 'OBJ_type' => 'Price' |
|
302 | - )); |
|
303 | - $sub_line_item = apply_filters( |
|
304 | - 'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item', |
|
305 | - $sub_line_item |
|
306 | - ); |
|
307 | - if ($price->is_percent()) { |
|
308 | - $sub_line_item->set_percent($sign * $price->amount()); |
|
309 | - } else { |
|
310 | - $sub_line_item->set_unit_price($sign * $price->amount()); |
|
311 | - } |
|
312 | - $running_total_for_ticket += $price_total; |
|
313 | - $line_item->add_child_line_item($sub_line_item); |
|
314 | - } |
|
315 | - return $line_item; |
|
316 | - } |
|
317 | - |
|
318 | - |
|
319 | - /** |
|
320 | - * Adds the specified item under the pre-tax-sub-total line item. Automatically |
|
321 | - * re-calculates the line item totals and updates the related transaction. But |
|
322 | - * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
323 | - * should probably change because of this). |
|
324 | - * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
325 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
326 | - * |
|
327 | - * @param EE_Line_Item $total_line_item |
|
328 | - * @param EE_Line_Item $item to be added |
|
329 | - * @return boolean |
|
330 | - * @throws \EE_Error |
|
331 | - */ |
|
332 | - public static function add_item(EE_Line_Item $total_line_item, EE_Line_Item $item) |
|
333 | - { |
|
334 | - $pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item); |
|
335 | - if ($pre_tax_subtotal instanceof EE_Line_Item) { |
|
336 | - $success = $pre_tax_subtotal->add_child_line_item($item); |
|
337 | - } else { |
|
338 | - return FALSE; |
|
339 | - } |
|
340 | - $total_line_item->recalculate_total_including_taxes(); |
|
341 | - return $success; |
|
342 | - } |
|
343 | - |
|
344 | - |
|
345 | - /** |
|
346 | - * cancels an existing ticket line item, |
|
347 | - * by decrementing it's quantity by 1 and adding a new "type_cancellation" sub-line-item. |
|
348 | - * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
349 | - * |
|
350 | - * @param EE_Line_Item $ticket_line_item |
|
351 | - * @param int $qty |
|
352 | - * @return bool success |
|
353 | - * @throws \EE_Error |
|
354 | - */ |
|
355 | - public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
356 | - { |
|
357 | - // validate incoming line_item |
|
358 | - if ($ticket_line_item->OBJ_type() !== 'Ticket') { |
|
359 | - throw new EE_Error( |
|
360 | - sprintf( |
|
361 | - __('The supplied line item must have an Object Type of "Ticket", not %1$s.', 'event_espresso'), |
|
362 | - $ticket_line_item->type() |
|
363 | - ) |
|
364 | - ); |
|
365 | - } |
|
366 | - if ($ticket_line_item->quantity() < $qty) { |
|
367 | - throw new EE_Error( |
|
368 | - sprintf( |
|
369 | - __('Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.', 'event_espresso'), |
|
370 | - $qty, |
|
371 | - $ticket_line_item->quantity() |
|
372 | - ) |
|
373 | - ); |
|
374 | - } |
|
375 | - // decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this |
|
376 | - $ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty); |
|
377 | - foreach ($ticket_line_item->children() as $child_line_item) { |
|
378 | - if ( |
|
379 | - $child_line_item->is_sub_line_item() |
|
380 | - && !$child_line_item->is_percent() |
|
381 | - && !$child_line_item->is_cancellation() |
|
382 | - ) { |
|
383 | - $child_line_item->set_quantity($child_line_item->quantity() - $qty); |
|
384 | - } |
|
385 | - } |
|
386 | - // get cancellation sub line item |
|
387 | - $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
388 | - $ticket_line_item, |
|
389 | - EEM_Line_Item::type_cancellation |
|
390 | - ); |
|
391 | - $cancellation_line_item = reset($cancellation_line_item); |
|
392 | - // verify that this ticket was indeed previously cancelled |
|
393 | - if ($cancellation_line_item instanceof EE_Line_Item) { |
|
394 | - // increment cancelled quantity |
|
395 | - $cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty); |
|
396 | - } else { |
|
397 | - // create cancellation sub line item |
|
398 | - $cancellation_line_item = EE_Line_Item::new_instance(array( |
|
399 | - 'LIN_name' => __('Cancellation', 'event_espresso'), |
|
400 | - 'LIN_desc' => sprintf( |
|
401 | - _x('Cancelled %1$s : %2$s', 'Cancelled Ticket Name : 2015-01-01 11:11', 'event_espresso'), |
|
402 | - $ticket_line_item->name(), |
|
403 | - current_time(get_option('date_format') . ' ' . get_option('time_format')) |
|
404 | - ), |
|
405 | - 'LIN_unit_price' => 0, // $ticket_line_item->unit_price() |
|
406 | - 'LIN_quantity' => $qty, |
|
407 | - 'LIN_is_taxable' => $ticket_line_item->is_taxable(), |
|
408 | - 'LIN_order' => count($ticket_line_item->children()), |
|
409 | - 'LIN_total' => 0, // $ticket_line_item->unit_price() |
|
410 | - 'LIN_type' => EEM_Line_Item::type_cancellation, |
|
411 | - )); |
|
412 | - $ticket_line_item->add_child_line_item($cancellation_line_item); |
|
413 | - } |
|
414 | - if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
415 | - // decrement parent line item quantity |
|
416 | - $event_line_item = $ticket_line_item->parent(); |
|
417 | - if ($event_line_item instanceof EE_Line_Item && $event_line_item->OBJ_type() === 'Event') { |
|
418 | - $event_line_item->set_quantity($event_line_item->quantity() - $qty); |
|
419 | - $event_line_item->save(); |
|
420 | - } |
|
421 | - EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
422 | - return true; |
|
423 | - } |
|
424 | - return false; |
|
425 | - } |
|
426 | - |
|
427 | - |
|
428 | - /** |
|
429 | - * reinstates (un-cancels?) a previously canceled ticket line item, |
|
430 | - * by incrementing it's quantity by 1, and decrementing it's "type_cancellation" sub-line-item. |
|
431 | - * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
432 | - * |
|
433 | - * @param EE_Line_Item $ticket_line_item |
|
434 | - * @param int $qty |
|
435 | - * @return bool success |
|
436 | - * @throws \EE_Error |
|
437 | - */ |
|
438 | - public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
439 | - { |
|
440 | - // validate incoming line_item |
|
441 | - if ($ticket_line_item->OBJ_type() !== 'Ticket') { |
|
442 | - throw new EE_Error( |
|
443 | - sprintf( |
|
444 | - __('The supplied line item must have an Object Type of "Ticket", not %1$s.', 'event_espresso'), |
|
445 | - $ticket_line_item->type() |
|
446 | - ) |
|
447 | - ); |
|
448 | - } |
|
449 | - // get cancellation sub line item |
|
450 | - $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
451 | - $ticket_line_item, |
|
452 | - EEM_Line_Item::type_cancellation |
|
453 | - ); |
|
454 | - $cancellation_line_item = reset($cancellation_line_item); |
|
455 | - // verify that this ticket was indeed previously cancelled |
|
456 | - if (!$cancellation_line_item instanceof EE_Line_Item) { |
|
457 | - return false; |
|
458 | - } |
|
459 | - if ($cancellation_line_item->quantity() > $qty) { |
|
460 | - // decrement cancelled quantity |
|
461 | - $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
462 | - } else if ($cancellation_line_item->quantity() == $qty) { |
|
463 | - // decrement cancelled quantity in case anyone still has the object kicking around |
|
464 | - $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
465 | - // delete because quantity will end up as 0 |
|
466 | - $cancellation_line_item->delete(); |
|
467 | - // and attempt to destroy the object, |
|
468 | - // even though PHP won't actually destroy it until it needs the memory |
|
469 | - unset($cancellation_line_item); |
|
470 | - } else { |
|
471 | - // what ?!?! negative quantity ?!?! |
|
472 | - throw new EE_Error( |
|
473 | - sprintf( |
|
474 | - __('Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.', |
|
475 | - 'event_espresso'), |
|
476 | - $qty, |
|
477 | - $cancellation_line_item->quantity() |
|
478 | - ) |
|
479 | - ); |
|
480 | - } |
|
481 | - // increment ticket quantity |
|
482 | - $ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty); |
|
483 | - if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
484 | - // increment parent line item quantity |
|
485 | - $event_line_item = $ticket_line_item->parent(); |
|
486 | - if ($event_line_item instanceof EE_Line_Item && $event_line_item->OBJ_type() === 'Event') { |
|
487 | - $event_line_item->set_quantity($event_line_item->quantity() + $qty); |
|
488 | - } |
|
489 | - EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
490 | - return true; |
|
491 | - } |
|
492 | - return false; |
|
493 | - } |
|
494 | - |
|
495 | - |
|
496 | - /** |
|
497 | - * calls EEH_Line_Item::find_transaction_grand_total_for_line_item() |
|
498 | - * then EE_Line_Item::recalculate_total_including_taxes() on the result |
|
499 | - * |
|
500 | - * @param EE_Line_Item $line_item |
|
501 | - * @return \EE_Line_Item |
|
502 | - */ |
|
503 | - public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item) |
|
504 | - { |
|
505 | - $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item); |
|
506 | - return $grand_total_line_item->recalculate_total_including_taxes(); |
|
507 | - } |
|
508 | - |
|
509 | - |
|
510 | - /** |
|
511 | - * Gets the line item which contains the subtotal of all the items |
|
512 | - * |
|
513 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
514 | - * @return \EE_Line_Item |
|
515 | - * @throws \EE_Error |
|
516 | - */ |
|
517 | - public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item) |
|
518 | - { |
|
519 | - $pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal'); |
|
520 | - return $pre_tax_subtotal instanceof EE_Line_Item |
|
521 | - ? $pre_tax_subtotal |
|
522 | - : self::create_pre_tax_subtotal($total_line_item); |
|
523 | - } |
|
524 | - |
|
525 | - |
|
526 | - /** |
|
527 | - * Gets the line item for the taxes subtotal |
|
528 | - * |
|
529 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
530 | - * @return \EE_Line_Item |
|
531 | - * @throws \EE_Error |
|
532 | - */ |
|
533 | - public static function get_taxes_subtotal(EE_Line_Item $total_line_item) |
|
534 | - { |
|
535 | - $taxes = $total_line_item->get_child_line_item('taxes'); |
|
536 | - return $taxes ? $taxes : self::create_taxes_subtotal($total_line_item); |
|
537 | - } |
|
538 | - |
|
539 | - |
|
540 | - /** |
|
541 | - * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object |
|
542 | - * |
|
543 | - * @param EE_Line_Item $line_item |
|
544 | - * @param EE_Transaction $transaction |
|
545 | - * @return void |
|
546 | - * @throws \EE_Error |
|
547 | - */ |
|
548 | - public static function set_TXN_ID(EE_Line_Item $line_item, $transaction = NULL) |
|
549 | - { |
|
550 | - if ($transaction) { |
|
551 | - /** @type EEM_Transaction $EEM_Transaction */ |
|
552 | - $EEM_Transaction = EE_Registry::instance()->load_model('Transaction'); |
|
553 | - $TXN_ID = $EEM_Transaction->ensure_is_ID($transaction); |
|
554 | - $line_item->set_TXN_ID($TXN_ID); |
|
555 | - } |
|
556 | - } |
|
557 | - |
|
558 | - |
|
559 | - /** |
|
560 | - * Creates a new default total line item for the transaction, |
|
561 | - * and its tickets subtotal and taxes subtotal line items (and adds the |
|
562 | - * existing taxes as children of the taxes subtotal line item) |
|
563 | - * |
|
564 | - * @param EE_Transaction $transaction |
|
565 | - * @return \EE_Line_Item of type total |
|
566 | - * @throws \EE_Error |
|
567 | - */ |
|
568 | - public static function create_total_line_item($transaction = NULL) |
|
569 | - { |
|
570 | - $total_line_item = EE_Line_Item::new_instance(array( |
|
571 | - 'LIN_code' => 'total', |
|
572 | - 'LIN_name' => __('Grand Total', 'event_espresso'), |
|
573 | - 'LIN_type' => EEM_Line_Item::type_total, |
|
574 | - 'OBJ_type' => 'Transaction' |
|
575 | - )); |
|
576 | - $total_line_item = apply_filters( |
|
577 | - 'FHEE__EEH_Line_Item__create_total_line_item__total_line_item', |
|
578 | - $total_line_item |
|
579 | - ); |
|
580 | - self::set_TXN_ID($total_line_item, $transaction); |
|
581 | - self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
582 | - self::create_taxes_subtotal($total_line_item, $transaction); |
|
583 | - return $total_line_item; |
|
584 | - } |
|
585 | - |
|
586 | - |
|
587 | - /** |
|
588 | - * Creates a default items subtotal line item |
|
589 | - * |
|
590 | - * @param EE_Line_Item $total_line_item |
|
591 | - * @param EE_Transaction $transaction |
|
592 | - * @return EE_Line_Item |
|
593 | - * @throws \EE_Error |
|
594 | - */ |
|
595 | - protected static function create_pre_tax_subtotal(EE_Line_Item $total_line_item, $transaction = NULL) |
|
596 | - { |
|
597 | - $pre_tax_line_item = EE_Line_Item::new_instance(array( |
|
598 | - 'LIN_code' => 'pre-tax-subtotal', |
|
599 | - 'LIN_name' => __('Pre-Tax Subtotal', 'event_espresso'), |
|
600 | - 'LIN_type' => EEM_Line_Item::type_sub_total |
|
601 | - )); |
|
602 | - $pre_tax_line_item = apply_filters( |
|
603 | - 'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item', |
|
604 | - $pre_tax_line_item |
|
605 | - ); |
|
606 | - self::set_TXN_ID($pre_tax_line_item, $transaction); |
|
607 | - $total_line_item->add_child_line_item($pre_tax_line_item); |
|
608 | - self::create_event_subtotal($pre_tax_line_item, $transaction); |
|
609 | - return $pre_tax_line_item; |
|
610 | - } |
|
611 | - |
|
612 | - |
|
613 | - /** |
|
614 | - * Creates a line item for the taxes subtotal and finds all the tax prices |
|
615 | - * and applies taxes to it |
|
616 | - * |
|
617 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
618 | - * @param EE_Transaction $transaction |
|
619 | - * @return EE_Line_Item |
|
620 | - * @throws \EE_Error |
|
621 | - */ |
|
622 | - protected static function create_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = NULL) |
|
623 | - { |
|
624 | - $tax_line_item = EE_Line_Item::new_instance(array( |
|
625 | - 'LIN_code' => 'taxes', |
|
626 | - 'LIN_name' => __('Taxes', 'event_espresso'), |
|
627 | - 'LIN_type' => EEM_Line_Item::type_tax_sub_total, |
|
628 | - 'LIN_order' => 1000,//this should always come last |
|
629 | - )); |
|
630 | - $tax_line_item = apply_filters( |
|
631 | - 'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item', |
|
632 | - $tax_line_item |
|
633 | - ); |
|
634 | - self::set_TXN_ID($tax_line_item, $transaction); |
|
635 | - $total_line_item->add_child_line_item($tax_line_item); |
|
636 | - //and lastly, add the actual taxes |
|
637 | - self::apply_taxes($total_line_item); |
|
638 | - return $tax_line_item; |
|
639 | - } |
|
640 | - |
|
641 | - |
|
642 | - /** |
|
643 | - * Creates a default items subtotal line item |
|
644 | - * |
|
645 | - * @param EE_Line_Item $pre_tax_line_item |
|
646 | - * @param EE_Transaction $transaction |
|
647 | - * @param EE_Event $event |
|
648 | - * @return EE_Line_Item |
|
649 | - * @throws \EE_Error |
|
650 | - */ |
|
651 | - public static function create_event_subtotal(EE_Line_Item $pre_tax_line_item, $transaction = NULL, $event = NULL) |
|
652 | - { |
|
653 | - $event_line_item = EE_Line_Item::new_instance(array( |
|
654 | - 'LIN_code' => self::get_event_code($event), |
|
655 | - 'LIN_name' => self::get_event_name($event), |
|
656 | - 'LIN_desc' => self::get_event_desc($event), |
|
657 | - 'LIN_type' => EEM_Line_Item::type_sub_total, |
|
658 | - 'OBJ_type' => 'Event', |
|
659 | - 'OBJ_ID' => $event instanceof EE_Event ? $event->ID() : 0 |
|
660 | - )); |
|
661 | - $event_line_item = apply_filters( |
|
662 | - 'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item', |
|
663 | - $event_line_item |
|
664 | - ); |
|
665 | - self::set_TXN_ID($event_line_item, $transaction); |
|
666 | - $pre_tax_line_item->add_child_line_item($event_line_item); |
|
667 | - return $event_line_item; |
|
668 | - } |
|
669 | - |
|
670 | - |
|
671 | - /** |
|
672 | - * Gets what the event ticket's code SHOULD be |
|
673 | - * |
|
674 | - * @param EE_Event $event |
|
675 | - * @return string |
|
676 | - * @throws \EE_Error |
|
677 | - */ |
|
678 | - public static function get_event_code($event) |
|
679 | - { |
|
680 | - return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0'); |
|
681 | - } |
|
682 | - |
|
683 | - /** |
|
684 | - * Gets the event name |
|
685 | - * @param EE_Event $event |
|
686 | - * @return string |
|
687 | - */ |
|
688 | - public static function get_event_name($event) |
|
689 | - { |
|
690 | - return $event instanceof EE_Event ? $event->name() : __('Event', 'event_espresso'); |
|
691 | - } |
|
692 | - |
|
693 | - /** |
|
694 | - * Gets the event excerpt |
|
695 | - * @param EE_Event $event |
|
696 | - * @return string |
|
697 | - */ |
|
698 | - public static function get_event_desc($event) |
|
699 | - { |
|
700 | - return $event instanceof EE_Event ? $event->short_description() : ''; |
|
701 | - } |
|
702 | - |
|
703 | - /** |
|
704 | - * Given the grand total line item and a ticket, finds the event sub-total |
|
705 | - * line item the ticket's purchase should be added onto |
|
706 | - * |
|
707 | - * @access public |
|
708 | - * @param EE_Line_Item $grand_total the grand total line item |
|
709 | - * @param EE_Ticket $ticket |
|
710 | - * @throws \EE_Error |
|
711 | - * @return EE_Line_Item |
|
712 | - */ |
|
713 | - public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket) |
|
714 | - { |
|
715 | - $first_datetime = $ticket->first_datetime(); |
|
716 | - if (!$first_datetime instanceof EE_Datetime) { |
|
717 | - throw new EE_Error( |
|
718 | - sprintf(__('The supplied ticket (ID %d) has no datetimes', 'event_espresso'), $ticket->ID()) |
|
719 | - ); |
|
720 | - } |
|
721 | - $event = $first_datetime->event(); |
|
722 | - if (!$event instanceof EE_Event) { |
|
723 | - throw new EE_Error( |
|
724 | - sprintf( |
|
725 | - __('The supplied ticket (ID %d) has no event data associated with it.', 'event_espresso'), |
|
726 | - $ticket->ID() |
|
727 | - ) |
|
728 | - ); |
|
729 | - } |
|
730 | - $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event); |
|
731 | - if (!$events_sub_total instanceof EE_Line_Item) { |
|
732 | - throw new EE_Error( |
|
733 | - sprintf( |
|
734 | - __('There is no events sub-total for ticket %s on total line item %d', 'event_espresso'), |
|
735 | - $ticket->ID(), |
|
736 | - $grand_total->ID() |
|
737 | - ) |
|
738 | - ); |
|
739 | - } |
|
740 | - return $events_sub_total; |
|
741 | - } |
|
742 | - |
|
743 | - |
|
744 | - /** |
|
745 | - * Gets the event line item |
|
746 | - * |
|
747 | - * @param EE_Line_Item $grand_total |
|
748 | - * @param EE_Event $event |
|
749 | - * @return EE_Line_Item for the event subtotal which is a child of $grand_total |
|
750 | - * @throws \EE_Error |
|
751 | - */ |
|
752 | - public static function get_event_line_item(EE_Line_Item $grand_total, $event) |
|
753 | - { |
|
754 | - /** @type EE_Event $event */ |
|
755 | - $event = EEM_Event::instance()->ensure_is_obj($event, true); |
|
756 | - $event_line_item = NULL; |
|
757 | - $found = false; |
|
758 | - foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) { |
|
759 | - // default event subtotal, we should only ever find this the first time this method is called |
|
760 | - if (!$event_line_item->OBJ_ID()) { |
|
761 | - // let's use this! but first... set the event details |
|
762 | - EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
763 | - $found = true; |
|
764 | - break; |
|
765 | - } else if ($event_line_item->OBJ_ID() === $event->ID()) { |
|
766 | - // found existing line item for this event in the cart, so break out of loop and use this one |
|
767 | - $found = true; |
|
768 | - break; |
|
769 | - } |
|
770 | - } |
|
771 | - if (!$found) { |
|
772 | - //there is no event sub-total yet, so add it |
|
773 | - $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total); |
|
774 | - // create a new "event" subtotal below that |
|
775 | - $event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event); |
|
776 | - // and set the event details |
|
777 | - EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
778 | - } |
|
779 | - return $event_line_item; |
|
780 | - } |
|
781 | - |
|
782 | - |
|
783 | - /** |
|
784 | - * Creates a default items subtotal line item |
|
785 | - * |
|
786 | - * @param EE_Line_Item $event_line_item |
|
787 | - * @param EE_Event $event |
|
788 | - * @param EE_Transaction $transaction |
|
789 | - * @return EE_Line_Item |
|
790 | - * @throws \EE_Error |
|
791 | - */ |
|
792 | - public static function set_event_subtotal_details( |
|
793 | - EE_Line_Item $event_line_item, |
|
794 | - EE_Event $event, |
|
795 | - $transaction = null |
|
796 | - ) |
|
797 | - { |
|
798 | - if ($event instanceof EE_Event) { |
|
799 | - $event_line_item->set_code(self::get_event_code($event)); |
|
800 | - $event_line_item->set_name(self::get_event_name($event)); |
|
801 | - $event_line_item->set_desc(self::get_event_desc($event)); |
|
802 | - $event_line_item->set_OBJ_ID($event->ID()); |
|
803 | - } |
|
804 | - self::set_TXN_ID($event_line_item, $transaction); |
|
805 | - } |
|
806 | - |
|
807 | - |
|
808 | - /** |
|
809 | - * Finds what taxes should apply, adds them as tax line items under the taxes sub-total, |
|
810 | - * and recalculates the taxes sub-total and the grand total. Resets the taxes, so |
|
811 | - * any old taxes are removed |
|
812 | - * |
|
813 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
814 | - * @throws \EE_Error |
|
815 | - */ |
|
816 | - public static function apply_taxes(EE_Line_Item $total_line_item) |
|
817 | - { |
|
818 | - /** @type EEM_Price $EEM_Price */ |
|
819 | - $EEM_Price = EE_Registry::instance()->load_model('Price'); |
|
820 | - // get array of taxes via Price Model |
|
821 | - $ordered_taxes = $EEM_Price->get_all_prices_that_are_taxes(); |
|
822 | - ksort($ordered_taxes); |
|
823 | - $taxes_line_item = self::get_taxes_subtotal($total_line_item); |
|
824 | - //just to be safe, remove its old tax line items |
|
825 | - $taxes_line_item->delete_children_line_items(); |
|
826 | - //loop thru taxes |
|
827 | - foreach ($ordered_taxes as $order => $taxes) { |
|
828 | - foreach ($taxes as $tax) { |
|
829 | - if ($tax instanceof EE_Price) { |
|
830 | - $tax_line_item = EE_Line_Item::new_instance( |
|
831 | - array( |
|
832 | - 'LIN_name' => $tax->name(), |
|
833 | - 'LIN_desc' => $tax->desc(), |
|
834 | - 'LIN_percent' => $tax->amount(), |
|
835 | - 'LIN_is_taxable' => false, |
|
836 | - 'LIN_order' => $order, |
|
837 | - 'LIN_total' => 0, |
|
838 | - 'LIN_type' => EEM_Line_Item::type_tax, |
|
839 | - 'OBJ_type' => 'Price', |
|
840 | - 'OBJ_ID' => $tax->ID() |
|
841 | - ) |
|
842 | - ); |
|
843 | - $tax_line_item = apply_filters( |
|
844 | - 'FHEE__EEH_Line_Item__apply_taxes__tax_line_item', |
|
845 | - $tax_line_item |
|
846 | - ); |
|
847 | - $taxes_line_item->add_child_line_item($tax_line_item); |
|
848 | - } |
|
849 | - } |
|
850 | - } |
|
851 | - $total_line_item->recalculate_total_including_taxes(); |
|
852 | - } |
|
853 | - |
|
854 | - |
|
855 | - /** |
|
856 | - * Ensures that taxes have been applied to the order, if not applies them. |
|
857 | - * Returns the total amount of tax |
|
858 | - * |
|
859 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
860 | - * @return float |
|
861 | - * @throws \EE_Error |
|
862 | - */ |
|
863 | - public static function ensure_taxes_applied($total_line_item) |
|
864 | - { |
|
865 | - $taxes_subtotal = self::get_taxes_subtotal($total_line_item); |
|
866 | - if (!$taxes_subtotal->children()) { |
|
867 | - self::apply_taxes($total_line_item); |
|
868 | - } |
|
869 | - return $taxes_subtotal->total(); |
|
870 | - } |
|
871 | - |
|
872 | - |
|
873 | - /** |
|
874 | - * Deletes ALL children of the passed line item |
|
875 | - * |
|
876 | - * @param EE_Line_Item $parent_line_item |
|
877 | - * @return bool |
|
878 | - * @throws \EE_Error |
|
879 | - */ |
|
880 | - public static function delete_all_child_items(EE_Line_Item $parent_line_item) |
|
881 | - { |
|
882 | - $deleted = 0; |
|
883 | - foreach ($parent_line_item->children() as $child_line_item) { |
|
884 | - if ($child_line_item instanceof EE_Line_Item) { |
|
885 | - $deleted += EEH_Line_Item::delete_all_child_items($child_line_item); |
|
886 | - if ($child_line_item->ID()) { |
|
887 | - $child_line_item->delete(); |
|
888 | - unset($child_line_item); |
|
889 | - } else { |
|
890 | - $parent_line_item->delete_child_line_item($child_line_item->code()); |
|
891 | - } |
|
892 | - $deleted++; |
|
893 | - } |
|
894 | - } |
|
895 | - return $deleted; |
|
896 | - } |
|
897 | - |
|
898 | - |
|
899 | - /** |
|
900 | - * Deletes the line items as indicated by the line item code(s) provided, |
|
901 | - * regardless of where they're found in the line item tree. Automatically |
|
902 | - * re-calculates the line item totals and updates the related transaction. But |
|
903 | - * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
904 | - * should probably change because of this). |
|
905 | - * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
906 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
907 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
908 | - * @param array|bool|string $line_item_codes |
|
909 | - * @return int number of items successfully removed |
|
910 | - */ |
|
911 | - public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = FALSE) |
|
912 | - { |
|
913 | - |
|
914 | - if ($total_line_item->type() !== EEM_Line_Item::type_total) { |
|
915 | - EE_Error::doing_it_wrong( |
|
916 | - 'EEH_Line_Item::delete_items', |
|
917 | - __( |
|
918 | - 'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly', |
|
919 | - 'event_espresso' |
|
920 | - ), |
|
921 | - '4.6.18' |
|
922 | - ); |
|
923 | - } |
|
924 | - do_action('AHEE_log', __FILE__, __FUNCTION__, ''); |
|
925 | - |
|
926 | - // check if only a single line_item_id was passed |
|
927 | - if (!empty($line_item_codes) && !is_array($line_item_codes)) { |
|
928 | - // place single line_item_id in an array to appear as multiple line_item_ids |
|
929 | - $line_item_codes = array($line_item_codes); |
|
930 | - } |
|
931 | - $removals = 0; |
|
932 | - // cycle thru line_item_ids |
|
933 | - foreach ($line_item_codes as $line_item_id) { |
|
934 | - $removals += $total_line_item->delete_child_line_item($line_item_id); |
|
935 | - } |
|
936 | - |
|
937 | - if ($removals > 0) { |
|
938 | - $total_line_item->recalculate_taxes_and_tax_total(); |
|
939 | - return $removals; |
|
940 | - } else { |
|
941 | - return FALSE; |
|
942 | - } |
|
943 | - } |
|
944 | - |
|
945 | - |
|
946 | - /** |
|
947 | - * Overwrites the previous tax by clearing out the old taxes, and creates a new |
|
948 | - * tax and updates the total line item accordingly |
|
949 | - * |
|
950 | - * @param EE_Line_Item $total_line_item |
|
951 | - * @param float $amount |
|
952 | - * @param string $name |
|
953 | - * @param string $description |
|
954 | - * @param string $code |
|
955 | - * @param boolean $add_to_existing_line_item |
|
956 | - * if true, and a duplicate line item with the same code is found, |
|
957 | - * $amount will be added onto it; otherwise will simply set the taxes to match $amount |
|
958 | - * @return EE_Line_Item the new tax line item created |
|
959 | - * @throws \EE_Error |
|
960 | - */ |
|
961 | - public static function set_total_tax_to( |
|
962 | - EE_Line_Item $total_line_item, |
|
963 | - $amount, |
|
964 | - $name = null, |
|
965 | - $description = null, |
|
966 | - $code = null, |
|
967 | - $add_to_existing_line_item = false |
|
968 | - ) |
|
969 | - { |
|
970 | - $tax_subtotal = self::get_taxes_subtotal($total_line_item); |
|
971 | - $taxable_total = $total_line_item->taxable_total(); |
|
972 | - |
|
973 | - if ($add_to_existing_line_item) { |
|
974 | - $new_tax = $tax_subtotal->get_child_line_item($code); |
|
975 | - EEM_Line_Item::instance()->delete( |
|
976 | - array(array('LIN_code' => array('!=', $code), 'LIN_parent' => $tax_subtotal->ID())) |
|
977 | - ); |
|
978 | - } else { |
|
979 | - $new_tax = null; |
|
980 | - $tax_subtotal->delete_children_line_items(); |
|
981 | - } |
|
982 | - if ($new_tax) { |
|
983 | - $new_tax->set_total($new_tax->total() + $amount); |
|
984 | - $new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0); |
|
985 | - } else { |
|
986 | - //no existing tax item. Create it |
|
987 | - $new_tax = EE_Line_Item::new_instance(array( |
|
988 | - 'TXN_ID' => $total_line_item->TXN_ID(), |
|
989 | - 'LIN_name' => $name ? $name : __('Tax', 'event_espresso'), |
|
990 | - 'LIN_desc' => $description ? $description : '', |
|
991 | - 'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0, |
|
992 | - 'LIN_total' => $amount, |
|
993 | - 'LIN_parent' => $tax_subtotal->ID(), |
|
994 | - 'LIN_type' => EEM_Line_Item::type_tax, |
|
995 | - 'LIN_code' => $code |
|
996 | - )); |
|
997 | - } |
|
998 | - |
|
999 | - $new_tax = apply_filters( |
|
1000 | - 'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal', |
|
1001 | - $new_tax, |
|
1002 | - $total_line_item |
|
1003 | - ); |
|
1004 | - $new_tax->save(); |
|
1005 | - $tax_subtotal->set_total($new_tax->total()); |
|
1006 | - $tax_subtotal->save(); |
|
1007 | - $total_line_item->recalculate_total_including_taxes(); |
|
1008 | - return $new_tax; |
|
1009 | - } |
|
1010 | - |
|
1011 | - |
|
1012 | - /** |
|
1013 | - * Makes all the line items which are children of $line_item taxable (or not). |
|
1014 | - * Does NOT save the line items |
|
1015 | - * @param EE_Line_Item $line_item |
|
1016 | - * @param string $code_substring_for_whitelist if this string is part of the line item's code |
|
1017 | - * it will be whitelisted (ie, except from becoming taxable) |
|
1018 | - * @param boolean $taxable |
|
1019 | - */ |
|
1020 | - public static function set_line_items_taxable( |
|
1021 | - EE_Line_Item $line_item, |
|
1022 | - $taxable = true, |
|
1023 | - $code_substring_for_whitelist = null |
|
1024 | - ) |
|
1025 | - { |
|
1026 | - $whitelisted = false; |
|
1027 | - if ($code_substring_for_whitelist !== null) { |
|
1028 | - $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false ? true : false; |
|
1029 | - } |
|
1030 | - if (!$whitelisted && $line_item->is_line_item()) { |
|
1031 | - $line_item->set_is_taxable($taxable); |
|
1032 | - } |
|
1033 | - foreach ($line_item->children() as $child_line_item) { |
|
1034 | - EEH_Line_Item::set_line_items_taxable($child_line_item, $taxable, $code_substring_for_whitelist); |
|
1035 | - } |
|
1036 | - } |
|
1037 | - |
|
1038 | - |
|
1039 | - /** |
|
1040 | - * Gets all descendants that are event subtotals |
|
1041 | - * |
|
1042 | - * @uses EEH_Line_Item::get_subtotals_of_object_type() |
|
1043 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1044 | - * @return EE_Line_Item[] |
|
1045 | - */ |
|
1046 | - public static function get_event_subtotals(EE_Line_Item $parent_line_item) |
|
1047 | - { |
|
1048 | - return self::get_subtotals_of_object_type($parent_line_item, 'Event'); |
|
1049 | - } |
|
1050 | - |
|
1051 | - |
|
1052 | - /** |
|
1053 | - * Gets all descendants subtotals that match the supplied object type |
|
1054 | - * |
|
1055 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1056 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1057 | - * @param string $obj_type |
|
1058 | - * @return EE_Line_Item[] |
|
1059 | - */ |
|
1060 | - public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
1061 | - { |
|
1062 | - return self::_get_descendants_by_type_and_object_type( |
|
1063 | - $parent_line_item, |
|
1064 | - EEM_Line_Item::type_sub_total, |
|
1065 | - $obj_type |
|
1066 | - ); |
|
1067 | - } |
|
1068 | - |
|
1069 | - |
|
1070 | - /** |
|
1071 | - * Gets all descendants that are tickets |
|
1072 | - * |
|
1073 | - * @uses EEH_Line_Item::get_line_items_of_object_type() |
|
1074 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1075 | - * @return EE_Line_Item[] |
|
1076 | - */ |
|
1077 | - public static function get_ticket_line_items(EE_Line_Item $parent_line_item) |
|
1078 | - { |
|
1079 | - return self::get_line_items_of_object_type($parent_line_item, 'Ticket'); |
|
1080 | - } |
|
1081 | - |
|
1082 | - |
|
1083 | - /** |
|
1084 | - * Gets all descendants subtotals that match the supplied object type |
|
1085 | - * |
|
1086 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1087 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1088 | - * @param string $obj_type |
|
1089 | - * @return EE_Line_Item[] |
|
1090 | - */ |
|
1091 | - public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
1092 | - { |
|
1093 | - return self::_get_descendants_by_type_and_object_type($parent_line_item, EEM_Line_Item::type_line_item, $obj_type); |
|
1094 | - } |
|
1095 | - |
|
1096 | - |
|
1097 | - /** |
|
1098 | - * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax' |
|
1099 | - * @uses EEH_Line_Item::get_descendants_of_type() |
|
1100 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1101 | - * @return EE_Line_Item[] |
|
1102 | - */ |
|
1103 | - public static function get_tax_descendants(EE_Line_Item $parent_line_item) |
|
1104 | - { |
|
1105 | - return EEH_Line_Item::get_descendants_of_type($parent_line_item, EEM_Line_Item::type_tax); |
|
1106 | - } |
|
1107 | - |
|
1108 | - |
|
1109 | - /** |
|
1110 | - * Gets all the real items purchased which are children of this item |
|
1111 | - * @uses EEH_Line_Item::get_descendants_of_type() |
|
1112 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1113 | - * @return EE_Line_Item[] |
|
1114 | - */ |
|
1115 | - public static function get_line_item_descendants(EE_Line_Item $parent_line_item) |
|
1116 | - { |
|
1117 | - return EEH_Line_Item::get_descendants_of_type($parent_line_item, EEM_Line_Item::type_line_item); |
|
1118 | - } |
|
1119 | - |
|
1120 | - |
|
1121 | - /** |
|
1122 | - * Gets all descendants of supplied line item that match the supplied line item type |
|
1123 | - * |
|
1124 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1125 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1126 | - * @param string $line_item_type one of the EEM_Line_Item constants |
|
1127 | - * @return EE_Line_Item[] |
|
1128 | - */ |
|
1129 | - public static function get_descendants_of_type(EE_Line_Item $parent_line_item, $line_item_type) |
|
1130 | - { |
|
1131 | - return self::_get_descendants_by_type_and_object_type($parent_line_item, $line_item_type, NULL); |
|
1132 | - } |
|
1133 | - |
|
1134 | - |
|
1135 | - /** |
|
1136 | - * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type as well |
|
1137 | - * |
|
1138 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1139 | - * @param string $line_item_type one of the EEM_Line_Item constants |
|
1140 | - * @param string | NULL $obj_type object model class name (minus prefix) or NULL to ignore object type when searching |
|
1141 | - * @return EE_Line_Item[] |
|
1142 | - */ |
|
1143 | - protected static function _get_descendants_by_type_and_object_type( |
|
1144 | - EE_Line_Item $parent_line_item, |
|
1145 | - $line_item_type, |
|
1146 | - $obj_type = null |
|
1147 | - ) |
|
1148 | - { |
|
1149 | - $objects = array(); |
|
1150 | - foreach ($parent_line_item->children() as $child_line_item) { |
|
1151 | - if ($child_line_item instanceof EE_Line_Item) { |
|
1152 | - if ( |
|
1153 | - $child_line_item->type() === $line_item_type |
|
1154 | - && ( |
|
1155 | - $child_line_item->OBJ_type() === $obj_type || $obj_type === null |
|
1156 | - ) |
|
1157 | - ) { |
|
1158 | - $objects[] = $child_line_item; |
|
1159 | - } else { |
|
1160 | - //go-through-all-its children looking for more matches |
|
1161 | - $objects = array_merge( |
|
1162 | - $objects, |
|
1163 | - self::_get_descendants_by_type_and_object_type( |
|
1164 | - $child_line_item, |
|
1165 | - $line_item_type, |
|
1166 | - $obj_type |
|
1167 | - ) |
|
1168 | - ); |
|
1169 | - } |
|
1170 | - } |
|
1171 | - } |
|
1172 | - return $objects; |
|
1173 | - } |
|
1174 | - |
|
1175 | - |
|
1176 | - /** |
|
1177 | - * Gets all descendants subtotals that match the supplied object type |
|
1178 | - * |
|
1179 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1180 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1181 | - * @param string $OBJ_type object type (like Event) |
|
1182 | - * @param array $OBJ_IDs array of OBJ_IDs |
|
1183 | - * @return EE_Line_Item[] |
|
1184 | - */ |
|
1185 | - public static function get_line_items_by_object_type_and_IDs( |
|
1186 | - EE_Line_Item $parent_line_item, |
|
1187 | - $OBJ_type = '', |
|
1188 | - $OBJ_IDs = array() |
|
1189 | - ) |
|
1190 | - { |
|
1191 | - return self::_get_descendants_by_object_type_and_object_ID($parent_line_item, $OBJ_type, $OBJ_IDs); |
|
1192 | - } |
|
1193 | - |
|
1194 | - |
|
1195 | - /** |
|
1196 | - * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type as well |
|
1197 | - * |
|
1198 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1199 | - * @param string $OBJ_type object type (like Event) |
|
1200 | - * @param array $OBJ_IDs array of OBJ_IDs |
|
1201 | - * @return EE_Line_Item[] |
|
1202 | - */ |
|
1203 | - protected static function _get_descendants_by_object_type_and_object_ID( |
|
1204 | - EE_Line_Item $parent_line_item, |
|
1205 | - $OBJ_type, |
|
1206 | - $OBJ_IDs |
|
1207 | - ) |
|
1208 | - { |
|
1209 | - $objects = array(); |
|
1210 | - foreach ($parent_line_item->children() as $child_line_item) { |
|
1211 | - if ($child_line_item instanceof EE_Line_Item) { |
|
1212 | - if ( |
|
1213 | - $child_line_item->OBJ_type() === $OBJ_type |
|
1214 | - && is_array($OBJ_IDs) |
|
1215 | - && in_array($child_line_item->OBJ_ID(), $OBJ_IDs) |
|
1216 | - ) { |
|
1217 | - $objects[] = $child_line_item; |
|
1218 | - } else { |
|
1219 | - //go-through-all-its children looking for more matches |
|
1220 | - $objects = array_merge( |
|
1221 | - $objects, |
|
1222 | - self::_get_descendants_by_object_type_and_object_ID( |
|
1223 | - $child_line_item, |
|
1224 | - $OBJ_type, |
|
1225 | - $OBJ_IDs |
|
1226 | - ) |
|
1227 | - ); |
|
1228 | - } |
|
1229 | - } |
|
1230 | - } |
|
1231 | - return $objects; |
|
1232 | - } |
|
1233 | - |
|
1234 | - |
|
1235 | - /** |
|
1236 | - * Uses a breadth-first-search in order to find the nearest descendant of |
|
1237 | - * the specified type and returns it, else NULL |
|
1238 | - * |
|
1239 | - * @uses EEH_Line_Item::_get_nearest_descendant() |
|
1240 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1241 | - * @param string $type like one of the EEM_Line_Item::type_* |
|
1242 | - * @return EE_Line_Item |
|
1243 | - */ |
|
1244 | - public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, $type) |
|
1245 | - { |
|
1246 | - return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type); |
|
1247 | - } |
|
1248 | - |
|
1249 | - |
|
1250 | - /** |
|
1251 | - * Uses a breadth-first-search in order to find the nearest descendant |
|
1252 | - * having the specified LIN_code and returns it, else NULL |
|
1253 | - * |
|
1254 | - * @uses EEH_Line_Item::_get_nearest_descendant() |
|
1255 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1256 | - * @param string $code any value used for LIN_code |
|
1257 | - * @return EE_Line_Item |
|
1258 | - */ |
|
1259 | - public static function get_nearest_descendant_having_code(EE_Line_Item $parent_line_item, $code) |
|
1260 | - { |
|
1261 | - return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code); |
|
1262 | - } |
|
1263 | - |
|
1264 | - |
|
1265 | - /** |
|
1266 | - * Uses a breadth-first-search in order to find the nearest descendant |
|
1267 | - * having the specified LIN_code and returns it, else NULL |
|
1268 | - * |
|
1269 | - * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1270 | - * @param string $search_field name of EE_Line_Item property |
|
1271 | - * @param string $value any value stored in $search_field |
|
1272 | - * @return EE_Line_Item |
|
1273 | - */ |
|
1274 | - protected static function _get_nearest_descendant(EE_Line_Item $parent_line_item, $search_field, $value) |
|
1275 | - { |
|
1276 | - foreach ($parent_line_item->children() as $child) { |
|
1277 | - if ($child->get($search_field) == $value) { |
|
1278 | - return $child; |
|
1279 | - } |
|
1280 | - } |
|
1281 | - foreach ($parent_line_item->children() as $child) { |
|
1282 | - $descendant_found = self::_get_nearest_descendant($child, $search_field, $value); |
|
1283 | - if ($descendant_found) { |
|
1284 | - return $descendant_found; |
|
1285 | - } |
|
1286 | - } |
|
1287 | - return NULL; |
|
1288 | - } |
|
1289 | - |
|
1290 | - |
|
1291 | - /** |
|
1292 | - * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction, |
|
1293 | - * else recursively walks up the line item tree until a parent of type total is found, |
|
1294 | - * |
|
1295 | - * @param EE_Line_Item $line_item |
|
1296 | - * @return \EE_Line_Item |
|
1297 | - * @throws \EE_Error |
|
1298 | - */ |
|
1299 | - public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item) |
|
1300 | - { |
|
1301 | - if ($line_item->TXN_ID()) { |
|
1302 | - $total_line_item = $line_item->transaction()->total_line_item(false); |
|
1303 | - if ($total_line_item instanceof EE_Line_Item) { |
|
1304 | - return $total_line_item; |
|
1305 | - } |
|
1306 | - } else { |
|
1307 | - $line_item_parent = $line_item->parent(); |
|
1308 | - if ($line_item_parent instanceof EE_Line_Item) { |
|
1309 | - if ($line_item_parent->is_total()) { |
|
1310 | - return $line_item_parent; |
|
1311 | - } |
|
1312 | - return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent); |
|
1313 | - } |
|
1314 | - } |
|
1315 | - throw new EE_Error( |
|
1316 | - sprintf( |
|
1317 | - __('A valid grand total for line item %1$d was not found.', 'event_espresso'), |
|
1318 | - $line_item->ID() |
|
1319 | - ) |
|
1320 | - ); |
|
1321 | - } |
|
1322 | - |
|
1323 | - |
|
1324 | - /** |
|
1325 | - * Prints out a representation of the line item tree |
|
1326 | - * |
|
1327 | - * @param EE_Line_Item $line_item |
|
1328 | - * @param int $indentation |
|
1329 | - * @return void |
|
1330 | - * @throws \EE_Error |
|
1331 | - */ |
|
1332 | - public static function visualize(EE_Line_Item $line_item, $indentation = 0) |
|
1333 | - { |
|
1334 | - echo defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
|
1335 | - if (!$indentation) { |
|
1336 | - echo defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
|
1337 | - } |
|
1338 | - for ($i = 0; $i < $indentation; $i++) { |
|
1339 | - echo ". "; |
|
1340 | - } |
|
1341 | - $breakdown = ''; |
|
1342 | - if ($line_item->is_line_item()) { |
|
1343 | - if ($line_item->is_percent()) { |
|
1344 | - $breakdown = "{$line_item->percent()}%"; |
|
1345 | - } else { |
|
1346 | - $breakdown = '$' . "{$line_item->unit_price()} x {$line_item->quantity()}"; |
|
1347 | - } |
|
1348 | - } |
|
1349 | - echo $line_item->name() . " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : " . '$' . "{$line_item->total()}"; |
|
1350 | - if ($breakdown) { |
|
1351 | - echo " ( {$breakdown} )"; |
|
1352 | - } |
|
1353 | - if ($line_item->is_taxable()) { |
|
1354 | - echo " * taxable"; |
|
1355 | - } |
|
1356 | - if ($line_item->children()) { |
|
1357 | - foreach ($line_item->children() as $child) { |
|
1358 | - self::visualize($child, $indentation + 1); |
|
1359 | - } |
|
1360 | - } |
|
1361 | - } |
|
1362 | - |
|
1363 | - |
|
1364 | - /** |
|
1365 | - * Calculates the registration's final price, taking into account that they |
|
1366 | - * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes, |
|
1367 | - * and receive a portion of any transaction-wide discounts. |
|
1368 | - * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount |
|
1369 | - * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get |
|
1370 | - * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50 |
|
1371 | - * and brent's final price should be $5.50. |
|
1372 | - * |
|
1373 | - * In order to do this, we basically need to traverse the line item tree calculating |
|
1374 | - * the running totals (just as if we were recalculating the total), but when we identify |
|
1375 | - * regular line items, we need to keep track of their share of the grand total. |
|
1376 | - * Also, we need to keep track of the TAXABLE total for each ticket purchase, so |
|
1377 | - * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total" |
|
1378 | - * when there are non-taxable items; otherwise they would be the same) |
|
1379 | - * |
|
1380 | - * @param EE_Line_Item $line_item |
|
1381 | - * @param array $billable_ticket_quantities array of EE_Ticket IDs and their corresponding quantity that |
|
1382 | - * can be included in price calculations at this moment |
|
1383 | - * @return array keys are line items for tickets IDs and values are their share of the running total, |
|
1384 | - * plus the key 'total', and 'taxable' which also has keys of all the ticket IDs. Eg |
|
1385 | - * array( |
|
1386 | - * 12 => 4.3 |
|
1387 | - * 23 => 8.0 |
|
1388 | - * 'total' => 16.6, |
|
1389 | - * 'taxable' => array( |
|
1390 | - * 12 => 10, |
|
1391 | - * 23 => 4 |
|
1392 | - * ). |
|
1393 | - * So to find which registrations have which final price, we need to find which line item |
|
1394 | - * is theirs, which can be done with |
|
1395 | - * `EEM_Line_Item::instance()->get_line_item_for_registration( $registration );` |
|
1396 | - */ |
|
1397 | - public static function calculate_reg_final_prices_per_line_item(EE_Line_Item $line_item, $billable_ticket_quantities = array()) |
|
1398 | - { |
|
1399 | - //init running grand total if not already |
|
1400 | - if (!isset($running_totals['total'])) { |
|
1401 | - $running_totals['total'] = 0; |
|
1402 | - } |
|
1403 | - if (!isset($running_totals['taxable'])) { |
|
1404 | - $running_totals['taxable'] = array('total' => 0); |
|
1405 | - } |
|
1406 | - foreach ($line_item->children() as $child_line_item) { |
|
1407 | - switch ($child_line_item->type()) { |
|
1408 | - |
|
1409 | - case EEM_Line_Item::type_sub_total : |
|
1410 | - $running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item($child_line_item, $billable_ticket_quantities); |
|
1411 | - //combine arrays but preserve numeric keys |
|
1412 | - $running_totals = array_replace_recursive($running_totals_from_subtotal, $running_totals); |
|
1413 | - $running_totals['total'] += $running_totals_from_subtotal['total']; |
|
1414 | - $running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total']; |
|
1415 | - break; |
|
1416 | - |
|
1417 | - case EEM_Line_Item::type_tax_sub_total : |
|
1418 | - |
|
1419 | - //find how much the taxes percentage is |
|
1420 | - if ($child_line_item->percent() !== 0) { |
|
1421 | - $tax_percent_decimal = $child_line_item->percent() / 100; |
|
1422 | - } else { |
|
1423 | - $tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100; |
|
1424 | - } |
|
1425 | - //and apply to all the taxable totals, and add to the pretax totals |
|
1426 | - foreach ($running_totals as $line_item_id => $this_running_total) { |
|
1427 | - //"total" and "taxable" array key is an exception |
|
1428 | - if ($line_item_id === 'taxable') { |
|
1429 | - continue; |
|
1430 | - } |
|
1431 | - $taxable_total = $running_totals['taxable'][$line_item_id]; |
|
1432 | - $running_totals[$line_item_id] += ($taxable_total * $tax_percent_decimal); |
|
1433 | - } |
|
1434 | - break; |
|
1435 | - |
|
1436 | - case EEM_Line_Item::type_line_item : |
|
1437 | - |
|
1438 | - // ticket line items or ???? |
|
1439 | - if ($child_line_item->OBJ_type() === 'Ticket') { |
|
1440 | - // kk it's a ticket |
|
1441 | - if (isset($running_totals[$child_line_item->ID()])) { |
|
1442 | - //huh? that shouldn't happen. |
|
1443 | - $running_totals['total'] += $child_line_item->total(); |
|
1444 | - } else { |
|
1445 | - //its not in our running totals yet. great. |
|
1446 | - if ($child_line_item->is_taxable()) { |
|
1447 | - $taxable_amount = $child_line_item->unit_price(); |
|
1448 | - } else { |
|
1449 | - $taxable_amount = 0; |
|
1450 | - } |
|
1451 | - // are we only calculating totals for some tickets? |
|
1452 | - if (isset($billable_ticket_quantities[$child_line_item->OBJ_ID()])) { |
|
1453 | - $quantity = $billable_ticket_quantities[$child_line_item->OBJ_ID()]; |
|
1454 | - $running_totals[$child_line_item->ID()] = $quantity |
|
1455 | - ? $child_line_item->unit_price() |
|
1456 | - : 0; |
|
1457 | - $running_totals['taxable'][$child_line_item->ID()] = $quantity |
|
1458 | - ? $taxable_amount |
|
1459 | - : 0; |
|
1460 | - } else { |
|
1461 | - $quantity = $child_line_item->quantity(); |
|
1462 | - $running_totals[$child_line_item->ID()] = $child_line_item->unit_price(); |
|
1463 | - $running_totals['taxable'][$child_line_item->ID()] = $taxable_amount; |
|
1464 | - } |
|
1465 | - $running_totals['taxable']['total'] += $taxable_amount * $quantity; |
|
1466 | - $running_totals['total'] += $child_line_item->unit_price() * $quantity; |
|
1467 | - } |
|
1468 | - } else { |
|
1469 | - // it's some other type of item added to the cart |
|
1470 | - // it should affect the running totals |
|
1471 | - // basically we want to convert it into a PERCENT modifier. Because |
|
1472 | - // more clearly affect all registration's final price equally |
|
1473 | - $line_items_percent_of_running_total = $running_totals['total'] > 0 |
|
1474 | - ? ($child_line_item->total() / $running_totals['total']) + 1 |
|
1475 | - : 1; |
|
1476 | - foreach ($running_totals as $line_item_id => $this_running_total) { |
|
1477 | - //the "taxable" array key is an exception |
|
1478 | - if ($line_item_id === 'taxable') { |
|
1479 | - continue; |
|
1480 | - } |
|
1481 | - // update the running totals |
|
1482 | - // yes this actually even works for the running grand total! |
|
1483 | - $running_totals[$line_item_id] = |
|
1484 | - $line_items_percent_of_running_total * $this_running_total; |
|
1485 | - |
|
1486 | - if ($child_line_item->is_taxable()) { |
|
1487 | - $running_totals['taxable'][$line_item_id] = |
|
1488 | - $line_items_percent_of_running_total * $running_totals['taxable'][$line_item_id]; |
|
1489 | - } |
|
1490 | - } |
|
1491 | - } |
|
1492 | - break; |
|
1493 | - } |
|
1494 | - } |
|
1495 | - return $running_totals; |
|
1496 | - } |
|
1497 | - |
|
1498 | - |
|
1499 | - /** |
|
1500 | - * @param \EE_Line_Item $total_line_item |
|
1501 | - * @param \EE_Line_Item $ticket_line_item |
|
1502 | - * @return float | null |
|
1503 | - * @throws \OutOfRangeException |
|
1504 | - */ |
|
1505 | - public static function calculate_final_price_for_ticket_line_item(\EE_Line_Item $total_line_item, \EE_Line_Item $ticket_line_item) |
|
1506 | - { |
|
1507 | - static $final_prices_per_ticket_line_item = array(); |
|
1508 | - if (empty($final_prices_per_ticket_line_item)) { |
|
1509 | - $final_prices_per_ticket_line_item = \EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
1510 | - $total_line_item |
|
1511 | - ); |
|
1512 | - } |
|
1513 | - //ok now find this new registration's final price |
|
1514 | - if (isset($final_prices_per_ticket_line_item[$ticket_line_item->ID()])) { |
|
1515 | - return $final_prices_per_ticket_line_item[$ticket_line_item->ID()]; |
|
1516 | - } |
|
1517 | - $message = sprintf( |
|
1518 | - __( |
|
1519 | - 'The final price for the ticket line item (ID:%1$d) could not be calculated.', |
|
1520 | - 'event_espresso' |
|
1521 | - ), |
|
1522 | - $ticket_line_item->ID() |
|
1523 | - ); |
|
1524 | - if (WP_DEBUG) { |
|
1525 | - $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true); |
|
1526 | - throw new \OutOfRangeException($message); |
|
1527 | - } else { |
|
1528 | - EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message); |
|
1529 | - } |
|
1530 | - return null; |
|
1531 | - } |
|
1532 | - |
|
1533 | - |
|
1534 | - /** |
|
1535 | - * Creates a duplicate of the line item tree, except only includes billable items |
|
1536 | - * and the portion of line items attributed to billable things |
|
1537 | - * |
|
1538 | - * @param EE_Line_Item $line_item |
|
1539 | - * @param EE_Registration[] $registrations |
|
1540 | - * @return \EE_Line_Item |
|
1541 | - * @throws \EE_Error |
|
1542 | - */ |
|
1543 | - public static function billable_line_item_tree(EE_Line_Item $line_item, $registrations) |
|
1544 | - { |
|
1545 | - $copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations); |
|
1546 | - foreach ($line_item->children() as $child_li) { |
|
1547 | - $copy_li->add_child_line_item(EEH_Line_Item::billable_line_item_tree($child_li, $registrations)); |
|
1548 | - } |
|
1549 | - //if this is the grand total line item, make sure the totals all add up |
|
1550 | - //(we could have duplicated this logic AS we copied the line items, but |
|
1551 | - //it seems DRYer this way) |
|
1552 | - if ($copy_li->type() === EEM_Line_Item::type_total) { |
|
1553 | - $copy_li->recalculate_total_including_taxes(); |
|
1554 | - } |
|
1555 | - return $copy_li; |
|
1556 | - } |
|
1557 | - |
|
1558 | - |
|
1559 | - /** |
|
1560 | - * Creates a new, unsaved line item from $line_item that factors in the |
|
1561 | - * number of billable registrations on $registrations. |
|
1562 | - * |
|
1563 | - * @param EE_Line_Item $line_item |
|
1564 | - * @return EE_Line_Item |
|
1565 | - * @throws \EE_Error |
|
1566 | - * @param EE_Registration[] $registrations |
|
1567 | - */ |
|
1568 | - public static function billable_line_item(EE_Line_Item $line_item, $registrations) |
|
1569 | - { |
|
1570 | - $new_li_fields = $line_item->model_field_array(); |
|
1571 | - if ($line_item->type() === EEM_Line_Item::type_line_item && |
|
1572 | - $line_item->OBJ_type() === 'Ticket' |
|
1573 | - ) { |
|
1574 | - $count = 0; |
|
1575 | - foreach ($registrations as $registration) { |
|
1576 | - if ($line_item->OBJ_ID() === $registration->ticket_ID() && |
|
1577 | - in_array($registration->status_ID(), EEM_Registration::reg_statuses_that_allow_payment()) |
|
1578 | - ) { |
|
1579 | - $count++; |
|
1580 | - } |
|
1581 | - } |
|
1582 | - $new_li_fields['LIN_quantity'] = $count; |
|
1583 | - } |
|
1584 | - //don't set the total. We'll leave that up to the code that calculates it |
|
1585 | - unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']); |
|
1586 | - return EE_Line_Item::new_instance($new_li_fields); |
|
1587 | - } |
|
1588 | - |
|
1589 | - |
|
1590 | - /** |
|
1591 | - * Returns a modified line item tree where all the subtotals which have a total of 0 |
|
1592 | - * are removed, and line items with a quantity of 0 |
|
1593 | - * |
|
1594 | - * @param EE_Line_Item $line_item |null |
|
1595 | - * @return \EE_Line_Item|null |
|
1596 | - * @throws \EE_Error |
|
1597 | - */ |
|
1598 | - public static function non_empty_line_items(EE_Line_Item $line_item) |
|
1599 | - { |
|
1600 | - $copied_li = EEH_Line_Item::non_empty_line_item($line_item); |
|
1601 | - if ($copied_li === null) { |
|
1602 | - return null; |
|
1603 | - } |
|
1604 | - //if this is an event subtotal, we want to only include it if it |
|
1605 | - //has a non-zero total and at least one ticket line item child |
|
1606 | - $ticket_children = 0; |
|
1607 | - foreach ($line_item->children() as $child_li) { |
|
1608 | - $child_li_copy = EEH_Line_Item::non_empty_line_items($child_li); |
|
1609 | - if ($child_li_copy !== null) { |
|
1610 | - $copied_li->add_child_line_item($child_li_copy); |
|
1611 | - if ($child_li_copy->type() === EEM_Line_Item::type_line_item && |
|
1612 | - $child_li_copy->OBJ_type() === 'Ticket' |
|
1613 | - ) { |
|
1614 | - $ticket_children++; |
|
1615 | - } |
|
1616 | - } |
|
1617 | - } |
|
1618 | - //if this is an event subtotal with NO ticket children |
|
1619 | - //we basically want to ignore it |
|
1620 | - if ( |
|
1621 | - $ticket_children === 0 |
|
1622 | - && $line_item->type() === EEM_Line_Item::type_sub_total |
|
1623 | - && $line_item->OBJ_type() === 'Event' |
|
1624 | - && $line_item->total() === 0 |
|
1625 | - ) { |
|
1626 | - return null; |
|
1627 | - } |
|
1628 | - return $copied_li; |
|
1629 | - } |
|
1630 | - |
|
1631 | - |
|
1632 | - /** |
|
1633 | - * Creates a new, unsaved line item, but if it's a ticket line item |
|
1634 | - * with a total of 0, or a subtotal of 0, returns null instead |
|
1635 | - * |
|
1636 | - * @param EE_Line_Item $line_item |
|
1637 | - * @return EE_Line_Item |
|
1638 | - * @throws \EE_Error |
|
1639 | - */ |
|
1640 | - public static function non_empty_line_item(EE_Line_Item $line_item) |
|
1641 | - { |
|
1642 | - if ($line_item->type() === EEM_Line_Item::type_line_item && |
|
1643 | - $line_item->OBJ_type() === 'Ticket' && |
|
1644 | - $line_item->quantity() === 0 |
|
1645 | - ) { |
|
1646 | - return null; |
|
1647 | - } |
|
1648 | - $new_li_fields = $line_item->model_field_array(); |
|
1649 | - //don't set the total. We'll leave that up to the code that calculates it |
|
1650 | - unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']); |
|
1651 | - return EE_Line_Item::new_instance($new_li_fields); |
|
1652 | - } |
|
1653 | - |
|
1654 | - |
|
1655 | - |
|
1656 | - /**************************************** @DEPRECATED METHODS *************************************** */ |
|
1657 | - /** |
|
1658 | - * @deprecated |
|
1659 | - * @param EE_Line_Item $total_line_item |
|
1660 | - * @return \EE_Line_Item |
|
1661 | - * @throws \EE_Error |
|
1662 | - */ |
|
1663 | - public static function get_items_subtotal(EE_Line_Item $total_line_item) |
|
1664 | - { |
|
1665 | - EE_Error::doing_it_wrong('EEH_Line_Item::get_items_subtotal()', __('Method replaced with EEH_Line_Item::get_pre_tax_subtotal()', 'event_espresso'), '4.6.0'); |
|
1666 | - return self::get_pre_tax_subtotal($total_line_item); |
|
1667 | - } |
|
1668 | - |
|
1669 | - |
|
1670 | - /** |
|
1671 | - * @deprecated |
|
1672 | - * @param EE_Transaction $transaction |
|
1673 | - * @return \EE_Line_Item |
|
1674 | - * @throws \EE_Error |
|
1675 | - */ |
|
1676 | - public static function create_default_total_line_item($transaction = NULL) |
|
1677 | - { |
|
1678 | - EE_Error::doing_it_wrong('EEH_Line_Item::create_default_total_line_item()', __('Method replaced with EEH_Line_Item::create_total_line_item()', 'event_espresso'), '4.6.0'); |
|
1679 | - return self::create_total_line_item($transaction); |
|
1680 | - } |
|
1681 | - |
|
1682 | - |
|
1683 | - /** |
|
1684 | - * @deprecated |
|
1685 | - * @param EE_Line_Item $total_line_item |
|
1686 | - * @param EE_Transaction $transaction |
|
1687 | - * @return \EE_Line_Item |
|
1688 | - * @throws \EE_Error |
|
1689 | - */ |
|
1690 | - public static function create_default_tickets_subtotal(EE_Line_Item $total_line_item, $transaction = NULL) |
|
1691 | - { |
|
1692 | - EE_Error::doing_it_wrong('EEH_Line_Item::create_default_tickets_subtotal()', __('Method replaced with EEH_Line_Item::create_pre_tax_subtotal()', 'event_espresso'), '4.6.0'); |
|
1693 | - return self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
1694 | - } |
|
1695 | - |
|
1696 | - |
|
1697 | - /** |
|
1698 | - * @deprecated |
|
1699 | - * @param EE_Line_Item $total_line_item |
|
1700 | - * @param EE_Transaction $transaction |
|
1701 | - * @return \EE_Line_Item |
|
1702 | - * @throws \EE_Error |
|
1703 | - */ |
|
1704 | - public static function create_default_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = NULL) |
|
1705 | - { |
|
1706 | - EE_Error::doing_it_wrong('EEH_Line_Item::create_default_taxes_subtotal()', __('Method replaced with EEH_Line_Item::create_taxes_subtotal()', 'event_espresso'), '4.6.0'); |
|
1707 | - return self::create_taxes_subtotal($total_line_item, $transaction); |
|
1708 | - } |
|
1709 | - |
|
1710 | - |
|
1711 | - /** |
|
1712 | - * @deprecated |
|
1713 | - * @param EE_Line_Item $total_line_item |
|
1714 | - * @param EE_Transaction $transaction |
|
1715 | - * @return \EE_Line_Item |
|
1716 | - * @throws \EE_Error |
|
1717 | - */ |
|
1718 | - public static function create_default_event_subtotal(EE_Line_Item $total_line_item, $transaction = NULL) |
|
1719 | - { |
|
1720 | - EE_Error::doing_it_wrong('EEH_Line_Item::create_default_event_subtotal()', __('Method replaced with EEH_Line_Item::create_event_subtotal()', 'event_espresso'), '4.6.0'); |
|
1721 | - return self::create_event_subtotal($total_line_item, $transaction); |
|
1722 | - } |
|
26 | + //other functions: cancel ticket purchase |
|
27 | + //delete ticket purchase |
|
28 | + //add promotion |
|
29 | + |
|
30 | + |
|
31 | + /** |
|
32 | + * Adds a simple item (unrelated to any other model object) to the provided PARENT line item. |
|
33 | + * Does NOT automatically re-calculate the line item totals or update the related transaction. |
|
34 | + * You should call recalculate_total_including_taxes() on the grant total line item after this |
|
35 | + * to update the subtotals, and EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
36 | + * to keep the registration final prices in-sync with the transaction's total. |
|
37 | + * |
|
38 | + * @param EE_Line_Item $parent_line_item |
|
39 | + * @param string $name |
|
40 | + * @param float $unit_price |
|
41 | + * @param string $description |
|
42 | + * @param int $quantity |
|
43 | + * @param boolean $taxable |
|
44 | + * @param boolean $code if set to a value, ensures there is only one line item with that code |
|
45 | + * @return boolean success |
|
46 | + * @throws \EE_Error |
|
47 | + */ |
|
48 | + public static function add_unrelated_item(EE_Line_Item $parent_line_item, $name, $unit_price, $description = '', $quantity = 1, $taxable = FALSE, $code = NULL) |
|
49 | + { |
|
50 | + $items_subtotal = self::get_pre_tax_subtotal($parent_line_item); |
|
51 | + $line_item = EE_Line_Item::new_instance(array( |
|
52 | + 'LIN_name' => $name, |
|
53 | + 'LIN_desc' => $description, |
|
54 | + 'LIN_unit_price' => $unit_price, |
|
55 | + 'LIN_quantity' => $quantity, |
|
56 | + 'LIN_percent' => null, |
|
57 | + 'LIN_is_taxable' => $taxable, |
|
58 | + 'LIN_order' => $items_subtotal instanceof EE_Line_Item ? count($items_subtotal->children()) : 0, |
|
59 | + 'LIN_total' => (float)$unit_price * (int)$quantity, |
|
60 | + 'LIN_type' => EEM_Line_Item::type_line_item, |
|
61 | + 'LIN_code' => $code, |
|
62 | + )); |
|
63 | + $line_item = apply_filters( |
|
64 | + 'FHEE__EEH_Line_Item__add_unrelated_item__line_item', |
|
65 | + $line_item, |
|
66 | + $parent_line_item |
|
67 | + ); |
|
68 | + return self::add_item($parent_line_item, $line_item); |
|
69 | + } |
|
70 | + |
|
71 | + |
|
72 | + /** |
|
73 | + * Adds a simple item ( unrelated to any other model object) to the total line item, |
|
74 | + * in the correct spot in the line item tree. Automatically |
|
75 | + * re-calculates the line item totals and updates the related transaction. But |
|
76 | + * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
77 | + * should probably change because of this). |
|
78 | + * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
79 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
80 | + * |
|
81 | + * @param EE_Line_Item $parent_line_item |
|
82 | + * @param string $name |
|
83 | + * @param float $percentage_amount |
|
84 | + * @param string $description |
|
85 | + * @param boolean $taxable |
|
86 | + * @return boolean success |
|
87 | + * @throws \EE_Error |
|
88 | + */ |
|
89 | + public static function add_percentage_based_item(EE_Line_Item $parent_line_item, $name, $percentage_amount, $description = '', $taxable = FALSE) |
|
90 | + { |
|
91 | + $line_item = EE_Line_Item::new_instance(array( |
|
92 | + 'LIN_name' => $name, |
|
93 | + 'LIN_desc' => $description, |
|
94 | + 'LIN_unit_price' => 0, |
|
95 | + 'LIN_percent' => $percentage_amount, |
|
96 | + 'LIN_quantity' => 1, |
|
97 | + 'LIN_is_taxable' => $taxable, |
|
98 | + 'LIN_total' => (float)($percentage_amount * ($parent_line_item->total() / 100)), |
|
99 | + 'LIN_type' => EEM_Line_Item::type_line_item, |
|
100 | + 'LIN_parent' => $parent_line_item->ID() |
|
101 | + )); |
|
102 | + $line_item = apply_filters( |
|
103 | + 'FHEE__EEH_Line_Item__add_percentage_based_item__line_item', |
|
104 | + $line_item |
|
105 | + ); |
|
106 | + return $parent_line_item->add_child_line_item($line_item, false); |
|
107 | + } |
|
108 | + |
|
109 | + |
|
110 | + /** |
|
111 | + * Returns the new line item created by adding a purchase of the ticket |
|
112 | + * ensures that ticket line item is saved, and that cart total has been recalculated. |
|
113 | + * If this ticket has already been purchased, just increments its count. |
|
114 | + * Automatically re-calculates the line item totals and updates the related transaction. But |
|
115 | + * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
116 | + * should probably change because of this). |
|
117 | + * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
118 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
119 | + * |
|
120 | + * @param EE_Line_Item $total_line_item grand total line item of type EEM_Line_Item::type_total |
|
121 | + * @param EE_Ticket $ticket |
|
122 | + * @param int $qty |
|
123 | + * @return \EE_Line_Item |
|
124 | + * @throws \EE_Error |
|
125 | + */ |
|
126 | + public static function add_ticket_purchase(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
127 | + { |
|
128 | + if (!$total_line_item instanceof EE_Line_Item || !$total_line_item->is_total()) { |
|
129 | + throw new EE_Error(sprintf(__('A valid line item total is required in order to add tickets. A line item of type "%s" was passed.', 'event_espresso'), $ticket->ID(), $total_line_item->ID())); |
|
130 | + } |
|
131 | + // either increment the qty for an existing ticket |
|
132 | + $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty); |
|
133 | + // or add a new one |
|
134 | + if (!$line_item instanceof EE_Line_Item) { |
|
135 | + $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty); |
|
136 | + } |
|
137 | + $total_line_item->recalculate_total_including_taxes(); |
|
138 | + return $line_item; |
|
139 | + } |
|
140 | + |
|
141 | + |
|
142 | + /** |
|
143 | + * Returns the new line item created by adding a purchase of the ticket |
|
144 | + * @param \EE_Line_Item $total_line_item |
|
145 | + * @param EE_Ticket $ticket |
|
146 | + * @param int $qty |
|
147 | + * @return \EE_Line_Item |
|
148 | + * @throws \EE_Error |
|
149 | + */ |
|
150 | + public static function increment_ticket_qty_if_already_in_cart(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
151 | + { |
|
152 | + $line_item = null; |
|
153 | + if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) { |
|
154 | + $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item); |
|
155 | + foreach ((array)$ticket_line_items as $ticket_line_item) { |
|
156 | + if ( |
|
157 | + $ticket_line_item instanceof EE_Line_Item |
|
158 | + && (int)$ticket_line_item->OBJ_ID() === (int)$ticket->ID() |
|
159 | + ) { |
|
160 | + $line_item = $ticket_line_item; |
|
161 | + break; |
|
162 | + } |
|
163 | + } |
|
164 | + } |
|
165 | + if ($line_item instanceof EE_Line_Item) { |
|
166 | + EEH_Line_Item::increment_quantity($line_item, $qty); |
|
167 | + return $line_item; |
|
168 | + } |
|
169 | + return null; |
|
170 | + } |
|
171 | + |
|
172 | + |
|
173 | + /** |
|
174 | + * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
175 | + * Does NOT save or recalculate other line items totals |
|
176 | + * |
|
177 | + * @param EE_Line_Item $line_item |
|
178 | + * @param int $qty |
|
179 | + * @return void |
|
180 | + * @throws \EE_Error |
|
181 | + */ |
|
182 | + public static function increment_quantity(EE_Line_Item $line_item, $qty = 1) |
|
183 | + { |
|
184 | + if (!$line_item->is_percent()) { |
|
185 | + $qty += $line_item->quantity(); |
|
186 | + $line_item->set_quantity($qty); |
|
187 | + $line_item->set_total($line_item->unit_price() * $qty); |
|
188 | + $line_item->save(); |
|
189 | + } |
|
190 | + foreach ($line_item->children() as $child) { |
|
191 | + if ($child->is_sub_line_item()) { |
|
192 | + EEH_Line_Item::update_quantity($child, $qty); |
|
193 | + } |
|
194 | + } |
|
195 | + } |
|
196 | + |
|
197 | + |
|
198 | + /** |
|
199 | + * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
200 | + * Does NOT save or recalculate other line items totals |
|
201 | + * |
|
202 | + * @param EE_Line_Item $line_item |
|
203 | + * @param int $qty |
|
204 | + * @return void |
|
205 | + * @throws \EE_Error |
|
206 | + */ |
|
207 | + public static function decrement_quantity(EE_Line_Item $line_item, $qty = 1) |
|
208 | + { |
|
209 | + if (!$line_item->is_percent()) { |
|
210 | + $qty = $line_item->quantity() - $qty; |
|
211 | + $qty = max($qty, 0); |
|
212 | + $line_item->set_quantity($qty); |
|
213 | + $line_item->set_total($line_item->unit_price() * $qty); |
|
214 | + $line_item->save(); |
|
215 | + } |
|
216 | + foreach ($line_item->children() as $child) { |
|
217 | + if ($child->is_sub_line_item()) { |
|
218 | + EEH_Line_Item::update_quantity($child, $qty); |
|
219 | + } |
|
220 | + } |
|
221 | + } |
|
222 | + |
|
223 | + |
|
224 | + /** |
|
225 | + * Updates the line item and its children's quantities to the specified number. |
|
226 | + * Does NOT save them or recalculate totals. |
|
227 | + * |
|
228 | + * @param EE_Line_Item $line_item |
|
229 | + * @param int $new_quantity |
|
230 | + * @throws \EE_Error |
|
231 | + */ |
|
232 | + public static function update_quantity(EE_Line_Item $line_item, $new_quantity) |
|
233 | + { |
|
234 | + if (!$line_item->is_percent()) { |
|
235 | + $line_item->set_quantity($new_quantity); |
|
236 | + $line_item->set_total($line_item->unit_price() * $new_quantity); |
|
237 | + $line_item->save(); |
|
238 | + } |
|
239 | + foreach ($line_item->children() as $child) { |
|
240 | + if ($child->is_sub_line_item()) { |
|
241 | + EEH_Line_Item::update_quantity($child, $new_quantity); |
|
242 | + } |
|
243 | + } |
|
244 | + } |
|
245 | + |
|
246 | + |
|
247 | + /** |
|
248 | + * Returns the new line item created by adding a purchase of the ticket |
|
249 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
250 | + * @param EE_Ticket $ticket |
|
251 | + * @param int $qty |
|
252 | + * @return \EE_Line_Item |
|
253 | + * @throws \EE_Error |
|
254 | + */ |
|
255 | + public static function create_ticket_line_item(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
256 | + { |
|
257 | + $datetimes = $ticket->datetimes(); |
|
258 | + $first_datetime = reset($datetimes); |
|
259 | + if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) { |
|
260 | + $first_datetime_name = $first_datetime->event()->name(); |
|
261 | + } else { |
|
262 | + $first_datetime_name = __('Event', 'event_espresso'); |
|
263 | + } |
|
264 | + $event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name); |
|
265 | + // get event subtotal line |
|
266 | + $events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket); |
|
267 | + // add $ticket to cart |
|
268 | + $line_item = EE_Line_Item::new_instance(array( |
|
269 | + 'LIN_name' => $ticket->name(), |
|
270 | + 'LIN_desc' => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event, |
|
271 | + 'LIN_unit_price' => $ticket->price(), |
|
272 | + 'LIN_quantity' => $qty, |
|
273 | + 'LIN_is_taxable' => $ticket->taxable(), |
|
274 | + 'LIN_order' => count($events_sub_total->children()), |
|
275 | + 'LIN_total' => $ticket->price() * $qty, |
|
276 | + 'LIN_type' => EEM_Line_Item::type_line_item, |
|
277 | + 'OBJ_ID' => $ticket->ID(), |
|
278 | + 'OBJ_type' => 'Ticket' |
|
279 | + )); |
|
280 | + $line_item = apply_filters( |
|
281 | + 'FHEE__EEH_Line_Item__create_ticket_line_item__line_item', |
|
282 | + $line_item |
|
283 | + ); |
|
284 | + $events_sub_total->add_child_line_item($line_item); |
|
285 | + //now add the sub-line items |
|
286 | + $running_total_for_ticket = 0; |
|
287 | + foreach ($ticket->prices(array('order_by' => array('PRC_order' => 'ASC'))) as $price) { |
|
288 | + $sign = $price->is_discount() ? -1 : 1; |
|
289 | + $price_total = $price->is_percent() |
|
290 | + ? $running_total_for_ticket * $price->amount() / 100 |
|
291 | + : $price->amount() * $qty; |
|
292 | + $sub_line_item = EE_Line_Item::new_instance(array( |
|
293 | + 'LIN_name' => $price->name(), |
|
294 | + 'LIN_desc' => $price->desc(), |
|
295 | + 'LIN_quantity' => $price->is_percent() ? null : $qty, |
|
296 | + 'LIN_is_taxable' => false, |
|
297 | + 'LIN_order' => $price->order(), |
|
298 | + 'LIN_total' => $sign * $price_total, |
|
299 | + 'LIN_type' => EEM_Line_Item::type_sub_line_item, |
|
300 | + 'OBJ_ID' => $price->ID(), |
|
301 | + 'OBJ_type' => 'Price' |
|
302 | + )); |
|
303 | + $sub_line_item = apply_filters( |
|
304 | + 'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item', |
|
305 | + $sub_line_item |
|
306 | + ); |
|
307 | + if ($price->is_percent()) { |
|
308 | + $sub_line_item->set_percent($sign * $price->amount()); |
|
309 | + } else { |
|
310 | + $sub_line_item->set_unit_price($sign * $price->amount()); |
|
311 | + } |
|
312 | + $running_total_for_ticket += $price_total; |
|
313 | + $line_item->add_child_line_item($sub_line_item); |
|
314 | + } |
|
315 | + return $line_item; |
|
316 | + } |
|
317 | + |
|
318 | + |
|
319 | + /** |
|
320 | + * Adds the specified item under the pre-tax-sub-total line item. Automatically |
|
321 | + * re-calculates the line item totals and updates the related transaction. But |
|
322 | + * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
323 | + * should probably change because of this). |
|
324 | + * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
325 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
326 | + * |
|
327 | + * @param EE_Line_Item $total_line_item |
|
328 | + * @param EE_Line_Item $item to be added |
|
329 | + * @return boolean |
|
330 | + * @throws \EE_Error |
|
331 | + */ |
|
332 | + public static function add_item(EE_Line_Item $total_line_item, EE_Line_Item $item) |
|
333 | + { |
|
334 | + $pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item); |
|
335 | + if ($pre_tax_subtotal instanceof EE_Line_Item) { |
|
336 | + $success = $pre_tax_subtotal->add_child_line_item($item); |
|
337 | + } else { |
|
338 | + return FALSE; |
|
339 | + } |
|
340 | + $total_line_item->recalculate_total_including_taxes(); |
|
341 | + return $success; |
|
342 | + } |
|
343 | + |
|
344 | + |
|
345 | + /** |
|
346 | + * cancels an existing ticket line item, |
|
347 | + * by decrementing it's quantity by 1 and adding a new "type_cancellation" sub-line-item. |
|
348 | + * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
349 | + * |
|
350 | + * @param EE_Line_Item $ticket_line_item |
|
351 | + * @param int $qty |
|
352 | + * @return bool success |
|
353 | + * @throws \EE_Error |
|
354 | + */ |
|
355 | + public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
356 | + { |
|
357 | + // validate incoming line_item |
|
358 | + if ($ticket_line_item->OBJ_type() !== 'Ticket') { |
|
359 | + throw new EE_Error( |
|
360 | + sprintf( |
|
361 | + __('The supplied line item must have an Object Type of "Ticket", not %1$s.', 'event_espresso'), |
|
362 | + $ticket_line_item->type() |
|
363 | + ) |
|
364 | + ); |
|
365 | + } |
|
366 | + if ($ticket_line_item->quantity() < $qty) { |
|
367 | + throw new EE_Error( |
|
368 | + sprintf( |
|
369 | + __('Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.', 'event_espresso'), |
|
370 | + $qty, |
|
371 | + $ticket_line_item->quantity() |
|
372 | + ) |
|
373 | + ); |
|
374 | + } |
|
375 | + // decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this |
|
376 | + $ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty); |
|
377 | + foreach ($ticket_line_item->children() as $child_line_item) { |
|
378 | + if ( |
|
379 | + $child_line_item->is_sub_line_item() |
|
380 | + && !$child_line_item->is_percent() |
|
381 | + && !$child_line_item->is_cancellation() |
|
382 | + ) { |
|
383 | + $child_line_item->set_quantity($child_line_item->quantity() - $qty); |
|
384 | + } |
|
385 | + } |
|
386 | + // get cancellation sub line item |
|
387 | + $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
388 | + $ticket_line_item, |
|
389 | + EEM_Line_Item::type_cancellation |
|
390 | + ); |
|
391 | + $cancellation_line_item = reset($cancellation_line_item); |
|
392 | + // verify that this ticket was indeed previously cancelled |
|
393 | + if ($cancellation_line_item instanceof EE_Line_Item) { |
|
394 | + // increment cancelled quantity |
|
395 | + $cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty); |
|
396 | + } else { |
|
397 | + // create cancellation sub line item |
|
398 | + $cancellation_line_item = EE_Line_Item::new_instance(array( |
|
399 | + 'LIN_name' => __('Cancellation', 'event_espresso'), |
|
400 | + 'LIN_desc' => sprintf( |
|
401 | + _x('Cancelled %1$s : %2$s', 'Cancelled Ticket Name : 2015-01-01 11:11', 'event_espresso'), |
|
402 | + $ticket_line_item->name(), |
|
403 | + current_time(get_option('date_format') . ' ' . get_option('time_format')) |
|
404 | + ), |
|
405 | + 'LIN_unit_price' => 0, // $ticket_line_item->unit_price() |
|
406 | + 'LIN_quantity' => $qty, |
|
407 | + 'LIN_is_taxable' => $ticket_line_item->is_taxable(), |
|
408 | + 'LIN_order' => count($ticket_line_item->children()), |
|
409 | + 'LIN_total' => 0, // $ticket_line_item->unit_price() |
|
410 | + 'LIN_type' => EEM_Line_Item::type_cancellation, |
|
411 | + )); |
|
412 | + $ticket_line_item->add_child_line_item($cancellation_line_item); |
|
413 | + } |
|
414 | + if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
415 | + // decrement parent line item quantity |
|
416 | + $event_line_item = $ticket_line_item->parent(); |
|
417 | + if ($event_line_item instanceof EE_Line_Item && $event_line_item->OBJ_type() === 'Event') { |
|
418 | + $event_line_item->set_quantity($event_line_item->quantity() - $qty); |
|
419 | + $event_line_item->save(); |
|
420 | + } |
|
421 | + EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
422 | + return true; |
|
423 | + } |
|
424 | + return false; |
|
425 | + } |
|
426 | + |
|
427 | + |
|
428 | + /** |
|
429 | + * reinstates (un-cancels?) a previously canceled ticket line item, |
|
430 | + * by incrementing it's quantity by 1, and decrementing it's "type_cancellation" sub-line-item. |
|
431 | + * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
432 | + * |
|
433 | + * @param EE_Line_Item $ticket_line_item |
|
434 | + * @param int $qty |
|
435 | + * @return bool success |
|
436 | + * @throws \EE_Error |
|
437 | + */ |
|
438 | + public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
439 | + { |
|
440 | + // validate incoming line_item |
|
441 | + if ($ticket_line_item->OBJ_type() !== 'Ticket') { |
|
442 | + throw new EE_Error( |
|
443 | + sprintf( |
|
444 | + __('The supplied line item must have an Object Type of "Ticket", not %1$s.', 'event_espresso'), |
|
445 | + $ticket_line_item->type() |
|
446 | + ) |
|
447 | + ); |
|
448 | + } |
|
449 | + // get cancellation sub line item |
|
450 | + $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
451 | + $ticket_line_item, |
|
452 | + EEM_Line_Item::type_cancellation |
|
453 | + ); |
|
454 | + $cancellation_line_item = reset($cancellation_line_item); |
|
455 | + // verify that this ticket was indeed previously cancelled |
|
456 | + if (!$cancellation_line_item instanceof EE_Line_Item) { |
|
457 | + return false; |
|
458 | + } |
|
459 | + if ($cancellation_line_item->quantity() > $qty) { |
|
460 | + // decrement cancelled quantity |
|
461 | + $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
462 | + } else if ($cancellation_line_item->quantity() == $qty) { |
|
463 | + // decrement cancelled quantity in case anyone still has the object kicking around |
|
464 | + $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
465 | + // delete because quantity will end up as 0 |
|
466 | + $cancellation_line_item->delete(); |
|
467 | + // and attempt to destroy the object, |
|
468 | + // even though PHP won't actually destroy it until it needs the memory |
|
469 | + unset($cancellation_line_item); |
|
470 | + } else { |
|
471 | + // what ?!?! negative quantity ?!?! |
|
472 | + throw new EE_Error( |
|
473 | + sprintf( |
|
474 | + __('Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.', |
|
475 | + 'event_espresso'), |
|
476 | + $qty, |
|
477 | + $cancellation_line_item->quantity() |
|
478 | + ) |
|
479 | + ); |
|
480 | + } |
|
481 | + // increment ticket quantity |
|
482 | + $ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty); |
|
483 | + if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
484 | + // increment parent line item quantity |
|
485 | + $event_line_item = $ticket_line_item->parent(); |
|
486 | + if ($event_line_item instanceof EE_Line_Item && $event_line_item->OBJ_type() === 'Event') { |
|
487 | + $event_line_item->set_quantity($event_line_item->quantity() + $qty); |
|
488 | + } |
|
489 | + EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
490 | + return true; |
|
491 | + } |
|
492 | + return false; |
|
493 | + } |
|
494 | + |
|
495 | + |
|
496 | + /** |
|
497 | + * calls EEH_Line_Item::find_transaction_grand_total_for_line_item() |
|
498 | + * then EE_Line_Item::recalculate_total_including_taxes() on the result |
|
499 | + * |
|
500 | + * @param EE_Line_Item $line_item |
|
501 | + * @return \EE_Line_Item |
|
502 | + */ |
|
503 | + public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item) |
|
504 | + { |
|
505 | + $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item); |
|
506 | + return $grand_total_line_item->recalculate_total_including_taxes(); |
|
507 | + } |
|
508 | + |
|
509 | + |
|
510 | + /** |
|
511 | + * Gets the line item which contains the subtotal of all the items |
|
512 | + * |
|
513 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
514 | + * @return \EE_Line_Item |
|
515 | + * @throws \EE_Error |
|
516 | + */ |
|
517 | + public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item) |
|
518 | + { |
|
519 | + $pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal'); |
|
520 | + return $pre_tax_subtotal instanceof EE_Line_Item |
|
521 | + ? $pre_tax_subtotal |
|
522 | + : self::create_pre_tax_subtotal($total_line_item); |
|
523 | + } |
|
524 | + |
|
525 | + |
|
526 | + /** |
|
527 | + * Gets the line item for the taxes subtotal |
|
528 | + * |
|
529 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
530 | + * @return \EE_Line_Item |
|
531 | + * @throws \EE_Error |
|
532 | + */ |
|
533 | + public static function get_taxes_subtotal(EE_Line_Item $total_line_item) |
|
534 | + { |
|
535 | + $taxes = $total_line_item->get_child_line_item('taxes'); |
|
536 | + return $taxes ? $taxes : self::create_taxes_subtotal($total_line_item); |
|
537 | + } |
|
538 | + |
|
539 | + |
|
540 | + /** |
|
541 | + * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object |
|
542 | + * |
|
543 | + * @param EE_Line_Item $line_item |
|
544 | + * @param EE_Transaction $transaction |
|
545 | + * @return void |
|
546 | + * @throws \EE_Error |
|
547 | + */ |
|
548 | + public static function set_TXN_ID(EE_Line_Item $line_item, $transaction = NULL) |
|
549 | + { |
|
550 | + if ($transaction) { |
|
551 | + /** @type EEM_Transaction $EEM_Transaction */ |
|
552 | + $EEM_Transaction = EE_Registry::instance()->load_model('Transaction'); |
|
553 | + $TXN_ID = $EEM_Transaction->ensure_is_ID($transaction); |
|
554 | + $line_item->set_TXN_ID($TXN_ID); |
|
555 | + } |
|
556 | + } |
|
557 | + |
|
558 | + |
|
559 | + /** |
|
560 | + * Creates a new default total line item for the transaction, |
|
561 | + * and its tickets subtotal and taxes subtotal line items (and adds the |
|
562 | + * existing taxes as children of the taxes subtotal line item) |
|
563 | + * |
|
564 | + * @param EE_Transaction $transaction |
|
565 | + * @return \EE_Line_Item of type total |
|
566 | + * @throws \EE_Error |
|
567 | + */ |
|
568 | + public static function create_total_line_item($transaction = NULL) |
|
569 | + { |
|
570 | + $total_line_item = EE_Line_Item::new_instance(array( |
|
571 | + 'LIN_code' => 'total', |
|
572 | + 'LIN_name' => __('Grand Total', 'event_espresso'), |
|
573 | + 'LIN_type' => EEM_Line_Item::type_total, |
|
574 | + 'OBJ_type' => 'Transaction' |
|
575 | + )); |
|
576 | + $total_line_item = apply_filters( |
|
577 | + 'FHEE__EEH_Line_Item__create_total_line_item__total_line_item', |
|
578 | + $total_line_item |
|
579 | + ); |
|
580 | + self::set_TXN_ID($total_line_item, $transaction); |
|
581 | + self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
582 | + self::create_taxes_subtotal($total_line_item, $transaction); |
|
583 | + return $total_line_item; |
|
584 | + } |
|
585 | + |
|
586 | + |
|
587 | + /** |
|
588 | + * Creates a default items subtotal line item |
|
589 | + * |
|
590 | + * @param EE_Line_Item $total_line_item |
|
591 | + * @param EE_Transaction $transaction |
|
592 | + * @return EE_Line_Item |
|
593 | + * @throws \EE_Error |
|
594 | + */ |
|
595 | + protected static function create_pre_tax_subtotal(EE_Line_Item $total_line_item, $transaction = NULL) |
|
596 | + { |
|
597 | + $pre_tax_line_item = EE_Line_Item::new_instance(array( |
|
598 | + 'LIN_code' => 'pre-tax-subtotal', |
|
599 | + 'LIN_name' => __('Pre-Tax Subtotal', 'event_espresso'), |
|
600 | + 'LIN_type' => EEM_Line_Item::type_sub_total |
|
601 | + )); |
|
602 | + $pre_tax_line_item = apply_filters( |
|
603 | + 'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item', |
|
604 | + $pre_tax_line_item |
|
605 | + ); |
|
606 | + self::set_TXN_ID($pre_tax_line_item, $transaction); |
|
607 | + $total_line_item->add_child_line_item($pre_tax_line_item); |
|
608 | + self::create_event_subtotal($pre_tax_line_item, $transaction); |
|
609 | + return $pre_tax_line_item; |
|
610 | + } |
|
611 | + |
|
612 | + |
|
613 | + /** |
|
614 | + * Creates a line item for the taxes subtotal and finds all the tax prices |
|
615 | + * and applies taxes to it |
|
616 | + * |
|
617 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
618 | + * @param EE_Transaction $transaction |
|
619 | + * @return EE_Line_Item |
|
620 | + * @throws \EE_Error |
|
621 | + */ |
|
622 | + protected static function create_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = NULL) |
|
623 | + { |
|
624 | + $tax_line_item = EE_Line_Item::new_instance(array( |
|
625 | + 'LIN_code' => 'taxes', |
|
626 | + 'LIN_name' => __('Taxes', 'event_espresso'), |
|
627 | + 'LIN_type' => EEM_Line_Item::type_tax_sub_total, |
|
628 | + 'LIN_order' => 1000,//this should always come last |
|
629 | + )); |
|
630 | + $tax_line_item = apply_filters( |
|
631 | + 'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item', |
|
632 | + $tax_line_item |
|
633 | + ); |
|
634 | + self::set_TXN_ID($tax_line_item, $transaction); |
|
635 | + $total_line_item->add_child_line_item($tax_line_item); |
|
636 | + //and lastly, add the actual taxes |
|
637 | + self::apply_taxes($total_line_item); |
|
638 | + return $tax_line_item; |
|
639 | + } |
|
640 | + |
|
641 | + |
|
642 | + /** |
|
643 | + * Creates a default items subtotal line item |
|
644 | + * |
|
645 | + * @param EE_Line_Item $pre_tax_line_item |
|
646 | + * @param EE_Transaction $transaction |
|
647 | + * @param EE_Event $event |
|
648 | + * @return EE_Line_Item |
|
649 | + * @throws \EE_Error |
|
650 | + */ |
|
651 | + public static function create_event_subtotal(EE_Line_Item $pre_tax_line_item, $transaction = NULL, $event = NULL) |
|
652 | + { |
|
653 | + $event_line_item = EE_Line_Item::new_instance(array( |
|
654 | + 'LIN_code' => self::get_event_code($event), |
|
655 | + 'LIN_name' => self::get_event_name($event), |
|
656 | + 'LIN_desc' => self::get_event_desc($event), |
|
657 | + 'LIN_type' => EEM_Line_Item::type_sub_total, |
|
658 | + 'OBJ_type' => 'Event', |
|
659 | + 'OBJ_ID' => $event instanceof EE_Event ? $event->ID() : 0 |
|
660 | + )); |
|
661 | + $event_line_item = apply_filters( |
|
662 | + 'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item', |
|
663 | + $event_line_item |
|
664 | + ); |
|
665 | + self::set_TXN_ID($event_line_item, $transaction); |
|
666 | + $pre_tax_line_item->add_child_line_item($event_line_item); |
|
667 | + return $event_line_item; |
|
668 | + } |
|
669 | + |
|
670 | + |
|
671 | + /** |
|
672 | + * Gets what the event ticket's code SHOULD be |
|
673 | + * |
|
674 | + * @param EE_Event $event |
|
675 | + * @return string |
|
676 | + * @throws \EE_Error |
|
677 | + */ |
|
678 | + public static function get_event_code($event) |
|
679 | + { |
|
680 | + return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0'); |
|
681 | + } |
|
682 | + |
|
683 | + /** |
|
684 | + * Gets the event name |
|
685 | + * @param EE_Event $event |
|
686 | + * @return string |
|
687 | + */ |
|
688 | + public static function get_event_name($event) |
|
689 | + { |
|
690 | + return $event instanceof EE_Event ? $event->name() : __('Event', 'event_espresso'); |
|
691 | + } |
|
692 | + |
|
693 | + /** |
|
694 | + * Gets the event excerpt |
|
695 | + * @param EE_Event $event |
|
696 | + * @return string |
|
697 | + */ |
|
698 | + public static function get_event_desc($event) |
|
699 | + { |
|
700 | + return $event instanceof EE_Event ? $event->short_description() : ''; |
|
701 | + } |
|
702 | + |
|
703 | + /** |
|
704 | + * Given the grand total line item and a ticket, finds the event sub-total |
|
705 | + * line item the ticket's purchase should be added onto |
|
706 | + * |
|
707 | + * @access public |
|
708 | + * @param EE_Line_Item $grand_total the grand total line item |
|
709 | + * @param EE_Ticket $ticket |
|
710 | + * @throws \EE_Error |
|
711 | + * @return EE_Line_Item |
|
712 | + */ |
|
713 | + public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket) |
|
714 | + { |
|
715 | + $first_datetime = $ticket->first_datetime(); |
|
716 | + if (!$first_datetime instanceof EE_Datetime) { |
|
717 | + throw new EE_Error( |
|
718 | + sprintf(__('The supplied ticket (ID %d) has no datetimes', 'event_espresso'), $ticket->ID()) |
|
719 | + ); |
|
720 | + } |
|
721 | + $event = $first_datetime->event(); |
|
722 | + if (!$event instanceof EE_Event) { |
|
723 | + throw new EE_Error( |
|
724 | + sprintf( |
|
725 | + __('The supplied ticket (ID %d) has no event data associated with it.', 'event_espresso'), |
|
726 | + $ticket->ID() |
|
727 | + ) |
|
728 | + ); |
|
729 | + } |
|
730 | + $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event); |
|
731 | + if (!$events_sub_total instanceof EE_Line_Item) { |
|
732 | + throw new EE_Error( |
|
733 | + sprintf( |
|
734 | + __('There is no events sub-total for ticket %s on total line item %d', 'event_espresso'), |
|
735 | + $ticket->ID(), |
|
736 | + $grand_total->ID() |
|
737 | + ) |
|
738 | + ); |
|
739 | + } |
|
740 | + return $events_sub_total; |
|
741 | + } |
|
742 | + |
|
743 | + |
|
744 | + /** |
|
745 | + * Gets the event line item |
|
746 | + * |
|
747 | + * @param EE_Line_Item $grand_total |
|
748 | + * @param EE_Event $event |
|
749 | + * @return EE_Line_Item for the event subtotal which is a child of $grand_total |
|
750 | + * @throws \EE_Error |
|
751 | + */ |
|
752 | + public static function get_event_line_item(EE_Line_Item $grand_total, $event) |
|
753 | + { |
|
754 | + /** @type EE_Event $event */ |
|
755 | + $event = EEM_Event::instance()->ensure_is_obj($event, true); |
|
756 | + $event_line_item = NULL; |
|
757 | + $found = false; |
|
758 | + foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) { |
|
759 | + // default event subtotal, we should only ever find this the first time this method is called |
|
760 | + if (!$event_line_item->OBJ_ID()) { |
|
761 | + // let's use this! but first... set the event details |
|
762 | + EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
763 | + $found = true; |
|
764 | + break; |
|
765 | + } else if ($event_line_item->OBJ_ID() === $event->ID()) { |
|
766 | + // found existing line item for this event in the cart, so break out of loop and use this one |
|
767 | + $found = true; |
|
768 | + break; |
|
769 | + } |
|
770 | + } |
|
771 | + if (!$found) { |
|
772 | + //there is no event sub-total yet, so add it |
|
773 | + $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total); |
|
774 | + // create a new "event" subtotal below that |
|
775 | + $event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event); |
|
776 | + // and set the event details |
|
777 | + EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
778 | + } |
|
779 | + return $event_line_item; |
|
780 | + } |
|
781 | + |
|
782 | + |
|
783 | + /** |
|
784 | + * Creates a default items subtotal line item |
|
785 | + * |
|
786 | + * @param EE_Line_Item $event_line_item |
|
787 | + * @param EE_Event $event |
|
788 | + * @param EE_Transaction $transaction |
|
789 | + * @return EE_Line_Item |
|
790 | + * @throws \EE_Error |
|
791 | + */ |
|
792 | + public static function set_event_subtotal_details( |
|
793 | + EE_Line_Item $event_line_item, |
|
794 | + EE_Event $event, |
|
795 | + $transaction = null |
|
796 | + ) |
|
797 | + { |
|
798 | + if ($event instanceof EE_Event) { |
|
799 | + $event_line_item->set_code(self::get_event_code($event)); |
|
800 | + $event_line_item->set_name(self::get_event_name($event)); |
|
801 | + $event_line_item->set_desc(self::get_event_desc($event)); |
|
802 | + $event_line_item->set_OBJ_ID($event->ID()); |
|
803 | + } |
|
804 | + self::set_TXN_ID($event_line_item, $transaction); |
|
805 | + } |
|
806 | + |
|
807 | + |
|
808 | + /** |
|
809 | + * Finds what taxes should apply, adds them as tax line items under the taxes sub-total, |
|
810 | + * and recalculates the taxes sub-total and the grand total. Resets the taxes, so |
|
811 | + * any old taxes are removed |
|
812 | + * |
|
813 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
814 | + * @throws \EE_Error |
|
815 | + */ |
|
816 | + public static function apply_taxes(EE_Line_Item $total_line_item) |
|
817 | + { |
|
818 | + /** @type EEM_Price $EEM_Price */ |
|
819 | + $EEM_Price = EE_Registry::instance()->load_model('Price'); |
|
820 | + // get array of taxes via Price Model |
|
821 | + $ordered_taxes = $EEM_Price->get_all_prices_that_are_taxes(); |
|
822 | + ksort($ordered_taxes); |
|
823 | + $taxes_line_item = self::get_taxes_subtotal($total_line_item); |
|
824 | + //just to be safe, remove its old tax line items |
|
825 | + $taxes_line_item->delete_children_line_items(); |
|
826 | + //loop thru taxes |
|
827 | + foreach ($ordered_taxes as $order => $taxes) { |
|
828 | + foreach ($taxes as $tax) { |
|
829 | + if ($tax instanceof EE_Price) { |
|
830 | + $tax_line_item = EE_Line_Item::new_instance( |
|
831 | + array( |
|
832 | + 'LIN_name' => $tax->name(), |
|
833 | + 'LIN_desc' => $tax->desc(), |
|
834 | + 'LIN_percent' => $tax->amount(), |
|
835 | + 'LIN_is_taxable' => false, |
|
836 | + 'LIN_order' => $order, |
|
837 | + 'LIN_total' => 0, |
|
838 | + 'LIN_type' => EEM_Line_Item::type_tax, |
|
839 | + 'OBJ_type' => 'Price', |
|
840 | + 'OBJ_ID' => $tax->ID() |
|
841 | + ) |
|
842 | + ); |
|
843 | + $tax_line_item = apply_filters( |
|
844 | + 'FHEE__EEH_Line_Item__apply_taxes__tax_line_item', |
|
845 | + $tax_line_item |
|
846 | + ); |
|
847 | + $taxes_line_item->add_child_line_item($tax_line_item); |
|
848 | + } |
|
849 | + } |
|
850 | + } |
|
851 | + $total_line_item->recalculate_total_including_taxes(); |
|
852 | + } |
|
853 | + |
|
854 | + |
|
855 | + /** |
|
856 | + * Ensures that taxes have been applied to the order, if not applies them. |
|
857 | + * Returns the total amount of tax |
|
858 | + * |
|
859 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
860 | + * @return float |
|
861 | + * @throws \EE_Error |
|
862 | + */ |
|
863 | + public static function ensure_taxes_applied($total_line_item) |
|
864 | + { |
|
865 | + $taxes_subtotal = self::get_taxes_subtotal($total_line_item); |
|
866 | + if (!$taxes_subtotal->children()) { |
|
867 | + self::apply_taxes($total_line_item); |
|
868 | + } |
|
869 | + return $taxes_subtotal->total(); |
|
870 | + } |
|
871 | + |
|
872 | + |
|
873 | + /** |
|
874 | + * Deletes ALL children of the passed line item |
|
875 | + * |
|
876 | + * @param EE_Line_Item $parent_line_item |
|
877 | + * @return bool |
|
878 | + * @throws \EE_Error |
|
879 | + */ |
|
880 | + public static function delete_all_child_items(EE_Line_Item $parent_line_item) |
|
881 | + { |
|
882 | + $deleted = 0; |
|
883 | + foreach ($parent_line_item->children() as $child_line_item) { |
|
884 | + if ($child_line_item instanceof EE_Line_Item) { |
|
885 | + $deleted += EEH_Line_Item::delete_all_child_items($child_line_item); |
|
886 | + if ($child_line_item->ID()) { |
|
887 | + $child_line_item->delete(); |
|
888 | + unset($child_line_item); |
|
889 | + } else { |
|
890 | + $parent_line_item->delete_child_line_item($child_line_item->code()); |
|
891 | + } |
|
892 | + $deleted++; |
|
893 | + } |
|
894 | + } |
|
895 | + return $deleted; |
|
896 | + } |
|
897 | + |
|
898 | + |
|
899 | + /** |
|
900 | + * Deletes the line items as indicated by the line item code(s) provided, |
|
901 | + * regardless of where they're found in the line item tree. Automatically |
|
902 | + * re-calculates the line item totals and updates the related transaction. But |
|
903 | + * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
904 | + * should probably change because of this). |
|
905 | + * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
906 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
907 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
908 | + * @param array|bool|string $line_item_codes |
|
909 | + * @return int number of items successfully removed |
|
910 | + */ |
|
911 | + public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = FALSE) |
|
912 | + { |
|
913 | + |
|
914 | + if ($total_line_item->type() !== EEM_Line_Item::type_total) { |
|
915 | + EE_Error::doing_it_wrong( |
|
916 | + 'EEH_Line_Item::delete_items', |
|
917 | + __( |
|
918 | + 'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly', |
|
919 | + 'event_espresso' |
|
920 | + ), |
|
921 | + '4.6.18' |
|
922 | + ); |
|
923 | + } |
|
924 | + do_action('AHEE_log', __FILE__, __FUNCTION__, ''); |
|
925 | + |
|
926 | + // check if only a single line_item_id was passed |
|
927 | + if (!empty($line_item_codes) && !is_array($line_item_codes)) { |
|
928 | + // place single line_item_id in an array to appear as multiple line_item_ids |
|
929 | + $line_item_codes = array($line_item_codes); |
|
930 | + } |
|
931 | + $removals = 0; |
|
932 | + // cycle thru line_item_ids |
|
933 | + foreach ($line_item_codes as $line_item_id) { |
|
934 | + $removals += $total_line_item->delete_child_line_item($line_item_id); |
|
935 | + } |
|
936 | + |
|
937 | + if ($removals > 0) { |
|
938 | + $total_line_item->recalculate_taxes_and_tax_total(); |
|
939 | + return $removals; |
|
940 | + } else { |
|
941 | + return FALSE; |
|
942 | + } |
|
943 | + } |
|
944 | + |
|
945 | + |
|
946 | + /** |
|
947 | + * Overwrites the previous tax by clearing out the old taxes, and creates a new |
|
948 | + * tax and updates the total line item accordingly |
|
949 | + * |
|
950 | + * @param EE_Line_Item $total_line_item |
|
951 | + * @param float $amount |
|
952 | + * @param string $name |
|
953 | + * @param string $description |
|
954 | + * @param string $code |
|
955 | + * @param boolean $add_to_existing_line_item |
|
956 | + * if true, and a duplicate line item with the same code is found, |
|
957 | + * $amount will be added onto it; otherwise will simply set the taxes to match $amount |
|
958 | + * @return EE_Line_Item the new tax line item created |
|
959 | + * @throws \EE_Error |
|
960 | + */ |
|
961 | + public static function set_total_tax_to( |
|
962 | + EE_Line_Item $total_line_item, |
|
963 | + $amount, |
|
964 | + $name = null, |
|
965 | + $description = null, |
|
966 | + $code = null, |
|
967 | + $add_to_existing_line_item = false |
|
968 | + ) |
|
969 | + { |
|
970 | + $tax_subtotal = self::get_taxes_subtotal($total_line_item); |
|
971 | + $taxable_total = $total_line_item->taxable_total(); |
|
972 | + |
|
973 | + if ($add_to_existing_line_item) { |
|
974 | + $new_tax = $tax_subtotal->get_child_line_item($code); |
|
975 | + EEM_Line_Item::instance()->delete( |
|
976 | + array(array('LIN_code' => array('!=', $code), 'LIN_parent' => $tax_subtotal->ID())) |
|
977 | + ); |
|
978 | + } else { |
|
979 | + $new_tax = null; |
|
980 | + $tax_subtotal->delete_children_line_items(); |
|
981 | + } |
|
982 | + if ($new_tax) { |
|
983 | + $new_tax->set_total($new_tax->total() + $amount); |
|
984 | + $new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0); |
|
985 | + } else { |
|
986 | + //no existing tax item. Create it |
|
987 | + $new_tax = EE_Line_Item::new_instance(array( |
|
988 | + 'TXN_ID' => $total_line_item->TXN_ID(), |
|
989 | + 'LIN_name' => $name ? $name : __('Tax', 'event_espresso'), |
|
990 | + 'LIN_desc' => $description ? $description : '', |
|
991 | + 'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0, |
|
992 | + 'LIN_total' => $amount, |
|
993 | + 'LIN_parent' => $tax_subtotal->ID(), |
|
994 | + 'LIN_type' => EEM_Line_Item::type_tax, |
|
995 | + 'LIN_code' => $code |
|
996 | + )); |
|
997 | + } |
|
998 | + |
|
999 | + $new_tax = apply_filters( |
|
1000 | + 'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal', |
|
1001 | + $new_tax, |
|
1002 | + $total_line_item |
|
1003 | + ); |
|
1004 | + $new_tax->save(); |
|
1005 | + $tax_subtotal->set_total($new_tax->total()); |
|
1006 | + $tax_subtotal->save(); |
|
1007 | + $total_line_item->recalculate_total_including_taxes(); |
|
1008 | + return $new_tax; |
|
1009 | + } |
|
1010 | + |
|
1011 | + |
|
1012 | + /** |
|
1013 | + * Makes all the line items which are children of $line_item taxable (or not). |
|
1014 | + * Does NOT save the line items |
|
1015 | + * @param EE_Line_Item $line_item |
|
1016 | + * @param string $code_substring_for_whitelist if this string is part of the line item's code |
|
1017 | + * it will be whitelisted (ie, except from becoming taxable) |
|
1018 | + * @param boolean $taxable |
|
1019 | + */ |
|
1020 | + public static function set_line_items_taxable( |
|
1021 | + EE_Line_Item $line_item, |
|
1022 | + $taxable = true, |
|
1023 | + $code_substring_for_whitelist = null |
|
1024 | + ) |
|
1025 | + { |
|
1026 | + $whitelisted = false; |
|
1027 | + if ($code_substring_for_whitelist !== null) { |
|
1028 | + $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false ? true : false; |
|
1029 | + } |
|
1030 | + if (!$whitelisted && $line_item->is_line_item()) { |
|
1031 | + $line_item->set_is_taxable($taxable); |
|
1032 | + } |
|
1033 | + foreach ($line_item->children() as $child_line_item) { |
|
1034 | + EEH_Line_Item::set_line_items_taxable($child_line_item, $taxable, $code_substring_for_whitelist); |
|
1035 | + } |
|
1036 | + } |
|
1037 | + |
|
1038 | + |
|
1039 | + /** |
|
1040 | + * Gets all descendants that are event subtotals |
|
1041 | + * |
|
1042 | + * @uses EEH_Line_Item::get_subtotals_of_object_type() |
|
1043 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1044 | + * @return EE_Line_Item[] |
|
1045 | + */ |
|
1046 | + public static function get_event_subtotals(EE_Line_Item $parent_line_item) |
|
1047 | + { |
|
1048 | + return self::get_subtotals_of_object_type($parent_line_item, 'Event'); |
|
1049 | + } |
|
1050 | + |
|
1051 | + |
|
1052 | + /** |
|
1053 | + * Gets all descendants subtotals that match the supplied object type |
|
1054 | + * |
|
1055 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1056 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1057 | + * @param string $obj_type |
|
1058 | + * @return EE_Line_Item[] |
|
1059 | + */ |
|
1060 | + public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
1061 | + { |
|
1062 | + return self::_get_descendants_by_type_and_object_type( |
|
1063 | + $parent_line_item, |
|
1064 | + EEM_Line_Item::type_sub_total, |
|
1065 | + $obj_type |
|
1066 | + ); |
|
1067 | + } |
|
1068 | + |
|
1069 | + |
|
1070 | + /** |
|
1071 | + * Gets all descendants that are tickets |
|
1072 | + * |
|
1073 | + * @uses EEH_Line_Item::get_line_items_of_object_type() |
|
1074 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1075 | + * @return EE_Line_Item[] |
|
1076 | + */ |
|
1077 | + public static function get_ticket_line_items(EE_Line_Item $parent_line_item) |
|
1078 | + { |
|
1079 | + return self::get_line_items_of_object_type($parent_line_item, 'Ticket'); |
|
1080 | + } |
|
1081 | + |
|
1082 | + |
|
1083 | + /** |
|
1084 | + * Gets all descendants subtotals that match the supplied object type |
|
1085 | + * |
|
1086 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1087 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1088 | + * @param string $obj_type |
|
1089 | + * @return EE_Line_Item[] |
|
1090 | + */ |
|
1091 | + public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
1092 | + { |
|
1093 | + return self::_get_descendants_by_type_and_object_type($parent_line_item, EEM_Line_Item::type_line_item, $obj_type); |
|
1094 | + } |
|
1095 | + |
|
1096 | + |
|
1097 | + /** |
|
1098 | + * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax' |
|
1099 | + * @uses EEH_Line_Item::get_descendants_of_type() |
|
1100 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1101 | + * @return EE_Line_Item[] |
|
1102 | + */ |
|
1103 | + public static function get_tax_descendants(EE_Line_Item $parent_line_item) |
|
1104 | + { |
|
1105 | + return EEH_Line_Item::get_descendants_of_type($parent_line_item, EEM_Line_Item::type_tax); |
|
1106 | + } |
|
1107 | + |
|
1108 | + |
|
1109 | + /** |
|
1110 | + * Gets all the real items purchased which are children of this item |
|
1111 | + * @uses EEH_Line_Item::get_descendants_of_type() |
|
1112 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1113 | + * @return EE_Line_Item[] |
|
1114 | + */ |
|
1115 | + public static function get_line_item_descendants(EE_Line_Item $parent_line_item) |
|
1116 | + { |
|
1117 | + return EEH_Line_Item::get_descendants_of_type($parent_line_item, EEM_Line_Item::type_line_item); |
|
1118 | + } |
|
1119 | + |
|
1120 | + |
|
1121 | + /** |
|
1122 | + * Gets all descendants of supplied line item that match the supplied line item type |
|
1123 | + * |
|
1124 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1125 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1126 | + * @param string $line_item_type one of the EEM_Line_Item constants |
|
1127 | + * @return EE_Line_Item[] |
|
1128 | + */ |
|
1129 | + public static function get_descendants_of_type(EE_Line_Item $parent_line_item, $line_item_type) |
|
1130 | + { |
|
1131 | + return self::_get_descendants_by_type_and_object_type($parent_line_item, $line_item_type, NULL); |
|
1132 | + } |
|
1133 | + |
|
1134 | + |
|
1135 | + /** |
|
1136 | + * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type as well |
|
1137 | + * |
|
1138 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1139 | + * @param string $line_item_type one of the EEM_Line_Item constants |
|
1140 | + * @param string | NULL $obj_type object model class name (minus prefix) or NULL to ignore object type when searching |
|
1141 | + * @return EE_Line_Item[] |
|
1142 | + */ |
|
1143 | + protected static function _get_descendants_by_type_and_object_type( |
|
1144 | + EE_Line_Item $parent_line_item, |
|
1145 | + $line_item_type, |
|
1146 | + $obj_type = null |
|
1147 | + ) |
|
1148 | + { |
|
1149 | + $objects = array(); |
|
1150 | + foreach ($parent_line_item->children() as $child_line_item) { |
|
1151 | + if ($child_line_item instanceof EE_Line_Item) { |
|
1152 | + if ( |
|
1153 | + $child_line_item->type() === $line_item_type |
|
1154 | + && ( |
|
1155 | + $child_line_item->OBJ_type() === $obj_type || $obj_type === null |
|
1156 | + ) |
|
1157 | + ) { |
|
1158 | + $objects[] = $child_line_item; |
|
1159 | + } else { |
|
1160 | + //go-through-all-its children looking for more matches |
|
1161 | + $objects = array_merge( |
|
1162 | + $objects, |
|
1163 | + self::_get_descendants_by_type_and_object_type( |
|
1164 | + $child_line_item, |
|
1165 | + $line_item_type, |
|
1166 | + $obj_type |
|
1167 | + ) |
|
1168 | + ); |
|
1169 | + } |
|
1170 | + } |
|
1171 | + } |
|
1172 | + return $objects; |
|
1173 | + } |
|
1174 | + |
|
1175 | + |
|
1176 | + /** |
|
1177 | + * Gets all descendants subtotals that match the supplied object type |
|
1178 | + * |
|
1179 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1180 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1181 | + * @param string $OBJ_type object type (like Event) |
|
1182 | + * @param array $OBJ_IDs array of OBJ_IDs |
|
1183 | + * @return EE_Line_Item[] |
|
1184 | + */ |
|
1185 | + public static function get_line_items_by_object_type_and_IDs( |
|
1186 | + EE_Line_Item $parent_line_item, |
|
1187 | + $OBJ_type = '', |
|
1188 | + $OBJ_IDs = array() |
|
1189 | + ) |
|
1190 | + { |
|
1191 | + return self::_get_descendants_by_object_type_and_object_ID($parent_line_item, $OBJ_type, $OBJ_IDs); |
|
1192 | + } |
|
1193 | + |
|
1194 | + |
|
1195 | + /** |
|
1196 | + * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type as well |
|
1197 | + * |
|
1198 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1199 | + * @param string $OBJ_type object type (like Event) |
|
1200 | + * @param array $OBJ_IDs array of OBJ_IDs |
|
1201 | + * @return EE_Line_Item[] |
|
1202 | + */ |
|
1203 | + protected static function _get_descendants_by_object_type_and_object_ID( |
|
1204 | + EE_Line_Item $parent_line_item, |
|
1205 | + $OBJ_type, |
|
1206 | + $OBJ_IDs |
|
1207 | + ) |
|
1208 | + { |
|
1209 | + $objects = array(); |
|
1210 | + foreach ($parent_line_item->children() as $child_line_item) { |
|
1211 | + if ($child_line_item instanceof EE_Line_Item) { |
|
1212 | + if ( |
|
1213 | + $child_line_item->OBJ_type() === $OBJ_type |
|
1214 | + && is_array($OBJ_IDs) |
|
1215 | + && in_array($child_line_item->OBJ_ID(), $OBJ_IDs) |
|
1216 | + ) { |
|
1217 | + $objects[] = $child_line_item; |
|
1218 | + } else { |
|
1219 | + //go-through-all-its children looking for more matches |
|
1220 | + $objects = array_merge( |
|
1221 | + $objects, |
|
1222 | + self::_get_descendants_by_object_type_and_object_ID( |
|
1223 | + $child_line_item, |
|
1224 | + $OBJ_type, |
|
1225 | + $OBJ_IDs |
|
1226 | + ) |
|
1227 | + ); |
|
1228 | + } |
|
1229 | + } |
|
1230 | + } |
|
1231 | + return $objects; |
|
1232 | + } |
|
1233 | + |
|
1234 | + |
|
1235 | + /** |
|
1236 | + * Uses a breadth-first-search in order to find the nearest descendant of |
|
1237 | + * the specified type and returns it, else NULL |
|
1238 | + * |
|
1239 | + * @uses EEH_Line_Item::_get_nearest_descendant() |
|
1240 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1241 | + * @param string $type like one of the EEM_Line_Item::type_* |
|
1242 | + * @return EE_Line_Item |
|
1243 | + */ |
|
1244 | + public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, $type) |
|
1245 | + { |
|
1246 | + return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type); |
|
1247 | + } |
|
1248 | + |
|
1249 | + |
|
1250 | + /** |
|
1251 | + * Uses a breadth-first-search in order to find the nearest descendant |
|
1252 | + * having the specified LIN_code and returns it, else NULL |
|
1253 | + * |
|
1254 | + * @uses EEH_Line_Item::_get_nearest_descendant() |
|
1255 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1256 | + * @param string $code any value used for LIN_code |
|
1257 | + * @return EE_Line_Item |
|
1258 | + */ |
|
1259 | + public static function get_nearest_descendant_having_code(EE_Line_Item $parent_line_item, $code) |
|
1260 | + { |
|
1261 | + return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code); |
|
1262 | + } |
|
1263 | + |
|
1264 | + |
|
1265 | + /** |
|
1266 | + * Uses a breadth-first-search in order to find the nearest descendant |
|
1267 | + * having the specified LIN_code and returns it, else NULL |
|
1268 | + * |
|
1269 | + * @param \EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1270 | + * @param string $search_field name of EE_Line_Item property |
|
1271 | + * @param string $value any value stored in $search_field |
|
1272 | + * @return EE_Line_Item |
|
1273 | + */ |
|
1274 | + protected static function _get_nearest_descendant(EE_Line_Item $parent_line_item, $search_field, $value) |
|
1275 | + { |
|
1276 | + foreach ($parent_line_item->children() as $child) { |
|
1277 | + if ($child->get($search_field) == $value) { |
|
1278 | + return $child; |
|
1279 | + } |
|
1280 | + } |
|
1281 | + foreach ($parent_line_item->children() as $child) { |
|
1282 | + $descendant_found = self::_get_nearest_descendant($child, $search_field, $value); |
|
1283 | + if ($descendant_found) { |
|
1284 | + return $descendant_found; |
|
1285 | + } |
|
1286 | + } |
|
1287 | + return NULL; |
|
1288 | + } |
|
1289 | + |
|
1290 | + |
|
1291 | + /** |
|
1292 | + * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction, |
|
1293 | + * else recursively walks up the line item tree until a parent of type total is found, |
|
1294 | + * |
|
1295 | + * @param EE_Line_Item $line_item |
|
1296 | + * @return \EE_Line_Item |
|
1297 | + * @throws \EE_Error |
|
1298 | + */ |
|
1299 | + public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item) |
|
1300 | + { |
|
1301 | + if ($line_item->TXN_ID()) { |
|
1302 | + $total_line_item = $line_item->transaction()->total_line_item(false); |
|
1303 | + if ($total_line_item instanceof EE_Line_Item) { |
|
1304 | + return $total_line_item; |
|
1305 | + } |
|
1306 | + } else { |
|
1307 | + $line_item_parent = $line_item->parent(); |
|
1308 | + if ($line_item_parent instanceof EE_Line_Item) { |
|
1309 | + if ($line_item_parent->is_total()) { |
|
1310 | + return $line_item_parent; |
|
1311 | + } |
|
1312 | + return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent); |
|
1313 | + } |
|
1314 | + } |
|
1315 | + throw new EE_Error( |
|
1316 | + sprintf( |
|
1317 | + __('A valid grand total for line item %1$d was not found.', 'event_espresso'), |
|
1318 | + $line_item->ID() |
|
1319 | + ) |
|
1320 | + ); |
|
1321 | + } |
|
1322 | + |
|
1323 | + |
|
1324 | + /** |
|
1325 | + * Prints out a representation of the line item tree |
|
1326 | + * |
|
1327 | + * @param EE_Line_Item $line_item |
|
1328 | + * @param int $indentation |
|
1329 | + * @return void |
|
1330 | + * @throws \EE_Error |
|
1331 | + */ |
|
1332 | + public static function visualize(EE_Line_Item $line_item, $indentation = 0) |
|
1333 | + { |
|
1334 | + echo defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
|
1335 | + if (!$indentation) { |
|
1336 | + echo defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
|
1337 | + } |
|
1338 | + for ($i = 0; $i < $indentation; $i++) { |
|
1339 | + echo ". "; |
|
1340 | + } |
|
1341 | + $breakdown = ''; |
|
1342 | + if ($line_item->is_line_item()) { |
|
1343 | + if ($line_item->is_percent()) { |
|
1344 | + $breakdown = "{$line_item->percent()}%"; |
|
1345 | + } else { |
|
1346 | + $breakdown = '$' . "{$line_item->unit_price()} x {$line_item->quantity()}"; |
|
1347 | + } |
|
1348 | + } |
|
1349 | + echo $line_item->name() . " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : " . '$' . "{$line_item->total()}"; |
|
1350 | + if ($breakdown) { |
|
1351 | + echo " ( {$breakdown} )"; |
|
1352 | + } |
|
1353 | + if ($line_item->is_taxable()) { |
|
1354 | + echo " * taxable"; |
|
1355 | + } |
|
1356 | + if ($line_item->children()) { |
|
1357 | + foreach ($line_item->children() as $child) { |
|
1358 | + self::visualize($child, $indentation + 1); |
|
1359 | + } |
|
1360 | + } |
|
1361 | + } |
|
1362 | + |
|
1363 | + |
|
1364 | + /** |
|
1365 | + * Calculates the registration's final price, taking into account that they |
|
1366 | + * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes, |
|
1367 | + * and receive a portion of any transaction-wide discounts. |
|
1368 | + * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount |
|
1369 | + * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get |
|
1370 | + * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50 |
|
1371 | + * and brent's final price should be $5.50. |
|
1372 | + * |
|
1373 | + * In order to do this, we basically need to traverse the line item tree calculating |
|
1374 | + * the running totals (just as if we were recalculating the total), but when we identify |
|
1375 | + * regular line items, we need to keep track of their share of the grand total. |
|
1376 | + * Also, we need to keep track of the TAXABLE total for each ticket purchase, so |
|
1377 | + * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total" |
|
1378 | + * when there are non-taxable items; otherwise they would be the same) |
|
1379 | + * |
|
1380 | + * @param EE_Line_Item $line_item |
|
1381 | + * @param array $billable_ticket_quantities array of EE_Ticket IDs and their corresponding quantity that |
|
1382 | + * can be included in price calculations at this moment |
|
1383 | + * @return array keys are line items for tickets IDs and values are their share of the running total, |
|
1384 | + * plus the key 'total', and 'taxable' which also has keys of all the ticket IDs. Eg |
|
1385 | + * array( |
|
1386 | + * 12 => 4.3 |
|
1387 | + * 23 => 8.0 |
|
1388 | + * 'total' => 16.6, |
|
1389 | + * 'taxable' => array( |
|
1390 | + * 12 => 10, |
|
1391 | + * 23 => 4 |
|
1392 | + * ). |
|
1393 | + * So to find which registrations have which final price, we need to find which line item |
|
1394 | + * is theirs, which can be done with |
|
1395 | + * `EEM_Line_Item::instance()->get_line_item_for_registration( $registration );` |
|
1396 | + */ |
|
1397 | + public static function calculate_reg_final_prices_per_line_item(EE_Line_Item $line_item, $billable_ticket_quantities = array()) |
|
1398 | + { |
|
1399 | + //init running grand total if not already |
|
1400 | + if (!isset($running_totals['total'])) { |
|
1401 | + $running_totals['total'] = 0; |
|
1402 | + } |
|
1403 | + if (!isset($running_totals['taxable'])) { |
|
1404 | + $running_totals['taxable'] = array('total' => 0); |
|
1405 | + } |
|
1406 | + foreach ($line_item->children() as $child_line_item) { |
|
1407 | + switch ($child_line_item->type()) { |
|
1408 | + |
|
1409 | + case EEM_Line_Item::type_sub_total : |
|
1410 | + $running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item($child_line_item, $billable_ticket_quantities); |
|
1411 | + //combine arrays but preserve numeric keys |
|
1412 | + $running_totals = array_replace_recursive($running_totals_from_subtotal, $running_totals); |
|
1413 | + $running_totals['total'] += $running_totals_from_subtotal['total']; |
|
1414 | + $running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total']; |
|
1415 | + break; |
|
1416 | + |
|
1417 | + case EEM_Line_Item::type_tax_sub_total : |
|
1418 | + |
|
1419 | + //find how much the taxes percentage is |
|
1420 | + if ($child_line_item->percent() !== 0) { |
|
1421 | + $tax_percent_decimal = $child_line_item->percent() / 100; |
|
1422 | + } else { |
|
1423 | + $tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100; |
|
1424 | + } |
|
1425 | + //and apply to all the taxable totals, and add to the pretax totals |
|
1426 | + foreach ($running_totals as $line_item_id => $this_running_total) { |
|
1427 | + //"total" and "taxable" array key is an exception |
|
1428 | + if ($line_item_id === 'taxable') { |
|
1429 | + continue; |
|
1430 | + } |
|
1431 | + $taxable_total = $running_totals['taxable'][$line_item_id]; |
|
1432 | + $running_totals[$line_item_id] += ($taxable_total * $tax_percent_decimal); |
|
1433 | + } |
|
1434 | + break; |
|
1435 | + |
|
1436 | + case EEM_Line_Item::type_line_item : |
|
1437 | + |
|
1438 | + // ticket line items or ???? |
|
1439 | + if ($child_line_item->OBJ_type() === 'Ticket') { |
|
1440 | + // kk it's a ticket |
|
1441 | + if (isset($running_totals[$child_line_item->ID()])) { |
|
1442 | + //huh? that shouldn't happen. |
|
1443 | + $running_totals['total'] += $child_line_item->total(); |
|
1444 | + } else { |
|
1445 | + //its not in our running totals yet. great. |
|
1446 | + if ($child_line_item->is_taxable()) { |
|
1447 | + $taxable_amount = $child_line_item->unit_price(); |
|
1448 | + } else { |
|
1449 | + $taxable_amount = 0; |
|
1450 | + } |
|
1451 | + // are we only calculating totals for some tickets? |
|
1452 | + if (isset($billable_ticket_quantities[$child_line_item->OBJ_ID()])) { |
|
1453 | + $quantity = $billable_ticket_quantities[$child_line_item->OBJ_ID()]; |
|
1454 | + $running_totals[$child_line_item->ID()] = $quantity |
|
1455 | + ? $child_line_item->unit_price() |
|
1456 | + : 0; |
|
1457 | + $running_totals['taxable'][$child_line_item->ID()] = $quantity |
|
1458 | + ? $taxable_amount |
|
1459 | + : 0; |
|
1460 | + } else { |
|
1461 | + $quantity = $child_line_item->quantity(); |
|
1462 | + $running_totals[$child_line_item->ID()] = $child_line_item->unit_price(); |
|
1463 | + $running_totals['taxable'][$child_line_item->ID()] = $taxable_amount; |
|
1464 | + } |
|
1465 | + $running_totals['taxable']['total'] += $taxable_amount * $quantity; |
|
1466 | + $running_totals['total'] += $child_line_item->unit_price() * $quantity; |
|
1467 | + } |
|
1468 | + } else { |
|
1469 | + // it's some other type of item added to the cart |
|
1470 | + // it should affect the running totals |
|
1471 | + // basically we want to convert it into a PERCENT modifier. Because |
|
1472 | + // more clearly affect all registration's final price equally |
|
1473 | + $line_items_percent_of_running_total = $running_totals['total'] > 0 |
|
1474 | + ? ($child_line_item->total() / $running_totals['total']) + 1 |
|
1475 | + : 1; |
|
1476 | + foreach ($running_totals as $line_item_id => $this_running_total) { |
|
1477 | + //the "taxable" array key is an exception |
|
1478 | + if ($line_item_id === 'taxable') { |
|
1479 | + continue; |
|
1480 | + } |
|
1481 | + // update the running totals |
|
1482 | + // yes this actually even works for the running grand total! |
|
1483 | + $running_totals[$line_item_id] = |
|
1484 | + $line_items_percent_of_running_total * $this_running_total; |
|
1485 | + |
|
1486 | + if ($child_line_item->is_taxable()) { |
|
1487 | + $running_totals['taxable'][$line_item_id] = |
|
1488 | + $line_items_percent_of_running_total * $running_totals['taxable'][$line_item_id]; |
|
1489 | + } |
|
1490 | + } |
|
1491 | + } |
|
1492 | + break; |
|
1493 | + } |
|
1494 | + } |
|
1495 | + return $running_totals; |
|
1496 | + } |
|
1497 | + |
|
1498 | + |
|
1499 | + /** |
|
1500 | + * @param \EE_Line_Item $total_line_item |
|
1501 | + * @param \EE_Line_Item $ticket_line_item |
|
1502 | + * @return float | null |
|
1503 | + * @throws \OutOfRangeException |
|
1504 | + */ |
|
1505 | + public static function calculate_final_price_for_ticket_line_item(\EE_Line_Item $total_line_item, \EE_Line_Item $ticket_line_item) |
|
1506 | + { |
|
1507 | + static $final_prices_per_ticket_line_item = array(); |
|
1508 | + if (empty($final_prices_per_ticket_line_item)) { |
|
1509 | + $final_prices_per_ticket_line_item = \EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
1510 | + $total_line_item |
|
1511 | + ); |
|
1512 | + } |
|
1513 | + //ok now find this new registration's final price |
|
1514 | + if (isset($final_prices_per_ticket_line_item[$ticket_line_item->ID()])) { |
|
1515 | + return $final_prices_per_ticket_line_item[$ticket_line_item->ID()]; |
|
1516 | + } |
|
1517 | + $message = sprintf( |
|
1518 | + __( |
|
1519 | + 'The final price for the ticket line item (ID:%1$d) could not be calculated.', |
|
1520 | + 'event_espresso' |
|
1521 | + ), |
|
1522 | + $ticket_line_item->ID() |
|
1523 | + ); |
|
1524 | + if (WP_DEBUG) { |
|
1525 | + $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true); |
|
1526 | + throw new \OutOfRangeException($message); |
|
1527 | + } else { |
|
1528 | + EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message); |
|
1529 | + } |
|
1530 | + return null; |
|
1531 | + } |
|
1532 | + |
|
1533 | + |
|
1534 | + /** |
|
1535 | + * Creates a duplicate of the line item tree, except only includes billable items |
|
1536 | + * and the portion of line items attributed to billable things |
|
1537 | + * |
|
1538 | + * @param EE_Line_Item $line_item |
|
1539 | + * @param EE_Registration[] $registrations |
|
1540 | + * @return \EE_Line_Item |
|
1541 | + * @throws \EE_Error |
|
1542 | + */ |
|
1543 | + public static function billable_line_item_tree(EE_Line_Item $line_item, $registrations) |
|
1544 | + { |
|
1545 | + $copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations); |
|
1546 | + foreach ($line_item->children() as $child_li) { |
|
1547 | + $copy_li->add_child_line_item(EEH_Line_Item::billable_line_item_tree($child_li, $registrations)); |
|
1548 | + } |
|
1549 | + //if this is the grand total line item, make sure the totals all add up |
|
1550 | + //(we could have duplicated this logic AS we copied the line items, but |
|
1551 | + //it seems DRYer this way) |
|
1552 | + if ($copy_li->type() === EEM_Line_Item::type_total) { |
|
1553 | + $copy_li->recalculate_total_including_taxes(); |
|
1554 | + } |
|
1555 | + return $copy_li; |
|
1556 | + } |
|
1557 | + |
|
1558 | + |
|
1559 | + /** |
|
1560 | + * Creates a new, unsaved line item from $line_item that factors in the |
|
1561 | + * number of billable registrations on $registrations. |
|
1562 | + * |
|
1563 | + * @param EE_Line_Item $line_item |
|
1564 | + * @return EE_Line_Item |
|
1565 | + * @throws \EE_Error |
|
1566 | + * @param EE_Registration[] $registrations |
|
1567 | + */ |
|
1568 | + public static function billable_line_item(EE_Line_Item $line_item, $registrations) |
|
1569 | + { |
|
1570 | + $new_li_fields = $line_item->model_field_array(); |
|
1571 | + if ($line_item->type() === EEM_Line_Item::type_line_item && |
|
1572 | + $line_item->OBJ_type() === 'Ticket' |
|
1573 | + ) { |
|
1574 | + $count = 0; |
|
1575 | + foreach ($registrations as $registration) { |
|
1576 | + if ($line_item->OBJ_ID() === $registration->ticket_ID() && |
|
1577 | + in_array($registration->status_ID(), EEM_Registration::reg_statuses_that_allow_payment()) |
|
1578 | + ) { |
|
1579 | + $count++; |
|
1580 | + } |
|
1581 | + } |
|
1582 | + $new_li_fields['LIN_quantity'] = $count; |
|
1583 | + } |
|
1584 | + //don't set the total. We'll leave that up to the code that calculates it |
|
1585 | + unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']); |
|
1586 | + return EE_Line_Item::new_instance($new_li_fields); |
|
1587 | + } |
|
1588 | + |
|
1589 | + |
|
1590 | + /** |
|
1591 | + * Returns a modified line item tree where all the subtotals which have a total of 0 |
|
1592 | + * are removed, and line items with a quantity of 0 |
|
1593 | + * |
|
1594 | + * @param EE_Line_Item $line_item |null |
|
1595 | + * @return \EE_Line_Item|null |
|
1596 | + * @throws \EE_Error |
|
1597 | + */ |
|
1598 | + public static function non_empty_line_items(EE_Line_Item $line_item) |
|
1599 | + { |
|
1600 | + $copied_li = EEH_Line_Item::non_empty_line_item($line_item); |
|
1601 | + if ($copied_li === null) { |
|
1602 | + return null; |
|
1603 | + } |
|
1604 | + //if this is an event subtotal, we want to only include it if it |
|
1605 | + //has a non-zero total and at least one ticket line item child |
|
1606 | + $ticket_children = 0; |
|
1607 | + foreach ($line_item->children() as $child_li) { |
|
1608 | + $child_li_copy = EEH_Line_Item::non_empty_line_items($child_li); |
|
1609 | + if ($child_li_copy !== null) { |
|
1610 | + $copied_li->add_child_line_item($child_li_copy); |
|
1611 | + if ($child_li_copy->type() === EEM_Line_Item::type_line_item && |
|
1612 | + $child_li_copy->OBJ_type() === 'Ticket' |
|
1613 | + ) { |
|
1614 | + $ticket_children++; |
|
1615 | + } |
|
1616 | + } |
|
1617 | + } |
|
1618 | + //if this is an event subtotal with NO ticket children |
|
1619 | + //we basically want to ignore it |
|
1620 | + if ( |
|
1621 | + $ticket_children === 0 |
|
1622 | + && $line_item->type() === EEM_Line_Item::type_sub_total |
|
1623 | + && $line_item->OBJ_type() === 'Event' |
|
1624 | + && $line_item->total() === 0 |
|
1625 | + ) { |
|
1626 | + return null; |
|
1627 | + } |
|
1628 | + return $copied_li; |
|
1629 | + } |
|
1630 | + |
|
1631 | + |
|
1632 | + /** |
|
1633 | + * Creates a new, unsaved line item, but if it's a ticket line item |
|
1634 | + * with a total of 0, or a subtotal of 0, returns null instead |
|
1635 | + * |
|
1636 | + * @param EE_Line_Item $line_item |
|
1637 | + * @return EE_Line_Item |
|
1638 | + * @throws \EE_Error |
|
1639 | + */ |
|
1640 | + public static function non_empty_line_item(EE_Line_Item $line_item) |
|
1641 | + { |
|
1642 | + if ($line_item->type() === EEM_Line_Item::type_line_item && |
|
1643 | + $line_item->OBJ_type() === 'Ticket' && |
|
1644 | + $line_item->quantity() === 0 |
|
1645 | + ) { |
|
1646 | + return null; |
|
1647 | + } |
|
1648 | + $new_li_fields = $line_item->model_field_array(); |
|
1649 | + //don't set the total. We'll leave that up to the code that calculates it |
|
1650 | + unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']); |
|
1651 | + return EE_Line_Item::new_instance($new_li_fields); |
|
1652 | + } |
|
1653 | + |
|
1654 | + |
|
1655 | + |
|
1656 | + /**************************************** @DEPRECATED METHODS *************************************** */ |
|
1657 | + /** |
|
1658 | + * @deprecated |
|
1659 | + * @param EE_Line_Item $total_line_item |
|
1660 | + * @return \EE_Line_Item |
|
1661 | + * @throws \EE_Error |
|
1662 | + */ |
|
1663 | + public static function get_items_subtotal(EE_Line_Item $total_line_item) |
|
1664 | + { |
|
1665 | + EE_Error::doing_it_wrong('EEH_Line_Item::get_items_subtotal()', __('Method replaced with EEH_Line_Item::get_pre_tax_subtotal()', 'event_espresso'), '4.6.0'); |
|
1666 | + return self::get_pre_tax_subtotal($total_line_item); |
|
1667 | + } |
|
1668 | + |
|
1669 | + |
|
1670 | + /** |
|
1671 | + * @deprecated |
|
1672 | + * @param EE_Transaction $transaction |
|
1673 | + * @return \EE_Line_Item |
|
1674 | + * @throws \EE_Error |
|
1675 | + */ |
|
1676 | + public static function create_default_total_line_item($transaction = NULL) |
|
1677 | + { |
|
1678 | + EE_Error::doing_it_wrong('EEH_Line_Item::create_default_total_line_item()', __('Method replaced with EEH_Line_Item::create_total_line_item()', 'event_espresso'), '4.6.0'); |
|
1679 | + return self::create_total_line_item($transaction); |
|
1680 | + } |
|
1681 | + |
|
1682 | + |
|
1683 | + /** |
|
1684 | + * @deprecated |
|
1685 | + * @param EE_Line_Item $total_line_item |
|
1686 | + * @param EE_Transaction $transaction |
|
1687 | + * @return \EE_Line_Item |
|
1688 | + * @throws \EE_Error |
|
1689 | + */ |
|
1690 | + public static function create_default_tickets_subtotal(EE_Line_Item $total_line_item, $transaction = NULL) |
|
1691 | + { |
|
1692 | + EE_Error::doing_it_wrong('EEH_Line_Item::create_default_tickets_subtotal()', __('Method replaced with EEH_Line_Item::create_pre_tax_subtotal()', 'event_espresso'), '4.6.0'); |
|
1693 | + return self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
1694 | + } |
|
1695 | + |
|
1696 | + |
|
1697 | + /** |
|
1698 | + * @deprecated |
|
1699 | + * @param EE_Line_Item $total_line_item |
|
1700 | + * @param EE_Transaction $transaction |
|
1701 | + * @return \EE_Line_Item |
|
1702 | + * @throws \EE_Error |
|
1703 | + */ |
|
1704 | + public static function create_default_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = NULL) |
|
1705 | + { |
|
1706 | + EE_Error::doing_it_wrong('EEH_Line_Item::create_default_taxes_subtotal()', __('Method replaced with EEH_Line_Item::create_taxes_subtotal()', 'event_espresso'), '4.6.0'); |
|
1707 | + return self::create_taxes_subtotal($total_line_item, $transaction); |
|
1708 | + } |
|
1709 | + |
|
1710 | + |
|
1711 | + /** |
|
1712 | + * @deprecated |
|
1713 | + * @param EE_Line_Item $total_line_item |
|
1714 | + * @param EE_Transaction $transaction |
|
1715 | + * @return \EE_Line_Item |
|
1716 | + * @throws \EE_Error |
|
1717 | + */ |
|
1718 | + public static function create_default_event_subtotal(EE_Line_Item $total_line_item, $transaction = NULL) |
|
1719 | + { |
|
1720 | + EE_Error::doing_it_wrong('EEH_Line_Item::create_default_event_subtotal()', __('Method replaced with EEH_Line_Item::create_event_subtotal()', 'event_espresso'), '4.6.0'); |
|
1721 | + return self::create_event_subtotal($total_line_item, $transaction); |
|
1722 | + } |
|
1723 | 1723 | |
1724 | 1724 | |
1725 | 1725 | } |
@@ -1,4 +1,4 @@ discard block |
||
1 | -<?php if (!defined('EVENT_ESPRESSO_VERSION')) { |
|
1 | +<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) { |
|
2 | 2 | exit('No direct script access allowed'); |
3 | 3 | } |
4 | 4 | |
@@ -56,7 +56,7 @@ discard block |
||
56 | 56 | 'LIN_percent' => null, |
57 | 57 | 'LIN_is_taxable' => $taxable, |
58 | 58 | 'LIN_order' => $items_subtotal instanceof EE_Line_Item ? count($items_subtotal->children()) : 0, |
59 | - 'LIN_total' => (float)$unit_price * (int)$quantity, |
|
59 | + 'LIN_total' => (float) $unit_price * (int) $quantity, |
|
60 | 60 | 'LIN_type' => EEM_Line_Item::type_line_item, |
61 | 61 | 'LIN_code' => $code, |
62 | 62 | )); |
@@ -95,7 +95,7 @@ discard block |
||
95 | 95 | 'LIN_percent' => $percentage_amount, |
96 | 96 | 'LIN_quantity' => 1, |
97 | 97 | 'LIN_is_taxable' => $taxable, |
98 | - 'LIN_total' => (float)($percentage_amount * ($parent_line_item->total() / 100)), |
|
98 | + 'LIN_total' => (float) ($percentage_amount * ($parent_line_item->total() / 100)), |
|
99 | 99 | 'LIN_type' => EEM_Line_Item::type_line_item, |
100 | 100 | 'LIN_parent' => $parent_line_item->ID() |
101 | 101 | )); |
@@ -125,13 +125,13 @@ discard block |
||
125 | 125 | */ |
126 | 126 | public static function add_ticket_purchase(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
127 | 127 | { |
128 | - if (!$total_line_item instanceof EE_Line_Item || !$total_line_item->is_total()) { |
|
128 | + if ( ! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) { |
|
129 | 129 | throw new EE_Error(sprintf(__('A valid line item total is required in order to add tickets. A line item of type "%s" was passed.', 'event_espresso'), $ticket->ID(), $total_line_item->ID())); |
130 | 130 | } |
131 | 131 | // either increment the qty for an existing ticket |
132 | 132 | $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty); |
133 | 133 | // or add a new one |
134 | - if (!$line_item instanceof EE_Line_Item) { |
|
134 | + if ( ! $line_item instanceof EE_Line_Item) { |
|
135 | 135 | $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty); |
136 | 136 | } |
137 | 137 | $total_line_item->recalculate_total_including_taxes(); |
@@ -152,10 +152,10 @@ discard block |
||
152 | 152 | $line_item = null; |
153 | 153 | if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) { |
154 | 154 | $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item); |
155 | - foreach ((array)$ticket_line_items as $ticket_line_item) { |
|
155 | + foreach ((array) $ticket_line_items as $ticket_line_item) { |
|
156 | 156 | if ( |
157 | 157 | $ticket_line_item instanceof EE_Line_Item |
158 | - && (int)$ticket_line_item->OBJ_ID() === (int)$ticket->ID() |
|
158 | + && (int) $ticket_line_item->OBJ_ID() === (int) $ticket->ID() |
|
159 | 159 | ) { |
160 | 160 | $line_item = $ticket_line_item; |
161 | 161 | break; |
@@ -181,7 +181,7 @@ discard block |
||
181 | 181 | */ |
182 | 182 | public static function increment_quantity(EE_Line_Item $line_item, $qty = 1) |
183 | 183 | { |
184 | - if (!$line_item->is_percent()) { |
|
184 | + if ( ! $line_item->is_percent()) { |
|
185 | 185 | $qty += $line_item->quantity(); |
186 | 186 | $line_item->set_quantity($qty); |
187 | 187 | $line_item->set_total($line_item->unit_price() * $qty); |
@@ -206,7 +206,7 @@ discard block |
||
206 | 206 | */ |
207 | 207 | public static function decrement_quantity(EE_Line_Item $line_item, $qty = 1) |
208 | 208 | { |
209 | - if (!$line_item->is_percent()) { |
|
209 | + if ( ! $line_item->is_percent()) { |
|
210 | 210 | $qty = $line_item->quantity() - $qty; |
211 | 211 | $qty = max($qty, 0); |
212 | 212 | $line_item->set_quantity($qty); |
@@ -231,7 +231,7 @@ discard block |
||
231 | 231 | */ |
232 | 232 | public static function update_quantity(EE_Line_Item $line_item, $new_quantity) |
233 | 233 | { |
234 | - if (!$line_item->is_percent()) { |
|
234 | + if ( ! $line_item->is_percent()) { |
|
235 | 235 | $line_item->set_quantity($new_quantity); |
236 | 236 | $line_item->set_total($line_item->unit_price() * $new_quantity); |
237 | 237 | $line_item->save(); |
@@ -267,7 +267,7 @@ discard block |
||
267 | 267 | // add $ticket to cart |
268 | 268 | $line_item = EE_Line_Item::new_instance(array( |
269 | 269 | 'LIN_name' => $ticket->name(), |
270 | - 'LIN_desc' => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event, |
|
270 | + 'LIN_desc' => $ticket->description() !== '' ? $ticket->description().' '.$event : $event, |
|
271 | 271 | 'LIN_unit_price' => $ticket->price(), |
272 | 272 | 'LIN_quantity' => $qty, |
273 | 273 | 'LIN_is_taxable' => $ticket->taxable(), |
@@ -377,8 +377,8 @@ discard block |
||
377 | 377 | foreach ($ticket_line_item->children() as $child_line_item) { |
378 | 378 | if ( |
379 | 379 | $child_line_item->is_sub_line_item() |
380 | - && !$child_line_item->is_percent() |
|
381 | - && !$child_line_item->is_cancellation() |
|
380 | + && ! $child_line_item->is_percent() |
|
381 | + && ! $child_line_item->is_cancellation() |
|
382 | 382 | ) { |
383 | 383 | $child_line_item->set_quantity($child_line_item->quantity() - $qty); |
384 | 384 | } |
@@ -400,7 +400,7 @@ discard block |
||
400 | 400 | 'LIN_desc' => sprintf( |
401 | 401 | _x('Cancelled %1$s : %2$s', 'Cancelled Ticket Name : 2015-01-01 11:11', 'event_espresso'), |
402 | 402 | $ticket_line_item->name(), |
403 | - current_time(get_option('date_format') . ' ' . get_option('time_format')) |
|
403 | + current_time(get_option('date_format').' '.get_option('time_format')) |
|
404 | 404 | ), |
405 | 405 | 'LIN_unit_price' => 0, // $ticket_line_item->unit_price() |
406 | 406 | 'LIN_quantity' => $qty, |
@@ -453,7 +453,7 @@ discard block |
||
453 | 453 | ); |
454 | 454 | $cancellation_line_item = reset($cancellation_line_item); |
455 | 455 | // verify that this ticket was indeed previously cancelled |
456 | - if (!$cancellation_line_item instanceof EE_Line_Item) { |
|
456 | + if ( ! $cancellation_line_item instanceof EE_Line_Item) { |
|
457 | 457 | return false; |
458 | 458 | } |
459 | 459 | if ($cancellation_line_item->quantity() > $qty) { |
@@ -625,7 +625,7 @@ discard block |
||
625 | 625 | 'LIN_code' => 'taxes', |
626 | 626 | 'LIN_name' => __('Taxes', 'event_espresso'), |
627 | 627 | 'LIN_type' => EEM_Line_Item::type_tax_sub_total, |
628 | - 'LIN_order' => 1000,//this should always come last |
|
628 | + 'LIN_order' => 1000, //this should always come last |
|
629 | 629 | )); |
630 | 630 | $tax_line_item = apply_filters( |
631 | 631 | 'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item', |
@@ -677,7 +677,7 @@ discard block |
||
677 | 677 | */ |
678 | 678 | public static function get_event_code($event) |
679 | 679 | { |
680 | - return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0'); |
|
680 | + return 'event-'.($event instanceof EE_Event ? $event->ID() : '0'); |
|
681 | 681 | } |
682 | 682 | |
683 | 683 | /** |
@@ -713,13 +713,13 @@ discard block |
||
713 | 713 | public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket) |
714 | 714 | { |
715 | 715 | $first_datetime = $ticket->first_datetime(); |
716 | - if (!$first_datetime instanceof EE_Datetime) { |
|
716 | + if ( ! $first_datetime instanceof EE_Datetime) { |
|
717 | 717 | throw new EE_Error( |
718 | 718 | sprintf(__('The supplied ticket (ID %d) has no datetimes', 'event_espresso'), $ticket->ID()) |
719 | 719 | ); |
720 | 720 | } |
721 | 721 | $event = $first_datetime->event(); |
722 | - if (!$event instanceof EE_Event) { |
|
722 | + if ( ! $event instanceof EE_Event) { |
|
723 | 723 | throw new EE_Error( |
724 | 724 | sprintf( |
725 | 725 | __('The supplied ticket (ID %d) has no event data associated with it.', 'event_espresso'), |
@@ -728,7 +728,7 @@ discard block |
||
728 | 728 | ); |
729 | 729 | } |
730 | 730 | $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event); |
731 | - if (!$events_sub_total instanceof EE_Line_Item) { |
|
731 | + if ( ! $events_sub_total instanceof EE_Line_Item) { |
|
732 | 732 | throw new EE_Error( |
733 | 733 | sprintf( |
734 | 734 | __('There is no events sub-total for ticket %s on total line item %d', 'event_espresso'), |
@@ -757,7 +757,7 @@ discard block |
||
757 | 757 | $found = false; |
758 | 758 | foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) { |
759 | 759 | // default event subtotal, we should only ever find this the first time this method is called |
760 | - if (!$event_line_item->OBJ_ID()) { |
|
760 | + if ( ! $event_line_item->OBJ_ID()) { |
|
761 | 761 | // let's use this! but first... set the event details |
762 | 762 | EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
763 | 763 | $found = true; |
@@ -768,7 +768,7 @@ discard block |
||
768 | 768 | break; |
769 | 769 | } |
770 | 770 | } |
771 | - if (!$found) { |
|
771 | + if ( ! $found) { |
|
772 | 772 | //there is no event sub-total yet, so add it |
773 | 773 | $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total); |
774 | 774 | // create a new "event" subtotal below that |
@@ -863,7 +863,7 @@ discard block |
||
863 | 863 | public static function ensure_taxes_applied($total_line_item) |
864 | 864 | { |
865 | 865 | $taxes_subtotal = self::get_taxes_subtotal($total_line_item); |
866 | - if (!$taxes_subtotal->children()) { |
|
866 | + if ( ! $taxes_subtotal->children()) { |
|
867 | 867 | self::apply_taxes($total_line_item); |
868 | 868 | } |
869 | 869 | return $taxes_subtotal->total(); |
@@ -924,7 +924,7 @@ discard block |
||
924 | 924 | do_action('AHEE_log', __FILE__, __FUNCTION__, ''); |
925 | 925 | |
926 | 926 | // check if only a single line_item_id was passed |
927 | - if (!empty($line_item_codes) && !is_array($line_item_codes)) { |
|
927 | + if ( ! empty($line_item_codes) && ! is_array($line_item_codes)) { |
|
928 | 928 | // place single line_item_id in an array to appear as multiple line_item_ids |
929 | 929 | $line_item_codes = array($line_item_codes); |
930 | 930 | } |
@@ -1027,7 +1027,7 @@ discard block |
||
1027 | 1027 | if ($code_substring_for_whitelist !== null) { |
1028 | 1028 | $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false ? true : false; |
1029 | 1029 | } |
1030 | - if (!$whitelisted && $line_item->is_line_item()) { |
|
1030 | + if ( ! $whitelisted && $line_item->is_line_item()) { |
|
1031 | 1031 | $line_item->set_is_taxable($taxable); |
1032 | 1032 | } |
1033 | 1033 | foreach ($line_item->children() as $child_line_item) { |
@@ -1332,7 +1332,7 @@ discard block |
||
1332 | 1332 | public static function visualize(EE_Line_Item $line_item, $indentation = 0) |
1333 | 1333 | { |
1334 | 1334 | echo defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
1335 | - if (!$indentation) { |
|
1335 | + if ( ! $indentation) { |
|
1336 | 1336 | echo defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
1337 | 1337 | } |
1338 | 1338 | for ($i = 0; $i < $indentation; $i++) { |
@@ -1343,10 +1343,10 @@ discard block |
||
1343 | 1343 | if ($line_item->is_percent()) { |
1344 | 1344 | $breakdown = "{$line_item->percent()}%"; |
1345 | 1345 | } else { |
1346 | - $breakdown = '$' . "{$line_item->unit_price()} x {$line_item->quantity()}"; |
|
1346 | + $breakdown = '$'."{$line_item->unit_price()} x {$line_item->quantity()}"; |
|
1347 | 1347 | } |
1348 | 1348 | } |
1349 | - echo $line_item->name() . " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : " . '$' . "{$line_item->total()}"; |
|
1349 | + echo $line_item->name()." [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : ".'$'."{$line_item->total()}"; |
|
1350 | 1350 | if ($breakdown) { |
1351 | 1351 | echo " ( {$breakdown} )"; |
1352 | 1352 | } |
@@ -1397,10 +1397,10 @@ discard block |
||
1397 | 1397 | public static function calculate_reg_final_prices_per_line_item(EE_Line_Item $line_item, $billable_ticket_quantities = array()) |
1398 | 1398 | { |
1399 | 1399 | //init running grand total if not already |
1400 | - if (!isset($running_totals['total'])) { |
|
1400 | + if ( ! isset($running_totals['total'])) { |
|
1401 | 1401 | $running_totals['total'] = 0; |
1402 | 1402 | } |
1403 | - if (!isset($running_totals['taxable'])) { |
|
1403 | + if ( ! isset($running_totals['taxable'])) { |
|
1404 | 1404 | $running_totals['taxable'] = array('total' => 0); |
1405 | 1405 | } |
1406 | 1406 | foreach ($line_item->children() as $child_line_item) { |
@@ -1522,7 +1522,7 @@ discard block |
||
1522 | 1522 | $ticket_line_item->ID() |
1523 | 1523 | ); |
1524 | 1524 | if (WP_DEBUG) { |
1525 | - $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true); |
|
1525 | + $message .= '<br>'.print_r($final_prices_per_ticket_line_item, true); |
|
1526 | 1526 | throw new \OutOfRangeException($message); |
1527 | 1527 | } else { |
1528 | 1528 | EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message); |
@@ -17,1432 +17,1432 @@ |
||
17 | 17 | class EE_Line_Item extends EE_Base_Class implements EEI_Line_Item |
18 | 18 | { |
19 | 19 | |
20 | - /** |
|
21 | - * for children line items (currently not a normal relation) |
|
22 | - * |
|
23 | - * @type EE_Line_Item[] |
|
24 | - */ |
|
25 | - protected $_children = array(); |
|
26 | - |
|
27 | - /** |
|
28 | - * for the parent line item |
|
29 | - * |
|
30 | - * @var EE_Line_Item |
|
31 | - */ |
|
32 | - protected $_parent; |
|
33 | - |
|
34 | - |
|
35 | - /** |
|
36 | - * |
|
37 | - * @param array $props_n_values incoming values |
|
38 | - * @param string $timezone incoming timezone (if not set the timezone set for the website will be |
|
39 | - * used.) |
|
40 | - * @param array $date_formats incoming date_formats in an array where the first value is the |
|
41 | - * date_format and the second value is the time format |
|
42 | - * @return EE_Line_Item |
|
43 | - * @throws EE_Error |
|
44 | - */ |
|
45 | - public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
46 | - { |
|
47 | - $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats); |
|
48 | - return $has_object |
|
49 | - ? $has_object |
|
50 | - : new self($props_n_values, false, $timezone); |
|
51 | - } |
|
52 | - |
|
53 | - |
|
54 | - /** |
|
55 | - * @param array $props_n_values incoming values from the database |
|
56 | - * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
57 | - * the website will be used. |
|
58 | - * @return EE_Line_Item |
|
59 | - * @throws EE_Error |
|
60 | - */ |
|
61 | - public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
62 | - { |
|
63 | - return new self($props_n_values, true, $timezone); |
|
64 | - } |
|
65 | - |
|
66 | - |
|
67 | - /** |
|
68 | - * Adds some defaults if they're not specified |
|
69 | - * |
|
70 | - * @param array $fieldValues |
|
71 | - * @param bool $bydb |
|
72 | - * @param string $timezone |
|
73 | - * @throws EE_Error |
|
74 | - */ |
|
75 | - protected function __construct($fieldValues = array(), $bydb = false, $timezone = '') |
|
76 | - { |
|
77 | - parent::__construct($fieldValues, $bydb, $timezone); |
|
78 | - if (!$this->get('LIN_code')) { |
|
79 | - $this->set_code($this->generate_code()); |
|
80 | - } |
|
81 | - } |
|
82 | - |
|
83 | - |
|
84 | - /** |
|
85 | - * Gets ID |
|
86 | - * |
|
87 | - * @return int |
|
88 | - * @throws EE_Error |
|
89 | - */ |
|
90 | - public function ID() |
|
91 | - { |
|
92 | - return $this->get('LIN_ID'); |
|
93 | - } |
|
94 | - |
|
95 | - |
|
96 | - /** |
|
97 | - * Gets TXN_ID |
|
98 | - * |
|
99 | - * @return int |
|
100 | - * @throws EE_Error |
|
101 | - */ |
|
102 | - public function TXN_ID() |
|
103 | - { |
|
104 | - return $this->get('TXN_ID'); |
|
105 | - } |
|
106 | - |
|
107 | - |
|
108 | - /** |
|
109 | - * Sets TXN_ID |
|
110 | - * |
|
111 | - * @param int $TXN_ID |
|
112 | - * @throws EE_Error |
|
113 | - */ |
|
114 | - public function set_TXN_ID($TXN_ID) |
|
115 | - { |
|
116 | - $this->set('TXN_ID', $TXN_ID); |
|
117 | - } |
|
118 | - |
|
119 | - |
|
120 | - /** |
|
121 | - * Gets name |
|
122 | - * |
|
123 | - * @return string |
|
124 | - * @throws EE_Error |
|
125 | - */ |
|
126 | - public function name() |
|
127 | - { |
|
128 | - $name = $this->get('LIN_name'); |
|
129 | - if (!$name) { |
|
130 | - $name = ucwords(str_replace('-', ' ', $this->type())); |
|
131 | - } |
|
132 | - return $name; |
|
133 | - } |
|
134 | - |
|
135 | - |
|
136 | - /** |
|
137 | - * Sets name |
|
138 | - * |
|
139 | - * @param string $name |
|
140 | - * @throws EE_Error |
|
141 | - */ |
|
142 | - public function set_name($name) |
|
143 | - { |
|
144 | - $this->set('LIN_name', $name); |
|
145 | - } |
|
146 | - |
|
147 | - |
|
148 | - /** |
|
149 | - * Gets desc |
|
150 | - * |
|
151 | - * @return string |
|
152 | - * @throws EE_Error |
|
153 | - */ |
|
154 | - public function desc() |
|
155 | - { |
|
156 | - return $this->get('LIN_desc'); |
|
157 | - } |
|
158 | - |
|
159 | - |
|
160 | - /** |
|
161 | - * Sets desc |
|
162 | - * |
|
163 | - * @param string $desc |
|
164 | - * @throws EE_Error |
|
165 | - */ |
|
166 | - public function set_desc($desc) |
|
167 | - { |
|
168 | - $this->set('LIN_desc', $desc); |
|
169 | - } |
|
170 | - |
|
171 | - |
|
172 | - /** |
|
173 | - * Gets quantity |
|
174 | - * |
|
175 | - * @return int |
|
176 | - * @throws EE_Error |
|
177 | - */ |
|
178 | - public function quantity() |
|
179 | - { |
|
180 | - return $this->get('LIN_quantity'); |
|
181 | - } |
|
182 | - |
|
183 | - |
|
184 | - /** |
|
185 | - * Sets quantity |
|
186 | - * |
|
187 | - * @param int $quantity |
|
188 | - * @throws EE_Error |
|
189 | - */ |
|
190 | - public function set_quantity($quantity) |
|
191 | - { |
|
192 | - $this->set('LIN_quantity', max($quantity, 0)); |
|
193 | - } |
|
194 | - |
|
195 | - |
|
196 | - /** |
|
197 | - * Gets item_id |
|
198 | - * |
|
199 | - * @return string |
|
200 | - * @throws EE_Error |
|
201 | - */ |
|
202 | - public function OBJ_ID() |
|
203 | - { |
|
204 | - return $this->get('OBJ_ID'); |
|
205 | - } |
|
206 | - |
|
207 | - |
|
208 | - /** |
|
209 | - * Sets item_id |
|
210 | - * |
|
211 | - * @param string $item_id |
|
212 | - * @throws EE_Error |
|
213 | - */ |
|
214 | - public function set_OBJ_ID($item_id) |
|
215 | - { |
|
216 | - $this->set('OBJ_ID', $item_id); |
|
217 | - } |
|
218 | - |
|
219 | - |
|
220 | - /** |
|
221 | - * Gets item_type |
|
222 | - * |
|
223 | - * @return string |
|
224 | - * @throws EE_Error |
|
225 | - */ |
|
226 | - public function OBJ_type() |
|
227 | - { |
|
228 | - return $this->get('OBJ_type'); |
|
229 | - } |
|
230 | - |
|
231 | - |
|
232 | - /** |
|
233 | - * Gets item_type |
|
234 | - * |
|
235 | - * @return string |
|
236 | - * @throws EE_Error |
|
237 | - */ |
|
238 | - public function OBJ_type_i18n() |
|
239 | - { |
|
240 | - $obj_type = $this->OBJ_type(); |
|
241 | - switch ($obj_type) { |
|
242 | - case 'Event': |
|
243 | - $obj_type = __('Event', 'event_espresso'); |
|
244 | - break; |
|
245 | - case 'Price': |
|
246 | - $obj_type = __('Price', 'event_espresso'); |
|
247 | - break; |
|
248 | - case 'Promotion': |
|
249 | - $obj_type = __('Promotion', 'event_espresso'); |
|
250 | - break; |
|
251 | - case 'Ticket': |
|
252 | - $obj_type = __('Ticket', 'event_espresso'); |
|
253 | - break; |
|
254 | - case 'Transaction': |
|
255 | - $obj_type = __('Transaction', 'event_espresso'); |
|
256 | - break; |
|
257 | - } |
|
258 | - return apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this); |
|
259 | - } |
|
260 | - |
|
261 | - |
|
262 | - /** |
|
263 | - * Sets item_type |
|
264 | - * |
|
265 | - * @param string $OBJ_type |
|
266 | - * @throws EE_Error |
|
267 | - */ |
|
268 | - public function set_OBJ_type($OBJ_type) |
|
269 | - { |
|
270 | - $this->set('OBJ_type', $OBJ_type); |
|
271 | - } |
|
272 | - |
|
273 | - |
|
274 | - /** |
|
275 | - * Gets unit_price |
|
276 | - * |
|
277 | - * @return float |
|
278 | - * @throws EE_Error |
|
279 | - */ |
|
280 | - public function unit_price() |
|
281 | - { |
|
282 | - return $this->get('LIN_unit_price'); |
|
283 | - } |
|
284 | - |
|
285 | - |
|
286 | - /** |
|
287 | - * Sets unit_price |
|
288 | - * |
|
289 | - * @param float $unit_price |
|
290 | - * @throws EE_Error |
|
291 | - */ |
|
292 | - public function set_unit_price($unit_price) |
|
293 | - { |
|
294 | - $this->set('LIN_unit_price', $unit_price); |
|
295 | - } |
|
296 | - |
|
297 | - |
|
298 | - /** |
|
299 | - * Checks if this item is a percentage modifier or not |
|
300 | - * |
|
301 | - * @return boolean |
|
302 | - * @throws EE_Error |
|
303 | - */ |
|
304 | - public function is_percent() |
|
305 | - { |
|
306 | - if ($this->is_tax_sub_total()) { |
|
307 | - //tax subtotals HAVE a percent on them, that percentage only applies |
|
308 | - //to taxable items, so its' an exception. Treat it like a flat line item |
|
309 | - return false; |
|
310 | - } |
|
311 | - $unit_price = abs($this->get('LIN_unit_price')); |
|
312 | - $percent = abs($this->get('LIN_percent')); |
|
313 | - if ($unit_price < .001 && $percent) { |
|
314 | - return true; |
|
315 | - } |
|
316 | - if ($unit_price >= .001 && !$percent) { |
|
317 | - return false; |
|
318 | - } |
|
319 | - if ($unit_price >= .001 && $percent) { |
|
320 | - throw new EE_Error( |
|
321 | - sprintf( |
|
322 | - esc_html__('A Line Item can not have a unit price of (%s) AND a percent (%s)!', 'event_espresso'), |
|
323 | - $unit_price, $percent |
|
324 | - ) |
|
325 | - ); |
|
326 | - } |
|
327 | - // if they're both 0, assume its not a percent item |
|
328 | - return false; |
|
329 | - } |
|
330 | - |
|
331 | - |
|
332 | - /** |
|
333 | - * Gets percent (between 100-.001) |
|
334 | - * |
|
335 | - * @return float |
|
336 | - * @throws EE_Error |
|
337 | - */ |
|
338 | - public function percent() |
|
339 | - { |
|
340 | - return $this->get('LIN_percent'); |
|
341 | - } |
|
342 | - |
|
343 | - |
|
344 | - /** |
|
345 | - * Sets percent (between 100-0.01) |
|
346 | - * |
|
347 | - * @param float $percent |
|
348 | - * @throws EE_Error |
|
349 | - */ |
|
350 | - public function set_percent($percent) |
|
351 | - { |
|
352 | - $this->set('LIN_percent', $percent); |
|
353 | - } |
|
354 | - |
|
355 | - |
|
356 | - /** |
|
357 | - * Gets total |
|
358 | - * |
|
359 | - * @return float |
|
360 | - * @throws EE_Error |
|
361 | - */ |
|
362 | - public function total() |
|
363 | - { |
|
364 | - return $this->get('LIN_total'); |
|
365 | - } |
|
366 | - |
|
367 | - |
|
368 | - /** |
|
369 | - * Sets total |
|
370 | - * |
|
371 | - * @param float $total |
|
372 | - * @throws EE_Error |
|
373 | - */ |
|
374 | - public function set_total($total) |
|
375 | - { |
|
376 | - $this->set('LIN_total', $total); |
|
377 | - } |
|
378 | - |
|
379 | - |
|
380 | - /** |
|
381 | - * Gets order |
|
382 | - * |
|
383 | - * @return int |
|
384 | - * @throws EE_Error |
|
385 | - */ |
|
386 | - public function order() |
|
387 | - { |
|
388 | - return $this->get('LIN_order'); |
|
389 | - } |
|
390 | - |
|
391 | - |
|
392 | - /** |
|
393 | - * Sets order |
|
394 | - * |
|
395 | - * @param int $order |
|
396 | - * @throws EE_Error |
|
397 | - */ |
|
398 | - public function set_order($order) |
|
399 | - { |
|
400 | - $this->set('LIN_order', $order); |
|
401 | - } |
|
402 | - |
|
403 | - |
|
404 | - /** |
|
405 | - * Gets parent |
|
406 | - * |
|
407 | - * @return int |
|
408 | - * @throws EE_Error |
|
409 | - */ |
|
410 | - public function parent_ID() |
|
411 | - { |
|
412 | - return $this->get('LIN_parent'); |
|
413 | - } |
|
414 | - |
|
415 | - |
|
416 | - /** |
|
417 | - * Sets parent |
|
418 | - * |
|
419 | - * @param int $parent |
|
420 | - * @throws EE_Error |
|
421 | - */ |
|
422 | - public function set_parent_ID($parent) |
|
423 | - { |
|
424 | - $this->set('LIN_parent', $parent); |
|
425 | - } |
|
426 | - |
|
427 | - |
|
428 | - /** |
|
429 | - * Gets type |
|
430 | - * |
|
431 | - * @return string |
|
432 | - * @throws EE_Error |
|
433 | - */ |
|
434 | - public function type() |
|
435 | - { |
|
436 | - return $this->get('LIN_type'); |
|
437 | - } |
|
438 | - |
|
439 | - |
|
440 | - /** |
|
441 | - * Sets type |
|
442 | - * |
|
443 | - * @param string $type |
|
444 | - * @throws EE_Error |
|
445 | - */ |
|
446 | - public function set_type($type) |
|
447 | - { |
|
448 | - $this->set('LIN_type', $type); |
|
449 | - } |
|
450 | - |
|
451 | - |
|
452 | - /** |
|
453 | - * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\ |
|
454 | - * If this line item is saved to the DB, fetches the parent from the DB. However, if this line item isn't in the DB |
|
455 | - * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()` |
|
456 | - * or indirectly by `EE_Line_item::add_child_line_item()`) |
|
457 | - * |
|
458 | - * @return EE_Base_Class|EE_Line_Item |
|
459 | - * @throws EE_Error |
|
460 | - */ |
|
461 | - public function parent() |
|
462 | - { |
|
463 | - return $this->ID() |
|
464 | - ? $this->get_model()->get_one_by_ID($this->parent_ID()) |
|
465 | - : $this->_parent; |
|
466 | - } |
|
467 | - |
|
468 | - |
|
469 | - /** |
|
470 | - * Gets ALL the children of this line item (ie, all the parts that contribute towards this total). |
|
471 | - * |
|
472 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
473 | - * @throws EE_Error |
|
474 | - */ |
|
475 | - public function children() |
|
476 | - { |
|
477 | - if ($this->ID()) { |
|
478 | - return $this->get_model()->get_all( |
|
479 | - array( |
|
480 | - array('LIN_parent' => $this->ID()), |
|
481 | - 'order_by' => array('LIN_order' => 'ASC'), |
|
482 | - ) |
|
483 | - ); |
|
484 | - } |
|
485 | - if (!is_array($this->_children)) { |
|
486 | - $this->_children = array(); |
|
487 | - } |
|
488 | - return $this->_children; |
|
489 | - } |
|
490 | - |
|
491 | - |
|
492 | - /** |
|
493 | - * Gets code |
|
494 | - * |
|
495 | - * @return string |
|
496 | - * @throws EE_Error |
|
497 | - */ |
|
498 | - public function code() |
|
499 | - { |
|
500 | - return $this->get('LIN_code'); |
|
501 | - } |
|
502 | - |
|
503 | - |
|
504 | - /** |
|
505 | - * Sets code |
|
506 | - * |
|
507 | - * @param string $code |
|
508 | - * @throws EE_Error |
|
509 | - */ |
|
510 | - public function set_code($code) |
|
511 | - { |
|
512 | - $this->set('LIN_code', $code); |
|
513 | - } |
|
514 | - |
|
515 | - |
|
516 | - /** |
|
517 | - * Gets is_taxable |
|
518 | - * |
|
519 | - * @return boolean |
|
520 | - * @throws EE_Error |
|
521 | - */ |
|
522 | - public function is_taxable() |
|
523 | - { |
|
524 | - return $this->get('LIN_is_taxable'); |
|
525 | - } |
|
526 | - |
|
527 | - |
|
528 | - /** |
|
529 | - * Sets is_taxable |
|
530 | - * |
|
531 | - * @param boolean $is_taxable |
|
532 | - * @throws EE_Error |
|
533 | - */ |
|
534 | - public function set_is_taxable($is_taxable) |
|
535 | - { |
|
536 | - $this->set('LIN_is_taxable', $is_taxable); |
|
537 | - } |
|
538 | - |
|
539 | - |
|
540 | - /** |
|
541 | - * Gets the object that this model-joins-to. |
|
542 | - * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on |
|
543 | - * EEM_Promotion_Object |
|
544 | - * |
|
545 | - * Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object |
|
546 | - * |
|
547 | - * @return EE_Base_Class | NULL |
|
548 | - * @throws EE_Error |
|
549 | - */ |
|
550 | - public function get_object() |
|
551 | - { |
|
552 | - $model_name_of_related_obj = $this->OBJ_type(); |
|
553 | - return $this->get_model()->has_relation($model_name_of_related_obj) |
|
554 | - ? $this->get_first_related($model_name_of_related_obj) |
|
555 | - : null; |
|
556 | - } |
|
557 | - |
|
558 | - |
|
559 | - /** |
|
560 | - * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket. |
|
561 | - * (IE, if this line item is for a price or something else, will return NULL) |
|
562 | - * |
|
563 | - * @param array $query_params |
|
564 | - * @return EE_Base_Class|EE_Ticket |
|
565 | - * @throws EE_Error |
|
566 | - */ |
|
567 | - public function ticket($query_params = array()) |
|
568 | - { |
|
569 | - //we're going to assume that when this method is called we always want to receive the attached ticket EVEN if that ticket is archived. This can be overridden via the incoming $query_params argument |
|
570 | - $remove_defaults = array('default_where_conditions' => 'none'); |
|
571 | - $query_params = array_merge($remove_defaults, $query_params); |
|
572 | - return $this->get_first_related('Ticket', $query_params); |
|
573 | - } |
|
574 | - |
|
575 | - |
|
576 | - /** |
|
577 | - * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket |
|
578 | - * |
|
579 | - * @return EE_Datetime | NULL |
|
580 | - * @throws EE_Error |
|
581 | - */ |
|
582 | - public function get_ticket_datetime() |
|
583 | - { |
|
584 | - if ($this->OBJ_type() === 'Ticket') { |
|
585 | - $ticket = $this->ticket(); |
|
586 | - if ($ticket instanceof EE_Ticket) { |
|
587 | - $datetime = $ticket->first_datetime(); |
|
588 | - if ($datetime instanceof EE_Datetime) { |
|
589 | - return $datetime; |
|
590 | - } |
|
591 | - } |
|
592 | - } |
|
593 | - return null; |
|
594 | - } |
|
595 | - |
|
596 | - |
|
597 | - /** |
|
598 | - * Gets the event's name that's related to the ticket, if this is for |
|
599 | - * a ticket |
|
600 | - * |
|
601 | - * @return string |
|
602 | - * @throws EE_Error |
|
603 | - */ |
|
604 | - public function ticket_event_name() |
|
605 | - { |
|
606 | - $event_name = esc_html__('Unknown', 'event_espresso'); |
|
607 | - $event = $this->ticket_event(); |
|
608 | - if ($event instanceof EE_Event) { |
|
609 | - $event_name = $event->name(); |
|
610 | - } |
|
611 | - return $event_name; |
|
612 | - } |
|
613 | - |
|
614 | - |
|
615 | - /** |
|
616 | - * Gets the event that's related to the ticket, if this line item represents a ticket. |
|
617 | - * |
|
618 | - * @return EE_Event|null |
|
619 | - * @throws EE_Error |
|
620 | - */ |
|
621 | - public function ticket_event() |
|
622 | - { |
|
623 | - $event = null; |
|
624 | - $ticket = $this->ticket(); |
|
625 | - if ($ticket instanceof EE_Ticket) { |
|
626 | - $datetime = $ticket->first_datetime(); |
|
627 | - if ($datetime instanceof EE_Datetime) { |
|
628 | - $event = $datetime->event(); |
|
629 | - } |
|
630 | - } |
|
631 | - return $event; |
|
632 | - } |
|
633 | - |
|
634 | - |
|
635 | - /** |
|
636 | - * Gets the first datetime for this lien item, assuming it's for a ticket |
|
637 | - * |
|
638 | - * @param string $date_format |
|
639 | - * @param string $time_format |
|
640 | - * @return string |
|
641 | - * @throws EE_Error |
|
642 | - */ |
|
643 | - public function ticket_datetime_start($date_format = '', $time_format = '') |
|
644 | - { |
|
645 | - $first_datetime_string = esc_html__('Unknown', 'event_espresso'); |
|
646 | - $datetime = $this->get_ticket_datetime(); |
|
647 | - if ($datetime) { |
|
648 | - $first_datetime_string = $datetime->start_date_and_time($date_format, $time_format); |
|
649 | - } |
|
650 | - return $first_datetime_string; |
|
651 | - } |
|
652 | - |
|
653 | - |
|
654 | - /** |
|
655 | - * Adds the line item as a child to this line item. If there is another child line |
|
656 | - * item with the same LIN_code, it is overwritten by this new one |
|
657 | - * |
|
658 | - * @param EEI_Line_Item $line_item |
|
659 | - * @param bool $set_order |
|
660 | - * @return bool success |
|
661 | - * @throws EE_Error |
|
662 | - */ |
|
663 | - public function add_child_line_item(EEI_Line_Item $line_item, $set_order = true) |
|
664 | - { |
|
665 | - // should we calculate the LIN_order for this line item ? |
|
666 | - if ($set_order || $line_item->order() === null) { |
|
667 | - $line_item->set_order(count($this->children())); |
|
668 | - } |
|
669 | - if ($this->ID()) { |
|
670 | - //check for any duplicate line items (with the same code), if so, this replaces it |
|
671 | - $line_item_with_same_code = $this->get_child_line_item($line_item->code()); |
|
672 | - if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) { |
|
673 | - $this->delete_child_line_item($line_item_with_same_code->code()); |
|
674 | - } |
|
675 | - $line_item->set_parent_ID($this->ID()); |
|
676 | - if ($this->TXN_ID()) { |
|
677 | - $line_item->set_TXN_ID($this->TXN_ID()); |
|
678 | - } |
|
679 | - return $line_item->save(); |
|
680 | - } |
|
681 | - $this->_children[$line_item->code()] = $line_item; |
|
682 | - if ($line_item->parent() !== $this) { |
|
683 | - $line_item->set_parent($this); |
|
684 | - } |
|
685 | - return true; |
|
686 | - } |
|
687 | - |
|
688 | - |
|
689 | - /** |
|
690 | - * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation. |
|
691 | - * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save() |
|
692 | - * However, if this line item is NOT saved to the DB, this just caches the parent on |
|
693 | - * the EE_Line_Item::_parent property. |
|
694 | - * |
|
695 | - * @param EE_Line_Item $line_item |
|
696 | - * @throws EE_Error |
|
697 | - */ |
|
698 | - public function set_parent($line_item) |
|
699 | - { |
|
700 | - if ($this->ID()) { |
|
701 | - if (!$line_item->ID()) { |
|
702 | - $line_item->save(); |
|
703 | - } |
|
704 | - $this->set_parent_ID($line_item->ID()); |
|
705 | - $this->save(); |
|
706 | - } else { |
|
707 | - $this->_parent = $line_item; |
|
708 | - $this->set_parent_ID($line_item->ID()); |
|
709 | - } |
|
710 | - } |
|
711 | - |
|
712 | - |
|
713 | - /** |
|
714 | - * Gets the child line item as specified by its code. Because this returns an object (by reference) |
|
715 | - * you can modify this child line item and the parent (this object) can know about them |
|
716 | - * because it also has a reference to that line item |
|
717 | - * |
|
718 | - * @param string $code |
|
719 | - * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
720 | - * @throws EE_Error |
|
721 | - */ |
|
722 | - public function get_child_line_item($code) |
|
723 | - { |
|
724 | - if ($this->ID()) { |
|
725 | - return $this->get_model()->get_one( |
|
726 | - array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code)) |
|
727 | - ); |
|
728 | - } |
|
729 | - return isset($this->_children[$code]) |
|
730 | - ? $this->_children[$code] |
|
731 | - : null; |
|
732 | - } |
|
733 | - |
|
734 | - |
|
735 | - /** |
|
736 | - * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD |
|
737 | - * cached on it) |
|
738 | - * |
|
739 | - * @return int |
|
740 | - * @throws EE_Error |
|
741 | - */ |
|
742 | - public function delete_children_line_items() |
|
743 | - { |
|
744 | - if ($this->ID()) { |
|
745 | - return $this->get_model()->delete(array(array('LIN_parent' => $this->ID()))); |
|
746 | - } |
|
747 | - $count = count($this->_children); |
|
748 | - $this->_children = array(); |
|
749 | - return $count; |
|
750 | - } |
|
751 | - |
|
752 | - |
|
753 | - /** |
|
754 | - * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line |
|
755 | - * HAS NOT been saved to the DB, removes the child line item with index $code. |
|
756 | - * Also searches through the child's children for a matching line item. However, once a line item has been found |
|
757 | - * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be |
|
758 | - * deleted) |
|
759 | - * |
|
760 | - * @param string $code |
|
761 | - * @param bool $stop_search_once_found |
|
762 | - * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to |
|
763 | - * the DB yet) |
|
764 | - * @throws EE_Error |
|
765 | - */ |
|
766 | - public function delete_child_line_item($code, $stop_search_once_found = true) |
|
767 | - { |
|
768 | - if ($this->ID()) { |
|
769 | - $items_deleted = 0; |
|
770 | - if ($this->code() === $code) { |
|
771 | - $items_deleted += EEH_Line_Item::delete_all_child_items($this); |
|
772 | - $items_deleted += (int)$this->delete(); |
|
773 | - if ($stop_search_once_found) { |
|
774 | - return $items_deleted; |
|
775 | - } |
|
776 | - } |
|
777 | - foreach ($this->children() as $child_line_item) { |
|
778 | - $items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found); |
|
779 | - } |
|
780 | - return $items_deleted; |
|
781 | - } |
|
782 | - if (isset($this->_children[$code])) { |
|
783 | - unset($this->_children[$code]); |
|
784 | - return 1; |
|
785 | - } |
|
786 | - return 0; |
|
787 | - } |
|
788 | - |
|
789 | - |
|
790 | - /** |
|
791 | - * If this line item is in the database, is of the type subtotal, and |
|
792 | - * has no children, why do we have it? It should be deleted so this function |
|
793 | - * does that |
|
794 | - * |
|
795 | - * @return boolean |
|
796 | - * @throws EE_Error |
|
797 | - */ |
|
798 | - public function delete_if_childless_subtotal() |
|
799 | - { |
|
800 | - if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && !$this->children()) { |
|
801 | - return $this->delete(); |
|
802 | - } |
|
803 | - return false; |
|
804 | - } |
|
805 | - |
|
806 | - |
|
807 | - /** |
|
808 | - * Creates a code and returns a string. doesn't assign the code to this model object |
|
809 | - * |
|
810 | - * @return string |
|
811 | - * @throws EE_Error |
|
812 | - */ |
|
813 | - public function generate_code() |
|
814 | - { |
|
815 | - // each line item in the cart requires a unique identifier |
|
816 | - return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime()); |
|
817 | - } |
|
818 | - |
|
819 | - |
|
820 | - /** |
|
821 | - * @return bool |
|
822 | - * @throws EE_Error |
|
823 | - */ |
|
824 | - public function is_tax() |
|
825 | - { |
|
826 | - return $this->type() === EEM_Line_Item::type_tax; |
|
827 | - } |
|
828 | - |
|
829 | - |
|
830 | - /** |
|
831 | - * @return bool |
|
832 | - * @throws EE_Error |
|
833 | - */ |
|
834 | - public function is_tax_sub_total() |
|
835 | - { |
|
836 | - return $this->type() === EEM_Line_Item::type_tax_sub_total; |
|
837 | - } |
|
838 | - |
|
839 | - |
|
840 | - /** |
|
841 | - * @return bool |
|
842 | - * @throws EE_Error |
|
843 | - */ |
|
844 | - public function is_line_item() |
|
845 | - { |
|
846 | - return $this->type() === EEM_Line_Item::type_line_item; |
|
847 | - } |
|
848 | - |
|
849 | - |
|
850 | - /** |
|
851 | - * @return bool |
|
852 | - * @throws EE_Error |
|
853 | - */ |
|
854 | - public function is_sub_line_item() |
|
855 | - { |
|
856 | - return $this->type() === EEM_Line_Item::type_sub_line_item; |
|
857 | - } |
|
858 | - |
|
859 | - |
|
860 | - /** |
|
861 | - * @return bool |
|
862 | - * @throws EE_Error |
|
863 | - */ |
|
864 | - public function is_sub_total() |
|
865 | - { |
|
866 | - return $this->type() === EEM_Line_Item::type_sub_total; |
|
867 | - } |
|
868 | - |
|
869 | - |
|
870 | - /** |
|
871 | - * Whether or not this line item is a cancellation line item |
|
872 | - * |
|
873 | - * @return boolean |
|
874 | - * @throws EE_Error |
|
875 | - */ |
|
876 | - public function is_cancellation() |
|
877 | - { |
|
878 | - return EEM_Line_Item::type_cancellation === $this->type(); |
|
879 | - } |
|
880 | - |
|
881 | - |
|
882 | - /** |
|
883 | - * @return bool |
|
884 | - * @throws EE_Error |
|
885 | - */ |
|
886 | - public function is_total() |
|
887 | - { |
|
888 | - return $this->type() === EEM_Line_Item::type_total; |
|
889 | - } |
|
890 | - |
|
891 | - |
|
892 | - /** |
|
893 | - * @return bool |
|
894 | - * @throws EE_Error |
|
895 | - */ |
|
896 | - public function is_cancelled() |
|
897 | - { |
|
898 | - return $this->type() === EEM_Line_Item::type_cancellation; |
|
899 | - } |
|
900 | - |
|
901 | - |
|
902 | - /** |
|
903 | - * @return string like '2, 004.00', formatted according to the localized currency |
|
904 | - * @throws EE_Error |
|
905 | - */ |
|
906 | - public function unit_price_no_code() |
|
907 | - { |
|
908 | - return $this->get_pretty('LIN_unit_price', 'no_currency_code'); |
|
909 | - } |
|
910 | - |
|
911 | - |
|
912 | - /** |
|
913 | - * @return string like '2, 004.00', formatted according to the localized currency |
|
914 | - * @throws EE_Error |
|
915 | - */ |
|
916 | - public function total_no_code() |
|
917 | - { |
|
918 | - return $this->get_pretty('LIN_total', 'no_currency_code'); |
|
919 | - } |
|
920 | - |
|
921 | - |
|
922 | - /** |
|
923 | - * Gets the final total on this item, taking taxes into account. |
|
924 | - * Has the side-effect of setting the sub-total as it was just calculated. |
|
925 | - * If this is used on a grand-total line item, also updates the transaction's |
|
926 | - * TXN_total (provided this line item is allowed to persist, otherwise we don't |
|
927 | - * want to change a persistable transaction with info from a non-persistent line item) |
|
928 | - * |
|
929 | - * @return float |
|
930 | - * @throws EE_Error |
|
931 | - * @throws InvalidArgumentException |
|
932 | - * @throws InvalidInterfaceException |
|
933 | - * @throws InvalidDataTypeException |
|
934 | - */ |
|
935 | - public function recalculate_total_including_taxes() |
|
936 | - { |
|
937 | - $pre_tax_total = $this->recalculate_pre_tax_total(); |
|
938 | - $tax_total = $this->recalculate_taxes_and_tax_total(); |
|
939 | - $total = $pre_tax_total + $tax_total; |
|
940 | - // no negative totals plz |
|
941 | - $total = max($total, 0); |
|
942 | - $this->set_total($total); |
|
943 | - //only update the related transaction's total |
|
944 | - //if we intend to save this line item and its a grand total |
|
945 | - if ( |
|
946 | - $this->allow_persist() && $this->type() === EEM_Line_Item::type_total |
|
947 | - && $this->transaction() |
|
948 | - instanceof |
|
949 | - EE_Transaction |
|
950 | - ) { |
|
951 | - $this->transaction()->set_total($total); |
|
952 | - if ($this->transaction()->ID()) { |
|
953 | - $this->transaction()->save(); |
|
954 | - } |
|
955 | - } |
|
956 | - $this->maybe_save(); |
|
957 | - return $total; |
|
958 | - } |
|
959 | - |
|
960 | - |
|
961 | - /** |
|
962 | - * Recursively goes through all the children and recalculates sub-totals EXCEPT for |
|
963 | - * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its |
|
964 | - * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and |
|
965 | - * when this is called on the grand total |
|
966 | - * |
|
967 | - * @return float |
|
968 | - * @throws InvalidArgumentException |
|
969 | - * @throws InvalidInterfaceException |
|
970 | - * @throws InvalidDataTypeException |
|
971 | - * @throws EE_Error |
|
972 | - */ |
|
973 | - public function recalculate_pre_tax_total() |
|
974 | - { |
|
975 | - $total = 0; |
|
976 | - $my_children = $this->children(); |
|
977 | - $has_children = !empty($my_children); |
|
978 | - if ($has_children && $this->is_line_item()) { |
|
979 | - $total = $this->_recalculate_pretax_total_for_line_item($total, $my_children); |
|
980 | - } elseif (!$has_children && ($this->is_sub_line_item() || $this->is_line_item())) { |
|
981 | - $total = $this->unit_price() * $this->quantity(); |
|
982 | - } elseif ($this->is_sub_total() || $this->is_total()) { |
|
983 | - $total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children); |
|
984 | - } elseif ($this->is_tax_sub_total() || $this->is_tax() || $this->is_cancelled()) { |
|
985 | - // completely ignore tax totals, tax sub-totals, and cancelled line items, when calculating the pre-tax-total |
|
986 | - return 0; |
|
987 | - } |
|
988 | - // ensure all non-line items and non-sub-line-items have a quantity of 1 (except for Events) |
|
989 | - if ( |
|
990 | - !$this->is_line_item() && !$this->is_sub_line_item() && !$this->is_cancellation() |
|
991 | - ) { |
|
992 | - if ($this->OBJ_type() !== 'Event') { |
|
993 | - $this->set_quantity(1); |
|
994 | - } |
|
995 | - if (!$this->is_percent()) { |
|
996 | - $this->set_unit_price($total); |
|
997 | - } |
|
998 | - } |
|
999 | - //we don't want to bother saving grand totals, because that needs to factor in taxes anyways |
|
1000 | - //so it ought to be |
|
1001 | - if (!$this->is_total()) { |
|
1002 | - $this->set_total($total); |
|
1003 | - //if not a percent line item, make sure we keep the unit price in sync |
|
1004 | - if ( |
|
1005 | - $has_children |
|
1006 | - && $this->is_line_item() |
|
1007 | - && !$this->is_percent() |
|
1008 | - ) { |
|
1009 | - if ($this->quantity() === 0) { |
|
1010 | - $new_unit_price = 0; |
|
1011 | - } else { |
|
1012 | - $new_unit_price = $this->total() / $this->quantity(); |
|
1013 | - } |
|
1014 | - $this->set_unit_price($new_unit_price); |
|
1015 | - } |
|
1016 | - $this->maybe_save(); |
|
1017 | - } |
|
1018 | - return $total; |
|
1019 | - } |
|
1020 | - |
|
1021 | - |
|
1022 | - /** |
|
1023 | - * Calculates the pretax total when this line item is a subtotal or total line item. |
|
1024 | - * Basically does a sum-then-round approach (ie, any percent line item that are children |
|
1025 | - * will calculate their total based on the un-rounded total we're working with so far, and |
|
1026 | - * THEN round the result; instead of rounding as we go like with sub-line-items) |
|
1027 | - * |
|
1028 | - * @param float $calculated_total_so_far |
|
1029 | - * @param EE_Line_Item[] $my_children |
|
1030 | - * @return float |
|
1031 | - * @throws InvalidArgumentException |
|
1032 | - * @throws InvalidInterfaceException |
|
1033 | - * @throws InvalidDataTypeException |
|
1034 | - * @throws EE_Error |
|
1035 | - */ |
|
1036 | - protected function _recalculate_pretax_total_for_subtotal($calculated_total_so_far, $my_children = null) |
|
1037 | - { |
|
1038 | - if ($my_children === null) { |
|
1039 | - $my_children = $this->children(); |
|
1040 | - } |
|
1041 | - $subtotal_quantity = 0; |
|
1042 | - //get the total of all its children |
|
1043 | - foreach ($my_children as $child_line_item) { |
|
1044 | - if ($child_line_item instanceof EE_Line_Item && !$child_line_item->is_cancellation()) { |
|
1045 | - // percentage line items are based on total so far |
|
1046 | - if ($child_line_item->is_percent()) { |
|
1047 | - //round as we go so that the line items add up ok |
|
1048 | - $percent_total = round( |
|
1049 | - $calculated_total_so_far * $child_line_item->percent() / 100, |
|
1050 | - EE_Registry::instance()->CFG->currency->dec_plc |
|
1051 | - ); |
|
1052 | - $child_line_item->set_total($percent_total); |
|
1053 | - //so far all percent line items should have a quantity of 1 |
|
1054 | - //(ie, no double percent discounts. Although that might be requested someday) |
|
1055 | - $child_line_item->set_quantity(1); |
|
1056 | - $child_line_item->maybe_save(); |
|
1057 | - $calculated_total_so_far += $percent_total; |
|
1058 | - } else { |
|
1059 | - //verify flat sub-line-item quantities match their parent |
|
1060 | - if ($child_line_item->is_sub_line_item()) { |
|
1061 | - $child_line_item->set_quantity($this->quantity()); |
|
1062 | - } |
|
1063 | - $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total(); |
|
1064 | - $subtotal_quantity += $child_line_item->quantity(); |
|
1065 | - } |
|
1066 | - } |
|
1067 | - } |
|
1068 | - if ($this->is_sub_total()) { |
|
1069 | - // no negative totals plz |
|
1070 | - $calculated_total_so_far = max($calculated_total_so_far, 0); |
|
1071 | - $subtotal_quantity = $subtotal_quantity > 0 ? 1 : 0; |
|
1072 | - $this->set_quantity($subtotal_quantity); |
|
1073 | - $this->maybe_save(); |
|
1074 | - } |
|
1075 | - return $calculated_total_so_far; |
|
1076 | - } |
|
1077 | - |
|
1078 | - |
|
1079 | - /** |
|
1080 | - * Calculates the pretax total for a normal line item, in a round-then-sum approach |
|
1081 | - * (where each sub-line-item is applied to the base price for the line item |
|
1082 | - * and the result is immediately rounded, rather than summing all the sub-line-items |
|
1083 | - * then rounding, like we do when recalculating pretax totals on totals and subtotals). |
|
1084 | - * |
|
1085 | - * @param float $calculated_total_so_far |
|
1086 | - * @param EE_Line_Item[] $my_children |
|
1087 | - * @return float |
|
1088 | - * @throws InvalidArgumentException |
|
1089 | - * @throws InvalidInterfaceException |
|
1090 | - * @throws InvalidDataTypeException |
|
1091 | - * @throws EE_Error |
|
1092 | - */ |
|
1093 | - protected function _recalculate_pretax_total_for_line_item($calculated_total_so_far, $my_children = null) |
|
1094 | - { |
|
1095 | - if ($my_children === null) { |
|
1096 | - $my_children = $this->children(); |
|
1097 | - } |
|
1098 | - //we need to keep track of the running total for a single item, |
|
1099 | - //because we need to round as we go |
|
1100 | - $unit_price_for_total = 0; |
|
1101 | - $quantity_for_total = 1; |
|
1102 | - //get the total of all its children |
|
1103 | - foreach ($my_children as $child_line_item) { |
|
1104 | - if ($child_line_item instanceof EE_Line_Item && !$child_line_item->is_cancellation()) { |
|
1105 | - if ($child_line_item->is_percent()) { |
|
1106 | - //it should be the unit-price-so-far multiplied by teh percent multiplied by the quantity |
|
1107 | - //not total multiplied by percent, because that ignores rounding along-the-way |
|
1108 | - $percent_unit_price = round( |
|
1109 | - $unit_price_for_total * $child_line_item->percent() / 100, |
|
1110 | - EE_Registry::instance()->CFG->currency->dec_plc |
|
1111 | - ); |
|
1112 | - $percent_total = $percent_unit_price * $quantity_for_total; |
|
1113 | - $child_line_item->set_total($percent_total); |
|
1114 | - //so far all percent line items should have a quantity of 1 |
|
1115 | - //(ie, no double percent discounts. Although that might be requested someday) |
|
1116 | - $child_line_item->set_quantity(1); |
|
1117 | - $child_line_item->maybe_save(); |
|
1118 | - $calculated_total_so_far += $percent_total; |
|
1119 | - $unit_price_for_total += $percent_unit_price; |
|
1120 | - } else { |
|
1121 | - //verify flat sub-line-item quantities match their parent |
|
1122 | - if ($child_line_item->is_sub_line_item()) { |
|
1123 | - $child_line_item->set_quantity($this->quantity()); |
|
1124 | - } |
|
1125 | - $quantity_for_total = $child_line_item->quantity(); |
|
1126 | - $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total(); |
|
1127 | - $unit_price_for_total += $child_line_item->unit_price(); |
|
1128 | - } |
|
1129 | - } |
|
1130 | - } |
|
1131 | - return $calculated_total_so_far; |
|
1132 | - } |
|
1133 | - |
|
1134 | - |
|
1135 | - /** |
|
1136 | - * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets |
|
1137 | - * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items |
|
1138 | - * and tax sub-total if already in the DB |
|
1139 | - * |
|
1140 | - * @return float |
|
1141 | - * @throws EE_Error |
|
1142 | - */ |
|
1143 | - public function recalculate_taxes_and_tax_total() |
|
1144 | - { |
|
1145 | - //get all taxes |
|
1146 | - $taxes = $this->tax_descendants(); |
|
1147 | - //calculate the pretax total |
|
1148 | - $taxable_total = $this->taxable_total(); |
|
1149 | - $tax_total = 0; |
|
1150 | - foreach ($taxes as $tax) { |
|
1151 | - $total_on_this_tax = $taxable_total * $tax->percent() / 100; |
|
1152 | - //remember the total on this line item |
|
1153 | - $tax->set_total($total_on_this_tax); |
|
1154 | - $tax->maybe_save(); |
|
1155 | - $tax_total += $tax->total(); |
|
1156 | - } |
|
1157 | - $this->_recalculate_tax_sub_total(); |
|
1158 | - return $tax_total; |
|
1159 | - } |
|
1160 | - |
|
1161 | - |
|
1162 | - /** |
|
1163 | - * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated |
|
1164 | - * |
|
1165 | - * @return void |
|
1166 | - * @throws EE_Error |
|
1167 | - */ |
|
1168 | - private function _recalculate_tax_sub_total() |
|
1169 | - { |
|
1170 | - if ($this->is_tax_sub_total()) { |
|
1171 | - $total = 0; |
|
1172 | - $total_percent = 0; |
|
1173 | - //simply loop through all its children (which should be taxes) and sum their total |
|
1174 | - foreach ($this->children() as $child_tax) { |
|
1175 | - if ($child_tax instanceof EE_Line_Item) { |
|
1176 | - $total += $child_tax->total(); |
|
1177 | - $total_percent += $child_tax->percent(); |
|
1178 | - } |
|
1179 | - } |
|
1180 | - $this->set_total($total); |
|
1181 | - $this->set_percent($total_percent); |
|
1182 | - $this->maybe_save(); |
|
1183 | - } elseif ($this->is_total()) { |
|
1184 | - foreach ($this->children() as $maybe_tax_subtotal) { |
|
1185 | - if ($maybe_tax_subtotal instanceof EE_Line_Item) { |
|
1186 | - $maybe_tax_subtotal->_recalculate_tax_sub_total(); |
|
1187 | - } |
|
1188 | - } |
|
1189 | - } |
|
1190 | - } |
|
1191 | - |
|
1192 | - |
|
1193 | - /** |
|
1194 | - * Gets the total tax on this line item. Assumes taxes have already been calculated using |
|
1195 | - * recalculate_taxes_and_total |
|
1196 | - * |
|
1197 | - * @return float |
|
1198 | - * @throws EE_Error |
|
1199 | - */ |
|
1200 | - public function get_total_tax() |
|
1201 | - { |
|
1202 | - $this->_recalculate_tax_sub_total(); |
|
1203 | - $total = 0; |
|
1204 | - foreach ($this->tax_descendants() as $tax_line_item) { |
|
1205 | - if ($tax_line_item instanceof EE_Line_Item) { |
|
1206 | - $total += $tax_line_item->total(); |
|
1207 | - } |
|
1208 | - } |
|
1209 | - return $total; |
|
1210 | - } |
|
1211 | - |
|
1212 | - |
|
1213 | - /** |
|
1214 | - * Gets the total for all the items purchased only |
|
1215 | - * |
|
1216 | - * @return float |
|
1217 | - * @throws EE_Error |
|
1218 | - */ |
|
1219 | - public function get_items_total() |
|
1220 | - { |
|
1221 | - //by default, let's make sure we're consistent with the existing line item |
|
1222 | - if ($this->is_total()) { |
|
1223 | - $pretax_subtotal_li = EEH_Line_Item::get_pre_tax_subtotal($this); |
|
1224 | - if ($pretax_subtotal_li instanceof EE_Line_Item) { |
|
1225 | - return $pretax_subtotal_li->total(); |
|
1226 | - } |
|
1227 | - } |
|
1228 | - $total = 0; |
|
1229 | - foreach ($this->get_items() as $item) { |
|
1230 | - if ($item instanceof EE_Line_Item) { |
|
1231 | - $total += $item->total(); |
|
1232 | - } |
|
1233 | - } |
|
1234 | - return $total; |
|
1235 | - } |
|
1236 | - |
|
1237 | - |
|
1238 | - /** |
|
1239 | - * Gets all the descendants (ie, children or children of children etc) that |
|
1240 | - * are of the type 'tax' |
|
1241 | - * |
|
1242 | - * @return EE_Line_Item[] |
|
1243 | - */ |
|
1244 | - public function tax_descendants() |
|
1245 | - { |
|
1246 | - return EEH_Line_Item::get_tax_descendants($this); |
|
1247 | - } |
|
1248 | - |
|
1249 | - |
|
1250 | - /** |
|
1251 | - * Gets all the real items purchased which are children of this item |
|
1252 | - * |
|
1253 | - * @return EE_Line_Item[] |
|
1254 | - */ |
|
1255 | - public function get_items() |
|
1256 | - { |
|
1257 | - return EEH_Line_Item::get_line_item_descendants($this); |
|
1258 | - } |
|
1259 | - |
|
1260 | - |
|
1261 | - /** |
|
1262 | - * Returns the amount taxable among this line item's children (or if it has no children, |
|
1263 | - * how much of it is taxable). Does not recalculate totals or subtotals. |
|
1264 | - * If the taxable total is negative, (eg, if none of the tickets were taxable, |
|
1265 | - * but there is a "Taxable" discount), returns 0. |
|
1266 | - * |
|
1267 | - * @return float |
|
1268 | - * @throws EE_Error |
|
1269 | - */ |
|
1270 | - public function taxable_total() |
|
1271 | - { |
|
1272 | - $total = 0; |
|
1273 | - if ($this->children()) { |
|
1274 | - foreach ($this->children() as $child_line_item) { |
|
1275 | - if ($child_line_item->type() === EEM_Line_Item::type_line_item && $child_line_item->is_taxable()) { |
|
1276 | - //if it's a percent item, only take into account the percent |
|
1277 | - //that's taxable too (the taxable total so far) |
|
1278 | - if ($child_line_item->is_percent()) { |
|
1279 | - $total += ($total * $child_line_item->percent() / 100); |
|
1280 | - } else { |
|
1281 | - $total += $child_line_item->total(); |
|
1282 | - } |
|
1283 | - } elseif ($child_line_item->type() === EEM_Line_Item::type_sub_total) { |
|
1284 | - $total += $child_line_item->taxable_total(); |
|
1285 | - } |
|
1286 | - } |
|
1287 | - } |
|
1288 | - return max($total, 0); |
|
1289 | - } |
|
1290 | - |
|
1291 | - |
|
1292 | - /** |
|
1293 | - * Gets the transaction for this line item |
|
1294 | - * |
|
1295 | - * @return EE_Base_Class|EE_Transaction |
|
1296 | - * @throws EE_Error |
|
1297 | - */ |
|
1298 | - public function transaction() |
|
1299 | - { |
|
1300 | - return $this->get_first_related('Transaction'); |
|
1301 | - } |
|
1302 | - |
|
1303 | - |
|
1304 | - /** |
|
1305 | - * Saves this line item to the DB, and recursively saves its descendants. |
|
1306 | - * Because there currently is no proper parent-child relation on the model, |
|
1307 | - * save_this_and_cached() will NOT save the descendants. |
|
1308 | - * Also sets the transaction on this line item and all its descendants before saving |
|
1309 | - * |
|
1310 | - * @param int $txn_id if none is provided, assumes $this->TXN_ID() |
|
1311 | - * @return int count of items saved |
|
1312 | - * @throws EE_Error |
|
1313 | - */ |
|
1314 | - public function save_this_and_descendants_to_txn($txn_id = null) |
|
1315 | - { |
|
1316 | - $count = 0; |
|
1317 | - if (!$txn_id) { |
|
1318 | - $txn_id = $this->TXN_ID(); |
|
1319 | - } |
|
1320 | - $this->set_TXN_ID($txn_id); |
|
1321 | - $children = $this->children(); |
|
1322 | - $count += $this->save() |
|
1323 | - ? 1 |
|
1324 | - : 0; |
|
1325 | - foreach ($children as $child_line_item) { |
|
1326 | - if ($child_line_item instanceof EE_Line_Item) { |
|
1327 | - $child_line_item->set_parent_ID($this->ID()); |
|
1328 | - $count += $child_line_item->save_this_and_descendants_to_txn($txn_id); |
|
1329 | - } |
|
1330 | - } |
|
1331 | - return $count; |
|
1332 | - } |
|
1333 | - |
|
1334 | - |
|
1335 | - /** |
|
1336 | - * Saves this line item to the DB, and recursively saves its descendants. |
|
1337 | - * |
|
1338 | - * @return int count of items saved |
|
1339 | - * @throws EE_Error |
|
1340 | - */ |
|
1341 | - public function save_this_and_descendants() |
|
1342 | - { |
|
1343 | - $count = 0; |
|
1344 | - $children = $this->children(); |
|
1345 | - $count += $this->save() |
|
1346 | - ? 1 |
|
1347 | - : 0; |
|
1348 | - foreach ($children as $child_line_item) { |
|
1349 | - if ($child_line_item instanceof EE_Line_Item) { |
|
1350 | - $child_line_item->set_parent_ID($this->ID()); |
|
1351 | - $count += $child_line_item->save_this_and_descendants(); |
|
1352 | - } |
|
1353 | - } |
|
1354 | - return $count; |
|
1355 | - } |
|
1356 | - |
|
1357 | - |
|
1358 | - /** |
|
1359 | - * returns the cancellation line item if this item was cancelled |
|
1360 | - * |
|
1361 | - * @return EE_Line_Item[] |
|
1362 | - * @throws InvalidArgumentException |
|
1363 | - * @throws InvalidInterfaceException |
|
1364 | - * @throws InvalidDataTypeException |
|
1365 | - * @throws ReflectionException |
|
1366 | - * @throws EE_Error |
|
1367 | - */ |
|
1368 | - public function get_cancellations() |
|
1369 | - { |
|
1370 | - EE_Registry::instance()->load_helper('Line_Item'); |
|
1371 | - return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation); |
|
1372 | - } |
|
1373 | - |
|
1374 | - |
|
1375 | - /** |
|
1376 | - * If this item has an ID, then this saves it again to update the db |
|
1377 | - * |
|
1378 | - * @return int count of items saved |
|
1379 | - * @throws EE_Error |
|
1380 | - */ |
|
1381 | - public function maybe_save() |
|
1382 | - { |
|
1383 | - if ($this->ID()) { |
|
1384 | - return $this->save(); |
|
1385 | - } |
|
1386 | - return false; |
|
1387 | - } |
|
1388 | - |
|
1389 | - |
|
1390 | - /** |
|
1391 | - * clears the cached children and parent from the line item |
|
1392 | - * |
|
1393 | - * @return void |
|
1394 | - */ |
|
1395 | - public function clear_related_line_item_cache() |
|
1396 | - { |
|
1397 | - $this->_children = array(); |
|
1398 | - $this->_parent = null; |
|
1399 | - } |
|
1400 | - |
|
1401 | - |
|
1402 | - /** |
|
1403 | - * @param bool $raw |
|
1404 | - * @return int |
|
1405 | - * @throws EE_Error |
|
1406 | - */ |
|
1407 | - public function timestamp($raw = false) |
|
1408 | - { |
|
1409 | - return $raw |
|
1410 | - ? $this->get_raw('LIN_timestamp') |
|
1411 | - : $this->get('LIN_timestamp'); |
|
1412 | - } |
|
1413 | - |
|
1414 | - |
|
1415 | - |
|
1416 | - |
|
1417 | - /************************* DEPRECATED *************************/ |
|
1418 | - /** |
|
1419 | - * @deprecated 4.6.0 |
|
1420 | - * @param string $type one of the constants on EEM_Line_Item |
|
1421 | - * @return EE_Line_Item[] |
|
1422 | - */ |
|
1423 | - protected function _get_descendants_of_type($type) |
|
1424 | - { |
|
1425 | - EE_Error::doing_it_wrong( |
|
1426 | - 'EE_Line_Item::_get_descendants_of_type()', |
|
1427 | - __('Method replaced with EEH_Line_Item::get_descendants_of_type()', 'event_espresso'), '4.6.0' |
|
1428 | - ); |
|
1429 | - return EEH_Line_Item::get_descendants_of_type($this, $type); |
|
1430 | - } |
|
1431 | - |
|
1432 | - |
|
1433 | - /** |
|
1434 | - * @deprecated 4.6.0 |
|
1435 | - * @param string $type like one of the EEM_Line_Item::type_* |
|
1436 | - * @return EE_Line_Item |
|
1437 | - */ |
|
1438 | - public function get_nearest_descendant_of_type($type) |
|
1439 | - { |
|
1440 | - EE_Error::doing_it_wrong( |
|
1441 | - 'EE_Line_Item::get_nearest_descendant_of_type()', |
|
1442 | - __('Method replaced with EEH_Line_Item::get_nearest_descendant_of_type()', 'event_espresso'), '4.6.0' |
|
1443 | - ); |
|
1444 | - return EEH_Line_Item::get_nearest_descendant_of_type($this, $type); |
|
1445 | - } |
|
20 | + /** |
|
21 | + * for children line items (currently not a normal relation) |
|
22 | + * |
|
23 | + * @type EE_Line_Item[] |
|
24 | + */ |
|
25 | + protected $_children = array(); |
|
26 | + |
|
27 | + /** |
|
28 | + * for the parent line item |
|
29 | + * |
|
30 | + * @var EE_Line_Item |
|
31 | + */ |
|
32 | + protected $_parent; |
|
33 | + |
|
34 | + |
|
35 | + /** |
|
36 | + * |
|
37 | + * @param array $props_n_values incoming values |
|
38 | + * @param string $timezone incoming timezone (if not set the timezone set for the website will be |
|
39 | + * used.) |
|
40 | + * @param array $date_formats incoming date_formats in an array where the first value is the |
|
41 | + * date_format and the second value is the time format |
|
42 | + * @return EE_Line_Item |
|
43 | + * @throws EE_Error |
|
44 | + */ |
|
45 | + public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
46 | + { |
|
47 | + $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats); |
|
48 | + return $has_object |
|
49 | + ? $has_object |
|
50 | + : new self($props_n_values, false, $timezone); |
|
51 | + } |
|
52 | + |
|
53 | + |
|
54 | + /** |
|
55 | + * @param array $props_n_values incoming values from the database |
|
56 | + * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
57 | + * the website will be used. |
|
58 | + * @return EE_Line_Item |
|
59 | + * @throws EE_Error |
|
60 | + */ |
|
61 | + public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
62 | + { |
|
63 | + return new self($props_n_values, true, $timezone); |
|
64 | + } |
|
65 | + |
|
66 | + |
|
67 | + /** |
|
68 | + * Adds some defaults if they're not specified |
|
69 | + * |
|
70 | + * @param array $fieldValues |
|
71 | + * @param bool $bydb |
|
72 | + * @param string $timezone |
|
73 | + * @throws EE_Error |
|
74 | + */ |
|
75 | + protected function __construct($fieldValues = array(), $bydb = false, $timezone = '') |
|
76 | + { |
|
77 | + parent::__construct($fieldValues, $bydb, $timezone); |
|
78 | + if (!$this->get('LIN_code')) { |
|
79 | + $this->set_code($this->generate_code()); |
|
80 | + } |
|
81 | + } |
|
82 | + |
|
83 | + |
|
84 | + /** |
|
85 | + * Gets ID |
|
86 | + * |
|
87 | + * @return int |
|
88 | + * @throws EE_Error |
|
89 | + */ |
|
90 | + public function ID() |
|
91 | + { |
|
92 | + return $this->get('LIN_ID'); |
|
93 | + } |
|
94 | + |
|
95 | + |
|
96 | + /** |
|
97 | + * Gets TXN_ID |
|
98 | + * |
|
99 | + * @return int |
|
100 | + * @throws EE_Error |
|
101 | + */ |
|
102 | + public function TXN_ID() |
|
103 | + { |
|
104 | + return $this->get('TXN_ID'); |
|
105 | + } |
|
106 | + |
|
107 | + |
|
108 | + /** |
|
109 | + * Sets TXN_ID |
|
110 | + * |
|
111 | + * @param int $TXN_ID |
|
112 | + * @throws EE_Error |
|
113 | + */ |
|
114 | + public function set_TXN_ID($TXN_ID) |
|
115 | + { |
|
116 | + $this->set('TXN_ID', $TXN_ID); |
|
117 | + } |
|
118 | + |
|
119 | + |
|
120 | + /** |
|
121 | + * Gets name |
|
122 | + * |
|
123 | + * @return string |
|
124 | + * @throws EE_Error |
|
125 | + */ |
|
126 | + public function name() |
|
127 | + { |
|
128 | + $name = $this->get('LIN_name'); |
|
129 | + if (!$name) { |
|
130 | + $name = ucwords(str_replace('-', ' ', $this->type())); |
|
131 | + } |
|
132 | + return $name; |
|
133 | + } |
|
134 | + |
|
135 | + |
|
136 | + /** |
|
137 | + * Sets name |
|
138 | + * |
|
139 | + * @param string $name |
|
140 | + * @throws EE_Error |
|
141 | + */ |
|
142 | + public function set_name($name) |
|
143 | + { |
|
144 | + $this->set('LIN_name', $name); |
|
145 | + } |
|
146 | + |
|
147 | + |
|
148 | + /** |
|
149 | + * Gets desc |
|
150 | + * |
|
151 | + * @return string |
|
152 | + * @throws EE_Error |
|
153 | + */ |
|
154 | + public function desc() |
|
155 | + { |
|
156 | + return $this->get('LIN_desc'); |
|
157 | + } |
|
158 | + |
|
159 | + |
|
160 | + /** |
|
161 | + * Sets desc |
|
162 | + * |
|
163 | + * @param string $desc |
|
164 | + * @throws EE_Error |
|
165 | + */ |
|
166 | + public function set_desc($desc) |
|
167 | + { |
|
168 | + $this->set('LIN_desc', $desc); |
|
169 | + } |
|
170 | + |
|
171 | + |
|
172 | + /** |
|
173 | + * Gets quantity |
|
174 | + * |
|
175 | + * @return int |
|
176 | + * @throws EE_Error |
|
177 | + */ |
|
178 | + public function quantity() |
|
179 | + { |
|
180 | + return $this->get('LIN_quantity'); |
|
181 | + } |
|
182 | + |
|
183 | + |
|
184 | + /** |
|
185 | + * Sets quantity |
|
186 | + * |
|
187 | + * @param int $quantity |
|
188 | + * @throws EE_Error |
|
189 | + */ |
|
190 | + public function set_quantity($quantity) |
|
191 | + { |
|
192 | + $this->set('LIN_quantity', max($quantity, 0)); |
|
193 | + } |
|
194 | + |
|
195 | + |
|
196 | + /** |
|
197 | + * Gets item_id |
|
198 | + * |
|
199 | + * @return string |
|
200 | + * @throws EE_Error |
|
201 | + */ |
|
202 | + public function OBJ_ID() |
|
203 | + { |
|
204 | + return $this->get('OBJ_ID'); |
|
205 | + } |
|
206 | + |
|
207 | + |
|
208 | + /** |
|
209 | + * Sets item_id |
|
210 | + * |
|
211 | + * @param string $item_id |
|
212 | + * @throws EE_Error |
|
213 | + */ |
|
214 | + public function set_OBJ_ID($item_id) |
|
215 | + { |
|
216 | + $this->set('OBJ_ID', $item_id); |
|
217 | + } |
|
218 | + |
|
219 | + |
|
220 | + /** |
|
221 | + * Gets item_type |
|
222 | + * |
|
223 | + * @return string |
|
224 | + * @throws EE_Error |
|
225 | + */ |
|
226 | + public function OBJ_type() |
|
227 | + { |
|
228 | + return $this->get('OBJ_type'); |
|
229 | + } |
|
230 | + |
|
231 | + |
|
232 | + /** |
|
233 | + * Gets item_type |
|
234 | + * |
|
235 | + * @return string |
|
236 | + * @throws EE_Error |
|
237 | + */ |
|
238 | + public function OBJ_type_i18n() |
|
239 | + { |
|
240 | + $obj_type = $this->OBJ_type(); |
|
241 | + switch ($obj_type) { |
|
242 | + case 'Event': |
|
243 | + $obj_type = __('Event', 'event_espresso'); |
|
244 | + break; |
|
245 | + case 'Price': |
|
246 | + $obj_type = __('Price', 'event_espresso'); |
|
247 | + break; |
|
248 | + case 'Promotion': |
|
249 | + $obj_type = __('Promotion', 'event_espresso'); |
|
250 | + break; |
|
251 | + case 'Ticket': |
|
252 | + $obj_type = __('Ticket', 'event_espresso'); |
|
253 | + break; |
|
254 | + case 'Transaction': |
|
255 | + $obj_type = __('Transaction', 'event_espresso'); |
|
256 | + break; |
|
257 | + } |
|
258 | + return apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this); |
|
259 | + } |
|
260 | + |
|
261 | + |
|
262 | + /** |
|
263 | + * Sets item_type |
|
264 | + * |
|
265 | + * @param string $OBJ_type |
|
266 | + * @throws EE_Error |
|
267 | + */ |
|
268 | + public function set_OBJ_type($OBJ_type) |
|
269 | + { |
|
270 | + $this->set('OBJ_type', $OBJ_type); |
|
271 | + } |
|
272 | + |
|
273 | + |
|
274 | + /** |
|
275 | + * Gets unit_price |
|
276 | + * |
|
277 | + * @return float |
|
278 | + * @throws EE_Error |
|
279 | + */ |
|
280 | + public function unit_price() |
|
281 | + { |
|
282 | + return $this->get('LIN_unit_price'); |
|
283 | + } |
|
284 | + |
|
285 | + |
|
286 | + /** |
|
287 | + * Sets unit_price |
|
288 | + * |
|
289 | + * @param float $unit_price |
|
290 | + * @throws EE_Error |
|
291 | + */ |
|
292 | + public function set_unit_price($unit_price) |
|
293 | + { |
|
294 | + $this->set('LIN_unit_price', $unit_price); |
|
295 | + } |
|
296 | + |
|
297 | + |
|
298 | + /** |
|
299 | + * Checks if this item is a percentage modifier or not |
|
300 | + * |
|
301 | + * @return boolean |
|
302 | + * @throws EE_Error |
|
303 | + */ |
|
304 | + public function is_percent() |
|
305 | + { |
|
306 | + if ($this->is_tax_sub_total()) { |
|
307 | + //tax subtotals HAVE a percent on them, that percentage only applies |
|
308 | + //to taxable items, so its' an exception. Treat it like a flat line item |
|
309 | + return false; |
|
310 | + } |
|
311 | + $unit_price = abs($this->get('LIN_unit_price')); |
|
312 | + $percent = abs($this->get('LIN_percent')); |
|
313 | + if ($unit_price < .001 && $percent) { |
|
314 | + return true; |
|
315 | + } |
|
316 | + if ($unit_price >= .001 && !$percent) { |
|
317 | + return false; |
|
318 | + } |
|
319 | + if ($unit_price >= .001 && $percent) { |
|
320 | + throw new EE_Error( |
|
321 | + sprintf( |
|
322 | + esc_html__('A Line Item can not have a unit price of (%s) AND a percent (%s)!', 'event_espresso'), |
|
323 | + $unit_price, $percent |
|
324 | + ) |
|
325 | + ); |
|
326 | + } |
|
327 | + // if they're both 0, assume its not a percent item |
|
328 | + return false; |
|
329 | + } |
|
330 | + |
|
331 | + |
|
332 | + /** |
|
333 | + * Gets percent (between 100-.001) |
|
334 | + * |
|
335 | + * @return float |
|
336 | + * @throws EE_Error |
|
337 | + */ |
|
338 | + public function percent() |
|
339 | + { |
|
340 | + return $this->get('LIN_percent'); |
|
341 | + } |
|
342 | + |
|
343 | + |
|
344 | + /** |
|
345 | + * Sets percent (between 100-0.01) |
|
346 | + * |
|
347 | + * @param float $percent |
|
348 | + * @throws EE_Error |
|
349 | + */ |
|
350 | + public function set_percent($percent) |
|
351 | + { |
|
352 | + $this->set('LIN_percent', $percent); |
|
353 | + } |
|
354 | + |
|
355 | + |
|
356 | + /** |
|
357 | + * Gets total |
|
358 | + * |
|
359 | + * @return float |
|
360 | + * @throws EE_Error |
|
361 | + */ |
|
362 | + public function total() |
|
363 | + { |
|
364 | + return $this->get('LIN_total'); |
|
365 | + } |
|
366 | + |
|
367 | + |
|
368 | + /** |
|
369 | + * Sets total |
|
370 | + * |
|
371 | + * @param float $total |
|
372 | + * @throws EE_Error |
|
373 | + */ |
|
374 | + public function set_total($total) |
|
375 | + { |
|
376 | + $this->set('LIN_total', $total); |
|
377 | + } |
|
378 | + |
|
379 | + |
|
380 | + /** |
|
381 | + * Gets order |
|
382 | + * |
|
383 | + * @return int |
|
384 | + * @throws EE_Error |
|
385 | + */ |
|
386 | + public function order() |
|
387 | + { |
|
388 | + return $this->get('LIN_order'); |
|
389 | + } |
|
390 | + |
|
391 | + |
|
392 | + /** |
|
393 | + * Sets order |
|
394 | + * |
|
395 | + * @param int $order |
|
396 | + * @throws EE_Error |
|
397 | + */ |
|
398 | + public function set_order($order) |
|
399 | + { |
|
400 | + $this->set('LIN_order', $order); |
|
401 | + } |
|
402 | + |
|
403 | + |
|
404 | + /** |
|
405 | + * Gets parent |
|
406 | + * |
|
407 | + * @return int |
|
408 | + * @throws EE_Error |
|
409 | + */ |
|
410 | + public function parent_ID() |
|
411 | + { |
|
412 | + return $this->get('LIN_parent'); |
|
413 | + } |
|
414 | + |
|
415 | + |
|
416 | + /** |
|
417 | + * Sets parent |
|
418 | + * |
|
419 | + * @param int $parent |
|
420 | + * @throws EE_Error |
|
421 | + */ |
|
422 | + public function set_parent_ID($parent) |
|
423 | + { |
|
424 | + $this->set('LIN_parent', $parent); |
|
425 | + } |
|
426 | + |
|
427 | + |
|
428 | + /** |
|
429 | + * Gets type |
|
430 | + * |
|
431 | + * @return string |
|
432 | + * @throws EE_Error |
|
433 | + */ |
|
434 | + public function type() |
|
435 | + { |
|
436 | + return $this->get('LIN_type'); |
|
437 | + } |
|
438 | + |
|
439 | + |
|
440 | + /** |
|
441 | + * Sets type |
|
442 | + * |
|
443 | + * @param string $type |
|
444 | + * @throws EE_Error |
|
445 | + */ |
|
446 | + public function set_type($type) |
|
447 | + { |
|
448 | + $this->set('LIN_type', $type); |
|
449 | + } |
|
450 | + |
|
451 | + |
|
452 | + /** |
|
453 | + * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\ |
|
454 | + * If this line item is saved to the DB, fetches the parent from the DB. However, if this line item isn't in the DB |
|
455 | + * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()` |
|
456 | + * or indirectly by `EE_Line_item::add_child_line_item()`) |
|
457 | + * |
|
458 | + * @return EE_Base_Class|EE_Line_Item |
|
459 | + * @throws EE_Error |
|
460 | + */ |
|
461 | + public function parent() |
|
462 | + { |
|
463 | + return $this->ID() |
|
464 | + ? $this->get_model()->get_one_by_ID($this->parent_ID()) |
|
465 | + : $this->_parent; |
|
466 | + } |
|
467 | + |
|
468 | + |
|
469 | + /** |
|
470 | + * Gets ALL the children of this line item (ie, all the parts that contribute towards this total). |
|
471 | + * |
|
472 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
473 | + * @throws EE_Error |
|
474 | + */ |
|
475 | + public function children() |
|
476 | + { |
|
477 | + if ($this->ID()) { |
|
478 | + return $this->get_model()->get_all( |
|
479 | + array( |
|
480 | + array('LIN_parent' => $this->ID()), |
|
481 | + 'order_by' => array('LIN_order' => 'ASC'), |
|
482 | + ) |
|
483 | + ); |
|
484 | + } |
|
485 | + if (!is_array($this->_children)) { |
|
486 | + $this->_children = array(); |
|
487 | + } |
|
488 | + return $this->_children; |
|
489 | + } |
|
490 | + |
|
491 | + |
|
492 | + /** |
|
493 | + * Gets code |
|
494 | + * |
|
495 | + * @return string |
|
496 | + * @throws EE_Error |
|
497 | + */ |
|
498 | + public function code() |
|
499 | + { |
|
500 | + return $this->get('LIN_code'); |
|
501 | + } |
|
502 | + |
|
503 | + |
|
504 | + /** |
|
505 | + * Sets code |
|
506 | + * |
|
507 | + * @param string $code |
|
508 | + * @throws EE_Error |
|
509 | + */ |
|
510 | + public function set_code($code) |
|
511 | + { |
|
512 | + $this->set('LIN_code', $code); |
|
513 | + } |
|
514 | + |
|
515 | + |
|
516 | + /** |
|
517 | + * Gets is_taxable |
|
518 | + * |
|
519 | + * @return boolean |
|
520 | + * @throws EE_Error |
|
521 | + */ |
|
522 | + public function is_taxable() |
|
523 | + { |
|
524 | + return $this->get('LIN_is_taxable'); |
|
525 | + } |
|
526 | + |
|
527 | + |
|
528 | + /** |
|
529 | + * Sets is_taxable |
|
530 | + * |
|
531 | + * @param boolean $is_taxable |
|
532 | + * @throws EE_Error |
|
533 | + */ |
|
534 | + public function set_is_taxable($is_taxable) |
|
535 | + { |
|
536 | + $this->set('LIN_is_taxable', $is_taxable); |
|
537 | + } |
|
538 | + |
|
539 | + |
|
540 | + /** |
|
541 | + * Gets the object that this model-joins-to. |
|
542 | + * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on |
|
543 | + * EEM_Promotion_Object |
|
544 | + * |
|
545 | + * Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object |
|
546 | + * |
|
547 | + * @return EE_Base_Class | NULL |
|
548 | + * @throws EE_Error |
|
549 | + */ |
|
550 | + public function get_object() |
|
551 | + { |
|
552 | + $model_name_of_related_obj = $this->OBJ_type(); |
|
553 | + return $this->get_model()->has_relation($model_name_of_related_obj) |
|
554 | + ? $this->get_first_related($model_name_of_related_obj) |
|
555 | + : null; |
|
556 | + } |
|
557 | + |
|
558 | + |
|
559 | + /** |
|
560 | + * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket. |
|
561 | + * (IE, if this line item is for a price or something else, will return NULL) |
|
562 | + * |
|
563 | + * @param array $query_params |
|
564 | + * @return EE_Base_Class|EE_Ticket |
|
565 | + * @throws EE_Error |
|
566 | + */ |
|
567 | + public function ticket($query_params = array()) |
|
568 | + { |
|
569 | + //we're going to assume that when this method is called we always want to receive the attached ticket EVEN if that ticket is archived. This can be overridden via the incoming $query_params argument |
|
570 | + $remove_defaults = array('default_where_conditions' => 'none'); |
|
571 | + $query_params = array_merge($remove_defaults, $query_params); |
|
572 | + return $this->get_first_related('Ticket', $query_params); |
|
573 | + } |
|
574 | + |
|
575 | + |
|
576 | + /** |
|
577 | + * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket |
|
578 | + * |
|
579 | + * @return EE_Datetime | NULL |
|
580 | + * @throws EE_Error |
|
581 | + */ |
|
582 | + public function get_ticket_datetime() |
|
583 | + { |
|
584 | + if ($this->OBJ_type() === 'Ticket') { |
|
585 | + $ticket = $this->ticket(); |
|
586 | + if ($ticket instanceof EE_Ticket) { |
|
587 | + $datetime = $ticket->first_datetime(); |
|
588 | + if ($datetime instanceof EE_Datetime) { |
|
589 | + return $datetime; |
|
590 | + } |
|
591 | + } |
|
592 | + } |
|
593 | + return null; |
|
594 | + } |
|
595 | + |
|
596 | + |
|
597 | + /** |
|
598 | + * Gets the event's name that's related to the ticket, if this is for |
|
599 | + * a ticket |
|
600 | + * |
|
601 | + * @return string |
|
602 | + * @throws EE_Error |
|
603 | + */ |
|
604 | + public function ticket_event_name() |
|
605 | + { |
|
606 | + $event_name = esc_html__('Unknown', 'event_espresso'); |
|
607 | + $event = $this->ticket_event(); |
|
608 | + if ($event instanceof EE_Event) { |
|
609 | + $event_name = $event->name(); |
|
610 | + } |
|
611 | + return $event_name; |
|
612 | + } |
|
613 | + |
|
614 | + |
|
615 | + /** |
|
616 | + * Gets the event that's related to the ticket, if this line item represents a ticket. |
|
617 | + * |
|
618 | + * @return EE_Event|null |
|
619 | + * @throws EE_Error |
|
620 | + */ |
|
621 | + public function ticket_event() |
|
622 | + { |
|
623 | + $event = null; |
|
624 | + $ticket = $this->ticket(); |
|
625 | + if ($ticket instanceof EE_Ticket) { |
|
626 | + $datetime = $ticket->first_datetime(); |
|
627 | + if ($datetime instanceof EE_Datetime) { |
|
628 | + $event = $datetime->event(); |
|
629 | + } |
|
630 | + } |
|
631 | + return $event; |
|
632 | + } |
|
633 | + |
|
634 | + |
|
635 | + /** |
|
636 | + * Gets the first datetime for this lien item, assuming it's for a ticket |
|
637 | + * |
|
638 | + * @param string $date_format |
|
639 | + * @param string $time_format |
|
640 | + * @return string |
|
641 | + * @throws EE_Error |
|
642 | + */ |
|
643 | + public function ticket_datetime_start($date_format = '', $time_format = '') |
|
644 | + { |
|
645 | + $first_datetime_string = esc_html__('Unknown', 'event_espresso'); |
|
646 | + $datetime = $this->get_ticket_datetime(); |
|
647 | + if ($datetime) { |
|
648 | + $first_datetime_string = $datetime->start_date_and_time($date_format, $time_format); |
|
649 | + } |
|
650 | + return $first_datetime_string; |
|
651 | + } |
|
652 | + |
|
653 | + |
|
654 | + /** |
|
655 | + * Adds the line item as a child to this line item. If there is another child line |
|
656 | + * item with the same LIN_code, it is overwritten by this new one |
|
657 | + * |
|
658 | + * @param EEI_Line_Item $line_item |
|
659 | + * @param bool $set_order |
|
660 | + * @return bool success |
|
661 | + * @throws EE_Error |
|
662 | + */ |
|
663 | + public function add_child_line_item(EEI_Line_Item $line_item, $set_order = true) |
|
664 | + { |
|
665 | + // should we calculate the LIN_order for this line item ? |
|
666 | + if ($set_order || $line_item->order() === null) { |
|
667 | + $line_item->set_order(count($this->children())); |
|
668 | + } |
|
669 | + if ($this->ID()) { |
|
670 | + //check for any duplicate line items (with the same code), if so, this replaces it |
|
671 | + $line_item_with_same_code = $this->get_child_line_item($line_item->code()); |
|
672 | + if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) { |
|
673 | + $this->delete_child_line_item($line_item_with_same_code->code()); |
|
674 | + } |
|
675 | + $line_item->set_parent_ID($this->ID()); |
|
676 | + if ($this->TXN_ID()) { |
|
677 | + $line_item->set_TXN_ID($this->TXN_ID()); |
|
678 | + } |
|
679 | + return $line_item->save(); |
|
680 | + } |
|
681 | + $this->_children[$line_item->code()] = $line_item; |
|
682 | + if ($line_item->parent() !== $this) { |
|
683 | + $line_item->set_parent($this); |
|
684 | + } |
|
685 | + return true; |
|
686 | + } |
|
687 | + |
|
688 | + |
|
689 | + /** |
|
690 | + * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation. |
|
691 | + * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save() |
|
692 | + * However, if this line item is NOT saved to the DB, this just caches the parent on |
|
693 | + * the EE_Line_Item::_parent property. |
|
694 | + * |
|
695 | + * @param EE_Line_Item $line_item |
|
696 | + * @throws EE_Error |
|
697 | + */ |
|
698 | + public function set_parent($line_item) |
|
699 | + { |
|
700 | + if ($this->ID()) { |
|
701 | + if (!$line_item->ID()) { |
|
702 | + $line_item->save(); |
|
703 | + } |
|
704 | + $this->set_parent_ID($line_item->ID()); |
|
705 | + $this->save(); |
|
706 | + } else { |
|
707 | + $this->_parent = $line_item; |
|
708 | + $this->set_parent_ID($line_item->ID()); |
|
709 | + } |
|
710 | + } |
|
711 | + |
|
712 | + |
|
713 | + /** |
|
714 | + * Gets the child line item as specified by its code. Because this returns an object (by reference) |
|
715 | + * you can modify this child line item and the parent (this object) can know about them |
|
716 | + * because it also has a reference to that line item |
|
717 | + * |
|
718 | + * @param string $code |
|
719 | + * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
720 | + * @throws EE_Error |
|
721 | + */ |
|
722 | + public function get_child_line_item($code) |
|
723 | + { |
|
724 | + if ($this->ID()) { |
|
725 | + return $this->get_model()->get_one( |
|
726 | + array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code)) |
|
727 | + ); |
|
728 | + } |
|
729 | + return isset($this->_children[$code]) |
|
730 | + ? $this->_children[$code] |
|
731 | + : null; |
|
732 | + } |
|
733 | + |
|
734 | + |
|
735 | + /** |
|
736 | + * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD |
|
737 | + * cached on it) |
|
738 | + * |
|
739 | + * @return int |
|
740 | + * @throws EE_Error |
|
741 | + */ |
|
742 | + public function delete_children_line_items() |
|
743 | + { |
|
744 | + if ($this->ID()) { |
|
745 | + return $this->get_model()->delete(array(array('LIN_parent' => $this->ID()))); |
|
746 | + } |
|
747 | + $count = count($this->_children); |
|
748 | + $this->_children = array(); |
|
749 | + return $count; |
|
750 | + } |
|
751 | + |
|
752 | + |
|
753 | + /** |
|
754 | + * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line |
|
755 | + * HAS NOT been saved to the DB, removes the child line item with index $code. |
|
756 | + * Also searches through the child's children for a matching line item. However, once a line item has been found |
|
757 | + * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be |
|
758 | + * deleted) |
|
759 | + * |
|
760 | + * @param string $code |
|
761 | + * @param bool $stop_search_once_found |
|
762 | + * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to |
|
763 | + * the DB yet) |
|
764 | + * @throws EE_Error |
|
765 | + */ |
|
766 | + public function delete_child_line_item($code, $stop_search_once_found = true) |
|
767 | + { |
|
768 | + if ($this->ID()) { |
|
769 | + $items_deleted = 0; |
|
770 | + if ($this->code() === $code) { |
|
771 | + $items_deleted += EEH_Line_Item::delete_all_child_items($this); |
|
772 | + $items_deleted += (int)$this->delete(); |
|
773 | + if ($stop_search_once_found) { |
|
774 | + return $items_deleted; |
|
775 | + } |
|
776 | + } |
|
777 | + foreach ($this->children() as $child_line_item) { |
|
778 | + $items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found); |
|
779 | + } |
|
780 | + return $items_deleted; |
|
781 | + } |
|
782 | + if (isset($this->_children[$code])) { |
|
783 | + unset($this->_children[$code]); |
|
784 | + return 1; |
|
785 | + } |
|
786 | + return 0; |
|
787 | + } |
|
788 | + |
|
789 | + |
|
790 | + /** |
|
791 | + * If this line item is in the database, is of the type subtotal, and |
|
792 | + * has no children, why do we have it? It should be deleted so this function |
|
793 | + * does that |
|
794 | + * |
|
795 | + * @return boolean |
|
796 | + * @throws EE_Error |
|
797 | + */ |
|
798 | + public function delete_if_childless_subtotal() |
|
799 | + { |
|
800 | + if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && !$this->children()) { |
|
801 | + return $this->delete(); |
|
802 | + } |
|
803 | + return false; |
|
804 | + } |
|
805 | + |
|
806 | + |
|
807 | + /** |
|
808 | + * Creates a code and returns a string. doesn't assign the code to this model object |
|
809 | + * |
|
810 | + * @return string |
|
811 | + * @throws EE_Error |
|
812 | + */ |
|
813 | + public function generate_code() |
|
814 | + { |
|
815 | + // each line item in the cart requires a unique identifier |
|
816 | + return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime()); |
|
817 | + } |
|
818 | + |
|
819 | + |
|
820 | + /** |
|
821 | + * @return bool |
|
822 | + * @throws EE_Error |
|
823 | + */ |
|
824 | + public function is_tax() |
|
825 | + { |
|
826 | + return $this->type() === EEM_Line_Item::type_tax; |
|
827 | + } |
|
828 | + |
|
829 | + |
|
830 | + /** |
|
831 | + * @return bool |
|
832 | + * @throws EE_Error |
|
833 | + */ |
|
834 | + public function is_tax_sub_total() |
|
835 | + { |
|
836 | + return $this->type() === EEM_Line_Item::type_tax_sub_total; |
|
837 | + } |
|
838 | + |
|
839 | + |
|
840 | + /** |
|
841 | + * @return bool |
|
842 | + * @throws EE_Error |
|
843 | + */ |
|
844 | + public function is_line_item() |
|
845 | + { |
|
846 | + return $this->type() === EEM_Line_Item::type_line_item; |
|
847 | + } |
|
848 | + |
|
849 | + |
|
850 | + /** |
|
851 | + * @return bool |
|
852 | + * @throws EE_Error |
|
853 | + */ |
|
854 | + public function is_sub_line_item() |
|
855 | + { |
|
856 | + return $this->type() === EEM_Line_Item::type_sub_line_item; |
|
857 | + } |
|
858 | + |
|
859 | + |
|
860 | + /** |
|
861 | + * @return bool |
|
862 | + * @throws EE_Error |
|
863 | + */ |
|
864 | + public function is_sub_total() |
|
865 | + { |
|
866 | + return $this->type() === EEM_Line_Item::type_sub_total; |
|
867 | + } |
|
868 | + |
|
869 | + |
|
870 | + /** |
|
871 | + * Whether or not this line item is a cancellation line item |
|
872 | + * |
|
873 | + * @return boolean |
|
874 | + * @throws EE_Error |
|
875 | + */ |
|
876 | + public function is_cancellation() |
|
877 | + { |
|
878 | + return EEM_Line_Item::type_cancellation === $this->type(); |
|
879 | + } |
|
880 | + |
|
881 | + |
|
882 | + /** |
|
883 | + * @return bool |
|
884 | + * @throws EE_Error |
|
885 | + */ |
|
886 | + public function is_total() |
|
887 | + { |
|
888 | + return $this->type() === EEM_Line_Item::type_total; |
|
889 | + } |
|
890 | + |
|
891 | + |
|
892 | + /** |
|
893 | + * @return bool |
|
894 | + * @throws EE_Error |
|
895 | + */ |
|
896 | + public function is_cancelled() |
|
897 | + { |
|
898 | + return $this->type() === EEM_Line_Item::type_cancellation; |
|
899 | + } |
|
900 | + |
|
901 | + |
|
902 | + /** |
|
903 | + * @return string like '2, 004.00', formatted according to the localized currency |
|
904 | + * @throws EE_Error |
|
905 | + */ |
|
906 | + public function unit_price_no_code() |
|
907 | + { |
|
908 | + return $this->get_pretty('LIN_unit_price', 'no_currency_code'); |
|
909 | + } |
|
910 | + |
|
911 | + |
|
912 | + /** |
|
913 | + * @return string like '2, 004.00', formatted according to the localized currency |
|
914 | + * @throws EE_Error |
|
915 | + */ |
|
916 | + public function total_no_code() |
|
917 | + { |
|
918 | + return $this->get_pretty('LIN_total', 'no_currency_code'); |
|
919 | + } |
|
920 | + |
|
921 | + |
|
922 | + /** |
|
923 | + * Gets the final total on this item, taking taxes into account. |
|
924 | + * Has the side-effect of setting the sub-total as it was just calculated. |
|
925 | + * If this is used on a grand-total line item, also updates the transaction's |
|
926 | + * TXN_total (provided this line item is allowed to persist, otherwise we don't |
|
927 | + * want to change a persistable transaction with info from a non-persistent line item) |
|
928 | + * |
|
929 | + * @return float |
|
930 | + * @throws EE_Error |
|
931 | + * @throws InvalidArgumentException |
|
932 | + * @throws InvalidInterfaceException |
|
933 | + * @throws InvalidDataTypeException |
|
934 | + */ |
|
935 | + public function recalculate_total_including_taxes() |
|
936 | + { |
|
937 | + $pre_tax_total = $this->recalculate_pre_tax_total(); |
|
938 | + $tax_total = $this->recalculate_taxes_and_tax_total(); |
|
939 | + $total = $pre_tax_total + $tax_total; |
|
940 | + // no negative totals plz |
|
941 | + $total = max($total, 0); |
|
942 | + $this->set_total($total); |
|
943 | + //only update the related transaction's total |
|
944 | + //if we intend to save this line item and its a grand total |
|
945 | + if ( |
|
946 | + $this->allow_persist() && $this->type() === EEM_Line_Item::type_total |
|
947 | + && $this->transaction() |
|
948 | + instanceof |
|
949 | + EE_Transaction |
|
950 | + ) { |
|
951 | + $this->transaction()->set_total($total); |
|
952 | + if ($this->transaction()->ID()) { |
|
953 | + $this->transaction()->save(); |
|
954 | + } |
|
955 | + } |
|
956 | + $this->maybe_save(); |
|
957 | + return $total; |
|
958 | + } |
|
959 | + |
|
960 | + |
|
961 | + /** |
|
962 | + * Recursively goes through all the children and recalculates sub-totals EXCEPT for |
|
963 | + * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its |
|
964 | + * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and |
|
965 | + * when this is called on the grand total |
|
966 | + * |
|
967 | + * @return float |
|
968 | + * @throws InvalidArgumentException |
|
969 | + * @throws InvalidInterfaceException |
|
970 | + * @throws InvalidDataTypeException |
|
971 | + * @throws EE_Error |
|
972 | + */ |
|
973 | + public function recalculate_pre_tax_total() |
|
974 | + { |
|
975 | + $total = 0; |
|
976 | + $my_children = $this->children(); |
|
977 | + $has_children = !empty($my_children); |
|
978 | + if ($has_children && $this->is_line_item()) { |
|
979 | + $total = $this->_recalculate_pretax_total_for_line_item($total, $my_children); |
|
980 | + } elseif (!$has_children && ($this->is_sub_line_item() || $this->is_line_item())) { |
|
981 | + $total = $this->unit_price() * $this->quantity(); |
|
982 | + } elseif ($this->is_sub_total() || $this->is_total()) { |
|
983 | + $total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children); |
|
984 | + } elseif ($this->is_tax_sub_total() || $this->is_tax() || $this->is_cancelled()) { |
|
985 | + // completely ignore tax totals, tax sub-totals, and cancelled line items, when calculating the pre-tax-total |
|
986 | + return 0; |
|
987 | + } |
|
988 | + // ensure all non-line items and non-sub-line-items have a quantity of 1 (except for Events) |
|
989 | + if ( |
|
990 | + !$this->is_line_item() && !$this->is_sub_line_item() && !$this->is_cancellation() |
|
991 | + ) { |
|
992 | + if ($this->OBJ_type() !== 'Event') { |
|
993 | + $this->set_quantity(1); |
|
994 | + } |
|
995 | + if (!$this->is_percent()) { |
|
996 | + $this->set_unit_price($total); |
|
997 | + } |
|
998 | + } |
|
999 | + //we don't want to bother saving grand totals, because that needs to factor in taxes anyways |
|
1000 | + //so it ought to be |
|
1001 | + if (!$this->is_total()) { |
|
1002 | + $this->set_total($total); |
|
1003 | + //if not a percent line item, make sure we keep the unit price in sync |
|
1004 | + if ( |
|
1005 | + $has_children |
|
1006 | + && $this->is_line_item() |
|
1007 | + && !$this->is_percent() |
|
1008 | + ) { |
|
1009 | + if ($this->quantity() === 0) { |
|
1010 | + $new_unit_price = 0; |
|
1011 | + } else { |
|
1012 | + $new_unit_price = $this->total() / $this->quantity(); |
|
1013 | + } |
|
1014 | + $this->set_unit_price($new_unit_price); |
|
1015 | + } |
|
1016 | + $this->maybe_save(); |
|
1017 | + } |
|
1018 | + return $total; |
|
1019 | + } |
|
1020 | + |
|
1021 | + |
|
1022 | + /** |
|
1023 | + * Calculates the pretax total when this line item is a subtotal or total line item. |
|
1024 | + * Basically does a sum-then-round approach (ie, any percent line item that are children |
|
1025 | + * will calculate their total based on the un-rounded total we're working with so far, and |
|
1026 | + * THEN round the result; instead of rounding as we go like with sub-line-items) |
|
1027 | + * |
|
1028 | + * @param float $calculated_total_so_far |
|
1029 | + * @param EE_Line_Item[] $my_children |
|
1030 | + * @return float |
|
1031 | + * @throws InvalidArgumentException |
|
1032 | + * @throws InvalidInterfaceException |
|
1033 | + * @throws InvalidDataTypeException |
|
1034 | + * @throws EE_Error |
|
1035 | + */ |
|
1036 | + protected function _recalculate_pretax_total_for_subtotal($calculated_total_so_far, $my_children = null) |
|
1037 | + { |
|
1038 | + if ($my_children === null) { |
|
1039 | + $my_children = $this->children(); |
|
1040 | + } |
|
1041 | + $subtotal_quantity = 0; |
|
1042 | + //get the total of all its children |
|
1043 | + foreach ($my_children as $child_line_item) { |
|
1044 | + if ($child_line_item instanceof EE_Line_Item && !$child_line_item->is_cancellation()) { |
|
1045 | + // percentage line items are based on total so far |
|
1046 | + if ($child_line_item->is_percent()) { |
|
1047 | + //round as we go so that the line items add up ok |
|
1048 | + $percent_total = round( |
|
1049 | + $calculated_total_so_far * $child_line_item->percent() / 100, |
|
1050 | + EE_Registry::instance()->CFG->currency->dec_plc |
|
1051 | + ); |
|
1052 | + $child_line_item->set_total($percent_total); |
|
1053 | + //so far all percent line items should have a quantity of 1 |
|
1054 | + //(ie, no double percent discounts. Although that might be requested someday) |
|
1055 | + $child_line_item->set_quantity(1); |
|
1056 | + $child_line_item->maybe_save(); |
|
1057 | + $calculated_total_so_far += $percent_total; |
|
1058 | + } else { |
|
1059 | + //verify flat sub-line-item quantities match their parent |
|
1060 | + if ($child_line_item->is_sub_line_item()) { |
|
1061 | + $child_line_item->set_quantity($this->quantity()); |
|
1062 | + } |
|
1063 | + $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total(); |
|
1064 | + $subtotal_quantity += $child_line_item->quantity(); |
|
1065 | + } |
|
1066 | + } |
|
1067 | + } |
|
1068 | + if ($this->is_sub_total()) { |
|
1069 | + // no negative totals plz |
|
1070 | + $calculated_total_so_far = max($calculated_total_so_far, 0); |
|
1071 | + $subtotal_quantity = $subtotal_quantity > 0 ? 1 : 0; |
|
1072 | + $this->set_quantity($subtotal_quantity); |
|
1073 | + $this->maybe_save(); |
|
1074 | + } |
|
1075 | + return $calculated_total_so_far; |
|
1076 | + } |
|
1077 | + |
|
1078 | + |
|
1079 | + /** |
|
1080 | + * Calculates the pretax total for a normal line item, in a round-then-sum approach |
|
1081 | + * (where each sub-line-item is applied to the base price for the line item |
|
1082 | + * and the result is immediately rounded, rather than summing all the sub-line-items |
|
1083 | + * then rounding, like we do when recalculating pretax totals on totals and subtotals). |
|
1084 | + * |
|
1085 | + * @param float $calculated_total_so_far |
|
1086 | + * @param EE_Line_Item[] $my_children |
|
1087 | + * @return float |
|
1088 | + * @throws InvalidArgumentException |
|
1089 | + * @throws InvalidInterfaceException |
|
1090 | + * @throws InvalidDataTypeException |
|
1091 | + * @throws EE_Error |
|
1092 | + */ |
|
1093 | + protected function _recalculate_pretax_total_for_line_item($calculated_total_so_far, $my_children = null) |
|
1094 | + { |
|
1095 | + if ($my_children === null) { |
|
1096 | + $my_children = $this->children(); |
|
1097 | + } |
|
1098 | + //we need to keep track of the running total for a single item, |
|
1099 | + //because we need to round as we go |
|
1100 | + $unit_price_for_total = 0; |
|
1101 | + $quantity_for_total = 1; |
|
1102 | + //get the total of all its children |
|
1103 | + foreach ($my_children as $child_line_item) { |
|
1104 | + if ($child_line_item instanceof EE_Line_Item && !$child_line_item->is_cancellation()) { |
|
1105 | + if ($child_line_item->is_percent()) { |
|
1106 | + //it should be the unit-price-so-far multiplied by teh percent multiplied by the quantity |
|
1107 | + //not total multiplied by percent, because that ignores rounding along-the-way |
|
1108 | + $percent_unit_price = round( |
|
1109 | + $unit_price_for_total * $child_line_item->percent() / 100, |
|
1110 | + EE_Registry::instance()->CFG->currency->dec_plc |
|
1111 | + ); |
|
1112 | + $percent_total = $percent_unit_price * $quantity_for_total; |
|
1113 | + $child_line_item->set_total($percent_total); |
|
1114 | + //so far all percent line items should have a quantity of 1 |
|
1115 | + //(ie, no double percent discounts. Although that might be requested someday) |
|
1116 | + $child_line_item->set_quantity(1); |
|
1117 | + $child_line_item->maybe_save(); |
|
1118 | + $calculated_total_so_far += $percent_total; |
|
1119 | + $unit_price_for_total += $percent_unit_price; |
|
1120 | + } else { |
|
1121 | + //verify flat sub-line-item quantities match their parent |
|
1122 | + if ($child_line_item->is_sub_line_item()) { |
|
1123 | + $child_line_item->set_quantity($this->quantity()); |
|
1124 | + } |
|
1125 | + $quantity_for_total = $child_line_item->quantity(); |
|
1126 | + $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total(); |
|
1127 | + $unit_price_for_total += $child_line_item->unit_price(); |
|
1128 | + } |
|
1129 | + } |
|
1130 | + } |
|
1131 | + return $calculated_total_so_far; |
|
1132 | + } |
|
1133 | + |
|
1134 | + |
|
1135 | + /** |
|
1136 | + * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets |
|
1137 | + * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items |
|
1138 | + * and tax sub-total if already in the DB |
|
1139 | + * |
|
1140 | + * @return float |
|
1141 | + * @throws EE_Error |
|
1142 | + */ |
|
1143 | + public function recalculate_taxes_and_tax_total() |
|
1144 | + { |
|
1145 | + //get all taxes |
|
1146 | + $taxes = $this->tax_descendants(); |
|
1147 | + //calculate the pretax total |
|
1148 | + $taxable_total = $this->taxable_total(); |
|
1149 | + $tax_total = 0; |
|
1150 | + foreach ($taxes as $tax) { |
|
1151 | + $total_on_this_tax = $taxable_total * $tax->percent() / 100; |
|
1152 | + //remember the total on this line item |
|
1153 | + $tax->set_total($total_on_this_tax); |
|
1154 | + $tax->maybe_save(); |
|
1155 | + $tax_total += $tax->total(); |
|
1156 | + } |
|
1157 | + $this->_recalculate_tax_sub_total(); |
|
1158 | + return $tax_total; |
|
1159 | + } |
|
1160 | + |
|
1161 | + |
|
1162 | + /** |
|
1163 | + * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated |
|
1164 | + * |
|
1165 | + * @return void |
|
1166 | + * @throws EE_Error |
|
1167 | + */ |
|
1168 | + private function _recalculate_tax_sub_total() |
|
1169 | + { |
|
1170 | + if ($this->is_tax_sub_total()) { |
|
1171 | + $total = 0; |
|
1172 | + $total_percent = 0; |
|
1173 | + //simply loop through all its children (which should be taxes) and sum their total |
|
1174 | + foreach ($this->children() as $child_tax) { |
|
1175 | + if ($child_tax instanceof EE_Line_Item) { |
|
1176 | + $total += $child_tax->total(); |
|
1177 | + $total_percent += $child_tax->percent(); |
|
1178 | + } |
|
1179 | + } |
|
1180 | + $this->set_total($total); |
|
1181 | + $this->set_percent($total_percent); |
|
1182 | + $this->maybe_save(); |
|
1183 | + } elseif ($this->is_total()) { |
|
1184 | + foreach ($this->children() as $maybe_tax_subtotal) { |
|
1185 | + if ($maybe_tax_subtotal instanceof EE_Line_Item) { |
|
1186 | + $maybe_tax_subtotal->_recalculate_tax_sub_total(); |
|
1187 | + } |
|
1188 | + } |
|
1189 | + } |
|
1190 | + } |
|
1191 | + |
|
1192 | + |
|
1193 | + /** |
|
1194 | + * Gets the total tax on this line item. Assumes taxes have already been calculated using |
|
1195 | + * recalculate_taxes_and_total |
|
1196 | + * |
|
1197 | + * @return float |
|
1198 | + * @throws EE_Error |
|
1199 | + */ |
|
1200 | + public function get_total_tax() |
|
1201 | + { |
|
1202 | + $this->_recalculate_tax_sub_total(); |
|
1203 | + $total = 0; |
|
1204 | + foreach ($this->tax_descendants() as $tax_line_item) { |
|
1205 | + if ($tax_line_item instanceof EE_Line_Item) { |
|
1206 | + $total += $tax_line_item->total(); |
|
1207 | + } |
|
1208 | + } |
|
1209 | + return $total; |
|
1210 | + } |
|
1211 | + |
|
1212 | + |
|
1213 | + /** |
|
1214 | + * Gets the total for all the items purchased only |
|
1215 | + * |
|
1216 | + * @return float |
|
1217 | + * @throws EE_Error |
|
1218 | + */ |
|
1219 | + public function get_items_total() |
|
1220 | + { |
|
1221 | + //by default, let's make sure we're consistent with the existing line item |
|
1222 | + if ($this->is_total()) { |
|
1223 | + $pretax_subtotal_li = EEH_Line_Item::get_pre_tax_subtotal($this); |
|
1224 | + if ($pretax_subtotal_li instanceof EE_Line_Item) { |
|
1225 | + return $pretax_subtotal_li->total(); |
|
1226 | + } |
|
1227 | + } |
|
1228 | + $total = 0; |
|
1229 | + foreach ($this->get_items() as $item) { |
|
1230 | + if ($item instanceof EE_Line_Item) { |
|
1231 | + $total += $item->total(); |
|
1232 | + } |
|
1233 | + } |
|
1234 | + return $total; |
|
1235 | + } |
|
1236 | + |
|
1237 | + |
|
1238 | + /** |
|
1239 | + * Gets all the descendants (ie, children or children of children etc) that |
|
1240 | + * are of the type 'tax' |
|
1241 | + * |
|
1242 | + * @return EE_Line_Item[] |
|
1243 | + */ |
|
1244 | + public function tax_descendants() |
|
1245 | + { |
|
1246 | + return EEH_Line_Item::get_tax_descendants($this); |
|
1247 | + } |
|
1248 | + |
|
1249 | + |
|
1250 | + /** |
|
1251 | + * Gets all the real items purchased which are children of this item |
|
1252 | + * |
|
1253 | + * @return EE_Line_Item[] |
|
1254 | + */ |
|
1255 | + public function get_items() |
|
1256 | + { |
|
1257 | + return EEH_Line_Item::get_line_item_descendants($this); |
|
1258 | + } |
|
1259 | + |
|
1260 | + |
|
1261 | + /** |
|
1262 | + * Returns the amount taxable among this line item's children (or if it has no children, |
|
1263 | + * how much of it is taxable). Does not recalculate totals or subtotals. |
|
1264 | + * If the taxable total is negative, (eg, if none of the tickets were taxable, |
|
1265 | + * but there is a "Taxable" discount), returns 0. |
|
1266 | + * |
|
1267 | + * @return float |
|
1268 | + * @throws EE_Error |
|
1269 | + */ |
|
1270 | + public function taxable_total() |
|
1271 | + { |
|
1272 | + $total = 0; |
|
1273 | + if ($this->children()) { |
|
1274 | + foreach ($this->children() as $child_line_item) { |
|
1275 | + if ($child_line_item->type() === EEM_Line_Item::type_line_item && $child_line_item->is_taxable()) { |
|
1276 | + //if it's a percent item, only take into account the percent |
|
1277 | + //that's taxable too (the taxable total so far) |
|
1278 | + if ($child_line_item->is_percent()) { |
|
1279 | + $total += ($total * $child_line_item->percent() / 100); |
|
1280 | + } else { |
|
1281 | + $total += $child_line_item->total(); |
|
1282 | + } |
|
1283 | + } elseif ($child_line_item->type() === EEM_Line_Item::type_sub_total) { |
|
1284 | + $total += $child_line_item->taxable_total(); |
|
1285 | + } |
|
1286 | + } |
|
1287 | + } |
|
1288 | + return max($total, 0); |
|
1289 | + } |
|
1290 | + |
|
1291 | + |
|
1292 | + /** |
|
1293 | + * Gets the transaction for this line item |
|
1294 | + * |
|
1295 | + * @return EE_Base_Class|EE_Transaction |
|
1296 | + * @throws EE_Error |
|
1297 | + */ |
|
1298 | + public function transaction() |
|
1299 | + { |
|
1300 | + return $this->get_first_related('Transaction'); |
|
1301 | + } |
|
1302 | + |
|
1303 | + |
|
1304 | + /** |
|
1305 | + * Saves this line item to the DB, and recursively saves its descendants. |
|
1306 | + * Because there currently is no proper parent-child relation on the model, |
|
1307 | + * save_this_and_cached() will NOT save the descendants. |
|
1308 | + * Also sets the transaction on this line item and all its descendants before saving |
|
1309 | + * |
|
1310 | + * @param int $txn_id if none is provided, assumes $this->TXN_ID() |
|
1311 | + * @return int count of items saved |
|
1312 | + * @throws EE_Error |
|
1313 | + */ |
|
1314 | + public function save_this_and_descendants_to_txn($txn_id = null) |
|
1315 | + { |
|
1316 | + $count = 0; |
|
1317 | + if (!$txn_id) { |
|
1318 | + $txn_id = $this->TXN_ID(); |
|
1319 | + } |
|
1320 | + $this->set_TXN_ID($txn_id); |
|
1321 | + $children = $this->children(); |
|
1322 | + $count += $this->save() |
|
1323 | + ? 1 |
|
1324 | + : 0; |
|
1325 | + foreach ($children as $child_line_item) { |
|
1326 | + if ($child_line_item instanceof EE_Line_Item) { |
|
1327 | + $child_line_item->set_parent_ID($this->ID()); |
|
1328 | + $count += $child_line_item->save_this_and_descendants_to_txn($txn_id); |
|
1329 | + } |
|
1330 | + } |
|
1331 | + return $count; |
|
1332 | + } |
|
1333 | + |
|
1334 | + |
|
1335 | + /** |
|
1336 | + * Saves this line item to the DB, and recursively saves its descendants. |
|
1337 | + * |
|
1338 | + * @return int count of items saved |
|
1339 | + * @throws EE_Error |
|
1340 | + */ |
|
1341 | + public function save_this_and_descendants() |
|
1342 | + { |
|
1343 | + $count = 0; |
|
1344 | + $children = $this->children(); |
|
1345 | + $count += $this->save() |
|
1346 | + ? 1 |
|
1347 | + : 0; |
|
1348 | + foreach ($children as $child_line_item) { |
|
1349 | + if ($child_line_item instanceof EE_Line_Item) { |
|
1350 | + $child_line_item->set_parent_ID($this->ID()); |
|
1351 | + $count += $child_line_item->save_this_and_descendants(); |
|
1352 | + } |
|
1353 | + } |
|
1354 | + return $count; |
|
1355 | + } |
|
1356 | + |
|
1357 | + |
|
1358 | + /** |
|
1359 | + * returns the cancellation line item if this item was cancelled |
|
1360 | + * |
|
1361 | + * @return EE_Line_Item[] |
|
1362 | + * @throws InvalidArgumentException |
|
1363 | + * @throws InvalidInterfaceException |
|
1364 | + * @throws InvalidDataTypeException |
|
1365 | + * @throws ReflectionException |
|
1366 | + * @throws EE_Error |
|
1367 | + */ |
|
1368 | + public function get_cancellations() |
|
1369 | + { |
|
1370 | + EE_Registry::instance()->load_helper('Line_Item'); |
|
1371 | + return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation); |
|
1372 | + } |
|
1373 | + |
|
1374 | + |
|
1375 | + /** |
|
1376 | + * If this item has an ID, then this saves it again to update the db |
|
1377 | + * |
|
1378 | + * @return int count of items saved |
|
1379 | + * @throws EE_Error |
|
1380 | + */ |
|
1381 | + public function maybe_save() |
|
1382 | + { |
|
1383 | + if ($this->ID()) { |
|
1384 | + return $this->save(); |
|
1385 | + } |
|
1386 | + return false; |
|
1387 | + } |
|
1388 | + |
|
1389 | + |
|
1390 | + /** |
|
1391 | + * clears the cached children and parent from the line item |
|
1392 | + * |
|
1393 | + * @return void |
|
1394 | + */ |
|
1395 | + public function clear_related_line_item_cache() |
|
1396 | + { |
|
1397 | + $this->_children = array(); |
|
1398 | + $this->_parent = null; |
|
1399 | + } |
|
1400 | + |
|
1401 | + |
|
1402 | + /** |
|
1403 | + * @param bool $raw |
|
1404 | + * @return int |
|
1405 | + * @throws EE_Error |
|
1406 | + */ |
|
1407 | + public function timestamp($raw = false) |
|
1408 | + { |
|
1409 | + return $raw |
|
1410 | + ? $this->get_raw('LIN_timestamp') |
|
1411 | + : $this->get('LIN_timestamp'); |
|
1412 | + } |
|
1413 | + |
|
1414 | + |
|
1415 | + |
|
1416 | + |
|
1417 | + /************************* DEPRECATED *************************/ |
|
1418 | + /** |
|
1419 | + * @deprecated 4.6.0 |
|
1420 | + * @param string $type one of the constants on EEM_Line_Item |
|
1421 | + * @return EE_Line_Item[] |
|
1422 | + */ |
|
1423 | + protected function _get_descendants_of_type($type) |
|
1424 | + { |
|
1425 | + EE_Error::doing_it_wrong( |
|
1426 | + 'EE_Line_Item::_get_descendants_of_type()', |
|
1427 | + __('Method replaced with EEH_Line_Item::get_descendants_of_type()', 'event_espresso'), '4.6.0' |
|
1428 | + ); |
|
1429 | + return EEH_Line_Item::get_descendants_of_type($this, $type); |
|
1430 | + } |
|
1431 | + |
|
1432 | + |
|
1433 | + /** |
|
1434 | + * @deprecated 4.6.0 |
|
1435 | + * @param string $type like one of the EEM_Line_Item::type_* |
|
1436 | + * @return EE_Line_Item |
|
1437 | + */ |
|
1438 | + public function get_nearest_descendant_of_type($type) |
|
1439 | + { |
|
1440 | + EE_Error::doing_it_wrong( |
|
1441 | + 'EE_Line_Item::get_nearest_descendant_of_type()', |
|
1442 | + __('Method replaced with EEH_Line_Item::get_nearest_descendant_of_type()', 'event_espresso'), '4.6.0' |
|
1443 | + ); |
|
1444 | + return EEH_Line_Item::get_nearest_descendant_of_type($this, $type); |
|
1445 | + } |
|
1446 | 1446 | |
1447 | 1447 | |
1448 | 1448 | } |
@@ -75,7 +75,7 @@ discard block |
||
75 | 75 | protected function __construct($fieldValues = array(), $bydb = false, $timezone = '') |
76 | 76 | { |
77 | 77 | parent::__construct($fieldValues, $bydb, $timezone); |
78 | - if (!$this->get('LIN_code')) { |
|
78 | + if ( ! $this->get('LIN_code')) { |
|
79 | 79 | $this->set_code($this->generate_code()); |
80 | 80 | } |
81 | 81 | } |
@@ -126,7 +126,7 @@ discard block |
||
126 | 126 | public function name() |
127 | 127 | { |
128 | 128 | $name = $this->get('LIN_name'); |
129 | - if (!$name) { |
|
129 | + if ( ! $name) { |
|
130 | 130 | $name = ucwords(str_replace('-', ' ', $this->type())); |
131 | 131 | } |
132 | 132 | return $name; |
@@ -313,7 +313,7 @@ discard block |
||
313 | 313 | if ($unit_price < .001 && $percent) { |
314 | 314 | return true; |
315 | 315 | } |
316 | - if ($unit_price >= .001 && !$percent) { |
|
316 | + if ($unit_price >= .001 && ! $percent) { |
|
317 | 317 | return false; |
318 | 318 | } |
319 | 319 | if ($unit_price >= .001 && $percent) { |
@@ -482,7 +482,7 @@ discard block |
||
482 | 482 | ) |
483 | 483 | ); |
484 | 484 | } |
485 | - if (!is_array($this->_children)) { |
|
485 | + if ( ! is_array($this->_children)) { |
|
486 | 486 | $this->_children = array(); |
487 | 487 | } |
488 | 488 | return $this->_children; |
@@ -698,7 +698,7 @@ discard block |
||
698 | 698 | public function set_parent($line_item) |
699 | 699 | { |
700 | 700 | if ($this->ID()) { |
701 | - if (!$line_item->ID()) { |
|
701 | + if ( ! $line_item->ID()) { |
|
702 | 702 | $line_item->save(); |
703 | 703 | } |
704 | 704 | $this->set_parent_ID($line_item->ID()); |
@@ -769,7 +769,7 @@ discard block |
||
769 | 769 | $items_deleted = 0; |
770 | 770 | if ($this->code() === $code) { |
771 | 771 | $items_deleted += EEH_Line_Item::delete_all_child_items($this); |
772 | - $items_deleted += (int)$this->delete(); |
|
772 | + $items_deleted += (int) $this->delete(); |
|
773 | 773 | if ($stop_search_once_found) { |
774 | 774 | return $items_deleted; |
775 | 775 | } |
@@ -797,7 +797,7 @@ discard block |
||
797 | 797 | */ |
798 | 798 | public function delete_if_childless_subtotal() |
799 | 799 | { |
800 | - if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && !$this->children()) { |
|
800 | + if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && ! $this->children()) { |
|
801 | 801 | return $this->delete(); |
802 | 802 | } |
803 | 803 | return false; |
@@ -813,7 +813,7 @@ discard block |
||
813 | 813 | public function generate_code() |
814 | 814 | { |
815 | 815 | // each line item in the cart requires a unique identifier |
816 | - return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime()); |
|
816 | + return md5($this->get('OBJ_type').$this->get('OBJ_ID').microtime()); |
|
817 | 817 | } |
818 | 818 | |
819 | 819 | |
@@ -974,10 +974,10 @@ discard block |
||
974 | 974 | { |
975 | 975 | $total = 0; |
976 | 976 | $my_children = $this->children(); |
977 | - $has_children = !empty($my_children); |
|
977 | + $has_children = ! empty($my_children); |
|
978 | 978 | if ($has_children && $this->is_line_item()) { |
979 | 979 | $total = $this->_recalculate_pretax_total_for_line_item($total, $my_children); |
980 | - } elseif (!$has_children && ($this->is_sub_line_item() || $this->is_line_item())) { |
|
980 | + } elseif ( ! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) { |
|
981 | 981 | $total = $this->unit_price() * $this->quantity(); |
982 | 982 | } elseif ($this->is_sub_total() || $this->is_total()) { |
983 | 983 | $total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children); |
@@ -987,24 +987,24 @@ discard block |
||
987 | 987 | } |
988 | 988 | // ensure all non-line items and non-sub-line-items have a quantity of 1 (except for Events) |
989 | 989 | if ( |
990 | - !$this->is_line_item() && !$this->is_sub_line_item() && !$this->is_cancellation() |
|
990 | + ! $this->is_line_item() && ! $this->is_sub_line_item() && ! $this->is_cancellation() |
|
991 | 991 | ) { |
992 | 992 | if ($this->OBJ_type() !== 'Event') { |
993 | 993 | $this->set_quantity(1); |
994 | 994 | } |
995 | - if (!$this->is_percent()) { |
|
995 | + if ( ! $this->is_percent()) { |
|
996 | 996 | $this->set_unit_price($total); |
997 | 997 | } |
998 | 998 | } |
999 | 999 | //we don't want to bother saving grand totals, because that needs to factor in taxes anyways |
1000 | 1000 | //so it ought to be |
1001 | - if (!$this->is_total()) { |
|
1001 | + if ( ! $this->is_total()) { |
|
1002 | 1002 | $this->set_total($total); |
1003 | 1003 | //if not a percent line item, make sure we keep the unit price in sync |
1004 | 1004 | if ( |
1005 | 1005 | $has_children |
1006 | 1006 | && $this->is_line_item() |
1007 | - && !$this->is_percent() |
|
1007 | + && ! $this->is_percent() |
|
1008 | 1008 | ) { |
1009 | 1009 | if ($this->quantity() === 0) { |
1010 | 1010 | $new_unit_price = 0; |
@@ -1041,7 +1041,7 @@ discard block |
||
1041 | 1041 | $subtotal_quantity = 0; |
1042 | 1042 | //get the total of all its children |
1043 | 1043 | foreach ($my_children as $child_line_item) { |
1044 | - if ($child_line_item instanceof EE_Line_Item && !$child_line_item->is_cancellation()) { |
|
1044 | + if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) { |
|
1045 | 1045 | // percentage line items are based on total so far |
1046 | 1046 | if ($child_line_item->is_percent()) { |
1047 | 1047 | //round as we go so that the line items add up ok |
@@ -1101,7 +1101,7 @@ discard block |
||
1101 | 1101 | $quantity_for_total = 1; |
1102 | 1102 | //get the total of all its children |
1103 | 1103 | foreach ($my_children as $child_line_item) { |
1104 | - if ($child_line_item instanceof EE_Line_Item && !$child_line_item->is_cancellation()) { |
|
1104 | + if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) { |
|
1105 | 1105 | if ($child_line_item->is_percent()) { |
1106 | 1106 | //it should be the unit-price-so-far multiplied by teh percent multiplied by the quantity |
1107 | 1107 | //not total multiplied by percent, because that ignores rounding along-the-way |
@@ -1314,7 +1314,7 @@ discard block |
||
1314 | 1314 | public function save_this_and_descendants_to_txn($txn_id = null) |
1315 | 1315 | { |
1316 | 1316 | $count = 0; |
1317 | - if (!$txn_id) { |
|
1317 | + if ( ! $txn_id) { |
|
1318 | 1318 | $txn_id = $this->TXN_ID(); |
1319 | 1319 | } |
1320 | 1320 | $this->set_TXN_ID($txn_id); |
@@ -41,384 +41,384 @@ |
||
41 | 41 | class EEM_Line_Item extends EEM_Base |
42 | 42 | { |
43 | 43 | |
44 | - /** |
|
45 | - * Tax sub-total is just the total of all the taxes, which should be children |
|
46 | - * of this line item. There should only ever be one tax sub-total, and it should |
|
47 | - * be a direct child of |
|
48 | - */ |
|
49 | - const type_tax_sub_total = 'tax-sub-total'; |
|
50 | - |
|
51 | - /** |
|
52 | - * Tax line items indicate a tax applied to all the taxable line items. |
|
53 | - * Should not have any children line items. |
|
54 | - */ |
|
55 | - const type_tax = 'tax'; |
|
56 | - |
|
57 | - /** |
|
58 | - * Indicating individual items purchased, or discounts or surcharges. |
|
59 | - * The sum of all the regular line items plus the tax items should equal |
|
60 | - * the grand total. |
|
61 | - * Possible children fo sub-line-items and cancellations. |
|
62 | - */ |
|
63 | - const type_line_item = 'line-item'; |
|
64 | - |
|
65 | - /** |
|
66 | - * line item indicating all the factors that make a single line item. |
|
67 | - * Sub-line items should have NO children line items. |
|
68 | - */ |
|
69 | - const type_sub_line_item = 'sub-item'; |
|
70 | - |
|
71 | - /** |
|
72 | - * line item indicating a sub-total (eg total for an event, or before taxes). |
|
73 | - * Direct children can be line items and other sub-totals |
|
74 | - * |
|
75 | - */ |
|
76 | - const type_sub_total = 'sub-total'; |
|
77 | - |
|
78 | - /** |
|
79 | - * line item for teh grand total of an order. Its direct children |
|
80 | - * should be tax subtotals and subtotals, and possibly a regular line item |
|
81 | - * indicating a transaction-wide discount/surcharge |
|
82 | - */ |
|
83 | - const type_total = 'total'; |
|
84 | - |
|
85 | - /** |
|
86 | - * When a line item is cancelled, a sub-line-item of type 'cancellation' |
|
87 | - * should be created, indicating the quantity that were cancelled |
|
88 | - * (because a line item could have a quantity of 1, and its cancellation item |
|
89 | - * could be for 3, indicating that originally 4 were purchased, but 3 have been |
|
90 | - * cancelled, and only one remains). |
|
91 | - * When items are refunded, a cancellation line item should be made, which points |
|
92 | - * to teh payment model object which actually refunded the payment. |
|
93 | - * Cancellations should NOT have any children line items; the should NOT affect |
|
94 | - * any calculations, and are only meant as a record that cancellations have occurred. |
|
95 | - */ |
|
96 | - const type_cancellation = 'cancellation'; |
|
97 | - |
|
98 | - // private instance of the EEM_Line_Item object |
|
99 | - protected static $_instance = NULL; |
|
100 | - |
|
101 | - |
|
102 | - /** |
|
103 | - * private constructor to prevent direct creation |
|
104 | - * @Constructor |
|
105 | - * @access protected |
|
106 | - * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any incoming timezone data that gets saved). Note this just sends the timezone info to the date time model field objects. Default is NULL (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
107 | - * @return \EEM_Line_Item |
|
108 | - */ |
|
109 | - protected function __construct($timezone) |
|
110 | - { |
|
111 | - $this->singular_item = __('Line Item', 'event_espresso'); |
|
112 | - $this->plural_item = __('Line Items', 'event_espresso'); |
|
113 | - |
|
114 | - $this->_tables = array( |
|
115 | - 'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID') |
|
116 | - ); |
|
117 | - $line_items_can_be_for = apply_filters('FHEE__EEM_Line_Item__line_items_can_be_for', array('Ticket', 'Price', 'Event')); |
|
118 | - $this->_fields = array( |
|
119 | - 'Line_Item' => array( |
|
120 | - 'LIN_ID' => new EE_Primary_Key_Int_Field('LIN_ID', __("ID", "event_espresso")), |
|
121 | - 'LIN_code' => new EE_Slug_Field('LIN_code', __("Code for index into Cart", "event_espresso"), TRUE), |
|
122 | - 'TXN_ID' => new EE_Foreign_Key_Int_Field('TXN_ID', __("Transaction ID", "event_espresso"), TRUE, NULL, 'Transaction'), |
|
123 | - 'LIN_name' => new EE_Full_HTML_Field('LIN_name', __("Line Item Name", "event_espresso"), FALSE, ''), |
|
124 | - 'LIN_desc' => new EE_Full_HTML_Field('LIN_desc', __("Line Item Description", "event_espresso"), TRUE), |
|
125 | - 'LIN_unit_price' => new EE_Money_Field('LIN_unit_price', __("Unit Price", "event_espresso"), FALSE, 0), |
|
126 | - 'LIN_percent' => new EE_Float_Field('LIN_percent', __("Percent", "event_espresso"), FALSE, 0), |
|
127 | - 'LIN_is_taxable' => new EE_Boolean_Field('LIN_is_taxable', __("Taxable", "event_espresso"), FALSE, FALSE), |
|
128 | - 'LIN_order' => new EE_Integer_Field('LIN_order', __("Order of Application towards total of parent", "event_espresso"), FALSE, 1), |
|
129 | - 'LIN_total' => new EE_Money_Field('LIN_total', __("Total (unit price x quantity)", "event_espresso"), FALSE, 0), |
|
130 | - 'LIN_quantity' => new EE_Integer_Field('LIN_quantity', __("Quantity", "event_espresso"), TRUE, 1), |
|
131 | - 'LIN_parent' => new EE_Integer_Field('LIN_parent', __("Parent ID (this item goes towards that Line Item's total)", "event_espresso"), TRUE, NULL), |
|
132 | - 'LIN_type' => new EE_Enum_Text_Field('LIN_type', __("Type", "event_espresso"), FALSE, 'line-item', array( |
|
133 | - self::type_line_item => __("Line Item", "event_espresso"), |
|
134 | - self::type_sub_line_item => __("Sub-Item", "event_espresso"), |
|
135 | - self::type_sub_total => __("Subtotal", "event_espresso"), |
|
136 | - self::type_tax_sub_total => __("Tax Subtotal", "event_espresso"), |
|
137 | - self::type_tax => __("Tax", "event_espresso"), |
|
138 | - self::type_total => __("Total", "event_espresso"), |
|
139 | - self::type_cancellation => __('Cancellation', 'event_espresso') |
|
140 | - ) |
|
141 | - ), |
|
142 | - 'OBJ_ID' => new EE_Foreign_Key_Int_Field('OBJ_ID', __('ID of Item purchased.', 'event_espresso'), TRUE, NULL, $line_items_can_be_for), |
|
143 | - 'OBJ_type' => new EE_Any_Foreign_Model_Name_Field('OBJ_type', __("Model Name this Line Item is for", "event_espresso"), TRUE, NULL, $line_items_can_be_for), |
|
144 | - 'LIN_timestamp' => new EE_Datetime_Field('LIN_timestamp', __('When the line item was created', 'event_espresso'), false, EE_Datetime_Field::now, $timezone), |
|
145 | - ) |
|
146 | - ); |
|
147 | - $this->_model_relations = array( |
|
148 | - 'Transaction' => new EE_Belongs_To_Relation(), |
|
149 | - 'Ticket' => new EE_Belongs_To_Any_Relation(), |
|
150 | - 'Price' => new EE_Belongs_To_Any_Relation(), |
|
151 | - 'Event' => new EE_Belongs_To_Any_Relation() |
|
152 | - ); |
|
153 | - $this->_model_chain_to_wp_user = 'Transaction.Registration.Event'; |
|
154 | - $this->_caps_slug = 'transactions'; |
|
155 | - parent::__construct($timezone); |
|
156 | - } |
|
157 | - |
|
158 | - |
|
159 | - /** |
|
160 | - * Gets all the line items for this transaction of the given type |
|
161 | - * @param string $line_item_type like one of EEM_Line_Item::type_* |
|
162 | - * @param EE_Transaction|int $transaction |
|
163 | - * @return EE_Line_Item[] |
|
164 | - */ |
|
165 | - public function get_all_of_type_for_transaction($line_item_type, $transaction) |
|
166 | - { |
|
167 | - $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
168 | - return $this->get_all(array(array( |
|
169 | - 'LIN_type' => $line_item_type, |
|
170 | - 'TXN_ID' => $transaction |
|
171 | - ))); |
|
172 | - } |
|
173 | - |
|
174 | - |
|
175 | - /** |
|
176 | - * Gets all line items unrelated to tickets that are normal line items |
|
177 | - * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category) |
|
178 | - * @param EE_Transaction|int $transaction |
|
179 | - * @return EE_Line_Item[] |
|
180 | - */ |
|
181 | - public function get_all_non_ticket_line_items_for_transaction($transaction) |
|
182 | - { |
|
183 | - $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
184 | - return $this->get_all(array(array( |
|
185 | - 'LIN_type' => self::type_line_item, |
|
186 | - 'TXN_ID' => $transaction, |
|
187 | - 'OR' => array( |
|
188 | - 'OBJ_type*notticket' => array('!=', 'Ticket'), |
|
189 | - 'OBJ_type*null' => array('IS_NULL')) |
|
190 | - ))); |
|
191 | - } |
|
192 | - |
|
193 | - /** |
|
194 | - * Deletes line items with no transaction who have passed the transaction cutoff time. |
|
195 | - * This needs to be very efficient |
|
196 | - * because if there are spam bots afoot there will be LOTS of line items |
|
197 | - * @return int count of how many deleted |
|
198 | - */ |
|
199 | - public function delete_line_items_with_no_transaction() |
|
200 | - { |
|
201 | - /** @type WPDB $wpdb */ |
|
202 | - global $wpdb; |
|
203 | - $time_to_leave_alone = apply_filters( |
|
204 | - 'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', WEEK_IN_SECONDS |
|
205 | - ); |
|
206 | - $query = $wpdb->prepare( |
|
207 | - 'DELETE li |
|
44 | + /** |
|
45 | + * Tax sub-total is just the total of all the taxes, which should be children |
|
46 | + * of this line item. There should only ever be one tax sub-total, and it should |
|
47 | + * be a direct child of |
|
48 | + */ |
|
49 | + const type_tax_sub_total = 'tax-sub-total'; |
|
50 | + |
|
51 | + /** |
|
52 | + * Tax line items indicate a tax applied to all the taxable line items. |
|
53 | + * Should not have any children line items. |
|
54 | + */ |
|
55 | + const type_tax = 'tax'; |
|
56 | + |
|
57 | + /** |
|
58 | + * Indicating individual items purchased, or discounts or surcharges. |
|
59 | + * The sum of all the regular line items plus the tax items should equal |
|
60 | + * the grand total. |
|
61 | + * Possible children fo sub-line-items and cancellations. |
|
62 | + */ |
|
63 | + const type_line_item = 'line-item'; |
|
64 | + |
|
65 | + /** |
|
66 | + * line item indicating all the factors that make a single line item. |
|
67 | + * Sub-line items should have NO children line items. |
|
68 | + */ |
|
69 | + const type_sub_line_item = 'sub-item'; |
|
70 | + |
|
71 | + /** |
|
72 | + * line item indicating a sub-total (eg total for an event, or before taxes). |
|
73 | + * Direct children can be line items and other sub-totals |
|
74 | + * |
|
75 | + */ |
|
76 | + const type_sub_total = 'sub-total'; |
|
77 | + |
|
78 | + /** |
|
79 | + * line item for teh grand total of an order. Its direct children |
|
80 | + * should be tax subtotals and subtotals, and possibly a regular line item |
|
81 | + * indicating a transaction-wide discount/surcharge |
|
82 | + */ |
|
83 | + const type_total = 'total'; |
|
84 | + |
|
85 | + /** |
|
86 | + * When a line item is cancelled, a sub-line-item of type 'cancellation' |
|
87 | + * should be created, indicating the quantity that were cancelled |
|
88 | + * (because a line item could have a quantity of 1, and its cancellation item |
|
89 | + * could be for 3, indicating that originally 4 were purchased, but 3 have been |
|
90 | + * cancelled, and only one remains). |
|
91 | + * When items are refunded, a cancellation line item should be made, which points |
|
92 | + * to teh payment model object which actually refunded the payment. |
|
93 | + * Cancellations should NOT have any children line items; the should NOT affect |
|
94 | + * any calculations, and are only meant as a record that cancellations have occurred. |
|
95 | + */ |
|
96 | + const type_cancellation = 'cancellation'; |
|
97 | + |
|
98 | + // private instance of the EEM_Line_Item object |
|
99 | + protected static $_instance = NULL; |
|
100 | + |
|
101 | + |
|
102 | + /** |
|
103 | + * private constructor to prevent direct creation |
|
104 | + * @Constructor |
|
105 | + * @access protected |
|
106 | + * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any incoming timezone data that gets saved). Note this just sends the timezone info to the date time model field objects. Default is NULL (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
107 | + * @return \EEM_Line_Item |
|
108 | + */ |
|
109 | + protected function __construct($timezone) |
|
110 | + { |
|
111 | + $this->singular_item = __('Line Item', 'event_espresso'); |
|
112 | + $this->plural_item = __('Line Items', 'event_espresso'); |
|
113 | + |
|
114 | + $this->_tables = array( |
|
115 | + 'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID') |
|
116 | + ); |
|
117 | + $line_items_can_be_for = apply_filters('FHEE__EEM_Line_Item__line_items_can_be_for', array('Ticket', 'Price', 'Event')); |
|
118 | + $this->_fields = array( |
|
119 | + 'Line_Item' => array( |
|
120 | + 'LIN_ID' => new EE_Primary_Key_Int_Field('LIN_ID', __("ID", "event_espresso")), |
|
121 | + 'LIN_code' => new EE_Slug_Field('LIN_code', __("Code for index into Cart", "event_espresso"), TRUE), |
|
122 | + 'TXN_ID' => new EE_Foreign_Key_Int_Field('TXN_ID', __("Transaction ID", "event_espresso"), TRUE, NULL, 'Transaction'), |
|
123 | + 'LIN_name' => new EE_Full_HTML_Field('LIN_name', __("Line Item Name", "event_espresso"), FALSE, ''), |
|
124 | + 'LIN_desc' => new EE_Full_HTML_Field('LIN_desc', __("Line Item Description", "event_espresso"), TRUE), |
|
125 | + 'LIN_unit_price' => new EE_Money_Field('LIN_unit_price', __("Unit Price", "event_espresso"), FALSE, 0), |
|
126 | + 'LIN_percent' => new EE_Float_Field('LIN_percent', __("Percent", "event_espresso"), FALSE, 0), |
|
127 | + 'LIN_is_taxable' => new EE_Boolean_Field('LIN_is_taxable', __("Taxable", "event_espresso"), FALSE, FALSE), |
|
128 | + 'LIN_order' => new EE_Integer_Field('LIN_order', __("Order of Application towards total of parent", "event_espresso"), FALSE, 1), |
|
129 | + 'LIN_total' => new EE_Money_Field('LIN_total', __("Total (unit price x quantity)", "event_espresso"), FALSE, 0), |
|
130 | + 'LIN_quantity' => new EE_Integer_Field('LIN_quantity', __("Quantity", "event_espresso"), TRUE, 1), |
|
131 | + 'LIN_parent' => new EE_Integer_Field('LIN_parent', __("Parent ID (this item goes towards that Line Item's total)", "event_espresso"), TRUE, NULL), |
|
132 | + 'LIN_type' => new EE_Enum_Text_Field('LIN_type', __("Type", "event_espresso"), FALSE, 'line-item', array( |
|
133 | + self::type_line_item => __("Line Item", "event_espresso"), |
|
134 | + self::type_sub_line_item => __("Sub-Item", "event_espresso"), |
|
135 | + self::type_sub_total => __("Subtotal", "event_espresso"), |
|
136 | + self::type_tax_sub_total => __("Tax Subtotal", "event_espresso"), |
|
137 | + self::type_tax => __("Tax", "event_espresso"), |
|
138 | + self::type_total => __("Total", "event_espresso"), |
|
139 | + self::type_cancellation => __('Cancellation', 'event_espresso') |
|
140 | + ) |
|
141 | + ), |
|
142 | + 'OBJ_ID' => new EE_Foreign_Key_Int_Field('OBJ_ID', __('ID of Item purchased.', 'event_espresso'), TRUE, NULL, $line_items_can_be_for), |
|
143 | + 'OBJ_type' => new EE_Any_Foreign_Model_Name_Field('OBJ_type', __("Model Name this Line Item is for", "event_espresso"), TRUE, NULL, $line_items_can_be_for), |
|
144 | + 'LIN_timestamp' => new EE_Datetime_Field('LIN_timestamp', __('When the line item was created', 'event_espresso'), false, EE_Datetime_Field::now, $timezone), |
|
145 | + ) |
|
146 | + ); |
|
147 | + $this->_model_relations = array( |
|
148 | + 'Transaction' => new EE_Belongs_To_Relation(), |
|
149 | + 'Ticket' => new EE_Belongs_To_Any_Relation(), |
|
150 | + 'Price' => new EE_Belongs_To_Any_Relation(), |
|
151 | + 'Event' => new EE_Belongs_To_Any_Relation() |
|
152 | + ); |
|
153 | + $this->_model_chain_to_wp_user = 'Transaction.Registration.Event'; |
|
154 | + $this->_caps_slug = 'transactions'; |
|
155 | + parent::__construct($timezone); |
|
156 | + } |
|
157 | + |
|
158 | + |
|
159 | + /** |
|
160 | + * Gets all the line items for this transaction of the given type |
|
161 | + * @param string $line_item_type like one of EEM_Line_Item::type_* |
|
162 | + * @param EE_Transaction|int $transaction |
|
163 | + * @return EE_Line_Item[] |
|
164 | + */ |
|
165 | + public function get_all_of_type_for_transaction($line_item_type, $transaction) |
|
166 | + { |
|
167 | + $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
168 | + return $this->get_all(array(array( |
|
169 | + 'LIN_type' => $line_item_type, |
|
170 | + 'TXN_ID' => $transaction |
|
171 | + ))); |
|
172 | + } |
|
173 | + |
|
174 | + |
|
175 | + /** |
|
176 | + * Gets all line items unrelated to tickets that are normal line items |
|
177 | + * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category) |
|
178 | + * @param EE_Transaction|int $transaction |
|
179 | + * @return EE_Line_Item[] |
|
180 | + */ |
|
181 | + public function get_all_non_ticket_line_items_for_transaction($transaction) |
|
182 | + { |
|
183 | + $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
184 | + return $this->get_all(array(array( |
|
185 | + 'LIN_type' => self::type_line_item, |
|
186 | + 'TXN_ID' => $transaction, |
|
187 | + 'OR' => array( |
|
188 | + 'OBJ_type*notticket' => array('!=', 'Ticket'), |
|
189 | + 'OBJ_type*null' => array('IS_NULL')) |
|
190 | + ))); |
|
191 | + } |
|
192 | + |
|
193 | + /** |
|
194 | + * Deletes line items with no transaction who have passed the transaction cutoff time. |
|
195 | + * This needs to be very efficient |
|
196 | + * because if there are spam bots afoot there will be LOTS of line items |
|
197 | + * @return int count of how many deleted |
|
198 | + */ |
|
199 | + public function delete_line_items_with_no_transaction() |
|
200 | + { |
|
201 | + /** @type WPDB $wpdb */ |
|
202 | + global $wpdb; |
|
203 | + $time_to_leave_alone = apply_filters( |
|
204 | + 'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', WEEK_IN_SECONDS |
|
205 | + ); |
|
206 | + $query = $wpdb->prepare( |
|
207 | + 'DELETE li |
|
208 | 208 | FROM ' . $this->table() . ' li |
209 | 209 | LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON li.TXN_ID = t.TXN_ID |
210 | 210 | WHERE t.TXN_ID IS NULL AND li.LIN_timestamp < %s', |
211 | - // use GMT time because that's what TXN_timestamps are in |
|
212 | - date('Y-m-d H:i:s', time() - $time_to_leave_alone) |
|
213 | - ); |
|
214 | - return $wpdb->query($query); |
|
215 | - } |
|
216 | - |
|
217 | - |
|
218 | - /** |
|
219 | - * get_line_item_for_transaction_object |
|
220 | - * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket |
|
221 | - * |
|
222 | - * @param int $TXN_ID |
|
223 | - * @param \EE_Base_Class $object |
|
224 | - * @return EE_Line_Item[] |
|
225 | - */ |
|
226 | - public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object) |
|
227 | - { |
|
228 | - return $this->get_all(array(array( |
|
229 | - 'TXN_ID' => $TXN_ID, |
|
230 | - 'OBJ_type' => str_replace('EE_', '', get_class($object)), |
|
231 | - 'OBJ_ID' => $object->ID() |
|
232 | - ))); |
|
233 | - } |
|
234 | - |
|
235 | - |
|
236 | - /** |
|
237 | - * get_object_line_items_for_transaction |
|
238 | - * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs |
|
239 | - * |
|
240 | - * @param int $TXN_ID |
|
241 | - * @param string $OBJ_type |
|
242 | - * @param array $OBJ_IDs |
|
243 | - * @return EE_Line_Item[] |
|
244 | - */ |
|
245 | - public function get_object_line_items_for_transaction($TXN_ID, $OBJ_type = 'Event', $OBJ_IDs = array()) |
|
246 | - { |
|
247 | - $query_params = array( |
|
248 | - 'OBJ_type' => $OBJ_type, |
|
249 | - // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query |
|
250 | - 'OBJ_ID' => is_array($OBJ_IDs) && !isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs |
|
251 | - ); |
|
252 | - if ($TXN_ID) { |
|
253 | - $query_params['TXN_ID'] = $TXN_ID; |
|
254 | - } |
|
255 | - return $this->get_all(array($query_params)); |
|
256 | - } |
|
257 | - |
|
258 | - |
|
259 | - /** |
|
260 | - * get_all_ticket_line_items_for_transaction |
|
261 | - * |
|
262 | - * @param EE_Transaction $transaction |
|
263 | - * @return EE_Line_Item[] |
|
264 | - */ |
|
265 | - public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction) |
|
266 | - { |
|
267 | - return $this->get_all(array( |
|
268 | - array( |
|
269 | - 'TXN_ID' => $transaction->ID(), |
|
270 | - 'OBJ_type' => 'Ticket', |
|
271 | - ) |
|
272 | - )); |
|
273 | - } |
|
274 | - |
|
275 | - |
|
276 | - /** |
|
277 | - * get_ticket_line_item_for_transaction |
|
278 | - * |
|
279 | - * @param int $TXN_ID |
|
280 | - * @param int $TKT_ID |
|
281 | - * @return \EE_Line_Item |
|
282 | - */ |
|
283 | - public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID) |
|
284 | - { |
|
285 | - return $this->get_one(array( |
|
286 | - array( |
|
287 | - 'TXN_ID' => EEM_Transaction::instance()->ensure_is_ID($TXN_ID), |
|
288 | - 'OBJ_ID' => $TKT_ID, |
|
289 | - 'OBJ_type' => 'Ticket', |
|
290 | - ) |
|
291 | - )); |
|
292 | - } |
|
293 | - |
|
294 | - |
|
295 | - /** |
|
296 | - * get_existing_promotion_line_item |
|
297 | - * searches the cart for existing line items for the specified promotion |
|
298 | - * |
|
299 | - * @since 1.0.0 |
|
300 | - * |
|
301 | - * @param EE_Line_Item $parent_line_item |
|
302 | - * @param EE_Promotion $promotion |
|
303 | - * @return EE_Line_Item |
|
304 | - */ |
|
305 | - public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion) |
|
306 | - { |
|
307 | - return $this->get_one(array( |
|
308 | - array( |
|
309 | - 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
310 | - 'LIN_parent' => $parent_line_item->ID(), |
|
311 | - 'OBJ_type' => 'Promotion', |
|
312 | - 'OBJ_ID' => $promotion->ID() |
|
313 | - ) |
|
314 | - )); |
|
315 | - } |
|
316 | - |
|
317 | - |
|
318 | - /** |
|
319 | - * get_all_promotion_line_items |
|
320 | - * searches the cart for any and all existing promotion line items |
|
321 | - * |
|
322 | - * @since 1.0.0 |
|
323 | - * |
|
324 | - * @param EE_Line_Item $parent_line_item |
|
325 | - * @return EE_Line_Item[] |
|
326 | - */ |
|
327 | - public function get_all_promotion_line_items(EE_Line_Item $parent_line_item) |
|
328 | - { |
|
329 | - return $this->get_all(array( |
|
330 | - array( |
|
331 | - 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
332 | - 'LIN_parent' => $parent_line_item->ID(), |
|
333 | - 'OBJ_type' => 'Promotion' |
|
334 | - ) |
|
335 | - )); |
|
336 | - } |
|
337 | - |
|
338 | - /** |
|
339 | - * Gets the registration's corresponding line item. |
|
340 | - * Note: basically does NOT support having multiple line items for a single ticket, |
|
341 | - * which would happen if some of the registrations had a price modifier while others didn't. |
|
342 | - * In order to support that, we'd probably need a LIN_ID on registrations or something. |
|
343 | - * @param EE_Registration $registration |
|
344 | - * @return EE_Line_ITem |
|
345 | - */ |
|
346 | - public function get_line_item_for_registration(EE_Registration $registration) |
|
347 | - { |
|
348 | - return $this->get_one($this->line_item_for_registration_query_params($registration)); |
|
349 | - } |
|
350 | - |
|
351 | - /** |
|
352 | - * Gets the query params used to retrieve a specific line item for the given registration |
|
353 | - * @param EE_Registration $registration |
|
354 | - * @param array $original_query_params any extra query params you'd like to be merged with |
|
355 | - * @return array like EEM_Base::get_all()'s $query_params |
|
356 | - */ |
|
357 | - public function line_item_for_registration_query_params(EE_Registration $registration, $original_query_params = array()) |
|
358 | - { |
|
359 | - return array_replace_recursive($original_query_params, array( |
|
360 | - array( |
|
361 | - 'OBJ_ID' => $registration->ticket_ID(), |
|
362 | - 'OBJ_type' => 'Ticket', |
|
363 | - 'TXN_ID' => $registration->transaction_ID() |
|
364 | - ) |
|
365 | - )); |
|
366 | - } |
|
367 | - |
|
368 | - |
|
369 | - /** |
|
370 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
371 | - * @throws \EE_Error |
|
372 | - */ |
|
373 | - public function get_total_line_items_with_no_transaction() |
|
374 | - { |
|
375 | - return $this->get_total_line_items_for_carts(); |
|
376 | - } |
|
377 | - |
|
378 | - |
|
379 | - /** |
|
380 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
381 | - * @throws \EE_Error |
|
382 | - */ |
|
383 | - public function get_total_line_items_for_active_carts() |
|
384 | - { |
|
385 | - return $this->get_total_line_items_for_carts(false); |
|
386 | - } |
|
387 | - |
|
388 | - |
|
389 | - /** |
|
390 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
391 | - * @throws \EE_Error |
|
392 | - */ |
|
393 | - public function get_total_line_items_for_expired_carts() |
|
394 | - { |
|
395 | - return $this->get_total_line_items_for_carts(true); |
|
396 | - } |
|
397 | - |
|
398 | - |
|
399 | - /** |
|
400 | - * Returns an array of grand total line items where the TXN_ID is 0. |
|
401 | - * If $expired is set to true, then only line items for expired sessions will be returned. |
|
402 | - * If $expired is set to false, then only line items for active sessions will be returned. |
|
403 | - * |
|
404 | - * @param bool|null $expired |
|
405 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
406 | - * @throws \EE_Error |
|
407 | - */ |
|
408 | - private function get_total_line_items_for_carts($expired = null) |
|
409 | - { |
|
410 | - $where_params = array( |
|
411 | - 'TXN_ID' => 0, |
|
412 | - 'LIN_type' => 'total', |
|
413 | - ); |
|
414 | - if ($expired !== null) { |
|
415 | - $where_params['LIN_timestamp'] = array( |
|
416 | - $expired ? '<=' : '>', |
|
417 | - time() - EE_Registry::instance()->SSN->lifespan(), |
|
418 | - ); |
|
419 | - } |
|
420 | - return $this->get_all(array($where_params)); |
|
421 | - } |
|
211 | + // use GMT time because that's what TXN_timestamps are in |
|
212 | + date('Y-m-d H:i:s', time() - $time_to_leave_alone) |
|
213 | + ); |
|
214 | + return $wpdb->query($query); |
|
215 | + } |
|
216 | + |
|
217 | + |
|
218 | + /** |
|
219 | + * get_line_item_for_transaction_object |
|
220 | + * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket |
|
221 | + * |
|
222 | + * @param int $TXN_ID |
|
223 | + * @param \EE_Base_Class $object |
|
224 | + * @return EE_Line_Item[] |
|
225 | + */ |
|
226 | + public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object) |
|
227 | + { |
|
228 | + return $this->get_all(array(array( |
|
229 | + 'TXN_ID' => $TXN_ID, |
|
230 | + 'OBJ_type' => str_replace('EE_', '', get_class($object)), |
|
231 | + 'OBJ_ID' => $object->ID() |
|
232 | + ))); |
|
233 | + } |
|
234 | + |
|
235 | + |
|
236 | + /** |
|
237 | + * get_object_line_items_for_transaction |
|
238 | + * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs |
|
239 | + * |
|
240 | + * @param int $TXN_ID |
|
241 | + * @param string $OBJ_type |
|
242 | + * @param array $OBJ_IDs |
|
243 | + * @return EE_Line_Item[] |
|
244 | + */ |
|
245 | + public function get_object_line_items_for_transaction($TXN_ID, $OBJ_type = 'Event', $OBJ_IDs = array()) |
|
246 | + { |
|
247 | + $query_params = array( |
|
248 | + 'OBJ_type' => $OBJ_type, |
|
249 | + // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query |
|
250 | + 'OBJ_ID' => is_array($OBJ_IDs) && !isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs |
|
251 | + ); |
|
252 | + if ($TXN_ID) { |
|
253 | + $query_params['TXN_ID'] = $TXN_ID; |
|
254 | + } |
|
255 | + return $this->get_all(array($query_params)); |
|
256 | + } |
|
257 | + |
|
258 | + |
|
259 | + /** |
|
260 | + * get_all_ticket_line_items_for_transaction |
|
261 | + * |
|
262 | + * @param EE_Transaction $transaction |
|
263 | + * @return EE_Line_Item[] |
|
264 | + */ |
|
265 | + public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction) |
|
266 | + { |
|
267 | + return $this->get_all(array( |
|
268 | + array( |
|
269 | + 'TXN_ID' => $transaction->ID(), |
|
270 | + 'OBJ_type' => 'Ticket', |
|
271 | + ) |
|
272 | + )); |
|
273 | + } |
|
274 | + |
|
275 | + |
|
276 | + /** |
|
277 | + * get_ticket_line_item_for_transaction |
|
278 | + * |
|
279 | + * @param int $TXN_ID |
|
280 | + * @param int $TKT_ID |
|
281 | + * @return \EE_Line_Item |
|
282 | + */ |
|
283 | + public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID) |
|
284 | + { |
|
285 | + return $this->get_one(array( |
|
286 | + array( |
|
287 | + 'TXN_ID' => EEM_Transaction::instance()->ensure_is_ID($TXN_ID), |
|
288 | + 'OBJ_ID' => $TKT_ID, |
|
289 | + 'OBJ_type' => 'Ticket', |
|
290 | + ) |
|
291 | + )); |
|
292 | + } |
|
293 | + |
|
294 | + |
|
295 | + /** |
|
296 | + * get_existing_promotion_line_item |
|
297 | + * searches the cart for existing line items for the specified promotion |
|
298 | + * |
|
299 | + * @since 1.0.0 |
|
300 | + * |
|
301 | + * @param EE_Line_Item $parent_line_item |
|
302 | + * @param EE_Promotion $promotion |
|
303 | + * @return EE_Line_Item |
|
304 | + */ |
|
305 | + public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion) |
|
306 | + { |
|
307 | + return $this->get_one(array( |
|
308 | + array( |
|
309 | + 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
310 | + 'LIN_parent' => $parent_line_item->ID(), |
|
311 | + 'OBJ_type' => 'Promotion', |
|
312 | + 'OBJ_ID' => $promotion->ID() |
|
313 | + ) |
|
314 | + )); |
|
315 | + } |
|
316 | + |
|
317 | + |
|
318 | + /** |
|
319 | + * get_all_promotion_line_items |
|
320 | + * searches the cart for any and all existing promotion line items |
|
321 | + * |
|
322 | + * @since 1.0.0 |
|
323 | + * |
|
324 | + * @param EE_Line_Item $parent_line_item |
|
325 | + * @return EE_Line_Item[] |
|
326 | + */ |
|
327 | + public function get_all_promotion_line_items(EE_Line_Item $parent_line_item) |
|
328 | + { |
|
329 | + return $this->get_all(array( |
|
330 | + array( |
|
331 | + 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
332 | + 'LIN_parent' => $parent_line_item->ID(), |
|
333 | + 'OBJ_type' => 'Promotion' |
|
334 | + ) |
|
335 | + )); |
|
336 | + } |
|
337 | + |
|
338 | + /** |
|
339 | + * Gets the registration's corresponding line item. |
|
340 | + * Note: basically does NOT support having multiple line items for a single ticket, |
|
341 | + * which would happen if some of the registrations had a price modifier while others didn't. |
|
342 | + * In order to support that, we'd probably need a LIN_ID on registrations or something. |
|
343 | + * @param EE_Registration $registration |
|
344 | + * @return EE_Line_ITem |
|
345 | + */ |
|
346 | + public function get_line_item_for_registration(EE_Registration $registration) |
|
347 | + { |
|
348 | + return $this->get_one($this->line_item_for_registration_query_params($registration)); |
|
349 | + } |
|
350 | + |
|
351 | + /** |
|
352 | + * Gets the query params used to retrieve a specific line item for the given registration |
|
353 | + * @param EE_Registration $registration |
|
354 | + * @param array $original_query_params any extra query params you'd like to be merged with |
|
355 | + * @return array like EEM_Base::get_all()'s $query_params |
|
356 | + */ |
|
357 | + public function line_item_for_registration_query_params(EE_Registration $registration, $original_query_params = array()) |
|
358 | + { |
|
359 | + return array_replace_recursive($original_query_params, array( |
|
360 | + array( |
|
361 | + 'OBJ_ID' => $registration->ticket_ID(), |
|
362 | + 'OBJ_type' => 'Ticket', |
|
363 | + 'TXN_ID' => $registration->transaction_ID() |
|
364 | + ) |
|
365 | + )); |
|
366 | + } |
|
367 | + |
|
368 | + |
|
369 | + /** |
|
370 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
371 | + * @throws \EE_Error |
|
372 | + */ |
|
373 | + public function get_total_line_items_with_no_transaction() |
|
374 | + { |
|
375 | + return $this->get_total_line_items_for_carts(); |
|
376 | + } |
|
377 | + |
|
378 | + |
|
379 | + /** |
|
380 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
381 | + * @throws \EE_Error |
|
382 | + */ |
|
383 | + public function get_total_line_items_for_active_carts() |
|
384 | + { |
|
385 | + return $this->get_total_line_items_for_carts(false); |
|
386 | + } |
|
387 | + |
|
388 | + |
|
389 | + /** |
|
390 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
391 | + * @throws \EE_Error |
|
392 | + */ |
|
393 | + public function get_total_line_items_for_expired_carts() |
|
394 | + { |
|
395 | + return $this->get_total_line_items_for_carts(true); |
|
396 | + } |
|
397 | + |
|
398 | + |
|
399 | + /** |
|
400 | + * Returns an array of grand total line items where the TXN_ID is 0. |
|
401 | + * If $expired is set to true, then only line items for expired sessions will be returned. |
|
402 | + * If $expired is set to false, then only line items for active sessions will be returned. |
|
403 | + * |
|
404 | + * @param bool|null $expired |
|
405 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
406 | + * @throws \EE_Error |
|
407 | + */ |
|
408 | + private function get_total_line_items_for_carts($expired = null) |
|
409 | + { |
|
410 | + $where_params = array( |
|
411 | + 'TXN_ID' => 0, |
|
412 | + 'LIN_type' => 'total', |
|
413 | + ); |
|
414 | + if ($expired !== null) { |
|
415 | + $where_params['LIN_timestamp'] = array( |
|
416 | + $expired ? '<=' : '>', |
|
417 | + time() - EE_Registry::instance()->SSN->lifespan(), |
|
418 | + ); |
|
419 | + } |
|
420 | + return $this->get_all(array($where_params)); |
|
421 | + } |
|
422 | 422 | |
423 | 423 | |
424 | 424 | } |
425 | 425 | \ No newline at end of file |
@@ -1,4 +1,4 @@ discard block |
||
1 | -<?php if (!defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed'); |
|
1 | +<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed'); |
|
2 | 2 | |
3 | 3 | /** |
4 | 4 | * Event Espresso |
@@ -205,8 +205,8 @@ discard block |
||
205 | 205 | ); |
206 | 206 | $query = $wpdb->prepare( |
207 | 207 | 'DELETE li |
208 | - FROM ' . $this->table() . ' li |
|
209 | - LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON li.TXN_ID = t.TXN_ID |
|
208 | + FROM ' . $this->table().' li |
|
209 | + LEFT JOIN ' . EEM_Transaction::instance()->table().' t ON li.TXN_ID = t.TXN_ID |
|
210 | 210 | WHERE t.TXN_ID IS NULL AND li.LIN_timestamp < %s', |
211 | 211 | // use GMT time because that's what TXN_timestamps are in |
212 | 212 | date('Y-m-d H:i:s', time() - $time_to_leave_alone) |
@@ -247,7 +247,7 @@ discard block |
||
247 | 247 | $query_params = array( |
248 | 248 | 'OBJ_type' => $OBJ_type, |
249 | 249 | // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query |
250 | - 'OBJ_ID' => is_array($OBJ_IDs) && !isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs |
|
250 | + 'OBJ_ID' => is_array($OBJ_IDs) && ! isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs |
|
251 | 251 | ); |
252 | 252 | if ($TXN_ID) { |
253 | 253 | $query_params['TXN_ID'] = $TXN_ID; |
@@ -1,4 +1,6 @@ |
||
1 | -<?php if (!defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed'); |
|
1 | +<?php if (!defined('EVENT_ESPRESSO_VERSION')) { |
|
2 | + exit('No direct script access allowed'); |
|
3 | +} |
|
2 | 4 | |
3 | 5 | /** |
4 | 6 | * Event Espresso |
@@ -38,216 +38,216 @@ |
||
38 | 38 | * @since 4.0 |
39 | 39 | */ |
40 | 40 | if (function_exists('espresso_version')) { |
41 | - if (! function_exists('espresso_duplicate_plugin_error')) { |
|
42 | - /** |
|
43 | - * espresso_duplicate_plugin_error |
|
44 | - * displays if more than one version of EE is activated at the same time |
|
45 | - */ |
|
46 | - function espresso_duplicate_plugin_error() |
|
47 | - { |
|
48 | - ?> |
|
41 | + if (! function_exists('espresso_duplicate_plugin_error')) { |
|
42 | + /** |
|
43 | + * espresso_duplicate_plugin_error |
|
44 | + * displays if more than one version of EE is activated at the same time |
|
45 | + */ |
|
46 | + function espresso_duplicate_plugin_error() |
|
47 | + { |
|
48 | + ?> |
|
49 | 49 | <div class="error"> |
50 | 50 | <p> |
51 | 51 | <?php |
52 | - echo esc_html__( |
|
53 | - 'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.', |
|
54 | - 'event_espresso' |
|
55 | - ); ?> |
|
52 | + echo esc_html__( |
|
53 | + 'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.', |
|
54 | + 'event_espresso' |
|
55 | + ); ?> |
|
56 | 56 | </p> |
57 | 57 | </div> |
58 | 58 | <?php |
59 | - espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
60 | - } |
|
61 | - } |
|
62 | - add_action('admin_notices', 'espresso_duplicate_plugin_error', 1); |
|
59 | + espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
60 | + } |
|
61 | + } |
|
62 | + add_action('admin_notices', 'espresso_duplicate_plugin_error', 1); |
|
63 | 63 | |
64 | 64 | } else { |
65 | - define('EE_MIN_PHP_VER_REQUIRED', '5.3.9'); |
|
66 | - if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) { |
|
67 | - /** |
|
68 | - * espresso_minimum_php_version_error |
|
69 | - * @return void |
|
70 | - */ |
|
71 | - function espresso_minimum_php_version_error() |
|
72 | - { |
|
73 | - ?> |
|
65 | + define('EE_MIN_PHP_VER_REQUIRED', '5.3.9'); |
|
66 | + if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) { |
|
67 | + /** |
|
68 | + * espresso_minimum_php_version_error |
|
69 | + * @return void |
|
70 | + */ |
|
71 | + function espresso_minimum_php_version_error() |
|
72 | + { |
|
73 | + ?> |
|
74 | 74 | <div class="error"> |
75 | 75 | <p> |
76 | 76 | <?php |
77 | - printf( |
|
78 | - esc_html__( |
|
79 | - 'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.', |
|
80 | - 'event_espresso' |
|
81 | - ), |
|
82 | - EE_MIN_PHP_VER_REQUIRED, |
|
83 | - PHP_VERSION, |
|
84 | - '<br/>', |
|
85 | - '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>' |
|
86 | - ); |
|
87 | - ?> |
|
77 | + printf( |
|
78 | + esc_html__( |
|
79 | + 'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.', |
|
80 | + 'event_espresso' |
|
81 | + ), |
|
82 | + EE_MIN_PHP_VER_REQUIRED, |
|
83 | + PHP_VERSION, |
|
84 | + '<br/>', |
|
85 | + '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>' |
|
86 | + ); |
|
87 | + ?> |
|
88 | 88 | </p> |
89 | 89 | </div> |
90 | 90 | <?php |
91 | - espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
92 | - } |
|
91 | + espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
92 | + } |
|
93 | 93 | |
94 | - add_action('admin_notices', 'espresso_minimum_php_version_error', 1); |
|
95 | - } else { |
|
96 | - define('EVENT_ESPRESSO_MAIN_FILE', __FILE__); |
|
97 | - /** |
|
98 | - * espresso_version |
|
99 | - * Returns the plugin version |
|
100 | - * |
|
101 | - * @return string |
|
102 | - */ |
|
103 | - function espresso_version() |
|
104 | - { |
|
105 | - return apply_filters('FHEE__espresso__espresso_version', '4.9.54.rc.030'); |
|
106 | - } |
|
94 | + add_action('admin_notices', 'espresso_minimum_php_version_error', 1); |
|
95 | + } else { |
|
96 | + define('EVENT_ESPRESSO_MAIN_FILE', __FILE__); |
|
97 | + /** |
|
98 | + * espresso_version |
|
99 | + * Returns the plugin version |
|
100 | + * |
|
101 | + * @return string |
|
102 | + */ |
|
103 | + function espresso_version() |
|
104 | + { |
|
105 | + return apply_filters('FHEE__espresso__espresso_version', '4.9.54.rc.030'); |
|
106 | + } |
|
107 | 107 | |
108 | - /** |
|
109 | - * espresso_plugin_activation |
|
110 | - * adds a wp-option to indicate that EE has been activated via the WP admin plugins page |
|
111 | - */ |
|
112 | - function espresso_plugin_activation() |
|
113 | - { |
|
114 | - update_option('ee_espresso_activation', true); |
|
115 | - } |
|
108 | + /** |
|
109 | + * espresso_plugin_activation |
|
110 | + * adds a wp-option to indicate that EE has been activated via the WP admin plugins page |
|
111 | + */ |
|
112 | + function espresso_plugin_activation() |
|
113 | + { |
|
114 | + update_option('ee_espresso_activation', true); |
|
115 | + } |
|
116 | 116 | |
117 | - register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation'); |
|
118 | - /** |
|
119 | - * espresso_load_error_handling |
|
120 | - * this function loads EE's class for handling exceptions and errors |
|
121 | - */ |
|
122 | - function espresso_load_error_handling() |
|
123 | - { |
|
124 | - static $error_handling_loaded = false; |
|
125 | - if ($error_handling_loaded) { |
|
126 | - return; |
|
127 | - } |
|
128 | - // load debugging tools |
|
129 | - if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) { |
|
130 | - require_once EE_HELPERS . 'EEH_Debug_Tools.helper.php'; |
|
131 | - \EEH_Debug_Tools::instance(); |
|
132 | - } |
|
133 | - // load error handling |
|
134 | - if (is_readable(EE_CORE . 'EE_Error.core.php')) { |
|
135 | - require_once EE_CORE . 'EE_Error.core.php'; |
|
136 | - } else { |
|
137 | - wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso')); |
|
138 | - } |
|
139 | - $error_handling_loaded = true; |
|
140 | - } |
|
117 | + register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation'); |
|
118 | + /** |
|
119 | + * espresso_load_error_handling |
|
120 | + * this function loads EE's class for handling exceptions and errors |
|
121 | + */ |
|
122 | + function espresso_load_error_handling() |
|
123 | + { |
|
124 | + static $error_handling_loaded = false; |
|
125 | + if ($error_handling_loaded) { |
|
126 | + return; |
|
127 | + } |
|
128 | + // load debugging tools |
|
129 | + if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) { |
|
130 | + require_once EE_HELPERS . 'EEH_Debug_Tools.helper.php'; |
|
131 | + \EEH_Debug_Tools::instance(); |
|
132 | + } |
|
133 | + // load error handling |
|
134 | + if (is_readable(EE_CORE . 'EE_Error.core.php')) { |
|
135 | + require_once EE_CORE . 'EE_Error.core.php'; |
|
136 | + } else { |
|
137 | + wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso')); |
|
138 | + } |
|
139 | + $error_handling_loaded = true; |
|
140 | + } |
|
141 | 141 | |
142 | - /** |
|
143 | - * espresso_load_required |
|
144 | - * given a class name and path, this function will load that file or throw an exception |
|
145 | - * |
|
146 | - * @param string $classname |
|
147 | - * @param string $full_path_to_file |
|
148 | - * @throws EE_Error |
|
149 | - */ |
|
150 | - function espresso_load_required($classname, $full_path_to_file) |
|
151 | - { |
|
152 | - if (is_readable($full_path_to_file)) { |
|
153 | - require_once $full_path_to_file; |
|
154 | - } else { |
|
155 | - throw new \EE_Error ( |
|
156 | - sprintf( |
|
157 | - esc_html__( |
|
158 | - 'The %s class file could not be located or is not readable due to file permissions.', |
|
159 | - 'event_espresso' |
|
160 | - ), |
|
161 | - $classname |
|
162 | - ) |
|
163 | - ); |
|
164 | - } |
|
165 | - } |
|
142 | + /** |
|
143 | + * espresso_load_required |
|
144 | + * given a class name and path, this function will load that file or throw an exception |
|
145 | + * |
|
146 | + * @param string $classname |
|
147 | + * @param string $full_path_to_file |
|
148 | + * @throws EE_Error |
|
149 | + */ |
|
150 | + function espresso_load_required($classname, $full_path_to_file) |
|
151 | + { |
|
152 | + if (is_readable($full_path_to_file)) { |
|
153 | + require_once $full_path_to_file; |
|
154 | + } else { |
|
155 | + throw new \EE_Error ( |
|
156 | + sprintf( |
|
157 | + esc_html__( |
|
158 | + 'The %s class file could not be located or is not readable due to file permissions.', |
|
159 | + 'event_espresso' |
|
160 | + ), |
|
161 | + $classname |
|
162 | + ) |
|
163 | + ); |
|
164 | + } |
|
165 | + } |
|
166 | 166 | |
167 | - /** |
|
168 | - * @since 4.9.27 |
|
169 | - * @throws \EE_Error |
|
170 | - * @throws \EventEspresso\core\exceptions\InvalidInterfaceException |
|
171 | - * @throws \EventEspresso\core\exceptions\InvalidEntityException |
|
172 | - * @throws \EventEspresso\core\exceptions\InvalidIdentifierException |
|
173 | - * @throws \EventEspresso\core\exceptions\InvalidClassException |
|
174 | - * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
175 | - * @throws \EventEspresso\core\services\container\exceptions\ServiceExistsException |
|
176 | - * @throws \EventEspresso\core\services\container\exceptions\ServiceNotFoundException |
|
177 | - * @throws \OutOfBoundsException |
|
178 | - */ |
|
179 | - function bootstrap_espresso() |
|
180 | - { |
|
181 | - require_once __DIR__ . '/core/espresso_definitions.php'; |
|
182 | - try { |
|
183 | - espresso_load_error_handling(); |
|
184 | - espresso_load_required( |
|
185 | - 'EEH_Base', |
|
186 | - EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php' |
|
187 | - ); |
|
188 | - espresso_load_required( |
|
189 | - 'EEH_File', |
|
190 | - EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php' |
|
191 | - ); |
|
192 | - espresso_load_required( |
|
193 | - 'EEH_File', |
|
194 | - EE_CORE . 'helpers' . DS . 'EEH_File.helper.php' |
|
195 | - ); |
|
196 | - espresso_load_required( |
|
197 | - 'EEH_Array', |
|
198 | - EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php' |
|
199 | - ); |
|
200 | - // instantiate and configure PSR4 autoloader |
|
201 | - espresso_load_required( |
|
202 | - 'Psr4Autoloader', |
|
203 | - EE_CORE . 'Psr4Autoloader.php' |
|
204 | - ); |
|
205 | - espresso_load_required( |
|
206 | - 'EE_Psr4AutoloaderInit', |
|
207 | - EE_CORE . 'EE_Psr4AutoloaderInit.core.php' |
|
208 | - ); |
|
209 | - $AutoloaderInit = new EE_Psr4AutoloaderInit(); |
|
210 | - $AutoloaderInit->initializeAutoloader(); |
|
211 | - espresso_load_required( |
|
212 | - 'EE_Request', |
|
213 | - EE_CORE . 'request_stack' . DS . 'EE_Request.core.php' |
|
214 | - ); |
|
215 | - espresso_load_required( |
|
216 | - 'EE_Response', |
|
217 | - EE_CORE . 'request_stack' . DS . 'EE_Response.core.php' |
|
218 | - ); |
|
219 | - espresso_load_required( |
|
220 | - 'EE_Bootstrap', |
|
221 | - EE_CORE . 'EE_Bootstrap.core.php' |
|
222 | - ); |
|
223 | - // bootstrap EE and the request stack |
|
224 | - new EE_Bootstrap( |
|
225 | - new EE_Request($_GET, $_POST, $_COOKIE), |
|
226 | - new EE_Response() |
|
227 | - ); |
|
228 | - } catch (Exception $e) { |
|
229 | - require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php'; |
|
230 | - new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e); |
|
231 | - } |
|
232 | - } |
|
233 | - bootstrap_espresso(); |
|
234 | - } |
|
167 | + /** |
|
168 | + * @since 4.9.27 |
|
169 | + * @throws \EE_Error |
|
170 | + * @throws \EventEspresso\core\exceptions\InvalidInterfaceException |
|
171 | + * @throws \EventEspresso\core\exceptions\InvalidEntityException |
|
172 | + * @throws \EventEspresso\core\exceptions\InvalidIdentifierException |
|
173 | + * @throws \EventEspresso\core\exceptions\InvalidClassException |
|
174 | + * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
175 | + * @throws \EventEspresso\core\services\container\exceptions\ServiceExistsException |
|
176 | + * @throws \EventEspresso\core\services\container\exceptions\ServiceNotFoundException |
|
177 | + * @throws \OutOfBoundsException |
|
178 | + */ |
|
179 | + function bootstrap_espresso() |
|
180 | + { |
|
181 | + require_once __DIR__ . '/core/espresso_definitions.php'; |
|
182 | + try { |
|
183 | + espresso_load_error_handling(); |
|
184 | + espresso_load_required( |
|
185 | + 'EEH_Base', |
|
186 | + EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php' |
|
187 | + ); |
|
188 | + espresso_load_required( |
|
189 | + 'EEH_File', |
|
190 | + EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php' |
|
191 | + ); |
|
192 | + espresso_load_required( |
|
193 | + 'EEH_File', |
|
194 | + EE_CORE . 'helpers' . DS . 'EEH_File.helper.php' |
|
195 | + ); |
|
196 | + espresso_load_required( |
|
197 | + 'EEH_Array', |
|
198 | + EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php' |
|
199 | + ); |
|
200 | + // instantiate and configure PSR4 autoloader |
|
201 | + espresso_load_required( |
|
202 | + 'Psr4Autoloader', |
|
203 | + EE_CORE . 'Psr4Autoloader.php' |
|
204 | + ); |
|
205 | + espresso_load_required( |
|
206 | + 'EE_Psr4AutoloaderInit', |
|
207 | + EE_CORE . 'EE_Psr4AutoloaderInit.core.php' |
|
208 | + ); |
|
209 | + $AutoloaderInit = new EE_Psr4AutoloaderInit(); |
|
210 | + $AutoloaderInit->initializeAutoloader(); |
|
211 | + espresso_load_required( |
|
212 | + 'EE_Request', |
|
213 | + EE_CORE . 'request_stack' . DS . 'EE_Request.core.php' |
|
214 | + ); |
|
215 | + espresso_load_required( |
|
216 | + 'EE_Response', |
|
217 | + EE_CORE . 'request_stack' . DS . 'EE_Response.core.php' |
|
218 | + ); |
|
219 | + espresso_load_required( |
|
220 | + 'EE_Bootstrap', |
|
221 | + EE_CORE . 'EE_Bootstrap.core.php' |
|
222 | + ); |
|
223 | + // bootstrap EE and the request stack |
|
224 | + new EE_Bootstrap( |
|
225 | + new EE_Request($_GET, $_POST, $_COOKIE), |
|
226 | + new EE_Response() |
|
227 | + ); |
|
228 | + } catch (Exception $e) { |
|
229 | + require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php'; |
|
230 | + new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e); |
|
231 | + } |
|
232 | + } |
|
233 | + bootstrap_espresso(); |
|
234 | + } |
|
235 | 235 | } |
236 | 236 | if (! function_exists('espresso_deactivate_plugin')) { |
237 | - /** |
|
238 | - * deactivate_plugin |
|
239 | - * usage: espresso_deactivate_plugin( plugin_basename( __FILE__ )); |
|
240 | - * |
|
241 | - * @access public |
|
242 | - * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file |
|
243 | - * @return void |
|
244 | - */ |
|
245 | - function espresso_deactivate_plugin($plugin_basename = '') |
|
246 | - { |
|
247 | - if (! function_exists('deactivate_plugins')) { |
|
248 | - require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
|
249 | - } |
|
250 | - unset($_GET['activate'], $_REQUEST['activate']); |
|
251 | - deactivate_plugins($plugin_basename); |
|
252 | - } |
|
237 | + /** |
|
238 | + * deactivate_plugin |
|
239 | + * usage: espresso_deactivate_plugin( plugin_basename( __FILE__ )); |
|
240 | + * |
|
241 | + * @access public |
|
242 | + * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file |
|
243 | + * @return void |
|
244 | + */ |
|
245 | + function espresso_deactivate_plugin($plugin_basename = '') |
|
246 | + { |
|
247 | + if (! function_exists('deactivate_plugins')) { |
|
248 | + require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
|
249 | + } |
|
250 | + unset($_GET['activate'], $_REQUEST['activate']); |
|
251 | + deactivate_plugins($plugin_basename); |
|
252 | + } |
|
253 | 253 | } |