@@ -6,57 +6,57 @@ |
||
| 6 | 6 | |
| 7 | 7 | class DecimalValues |
| 8 | 8 | { |
| 9 | - /** |
|
| 10 | - * number of decimal places to round numbers to when performing calculations |
|
| 11 | - * |
|
| 12 | - * @var integer |
|
| 13 | - */ |
|
| 14 | - protected $decimal_precision = 6; |
|
| 15 | - |
|
| 16 | - /** |
|
| 17 | - * number of decimal places to round numbers to for display |
|
| 18 | - * |
|
| 19 | - * @var integer |
|
| 20 | - */ |
|
| 21 | - protected $locale_precision = 6; |
|
| 22 | - |
|
| 23 | - |
|
| 24 | - /** |
|
| 25 | - * @param EE_Currency_Config $currency_config |
|
| 26 | - */ |
|
| 27 | - public function __construct(EE_Currency_Config $currency_config) |
|
| 28 | - { |
|
| 29 | - $this->locale_precision = $currency_config->dec_plc; |
|
| 30 | - } |
|
| 31 | - |
|
| 32 | - /** |
|
| 33 | - * strips formatting, rounds the provided number, and returns a float |
|
| 34 | - * if $round is set to true, then the decimal precision for the site locale will be used, |
|
| 35 | - * otherwise the default decimal precision of 6 will be used |
|
| 36 | - * |
|
| 37 | - * @param float|int|string $number unformatted number value, ex: 1234.5678956789 |
|
| 38 | - * @param bool $round whether to round the price off according to the locale settings |
|
| 39 | - * @return float rounded value, ex: 1,234.567896 |
|
| 40 | - */ |
|
| 41 | - public function roundDecimalValue($number, bool $round = false): float |
|
| 42 | - { |
|
| 43 | - $precision = $round ? $this->locale_precision : $this->decimal_precision; |
|
| 44 | - return round( |
|
| 45 | - $this->filterDecimalValue($number), |
|
| 46 | - $precision ?? $this->decimal_precision, |
|
| 47 | - PHP_ROUND_HALF_UP |
|
| 48 | - ); |
|
| 49 | - } |
|
| 50 | - |
|
| 51 | - |
|
| 52 | - /** |
|
| 53 | - * Removes all characters except digits, +- and . |
|
| 54 | - * |
|
| 55 | - * @param float|int|string $number |
|
| 56 | - * @return float |
|
| 57 | - */ |
|
| 58 | - public function filterDecimalValue($number): float |
|
| 59 | - { |
|
| 60 | - return (float) filter_var($number, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); |
|
| 61 | - } |
|
| 9 | + /** |
|
| 10 | + * number of decimal places to round numbers to when performing calculations |
|
| 11 | + * |
|
| 12 | + * @var integer |
|
| 13 | + */ |
|
| 14 | + protected $decimal_precision = 6; |
|
| 15 | + |
|
| 16 | + /** |
|
| 17 | + * number of decimal places to round numbers to for display |
|
| 18 | + * |
|
| 19 | + * @var integer |
|
| 20 | + */ |
|
| 21 | + protected $locale_precision = 6; |
|
| 22 | + |
|
| 23 | + |
|
| 24 | + /** |
|
| 25 | + * @param EE_Currency_Config $currency_config |
|
| 26 | + */ |
|
| 27 | + public function __construct(EE_Currency_Config $currency_config) |
|
| 28 | + { |
|
| 29 | + $this->locale_precision = $currency_config->dec_plc; |
|
| 30 | + } |
|
| 31 | + |
|
| 32 | + /** |
|
| 33 | + * strips formatting, rounds the provided number, and returns a float |
|
| 34 | + * if $round is set to true, then the decimal precision for the site locale will be used, |
|
| 35 | + * otherwise the default decimal precision of 6 will be used |
|
| 36 | + * |
|
| 37 | + * @param float|int|string $number unformatted number value, ex: 1234.5678956789 |
|
| 38 | + * @param bool $round whether to round the price off according to the locale settings |
|
| 39 | + * @return float rounded value, ex: 1,234.567896 |
|
| 40 | + */ |
|
| 41 | + public function roundDecimalValue($number, bool $round = false): float |
|
| 42 | + { |
|
| 43 | + $precision = $round ? $this->locale_precision : $this->decimal_precision; |
|
| 44 | + return round( |
|
| 45 | + $this->filterDecimalValue($number), |
|
| 46 | + $precision ?? $this->decimal_precision, |
|
| 47 | + PHP_ROUND_HALF_UP |
|
| 48 | + ); |
|
| 49 | + } |
|
| 50 | + |
|
| 51 | + |
|
| 52 | + /** |
|
| 53 | + * Removes all characters except digits, +- and . |
|
| 54 | + * |
|
| 55 | + * @param float|int|string $number |
|
| 56 | + * @return float |
|
| 57 | + */ |
|
| 58 | + public function filterDecimalValue($number): float |
|
| 59 | + { |
|
| 60 | + return (float) filter_var($number, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); |
|
| 61 | + } |
|
| 62 | 62 | } |
@@ -21,714 +21,714 @@ |
||
| 21 | 21 | class LineItemCalculator |
| 22 | 22 | { |
| 23 | 23 | |
| 24 | - /** |
|
| 25 | - * @var DecimalValues |
|
| 26 | - */ |
|
| 27 | - protected $decimal_values; |
|
| 28 | - |
|
| 29 | - /** |
|
| 30 | - * @var array |
|
| 31 | - */ |
|
| 32 | - protected $default_query_params = [ |
|
| 33 | - ['LIN_type' => ['!=', EEM_Line_Item::type_cancellation]] |
|
| 34 | - ]; |
|
| 35 | - |
|
| 36 | - |
|
| 37 | - /** |
|
| 38 | - * @param DecimalValues $decimal_values |
|
| 39 | - */ |
|
| 40 | - public function __construct(DecimalValues $decimal_values) |
|
| 41 | - { |
|
| 42 | - $this->decimal_values = $decimal_values; |
|
| 43 | - } |
|
| 44 | - |
|
| 45 | - |
|
| 46 | - /** |
|
| 47 | - * Gets the final total on this item, taking taxes into account. |
|
| 48 | - * Has the side-effect of setting the sub-total as it was just calculated. |
|
| 49 | - * If this is used on a grand-total line item, also updates the transaction's |
|
| 50 | - * TXN_total (provided this line item is allowed to persist, otherwise we don't |
|
| 51 | - * want to change a persistable transaction with info from a non-persistent line item) |
|
| 52 | - * |
|
| 53 | - * @param EE_Line_Item $line_item |
|
| 54 | - * @param bool $update_txn_status |
|
| 55 | - * @return float |
|
| 56 | - * @throws EE_Error |
|
| 57 | - * @throws ReflectionException |
|
| 58 | - */ |
|
| 59 | - public function recalculateTotalIncludingTaxes(EE_Line_Item $line_item, bool $update_txn_status = false): float |
|
| 60 | - { |
|
| 61 | - $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total); |
|
| 62 | - $ticket_line_items = EEH_Line_Item::get_ticket_line_items($line_item); |
|
| 63 | - if (empty($ticket_line_items)) { |
|
| 64 | - return 0; |
|
| 65 | - } |
|
| 66 | - [, $pretax] = $this->recalculateLineItemTotals($line_item); |
|
| 67 | - $total_tax = $this->recalculateTaxesAndTaxTotal($line_item); |
|
| 68 | - // no negative totals plz |
|
| 69 | - $grand_total = max($pretax + $total_tax, 0); |
|
| 70 | - $this->updatePreTaxTotal($line_item, $pretax, true); |
|
| 71 | - $grand_total = $this->updateTotal($line_item, $grand_total, true); |
|
| 72 | - $this->updateTransaction($line_item, $grand_total, $update_txn_status); |
|
| 73 | - return $grand_total; |
|
| 74 | - } |
|
| 75 | - |
|
| 76 | - |
|
| 77 | - /** |
|
| 78 | - * Recursively goes through all the children and recalculates sub-totals EXCEPT for |
|
| 79 | - * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its |
|
| 80 | - * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and |
|
| 81 | - * when this is called on the grand total |
|
| 82 | - * |
|
| 83 | - * @param EE_Line_Item $line_item |
|
| 84 | - * @param float $total |
|
| 85 | - * @param float $pretax |
|
| 86 | - * @return array |
|
| 87 | - * @throws EE_Error |
|
| 88 | - * @throws ReflectionException |
|
| 89 | - */ |
|
| 90 | - public function recalculateLineItemTotals( |
|
| 91 | - EE_Line_Item $line_item, |
|
| 92 | - float $total = 0, |
|
| 93 | - float $pretax = 0 |
|
| 94 | - ): array { |
|
| 95 | - $new_total = $new_pretax = 0; |
|
| 96 | - switch ($line_item->type()) { |
|
| 97 | - case EEM_Line_Item::type_total: |
|
| 98 | - case EEM_Line_Item::type_sub_total: |
|
| 99 | - [$new_total, $new_pretax] = $this->recalculateSubTotal($line_item, $total, $pretax); |
|
| 100 | - break; |
|
| 101 | - |
|
| 102 | - case EEM_Line_Item::type_line_item: |
|
| 103 | - [$new_total, $new_pretax] = $this->recalculateLineItem($line_item, $total, $pretax); |
|
| 104 | - break; |
|
| 105 | - |
|
| 106 | - case EEM_Line_Item::type_sub_line_item: |
|
| 107 | - // sub line items operate on the total and update both the total AND the pre-tax total |
|
| 108 | - $new_total = $new_pretax = $this->recalculateSubLineItem($line_item, $total); |
|
| 109 | - break; |
|
| 110 | - |
|
| 111 | - case EEM_Line_Item::type_sub_tax: |
|
| 112 | - // sub line item taxes ONLY operate on the pre-tax total and ONLY update the total |
|
| 113 | - $new_total = $this->recalculateSubTax($line_item, $pretax); |
|
| 114 | - break; |
|
| 115 | - |
|
| 116 | - case EEM_Line_Item::type_tax_sub_total: |
|
| 117 | - case EEM_Line_Item::type_tax: |
|
| 118 | - case EEM_Line_Item::type_cancellation: |
|
| 119 | - // completely ignore tax totals, tax sub-totals, and cancelled line items |
|
| 120 | - // when calculating the pre-tax-total |
|
| 121 | - break; |
|
| 122 | - } |
|
| 123 | - return [$new_total, $new_pretax]; |
|
| 124 | - } |
|
| 125 | - |
|
| 126 | - |
|
| 127 | - /** |
|
| 128 | - * @param EE_Line_Item $line_item |
|
| 129 | - * @param float $total |
|
| 130 | - * @param float $pretax |
|
| 131 | - * @return array |
|
| 132 | - * @throws EE_Error |
|
| 133 | - * @throws ReflectionException |
|
| 134 | - */ |
|
| 135 | - private function recalculateSubTotal( |
|
| 136 | - EE_Line_Item $line_item, |
|
| 137 | - float $total = 0, |
|
| 138 | - float $pretax = 0 |
|
| 139 | - ): array { |
|
| 140 | - if ($line_item->is_total()) { |
|
| 141 | - // if this is the grand total line item |
|
| 142 | - // then first update ALL of the line item quantities (if need be) |
|
| 143 | - $this->updateLineItemQuantities($line_item); |
|
| 144 | - } |
|
| 145 | - // recursively loop through children and recalculate their totals |
|
| 146 | - $children = $line_item->children($this->default_query_params); |
|
| 147 | - if (empty($children)) { |
|
| 148 | - return [$total, $pretax]; |
|
| 149 | - } |
|
| 150 | - // reset the total and pretax total to zero since we are recalculating them |
|
| 151 | - $pretax = $total = 0; |
|
| 152 | - foreach ($children as $child_line_item) { |
|
| 153 | - [$child_total, $child_pretax] = $this->recalculateLineItemTotals($child_line_item, $total, $pretax); |
|
| 154 | - $total += $child_total; |
|
| 155 | - $pretax += $child_pretax; |
|
| 156 | - } |
|
| 157 | - // for the actual pre-tax sub total line item, we want to save the pretax value for everything |
|
| 158 | - if ($line_item->is_sub_total() && $line_item->name() === esc_html__('Pre-Tax Subtotal', 'event_espresso')) { |
|
| 159 | - $this->updateUnitPrice($line_item, $pretax); |
|
| 160 | - $this->updateTotal($line_item, $pretax, true); |
|
| 161 | - } elseif ($line_item->is_total()) { |
|
| 162 | - // only update the unit price for the total line item, because that will need to include taxes |
|
| 163 | - $this->updateUnitPrice($line_item, $total); |
|
| 164 | - } else { |
|
| 165 | - $this->updateUnitPrice($line_item, $total); |
|
| 166 | - $total = $this->updateTotal($line_item, $total, true); |
|
| 167 | - } |
|
| 168 | - $pretax = $this->updatePreTaxTotal($line_item, $pretax, true); |
|
| 169 | - return [$total, $pretax]; |
|
| 170 | - } |
|
| 171 | - |
|
| 172 | - |
|
| 173 | - /** |
|
| 174 | - * @param EE_Line_Item $line_item |
|
| 175 | - * @param float $total |
|
| 176 | - * @param float $pretax |
|
| 177 | - * @return array |
|
| 178 | - * @throws EE_Error |
|
| 179 | - * @throws ReflectionException |
|
| 180 | - */ |
|
| 181 | - private function recalculateLineItem( |
|
| 182 | - EE_Line_Item $line_item, |
|
| 183 | - float $total = 0, |
|
| 184 | - float $pretax = 0 |
|
| 185 | - ): array { |
|
| 186 | - if ($line_item->is_percent()) { |
|
| 187 | - $total = $this->calculatePercentage($total, $line_item->percent()); |
|
| 188 | - $pretax = $this->calculatePercentage($pretax, $line_item->percent()); |
|
| 189 | - } else { |
|
| 190 | - // recursively loop through children and recalculate their totals |
|
| 191 | - $children = $line_item->children($this->default_query_params); |
|
| 192 | - if (! empty($children)) { |
|
| 193 | - // reset the total and pretax total to zero since we are recalculating them |
|
| 194 | - $pretax = $total = 0; |
|
| 195 | - foreach ($children as $child_line_item) { |
|
| 196 | - [$child_total, $child_pretax] = $this->recalculateLineItemTotals($child_line_item, $total, $total); |
|
| 197 | - $total += $child_total; |
|
| 198 | - $pretax += $child_pretax; |
|
| 199 | - } |
|
| 200 | - } else { |
|
| 201 | - // no child line items, so recalculate the total from the unit price and quantity |
|
| 202 | - // and set the pretax total to match since their are obviously no sub-taxes |
|
| 203 | - $pretax = $total = $this->calculateTotal($line_item); |
|
| 204 | - } |
|
| 205 | - } |
|
| 206 | - $total = $this->updateTotal($line_item, $total, true); |
|
| 207 | - $pretax = $this->updatePreTaxTotal($line_item, $pretax, true); |
|
| 208 | - |
|
| 209 | - if (! $line_item->is_percent()) { |
|
| 210 | - // need to also adjust unit price too if the pretax total or quantity has been updated |
|
| 211 | - $this->updateUnitPrice($line_item, $pretax); |
|
| 212 | - } |
|
| 213 | - return [$total, $pretax]; |
|
| 214 | - } |
|
| 215 | - |
|
| 216 | - |
|
| 217 | - /** |
|
| 218 | - * @param EE_Line_Item $line_item |
|
| 219 | - * @param float|int $total |
|
| 220 | - * @return float |
|
| 221 | - * @throws EE_Error |
|
| 222 | - * @throws ReflectionException |
|
| 223 | - */ |
|
| 224 | - private function recalculateSubLineItem(EE_Line_Item $line_item, float $total = 0): float |
|
| 225 | - { |
|
| 226 | - $total = $line_item->is_percent() |
|
| 227 | - ? $this->calculatePercentage($total, $line_item->percent()) |
|
| 228 | - : $this->calculateTotal($line_item); |
|
| 229 | - return $this->updateTotal($line_item, $total); |
|
| 230 | - } |
|
| 231 | - |
|
| 232 | - |
|
| 233 | - /** |
|
| 234 | - * @param EE_Line_Item $line_item |
|
| 235 | - * @param float|int $total |
|
| 236 | - * @return float |
|
| 237 | - * @throws EE_Error |
|
| 238 | - * @throws ReflectionException |
|
| 239 | - */ |
|
| 240 | - private function recalculateSubTax(EE_Line_Item $line_item, float $total = 0): float |
|
| 241 | - { |
|
| 242 | - $total = $this->calculatePercentage($total, $line_item->percent()); |
|
| 243 | - return $this->updateTotal($line_item, $total); |
|
| 244 | - } |
|
| 245 | - |
|
| 246 | - |
|
| 247 | - /** |
|
| 248 | - * recursively loops through the entire line item tree updating line item quantities accordingly. |
|
| 249 | - * this needs to be done prior to running any other calculations for reasons that are hopefully obvious :p |
|
| 250 | - * |
|
| 251 | - * @param EE_Line_Item $line_item |
|
| 252 | - * @param int $quantity |
|
| 253 | - * @return int |
|
| 254 | - * @throws EE_Error |
|
| 255 | - * @throws ReflectionException |
|
| 256 | - */ |
|
| 257 | - private function updateLineItemQuantities(EE_Line_Item $line_item, int $quantity = 1): int |
|
| 258 | - { |
|
| 259 | - switch ($line_item->type()) { |
|
| 260 | - case EEM_Line_Item::type_total: |
|
| 261 | - case EEM_Line_Item::type_sub_total: |
|
| 262 | - case EEM_Line_Item::type_tax_sub_total: |
|
| 263 | - // first, loop through children and set their quantities |
|
| 264 | - $count = 0; |
|
| 265 | - $children = $line_item->children($this->default_query_params); |
|
| 266 | - foreach ($children as $child_line_item) { |
|
| 267 | - $count += $this->updateLineItemQuantities($child_line_item); |
|
| 268 | - } |
|
| 269 | - // totals and subtotals should have a quantity of 1 |
|
| 270 | - // unless their children have all been removed, in which case we can set them to 0 |
|
| 271 | - $quantity = $count > 0 ? 1 : 0; |
|
| 272 | - $this->updateQuantity($line_item, $quantity); |
|
| 273 | - return $quantity; |
|
| 274 | - |
|
| 275 | - case EEM_Line_Item::type_line_item: |
|
| 276 | - // line items should ALREADY have accurate quantities set, if not, then somebody done goofed! |
|
| 277 | - // but if this is a percentage based line item, then ensure its quantity is 1 |
|
| 278 | - if ($line_item->is_percent()) { |
|
| 279 | - $this->updateQuantity($line_item, 1); |
|
| 280 | - } |
|
| 281 | - // and we also need to loop through all of the sub items and ensure those quantities match this parent. |
|
| 282 | - $children = $line_item->children($this->default_query_params); |
|
| 283 | - $quantity = $line_item->quantity(); |
|
| 284 | - foreach ($children as $child_line_item) { |
|
| 285 | - $this->updateLineItemQuantities($child_line_item, $quantity); |
|
| 286 | - } |
|
| 287 | - // percentage line items should not increment their parent's count, so they return 0 |
|
| 288 | - return ! $line_item->is_percent() ? $quantity : 0; |
|
| 289 | - |
|
| 290 | - case EEM_Line_Item::type_sub_line_item: |
|
| 291 | - // percentage based items need their quantity set to 1, |
|
| 292 | - // all others use the incoming value from the parent line item |
|
| 293 | - $quantity = $line_item->is_percent() ? 1 : $quantity; |
|
| 294 | - $this->updateQuantity($line_item, $quantity); |
|
| 295 | - // percentage line items should not increment their parent's count, so they return 0 |
|
| 296 | - return ! $line_item->is_percent() ? $quantity : 0; |
|
| 297 | - |
|
| 298 | - case EEM_Line_Item::type_tax: |
|
| 299 | - case EEM_Line_Item::type_sub_tax: |
|
| 300 | - // taxes should have a quantity of 1 |
|
| 301 | - $this->updateQuantity($line_item, 1); |
|
| 302 | - return 1; |
|
| 303 | - |
|
| 304 | - case EEM_Line_Item::type_cancellation: |
|
| 305 | - // cancellations will be ignored for all calculations |
|
| 306 | - // because their parent quantities should have already been adjusted when they were added |
|
| 307 | - // so assume that things are already set correctly |
|
| 308 | - return 0; |
|
| 309 | - } |
|
| 310 | - return 0; |
|
| 311 | - } |
|
| 312 | - |
|
| 313 | - |
|
| 314 | - /** |
|
| 315 | - * @param float $total |
|
| 316 | - * @param float $percent |
|
| 317 | - * @param bool $round |
|
| 318 | - * @return float |
|
| 319 | - */ |
|
| 320 | - private function calculatePercentage(float $total, float $percent, bool $round = false): float |
|
| 321 | - { |
|
| 322 | - $amount = $total * $percent / 100; |
|
| 323 | - return $this->decimal_values->roundDecimalValue($amount, $round); |
|
| 324 | - } |
|
| 325 | - |
|
| 326 | - |
|
| 327 | - /** |
|
| 328 | - * @param EE_Line_Item $line_item |
|
| 329 | - * @return float |
|
| 330 | - * @throws EE_Error |
|
| 331 | - * @throws ReflectionException |
|
| 332 | - */ |
|
| 333 | - private function calculateTotal(EE_Line_Item $line_item): float |
|
| 334 | - { |
|
| 335 | - $total = $line_item->unit_price() * $line_item->quantity(); |
|
| 336 | - return $this->decimal_values->roundDecimalValue($total); |
|
| 337 | - } |
|
| 338 | - |
|
| 339 | - |
|
| 340 | - /** |
|
| 341 | - * @param EE_Line_Item $line_item |
|
| 342 | - * @param float $percent |
|
| 343 | - * @throws EE_Error |
|
| 344 | - * @throws ReflectionException |
|
| 345 | - */ |
|
| 346 | - private function updatePercent(EE_Line_Item $line_item, float $percent) |
|
| 347 | - { |
|
| 348 | - // update and save new percent only if incoming value does not match existing value |
|
| 349 | - if ($line_item->percent() !== $percent) { |
|
| 350 | - $line_item->set_percent($percent); |
|
| 351 | - $line_item->maybe_save(); |
|
| 352 | - } |
|
| 353 | - } |
|
| 354 | - |
|
| 355 | - |
|
| 356 | - /** |
|
| 357 | - * @param EE_Line_Item $line_item |
|
| 358 | - * @param int $quantity |
|
| 359 | - * @throws EE_Error |
|
| 360 | - * @throws ReflectionException |
|
| 361 | - */ |
|
| 362 | - private function updateQuantity(EE_Line_Item $line_item, int $quantity) |
|
| 363 | - { |
|
| 364 | - // update and save new quantity only if incoming value does not match existing value |
|
| 365 | - if ($line_item->quantity() !== $quantity) { |
|
| 366 | - $line_item->set_quantity($quantity); |
|
| 367 | - $line_item->maybe_save(); |
|
| 368 | - } |
|
| 369 | - } |
|
| 370 | - |
|
| 371 | - |
|
| 372 | - /** |
|
| 373 | - * @param EE_Line_Item $line_item |
|
| 374 | - * @param float $pretax_total |
|
| 375 | - * @param bool $round |
|
| 376 | - * @return float |
|
| 377 | - * @throws EE_Error |
|
| 378 | - * @throws ReflectionException |
|
| 379 | - */ |
|
| 380 | - private function updatePreTaxTotal(EE_Line_Item $line_item, float $pretax_total, bool $round = false): float |
|
| 381 | - { |
|
| 382 | - $pretax_total = $this->decimal_values->roundDecimalValue($pretax_total, $round); |
|
| 383 | - // update and save new total only if incoming value does not match existing value |
|
| 384 | - if ($line_item->preTaxTotal() !== $pretax_total) { |
|
| 385 | - $line_item->setPreTaxTotal($pretax_total); |
|
| 386 | - $line_item->maybe_save(); |
|
| 387 | - } |
|
| 388 | - return $pretax_total; |
|
| 389 | - } |
|
| 390 | - |
|
| 391 | - |
|
| 392 | - /** |
|
| 393 | - * @param EE_Line_Item $line_item |
|
| 394 | - * @param float $total |
|
| 395 | - * @param bool $round |
|
| 396 | - * @return float |
|
| 397 | - * @throws EE_Error |
|
| 398 | - * @throws ReflectionException |
|
| 399 | - */ |
|
| 400 | - private function updateTotal(EE_Line_Item $line_item, float $total, bool $round = false): float |
|
| 401 | - { |
|
| 402 | - $total = $this->decimal_values->roundDecimalValue($total, $round); |
|
| 403 | - // update and save new total only if incoming value does not match existing value |
|
| 404 | - if ($line_item->total() !== $total) { |
|
| 405 | - $line_item->set_total($total); |
|
| 406 | - $line_item->maybe_save(); |
|
| 407 | - } |
|
| 408 | - return $total; |
|
| 409 | - } |
|
| 410 | - |
|
| 411 | - |
|
| 412 | - /** |
|
| 413 | - * @param EE_Line_Item $line_item |
|
| 414 | - * @param float $total |
|
| 415 | - * @param bool $update_status |
|
| 416 | - * @return void |
|
| 417 | - * @throws EE_Error |
|
| 418 | - * @throws ReflectionException |
|
| 419 | - */ |
|
| 420 | - private function updateTransaction(EE_Line_Item $line_item, float $total, bool $update_status) |
|
| 421 | - { |
|
| 422 | - // only update the related transaction's total |
|
| 423 | - // if we intend to save this line item and its a grand total |
|
| 424 | - if ($line_item->allow_persist()) { |
|
| 425 | - $transaction = $line_item->transaction(); |
|
| 426 | - if ($transaction instanceof EE_Transaction) { |
|
| 427 | - $transaction->set_total($total); |
|
| 428 | - if ($update_status) { |
|
| 429 | - // don't save the TXN because that will be done below |
|
| 430 | - // and the following method only saves if the status changes |
|
| 431 | - $transaction->update_status_based_on_total_paid(false); |
|
| 432 | - } |
|
| 433 | - if ($transaction->ID()) { |
|
| 434 | - $transaction->save(); |
|
| 435 | - } |
|
| 436 | - } |
|
| 437 | - } |
|
| 438 | - } |
|
| 439 | - |
|
| 440 | - |
|
| 441 | - /** |
|
| 442 | - * @param EE_Line_Item $line_item |
|
| 443 | - * @param float $total |
|
| 444 | - * @return void |
|
| 445 | - * @throws EE_Error |
|
| 446 | - * @throws ReflectionException |
|
| 447 | - */ |
|
| 448 | - private function updateUnitPrice(EE_Line_Item $line_item, float $total) |
|
| 449 | - { |
|
| 450 | - $quantity = $line_item->quantity(); |
|
| 451 | - // don't divide by zero else you'll create a singularity and implode the interweb |
|
| 452 | - if ($quantity === 0) { |
|
| 453 | - return; |
|
| 454 | - } |
|
| 455 | - // $new_unit_price = $quantity !== 0 ? $total / $quantity : 0; |
|
| 456 | - $new_unit_price = $total / $quantity; |
|
| 457 | - $new_unit_price = $this->decimal_values->roundDecimalValue($new_unit_price); |
|
| 458 | - // update and save new total only if incoming value does not match existing value |
|
| 459 | - if ($line_item->unit_price() !== $new_unit_price) { |
|
| 460 | - $line_item->set_unit_price($new_unit_price); |
|
| 461 | - $line_item->maybe_save(); |
|
| 462 | - } |
|
| 463 | - } |
|
| 464 | - |
|
| 465 | - |
|
| 466 | - /** |
|
| 467 | - * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets |
|
| 468 | - * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items |
|
| 469 | - * and tax sub-total if already in the DB |
|
| 470 | - * |
|
| 471 | - * @param EE_Line_Item $total_line_item |
|
| 472 | - * @return float |
|
| 473 | - * @throws EE_Error |
|
| 474 | - * @throws ReflectionException |
|
| 475 | - */ |
|
| 476 | - public function recalculateTaxesAndTaxTotal(EE_Line_Item $total_line_item): float |
|
| 477 | - { |
|
| 478 | - $this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total); |
|
| 479 | - // calculate the total taxable amount for globally applied taxes |
|
| 480 | - $taxable_total = $this->taxableAmountForGlobalTaxes($total_line_item); |
|
| 481 | - $global_taxes = $this->applyGlobalTaxes($total_line_item, $taxable_total); |
|
| 482 | - $non_global_taxes = $this->calculateNonGlobalTaxes($total_line_item); |
|
| 483 | - $all_tax_total = $this->applyNonGlobalTaxes($total_line_item, $global_taxes, $non_global_taxes); |
|
| 484 | - $this->recalculateTaxSubTotal($total_line_item); |
|
| 485 | - return $all_tax_total; |
|
| 486 | - } |
|
| 487 | - |
|
| 488 | - |
|
| 489 | - /** |
|
| 490 | - * @param EE_Line_Item $total_line_item |
|
| 491 | - * @param float $taxable_total |
|
| 492 | - * @return float |
|
| 493 | - * @throws EE_Error |
|
| 494 | - * @throws ReflectionException |
|
| 495 | - */ |
|
| 496 | - private function applyGlobalTaxes(EE_Line_Item $total_line_item, float $taxable_total): float |
|
| 497 | - { |
|
| 498 | - $this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total); |
|
| 499 | - $total_tax = 0; |
|
| 500 | - // loop through all global taxes all taxes |
|
| 501 | - $global_taxes = $total_line_item->tax_descendants(); |
|
| 502 | - foreach ($global_taxes as $tax) { |
|
| 503 | - $tax_total = $this->calculatePercentage($taxable_total, $tax->percent()); |
|
| 504 | - $tax_total = $this->updateTotal($tax, $tax_total, true); |
|
| 505 | - $total_tax += $tax_total; |
|
| 506 | - } |
|
| 507 | - return $this->decimal_values->roundDecimalValue($total_tax, true); |
|
| 508 | - } |
|
| 509 | - |
|
| 510 | - |
|
| 511 | - /** |
|
| 512 | - * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated |
|
| 513 | - * |
|
| 514 | - * @param EE_Line_Item $line_item |
|
| 515 | - * @return void |
|
| 516 | - * @throws EE_Error |
|
| 517 | - * @throws ReflectionException |
|
| 518 | - */ |
|
| 519 | - private function recalculateTaxSubTotal(EE_Line_Item $line_item) |
|
| 520 | - { |
|
| 521 | - $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total); |
|
| 522 | - foreach ($line_item->children() as $maybe_tax_subtotal) { |
|
| 523 | - if ( |
|
| 524 | - $this->validateLineItemAndType($maybe_tax_subtotal) |
|
| 525 | - && $maybe_tax_subtotal->is_tax_sub_total() |
|
| 526 | - ) { |
|
| 527 | - $total = 0; |
|
| 528 | - $total_percent = 0; |
|
| 529 | - // simply loop through all its children (which should be taxes) and sum their total |
|
| 530 | - foreach ($maybe_tax_subtotal->children() as $child_tax) { |
|
| 531 | - if ($this->validateLineItemAndType($child_tax) && $child_tax->isGlobalTax()) { |
|
| 532 | - $total += $child_tax->total(); |
|
| 533 | - $total_percent += $child_tax->percent(); |
|
| 534 | - } |
|
| 535 | - } |
|
| 536 | - $this->updateTotal($maybe_tax_subtotal, $total, true); |
|
| 537 | - $this->updatePercent($maybe_tax_subtotal, $total_percent); |
|
| 538 | - } |
|
| 539 | - } |
|
| 540 | - } |
|
| 541 | - |
|
| 542 | - |
|
| 543 | - /** |
|
| 544 | - * returns an array of tax details like: |
|
| 545 | - * [ |
|
| 546 | - * 'GST_7' => [ |
|
| 547 | - * 'name' => 'GST', |
|
| 548 | - * 'rate' => float(7), |
|
| 549 | - * 'total' => float(4.9), |
|
| 550 | - * ] |
|
| 551 | - * ] |
|
| 552 | - * |
|
| 553 | - * @param EE_Line_Item $total_line_item |
|
| 554 | - * @param array $non_global_taxes |
|
| 555 | - * @param float $line_item_total |
|
| 556 | - * @return array |
|
| 557 | - * @throws EE_Error |
|
| 558 | - * @throws ReflectionException |
|
| 559 | - */ |
|
| 560 | - private function calculateNonGlobalTaxes( |
|
| 561 | - EE_Line_Item $total_line_item, |
|
| 562 | - array $non_global_taxes = [], |
|
| 563 | - float $line_item_total = 0 |
|
| 564 | - ): array { |
|
| 565 | - foreach ($total_line_item->children() as $line_item) { |
|
| 566 | - if ($this->validateLineItemAndType($line_item)) { |
|
| 567 | - if ($line_item->is_sub_total()) { |
|
| 568 | - $non_global_taxes = $this->calculateNonGlobalTaxes($line_item, $non_global_taxes); |
|
| 569 | - } elseif ($line_item->is_line_item()) { |
|
| 570 | - $non_global_taxes = $this->calculateNonGlobalTaxes( |
|
| 571 | - $line_item, |
|
| 572 | - $non_global_taxes, |
|
| 573 | - $line_item->pretaxTotal() |
|
| 574 | - ); |
|
| 575 | - } elseif ($line_item->isSubTax()) { |
|
| 576 | - $tax_ID = $line_item->name() . '_' . $line_item->percent(); |
|
| 577 | - if (! isset($non_global_taxes[ $tax_ID ])) { |
|
| 578 | - $non_global_taxes[ $tax_ID ] = [ |
|
| 579 | - 'name' => $line_item->name(), |
|
| 580 | - 'rate' => $line_item->percent(), |
|
| 581 | - 'total' => 0, |
|
| 582 | - 'obj' => $line_item->OBJ_type(), |
|
| 583 | - 'objID' => $line_item->OBJ_ID(), |
|
| 584 | - ]; |
|
| 585 | - } |
|
| 586 | - $tax = $this->calculatePercentage($line_item_total, $line_item->percent()); |
|
| 587 | - $non_global_taxes[ $tax_ID ]['total'] += $tax; |
|
| 588 | - } |
|
| 589 | - } |
|
| 590 | - } |
|
| 591 | - return $non_global_taxes; |
|
| 592 | - } |
|
| 593 | - |
|
| 594 | - |
|
| 595 | - /** |
|
| 596 | - * @param EE_Line_Item $total_line_item |
|
| 597 | - * @param float $tax_total |
|
| 598 | - * @param array $non_global_taxes array of tax details generated by calculateNonGlobalTaxes() |
|
| 599 | - * @return float |
|
| 600 | - * @throws EE_Error |
|
| 601 | - * @throws ReflectionException |
|
| 602 | - */ |
|
| 603 | - private function applyNonGlobalTaxes( |
|
| 604 | - EE_Line_Item $total_line_item, |
|
| 605 | - float $tax_total, |
|
| 606 | - array $non_global_taxes |
|
| 607 | - ): float { |
|
| 608 | - $global_taxes = $total_line_item->tax_descendants(); |
|
| 609 | - $taxes_subtotal = EEH_Line_Item::get_taxes_subtotal($total_line_item); |
|
| 610 | - foreach ($non_global_taxes as $non_global_tax) { |
|
| 611 | - $found = false; |
|
| 612 | - foreach ($global_taxes as $global_tax) { |
|
| 613 | - if ( |
|
| 614 | - $this->validateLineItemAndType($global_tax) |
|
| 615 | - && $non_global_tax['obj'] === $global_tax->OBJ_type() |
|
| 616 | - && $non_global_tax['objID'] === $global_tax->OBJ_ID() |
|
| 617 | - ) { |
|
| 618 | - $found = true; |
|
| 619 | - $new_total = $global_tax->total() + $non_global_tax['total']; |
|
| 620 | - // add non global tax to matching global tax AND the tax total |
|
| 621 | - $global_tax->set_total($new_total); |
|
| 622 | - $global_tax->maybe_save(); |
|
| 623 | - $tax_total += $non_global_tax['total']; |
|
| 624 | - } |
|
| 625 | - } |
|
| 626 | - if (! $found) { |
|
| 627 | - // add a new line item for this non global tax |
|
| 628 | - $taxes_subtotal->add_child_line_item( |
|
| 629 | - EE_Line_Item::new_instance( |
|
| 630 | - [ |
|
| 631 | - 'LIN_name' => $non_global_tax['name'], |
|
| 632 | - 'LIN_percent' => $non_global_tax['rate'], |
|
| 633 | - 'LIN_is_taxable' => false, |
|
| 634 | - 'LIN_total' => $non_global_tax['total'], |
|
| 635 | - 'LIN_type' => EEM_Line_Item::type_tax, |
|
| 636 | - 'OBJ_type' => $non_global_tax['obj'], |
|
| 637 | - 'OBJ_ID' => $non_global_tax['objID'], |
|
| 638 | - ] |
|
| 639 | - ) |
|
| 640 | - ); |
|
| 641 | - $tax_total += $non_global_tax['total']; |
|
| 642 | - } |
|
| 643 | - } |
|
| 644 | - return $this->decimal_values->roundDecimalValue($tax_total, true); |
|
| 645 | - } |
|
| 646 | - |
|
| 647 | - |
|
| 648 | - /** |
|
| 649 | - * Gets the total tax on this line item. Assumes taxes have already been calculated using |
|
| 650 | - * recalculate_taxes_and_total |
|
| 651 | - * |
|
| 652 | - * @param EE_Line_Item $line_item |
|
| 653 | - * @return float |
|
| 654 | - * @throws EE_Error |
|
| 655 | - * @throws ReflectionException |
|
| 656 | - */ |
|
| 657 | - public function getTotalTax(EE_Line_Item $line_item): float |
|
| 658 | - { |
|
| 659 | - $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total); |
|
| 660 | - $this->recalculateTaxSubTotal($line_item); |
|
| 661 | - $total = 0; |
|
| 662 | - foreach ($line_item->tax_descendants() as $tax_line_item) { |
|
| 663 | - if ($this->validateLineItemAndType($tax_line_item)) { |
|
| 664 | - $total += $tax_line_item->total(); |
|
| 665 | - } |
|
| 666 | - } |
|
| 667 | - return $this->decimal_values->roundDecimalValue($total, true); |
|
| 668 | - } |
|
| 669 | - |
|
| 670 | - |
|
| 671 | - /** |
|
| 672 | - * Returns the amount taxable among this line item's children (or if it has no children, |
|
| 673 | - * how much of it is taxable). Does not recalculate totals or subtotals. |
|
| 674 | - * If the taxable total is negative, (eg, if none of the tickets were taxable, |
|
| 675 | - * but there is a "Taxable" discount), returns 0. |
|
| 676 | - * |
|
| 677 | - * @param EE_Line_Item|null $line_item |
|
| 678 | - * @return float |
|
| 679 | - * @throws EE_Error |
|
| 680 | - * @throws ReflectionException |
|
| 681 | - */ |
|
| 682 | - public function taxableAmountForGlobalTaxes(?EE_Line_Item $line_item): float |
|
| 683 | - { |
|
| 684 | - $total = 0; |
|
| 685 | - $child_line_items = $line_item->children($this->default_query_params); |
|
| 686 | - foreach ($child_line_items as $child_line_item) { |
|
| 687 | - $this->validateLineItemAndType($child_line_item); |
|
| 688 | - if ($child_line_item->is_sub_total()) { |
|
| 689 | - $total += $this->taxableAmountForGlobalTaxes($child_line_item); |
|
| 690 | - } elseif ($child_line_item->is_line_item() && $child_line_item->is_taxable()) { |
|
| 691 | - // if it's a percent item, only take into account |
|
| 692 | - // the percentage that's taxable (the taxable total so far) |
|
| 693 | - if ($child_line_item->is_percent()) { |
|
| 694 | - $total += $this->calculatePercentage($total, $child_line_item->percent(), true); |
|
| 695 | - } else { |
|
| 696 | - // pretax total will be equal to the total for line items with globally applied taxes |
|
| 697 | - $pretax_total = $this->calculateTotal($child_line_item); |
|
| 698 | - $total += $this->updatePreTaxTotal($child_line_item, $pretax_total); |
|
| 699 | - } |
|
| 700 | - } |
|
| 701 | - } |
|
| 702 | - return max($total, 0); |
|
| 703 | - } |
|
| 704 | - |
|
| 705 | - |
|
| 706 | - /** |
|
| 707 | - * @param EE_Line_Item|null $line_item |
|
| 708 | - * @param string|null $type |
|
| 709 | - * @return bool |
|
| 710 | - * @throws EE_Error |
|
| 711 | - * @throws ReflectionException |
|
| 712 | - */ |
|
| 713 | - private function validateLineItemAndType(?EE_Line_Item $line_item, ?string $type = null): bool |
|
| 714 | - { |
|
| 715 | - if (! $line_item instanceof EE_Line_Item) { |
|
| 716 | - throw new DomainException( |
|
| 717 | - esc_html__('Invalid or missing Line Item supplied .', 'event_espresso') |
|
| 718 | - ); |
|
| 719 | - } |
|
| 720 | - if ($type && $line_item->type() !== $type) { |
|
| 721 | - throw new DomainException( |
|
| 722 | - sprintf( |
|
| 723 | - esc_html__( |
|
| 724 | - 'Invalid Line Item type supplied. Received "%1$s" but expected "%2$s".', |
|
| 725 | - 'event_espresso' |
|
| 726 | - ), |
|
| 727 | - $line_item->type(), |
|
| 728 | - $type |
|
| 729 | - ) |
|
| 730 | - ); |
|
| 731 | - } |
|
| 732 | - return true; |
|
| 733 | - } |
|
| 24 | + /** |
|
| 25 | + * @var DecimalValues |
|
| 26 | + */ |
|
| 27 | + protected $decimal_values; |
|
| 28 | + |
|
| 29 | + /** |
|
| 30 | + * @var array |
|
| 31 | + */ |
|
| 32 | + protected $default_query_params = [ |
|
| 33 | + ['LIN_type' => ['!=', EEM_Line_Item::type_cancellation]] |
|
| 34 | + ]; |
|
| 35 | + |
|
| 36 | + |
|
| 37 | + /** |
|
| 38 | + * @param DecimalValues $decimal_values |
|
| 39 | + */ |
|
| 40 | + public function __construct(DecimalValues $decimal_values) |
|
| 41 | + { |
|
| 42 | + $this->decimal_values = $decimal_values; |
|
| 43 | + } |
|
| 44 | + |
|
| 45 | + |
|
| 46 | + /** |
|
| 47 | + * Gets the final total on this item, taking taxes into account. |
|
| 48 | + * Has the side-effect of setting the sub-total as it was just calculated. |
|
| 49 | + * If this is used on a grand-total line item, also updates the transaction's |
|
| 50 | + * TXN_total (provided this line item is allowed to persist, otherwise we don't |
|
| 51 | + * want to change a persistable transaction with info from a non-persistent line item) |
|
| 52 | + * |
|
| 53 | + * @param EE_Line_Item $line_item |
|
| 54 | + * @param bool $update_txn_status |
|
| 55 | + * @return float |
|
| 56 | + * @throws EE_Error |
|
| 57 | + * @throws ReflectionException |
|
| 58 | + */ |
|
| 59 | + public function recalculateTotalIncludingTaxes(EE_Line_Item $line_item, bool $update_txn_status = false): float |
|
| 60 | + { |
|
| 61 | + $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total); |
|
| 62 | + $ticket_line_items = EEH_Line_Item::get_ticket_line_items($line_item); |
|
| 63 | + if (empty($ticket_line_items)) { |
|
| 64 | + return 0; |
|
| 65 | + } |
|
| 66 | + [, $pretax] = $this->recalculateLineItemTotals($line_item); |
|
| 67 | + $total_tax = $this->recalculateTaxesAndTaxTotal($line_item); |
|
| 68 | + // no negative totals plz |
|
| 69 | + $grand_total = max($pretax + $total_tax, 0); |
|
| 70 | + $this->updatePreTaxTotal($line_item, $pretax, true); |
|
| 71 | + $grand_total = $this->updateTotal($line_item, $grand_total, true); |
|
| 72 | + $this->updateTransaction($line_item, $grand_total, $update_txn_status); |
|
| 73 | + return $grand_total; |
|
| 74 | + } |
|
| 75 | + |
|
| 76 | + |
|
| 77 | + /** |
|
| 78 | + * Recursively goes through all the children and recalculates sub-totals EXCEPT for |
|
| 79 | + * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its |
|
| 80 | + * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and |
|
| 81 | + * when this is called on the grand total |
|
| 82 | + * |
|
| 83 | + * @param EE_Line_Item $line_item |
|
| 84 | + * @param float $total |
|
| 85 | + * @param float $pretax |
|
| 86 | + * @return array |
|
| 87 | + * @throws EE_Error |
|
| 88 | + * @throws ReflectionException |
|
| 89 | + */ |
|
| 90 | + public function recalculateLineItemTotals( |
|
| 91 | + EE_Line_Item $line_item, |
|
| 92 | + float $total = 0, |
|
| 93 | + float $pretax = 0 |
|
| 94 | + ): array { |
|
| 95 | + $new_total = $new_pretax = 0; |
|
| 96 | + switch ($line_item->type()) { |
|
| 97 | + case EEM_Line_Item::type_total: |
|
| 98 | + case EEM_Line_Item::type_sub_total: |
|
| 99 | + [$new_total, $new_pretax] = $this->recalculateSubTotal($line_item, $total, $pretax); |
|
| 100 | + break; |
|
| 101 | + |
|
| 102 | + case EEM_Line_Item::type_line_item: |
|
| 103 | + [$new_total, $new_pretax] = $this->recalculateLineItem($line_item, $total, $pretax); |
|
| 104 | + break; |
|
| 105 | + |
|
| 106 | + case EEM_Line_Item::type_sub_line_item: |
|
| 107 | + // sub line items operate on the total and update both the total AND the pre-tax total |
|
| 108 | + $new_total = $new_pretax = $this->recalculateSubLineItem($line_item, $total); |
|
| 109 | + break; |
|
| 110 | + |
|
| 111 | + case EEM_Line_Item::type_sub_tax: |
|
| 112 | + // sub line item taxes ONLY operate on the pre-tax total and ONLY update the total |
|
| 113 | + $new_total = $this->recalculateSubTax($line_item, $pretax); |
|
| 114 | + break; |
|
| 115 | + |
|
| 116 | + case EEM_Line_Item::type_tax_sub_total: |
|
| 117 | + case EEM_Line_Item::type_tax: |
|
| 118 | + case EEM_Line_Item::type_cancellation: |
|
| 119 | + // completely ignore tax totals, tax sub-totals, and cancelled line items |
|
| 120 | + // when calculating the pre-tax-total |
|
| 121 | + break; |
|
| 122 | + } |
|
| 123 | + return [$new_total, $new_pretax]; |
|
| 124 | + } |
|
| 125 | + |
|
| 126 | + |
|
| 127 | + /** |
|
| 128 | + * @param EE_Line_Item $line_item |
|
| 129 | + * @param float $total |
|
| 130 | + * @param float $pretax |
|
| 131 | + * @return array |
|
| 132 | + * @throws EE_Error |
|
| 133 | + * @throws ReflectionException |
|
| 134 | + */ |
|
| 135 | + private function recalculateSubTotal( |
|
| 136 | + EE_Line_Item $line_item, |
|
| 137 | + float $total = 0, |
|
| 138 | + float $pretax = 0 |
|
| 139 | + ): array { |
|
| 140 | + if ($line_item->is_total()) { |
|
| 141 | + // if this is the grand total line item |
|
| 142 | + // then first update ALL of the line item quantities (if need be) |
|
| 143 | + $this->updateLineItemQuantities($line_item); |
|
| 144 | + } |
|
| 145 | + // recursively loop through children and recalculate their totals |
|
| 146 | + $children = $line_item->children($this->default_query_params); |
|
| 147 | + if (empty($children)) { |
|
| 148 | + return [$total, $pretax]; |
|
| 149 | + } |
|
| 150 | + // reset the total and pretax total to zero since we are recalculating them |
|
| 151 | + $pretax = $total = 0; |
|
| 152 | + foreach ($children as $child_line_item) { |
|
| 153 | + [$child_total, $child_pretax] = $this->recalculateLineItemTotals($child_line_item, $total, $pretax); |
|
| 154 | + $total += $child_total; |
|
| 155 | + $pretax += $child_pretax; |
|
| 156 | + } |
|
| 157 | + // for the actual pre-tax sub total line item, we want to save the pretax value for everything |
|
| 158 | + if ($line_item->is_sub_total() && $line_item->name() === esc_html__('Pre-Tax Subtotal', 'event_espresso')) { |
|
| 159 | + $this->updateUnitPrice($line_item, $pretax); |
|
| 160 | + $this->updateTotal($line_item, $pretax, true); |
|
| 161 | + } elseif ($line_item->is_total()) { |
|
| 162 | + // only update the unit price for the total line item, because that will need to include taxes |
|
| 163 | + $this->updateUnitPrice($line_item, $total); |
|
| 164 | + } else { |
|
| 165 | + $this->updateUnitPrice($line_item, $total); |
|
| 166 | + $total = $this->updateTotal($line_item, $total, true); |
|
| 167 | + } |
|
| 168 | + $pretax = $this->updatePreTaxTotal($line_item, $pretax, true); |
|
| 169 | + return [$total, $pretax]; |
|
| 170 | + } |
|
| 171 | + |
|
| 172 | + |
|
| 173 | + /** |
|
| 174 | + * @param EE_Line_Item $line_item |
|
| 175 | + * @param float $total |
|
| 176 | + * @param float $pretax |
|
| 177 | + * @return array |
|
| 178 | + * @throws EE_Error |
|
| 179 | + * @throws ReflectionException |
|
| 180 | + */ |
|
| 181 | + private function recalculateLineItem( |
|
| 182 | + EE_Line_Item $line_item, |
|
| 183 | + float $total = 0, |
|
| 184 | + float $pretax = 0 |
|
| 185 | + ): array { |
|
| 186 | + if ($line_item->is_percent()) { |
|
| 187 | + $total = $this->calculatePercentage($total, $line_item->percent()); |
|
| 188 | + $pretax = $this->calculatePercentage($pretax, $line_item->percent()); |
|
| 189 | + } else { |
|
| 190 | + // recursively loop through children and recalculate their totals |
|
| 191 | + $children = $line_item->children($this->default_query_params); |
|
| 192 | + if (! empty($children)) { |
|
| 193 | + // reset the total and pretax total to zero since we are recalculating them |
|
| 194 | + $pretax = $total = 0; |
|
| 195 | + foreach ($children as $child_line_item) { |
|
| 196 | + [$child_total, $child_pretax] = $this->recalculateLineItemTotals($child_line_item, $total, $total); |
|
| 197 | + $total += $child_total; |
|
| 198 | + $pretax += $child_pretax; |
|
| 199 | + } |
|
| 200 | + } else { |
|
| 201 | + // no child line items, so recalculate the total from the unit price and quantity |
|
| 202 | + // and set the pretax total to match since their are obviously no sub-taxes |
|
| 203 | + $pretax = $total = $this->calculateTotal($line_item); |
|
| 204 | + } |
|
| 205 | + } |
|
| 206 | + $total = $this->updateTotal($line_item, $total, true); |
|
| 207 | + $pretax = $this->updatePreTaxTotal($line_item, $pretax, true); |
|
| 208 | + |
|
| 209 | + if (! $line_item->is_percent()) { |
|
| 210 | + // need to also adjust unit price too if the pretax total or quantity has been updated |
|
| 211 | + $this->updateUnitPrice($line_item, $pretax); |
|
| 212 | + } |
|
| 213 | + return [$total, $pretax]; |
|
| 214 | + } |
|
| 215 | + |
|
| 216 | + |
|
| 217 | + /** |
|
| 218 | + * @param EE_Line_Item $line_item |
|
| 219 | + * @param float|int $total |
|
| 220 | + * @return float |
|
| 221 | + * @throws EE_Error |
|
| 222 | + * @throws ReflectionException |
|
| 223 | + */ |
|
| 224 | + private function recalculateSubLineItem(EE_Line_Item $line_item, float $total = 0): float |
|
| 225 | + { |
|
| 226 | + $total = $line_item->is_percent() |
|
| 227 | + ? $this->calculatePercentage($total, $line_item->percent()) |
|
| 228 | + : $this->calculateTotal($line_item); |
|
| 229 | + return $this->updateTotal($line_item, $total); |
|
| 230 | + } |
|
| 231 | + |
|
| 232 | + |
|
| 233 | + /** |
|
| 234 | + * @param EE_Line_Item $line_item |
|
| 235 | + * @param float|int $total |
|
| 236 | + * @return float |
|
| 237 | + * @throws EE_Error |
|
| 238 | + * @throws ReflectionException |
|
| 239 | + */ |
|
| 240 | + private function recalculateSubTax(EE_Line_Item $line_item, float $total = 0): float |
|
| 241 | + { |
|
| 242 | + $total = $this->calculatePercentage($total, $line_item->percent()); |
|
| 243 | + return $this->updateTotal($line_item, $total); |
|
| 244 | + } |
|
| 245 | + |
|
| 246 | + |
|
| 247 | + /** |
|
| 248 | + * recursively loops through the entire line item tree updating line item quantities accordingly. |
|
| 249 | + * this needs to be done prior to running any other calculations for reasons that are hopefully obvious :p |
|
| 250 | + * |
|
| 251 | + * @param EE_Line_Item $line_item |
|
| 252 | + * @param int $quantity |
|
| 253 | + * @return int |
|
| 254 | + * @throws EE_Error |
|
| 255 | + * @throws ReflectionException |
|
| 256 | + */ |
|
| 257 | + private function updateLineItemQuantities(EE_Line_Item $line_item, int $quantity = 1): int |
|
| 258 | + { |
|
| 259 | + switch ($line_item->type()) { |
|
| 260 | + case EEM_Line_Item::type_total: |
|
| 261 | + case EEM_Line_Item::type_sub_total: |
|
| 262 | + case EEM_Line_Item::type_tax_sub_total: |
|
| 263 | + // first, loop through children and set their quantities |
|
| 264 | + $count = 0; |
|
| 265 | + $children = $line_item->children($this->default_query_params); |
|
| 266 | + foreach ($children as $child_line_item) { |
|
| 267 | + $count += $this->updateLineItemQuantities($child_line_item); |
|
| 268 | + } |
|
| 269 | + // totals and subtotals should have a quantity of 1 |
|
| 270 | + // unless their children have all been removed, in which case we can set them to 0 |
|
| 271 | + $quantity = $count > 0 ? 1 : 0; |
|
| 272 | + $this->updateQuantity($line_item, $quantity); |
|
| 273 | + return $quantity; |
|
| 274 | + |
|
| 275 | + case EEM_Line_Item::type_line_item: |
|
| 276 | + // line items should ALREADY have accurate quantities set, if not, then somebody done goofed! |
|
| 277 | + // but if this is a percentage based line item, then ensure its quantity is 1 |
|
| 278 | + if ($line_item->is_percent()) { |
|
| 279 | + $this->updateQuantity($line_item, 1); |
|
| 280 | + } |
|
| 281 | + // and we also need to loop through all of the sub items and ensure those quantities match this parent. |
|
| 282 | + $children = $line_item->children($this->default_query_params); |
|
| 283 | + $quantity = $line_item->quantity(); |
|
| 284 | + foreach ($children as $child_line_item) { |
|
| 285 | + $this->updateLineItemQuantities($child_line_item, $quantity); |
|
| 286 | + } |
|
| 287 | + // percentage line items should not increment their parent's count, so they return 0 |
|
| 288 | + return ! $line_item->is_percent() ? $quantity : 0; |
|
| 289 | + |
|
| 290 | + case EEM_Line_Item::type_sub_line_item: |
|
| 291 | + // percentage based items need their quantity set to 1, |
|
| 292 | + // all others use the incoming value from the parent line item |
|
| 293 | + $quantity = $line_item->is_percent() ? 1 : $quantity; |
|
| 294 | + $this->updateQuantity($line_item, $quantity); |
|
| 295 | + // percentage line items should not increment their parent's count, so they return 0 |
|
| 296 | + return ! $line_item->is_percent() ? $quantity : 0; |
|
| 297 | + |
|
| 298 | + case EEM_Line_Item::type_tax: |
|
| 299 | + case EEM_Line_Item::type_sub_tax: |
|
| 300 | + // taxes should have a quantity of 1 |
|
| 301 | + $this->updateQuantity($line_item, 1); |
|
| 302 | + return 1; |
|
| 303 | + |
|
| 304 | + case EEM_Line_Item::type_cancellation: |
|
| 305 | + // cancellations will be ignored for all calculations |
|
| 306 | + // because their parent quantities should have already been adjusted when they were added |
|
| 307 | + // so assume that things are already set correctly |
|
| 308 | + return 0; |
|
| 309 | + } |
|
| 310 | + return 0; |
|
| 311 | + } |
|
| 312 | + |
|
| 313 | + |
|
| 314 | + /** |
|
| 315 | + * @param float $total |
|
| 316 | + * @param float $percent |
|
| 317 | + * @param bool $round |
|
| 318 | + * @return float |
|
| 319 | + */ |
|
| 320 | + private function calculatePercentage(float $total, float $percent, bool $round = false): float |
|
| 321 | + { |
|
| 322 | + $amount = $total * $percent / 100; |
|
| 323 | + return $this->decimal_values->roundDecimalValue($amount, $round); |
|
| 324 | + } |
|
| 325 | + |
|
| 326 | + |
|
| 327 | + /** |
|
| 328 | + * @param EE_Line_Item $line_item |
|
| 329 | + * @return float |
|
| 330 | + * @throws EE_Error |
|
| 331 | + * @throws ReflectionException |
|
| 332 | + */ |
|
| 333 | + private function calculateTotal(EE_Line_Item $line_item): float |
|
| 334 | + { |
|
| 335 | + $total = $line_item->unit_price() * $line_item->quantity(); |
|
| 336 | + return $this->decimal_values->roundDecimalValue($total); |
|
| 337 | + } |
|
| 338 | + |
|
| 339 | + |
|
| 340 | + /** |
|
| 341 | + * @param EE_Line_Item $line_item |
|
| 342 | + * @param float $percent |
|
| 343 | + * @throws EE_Error |
|
| 344 | + * @throws ReflectionException |
|
| 345 | + */ |
|
| 346 | + private function updatePercent(EE_Line_Item $line_item, float $percent) |
|
| 347 | + { |
|
| 348 | + // update and save new percent only if incoming value does not match existing value |
|
| 349 | + if ($line_item->percent() !== $percent) { |
|
| 350 | + $line_item->set_percent($percent); |
|
| 351 | + $line_item->maybe_save(); |
|
| 352 | + } |
|
| 353 | + } |
|
| 354 | + |
|
| 355 | + |
|
| 356 | + /** |
|
| 357 | + * @param EE_Line_Item $line_item |
|
| 358 | + * @param int $quantity |
|
| 359 | + * @throws EE_Error |
|
| 360 | + * @throws ReflectionException |
|
| 361 | + */ |
|
| 362 | + private function updateQuantity(EE_Line_Item $line_item, int $quantity) |
|
| 363 | + { |
|
| 364 | + // update and save new quantity only if incoming value does not match existing value |
|
| 365 | + if ($line_item->quantity() !== $quantity) { |
|
| 366 | + $line_item->set_quantity($quantity); |
|
| 367 | + $line_item->maybe_save(); |
|
| 368 | + } |
|
| 369 | + } |
|
| 370 | + |
|
| 371 | + |
|
| 372 | + /** |
|
| 373 | + * @param EE_Line_Item $line_item |
|
| 374 | + * @param float $pretax_total |
|
| 375 | + * @param bool $round |
|
| 376 | + * @return float |
|
| 377 | + * @throws EE_Error |
|
| 378 | + * @throws ReflectionException |
|
| 379 | + */ |
|
| 380 | + private function updatePreTaxTotal(EE_Line_Item $line_item, float $pretax_total, bool $round = false): float |
|
| 381 | + { |
|
| 382 | + $pretax_total = $this->decimal_values->roundDecimalValue($pretax_total, $round); |
|
| 383 | + // update and save new total only if incoming value does not match existing value |
|
| 384 | + if ($line_item->preTaxTotal() !== $pretax_total) { |
|
| 385 | + $line_item->setPreTaxTotal($pretax_total); |
|
| 386 | + $line_item->maybe_save(); |
|
| 387 | + } |
|
| 388 | + return $pretax_total; |
|
| 389 | + } |
|
| 390 | + |
|
| 391 | + |
|
| 392 | + /** |
|
| 393 | + * @param EE_Line_Item $line_item |
|
| 394 | + * @param float $total |
|
| 395 | + * @param bool $round |
|
| 396 | + * @return float |
|
| 397 | + * @throws EE_Error |
|
| 398 | + * @throws ReflectionException |
|
| 399 | + */ |
|
| 400 | + private function updateTotal(EE_Line_Item $line_item, float $total, bool $round = false): float |
|
| 401 | + { |
|
| 402 | + $total = $this->decimal_values->roundDecimalValue($total, $round); |
|
| 403 | + // update and save new total only if incoming value does not match existing value |
|
| 404 | + if ($line_item->total() !== $total) { |
|
| 405 | + $line_item->set_total($total); |
|
| 406 | + $line_item->maybe_save(); |
|
| 407 | + } |
|
| 408 | + return $total; |
|
| 409 | + } |
|
| 410 | + |
|
| 411 | + |
|
| 412 | + /** |
|
| 413 | + * @param EE_Line_Item $line_item |
|
| 414 | + * @param float $total |
|
| 415 | + * @param bool $update_status |
|
| 416 | + * @return void |
|
| 417 | + * @throws EE_Error |
|
| 418 | + * @throws ReflectionException |
|
| 419 | + */ |
|
| 420 | + private function updateTransaction(EE_Line_Item $line_item, float $total, bool $update_status) |
|
| 421 | + { |
|
| 422 | + // only update the related transaction's total |
|
| 423 | + // if we intend to save this line item and its a grand total |
|
| 424 | + if ($line_item->allow_persist()) { |
|
| 425 | + $transaction = $line_item->transaction(); |
|
| 426 | + if ($transaction instanceof EE_Transaction) { |
|
| 427 | + $transaction->set_total($total); |
|
| 428 | + if ($update_status) { |
|
| 429 | + // don't save the TXN because that will be done below |
|
| 430 | + // and the following method only saves if the status changes |
|
| 431 | + $transaction->update_status_based_on_total_paid(false); |
|
| 432 | + } |
|
| 433 | + if ($transaction->ID()) { |
|
| 434 | + $transaction->save(); |
|
| 435 | + } |
|
| 436 | + } |
|
| 437 | + } |
|
| 438 | + } |
|
| 439 | + |
|
| 440 | + |
|
| 441 | + /** |
|
| 442 | + * @param EE_Line_Item $line_item |
|
| 443 | + * @param float $total |
|
| 444 | + * @return void |
|
| 445 | + * @throws EE_Error |
|
| 446 | + * @throws ReflectionException |
|
| 447 | + */ |
|
| 448 | + private function updateUnitPrice(EE_Line_Item $line_item, float $total) |
|
| 449 | + { |
|
| 450 | + $quantity = $line_item->quantity(); |
|
| 451 | + // don't divide by zero else you'll create a singularity and implode the interweb |
|
| 452 | + if ($quantity === 0) { |
|
| 453 | + return; |
|
| 454 | + } |
|
| 455 | + // $new_unit_price = $quantity !== 0 ? $total / $quantity : 0; |
|
| 456 | + $new_unit_price = $total / $quantity; |
|
| 457 | + $new_unit_price = $this->decimal_values->roundDecimalValue($new_unit_price); |
|
| 458 | + // update and save new total only if incoming value does not match existing value |
|
| 459 | + if ($line_item->unit_price() !== $new_unit_price) { |
|
| 460 | + $line_item->set_unit_price($new_unit_price); |
|
| 461 | + $line_item->maybe_save(); |
|
| 462 | + } |
|
| 463 | + } |
|
| 464 | + |
|
| 465 | + |
|
| 466 | + /** |
|
| 467 | + * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets |
|
| 468 | + * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items |
|
| 469 | + * and tax sub-total if already in the DB |
|
| 470 | + * |
|
| 471 | + * @param EE_Line_Item $total_line_item |
|
| 472 | + * @return float |
|
| 473 | + * @throws EE_Error |
|
| 474 | + * @throws ReflectionException |
|
| 475 | + */ |
|
| 476 | + public function recalculateTaxesAndTaxTotal(EE_Line_Item $total_line_item): float |
|
| 477 | + { |
|
| 478 | + $this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total); |
|
| 479 | + // calculate the total taxable amount for globally applied taxes |
|
| 480 | + $taxable_total = $this->taxableAmountForGlobalTaxes($total_line_item); |
|
| 481 | + $global_taxes = $this->applyGlobalTaxes($total_line_item, $taxable_total); |
|
| 482 | + $non_global_taxes = $this->calculateNonGlobalTaxes($total_line_item); |
|
| 483 | + $all_tax_total = $this->applyNonGlobalTaxes($total_line_item, $global_taxes, $non_global_taxes); |
|
| 484 | + $this->recalculateTaxSubTotal($total_line_item); |
|
| 485 | + return $all_tax_total; |
|
| 486 | + } |
|
| 487 | + |
|
| 488 | + |
|
| 489 | + /** |
|
| 490 | + * @param EE_Line_Item $total_line_item |
|
| 491 | + * @param float $taxable_total |
|
| 492 | + * @return float |
|
| 493 | + * @throws EE_Error |
|
| 494 | + * @throws ReflectionException |
|
| 495 | + */ |
|
| 496 | + private function applyGlobalTaxes(EE_Line_Item $total_line_item, float $taxable_total): float |
|
| 497 | + { |
|
| 498 | + $this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total); |
|
| 499 | + $total_tax = 0; |
|
| 500 | + // loop through all global taxes all taxes |
|
| 501 | + $global_taxes = $total_line_item->tax_descendants(); |
|
| 502 | + foreach ($global_taxes as $tax) { |
|
| 503 | + $tax_total = $this->calculatePercentage($taxable_total, $tax->percent()); |
|
| 504 | + $tax_total = $this->updateTotal($tax, $tax_total, true); |
|
| 505 | + $total_tax += $tax_total; |
|
| 506 | + } |
|
| 507 | + return $this->decimal_values->roundDecimalValue($total_tax, true); |
|
| 508 | + } |
|
| 509 | + |
|
| 510 | + |
|
| 511 | + /** |
|
| 512 | + * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated |
|
| 513 | + * |
|
| 514 | + * @param EE_Line_Item $line_item |
|
| 515 | + * @return void |
|
| 516 | + * @throws EE_Error |
|
| 517 | + * @throws ReflectionException |
|
| 518 | + */ |
|
| 519 | + private function recalculateTaxSubTotal(EE_Line_Item $line_item) |
|
| 520 | + { |
|
| 521 | + $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total); |
|
| 522 | + foreach ($line_item->children() as $maybe_tax_subtotal) { |
|
| 523 | + if ( |
|
| 524 | + $this->validateLineItemAndType($maybe_tax_subtotal) |
|
| 525 | + && $maybe_tax_subtotal->is_tax_sub_total() |
|
| 526 | + ) { |
|
| 527 | + $total = 0; |
|
| 528 | + $total_percent = 0; |
|
| 529 | + // simply loop through all its children (which should be taxes) and sum their total |
|
| 530 | + foreach ($maybe_tax_subtotal->children() as $child_tax) { |
|
| 531 | + if ($this->validateLineItemAndType($child_tax) && $child_tax->isGlobalTax()) { |
|
| 532 | + $total += $child_tax->total(); |
|
| 533 | + $total_percent += $child_tax->percent(); |
|
| 534 | + } |
|
| 535 | + } |
|
| 536 | + $this->updateTotal($maybe_tax_subtotal, $total, true); |
|
| 537 | + $this->updatePercent($maybe_tax_subtotal, $total_percent); |
|
| 538 | + } |
|
| 539 | + } |
|
| 540 | + } |
|
| 541 | + |
|
| 542 | + |
|
| 543 | + /** |
|
| 544 | + * returns an array of tax details like: |
|
| 545 | + * [ |
|
| 546 | + * 'GST_7' => [ |
|
| 547 | + * 'name' => 'GST', |
|
| 548 | + * 'rate' => float(7), |
|
| 549 | + * 'total' => float(4.9), |
|
| 550 | + * ] |
|
| 551 | + * ] |
|
| 552 | + * |
|
| 553 | + * @param EE_Line_Item $total_line_item |
|
| 554 | + * @param array $non_global_taxes |
|
| 555 | + * @param float $line_item_total |
|
| 556 | + * @return array |
|
| 557 | + * @throws EE_Error |
|
| 558 | + * @throws ReflectionException |
|
| 559 | + */ |
|
| 560 | + private function calculateNonGlobalTaxes( |
|
| 561 | + EE_Line_Item $total_line_item, |
|
| 562 | + array $non_global_taxes = [], |
|
| 563 | + float $line_item_total = 0 |
|
| 564 | + ): array { |
|
| 565 | + foreach ($total_line_item->children() as $line_item) { |
|
| 566 | + if ($this->validateLineItemAndType($line_item)) { |
|
| 567 | + if ($line_item->is_sub_total()) { |
|
| 568 | + $non_global_taxes = $this->calculateNonGlobalTaxes($line_item, $non_global_taxes); |
|
| 569 | + } elseif ($line_item->is_line_item()) { |
|
| 570 | + $non_global_taxes = $this->calculateNonGlobalTaxes( |
|
| 571 | + $line_item, |
|
| 572 | + $non_global_taxes, |
|
| 573 | + $line_item->pretaxTotal() |
|
| 574 | + ); |
|
| 575 | + } elseif ($line_item->isSubTax()) { |
|
| 576 | + $tax_ID = $line_item->name() . '_' . $line_item->percent(); |
|
| 577 | + if (! isset($non_global_taxes[ $tax_ID ])) { |
|
| 578 | + $non_global_taxes[ $tax_ID ] = [ |
|
| 579 | + 'name' => $line_item->name(), |
|
| 580 | + 'rate' => $line_item->percent(), |
|
| 581 | + 'total' => 0, |
|
| 582 | + 'obj' => $line_item->OBJ_type(), |
|
| 583 | + 'objID' => $line_item->OBJ_ID(), |
|
| 584 | + ]; |
|
| 585 | + } |
|
| 586 | + $tax = $this->calculatePercentage($line_item_total, $line_item->percent()); |
|
| 587 | + $non_global_taxes[ $tax_ID ]['total'] += $tax; |
|
| 588 | + } |
|
| 589 | + } |
|
| 590 | + } |
|
| 591 | + return $non_global_taxes; |
|
| 592 | + } |
|
| 593 | + |
|
| 594 | + |
|
| 595 | + /** |
|
| 596 | + * @param EE_Line_Item $total_line_item |
|
| 597 | + * @param float $tax_total |
|
| 598 | + * @param array $non_global_taxes array of tax details generated by calculateNonGlobalTaxes() |
|
| 599 | + * @return float |
|
| 600 | + * @throws EE_Error |
|
| 601 | + * @throws ReflectionException |
|
| 602 | + */ |
|
| 603 | + private function applyNonGlobalTaxes( |
|
| 604 | + EE_Line_Item $total_line_item, |
|
| 605 | + float $tax_total, |
|
| 606 | + array $non_global_taxes |
|
| 607 | + ): float { |
|
| 608 | + $global_taxes = $total_line_item->tax_descendants(); |
|
| 609 | + $taxes_subtotal = EEH_Line_Item::get_taxes_subtotal($total_line_item); |
|
| 610 | + foreach ($non_global_taxes as $non_global_tax) { |
|
| 611 | + $found = false; |
|
| 612 | + foreach ($global_taxes as $global_tax) { |
|
| 613 | + if ( |
|
| 614 | + $this->validateLineItemAndType($global_tax) |
|
| 615 | + && $non_global_tax['obj'] === $global_tax->OBJ_type() |
|
| 616 | + && $non_global_tax['objID'] === $global_tax->OBJ_ID() |
|
| 617 | + ) { |
|
| 618 | + $found = true; |
|
| 619 | + $new_total = $global_tax->total() + $non_global_tax['total']; |
|
| 620 | + // add non global tax to matching global tax AND the tax total |
|
| 621 | + $global_tax->set_total($new_total); |
|
| 622 | + $global_tax->maybe_save(); |
|
| 623 | + $tax_total += $non_global_tax['total']; |
|
| 624 | + } |
|
| 625 | + } |
|
| 626 | + if (! $found) { |
|
| 627 | + // add a new line item for this non global tax |
|
| 628 | + $taxes_subtotal->add_child_line_item( |
|
| 629 | + EE_Line_Item::new_instance( |
|
| 630 | + [ |
|
| 631 | + 'LIN_name' => $non_global_tax['name'], |
|
| 632 | + 'LIN_percent' => $non_global_tax['rate'], |
|
| 633 | + 'LIN_is_taxable' => false, |
|
| 634 | + 'LIN_total' => $non_global_tax['total'], |
|
| 635 | + 'LIN_type' => EEM_Line_Item::type_tax, |
|
| 636 | + 'OBJ_type' => $non_global_tax['obj'], |
|
| 637 | + 'OBJ_ID' => $non_global_tax['objID'], |
|
| 638 | + ] |
|
| 639 | + ) |
|
| 640 | + ); |
|
| 641 | + $tax_total += $non_global_tax['total']; |
|
| 642 | + } |
|
| 643 | + } |
|
| 644 | + return $this->decimal_values->roundDecimalValue($tax_total, true); |
|
| 645 | + } |
|
| 646 | + |
|
| 647 | + |
|
| 648 | + /** |
|
| 649 | + * Gets the total tax on this line item. Assumes taxes have already been calculated using |
|
| 650 | + * recalculate_taxes_and_total |
|
| 651 | + * |
|
| 652 | + * @param EE_Line_Item $line_item |
|
| 653 | + * @return float |
|
| 654 | + * @throws EE_Error |
|
| 655 | + * @throws ReflectionException |
|
| 656 | + */ |
|
| 657 | + public function getTotalTax(EE_Line_Item $line_item): float |
|
| 658 | + { |
|
| 659 | + $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total); |
|
| 660 | + $this->recalculateTaxSubTotal($line_item); |
|
| 661 | + $total = 0; |
|
| 662 | + foreach ($line_item->tax_descendants() as $tax_line_item) { |
|
| 663 | + if ($this->validateLineItemAndType($tax_line_item)) { |
|
| 664 | + $total += $tax_line_item->total(); |
|
| 665 | + } |
|
| 666 | + } |
|
| 667 | + return $this->decimal_values->roundDecimalValue($total, true); |
|
| 668 | + } |
|
| 669 | + |
|
| 670 | + |
|
| 671 | + /** |
|
| 672 | + * Returns the amount taxable among this line item's children (or if it has no children, |
|
| 673 | + * how much of it is taxable). Does not recalculate totals or subtotals. |
|
| 674 | + * If the taxable total is negative, (eg, if none of the tickets were taxable, |
|
| 675 | + * but there is a "Taxable" discount), returns 0. |
|
| 676 | + * |
|
| 677 | + * @param EE_Line_Item|null $line_item |
|
| 678 | + * @return float |
|
| 679 | + * @throws EE_Error |
|
| 680 | + * @throws ReflectionException |
|
| 681 | + */ |
|
| 682 | + public function taxableAmountForGlobalTaxes(?EE_Line_Item $line_item): float |
|
| 683 | + { |
|
| 684 | + $total = 0; |
|
| 685 | + $child_line_items = $line_item->children($this->default_query_params); |
|
| 686 | + foreach ($child_line_items as $child_line_item) { |
|
| 687 | + $this->validateLineItemAndType($child_line_item); |
|
| 688 | + if ($child_line_item->is_sub_total()) { |
|
| 689 | + $total += $this->taxableAmountForGlobalTaxes($child_line_item); |
|
| 690 | + } elseif ($child_line_item->is_line_item() && $child_line_item->is_taxable()) { |
|
| 691 | + // if it's a percent item, only take into account |
|
| 692 | + // the percentage that's taxable (the taxable total so far) |
|
| 693 | + if ($child_line_item->is_percent()) { |
|
| 694 | + $total += $this->calculatePercentage($total, $child_line_item->percent(), true); |
|
| 695 | + } else { |
|
| 696 | + // pretax total will be equal to the total for line items with globally applied taxes |
|
| 697 | + $pretax_total = $this->calculateTotal($child_line_item); |
|
| 698 | + $total += $this->updatePreTaxTotal($child_line_item, $pretax_total); |
|
| 699 | + } |
|
| 700 | + } |
|
| 701 | + } |
|
| 702 | + return max($total, 0); |
|
| 703 | + } |
|
| 704 | + |
|
| 705 | + |
|
| 706 | + /** |
|
| 707 | + * @param EE_Line_Item|null $line_item |
|
| 708 | + * @param string|null $type |
|
| 709 | + * @return bool |
|
| 710 | + * @throws EE_Error |
|
| 711 | + * @throws ReflectionException |
|
| 712 | + */ |
|
| 713 | + private function validateLineItemAndType(?EE_Line_Item $line_item, ?string $type = null): bool |
|
| 714 | + { |
|
| 715 | + if (! $line_item instanceof EE_Line_Item) { |
|
| 716 | + throw new DomainException( |
|
| 717 | + esc_html__('Invalid or missing Line Item supplied .', 'event_espresso') |
|
| 718 | + ); |
|
| 719 | + } |
|
| 720 | + if ($type && $line_item->type() !== $type) { |
|
| 721 | + throw new DomainException( |
|
| 722 | + sprintf( |
|
| 723 | + esc_html__( |
|
| 724 | + 'Invalid Line Item type supplied. Received "%1$s" but expected "%2$s".', |
|
| 725 | + 'event_espresso' |
|
| 726 | + ), |
|
| 727 | + $line_item->type(), |
|
| 728 | + $type |
|
| 729 | + ) |
|
| 730 | + ); |
|
| 731 | + } |
|
| 732 | + return true; |
|
| 733 | + } |
|
| 734 | 734 | } |
@@ -189,7 +189,7 @@ discard block |
||
| 189 | 189 | } else { |
| 190 | 190 | // recursively loop through children and recalculate their totals |
| 191 | 191 | $children = $line_item->children($this->default_query_params); |
| 192 | - if (! empty($children)) { |
|
| 192 | + if ( ! empty($children)) { |
|
| 193 | 193 | // reset the total and pretax total to zero since we are recalculating them |
| 194 | 194 | $pretax = $total = 0; |
| 195 | 195 | foreach ($children as $child_line_item) { |
@@ -206,7 +206,7 @@ discard block |
||
| 206 | 206 | $total = $this->updateTotal($line_item, $total, true); |
| 207 | 207 | $pretax = $this->updatePreTaxTotal($line_item, $pretax, true); |
| 208 | 208 | |
| 209 | - if (! $line_item->is_percent()) { |
|
| 209 | + if ( ! $line_item->is_percent()) { |
|
| 210 | 210 | // need to also adjust unit price too if the pretax total or quantity has been updated |
| 211 | 211 | $this->updateUnitPrice($line_item, $pretax); |
| 212 | 212 | } |
@@ -480,7 +480,7 @@ discard block |
||
| 480 | 480 | $taxable_total = $this->taxableAmountForGlobalTaxes($total_line_item); |
| 481 | 481 | $global_taxes = $this->applyGlobalTaxes($total_line_item, $taxable_total); |
| 482 | 482 | $non_global_taxes = $this->calculateNonGlobalTaxes($total_line_item); |
| 483 | - $all_tax_total = $this->applyNonGlobalTaxes($total_line_item, $global_taxes, $non_global_taxes); |
|
| 483 | + $all_tax_total = $this->applyNonGlobalTaxes($total_line_item, $global_taxes, $non_global_taxes); |
|
| 484 | 484 | $this->recalculateTaxSubTotal($total_line_item); |
| 485 | 485 | return $all_tax_total; |
| 486 | 486 | } |
@@ -573,9 +573,9 @@ discard block |
||
| 573 | 573 | $line_item->pretaxTotal() |
| 574 | 574 | ); |
| 575 | 575 | } elseif ($line_item->isSubTax()) { |
| 576 | - $tax_ID = $line_item->name() . '_' . $line_item->percent(); |
|
| 577 | - if (! isset($non_global_taxes[ $tax_ID ])) { |
|
| 578 | - $non_global_taxes[ $tax_ID ] = [ |
|
| 576 | + $tax_ID = $line_item->name().'_'.$line_item->percent(); |
|
| 577 | + if ( ! isset($non_global_taxes[$tax_ID])) { |
|
| 578 | + $non_global_taxes[$tax_ID] = [ |
|
| 579 | 579 | 'name' => $line_item->name(), |
| 580 | 580 | 'rate' => $line_item->percent(), |
| 581 | 581 | 'total' => 0, |
@@ -584,7 +584,7 @@ discard block |
||
| 584 | 584 | ]; |
| 585 | 585 | } |
| 586 | 586 | $tax = $this->calculatePercentage($line_item_total, $line_item->percent()); |
| 587 | - $non_global_taxes[ $tax_ID ]['total'] += $tax; |
|
| 587 | + $non_global_taxes[$tax_ID]['total'] += $tax; |
|
| 588 | 588 | } |
| 589 | 589 | } |
| 590 | 590 | } |
@@ -623,7 +623,7 @@ discard block |
||
| 623 | 623 | $tax_total += $non_global_tax['total']; |
| 624 | 624 | } |
| 625 | 625 | } |
| 626 | - if (! $found) { |
|
| 626 | + if ( ! $found) { |
|
| 627 | 627 | // add a new line item for this non global tax |
| 628 | 628 | $taxes_subtotal->add_child_line_item( |
| 629 | 629 | EE_Line_Item::new_instance( |
@@ -681,7 +681,7 @@ discard block |
||
| 681 | 681 | */ |
| 682 | 682 | public function taxableAmountForGlobalTaxes(?EE_Line_Item $line_item): float |
| 683 | 683 | { |
| 684 | - $total = 0; |
|
| 684 | + $total = 0; |
|
| 685 | 685 | $child_line_items = $line_item->children($this->default_query_params); |
| 686 | 686 | foreach ($child_line_items as $child_line_item) { |
| 687 | 687 | $this->validateLineItemAndType($child_line_item); |
@@ -712,7 +712,7 @@ discard block |
||
| 712 | 712 | */ |
| 713 | 713 | private function validateLineItemAndType(?EE_Line_Item $line_item, ?string $type = null): bool |
| 714 | 714 | { |
| 715 | - if (! $line_item instanceof EE_Line_Item) { |
|
| 715 | + if ( ! $line_item instanceof EE_Line_Item) { |
|
| 716 | 716 | throw new DomainException( |
| 717 | 717 | esc_html__('Invalid or missing Line Item supplied .', 'event_espresso') |
| 718 | 718 | ); |
@@ -15,2054 +15,2054 @@ |
||
| 15 | 15 | class EE_Ticket extends EE_Soft_Delete_Base_Class implements EEI_Line_Item_Object, EEI_Event_Relation, EEI_Has_Icon |
| 16 | 16 | { |
| 17 | 17 | |
| 18 | - /** |
|
| 19 | - * TicKet Archived: |
|
| 20 | - * constant used by ticket_status() to indicate that a ticket is archived |
|
| 21 | - * and no longer available for purchase |
|
| 22 | - */ |
|
| 23 | - const archived = 'TKA'; |
|
| 24 | - |
|
| 25 | - /** |
|
| 26 | - * TicKet Expired: |
|
| 27 | - * constant used by ticket_status() to indicate that a ticket is expired |
|
| 28 | - * and no longer available for purchase |
|
| 29 | - */ |
|
| 30 | - const expired = 'TKE'; |
|
| 31 | - |
|
| 32 | - /** |
|
| 33 | - * TicKet On sale: |
|
| 34 | - * constant used by ticket_status() to indicate that a ticket is On Sale |
|
| 35 | - * and IS available for purchase |
|
| 36 | - */ |
|
| 37 | - const onsale = 'TKO'; |
|
| 38 | - |
|
| 39 | - /** |
|
| 40 | - * TicKet Pending: |
|
| 41 | - * constant used by ticket_status() to indicate that a ticket is pending |
|
| 42 | - * and is NOT YET available for purchase |
|
| 43 | - */ |
|
| 44 | - const pending = 'TKP'; |
|
| 45 | - |
|
| 46 | - /** |
|
| 47 | - * TicKet Sold out: |
|
| 48 | - * constant used by ticket_status() to indicate that a ticket is sold out |
|
| 49 | - * and no longer available for purchases |
|
| 50 | - */ |
|
| 51 | - const sold_out = 'TKS'; |
|
| 52 | - |
|
| 53 | - /** |
|
| 54 | - * extra meta key for tracking ticket reservations |
|
| 55 | - * |
|
| 56 | - * @type string |
|
| 57 | - */ |
|
| 58 | - const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations'; |
|
| 59 | - |
|
| 60 | - /** |
|
| 61 | - * override of parent property |
|
| 62 | - * |
|
| 63 | - * @var EEM_Ticket |
|
| 64 | - */ |
|
| 65 | - protected $_model; |
|
| 66 | - |
|
| 67 | - /** |
|
| 68 | - * cached result from method of the same name |
|
| 69 | - * |
|
| 70 | - * @var float $_ticket_total_with_taxes |
|
| 71 | - */ |
|
| 72 | - private $_ticket_total_with_taxes; |
|
| 73 | - |
|
| 74 | - /** |
|
| 75 | - * @var TicketPriceModifiers |
|
| 76 | - */ |
|
| 77 | - protected $ticket_price_modifiers; |
|
| 78 | - |
|
| 79 | - |
|
| 80 | - /** |
|
| 81 | - * @param array $props_n_values incoming values |
|
| 82 | - * @param string $timezone incoming timezone (if not set the timezone set for the website will be |
|
| 83 | - * used.) |
|
| 84 | - * @param array $date_formats incoming date_formats in an array where the first value is the |
|
| 85 | - * date_format and the second value is the time format |
|
| 86 | - * @return EE_Ticket |
|
| 87 | - * @throws EE_Error |
|
| 88 | - * @throws ReflectionException |
|
| 89 | - */ |
|
| 90 | - public static function new_instance($props_n_values = [], $timezone = null, $date_formats = []) |
|
| 91 | - { |
|
| 92 | - $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats); |
|
| 93 | - return $has_object ?: new self($props_n_values, false, $timezone, $date_formats); |
|
| 94 | - } |
|
| 95 | - |
|
| 96 | - |
|
| 97 | - /** |
|
| 98 | - * @param array $props_n_values incoming values from the database |
|
| 99 | - * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
| 100 | - * the website will be used. |
|
| 101 | - * @return EE_Ticket |
|
| 102 | - * @throws EE_Error |
|
| 103 | - * @throws ReflectionException |
|
| 104 | - */ |
|
| 105 | - public static function new_instance_from_db($props_n_values = [], $timezone = null) |
|
| 106 | - { |
|
| 107 | - return new self($props_n_values, true, $timezone); |
|
| 108 | - } |
|
| 109 | - |
|
| 110 | - |
|
| 111 | - /** |
|
| 112 | - * @param array $fieldValues |
|
| 113 | - * @param false $bydb |
|
| 114 | - * @param string $timezone |
|
| 115 | - * @param array $date_formats |
|
| 116 | - * @throws EE_Error |
|
| 117 | - * @throws ReflectionException |
|
| 118 | - */ |
|
| 119 | - public function __construct($fieldValues = [], $bydb = false, $timezone = '', $date_formats = []) |
|
| 120 | - { |
|
| 121 | - parent::__construct($fieldValues, $bydb, $timezone, $date_formats); |
|
| 122 | - $this->ticket_price_modifiers = new TicketPriceModifiers($this); |
|
| 123 | - } |
|
| 124 | - |
|
| 125 | - |
|
| 126 | - /** |
|
| 127 | - * @return bool |
|
| 128 | - * @throws EE_Error |
|
| 129 | - * @throws ReflectionException |
|
| 130 | - */ |
|
| 131 | - public function parent() |
|
| 132 | - { |
|
| 133 | - return $this->get('TKT_parent'); |
|
| 134 | - } |
|
| 135 | - |
|
| 136 | - |
|
| 137 | - /** |
|
| 138 | - * return if a ticket has quantities available for purchase |
|
| 139 | - * |
|
| 140 | - * @param int $DTT_ID the primary key for a particular datetime |
|
| 141 | - * @return boolean |
|
| 142 | - * @throws EE_Error |
|
| 143 | - * @throws ReflectionException |
|
| 144 | - */ |
|
| 145 | - public function available($DTT_ID = 0) |
|
| 146 | - { |
|
| 147 | - // are we checking availability for a particular datetime ? |
|
| 148 | - if ($DTT_ID) { |
|
| 149 | - // get that datetime object |
|
| 150 | - $datetime = $this->get_first_related('Datetime', [['DTT_ID' => $DTT_ID]]); |
|
| 151 | - // if ticket sales for this datetime have exceeded the reg limit... |
|
| 152 | - if ($datetime instanceof EE_Datetime && $datetime->sold_out()) { |
|
| 153 | - return false; |
|
| 154 | - } |
|
| 155 | - } |
|
| 156 | - // datetime is still open for registration, but is this ticket sold out ? |
|
| 157 | - return $this->qty() < 1 || $this->qty() > $this->sold(); |
|
| 158 | - } |
|
| 159 | - |
|
| 160 | - |
|
| 161 | - /** |
|
| 162 | - * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired |
|
| 163 | - * |
|
| 164 | - * @param bool $display true = we'll return a localized string, otherwise we just return the value of the |
|
| 165 | - * relevant status const |
|
| 166 | - * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save |
|
| 167 | - * further processing |
|
| 168 | - * @return mixed status int if the display string isn't requested |
|
| 169 | - * @throws EE_Error |
|
| 170 | - * @throws ReflectionException |
|
| 171 | - */ |
|
| 172 | - public function ticket_status($display = false, $remaining = null) |
|
| 173 | - { |
|
| 174 | - $remaining = is_bool($remaining) ? $remaining : $this->is_remaining(); |
|
| 175 | - if (! $remaining) { |
|
| 176 | - return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out; |
|
| 177 | - } |
|
| 178 | - if ($this->get('TKT_deleted')) { |
|
| 179 | - return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived; |
|
| 180 | - } |
|
| 181 | - if ($this->is_expired()) { |
|
| 182 | - return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired; |
|
| 183 | - } |
|
| 184 | - if ($this->is_pending()) { |
|
| 185 | - return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending; |
|
| 186 | - } |
|
| 187 | - if ($this->is_on_sale()) { |
|
| 188 | - return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale; |
|
| 189 | - } |
|
| 190 | - return ''; |
|
| 191 | - } |
|
| 192 | - |
|
| 193 | - |
|
| 194 | - /** |
|
| 195 | - * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale |
|
| 196 | - * considering ALL the factors used for figuring that out. |
|
| 197 | - * |
|
| 198 | - * @param int $DTT_ID if an int above 0 is included here then we get a specific dtt. |
|
| 199 | - * @return boolean true = tickets remaining, false not. |
|
| 200 | - * @throws EE_Error |
|
| 201 | - * @throws ReflectionException |
|
| 202 | - */ |
|
| 203 | - public function is_remaining($DTT_ID = 0) |
|
| 204 | - { |
|
| 205 | - $num_remaining = $this->remaining($DTT_ID); |
|
| 206 | - if ($num_remaining === 0) { |
|
| 207 | - return false; |
|
| 208 | - } |
|
| 209 | - if ($num_remaining > 0 && $num_remaining < $this->min()) { |
|
| 210 | - return false; |
|
| 211 | - } |
|
| 212 | - return true; |
|
| 213 | - } |
|
| 214 | - |
|
| 215 | - |
|
| 216 | - /** |
|
| 217 | - * return the total number of tickets available for purchase |
|
| 218 | - * |
|
| 219 | - * @param int $DTT_ID the primary key for a particular datetime. |
|
| 220 | - * set to 0 for all related datetimes |
|
| 221 | - * @return int |
|
| 222 | - * @throws EE_Error |
|
| 223 | - * @throws ReflectionException |
|
| 224 | - */ |
|
| 225 | - public function remaining($DTT_ID = 0) |
|
| 226 | - { |
|
| 227 | - return $this->real_quantity_on_ticket('saleable', $DTT_ID); |
|
| 228 | - } |
|
| 229 | - |
|
| 230 | - |
|
| 231 | - /** |
|
| 232 | - * Gets min |
|
| 233 | - * |
|
| 234 | - * @return int |
|
| 235 | - * @throws EE_Error |
|
| 236 | - * @throws ReflectionException |
|
| 237 | - */ |
|
| 238 | - public function min() |
|
| 239 | - { |
|
| 240 | - return $this->get('TKT_min'); |
|
| 241 | - } |
|
| 242 | - |
|
| 243 | - |
|
| 244 | - /** |
|
| 245 | - * return if a ticket is no longer available cause its available dates have expired. |
|
| 246 | - * |
|
| 247 | - * @return boolean |
|
| 248 | - * @throws EE_Error |
|
| 249 | - * @throws ReflectionException |
|
| 250 | - */ |
|
| 251 | - public function is_expired() |
|
| 252 | - { |
|
| 253 | - return ($this->get_raw('TKT_end_date') < time()); |
|
| 254 | - } |
|
| 255 | - |
|
| 256 | - |
|
| 257 | - /** |
|
| 258 | - * Return if a ticket is yet to go on sale or not |
|
| 259 | - * |
|
| 260 | - * @return boolean |
|
| 261 | - * @throws EE_Error |
|
| 262 | - * @throws ReflectionException |
|
| 263 | - */ |
|
| 264 | - public function is_pending() |
|
| 265 | - { |
|
| 266 | - return ($this->get_raw('TKT_start_date') >= time()); |
|
| 267 | - } |
|
| 268 | - |
|
| 269 | - |
|
| 270 | - /** |
|
| 271 | - * Return if a ticket is on sale or not |
|
| 272 | - * |
|
| 273 | - * @return boolean |
|
| 274 | - * @throws EE_Error |
|
| 275 | - * @throws ReflectionException |
|
| 276 | - */ |
|
| 277 | - public function is_on_sale() |
|
| 278 | - { |
|
| 279 | - return ($this->get_raw('TKT_start_date') <= time() && $this->get_raw('TKT_end_date') >= time()); |
|
| 280 | - } |
|
| 281 | - |
|
| 282 | - |
|
| 283 | - /** |
|
| 284 | - * This returns the chronologically last datetime that this ticket is associated with |
|
| 285 | - * |
|
| 286 | - * @param string $date_format |
|
| 287 | - * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with |
|
| 288 | - * the end date ie: Jan 01 "to" Dec 31 |
|
| 289 | - * @return string |
|
| 290 | - * @throws EE_Error |
|
| 291 | - * @throws ReflectionException |
|
| 292 | - */ |
|
| 293 | - public function date_range($date_format = '', $conjunction = ' - ') |
|
| 294 | - { |
|
| 295 | - $date_format = ! empty($date_format) ? $date_format : $this->_dt_frmt; |
|
| 296 | - $first_date = $this->first_datetime() instanceof EE_Datetime |
|
| 297 | - ? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $date_format) |
|
| 298 | - : ''; |
|
| 299 | - $last_date = $this->last_datetime() instanceof EE_Datetime |
|
| 300 | - ? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $date_format) |
|
| 301 | - : ''; |
|
| 302 | - |
|
| 303 | - return $first_date && $last_date ? $first_date . $conjunction . $last_date : ''; |
|
| 304 | - } |
|
| 305 | - |
|
| 306 | - |
|
| 307 | - /** |
|
| 308 | - * This returns the chronologically first datetime that this ticket is associated with |
|
| 309 | - * |
|
| 310 | - * @return EE_Datetime |
|
| 311 | - * @throws EE_Error |
|
| 312 | - * @throws ReflectionException |
|
| 313 | - */ |
|
| 314 | - public function first_datetime() |
|
| 315 | - { |
|
| 316 | - $datetimes = $this->datetimes(['limit' => 1]); |
|
| 317 | - return reset($datetimes); |
|
| 318 | - } |
|
| 319 | - |
|
| 320 | - |
|
| 321 | - /** |
|
| 322 | - * Gets all the datetimes this ticket can be used for attending. |
|
| 323 | - * Unless otherwise specified, orders datetimes by start date. |
|
| 324 | - * |
|
| 325 | - * @param array $query_params |
|
| 326 | - * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 327 | - * @return EE_Datetime[]|EE_Base_Class[] |
|
| 328 | - * @throws EE_Error |
|
| 329 | - * @throws ReflectionException |
|
| 330 | - */ |
|
| 331 | - public function datetimes($query_params = []) |
|
| 332 | - { |
|
| 333 | - if (! isset($query_params['order_by'])) { |
|
| 334 | - $query_params['order_by']['DTT_order'] = 'ASC'; |
|
| 335 | - } |
|
| 336 | - return $this->get_many_related('Datetime', $query_params); |
|
| 337 | - } |
|
| 338 | - |
|
| 339 | - |
|
| 340 | - /** |
|
| 341 | - * This returns the chronologically last datetime that this ticket is associated with |
|
| 342 | - * |
|
| 343 | - * @return EE_Datetime |
|
| 344 | - * @throws EE_Error |
|
| 345 | - * @throws ReflectionException |
|
| 346 | - */ |
|
| 347 | - public function last_datetime() |
|
| 348 | - { |
|
| 349 | - $datetimes = $this->datetimes(['limit' => 1, 'order_by' => ['DTT_EVT_start' => 'DESC']]); |
|
| 350 | - return end($datetimes); |
|
| 351 | - } |
|
| 352 | - |
|
| 353 | - |
|
| 354 | - /** |
|
| 355 | - * This returns the total tickets sold depending on the given parameters. |
|
| 356 | - * |
|
| 357 | - * @param string $what Can be one of two options: 'ticket', 'datetime'. |
|
| 358 | - * 'ticket' = total ticket sales for all datetimes this ticket is related to |
|
| 359 | - * 'datetime' = total ticket sales for a specified datetime (required $dtt_id) |
|
| 360 | - * 'datetime' = total ticket sales in the datetime_ticket table. |
|
| 361 | - * If $dtt_id is not given then we return an array of sales indexed by datetime. |
|
| 362 | - * If $dtt_id IS given then we return the tickets sold for that given datetime. |
|
| 363 | - * @param int $dtt_id [optional] include the dtt_id with $what = 'datetime'. |
|
| 364 | - * @return mixed (array|int) how many tickets have sold |
|
| 365 | - * @throws EE_Error |
|
| 366 | - * @throws ReflectionException |
|
| 367 | - */ |
|
| 368 | - public function tickets_sold($what = 'ticket', $dtt_id = null) |
|
| 369 | - { |
|
| 370 | - $total = 0; |
|
| 371 | - $tickets_sold = $this->_all_tickets_sold(); |
|
| 372 | - switch ($what) { |
|
| 373 | - case 'ticket': |
|
| 374 | - return $tickets_sold['ticket']; |
|
| 375 | - |
|
| 376 | - case 'datetime': |
|
| 377 | - if (empty($tickets_sold['datetime'])) { |
|
| 378 | - return $total; |
|
| 379 | - } |
|
| 380 | - if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) { |
|
| 381 | - EE_Error::add_error( |
|
| 382 | - __( |
|
| 383 | - 'You\'ve requested the amount of tickets sold for a given ticket and datetime, however there are no records for the datetime id you included. Are you SURE that is a datetime related to this ticket?', |
|
| 384 | - 'event_espresso' |
|
| 385 | - ), |
|
| 386 | - __FILE__, |
|
| 387 | - __FUNCTION__, |
|
| 388 | - __LINE__ |
|
| 389 | - ); |
|
| 390 | - return $total; |
|
| 391 | - } |
|
| 392 | - return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ]; |
|
| 393 | - |
|
| 394 | - default: |
|
| 395 | - return $total; |
|
| 396 | - } |
|
| 397 | - } |
|
| 398 | - |
|
| 399 | - |
|
| 400 | - /** |
|
| 401 | - * This returns an array indexed by datetime_id for tickets sold with this ticket. |
|
| 402 | - * |
|
| 403 | - * @return EE_Ticket[] |
|
| 404 | - * @throws EE_Error |
|
| 405 | - * @throws ReflectionException |
|
| 406 | - */ |
|
| 407 | - protected function _all_tickets_sold() |
|
| 408 | - { |
|
| 409 | - $datetimes = $this->get_many_related('Datetime'); |
|
| 410 | - $tickets_sold = []; |
|
| 411 | - if (! empty($datetimes)) { |
|
| 412 | - foreach ($datetimes as $datetime) { |
|
| 413 | - $tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold'); |
|
| 414 | - } |
|
| 415 | - } |
|
| 416 | - // Tickets sold |
|
| 417 | - $tickets_sold['ticket'] = $this->sold(); |
|
| 418 | - return $tickets_sold; |
|
| 419 | - } |
|
| 420 | - |
|
| 421 | - |
|
| 422 | - /** |
|
| 423 | - * This returns the base price object for the ticket. |
|
| 424 | - * |
|
| 425 | - * @param bool $return_array whether to return as an array indexed by price id or just the object. |
|
| 426 | - * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[] |
|
| 427 | - * @throws EE_Error |
|
| 428 | - * @throws ReflectionException |
|
| 429 | - */ |
|
| 430 | - public function base_price(bool $return_array = false) |
|
| 431 | - { |
|
| 432 | - $base_price = $this->ticket_price_modifiers->getBasePrice(); |
|
| 433 | - if (! empty($base_price)) { |
|
| 434 | - return $return_array ? $base_price : reset($base_price); |
|
| 435 | - } |
|
| 436 | - $_where = ['Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price]; |
|
| 437 | - return $return_array |
|
| 438 | - ? $this->get_many_related('Price', [$_where]) |
|
| 439 | - : $this->get_first_related('Price', [$_where]); |
|
| 440 | - } |
|
| 441 | - |
|
| 442 | - |
|
| 443 | - /** |
|
| 444 | - * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price) |
|
| 445 | - * |
|
| 446 | - * @return EE_Price[] |
|
| 447 | - * @throws EE_Error |
|
| 448 | - * @throws ReflectionException |
|
| 449 | - */ |
|
| 450 | - public function price_modifiers(): array |
|
| 451 | - { |
|
| 452 | - $price_modifiers = $this->usesGlobalTaxes() |
|
| 453 | - ? $this->ticket_price_modifiers->getAllDiscountAndSurchargeModifiersForTicket() |
|
| 454 | - : $this->ticket_price_modifiers ->getAllModifiersForTicket(); |
|
| 455 | - if (! empty($price_modifiers)) { |
|
| 456 | - return $price_modifiers; |
|
| 457 | - } |
|
| 458 | - return $this->prices( |
|
| 459 | - [ |
|
| 460 | - [ |
|
| 461 | - 'Price_Type.PBT_ID' => [ |
|
| 462 | - 'NOT IN', |
|
| 463 | - [EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax], |
|
| 464 | - ] |
|
| 465 | - ] |
|
| 466 | - ] |
|
| 467 | - ); |
|
| 468 | - } |
|
| 469 | - |
|
| 470 | - |
|
| 471 | - /** |
|
| 472 | - * This returns ONLY the TAX price modifiers for the ticket |
|
| 473 | - * |
|
| 474 | - * @return EE_Price[] |
|
| 475 | - * @throws EE_Error |
|
| 476 | - * @throws ReflectionException |
|
| 477 | - */ |
|
| 478 | - public function tax_price_modifiers(): array |
|
| 479 | - { |
|
| 480 | - $tax_price_modifiers = $this->ticket_price_modifiers->getAllTaxesForTicket(); |
|
| 481 | - if (! empty($tax_price_modifiers)) { |
|
| 482 | - return $tax_price_modifiers; |
|
| 483 | - } |
|
| 484 | - return $this->prices([['Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax]]); |
|
| 485 | - } |
|
| 486 | - |
|
| 487 | - |
|
| 488 | - /** |
|
| 489 | - * Gets all the prices that combine to form the final price of this ticket |
|
| 490 | - * |
|
| 491 | - * @param array $query_params |
|
| 492 | - * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 493 | - * @return EE_Price[]|EE_Base_Class[] |
|
| 494 | - * @throws EE_Error |
|
| 495 | - * @throws ReflectionException |
|
| 496 | - */ |
|
| 497 | - public function prices(array $query_params = []): array |
|
| 498 | - { |
|
| 499 | - if (! isset($query_params['order_by'])) { |
|
| 500 | - $query_params['order_by']['PRC_order'] = 'ASC'; |
|
| 501 | - } |
|
| 502 | - return $this->get_many_related('Price', $query_params); |
|
| 503 | - } |
|
| 504 | - |
|
| 505 | - |
|
| 506 | - /** |
|
| 507 | - * Gets all the ticket datetimes (ie, relations between datetimes and tickets) |
|
| 508 | - * |
|
| 509 | - * @param array $query_params |
|
| 510 | - * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 511 | - * @return EE_Datetime_Ticket|EE_Base_Class[] |
|
| 512 | - * @throws EE_Error |
|
| 513 | - * @throws ReflectionException |
|
| 514 | - */ |
|
| 515 | - public function datetime_tickets($query_params = []) |
|
| 516 | - { |
|
| 517 | - return $this->get_many_related('Datetime_Ticket', $query_params); |
|
| 518 | - } |
|
| 519 | - |
|
| 520 | - |
|
| 521 | - /** |
|
| 522 | - * Gets all the datetimes from the db ordered by DTT_order |
|
| 523 | - * |
|
| 524 | - * @param boolean $show_expired |
|
| 525 | - * @param boolean $show_deleted |
|
| 526 | - * @return EE_Datetime[] |
|
| 527 | - * @throws EE_Error |
|
| 528 | - * @throws ReflectionException |
|
| 529 | - */ |
|
| 530 | - public function datetimes_ordered($show_expired = true, $show_deleted = false) |
|
| 531 | - { |
|
| 532 | - return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order( |
|
| 533 | - $this->ID(), |
|
| 534 | - $show_expired, |
|
| 535 | - $show_deleted |
|
| 536 | - ); |
|
| 537 | - } |
|
| 538 | - |
|
| 539 | - |
|
| 540 | - /** |
|
| 541 | - * Gets ID |
|
| 542 | - * |
|
| 543 | - * @return int |
|
| 544 | - * @throws EE_Error |
|
| 545 | - * @throws ReflectionException |
|
| 546 | - */ |
|
| 547 | - public function ID() |
|
| 548 | - { |
|
| 549 | - return $this->get('TKT_ID'); |
|
| 550 | - } |
|
| 551 | - |
|
| 552 | - |
|
| 553 | - /** |
|
| 554 | - * get the author of the ticket. |
|
| 555 | - * |
|
| 556 | - * @return int |
|
| 557 | - * @throws EE_Error |
|
| 558 | - * @throws ReflectionException |
|
| 559 | - * @since 4.5.0 |
|
| 560 | - */ |
|
| 561 | - public function wp_user() |
|
| 562 | - { |
|
| 563 | - return $this->get('TKT_wp_user'); |
|
| 564 | - } |
|
| 565 | - |
|
| 566 | - |
|
| 567 | - /** |
|
| 568 | - * Gets the template for the ticket |
|
| 569 | - * |
|
| 570 | - * @return EE_Ticket_Template|EE_Base_Class |
|
| 571 | - * @throws EE_Error |
|
| 572 | - * @throws ReflectionException |
|
| 573 | - */ |
|
| 574 | - public function template() |
|
| 575 | - { |
|
| 576 | - return $this->get_first_related('Ticket_Template'); |
|
| 577 | - } |
|
| 578 | - |
|
| 579 | - |
|
| 580 | - /** |
|
| 581 | - * Simply returns an array of EE_Price objects that are taxes. |
|
| 582 | - * |
|
| 583 | - * @return EE_Price[] |
|
| 584 | - * @throws EE_Error |
|
| 585 | - * @throws ReflectionException |
|
| 586 | - */ |
|
| 587 | - public function get_ticket_taxes_for_admin(): array |
|
| 588 | - { |
|
| 589 | - return $this->usesGlobalTaxes() ? EE_Taxes::get_taxes_for_admin() : $this->tax_price_modifiers(); |
|
| 590 | - } |
|
| 591 | - |
|
| 592 | - |
|
| 593 | - /** |
|
| 594 | - * alias of taxable() to better indicate that ticket uses the legacy method of applying default "global" taxes |
|
| 595 | - * as opposed to having tax price modifiers added directly to each ticket |
|
| 596 | - * |
|
| 597 | - * @return bool |
|
| 598 | - * @throws EE_Error |
|
| 599 | - * @throws ReflectionException |
|
| 600 | - * @since $VID:$ |
|
| 601 | - */ |
|
| 602 | - public function usesGlobalTaxes(): bool |
|
| 603 | - { |
|
| 604 | - return $this->taxable(); |
|
| 605 | - } |
|
| 606 | - |
|
| 607 | - |
|
| 608 | - /** |
|
| 609 | - * @return float |
|
| 610 | - * @throws EE_Error |
|
| 611 | - * @throws ReflectionException |
|
| 612 | - */ |
|
| 613 | - public function ticket_price() |
|
| 614 | - { |
|
| 615 | - return $this->get('TKT_price'); |
|
| 616 | - } |
|
| 617 | - |
|
| 618 | - |
|
| 619 | - /** |
|
| 620 | - * @return mixed |
|
| 621 | - * @throws EE_Error |
|
| 622 | - * @throws ReflectionException |
|
| 623 | - */ |
|
| 624 | - public function pretty_price() |
|
| 625 | - { |
|
| 626 | - return $this->get_pretty('TKT_price'); |
|
| 627 | - } |
|
| 628 | - |
|
| 629 | - |
|
| 630 | - /** |
|
| 631 | - * @return bool |
|
| 632 | - * @throws EE_Error |
|
| 633 | - * @throws ReflectionException |
|
| 634 | - */ |
|
| 635 | - public function is_free() |
|
| 636 | - { |
|
| 637 | - return $this->get_ticket_total_with_taxes() === (float) 0; |
|
| 638 | - } |
|
| 639 | - |
|
| 640 | - |
|
| 641 | - /** |
|
| 642 | - * get_ticket_total_with_taxes |
|
| 643 | - * |
|
| 644 | - * @param bool $no_cache |
|
| 645 | - * @return float |
|
| 646 | - * @throws EE_Error |
|
| 647 | - * @throws ReflectionException |
|
| 648 | - */ |
|
| 649 | - public function get_ticket_total_with_taxes($no_cache = false) |
|
| 650 | - { |
|
| 651 | - if ($this->_ticket_total_with_taxes === null || $no_cache) { |
|
| 652 | - $this->_ticket_total_with_taxes = $this->usesGlobalTaxes() |
|
| 653 | - ? $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin() |
|
| 654 | - : $this->ticket_price(); |
|
| 655 | - } |
|
| 656 | - return (float) $this->_ticket_total_with_taxes; |
|
| 657 | - } |
|
| 658 | - |
|
| 659 | - |
|
| 660 | - /** |
|
| 661 | - * @throws EE_Error |
|
| 662 | - * @throws ReflectionException |
|
| 663 | - */ |
|
| 664 | - public function ensure_TKT_Price_correct() |
|
| 665 | - { |
|
| 666 | - $this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this)); |
|
| 667 | - $this->save(); |
|
| 668 | - } |
|
| 669 | - |
|
| 670 | - |
|
| 671 | - /** |
|
| 672 | - * @return float |
|
| 673 | - * @throws EE_Error |
|
| 674 | - * @throws ReflectionException |
|
| 675 | - */ |
|
| 676 | - public function get_ticket_subtotal() |
|
| 677 | - { |
|
| 678 | - return EE_Taxes::get_subtotal_for_admin($this); |
|
| 679 | - } |
|
| 680 | - |
|
| 681 | - |
|
| 682 | - /** |
|
| 683 | - * Returns the total taxes applied to this ticket |
|
| 684 | - * |
|
| 685 | - * @return float |
|
| 686 | - * @throws EE_Error |
|
| 687 | - * @throws ReflectionException |
|
| 688 | - */ |
|
| 689 | - public function get_ticket_taxes_total_for_admin() |
|
| 690 | - { |
|
| 691 | - return EE_Taxes::get_total_taxes_for_admin($this); |
|
| 692 | - } |
|
| 693 | - |
|
| 694 | - |
|
| 695 | - /** |
|
| 696 | - * Sets name |
|
| 697 | - * |
|
| 698 | - * @param string $name |
|
| 699 | - * @throws EE_Error |
|
| 700 | - * @throws ReflectionException |
|
| 701 | - */ |
|
| 702 | - public function set_name($name) |
|
| 703 | - { |
|
| 704 | - $this->set('TKT_name', $name); |
|
| 705 | - } |
|
| 706 | - |
|
| 707 | - |
|
| 708 | - /** |
|
| 709 | - * Gets description |
|
| 710 | - * |
|
| 711 | - * @return string |
|
| 712 | - * @throws EE_Error |
|
| 713 | - * @throws ReflectionException |
|
| 714 | - */ |
|
| 715 | - public function description() |
|
| 716 | - { |
|
| 717 | - return $this->get('TKT_description'); |
|
| 718 | - } |
|
| 719 | - |
|
| 720 | - |
|
| 721 | - /** |
|
| 722 | - * Sets description |
|
| 723 | - * |
|
| 724 | - * @param string $description |
|
| 725 | - * @throws EE_Error |
|
| 726 | - * @throws ReflectionException |
|
| 727 | - */ |
|
| 728 | - public function set_description($description) |
|
| 729 | - { |
|
| 730 | - $this->set('TKT_description', $description); |
|
| 731 | - } |
|
| 732 | - |
|
| 733 | - |
|
| 734 | - /** |
|
| 735 | - * Gets start_date |
|
| 736 | - * |
|
| 737 | - * @param string $date_format |
|
| 738 | - * @param string $time_format |
|
| 739 | - * @return string |
|
| 740 | - * @throws EE_Error |
|
| 741 | - * @throws ReflectionException |
|
| 742 | - */ |
|
| 743 | - public function start_date($date_format = '', $time_format = '') |
|
| 744 | - { |
|
| 745 | - return $this->_get_datetime('TKT_start_date', $date_format, $time_format); |
|
| 746 | - } |
|
| 747 | - |
|
| 748 | - |
|
| 749 | - /** |
|
| 750 | - * Sets start_date |
|
| 751 | - * |
|
| 752 | - * @param string $start_date |
|
| 753 | - * @return void |
|
| 754 | - * @throws EE_Error |
|
| 755 | - * @throws ReflectionException |
|
| 756 | - */ |
|
| 757 | - public function set_start_date($start_date) |
|
| 758 | - { |
|
| 759 | - $this->_set_date_time('B', $start_date, 'TKT_start_date'); |
|
| 760 | - } |
|
| 761 | - |
|
| 762 | - |
|
| 763 | - /** |
|
| 764 | - * Gets end_date |
|
| 765 | - * |
|
| 766 | - * @param string $date_format |
|
| 767 | - * @param string $time_format |
|
| 768 | - * @return string |
|
| 769 | - * @throws EE_Error |
|
| 770 | - * @throws ReflectionException |
|
| 771 | - */ |
|
| 772 | - public function end_date($date_format = '', $time_format = '') |
|
| 773 | - { |
|
| 774 | - return $this->_get_datetime('TKT_end_date', $date_format, $time_format); |
|
| 775 | - } |
|
| 776 | - |
|
| 777 | - |
|
| 778 | - /** |
|
| 779 | - * Sets end_date |
|
| 780 | - * |
|
| 781 | - * @param string $end_date |
|
| 782 | - * @return void |
|
| 783 | - * @throws EE_Error |
|
| 784 | - * @throws ReflectionException |
|
| 785 | - */ |
|
| 786 | - public function set_end_date($end_date) |
|
| 787 | - { |
|
| 788 | - $this->_set_date_time('B', $end_date, 'TKT_end_date'); |
|
| 789 | - } |
|
| 790 | - |
|
| 791 | - |
|
| 792 | - /** |
|
| 793 | - * Sets sell until time |
|
| 794 | - * |
|
| 795 | - * @param string $time a string representation of the sell until time (ex 9am or 7:30pm) |
|
| 796 | - * @throws EE_Error |
|
| 797 | - * @throws ReflectionException |
|
| 798 | - * @since 4.5.0 |
|
| 799 | - */ |
|
| 800 | - public function set_end_time($time) |
|
| 801 | - { |
|
| 802 | - $this->_set_time_for($time, 'TKT_end_date'); |
|
| 803 | - } |
|
| 804 | - |
|
| 805 | - |
|
| 806 | - /** |
|
| 807 | - * Sets min |
|
| 808 | - * |
|
| 809 | - * @param int $min |
|
| 810 | - * @return void |
|
| 811 | - * @throws EE_Error |
|
| 812 | - * @throws ReflectionException |
|
| 813 | - */ |
|
| 814 | - public function set_min($min) |
|
| 815 | - { |
|
| 816 | - $this->set('TKT_min', $min); |
|
| 817 | - } |
|
| 818 | - |
|
| 819 | - |
|
| 820 | - /** |
|
| 821 | - * Gets max |
|
| 822 | - * |
|
| 823 | - * @return int |
|
| 824 | - * @throws EE_Error |
|
| 825 | - * @throws ReflectionException |
|
| 826 | - */ |
|
| 827 | - public function max() |
|
| 828 | - { |
|
| 829 | - return $this->get('TKT_max'); |
|
| 830 | - } |
|
| 831 | - |
|
| 832 | - |
|
| 833 | - /** |
|
| 834 | - * Sets max |
|
| 835 | - * |
|
| 836 | - * @param int $max |
|
| 837 | - * @return void |
|
| 838 | - * @throws EE_Error |
|
| 839 | - * @throws ReflectionException |
|
| 840 | - */ |
|
| 841 | - public function set_max($max) |
|
| 842 | - { |
|
| 843 | - $this->set('TKT_max', $max); |
|
| 844 | - } |
|
| 845 | - |
|
| 846 | - |
|
| 847 | - /** |
|
| 848 | - * Sets price |
|
| 849 | - * |
|
| 850 | - * @param float $price |
|
| 851 | - * @return void |
|
| 852 | - * @throws EE_Error |
|
| 853 | - * @throws ReflectionException |
|
| 854 | - */ |
|
| 855 | - public function set_price($price) |
|
| 856 | - { |
|
| 857 | - $this->set('TKT_price', $price); |
|
| 858 | - } |
|
| 859 | - |
|
| 860 | - |
|
| 861 | - /** |
|
| 862 | - * Gets sold |
|
| 863 | - * |
|
| 864 | - * @return int |
|
| 865 | - * @throws EE_Error |
|
| 866 | - * @throws ReflectionException |
|
| 867 | - */ |
|
| 868 | - public function sold() |
|
| 869 | - { |
|
| 870 | - return $this->get_raw('TKT_sold'); |
|
| 871 | - } |
|
| 872 | - |
|
| 873 | - |
|
| 874 | - /** |
|
| 875 | - * Sets sold |
|
| 876 | - * |
|
| 877 | - * @param int $sold |
|
| 878 | - * @return void |
|
| 879 | - * @throws EE_Error |
|
| 880 | - * @throws ReflectionException |
|
| 881 | - */ |
|
| 882 | - public function set_sold($sold) |
|
| 883 | - { |
|
| 884 | - // sold can not go below zero |
|
| 885 | - $sold = max(0, $sold); |
|
| 886 | - $this->set('TKT_sold', $sold); |
|
| 887 | - } |
|
| 888 | - |
|
| 889 | - |
|
| 890 | - /** |
|
| 891 | - * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its |
|
| 892 | - * associated datetimes. |
|
| 893 | - * |
|
| 894 | - * @param int $qty |
|
| 895 | - * @return boolean |
|
| 896 | - * @throws EE_Error |
|
| 897 | - * @throws InvalidArgumentException |
|
| 898 | - * @throws InvalidDataTypeException |
|
| 899 | - * @throws InvalidInterfaceException |
|
| 900 | - * @throws ReflectionException |
|
| 901 | - * @since 4.9.80.p |
|
| 902 | - */ |
|
| 903 | - public function increaseSold($qty = 1) |
|
| 904 | - { |
|
| 905 | - $qty = absint($qty); |
|
| 906 | - // increment sold and decrement reserved datetime quantities simultaneously |
|
| 907 | - // don't worry about failures, because they must have already had a spot reserved |
|
| 908 | - $this->increaseSoldForDatetimes($qty); |
|
| 909 | - // Increment and decrement ticket quantities simultaneously |
|
| 910 | - $success = $this->adjustNumericFieldsInDb( |
|
| 911 | - [ |
|
| 912 | - 'TKT_reserved' => $qty * -1, |
|
| 913 | - 'TKT_sold' => $qty, |
|
| 914 | - ] |
|
| 915 | - ); |
|
| 916 | - do_action( |
|
| 917 | - 'AHEE__EE_Ticket__increase_sold', |
|
| 918 | - $this, |
|
| 919 | - $qty, |
|
| 920 | - $this->sold(), |
|
| 921 | - $success |
|
| 922 | - ); |
|
| 923 | - return $success; |
|
| 924 | - } |
|
| 925 | - |
|
| 926 | - |
|
| 927 | - /** |
|
| 928 | - * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty. |
|
| 929 | - * |
|
| 930 | - * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved |
|
| 931 | - * counts), Negative means to decreases old counts (and increase reserved counts). |
|
| 932 | - * @param EE_Datetime[] $datetimes |
|
| 933 | - * @throws EE_Error |
|
| 934 | - * @throws InvalidArgumentException |
|
| 935 | - * @throws InvalidDataTypeException |
|
| 936 | - * @throws InvalidInterfaceException |
|
| 937 | - * @throws ReflectionException |
|
| 938 | - * @since 4.9.80.p |
|
| 939 | - */ |
|
| 940 | - protected function increaseSoldForDatetimes($qty, array $datetimes = []) |
|
| 941 | - { |
|
| 942 | - $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes(); |
|
| 943 | - foreach ($datetimes as $datetime) { |
|
| 944 | - $datetime->increaseSold($qty); |
|
| 945 | - } |
|
| 946 | - } |
|
| 947 | - |
|
| 948 | - |
|
| 949 | - /** |
|
| 950 | - * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the |
|
| 951 | - * DB and then updates the model objects. |
|
| 952 | - * Does not affect the reserved counts. |
|
| 953 | - * |
|
| 954 | - * @param int $qty |
|
| 955 | - * @return boolean |
|
| 956 | - * @throws EE_Error |
|
| 957 | - * @throws InvalidArgumentException |
|
| 958 | - * @throws InvalidDataTypeException |
|
| 959 | - * @throws InvalidInterfaceException |
|
| 960 | - * @throws ReflectionException |
|
| 961 | - * @since 4.9.80.p |
|
| 962 | - */ |
|
| 963 | - public function decreaseSold($qty = 1) |
|
| 964 | - { |
|
| 965 | - $qty = absint($qty); |
|
| 966 | - $this->decreaseSoldForDatetimes($qty); |
|
| 967 | - $success = $this->adjustNumericFieldsInDb( |
|
| 968 | - [ |
|
| 969 | - 'TKT_sold' => $qty * -1, |
|
| 970 | - ] |
|
| 971 | - ); |
|
| 972 | - do_action( |
|
| 973 | - 'AHEE__EE_Ticket__decrease_sold', |
|
| 974 | - $this, |
|
| 975 | - $qty, |
|
| 976 | - $this->sold(), |
|
| 977 | - $success |
|
| 978 | - ); |
|
| 979 | - return $success; |
|
| 980 | - } |
|
| 981 | - |
|
| 982 | - |
|
| 983 | - /** |
|
| 984 | - * Decreases sold on related datetimes |
|
| 985 | - * |
|
| 986 | - * @param int $qty |
|
| 987 | - * @param EE_Datetime[] $datetimes |
|
| 988 | - * @return void |
|
| 989 | - * @throws EE_Error |
|
| 990 | - * @throws InvalidArgumentException |
|
| 991 | - * @throws InvalidDataTypeException |
|
| 992 | - * @throws InvalidInterfaceException |
|
| 993 | - * @throws ReflectionException |
|
| 994 | - * @since 4.9.80.p |
|
| 995 | - */ |
|
| 996 | - protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = []) |
|
| 997 | - { |
|
| 998 | - $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes(); |
|
| 999 | - if (is_array($datetimes)) { |
|
| 1000 | - foreach ($datetimes as $datetime) { |
|
| 1001 | - if ($datetime instanceof EE_Datetime) { |
|
| 1002 | - $datetime->decreaseSold($qty); |
|
| 1003 | - } |
|
| 1004 | - } |
|
| 1005 | - } |
|
| 1006 | - } |
|
| 1007 | - |
|
| 1008 | - |
|
| 1009 | - /** |
|
| 1010 | - * Gets qty of reserved tickets |
|
| 1011 | - * |
|
| 1012 | - * @return int |
|
| 1013 | - * @throws EE_Error |
|
| 1014 | - * @throws ReflectionException |
|
| 1015 | - */ |
|
| 1016 | - public function reserved() |
|
| 1017 | - { |
|
| 1018 | - return $this->get_raw('TKT_reserved'); |
|
| 1019 | - } |
|
| 1020 | - |
|
| 1021 | - |
|
| 1022 | - /** |
|
| 1023 | - * Sets reserved |
|
| 1024 | - * |
|
| 1025 | - * @param int $reserved |
|
| 1026 | - * @return void |
|
| 1027 | - * @throws EE_Error |
|
| 1028 | - * @throws ReflectionException |
|
| 1029 | - */ |
|
| 1030 | - public function set_reserved($reserved) |
|
| 1031 | - { |
|
| 1032 | - // reserved can not go below zero |
|
| 1033 | - $reserved = max(0, (int) $reserved); |
|
| 1034 | - $this->set('TKT_reserved', $reserved); |
|
| 1035 | - } |
|
| 1036 | - |
|
| 1037 | - |
|
| 1038 | - /** |
|
| 1039 | - * Increments reserved by amount passed by $qty, and persists it immediately to the database. |
|
| 1040 | - * |
|
| 1041 | - * @param int $qty |
|
| 1042 | - * @param string $source |
|
| 1043 | - * @return bool whether we successfully reserved the ticket or not. |
|
| 1044 | - * @throws EE_Error |
|
| 1045 | - * @throws InvalidArgumentException |
|
| 1046 | - * @throws ReflectionException |
|
| 1047 | - * @throws InvalidDataTypeException |
|
| 1048 | - * @throws InvalidInterfaceException |
|
| 1049 | - * @since 4.9.80.p |
|
| 1050 | - */ |
|
| 1051 | - public function increaseReserved($qty = 1, $source = 'unknown') |
|
| 1052 | - { |
|
| 1053 | - $qty = absint($qty); |
|
| 1054 | - do_action( |
|
| 1055 | - 'AHEE__EE_Ticket__increase_reserved__begin', |
|
| 1056 | - $this, |
|
| 1057 | - $qty, |
|
| 1058 | - $source |
|
| 1059 | - ); |
|
| 1060 | - $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}"); |
|
| 1061 | - $success = false; |
|
| 1062 | - $datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty); |
|
| 1063 | - if ($datetimes_adjusted_successfully) { |
|
| 1064 | - $success = $this->incrementFieldConditionallyInDb( |
|
| 1065 | - 'TKT_reserved', |
|
| 1066 | - 'TKT_sold', |
|
| 1067 | - 'TKT_qty', |
|
| 1068 | - $qty |
|
| 1069 | - ); |
|
| 1070 | - if (! $success) { |
|
| 1071 | - // The datetimes were successfully bumped, but not the |
|
| 1072 | - // ticket. So we need to manually rollback the datetimes. |
|
| 1073 | - $this->decreaseReservedForDatetimes($qty); |
|
| 1074 | - } |
|
| 1075 | - } |
|
| 1076 | - do_action( |
|
| 1077 | - 'AHEE__EE_Ticket__increase_reserved', |
|
| 1078 | - $this, |
|
| 1079 | - $qty, |
|
| 1080 | - $this->reserved(), |
|
| 1081 | - $success |
|
| 1082 | - ); |
|
| 1083 | - return $success; |
|
| 1084 | - } |
|
| 1085 | - |
|
| 1086 | - |
|
| 1087 | - /** |
|
| 1088 | - * Increases reserved counts on related datetimes |
|
| 1089 | - * |
|
| 1090 | - * @param int $qty |
|
| 1091 | - * @param EE_Datetime[] $datetimes |
|
| 1092 | - * @return boolean indicating success |
|
| 1093 | - * @throws EE_Error |
|
| 1094 | - * @throws InvalidArgumentException |
|
| 1095 | - * @throws InvalidDataTypeException |
|
| 1096 | - * @throws InvalidInterfaceException |
|
| 1097 | - * @throws ReflectionException |
|
| 1098 | - * @since 4.9.80.p |
|
| 1099 | - */ |
|
| 1100 | - protected function increaseReservedForDatetimes($qty = 1, array $datetimes = []) |
|
| 1101 | - { |
|
| 1102 | - $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes(); |
|
| 1103 | - $datetimes_updated = []; |
|
| 1104 | - $limit_exceeded = false; |
|
| 1105 | - if (is_array($datetimes)) { |
|
| 1106 | - foreach ($datetimes as $datetime) { |
|
| 1107 | - if ($datetime instanceof EE_Datetime) { |
|
| 1108 | - if ($datetime->increaseReserved($qty)) { |
|
| 1109 | - $datetimes_updated[] = $datetime; |
|
| 1110 | - } else { |
|
| 1111 | - $limit_exceeded = true; |
|
| 1112 | - break; |
|
| 1113 | - } |
|
| 1114 | - } |
|
| 1115 | - } |
|
| 1116 | - // If somewhere along the way we detected a datetime whose |
|
| 1117 | - // limit was exceeded, do a manual rollback. |
|
| 1118 | - if ($limit_exceeded) { |
|
| 1119 | - $this->decreaseReservedForDatetimes($qty, $datetimes_updated); |
|
| 1120 | - return false; |
|
| 1121 | - } |
|
| 1122 | - } |
|
| 1123 | - return true; |
|
| 1124 | - } |
|
| 1125 | - |
|
| 1126 | - |
|
| 1127 | - /** |
|
| 1128 | - * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database. |
|
| 1129 | - * |
|
| 1130 | - * @param int $qty |
|
| 1131 | - * @param bool $adjust_datetimes |
|
| 1132 | - * @param string $source |
|
| 1133 | - * @return boolean |
|
| 1134 | - * @throws EE_Error |
|
| 1135 | - * @throws InvalidArgumentException |
|
| 1136 | - * @throws ReflectionException |
|
| 1137 | - * @throws InvalidDataTypeException |
|
| 1138 | - * @throws InvalidInterfaceException |
|
| 1139 | - * @since 4.9.80.p |
|
| 1140 | - */ |
|
| 1141 | - public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown') |
|
| 1142 | - { |
|
| 1143 | - $qty = absint($qty); |
|
| 1144 | - $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}"); |
|
| 1145 | - if ($adjust_datetimes) { |
|
| 1146 | - $this->decreaseReservedForDatetimes($qty); |
|
| 1147 | - } |
|
| 1148 | - $success = $this->adjustNumericFieldsInDb( |
|
| 1149 | - [ |
|
| 1150 | - 'TKT_reserved' => $qty * -1, |
|
| 1151 | - ] |
|
| 1152 | - ); |
|
| 1153 | - do_action( |
|
| 1154 | - 'AHEE__EE_Ticket__decrease_reserved', |
|
| 1155 | - $this, |
|
| 1156 | - $qty, |
|
| 1157 | - $this->reserved(), |
|
| 1158 | - $success |
|
| 1159 | - ); |
|
| 1160 | - return $success; |
|
| 1161 | - } |
|
| 1162 | - |
|
| 1163 | - |
|
| 1164 | - /** |
|
| 1165 | - * Decreases the reserved count on the specified datetimes. |
|
| 1166 | - * |
|
| 1167 | - * @param int $qty |
|
| 1168 | - * @param EE_Datetime[] $datetimes |
|
| 1169 | - * @throws EE_Error |
|
| 1170 | - * @throws InvalidArgumentException |
|
| 1171 | - * @throws ReflectionException |
|
| 1172 | - * @throws InvalidDataTypeException |
|
| 1173 | - * @throws InvalidInterfaceException |
|
| 1174 | - * @since 4.9.80.p |
|
| 1175 | - */ |
|
| 1176 | - protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = []) |
|
| 1177 | - { |
|
| 1178 | - $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes(); |
|
| 1179 | - foreach ($datetimes as $datetime) { |
|
| 1180 | - if ($datetime instanceof EE_Datetime) { |
|
| 1181 | - $datetime->decreaseReserved($qty); |
|
| 1182 | - } |
|
| 1183 | - } |
|
| 1184 | - } |
|
| 1185 | - |
|
| 1186 | - |
|
| 1187 | - /** |
|
| 1188 | - * Gets ticket quantity |
|
| 1189 | - * |
|
| 1190 | - * @param string $context ticket quantity is somewhat subjective depending on the exact information sought |
|
| 1191 | - * therefore $context can be one of three values: '', 'reg_limit', or 'saleable' |
|
| 1192 | - * '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects |
|
| 1193 | - * REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes |
|
| 1194 | - * SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and |
|
| 1195 | - * is therefore the truest measure of tickets that can be purchased at the moment |
|
| 1196 | - * @return int |
|
| 1197 | - * @throws EE_Error |
|
| 1198 | - * @throws ReflectionException |
|
| 1199 | - */ |
|
| 1200 | - public function qty($context = '') |
|
| 1201 | - { |
|
| 1202 | - switch ($context) { |
|
| 1203 | - case 'reg_limit': |
|
| 1204 | - return $this->real_quantity_on_ticket(); |
|
| 1205 | - case 'saleable': |
|
| 1206 | - return $this->real_quantity_on_ticket('saleable'); |
|
| 1207 | - default: |
|
| 1208 | - return $this->get_raw('TKT_qty'); |
|
| 1209 | - } |
|
| 1210 | - } |
|
| 1211 | - |
|
| 1212 | - |
|
| 1213 | - /** |
|
| 1214 | - * Gets ticket quantity |
|
| 1215 | - * |
|
| 1216 | - * @param string $context ticket quantity is somewhat subjective depending on the exact information sought |
|
| 1217 | - * therefore $context can be one of two values: 'reg_limit', or 'saleable' |
|
| 1218 | - * REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes |
|
| 1219 | - * SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and |
|
| 1220 | - * is therefore the truest measure of tickets that can be purchased at the moment |
|
| 1221 | - * @param int $DTT_ID the primary key for a particular datetime. |
|
| 1222 | - * set to 0 for all related datetimes |
|
| 1223 | - * @return int |
|
| 1224 | - * @throws EE_Error |
|
| 1225 | - * @throws ReflectionException |
|
| 1226 | - */ |
|
| 1227 | - public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0) |
|
| 1228 | - { |
|
| 1229 | - $raw = $this->get_raw('TKT_qty'); |
|
| 1230 | - // return immediately if it's zero |
|
| 1231 | - if ($raw === 0) { |
|
| 1232 | - return $raw; |
|
| 1233 | - } |
|
| 1234 | - // echo "\n\n<br />Ticket: " . $this->name() . '<br />'; |
|
| 1235 | - // ensure qty doesn't exceed raw value for THIS ticket |
|
| 1236 | - $qty = min(EE_INF, $raw); |
|
| 1237 | - // echo "\n . qty: " . $qty . '<br />'; |
|
| 1238 | - // calculate this ticket's total sales and reservations |
|
| 1239 | - $sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved(); |
|
| 1240 | - // echo "\n . sold: " . $this->sold() . '<br />'; |
|
| 1241 | - // echo "\n . reserved: " . $this->reserved() . '<br />'; |
|
| 1242 | - // echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />'; |
|
| 1243 | - // first we need to calculate the maximum number of tickets available for the datetime |
|
| 1244 | - // do we want data for one datetime or all of them ? |
|
| 1245 | - $query_params = $DTT_ID ? [['DTT_ID' => $DTT_ID]] : []; |
|
| 1246 | - $datetimes = $this->datetimes($query_params); |
|
| 1247 | - if (is_array($datetimes) && ! empty($datetimes)) { |
|
| 1248 | - foreach ($datetimes as $datetime) { |
|
| 1249 | - if ($datetime instanceof EE_Datetime) { |
|
| 1250 | - $datetime->refresh_from_db(); |
|
| 1251 | - // echo "\n . . datetime name: " . $datetime->name() . '<br />'; |
|
| 1252 | - // echo "\n . . datetime ID: " . $datetime->ID() . '<br />'; |
|
| 1253 | - // initialize with no restrictions for each datetime |
|
| 1254 | - // but adjust datetime qty based on datetime reg limit |
|
| 1255 | - $datetime_qty = min(EE_INF, $datetime->reg_limit()); |
|
| 1256 | - // echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />'; |
|
| 1257 | - // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />'; |
|
| 1258 | - // if we want the actual saleable amount, then we need to consider OTHER ticket sales |
|
| 1259 | - // and reservations for this datetime, that do NOT include sales and reservations |
|
| 1260 | - // for this ticket (so we add $this->sold() and $this->reserved() back in) |
|
| 1261 | - if ($context === 'saleable') { |
|
| 1262 | - $datetime_qty = max( |
|
| 1263 | - $datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket, |
|
| 1264 | - 0 |
|
| 1265 | - ); |
|
| 1266 | - // echo "\n . . . datetime sold: " . $datetime->sold() . '<br />'; |
|
| 1267 | - // echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />'; |
|
| 1268 | - // echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />'; |
|
| 1269 | - // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />'; |
|
| 1270 | - $datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0; |
|
| 1271 | - // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />'; |
|
| 1272 | - } |
|
| 1273 | - $qty = min($datetime_qty, $qty); |
|
| 1274 | - // echo "\n . . qty: " . $qty . '<br />'; |
|
| 1275 | - } |
|
| 1276 | - } |
|
| 1277 | - } |
|
| 1278 | - // NOW that we know the maximum number of tickets available for the datetime |
|
| 1279 | - // we can finally factor in the details for this specific ticket |
|
| 1280 | - if ($qty > 0 && $context === 'saleable') { |
|
| 1281 | - // and subtract the sales for THIS ticket |
|
| 1282 | - $qty = max($qty - $sold_and_reserved_for_this_ticket, 0); |
|
| 1283 | - // echo "\n . qty: " . $qty . '<br />'; |
|
| 1284 | - } |
|
| 1285 | - // echo "\nFINAL QTY: " . $qty . "<br /><br />"; |
|
| 1286 | - return $qty; |
|
| 1287 | - } |
|
| 1288 | - |
|
| 1289 | - |
|
| 1290 | - /** |
|
| 1291 | - * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes |
|
| 1292 | - * |
|
| 1293 | - * @param int $qty |
|
| 1294 | - * @return void |
|
| 1295 | - * @throws EE_Error |
|
| 1296 | - * @throws ReflectionException |
|
| 1297 | - */ |
|
| 1298 | - public function set_qty($qty) |
|
| 1299 | - { |
|
| 1300 | - $datetimes = $this->datetimes(); |
|
| 1301 | - foreach ($datetimes as $datetime) { |
|
| 1302 | - if ($datetime instanceof EE_Datetime) { |
|
| 1303 | - $qty = min($qty, $datetime->reg_limit()); |
|
| 1304 | - } |
|
| 1305 | - } |
|
| 1306 | - $this->set('TKT_qty', $qty); |
|
| 1307 | - } |
|
| 1308 | - |
|
| 1309 | - |
|
| 1310 | - /** |
|
| 1311 | - * Gets uses |
|
| 1312 | - * |
|
| 1313 | - * @return int |
|
| 1314 | - * @throws EE_Error |
|
| 1315 | - * @throws ReflectionException |
|
| 1316 | - */ |
|
| 1317 | - public function uses() |
|
| 1318 | - { |
|
| 1319 | - return $this->get('TKT_uses'); |
|
| 1320 | - } |
|
| 1321 | - |
|
| 1322 | - |
|
| 1323 | - /** |
|
| 1324 | - * Sets uses |
|
| 1325 | - * |
|
| 1326 | - * @param int $uses |
|
| 1327 | - * @return void |
|
| 1328 | - * @throws EE_Error |
|
| 1329 | - * @throws ReflectionException |
|
| 1330 | - */ |
|
| 1331 | - public function set_uses($uses) |
|
| 1332 | - { |
|
| 1333 | - $this->set('TKT_uses', $uses); |
|
| 1334 | - } |
|
| 1335 | - |
|
| 1336 | - |
|
| 1337 | - /** |
|
| 1338 | - * returns whether ticket is required or not. |
|
| 1339 | - * |
|
| 1340 | - * @return boolean |
|
| 1341 | - * @throws EE_Error |
|
| 1342 | - * @throws ReflectionException |
|
| 1343 | - */ |
|
| 1344 | - public function required() |
|
| 1345 | - { |
|
| 1346 | - return $this->get('TKT_required'); |
|
| 1347 | - } |
|
| 1348 | - |
|
| 1349 | - |
|
| 1350 | - /** |
|
| 1351 | - * sets the TKT_required property |
|
| 1352 | - * |
|
| 1353 | - * @param boolean $required |
|
| 1354 | - * @return void |
|
| 1355 | - * @throws EE_Error |
|
| 1356 | - * @throws ReflectionException |
|
| 1357 | - */ |
|
| 1358 | - public function set_required($required) |
|
| 1359 | - { |
|
| 1360 | - $this->set('TKT_required', $required); |
|
| 1361 | - } |
|
| 1362 | - |
|
| 1363 | - |
|
| 1364 | - /** |
|
| 1365 | - * Gets taxable |
|
| 1366 | - * |
|
| 1367 | - * @return boolean |
|
| 1368 | - * @throws EE_Error |
|
| 1369 | - * @throws ReflectionException |
|
| 1370 | - */ |
|
| 1371 | - public function taxable() |
|
| 1372 | - { |
|
| 1373 | - return $this->get('TKT_taxable'); |
|
| 1374 | - } |
|
| 1375 | - |
|
| 1376 | - |
|
| 1377 | - /** |
|
| 1378 | - * Sets taxable |
|
| 1379 | - * |
|
| 1380 | - * @param boolean $taxable |
|
| 1381 | - * @return void |
|
| 1382 | - * @throws EE_Error |
|
| 1383 | - * @throws ReflectionException |
|
| 1384 | - */ |
|
| 1385 | - public function set_taxable($taxable) |
|
| 1386 | - { |
|
| 1387 | - $this->set('TKT_taxable', $taxable); |
|
| 1388 | - } |
|
| 1389 | - |
|
| 1390 | - |
|
| 1391 | - /** |
|
| 1392 | - * Gets is_default |
|
| 1393 | - * |
|
| 1394 | - * @return boolean |
|
| 1395 | - * @throws EE_Error |
|
| 1396 | - * @throws ReflectionException |
|
| 1397 | - */ |
|
| 1398 | - public function is_default() |
|
| 1399 | - { |
|
| 1400 | - return $this->get('TKT_is_default'); |
|
| 1401 | - } |
|
| 1402 | - |
|
| 1403 | - |
|
| 1404 | - /** |
|
| 1405 | - * Sets is_default |
|
| 1406 | - * |
|
| 1407 | - * @param boolean $is_default |
|
| 1408 | - * @return void |
|
| 1409 | - * @throws EE_Error |
|
| 1410 | - * @throws ReflectionException |
|
| 1411 | - */ |
|
| 1412 | - public function set_is_default($is_default) |
|
| 1413 | - { |
|
| 1414 | - $this->set('TKT_is_default', $is_default); |
|
| 1415 | - } |
|
| 1416 | - |
|
| 1417 | - |
|
| 1418 | - /** |
|
| 1419 | - * Gets order |
|
| 1420 | - * |
|
| 1421 | - * @return int |
|
| 1422 | - * @throws EE_Error |
|
| 1423 | - * @throws ReflectionException |
|
| 1424 | - */ |
|
| 1425 | - public function order() |
|
| 1426 | - { |
|
| 1427 | - return $this->get('TKT_order'); |
|
| 1428 | - } |
|
| 1429 | - |
|
| 1430 | - |
|
| 1431 | - /** |
|
| 1432 | - * Sets order |
|
| 1433 | - * |
|
| 1434 | - * @param int $order |
|
| 1435 | - * @return void |
|
| 1436 | - * @throws EE_Error |
|
| 1437 | - * @throws ReflectionException |
|
| 1438 | - */ |
|
| 1439 | - public function set_order($order) |
|
| 1440 | - { |
|
| 1441 | - $this->set('TKT_order', $order); |
|
| 1442 | - } |
|
| 1443 | - |
|
| 1444 | - |
|
| 1445 | - /** |
|
| 1446 | - * Gets row |
|
| 1447 | - * |
|
| 1448 | - * @return int |
|
| 1449 | - * @throws EE_Error |
|
| 1450 | - * @throws ReflectionException |
|
| 1451 | - */ |
|
| 1452 | - public function row() |
|
| 1453 | - { |
|
| 1454 | - return $this->get('TKT_row'); |
|
| 1455 | - } |
|
| 1456 | - |
|
| 1457 | - |
|
| 1458 | - /** |
|
| 1459 | - * Sets row |
|
| 1460 | - * |
|
| 1461 | - * @param int $row |
|
| 1462 | - * @return void |
|
| 1463 | - * @throws EE_Error |
|
| 1464 | - * @throws ReflectionException |
|
| 1465 | - */ |
|
| 1466 | - public function set_row($row) |
|
| 1467 | - { |
|
| 1468 | - $this->set('TKT_row', $row); |
|
| 1469 | - } |
|
| 1470 | - |
|
| 1471 | - |
|
| 1472 | - /** |
|
| 1473 | - * Gets deleted |
|
| 1474 | - * |
|
| 1475 | - * @return boolean |
|
| 1476 | - * @throws EE_Error |
|
| 1477 | - * @throws ReflectionException |
|
| 1478 | - */ |
|
| 1479 | - public function deleted() |
|
| 1480 | - { |
|
| 1481 | - return $this->get('TKT_deleted'); |
|
| 1482 | - } |
|
| 1483 | - |
|
| 1484 | - |
|
| 1485 | - /** |
|
| 1486 | - * Sets deleted |
|
| 1487 | - * |
|
| 1488 | - * @param boolean $deleted |
|
| 1489 | - * @return void |
|
| 1490 | - * @throws EE_Error |
|
| 1491 | - * @throws ReflectionException |
|
| 1492 | - */ |
|
| 1493 | - public function set_deleted($deleted) |
|
| 1494 | - { |
|
| 1495 | - $this->set('TKT_deleted', $deleted); |
|
| 1496 | - } |
|
| 1497 | - |
|
| 1498 | - |
|
| 1499 | - /** |
|
| 1500 | - * Gets parent |
|
| 1501 | - * |
|
| 1502 | - * @return int |
|
| 1503 | - * @throws EE_Error |
|
| 1504 | - * @throws ReflectionException |
|
| 1505 | - */ |
|
| 1506 | - public function parent_ID() |
|
| 1507 | - { |
|
| 1508 | - return $this->get('TKT_parent'); |
|
| 1509 | - } |
|
| 1510 | - |
|
| 1511 | - |
|
| 1512 | - /** |
|
| 1513 | - * Sets parent |
|
| 1514 | - * |
|
| 1515 | - * @param int $parent |
|
| 1516 | - * @return void |
|
| 1517 | - * @throws EE_Error |
|
| 1518 | - * @throws ReflectionException |
|
| 1519 | - */ |
|
| 1520 | - public function set_parent_ID($parent) |
|
| 1521 | - { |
|
| 1522 | - $this->set('TKT_parent', $parent); |
|
| 1523 | - } |
|
| 1524 | - |
|
| 1525 | - |
|
| 1526 | - /** |
|
| 1527 | - * @return boolean |
|
| 1528 | - * @throws EE_Error |
|
| 1529 | - * @throws InvalidArgumentException |
|
| 1530 | - * @throws InvalidDataTypeException |
|
| 1531 | - * @throws InvalidInterfaceException |
|
| 1532 | - * @throws ReflectionException |
|
| 1533 | - */ |
|
| 1534 | - public function reverse_calculate() |
|
| 1535 | - { |
|
| 1536 | - return $this->get('TKT_reverse_calculate'); |
|
| 1537 | - } |
|
| 1538 | - |
|
| 1539 | - |
|
| 1540 | - /** |
|
| 1541 | - * @param boolean $reverse_calculate |
|
| 1542 | - * @throws EE_Error |
|
| 1543 | - * @throws InvalidArgumentException |
|
| 1544 | - * @throws InvalidDataTypeException |
|
| 1545 | - * @throws InvalidInterfaceException |
|
| 1546 | - * @throws ReflectionException |
|
| 1547 | - */ |
|
| 1548 | - public function set_reverse_calculate($reverse_calculate) |
|
| 1549 | - { |
|
| 1550 | - $this->set('TKT_reverse_calculate', $reverse_calculate); |
|
| 1551 | - } |
|
| 1552 | - |
|
| 1553 | - |
|
| 1554 | - /** |
|
| 1555 | - * Gets a string which is handy for showing in gateways etc that describes the ticket. |
|
| 1556 | - * |
|
| 1557 | - * @return string |
|
| 1558 | - * @throws EE_Error |
|
| 1559 | - * @throws ReflectionException |
|
| 1560 | - */ |
|
| 1561 | - public function name_and_info() |
|
| 1562 | - { |
|
| 1563 | - $times = []; |
|
| 1564 | - foreach ($this->datetimes() as $datetime) { |
|
| 1565 | - $times[] = $datetime->start_date_and_time(); |
|
| 1566 | - } |
|
| 1567 | - return $this->name() . ' @ ' . implode(', ', $times) . ' for ' . $this->pretty_price(); |
|
| 1568 | - } |
|
| 1569 | - |
|
| 1570 | - |
|
| 1571 | - /** |
|
| 1572 | - * Gets name |
|
| 1573 | - * |
|
| 1574 | - * @return string |
|
| 1575 | - * @throws EE_Error |
|
| 1576 | - * @throws ReflectionException |
|
| 1577 | - */ |
|
| 1578 | - public function name() |
|
| 1579 | - { |
|
| 1580 | - return $this->get('TKT_name'); |
|
| 1581 | - } |
|
| 1582 | - |
|
| 1583 | - |
|
| 1584 | - /** |
|
| 1585 | - * Gets price |
|
| 1586 | - * |
|
| 1587 | - * @return float |
|
| 1588 | - * @throws EE_Error |
|
| 1589 | - * @throws ReflectionException |
|
| 1590 | - */ |
|
| 1591 | - public function price() |
|
| 1592 | - { |
|
| 1593 | - return $this->get('TKT_price'); |
|
| 1594 | - } |
|
| 1595 | - |
|
| 1596 | - |
|
| 1597 | - /** |
|
| 1598 | - * Gets all the registrations for this ticket |
|
| 1599 | - * |
|
| 1600 | - * @param array $query_params |
|
| 1601 | - * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 1602 | - * @return EE_Registration[]|EE_Base_Class[] |
|
| 1603 | - * @throws EE_Error |
|
| 1604 | - * @throws ReflectionException |
|
| 1605 | - */ |
|
| 1606 | - public function registrations($query_params = []) |
|
| 1607 | - { |
|
| 1608 | - return $this->get_many_related('Registration', $query_params); |
|
| 1609 | - } |
|
| 1610 | - |
|
| 1611 | - |
|
| 1612 | - /** |
|
| 1613 | - * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket. |
|
| 1614 | - * |
|
| 1615 | - * @return int |
|
| 1616 | - * @throws EE_Error |
|
| 1617 | - * @throws ReflectionException |
|
| 1618 | - */ |
|
| 1619 | - public function update_tickets_sold() |
|
| 1620 | - { |
|
| 1621 | - $count_regs_for_this_ticket = $this->count_registrations( |
|
| 1622 | - [ |
|
| 1623 | - [ |
|
| 1624 | - 'STS_ID' => EEM_Registration::status_id_approved, |
|
| 1625 | - 'REG_deleted' => 0, |
|
| 1626 | - ], |
|
| 1627 | - ] |
|
| 1628 | - ); |
|
| 1629 | - $this->set_sold($count_regs_for_this_ticket); |
|
| 1630 | - $this->save(); |
|
| 1631 | - return $count_regs_for_this_ticket; |
|
| 1632 | - } |
|
| 1633 | - |
|
| 1634 | - |
|
| 1635 | - /** |
|
| 1636 | - * Counts the registrations for this ticket |
|
| 1637 | - * |
|
| 1638 | - * @param array $query_params |
|
| 1639 | - * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 1640 | - * @return int |
|
| 1641 | - * @throws EE_Error |
|
| 1642 | - * @throws ReflectionException |
|
| 1643 | - */ |
|
| 1644 | - public function count_registrations($query_params = []) |
|
| 1645 | - { |
|
| 1646 | - return $this->count_related('Registration', $query_params); |
|
| 1647 | - } |
|
| 1648 | - |
|
| 1649 | - |
|
| 1650 | - /** |
|
| 1651 | - * Implementation for EEI_Has_Icon interface method. |
|
| 1652 | - * |
|
| 1653 | - * @return string |
|
| 1654 | - * @see EEI_Visual_Representation for comments |
|
| 1655 | - */ |
|
| 1656 | - public function get_icon() |
|
| 1657 | - { |
|
| 1658 | - return '<span class="dashicons dashicons-tickets-alt"/>'; |
|
| 1659 | - } |
|
| 1660 | - |
|
| 1661 | - |
|
| 1662 | - /** |
|
| 1663 | - * Implementation of the EEI_Event_Relation interface method |
|
| 1664 | - * |
|
| 1665 | - * @return EE_Event |
|
| 1666 | - * @throws EE_Error |
|
| 1667 | - * @throws UnexpectedEntityException |
|
| 1668 | - * @throws ReflectionException |
|
| 1669 | - * @see EEI_Event_Relation for comments |
|
| 1670 | - */ |
|
| 1671 | - public function get_related_event() |
|
| 1672 | - { |
|
| 1673 | - // get one datetime to use for getting the event |
|
| 1674 | - $datetime = $this->first_datetime(); |
|
| 1675 | - if (! $datetime instanceof EE_Datetime) { |
|
| 1676 | - throw new UnexpectedEntityException( |
|
| 1677 | - $datetime, |
|
| 1678 | - 'EE_Datetime', |
|
| 1679 | - sprintf( |
|
| 1680 | - __('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'), |
|
| 1681 | - $this->name() |
|
| 1682 | - ) |
|
| 1683 | - ); |
|
| 1684 | - } |
|
| 1685 | - $event = $datetime->event(); |
|
| 1686 | - if (! $event instanceof EE_Event) { |
|
| 1687 | - throw new UnexpectedEntityException( |
|
| 1688 | - $event, |
|
| 1689 | - 'EE_Event', |
|
| 1690 | - sprintf( |
|
| 1691 | - __('The ticket (%s) is not associated with a valid event.', 'event_espresso'), |
|
| 1692 | - $this->name() |
|
| 1693 | - ) |
|
| 1694 | - ); |
|
| 1695 | - } |
|
| 1696 | - return $event; |
|
| 1697 | - } |
|
| 1698 | - |
|
| 1699 | - |
|
| 1700 | - /** |
|
| 1701 | - * Implementation of the EEI_Event_Relation interface method |
|
| 1702 | - * |
|
| 1703 | - * @return string |
|
| 1704 | - * @throws UnexpectedEntityException |
|
| 1705 | - * @throws EE_Error |
|
| 1706 | - * @throws ReflectionException |
|
| 1707 | - * @see EEI_Event_Relation for comments |
|
| 1708 | - */ |
|
| 1709 | - public function get_event_name() |
|
| 1710 | - { |
|
| 1711 | - $event = $this->get_related_event(); |
|
| 1712 | - return $event instanceof EE_Event ? $event->name() : ''; |
|
| 1713 | - } |
|
| 1714 | - |
|
| 1715 | - |
|
| 1716 | - /** |
|
| 1717 | - * Implementation of the EEI_Event_Relation interface method |
|
| 1718 | - * |
|
| 1719 | - * @return int |
|
| 1720 | - * @throws UnexpectedEntityException |
|
| 1721 | - * @throws EE_Error |
|
| 1722 | - * @throws ReflectionException |
|
| 1723 | - * @see EEI_Event_Relation for comments |
|
| 1724 | - */ |
|
| 1725 | - public function get_event_ID() |
|
| 1726 | - { |
|
| 1727 | - $event = $this->get_related_event(); |
|
| 1728 | - return $event instanceof EE_Event ? $event->ID() : 0; |
|
| 1729 | - } |
|
| 1730 | - |
|
| 1731 | - |
|
| 1732 | - /** |
|
| 1733 | - * This simply returns whether a ticket can be permanently deleted or not. |
|
| 1734 | - * The criteria for determining this is whether the ticket has any related registrations. |
|
| 1735 | - * If there are none then it can be permanently deleted. |
|
| 1736 | - * |
|
| 1737 | - * @return bool |
|
| 1738 | - * @throws EE_Error |
|
| 1739 | - * @throws ReflectionException |
|
| 1740 | - */ |
|
| 1741 | - public function is_permanently_deleteable() |
|
| 1742 | - { |
|
| 1743 | - return $this->count_registrations() === 0; |
|
| 1744 | - } |
|
| 1745 | - |
|
| 1746 | - |
|
| 1747 | - /** |
|
| 1748 | - * @return int |
|
| 1749 | - * @throws EE_Error |
|
| 1750 | - * @throws ReflectionException |
|
| 1751 | - * @since $VID:$ |
|
| 1752 | - */ |
|
| 1753 | - public function visibility(): int |
|
| 1754 | - { |
|
| 1755 | - return $this->get('TKT_visibility'); |
|
| 1756 | - } |
|
| 1757 | - |
|
| 1758 | - |
|
| 1759 | - /** |
|
| 1760 | - * @return int |
|
| 1761 | - * @throws EE_Error |
|
| 1762 | - * @throws ReflectionException |
|
| 1763 | - * @since $VID:$ |
|
| 1764 | - */ |
|
| 1765 | - public function isHidden(): int |
|
| 1766 | - { |
|
| 1767 | - return $this->visibility() === EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE; |
|
| 1768 | - } |
|
| 1769 | - |
|
| 1770 | - |
|
| 1771 | - /** |
|
| 1772 | - * @return int |
|
| 1773 | - * @throws EE_Error |
|
| 1774 | - * @throws ReflectionException |
|
| 1775 | - * @since $VID:$ |
|
| 1776 | - */ |
|
| 1777 | - public function isNotHidden(): int |
|
| 1778 | - { |
|
| 1779 | - return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE; |
|
| 1780 | - } |
|
| 1781 | - |
|
| 1782 | - |
|
| 1783 | - /** |
|
| 1784 | - * @return int |
|
| 1785 | - * @throws EE_Error |
|
| 1786 | - * @throws ReflectionException |
|
| 1787 | - * @since $VID:$ |
|
| 1788 | - */ |
|
| 1789 | - public function isPublicOnly(): int |
|
| 1790 | - { |
|
| 1791 | - return $this->isNotHidden() && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_PUBLIC_VALUE; |
|
| 1792 | - } |
|
| 1793 | - |
|
| 1794 | - |
|
| 1795 | - /** |
|
| 1796 | - * @return int |
|
| 1797 | - * @throws EE_Error |
|
| 1798 | - * @throws ReflectionException |
|
| 1799 | - * @since $VID:$ |
|
| 1800 | - */ |
|
| 1801 | - public function isMembersOnly(): int |
|
| 1802 | - { |
|
| 1803 | - return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_PUBLIC_VALUE |
|
| 1804 | - && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_MEMBERS_ONLY_VALUE; |
|
| 1805 | - } |
|
| 1806 | - |
|
| 1807 | - |
|
| 1808 | - /** |
|
| 1809 | - * @return int |
|
| 1810 | - * @throws EE_Error |
|
| 1811 | - * @throws ReflectionException |
|
| 1812 | - * @since $VID:$ |
|
| 1813 | - */ |
|
| 1814 | - public function isAdminsOnly(): int |
|
| 1815 | - { |
|
| 1816 | - return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_MEMBERS_ONLY_VALUE |
|
| 1817 | - && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_ADMINS_ONLY_VALUE; |
|
| 1818 | - } |
|
| 1819 | - |
|
| 1820 | - |
|
| 1821 | - /** |
|
| 1822 | - * @return int |
|
| 1823 | - * @throws EE_Error |
|
| 1824 | - * @throws ReflectionException |
|
| 1825 | - * @since $VID:$ |
|
| 1826 | - */ |
|
| 1827 | - public function isAdminUiOnly(): int |
|
| 1828 | - { |
|
| 1829 | - return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_ADMINS_ONLY_VALUE |
|
| 1830 | - && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_ADMIN_UI_ONLY_VALUE; |
|
| 1831 | - } |
|
| 1832 | - |
|
| 1833 | - |
|
| 1834 | - /** |
|
| 1835 | - * @param int $visibility |
|
| 1836 | - * @throws EE_Error |
|
| 1837 | - * @throws ReflectionException |
|
| 1838 | - * @since $VID:$ |
|
| 1839 | - */ |
|
| 1840 | - public function set_visibility(int $visibility) |
|
| 1841 | - { |
|
| 1842 | - |
|
| 1843 | - $ticket_visibility_options = $this->_model->ticketVisibilityOptions(); |
|
| 1844 | - $ticket_visibility = -1; |
|
| 1845 | - foreach ($ticket_visibility_options as $ticket_visibility_option) { |
|
| 1846 | - if ($visibility === $ticket_visibility_option) { |
|
| 1847 | - $ticket_visibility = $visibility; |
|
| 1848 | - } |
|
| 1849 | - } |
|
| 1850 | - if ($ticket_visibility === -1) { |
|
| 1851 | - throw new DomainException( |
|
| 1852 | - sprintf( |
|
| 1853 | - esc_html__( |
|
| 1854 | - 'The supplied ticket visibility setting of "%1$s" is not valid. It needs to match one of the keys in the following array:%2$s %3$s ', |
|
| 1855 | - 'event_espresso' |
|
| 1856 | - ), |
|
| 1857 | - $visibility, |
|
| 1858 | - '<br />', |
|
| 1859 | - var_export($ticket_visibility_options, true) |
|
| 1860 | - ) |
|
| 1861 | - ); |
|
| 1862 | - } |
|
| 1863 | - $this->set('TKT_visibility', $ticket_visibility); |
|
| 1864 | - } |
|
| 1865 | - |
|
| 1866 | - |
|
| 1867 | - /******************************************************************* |
|
| 18 | + /** |
|
| 19 | + * TicKet Archived: |
|
| 20 | + * constant used by ticket_status() to indicate that a ticket is archived |
|
| 21 | + * and no longer available for purchase |
|
| 22 | + */ |
|
| 23 | + const archived = 'TKA'; |
|
| 24 | + |
|
| 25 | + /** |
|
| 26 | + * TicKet Expired: |
|
| 27 | + * constant used by ticket_status() to indicate that a ticket is expired |
|
| 28 | + * and no longer available for purchase |
|
| 29 | + */ |
|
| 30 | + const expired = 'TKE'; |
|
| 31 | + |
|
| 32 | + /** |
|
| 33 | + * TicKet On sale: |
|
| 34 | + * constant used by ticket_status() to indicate that a ticket is On Sale |
|
| 35 | + * and IS available for purchase |
|
| 36 | + */ |
|
| 37 | + const onsale = 'TKO'; |
|
| 38 | + |
|
| 39 | + /** |
|
| 40 | + * TicKet Pending: |
|
| 41 | + * constant used by ticket_status() to indicate that a ticket is pending |
|
| 42 | + * and is NOT YET available for purchase |
|
| 43 | + */ |
|
| 44 | + const pending = 'TKP'; |
|
| 45 | + |
|
| 46 | + /** |
|
| 47 | + * TicKet Sold out: |
|
| 48 | + * constant used by ticket_status() to indicate that a ticket is sold out |
|
| 49 | + * and no longer available for purchases |
|
| 50 | + */ |
|
| 51 | + const sold_out = 'TKS'; |
|
| 52 | + |
|
| 53 | + /** |
|
| 54 | + * extra meta key for tracking ticket reservations |
|
| 55 | + * |
|
| 56 | + * @type string |
|
| 57 | + */ |
|
| 58 | + const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations'; |
|
| 59 | + |
|
| 60 | + /** |
|
| 61 | + * override of parent property |
|
| 62 | + * |
|
| 63 | + * @var EEM_Ticket |
|
| 64 | + */ |
|
| 65 | + protected $_model; |
|
| 66 | + |
|
| 67 | + /** |
|
| 68 | + * cached result from method of the same name |
|
| 69 | + * |
|
| 70 | + * @var float $_ticket_total_with_taxes |
|
| 71 | + */ |
|
| 72 | + private $_ticket_total_with_taxes; |
|
| 73 | + |
|
| 74 | + /** |
|
| 75 | + * @var TicketPriceModifiers |
|
| 76 | + */ |
|
| 77 | + protected $ticket_price_modifiers; |
|
| 78 | + |
|
| 79 | + |
|
| 80 | + /** |
|
| 81 | + * @param array $props_n_values incoming values |
|
| 82 | + * @param string $timezone incoming timezone (if not set the timezone set for the website will be |
|
| 83 | + * used.) |
|
| 84 | + * @param array $date_formats incoming date_formats in an array where the first value is the |
|
| 85 | + * date_format and the second value is the time format |
|
| 86 | + * @return EE_Ticket |
|
| 87 | + * @throws EE_Error |
|
| 88 | + * @throws ReflectionException |
|
| 89 | + */ |
|
| 90 | + public static function new_instance($props_n_values = [], $timezone = null, $date_formats = []) |
|
| 91 | + { |
|
| 92 | + $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats); |
|
| 93 | + return $has_object ?: new self($props_n_values, false, $timezone, $date_formats); |
|
| 94 | + } |
|
| 95 | + |
|
| 96 | + |
|
| 97 | + /** |
|
| 98 | + * @param array $props_n_values incoming values from the database |
|
| 99 | + * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
| 100 | + * the website will be used. |
|
| 101 | + * @return EE_Ticket |
|
| 102 | + * @throws EE_Error |
|
| 103 | + * @throws ReflectionException |
|
| 104 | + */ |
|
| 105 | + public static function new_instance_from_db($props_n_values = [], $timezone = null) |
|
| 106 | + { |
|
| 107 | + return new self($props_n_values, true, $timezone); |
|
| 108 | + } |
|
| 109 | + |
|
| 110 | + |
|
| 111 | + /** |
|
| 112 | + * @param array $fieldValues |
|
| 113 | + * @param false $bydb |
|
| 114 | + * @param string $timezone |
|
| 115 | + * @param array $date_formats |
|
| 116 | + * @throws EE_Error |
|
| 117 | + * @throws ReflectionException |
|
| 118 | + */ |
|
| 119 | + public function __construct($fieldValues = [], $bydb = false, $timezone = '', $date_formats = []) |
|
| 120 | + { |
|
| 121 | + parent::__construct($fieldValues, $bydb, $timezone, $date_formats); |
|
| 122 | + $this->ticket_price_modifiers = new TicketPriceModifiers($this); |
|
| 123 | + } |
|
| 124 | + |
|
| 125 | + |
|
| 126 | + /** |
|
| 127 | + * @return bool |
|
| 128 | + * @throws EE_Error |
|
| 129 | + * @throws ReflectionException |
|
| 130 | + */ |
|
| 131 | + public function parent() |
|
| 132 | + { |
|
| 133 | + return $this->get('TKT_parent'); |
|
| 134 | + } |
|
| 135 | + |
|
| 136 | + |
|
| 137 | + /** |
|
| 138 | + * return if a ticket has quantities available for purchase |
|
| 139 | + * |
|
| 140 | + * @param int $DTT_ID the primary key for a particular datetime |
|
| 141 | + * @return boolean |
|
| 142 | + * @throws EE_Error |
|
| 143 | + * @throws ReflectionException |
|
| 144 | + */ |
|
| 145 | + public function available($DTT_ID = 0) |
|
| 146 | + { |
|
| 147 | + // are we checking availability for a particular datetime ? |
|
| 148 | + if ($DTT_ID) { |
|
| 149 | + // get that datetime object |
|
| 150 | + $datetime = $this->get_first_related('Datetime', [['DTT_ID' => $DTT_ID]]); |
|
| 151 | + // if ticket sales for this datetime have exceeded the reg limit... |
|
| 152 | + if ($datetime instanceof EE_Datetime && $datetime->sold_out()) { |
|
| 153 | + return false; |
|
| 154 | + } |
|
| 155 | + } |
|
| 156 | + // datetime is still open for registration, but is this ticket sold out ? |
|
| 157 | + return $this->qty() < 1 || $this->qty() > $this->sold(); |
|
| 158 | + } |
|
| 159 | + |
|
| 160 | + |
|
| 161 | + /** |
|
| 162 | + * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired |
|
| 163 | + * |
|
| 164 | + * @param bool $display true = we'll return a localized string, otherwise we just return the value of the |
|
| 165 | + * relevant status const |
|
| 166 | + * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save |
|
| 167 | + * further processing |
|
| 168 | + * @return mixed status int if the display string isn't requested |
|
| 169 | + * @throws EE_Error |
|
| 170 | + * @throws ReflectionException |
|
| 171 | + */ |
|
| 172 | + public function ticket_status($display = false, $remaining = null) |
|
| 173 | + { |
|
| 174 | + $remaining = is_bool($remaining) ? $remaining : $this->is_remaining(); |
|
| 175 | + if (! $remaining) { |
|
| 176 | + return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out; |
|
| 177 | + } |
|
| 178 | + if ($this->get('TKT_deleted')) { |
|
| 179 | + return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived; |
|
| 180 | + } |
|
| 181 | + if ($this->is_expired()) { |
|
| 182 | + return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired; |
|
| 183 | + } |
|
| 184 | + if ($this->is_pending()) { |
|
| 185 | + return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending; |
|
| 186 | + } |
|
| 187 | + if ($this->is_on_sale()) { |
|
| 188 | + return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale; |
|
| 189 | + } |
|
| 190 | + return ''; |
|
| 191 | + } |
|
| 192 | + |
|
| 193 | + |
|
| 194 | + /** |
|
| 195 | + * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale |
|
| 196 | + * considering ALL the factors used for figuring that out. |
|
| 197 | + * |
|
| 198 | + * @param int $DTT_ID if an int above 0 is included here then we get a specific dtt. |
|
| 199 | + * @return boolean true = tickets remaining, false not. |
|
| 200 | + * @throws EE_Error |
|
| 201 | + * @throws ReflectionException |
|
| 202 | + */ |
|
| 203 | + public function is_remaining($DTT_ID = 0) |
|
| 204 | + { |
|
| 205 | + $num_remaining = $this->remaining($DTT_ID); |
|
| 206 | + if ($num_remaining === 0) { |
|
| 207 | + return false; |
|
| 208 | + } |
|
| 209 | + if ($num_remaining > 0 && $num_remaining < $this->min()) { |
|
| 210 | + return false; |
|
| 211 | + } |
|
| 212 | + return true; |
|
| 213 | + } |
|
| 214 | + |
|
| 215 | + |
|
| 216 | + /** |
|
| 217 | + * return the total number of tickets available for purchase |
|
| 218 | + * |
|
| 219 | + * @param int $DTT_ID the primary key for a particular datetime. |
|
| 220 | + * set to 0 for all related datetimes |
|
| 221 | + * @return int |
|
| 222 | + * @throws EE_Error |
|
| 223 | + * @throws ReflectionException |
|
| 224 | + */ |
|
| 225 | + public function remaining($DTT_ID = 0) |
|
| 226 | + { |
|
| 227 | + return $this->real_quantity_on_ticket('saleable', $DTT_ID); |
|
| 228 | + } |
|
| 229 | + |
|
| 230 | + |
|
| 231 | + /** |
|
| 232 | + * Gets min |
|
| 233 | + * |
|
| 234 | + * @return int |
|
| 235 | + * @throws EE_Error |
|
| 236 | + * @throws ReflectionException |
|
| 237 | + */ |
|
| 238 | + public function min() |
|
| 239 | + { |
|
| 240 | + return $this->get('TKT_min'); |
|
| 241 | + } |
|
| 242 | + |
|
| 243 | + |
|
| 244 | + /** |
|
| 245 | + * return if a ticket is no longer available cause its available dates have expired. |
|
| 246 | + * |
|
| 247 | + * @return boolean |
|
| 248 | + * @throws EE_Error |
|
| 249 | + * @throws ReflectionException |
|
| 250 | + */ |
|
| 251 | + public function is_expired() |
|
| 252 | + { |
|
| 253 | + return ($this->get_raw('TKT_end_date') < time()); |
|
| 254 | + } |
|
| 255 | + |
|
| 256 | + |
|
| 257 | + /** |
|
| 258 | + * Return if a ticket is yet to go on sale or not |
|
| 259 | + * |
|
| 260 | + * @return boolean |
|
| 261 | + * @throws EE_Error |
|
| 262 | + * @throws ReflectionException |
|
| 263 | + */ |
|
| 264 | + public function is_pending() |
|
| 265 | + { |
|
| 266 | + return ($this->get_raw('TKT_start_date') >= time()); |
|
| 267 | + } |
|
| 268 | + |
|
| 269 | + |
|
| 270 | + /** |
|
| 271 | + * Return if a ticket is on sale or not |
|
| 272 | + * |
|
| 273 | + * @return boolean |
|
| 274 | + * @throws EE_Error |
|
| 275 | + * @throws ReflectionException |
|
| 276 | + */ |
|
| 277 | + public function is_on_sale() |
|
| 278 | + { |
|
| 279 | + return ($this->get_raw('TKT_start_date') <= time() && $this->get_raw('TKT_end_date') >= time()); |
|
| 280 | + } |
|
| 281 | + |
|
| 282 | + |
|
| 283 | + /** |
|
| 284 | + * This returns the chronologically last datetime that this ticket is associated with |
|
| 285 | + * |
|
| 286 | + * @param string $date_format |
|
| 287 | + * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with |
|
| 288 | + * the end date ie: Jan 01 "to" Dec 31 |
|
| 289 | + * @return string |
|
| 290 | + * @throws EE_Error |
|
| 291 | + * @throws ReflectionException |
|
| 292 | + */ |
|
| 293 | + public function date_range($date_format = '', $conjunction = ' - ') |
|
| 294 | + { |
|
| 295 | + $date_format = ! empty($date_format) ? $date_format : $this->_dt_frmt; |
|
| 296 | + $first_date = $this->first_datetime() instanceof EE_Datetime |
|
| 297 | + ? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $date_format) |
|
| 298 | + : ''; |
|
| 299 | + $last_date = $this->last_datetime() instanceof EE_Datetime |
|
| 300 | + ? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $date_format) |
|
| 301 | + : ''; |
|
| 302 | + |
|
| 303 | + return $first_date && $last_date ? $first_date . $conjunction . $last_date : ''; |
|
| 304 | + } |
|
| 305 | + |
|
| 306 | + |
|
| 307 | + /** |
|
| 308 | + * This returns the chronologically first datetime that this ticket is associated with |
|
| 309 | + * |
|
| 310 | + * @return EE_Datetime |
|
| 311 | + * @throws EE_Error |
|
| 312 | + * @throws ReflectionException |
|
| 313 | + */ |
|
| 314 | + public function first_datetime() |
|
| 315 | + { |
|
| 316 | + $datetimes = $this->datetimes(['limit' => 1]); |
|
| 317 | + return reset($datetimes); |
|
| 318 | + } |
|
| 319 | + |
|
| 320 | + |
|
| 321 | + /** |
|
| 322 | + * Gets all the datetimes this ticket can be used for attending. |
|
| 323 | + * Unless otherwise specified, orders datetimes by start date. |
|
| 324 | + * |
|
| 325 | + * @param array $query_params |
|
| 326 | + * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 327 | + * @return EE_Datetime[]|EE_Base_Class[] |
|
| 328 | + * @throws EE_Error |
|
| 329 | + * @throws ReflectionException |
|
| 330 | + */ |
|
| 331 | + public function datetimes($query_params = []) |
|
| 332 | + { |
|
| 333 | + if (! isset($query_params['order_by'])) { |
|
| 334 | + $query_params['order_by']['DTT_order'] = 'ASC'; |
|
| 335 | + } |
|
| 336 | + return $this->get_many_related('Datetime', $query_params); |
|
| 337 | + } |
|
| 338 | + |
|
| 339 | + |
|
| 340 | + /** |
|
| 341 | + * This returns the chronologically last datetime that this ticket is associated with |
|
| 342 | + * |
|
| 343 | + * @return EE_Datetime |
|
| 344 | + * @throws EE_Error |
|
| 345 | + * @throws ReflectionException |
|
| 346 | + */ |
|
| 347 | + public function last_datetime() |
|
| 348 | + { |
|
| 349 | + $datetimes = $this->datetimes(['limit' => 1, 'order_by' => ['DTT_EVT_start' => 'DESC']]); |
|
| 350 | + return end($datetimes); |
|
| 351 | + } |
|
| 352 | + |
|
| 353 | + |
|
| 354 | + /** |
|
| 355 | + * This returns the total tickets sold depending on the given parameters. |
|
| 356 | + * |
|
| 357 | + * @param string $what Can be one of two options: 'ticket', 'datetime'. |
|
| 358 | + * 'ticket' = total ticket sales for all datetimes this ticket is related to |
|
| 359 | + * 'datetime' = total ticket sales for a specified datetime (required $dtt_id) |
|
| 360 | + * 'datetime' = total ticket sales in the datetime_ticket table. |
|
| 361 | + * If $dtt_id is not given then we return an array of sales indexed by datetime. |
|
| 362 | + * If $dtt_id IS given then we return the tickets sold for that given datetime. |
|
| 363 | + * @param int $dtt_id [optional] include the dtt_id with $what = 'datetime'. |
|
| 364 | + * @return mixed (array|int) how many tickets have sold |
|
| 365 | + * @throws EE_Error |
|
| 366 | + * @throws ReflectionException |
|
| 367 | + */ |
|
| 368 | + public function tickets_sold($what = 'ticket', $dtt_id = null) |
|
| 369 | + { |
|
| 370 | + $total = 0; |
|
| 371 | + $tickets_sold = $this->_all_tickets_sold(); |
|
| 372 | + switch ($what) { |
|
| 373 | + case 'ticket': |
|
| 374 | + return $tickets_sold['ticket']; |
|
| 375 | + |
|
| 376 | + case 'datetime': |
|
| 377 | + if (empty($tickets_sold['datetime'])) { |
|
| 378 | + return $total; |
|
| 379 | + } |
|
| 380 | + if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) { |
|
| 381 | + EE_Error::add_error( |
|
| 382 | + __( |
|
| 383 | + 'You\'ve requested the amount of tickets sold for a given ticket and datetime, however there are no records for the datetime id you included. Are you SURE that is a datetime related to this ticket?', |
|
| 384 | + 'event_espresso' |
|
| 385 | + ), |
|
| 386 | + __FILE__, |
|
| 387 | + __FUNCTION__, |
|
| 388 | + __LINE__ |
|
| 389 | + ); |
|
| 390 | + return $total; |
|
| 391 | + } |
|
| 392 | + return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ]; |
|
| 393 | + |
|
| 394 | + default: |
|
| 395 | + return $total; |
|
| 396 | + } |
|
| 397 | + } |
|
| 398 | + |
|
| 399 | + |
|
| 400 | + /** |
|
| 401 | + * This returns an array indexed by datetime_id for tickets sold with this ticket. |
|
| 402 | + * |
|
| 403 | + * @return EE_Ticket[] |
|
| 404 | + * @throws EE_Error |
|
| 405 | + * @throws ReflectionException |
|
| 406 | + */ |
|
| 407 | + protected function _all_tickets_sold() |
|
| 408 | + { |
|
| 409 | + $datetimes = $this->get_many_related('Datetime'); |
|
| 410 | + $tickets_sold = []; |
|
| 411 | + if (! empty($datetimes)) { |
|
| 412 | + foreach ($datetimes as $datetime) { |
|
| 413 | + $tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold'); |
|
| 414 | + } |
|
| 415 | + } |
|
| 416 | + // Tickets sold |
|
| 417 | + $tickets_sold['ticket'] = $this->sold(); |
|
| 418 | + return $tickets_sold; |
|
| 419 | + } |
|
| 420 | + |
|
| 421 | + |
|
| 422 | + /** |
|
| 423 | + * This returns the base price object for the ticket. |
|
| 424 | + * |
|
| 425 | + * @param bool $return_array whether to return as an array indexed by price id or just the object. |
|
| 426 | + * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[] |
|
| 427 | + * @throws EE_Error |
|
| 428 | + * @throws ReflectionException |
|
| 429 | + */ |
|
| 430 | + public function base_price(bool $return_array = false) |
|
| 431 | + { |
|
| 432 | + $base_price = $this->ticket_price_modifiers->getBasePrice(); |
|
| 433 | + if (! empty($base_price)) { |
|
| 434 | + return $return_array ? $base_price : reset($base_price); |
|
| 435 | + } |
|
| 436 | + $_where = ['Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price]; |
|
| 437 | + return $return_array |
|
| 438 | + ? $this->get_many_related('Price', [$_where]) |
|
| 439 | + : $this->get_first_related('Price', [$_where]); |
|
| 440 | + } |
|
| 441 | + |
|
| 442 | + |
|
| 443 | + /** |
|
| 444 | + * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price) |
|
| 445 | + * |
|
| 446 | + * @return EE_Price[] |
|
| 447 | + * @throws EE_Error |
|
| 448 | + * @throws ReflectionException |
|
| 449 | + */ |
|
| 450 | + public function price_modifiers(): array |
|
| 451 | + { |
|
| 452 | + $price_modifiers = $this->usesGlobalTaxes() |
|
| 453 | + ? $this->ticket_price_modifiers->getAllDiscountAndSurchargeModifiersForTicket() |
|
| 454 | + : $this->ticket_price_modifiers ->getAllModifiersForTicket(); |
|
| 455 | + if (! empty($price_modifiers)) { |
|
| 456 | + return $price_modifiers; |
|
| 457 | + } |
|
| 458 | + return $this->prices( |
|
| 459 | + [ |
|
| 460 | + [ |
|
| 461 | + 'Price_Type.PBT_ID' => [ |
|
| 462 | + 'NOT IN', |
|
| 463 | + [EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax], |
|
| 464 | + ] |
|
| 465 | + ] |
|
| 466 | + ] |
|
| 467 | + ); |
|
| 468 | + } |
|
| 469 | + |
|
| 470 | + |
|
| 471 | + /** |
|
| 472 | + * This returns ONLY the TAX price modifiers for the ticket |
|
| 473 | + * |
|
| 474 | + * @return EE_Price[] |
|
| 475 | + * @throws EE_Error |
|
| 476 | + * @throws ReflectionException |
|
| 477 | + */ |
|
| 478 | + public function tax_price_modifiers(): array |
|
| 479 | + { |
|
| 480 | + $tax_price_modifiers = $this->ticket_price_modifiers->getAllTaxesForTicket(); |
|
| 481 | + if (! empty($tax_price_modifiers)) { |
|
| 482 | + return $tax_price_modifiers; |
|
| 483 | + } |
|
| 484 | + return $this->prices([['Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax]]); |
|
| 485 | + } |
|
| 486 | + |
|
| 487 | + |
|
| 488 | + /** |
|
| 489 | + * Gets all the prices that combine to form the final price of this ticket |
|
| 490 | + * |
|
| 491 | + * @param array $query_params |
|
| 492 | + * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 493 | + * @return EE_Price[]|EE_Base_Class[] |
|
| 494 | + * @throws EE_Error |
|
| 495 | + * @throws ReflectionException |
|
| 496 | + */ |
|
| 497 | + public function prices(array $query_params = []): array |
|
| 498 | + { |
|
| 499 | + if (! isset($query_params['order_by'])) { |
|
| 500 | + $query_params['order_by']['PRC_order'] = 'ASC'; |
|
| 501 | + } |
|
| 502 | + return $this->get_many_related('Price', $query_params); |
|
| 503 | + } |
|
| 504 | + |
|
| 505 | + |
|
| 506 | + /** |
|
| 507 | + * Gets all the ticket datetimes (ie, relations between datetimes and tickets) |
|
| 508 | + * |
|
| 509 | + * @param array $query_params |
|
| 510 | + * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 511 | + * @return EE_Datetime_Ticket|EE_Base_Class[] |
|
| 512 | + * @throws EE_Error |
|
| 513 | + * @throws ReflectionException |
|
| 514 | + */ |
|
| 515 | + public function datetime_tickets($query_params = []) |
|
| 516 | + { |
|
| 517 | + return $this->get_many_related('Datetime_Ticket', $query_params); |
|
| 518 | + } |
|
| 519 | + |
|
| 520 | + |
|
| 521 | + /** |
|
| 522 | + * Gets all the datetimes from the db ordered by DTT_order |
|
| 523 | + * |
|
| 524 | + * @param boolean $show_expired |
|
| 525 | + * @param boolean $show_deleted |
|
| 526 | + * @return EE_Datetime[] |
|
| 527 | + * @throws EE_Error |
|
| 528 | + * @throws ReflectionException |
|
| 529 | + */ |
|
| 530 | + public function datetimes_ordered($show_expired = true, $show_deleted = false) |
|
| 531 | + { |
|
| 532 | + return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order( |
|
| 533 | + $this->ID(), |
|
| 534 | + $show_expired, |
|
| 535 | + $show_deleted |
|
| 536 | + ); |
|
| 537 | + } |
|
| 538 | + |
|
| 539 | + |
|
| 540 | + /** |
|
| 541 | + * Gets ID |
|
| 542 | + * |
|
| 543 | + * @return int |
|
| 544 | + * @throws EE_Error |
|
| 545 | + * @throws ReflectionException |
|
| 546 | + */ |
|
| 547 | + public function ID() |
|
| 548 | + { |
|
| 549 | + return $this->get('TKT_ID'); |
|
| 550 | + } |
|
| 551 | + |
|
| 552 | + |
|
| 553 | + /** |
|
| 554 | + * get the author of the ticket. |
|
| 555 | + * |
|
| 556 | + * @return int |
|
| 557 | + * @throws EE_Error |
|
| 558 | + * @throws ReflectionException |
|
| 559 | + * @since 4.5.0 |
|
| 560 | + */ |
|
| 561 | + public function wp_user() |
|
| 562 | + { |
|
| 563 | + return $this->get('TKT_wp_user'); |
|
| 564 | + } |
|
| 565 | + |
|
| 566 | + |
|
| 567 | + /** |
|
| 568 | + * Gets the template for the ticket |
|
| 569 | + * |
|
| 570 | + * @return EE_Ticket_Template|EE_Base_Class |
|
| 571 | + * @throws EE_Error |
|
| 572 | + * @throws ReflectionException |
|
| 573 | + */ |
|
| 574 | + public function template() |
|
| 575 | + { |
|
| 576 | + return $this->get_first_related('Ticket_Template'); |
|
| 577 | + } |
|
| 578 | + |
|
| 579 | + |
|
| 580 | + /** |
|
| 581 | + * Simply returns an array of EE_Price objects that are taxes. |
|
| 582 | + * |
|
| 583 | + * @return EE_Price[] |
|
| 584 | + * @throws EE_Error |
|
| 585 | + * @throws ReflectionException |
|
| 586 | + */ |
|
| 587 | + public function get_ticket_taxes_for_admin(): array |
|
| 588 | + { |
|
| 589 | + return $this->usesGlobalTaxes() ? EE_Taxes::get_taxes_for_admin() : $this->tax_price_modifiers(); |
|
| 590 | + } |
|
| 591 | + |
|
| 592 | + |
|
| 593 | + /** |
|
| 594 | + * alias of taxable() to better indicate that ticket uses the legacy method of applying default "global" taxes |
|
| 595 | + * as opposed to having tax price modifiers added directly to each ticket |
|
| 596 | + * |
|
| 597 | + * @return bool |
|
| 598 | + * @throws EE_Error |
|
| 599 | + * @throws ReflectionException |
|
| 600 | + * @since $VID:$ |
|
| 601 | + */ |
|
| 602 | + public function usesGlobalTaxes(): bool |
|
| 603 | + { |
|
| 604 | + return $this->taxable(); |
|
| 605 | + } |
|
| 606 | + |
|
| 607 | + |
|
| 608 | + /** |
|
| 609 | + * @return float |
|
| 610 | + * @throws EE_Error |
|
| 611 | + * @throws ReflectionException |
|
| 612 | + */ |
|
| 613 | + public function ticket_price() |
|
| 614 | + { |
|
| 615 | + return $this->get('TKT_price'); |
|
| 616 | + } |
|
| 617 | + |
|
| 618 | + |
|
| 619 | + /** |
|
| 620 | + * @return mixed |
|
| 621 | + * @throws EE_Error |
|
| 622 | + * @throws ReflectionException |
|
| 623 | + */ |
|
| 624 | + public function pretty_price() |
|
| 625 | + { |
|
| 626 | + return $this->get_pretty('TKT_price'); |
|
| 627 | + } |
|
| 628 | + |
|
| 629 | + |
|
| 630 | + /** |
|
| 631 | + * @return bool |
|
| 632 | + * @throws EE_Error |
|
| 633 | + * @throws ReflectionException |
|
| 634 | + */ |
|
| 635 | + public function is_free() |
|
| 636 | + { |
|
| 637 | + return $this->get_ticket_total_with_taxes() === (float) 0; |
|
| 638 | + } |
|
| 639 | + |
|
| 640 | + |
|
| 641 | + /** |
|
| 642 | + * get_ticket_total_with_taxes |
|
| 643 | + * |
|
| 644 | + * @param bool $no_cache |
|
| 645 | + * @return float |
|
| 646 | + * @throws EE_Error |
|
| 647 | + * @throws ReflectionException |
|
| 648 | + */ |
|
| 649 | + public function get_ticket_total_with_taxes($no_cache = false) |
|
| 650 | + { |
|
| 651 | + if ($this->_ticket_total_with_taxes === null || $no_cache) { |
|
| 652 | + $this->_ticket_total_with_taxes = $this->usesGlobalTaxes() |
|
| 653 | + ? $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin() |
|
| 654 | + : $this->ticket_price(); |
|
| 655 | + } |
|
| 656 | + return (float) $this->_ticket_total_with_taxes; |
|
| 657 | + } |
|
| 658 | + |
|
| 659 | + |
|
| 660 | + /** |
|
| 661 | + * @throws EE_Error |
|
| 662 | + * @throws ReflectionException |
|
| 663 | + */ |
|
| 664 | + public function ensure_TKT_Price_correct() |
|
| 665 | + { |
|
| 666 | + $this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this)); |
|
| 667 | + $this->save(); |
|
| 668 | + } |
|
| 669 | + |
|
| 670 | + |
|
| 671 | + /** |
|
| 672 | + * @return float |
|
| 673 | + * @throws EE_Error |
|
| 674 | + * @throws ReflectionException |
|
| 675 | + */ |
|
| 676 | + public function get_ticket_subtotal() |
|
| 677 | + { |
|
| 678 | + return EE_Taxes::get_subtotal_for_admin($this); |
|
| 679 | + } |
|
| 680 | + |
|
| 681 | + |
|
| 682 | + /** |
|
| 683 | + * Returns the total taxes applied to this ticket |
|
| 684 | + * |
|
| 685 | + * @return float |
|
| 686 | + * @throws EE_Error |
|
| 687 | + * @throws ReflectionException |
|
| 688 | + */ |
|
| 689 | + public function get_ticket_taxes_total_for_admin() |
|
| 690 | + { |
|
| 691 | + return EE_Taxes::get_total_taxes_for_admin($this); |
|
| 692 | + } |
|
| 693 | + |
|
| 694 | + |
|
| 695 | + /** |
|
| 696 | + * Sets name |
|
| 697 | + * |
|
| 698 | + * @param string $name |
|
| 699 | + * @throws EE_Error |
|
| 700 | + * @throws ReflectionException |
|
| 701 | + */ |
|
| 702 | + public function set_name($name) |
|
| 703 | + { |
|
| 704 | + $this->set('TKT_name', $name); |
|
| 705 | + } |
|
| 706 | + |
|
| 707 | + |
|
| 708 | + /** |
|
| 709 | + * Gets description |
|
| 710 | + * |
|
| 711 | + * @return string |
|
| 712 | + * @throws EE_Error |
|
| 713 | + * @throws ReflectionException |
|
| 714 | + */ |
|
| 715 | + public function description() |
|
| 716 | + { |
|
| 717 | + return $this->get('TKT_description'); |
|
| 718 | + } |
|
| 719 | + |
|
| 720 | + |
|
| 721 | + /** |
|
| 722 | + * Sets description |
|
| 723 | + * |
|
| 724 | + * @param string $description |
|
| 725 | + * @throws EE_Error |
|
| 726 | + * @throws ReflectionException |
|
| 727 | + */ |
|
| 728 | + public function set_description($description) |
|
| 729 | + { |
|
| 730 | + $this->set('TKT_description', $description); |
|
| 731 | + } |
|
| 732 | + |
|
| 733 | + |
|
| 734 | + /** |
|
| 735 | + * Gets start_date |
|
| 736 | + * |
|
| 737 | + * @param string $date_format |
|
| 738 | + * @param string $time_format |
|
| 739 | + * @return string |
|
| 740 | + * @throws EE_Error |
|
| 741 | + * @throws ReflectionException |
|
| 742 | + */ |
|
| 743 | + public function start_date($date_format = '', $time_format = '') |
|
| 744 | + { |
|
| 745 | + return $this->_get_datetime('TKT_start_date', $date_format, $time_format); |
|
| 746 | + } |
|
| 747 | + |
|
| 748 | + |
|
| 749 | + /** |
|
| 750 | + * Sets start_date |
|
| 751 | + * |
|
| 752 | + * @param string $start_date |
|
| 753 | + * @return void |
|
| 754 | + * @throws EE_Error |
|
| 755 | + * @throws ReflectionException |
|
| 756 | + */ |
|
| 757 | + public function set_start_date($start_date) |
|
| 758 | + { |
|
| 759 | + $this->_set_date_time('B', $start_date, 'TKT_start_date'); |
|
| 760 | + } |
|
| 761 | + |
|
| 762 | + |
|
| 763 | + /** |
|
| 764 | + * Gets end_date |
|
| 765 | + * |
|
| 766 | + * @param string $date_format |
|
| 767 | + * @param string $time_format |
|
| 768 | + * @return string |
|
| 769 | + * @throws EE_Error |
|
| 770 | + * @throws ReflectionException |
|
| 771 | + */ |
|
| 772 | + public function end_date($date_format = '', $time_format = '') |
|
| 773 | + { |
|
| 774 | + return $this->_get_datetime('TKT_end_date', $date_format, $time_format); |
|
| 775 | + } |
|
| 776 | + |
|
| 777 | + |
|
| 778 | + /** |
|
| 779 | + * Sets end_date |
|
| 780 | + * |
|
| 781 | + * @param string $end_date |
|
| 782 | + * @return void |
|
| 783 | + * @throws EE_Error |
|
| 784 | + * @throws ReflectionException |
|
| 785 | + */ |
|
| 786 | + public function set_end_date($end_date) |
|
| 787 | + { |
|
| 788 | + $this->_set_date_time('B', $end_date, 'TKT_end_date'); |
|
| 789 | + } |
|
| 790 | + |
|
| 791 | + |
|
| 792 | + /** |
|
| 793 | + * Sets sell until time |
|
| 794 | + * |
|
| 795 | + * @param string $time a string representation of the sell until time (ex 9am or 7:30pm) |
|
| 796 | + * @throws EE_Error |
|
| 797 | + * @throws ReflectionException |
|
| 798 | + * @since 4.5.0 |
|
| 799 | + */ |
|
| 800 | + public function set_end_time($time) |
|
| 801 | + { |
|
| 802 | + $this->_set_time_for($time, 'TKT_end_date'); |
|
| 803 | + } |
|
| 804 | + |
|
| 805 | + |
|
| 806 | + /** |
|
| 807 | + * Sets min |
|
| 808 | + * |
|
| 809 | + * @param int $min |
|
| 810 | + * @return void |
|
| 811 | + * @throws EE_Error |
|
| 812 | + * @throws ReflectionException |
|
| 813 | + */ |
|
| 814 | + public function set_min($min) |
|
| 815 | + { |
|
| 816 | + $this->set('TKT_min', $min); |
|
| 817 | + } |
|
| 818 | + |
|
| 819 | + |
|
| 820 | + /** |
|
| 821 | + * Gets max |
|
| 822 | + * |
|
| 823 | + * @return int |
|
| 824 | + * @throws EE_Error |
|
| 825 | + * @throws ReflectionException |
|
| 826 | + */ |
|
| 827 | + public function max() |
|
| 828 | + { |
|
| 829 | + return $this->get('TKT_max'); |
|
| 830 | + } |
|
| 831 | + |
|
| 832 | + |
|
| 833 | + /** |
|
| 834 | + * Sets max |
|
| 835 | + * |
|
| 836 | + * @param int $max |
|
| 837 | + * @return void |
|
| 838 | + * @throws EE_Error |
|
| 839 | + * @throws ReflectionException |
|
| 840 | + */ |
|
| 841 | + public function set_max($max) |
|
| 842 | + { |
|
| 843 | + $this->set('TKT_max', $max); |
|
| 844 | + } |
|
| 845 | + |
|
| 846 | + |
|
| 847 | + /** |
|
| 848 | + * Sets price |
|
| 849 | + * |
|
| 850 | + * @param float $price |
|
| 851 | + * @return void |
|
| 852 | + * @throws EE_Error |
|
| 853 | + * @throws ReflectionException |
|
| 854 | + */ |
|
| 855 | + public function set_price($price) |
|
| 856 | + { |
|
| 857 | + $this->set('TKT_price', $price); |
|
| 858 | + } |
|
| 859 | + |
|
| 860 | + |
|
| 861 | + /** |
|
| 862 | + * Gets sold |
|
| 863 | + * |
|
| 864 | + * @return int |
|
| 865 | + * @throws EE_Error |
|
| 866 | + * @throws ReflectionException |
|
| 867 | + */ |
|
| 868 | + public function sold() |
|
| 869 | + { |
|
| 870 | + return $this->get_raw('TKT_sold'); |
|
| 871 | + } |
|
| 872 | + |
|
| 873 | + |
|
| 874 | + /** |
|
| 875 | + * Sets sold |
|
| 876 | + * |
|
| 877 | + * @param int $sold |
|
| 878 | + * @return void |
|
| 879 | + * @throws EE_Error |
|
| 880 | + * @throws ReflectionException |
|
| 881 | + */ |
|
| 882 | + public function set_sold($sold) |
|
| 883 | + { |
|
| 884 | + // sold can not go below zero |
|
| 885 | + $sold = max(0, $sold); |
|
| 886 | + $this->set('TKT_sold', $sold); |
|
| 887 | + } |
|
| 888 | + |
|
| 889 | + |
|
| 890 | + /** |
|
| 891 | + * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its |
|
| 892 | + * associated datetimes. |
|
| 893 | + * |
|
| 894 | + * @param int $qty |
|
| 895 | + * @return boolean |
|
| 896 | + * @throws EE_Error |
|
| 897 | + * @throws InvalidArgumentException |
|
| 898 | + * @throws InvalidDataTypeException |
|
| 899 | + * @throws InvalidInterfaceException |
|
| 900 | + * @throws ReflectionException |
|
| 901 | + * @since 4.9.80.p |
|
| 902 | + */ |
|
| 903 | + public function increaseSold($qty = 1) |
|
| 904 | + { |
|
| 905 | + $qty = absint($qty); |
|
| 906 | + // increment sold and decrement reserved datetime quantities simultaneously |
|
| 907 | + // don't worry about failures, because they must have already had a spot reserved |
|
| 908 | + $this->increaseSoldForDatetimes($qty); |
|
| 909 | + // Increment and decrement ticket quantities simultaneously |
|
| 910 | + $success = $this->adjustNumericFieldsInDb( |
|
| 911 | + [ |
|
| 912 | + 'TKT_reserved' => $qty * -1, |
|
| 913 | + 'TKT_sold' => $qty, |
|
| 914 | + ] |
|
| 915 | + ); |
|
| 916 | + do_action( |
|
| 917 | + 'AHEE__EE_Ticket__increase_sold', |
|
| 918 | + $this, |
|
| 919 | + $qty, |
|
| 920 | + $this->sold(), |
|
| 921 | + $success |
|
| 922 | + ); |
|
| 923 | + return $success; |
|
| 924 | + } |
|
| 925 | + |
|
| 926 | + |
|
| 927 | + /** |
|
| 928 | + * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty. |
|
| 929 | + * |
|
| 930 | + * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved |
|
| 931 | + * counts), Negative means to decreases old counts (and increase reserved counts). |
|
| 932 | + * @param EE_Datetime[] $datetimes |
|
| 933 | + * @throws EE_Error |
|
| 934 | + * @throws InvalidArgumentException |
|
| 935 | + * @throws InvalidDataTypeException |
|
| 936 | + * @throws InvalidInterfaceException |
|
| 937 | + * @throws ReflectionException |
|
| 938 | + * @since 4.9.80.p |
|
| 939 | + */ |
|
| 940 | + protected function increaseSoldForDatetimes($qty, array $datetimes = []) |
|
| 941 | + { |
|
| 942 | + $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes(); |
|
| 943 | + foreach ($datetimes as $datetime) { |
|
| 944 | + $datetime->increaseSold($qty); |
|
| 945 | + } |
|
| 946 | + } |
|
| 947 | + |
|
| 948 | + |
|
| 949 | + /** |
|
| 950 | + * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the |
|
| 951 | + * DB and then updates the model objects. |
|
| 952 | + * Does not affect the reserved counts. |
|
| 953 | + * |
|
| 954 | + * @param int $qty |
|
| 955 | + * @return boolean |
|
| 956 | + * @throws EE_Error |
|
| 957 | + * @throws InvalidArgumentException |
|
| 958 | + * @throws InvalidDataTypeException |
|
| 959 | + * @throws InvalidInterfaceException |
|
| 960 | + * @throws ReflectionException |
|
| 961 | + * @since 4.9.80.p |
|
| 962 | + */ |
|
| 963 | + public function decreaseSold($qty = 1) |
|
| 964 | + { |
|
| 965 | + $qty = absint($qty); |
|
| 966 | + $this->decreaseSoldForDatetimes($qty); |
|
| 967 | + $success = $this->adjustNumericFieldsInDb( |
|
| 968 | + [ |
|
| 969 | + 'TKT_sold' => $qty * -1, |
|
| 970 | + ] |
|
| 971 | + ); |
|
| 972 | + do_action( |
|
| 973 | + 'AHEE__EE_Ticket__decrease_sold', |
|
| 974 | + $this, |
|
| 975 | + $qty, |
|
| 976 | + $this->sold(), |
|
| 977 | + $success |
|
| 978 | + ); |
|
| 979 | + return $success; |
|
| 980 | + } |
|
| 981 | + |
|
| 982 | + |
|
| 983 | + /** |
|
| 984 | + * Decreases sold on related datetimes |
|
| 985 | + * |
|
| 986 | + * @param int $qty |
|
| 987 | + * @param EE_Datetime[] $datetimes |
|
| 988 | + * @return void |
|
| 989 | + * @throws EE_Error |
|
| 990 | + * @throws InvalidArgumentException |
|
| 991 | + * @throws InvalidDataTypeException |
|
| 992 | + * @throws InvalidInterfaceException |
|
| 993 | + * @throws ReflectionException |
|
| 994 | + * @since 4.9.80.p |
|
| 995 | + */ |
|
| 996 | + protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = []) |
|
| 997 | + { |
|
| 998 | + $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes(); |
|
| 999 | + if (is_array($datetimes)) { |
|
| 1000 | + foreach ($datetimes as $datetime) { |
|
| 1001 | + if ($datetime instanceof EE_Datetime) { |
|
| 1002 | + $datetime->decreaseSold($qty); |
|
| 1003 | + } |
|
| 1004 | + } |
|
| 1005 | + } |
|
| 1006 | + } |
|
| 1007 | + |
|
| 1008 | + |
|
| 1009 | + /** |
|
| 1010 | + * Gets qty of reserved tickets |
|
| 1011 | + * |
|
| 1012 | + * @return int |
|
| 1013 | + * @throws EE_Error |
|
| 1014 | + * @throws ReflectionException |
|
| 1015 | + */ |
|
| 1016 | + public function reserved() |
|
| 1017 | + { |
|
| 1018 | + return $this->get_raw('TKT_reserved'); |
|
| 1019 | + } |
|
| 1020 | + |
|
| 1021 | + |
|
| 1022 | + /** |
|
| 1023 | + * Sets reserved |
|
| 1024 | + * |
|
| 1025 | + * @param int $reserved |
|
| 1026 | + * @return void |
|
| 1027 | + * @throws EE_Error |
|
| 1028 | + * @throws ReflectionException |
|
| 1029 | + */ |
|
| 1030 | + public function set_reserved($reserved) |
|
| 1031 | + { |
|
| 1032 | + // reserved can not go below zero |
|
| 1033 | + $reserved = max(0, (int) $reserved); |
|
| 1034 | + $this->set('TKT_reserved', $reserved); |
|
| 1035 | + } |
|
| 1036 | + |
|
| 1037 | + |
|
| 1038 | + /** |
|
| 1039 | + * Increments reserved by amount passed by $qty, and persists it immediately to the database. |
|
| 1040 | + * |
|
| 1041 | + * @param int $qty |
|
| 1042 | + * @param string $source |
|
| 1043 | + * @return bool whether we successfully reserved the ticket or not. |
|
| 1044 | + * @throws EE_Error |
|
| 1045 | + * @throws InvalidArgumentException |
|
| 1046 | + * @throws ReflectionException |
|
| 1047 | + * @throws InvalidDataTypeException |
|
| 1048 | + * @throws InvalidInterfaceException |
|
| 1049 | + * @since 4.9.80.p |
|
| 1050 | + */ |
|
| 1051 | + public function increaseReserved($qty = 1, $source = 'unknown') |
|
| 1052 | + { |
|
| 1053 | + $qty = absint($qty); |
|
| 1054 | + do_action( |
|
| 1055 | + 'AHEE__EE_Ticket__increase_reserved__begin', |
|
| 1056 | + $this, |
|
| 1057 | + $qty, |
|
| 1058 | + $source |
|
| 1059 | + ); |
|
| 1060 | + $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}"); |
|
| 1061 | + $success = false; |
|
| 1062 | + $datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty); |
|
| 1063 | + if ($datetimes_adjusted_successfully) { |
|
| 1064 | + $success = $this->incrementFieldConditionallyInDb( |
|
| 1065 | + 'TKT_reserved', |
|
| 1066 | + 'TKT_sold', |
|
| 1067 | + 'TKT_qty', |
|
| 1068 | + $qty |
|
| 1069 | + ); |
|
| 1070 | + if (! $success) { |
|
| 1071 | + // The datetimes were successfully bumped, but not the |
|
| 1072 | + // ticket. So we need to manually rollback the datetimes. |
|
| 1073 | + $this->decreaseReservedForDatetimes($qty); |
|
| 1074 | + } |
|
| 1075 | + } |
|
| 1076 | + do_action( |
|
| 1077 | + 'AHEE__EE_Ticket__increase_reserved', |
|
| 1078 | + $this, |
|
| 1079 | + $qty, |
|
| 1080 | + $this->reserved(), |
|
| 1081 | + $success |
|
| 1082 | + ); |
|
| 1083 | + return $success; |
|
| 1084 | + } |
|
| 1085 | + |
|
| 1086 | + |
|
| 1087 | + /** |
|
| 1088 | + * Increases reserved counts on related datetimes |
|
| 1089 | + * |
|
| 1090 | + * @param int $qty |
|
| 1091 | + * @param EE_Datetime[] $datetimes |
|
| 1092 | + * @return boolean indicating success |
|
| 1093 | + * @throws EE_Error |
|
| 1094 | + * @throws InvalidArgumentException |
|
| 1095 | + * @throws InvalidDataTypeException |
|
| 1096 | + * @throws InvalidInterfaceException |
|
| 1097 | + * @throws ReflectionException |
|
| 1098 | + * @since 4.9.80.p |
|
| 1099 | + */ |
|
| 1100 | + protected function increaseReservedForDatetimes($qty = 1, array $datetimes = []) |
|
| 1101 | + { |
|
| 1102 | + $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes(); |
|
| 1103 | + $datetimes_updated = []; |
|
| 1104 | + $limit_exceeded = false; |
|
| 1105 | + if (is_array($datetimes)) { |
|
| 1106 | + foreach ($datetimes as $datetime) { |
|
| 1107 | + if ($datetime instanceof EE_Datetime) { |
|
| 1108 | + if ($datetime->increaseReserved($qty)) { |
|
| 1109 | + $datetimes_updated[] = $datetime; |
|
| 1110 | + } else { |
|
| 1111 | + $limit_exceeded = true; |
|
| 1112 | + break; |
|
| 1113 | + } |
|
| 1114 | + } |
|
| 1115 | + } |
|
| 1116 | + // If somewhere along the way we detected a datetime whose |
|
| 1117 | + // limit was exceeded, do a manual rollback. |
|
| 1118 | + if ($limit_exceeded) { |
|
| 1119 | + $this->decreaseReservedForDatetimes($qty, $datetimes_updated); |
|
| 1120 | + return false; |
|
| 1121 | + } |
|
| 1122 | + } |
|
| 1123 | + return true; |
|
| 1124 | + } |
|
| 1125 | + |
|
| 1126 | + |
|
| 1127 | + /** |
|
| 1128 | + * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database. |
|
| 1129 | + * |
|
| 1130 | + * @param int $qty |
|
| 1131 | + * @param bool $adjust_datetimes |
|
| 1132 | + * @param string $source |
|
| 1133 | + * @return boolean |
|
| 1134 | + * @throws EE_Error |
|
| 1135 | + * @throws InvalidArgumentException |
|
| 1136 | + * @throws ReflectionException |
|
| 1137 | + * @throws InvalidDataTypeException |
|
| 1138 | + * @throws InvalidInterfaceException |
|
| 1139 | + * @since 4.9.80.p |
|
| 1140 | + */ |
|
| 1141 | + public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown') |
|
| 1142 | + { |
|
| 1143 | + $qty = absint($qty); |
|
| 1144 | + $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}"); |
|
| 1145 | + if ($adjust_datetimes) { |
|
| 1146 | + $this->decreaseReservedForDatetimes($qty); |
|
| 1147 | + } |
|
| 1148 | + $success = $this->adjustNumericFieldsInDb( |
|
| 1149 | + [ |
|
| 1150 | + 'TKT_reserved' => $qty * -1, |
|
| 1151 | + ] |
|
| 1152 | + ); |
|
| 1153 | + do_action( |
|
| 1154 | + 'AHEE__EE_Ticket__decrease_reserved', |
|
| 1155 | + $this, |
|
| 1156 | + $qty, |
|
| 1157 | + $this->reserved(), |
|
| 1158 | + $success |
|
| 1159 | + ); |
|
| 1160 | + return $success; |
|
| 1161 | + } |
|
| 1162 | + |
|
| 1163 | + |
|
| 1164 | + /** |
|
| 1165 | + * Decreases the reserved count on the specified datetimes. |
|
| 1166 | + * |
|
| 1167 | + * @param int $qty |
|
| 1168 | + * @param EE_Datetime[] $datetimes |
|
| 1169 | + * @throws EE_Error |
|
| 1170 | + * @throws InvalidArgumentException |
|
| 1171 | + * @throws ReflectionException |
|
| 1172 | + * @throws InvalidDataTypeException |
|
| 1173 | + * @throws InvalidInterfaceException |
|
| 1174 | + * @since 4.9.80.p |
|
| 1175 | + */ |
|
| 1176 | + protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = []) |
|
| 1177 | + { |
|
| 1178 | + $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes(); |
|
| 1179 | + foreach ($datetimes as $datetime) { |
|
| 1180 | + if ($datetime instanceof EE_Datetime) { |
|
| 1181 | + $datetime->decreaseReserved($qty); |
|
| 1182 | + } |
|
| 1183 | + } |
|
| 1184 | + } |
|
| 1185 | + |
|
| 1186 | + |
|
| 1187 | + /** |
|
| 1188 | + * Gets ticket quantity |
|
| 1189 | + * |
|
| 1190 | + * @param string $context ticket quantity is somewhat subjective depending on the exact information sought |
|
| 1191 | + * therefore $context can be one of three values: '', 'reg_limit', or 'saleable' |
|
| 1192 | + * '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects |
|
| 1193 | + * REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes |
|
| 1194 | + * SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and |
|
| 1195 | + * is therefore the truest measure of tickets that can be purchased at the moment |
|
| 1196 | + * @return int |
|
| 1197 | + * @throws EE_Error |
|
| 1198 | + * @throws ReflectionException |
|
| 1199 | + */ |
|
| 1200 | + public function qty($context = '') |
|
| 1201 | + { |
|
| 1202 | + switch ($context) { |
|
| 1203 | + case 'reg_limit': |
|
| 1204 | + return $this->real_quantity_on_ticket(); |
|
| 1205 | + case 'saleable': |
|
| 1206 | + return $this->real_quantity_on_ticket('saleable'); |
|
| 1207 | + default: |
|
| 1208 | + return $this->get_raw('TKT_qty'); |
|
| 1209 | + } |
|
| 1210 | + } |
|
| 1211 | + |
|
| 1212 | + |
|
| 1213 | + /** |
|
| 1214 | + * Gets ticket quantity |
|
| 1215 | + * |
|
| 1216 | + * @param string $context ticket quantity is somewhat subjective depending on the exact information sought |
|
| 1217 | + * therefore $context can be one of two values: 'reg_limit', or 'saleable' |
|
| 1218 | + * REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes |
|
| 1219 | + * SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and |
|
| 1220 | + * is therefore the truest measure of tickets that can be purchased at the moment |
|
| 1221 | + * @param int $DTT_ID the primary key for a particular datetime. |
|
| 1222 | + * set to 0 for all related datetimes |
|
| 1223 | + * @return int |
|
| 1224 | + * @throws EE_Error |
|
| 1225 | + * @throws ReflectionException |
|
| 1226 | + */ |
|
| 1227 | + public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0) |
|
| 1228 | + { |
|
| 1229 | + $raw = $this->get_raw('TKT_qty'); |
|
| 1230 | + // return immediately if it's zero |
|
| 1231 | + if ($raw === 0) { |
|
| 1232 | + return $raw; |
|
| 1233 | + } |
|
| 1234 | + // echo "\n\n<br />Ticket: " . $this->name() . '<br />'; |
|
| 1235 | + // ensure qty doesn't exceed raw value for THIS ticket |
|
| 1236 | + $qty = min(EE_INF, $raw); |
|
| 1237 | + // echo "\n . qty: " . $qty . '<br />'; |
|
| 1238 | + // calculate this ticket's total sales and reservations |
|
| 1239 | + $sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved(); |
|
| 1240 | + // echo "\n . sold: " . $this->sold() . '<br />'; |
|
| 1241 | + // echo "\n . reserved: " . $this->reserved() . '<br />'; |
|
| 1242 | + // echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />'; |
|
| 1243 | + // first we need to calculate the maximum number of tickets available for the datetime |
|
| 1244 | + // do we want data for one datetime or all of them ? |
|
| 1245 | + $query_params = $DTT_ID ? [['DTT_ID' => $DTT_ID]] : []; |
|
| 1246 | + $datetimes = $this->datetimes($query_params); |
|
| 1247 | + if (is_array($datetimes) && ! empty($datetimes)) { |
|
| 1248 | + foreach ($datetimes as $datetime) { |
|
| 1249 | + if ($datetime instanceof EE_Datetime) { |
|
| 1250 | + $datetime->refresh_from_db(); |
|
| 1251 | + // echo "\n . . datetime name: " . $datetime->name() . '<br />'; |
|
| 1252 | + // echo "\n . . datetime ID: " . $datetime->ID() . '<br />'; |
|
| 1253 | + // initialize with no restrictions for each datetime |
|
| 1254 | + // but adjust datetime qty based on datetime reg limit |
|
| 1255 | + $datetime_qty = min(EE_INF, $datetime->reg_limit()); |
|
| 1256 | + // echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />'; |
|
| 1257 | + // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />'; |
|
| 1258 | + // if we want the actual saleable amount, then we need to consider OTHER ticket sales |
|
| 1259 | + // and reservations for this datetime, that do NOT include sales and reservations |
|
| 1260 | + // for this ticket (so we add $this->sold() and $this->reserved() back in) |
|
| 1261 | + if ($context === 'saleable') { |
|
| 1262 | + $datetime_qty = max( |
|
| 1263 | + $datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket, |
|
| 1264 | + 0 |
|
| 1265 | + ); |
|
| 1266 | + // echo "\n . . . datetime sold: " . $datetime->sold() . '<br />'; |
|
| 1267 | + // echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />'; |
|
| 1268 | + // echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />'; |
|
| 1269 | + // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />'; |
|
| 1270 | + $datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0; |
|
| 1271 | + // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />'; |
|
| 1272 | + } |
|
| 1273 | + $qty = min($datetime_qty, $qty); |
|
| 1274 | + // echo "\n . . qty: " . $qty . '<br />'; |
|
| 1275 | + } |
|
| 1276 | + } |
|
| 1277 | + } |
|
| 1278 | + // NOW that we know the maximum number of tickets available for the datetime |
|
| 1279 | + // we can finally factor in the details for this specific ticket |
|
| 1280 | + if ($qty > 0 && $context === 'saleable') { |
|
| 1281 | + // and subtract the sales for THIS ticket |
|
| 1282 | + $qty = max($qty - $sold_and_reserved_for_this_ticket, 0); |
|
| 1283 | + // echo "\n . qty: " . $qty . '<br />'; |
|
| 1284 | + } |
|
| 1285 | + // echo "\nFINAL QTY: " . $qty . "<br /><br />"; |
|
| 1286 | + return $qty; |
|
| 1287 | + } |
|
| 1288 | + |
|
| 1289 | + |
|
| 1290 | + /** |
|
| 1291 | + * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes |
|
| 1292 | + * |
|
| 1293 | + * @param int $qty |
|
| 1294 | + * @return void |
|
| 1295 | + * @throws EE_Error |
|
| 1296 | + * @throws ReflectionException |
|
| 1297 | + */ |
|
| 1298 | + public function set_qty($qty) |
|
| 1299 | + { |
|
| 1300 | + $datetimes = $this->datetimes(); |
|
| 1301 | + foreach ($datetimes as $datetime) { |
|
| 1302 | + if ($datetime instanceof EE_Datetime) { |
|
| 1303 | + $qty = min($qty, $datetime->reg_limit()); |
|
| 1304 | + } |
|
| 1305 | + } |
|
| 1306 | + $this->set('TKT_qty', $qty); |
|
| 1307 | + } |
|
| 1308 | + |
|
| 1309 | + |
|
| 1310 | + /** |
|
| 1311 | + * Gets uses |
|
| 1312 | + * |
|
| 1313 | + * @return int |
|
| 1314 | + * @throws EE_Error |
|
| 1315 | + * @throws ReflectionException |
|
| 1316 | + */ |
|
| 1317 | + public function uses() |
|
| 1318 | + { |
|
| 1319 | + return $this->get('TKT_uses'); |
|
| 1320 | + } |
|
| 1321 | + |
|
| 1322 | + |
|
| 1323 | + /** |
|
| 1324 | + * Sets uses |
|
| 1325 | + * |
|
| 1326 | + * @param int $uses |
|
| 1327 | + * @return void |
|
| 1328 | + * @throws EE_Error |
|
| 1329 | + * @throws ReflectionException |
|
| 1330 | + */ |
|
| 1331 | + public function set_uses($uses) |
|
| 1332 | + { |
|
| 1333 | + $this->set('TKT_uses', $uses); |
|
| 1334 | + } |
|
| 1335 | + |
|
| 1336 | + |
|
| 1337 | + /** |
|
| 1338 | + * returns whether ticket is required or not. |
|
| 1339 | + * |
|
| 1340 | + * @return boolean |
|
| 1341 | + * @throws EE_Error |
|
| 1342 | + * @throws ReflectionException |
|
| 1343 | + */ |
|
| 1344 | + public function required() |
|
| 1345 | + { |
|
| 1346 | + return $this->get('TKT_required'); |
|
| 1347 | + } |
|
| 1348 | + |
|
| 1349 | + |
|
| 1350 | + /** |
|
| 1351 | + * sets the TKT_required property |
|
| 1352 | + * |
|
| 1353 | + * @param boolean $required |
|
| 1354 | + * @return void |
|
| 1355 | + * @throws EE_Error |
|
| 1356 | + * @throws ReflectionException |
|
| 1357 | + */ |
|
| 1358 | + public function set_required($required) |
|
| 1359 | + { |
|
| 1360 | + $this->set('TKT_required', $required); |
|
| 1361 | + } |
|
| 1362 | + |
|
| 1363 | + |
|
| 1364 | + /** |
|
| 1365 | + * Gets taxable |
|
| 1366 | + * |
|
| 1367 | + * @return boolean |
|
| 1368 | + * @throws EE_Error |
|
| 1369 | + * @throws ReflectionException |
|
| 1370 | + */ |
|
| 1371 | + public function taxable() |
|
| 1372 | + { |
|
| 1373 | + return $this->get('TKT_taxable'); |
|
| 1374 | + } |
|
| 1375 | + |
|
| 1376 | + |
|
| 1377 | + /** |
|
| 1378 | + * Sets taxable |
|
| 1379 | + * |
|
| 1380 | + * @param boolean $taxable |
|
| 1381 | + * @return void |
|
| 1382 | + * @throws EE_Error |
|
| 1383 | + * @throws ReflectionException |
|
| 1384 | + */ |
|
| 1385 | + public function set_taxable($taxable) |
|
| 1386 | + { |
|
| 1387 | + $this->set('TKT_taxable', $taxable); |
|
| 1388 | + } |
|
| 1389 | + |
|
| 1390 | + |
|
| 1391 | + /** |
|
| 1392 | + * Gets is_default |
|
| 1393 | + * |
|
| 1394 | + * @return boolean |
|
| 1395 | + * @throws EE_Error |
|
| 1396 | + * @throws ReflectionException |
|
| 1397 | + */ |
|
| 1398 | + public function is_default() |
|
| 1399 | + { |
|
| 1400 | + return $this->get('TKT_is_default'); |
|
| 1401 | + } |
|
| 1402 | + |
|
| 1403 | + |
|
| 1404 | + /** |
|
| 1405 | + * Sets is_default |
|
| 1406 | + * |
|
| 1407 | + * @param boolean $is_default |
|
| 1408 | + * @return void |
|
| 1409 | + * @throws EE_Error |
|
| 1410 | + * @throws ReflectionException |
|
| 1411 | + */ |
|
| 1412 | + public function set_is_default($is_default) |
|
| 1413 | + { |
|
| 1414 | + $this->set('TKT_is_default', $is_default); |
|
| 1415 | + } |
|
| 1416 | + |
|
| 1417 | + |
|
| 1418 | + /** |
|
| 1419 | + * Gets order |
|
| 1420 | + * |
|
| 1421 | + * @return int |
|
| 1422 | + * @throws EE_Error |
|
| 1423 | + * @throws ReflectionException |
|
| 1424 | + */ |
|
| 1425 | + public function order() |
|
| 1426 | + { |
|
| 1427 | + return $this->get('TKT_order'); |
|
| 1428 | + } |
|
| 1429 | + |
|
| 1430 | + |
|
| 1431 | + /** |
|
| 1432 | + * Sets order |
|
| 1433 | + * |
|
| 1434 | + * @param int $order |
|
| 1435 | + * @return void |
|
| 1436 | + * @throws EE_Error |
|
| 1437 | + * @throws ReflectionException |
|
| 1438 | + */ |
|
| 1439 | + public function set_order($order) |
|
| 1440 | + { |
|
| 1441 | + $this->set('TKT_order', $order); |
|
| 1442 | + } |
|
| 1443 | + |
|
| 1444 | + |
|
| 1445 | + /** |
|
| 1446 | + * Gets row |
|
| 1447 | + * |
|
| 1448 | + * @return int |
|
| 1449 | + * @throws EE_Error |
|
| 1450 | + * @throws ReflectionException |
|
| 1451 | + */ |
|
| 1452 | + public function row() |
|
| 1453 | + { |
|
| 1454 | + return $this->get('TKT_row'); |
|
| 1455 | + } |
|
| 1456 | + |
|
| 1457 | + |
|
| 1458 | + /** |
|
| 1459 | + * Sets row |
|
| 1460 | + * |
|
| 1461 | + * @param int $row |
|
| 1462 | + * @return void |
|
| 1463 | + * @throws EE_Error |
|
| 1464 | + * @throws ReflectionException |
|
| 1465 | + */ |
|
| 1466 | + public function set_row($row) |
|
| 1467 | + { |
|
| 1468 | + $this->set('TKT_row', $row); |
|
| 1469 | + } |
|
| 1470 | + |
|
| 1471 | + |
|
| 1472 | + /** |
|
| 1473 | + * Gets deleted |
|
| 1474 | + * |
|
| 1475 | + * @return boolean |
|
| 1476 | + * @throws EE_Error |
|
| 1477 | + * @throws ReflectionException |
|
| 1478 | + */ |
|
| 1479 | + public function deleted() |
|
| 1480 | + { |
|
| 1481 | + return $this->get('TKT_deleted'); |
|
| 1482 | + } |
|
| 1483 | + |
|
| 1484 | + |
|
| 1485 | + /** |
|
| 1486 | + * Sets deleted |
|
| 1487 | + * |
|
| 1488 | + * @param boolean $deleted |
|
| 1489 | + * @return void |
|
| 1490 | + * @throws EE_Error |
|
| 1491 | + * @throws ReflectionException |
|
| 1492 | + */ |
|
| 1493 | + public function set_deleted($deleted) |
|
| 1494 | + { |
|
| 1495 | + $this->set('TKT_deleted', $deleted); |
|
| 1496 | + } |
|
| 1497 | + |
|
| 1498 | + |
|
| 1499 | + /** |
|
| 1500 | + * Gets parent |
|
| 1501 | + * |
|
| 1502 | + * @return int |
|
| 1503 | + * @throws EE_Error |
|
| 1504 | + * @throws ReflectionException |
|
| 1505 | + */ |
|
| 1506 | + public function parent_ID() |
|
| 1507 | + { |
|
| 1508 | + return $this->get('TKT_parent'); |
|
| 1509 | + } |
|
| 1510 | + |
|
| 1511 | + |
|
| 1512 | + /** |
|
| 1513 | + * Sets parent |
|
| 1514 | + * |
|
| 1515 | + * @param int $parent |
|
| 1516 | + * @return void |
|
| 1517 | + * @throws EE_Error |
|
| 1518 | + * @throws ReflectionException |
|
| 1519 | + */ |
|
| 1520 | + public function set_parent_ID($parent) |
|
| 1521 | + { |
|
| 1522 | + $this->set('TKT_parent', $parent); |
|
| 1523 | + } |
|
| 1524 | + |
|
| 1525 | + |
|
| 1526 | + /** |
|
| 1527 | + * @return boolean |
|
| 1528 | + * @throws EE_Error |
|
| 1529 | + * @throws InvalidArgumentException |
|
| 1530 | + * @throws InvalidDataTypeException |
|
| 1531 | + * @throws InvalidInterfaceException |
|
| 1532 | + * @throws ReflectionException |
|
| 1533 | + */ |
|
| 1534 | + public function reverse_calculate() |
|
| 1535 | + { |
|
| 1536 | + return $this->get('TKT_reverse_calculate'); |
|
| 1537 | + } |
|
| 1538 | + |
|
| 1539 | + |
|
| 1540 | + /** |
|
| 1541 | + * @param boolean $reverse_calculate |
|
| 1542 | + * @throws EE_Error |
|
| 1543 | + * @throws InvalidArgumentException |
|
| 1544 | + * @throws InvalidDataTypeException |
|
| 1545 | + * @throws InvalidInterfaceException |
|
| 1546 | + * @throws ReflectionException |
|
| 1547 | + */ |
|
| 1548 | + public function set_reverse_calculate($reverse_calculate) |
|
| 1549 | + { |
|
| 1550 | + $this->set('TKT_reverse_calculate', $reverse_calculate); |
|
| 1551 | + } |
|
| 1552 | + |
|
| 1553 | + |
|
| 1554 | + /** |
|
| 1555 | + * Gets a string which is handy for showing in gateways etc that describes the ticket. |
|
| 1556 | + * |
|
| 1557 | + * @return string |
|
| 1558 | + * @throws EE_Error |
|
| 1559 | + * @throws ReflectionException |
|
| 1560 | + */ |
|
| 1561 | + public function name_and_info() |
|
| 1562 | + { |
|
| 1563 | + $times = []; |
|
| 1564 | + foreach ($this->datetimes() as $datetime) { |
|
| 1565 | + $times[] = $datetime->start_date_and_time(); |
|
| 1566 | + } |
|
| 1567 | + return $this->name() . ' @ ' . implode(', ', $times) . ' for ' . $this->pretty_price(); |
|
| 1568 | + } |
|
| 1569 | + |
|
| 1570 | + |
|
| 1571 | + /** |
|
| 1572 | + * Gets name |
|
| 1573 | + * |
|
| 1574 | + * @return string |
|
| 1575 | + * @throws EE_Error |
|
| 1576 | + * @throws ReflectionException |
|
| 1577 | + */ |
|
| 1578 | + public function name() |
|
| 1579 | + { |
|
| 1580 | + return $this->get('TKT_name'); |
|
| 1581 | + } |
|
| 1582 | + |
|
| 1583 | + |
|
| 1584 | + /** |
|
| 1585 | + * Gets price |
|
| 1586 | + * |
|
| 1587 | + * @return float |
|
| 1588 | + * @throws EE_Error |
|
| 1589 | + * @throws ReflectionException |
|
| 1590 | + */ |
|
| 1591 | + public function price() |
|
| 1592 | + { |
|
| 1593 | + return $this->get('TKT_price'); |
|
| 1594 | + } |
|
| 1595 | + |
|
| 1596 | + |
|
| 1597 | + /** |
|
| 1598 | + * Gets all the registrations for this ticket |
|
| 1599 | + * |
|
| 1600 | + * @param array $query_params |
|
| 1601 | + * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 1602 | + * @return EE_Registration[]|EE_Base_Class[] |
|
| 1603 | + * @throws EE_Error |
|
| 1604 | + * @throws ReflectionException |
|
| 1605 | + */ |
|
| 1606 | + public function registrations($query_params = []) |
|
| 1607 | + { |
|
| 1608 | + return $this->get_many_related('Registration', $query_params); |
|
| 1609 | + } |
|
| 1610 | + |
|
| 1611 | + |
|
| 1612 | + /** |
|
| 1613 | + * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket. |
|
| 1614 | + * |
|
| 1615 | + * @return int |
|
| 1616 | + * @throws EE_Error |
|
| 1617 | + * @throws ReflectionException |
|
| 1618 | + */ |
|
| 1619 | + public function update_tickets_sold() |
|
| 1620 | + { |
|
| 1621 | + $count_regs_for_this_ticket = $this->count_registrations( |
|
| 1622 | + [ |
|
| 1623 | + [ |
|
| 1624 | + 'STS_ID' => EEM_Registration::status_id_approved, |
|
| 1625 | + 'REG_deleted' => 0, |
|
| 1626 | + ], |
|
| 1627 | + ] |
|
| 1628 | + ); |
|
| 1629 | + $this->set_sold($count_regs_for_this_ticket); |
|
| 1630 | + $this->save(); |
|
| 1631 | + return $count_regs_for_this_ticket; |
|
| 1632 | + } |
|
| 1633 | + |
|
| 1634 | + |
|
| 1635 | + /** |
|
| 1636 | + * Counts the registrations for this ticket |
|
| 1637 | + * |
|
| 1638 | + * @param array $query_params |
|
| 1639 | + * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 1640 | + * @return int |
|
| 1641 | + * @throws EE_Error |
|
| 1642 | + * @throws ReflectionException |
|
| 1643 | + */ |
|
| 1644 | + public function count_registrations($query_params = []) |
|
| 1645 | + { |
|
| 1646 | + return $this->count_related('Registration', $query_params); |
|
| 1647 | + } |
|
| 1648 | + |
|
| 1649 | + |
|
| 1650 | + /** |
|
| 1651 | + * Implementation for EEI_Has_Icon interface method. |
|
| 1652 | + * |
|
| 1653 | + * @return string |
|
| 1654 | + * @see EEI_Visual_Representation for comments |
|
| 1655 | + */ |
|
| 1656 | + public function get_icon() |
|
| 1657 | + { |
|
| 1658 | + return '<span class="dashicons dashicons-tickets-alt"/>'; |
|
| 1659 | + } |
|
| 1660 | + |
|
| 1661 | + |
|
| 1662 | + /** |
|
| 1663 | + * Implementation of the EEI_Event_Relation interface method |
|
| 1664 | + * |
|
| 1665 | + * @return EE_Event |
|
| 1666 | + * @throws EE_Error |
|
| 1667 | + * @throws UnexpectedEntityException |
|
| 1668 | + * @throws ReflectionException |
|
| 1669 | + * @see EEI_Event_Relation for comments |
|
| 1670 | + */ |
|
| 1671 | + public function get_related_event() |
|
| 1672 | + { |
|
| 1673 | + // get one datetime to use for getting the event |
|
| 1674 | + $datetime = $this->first_datetime(); |
|
| 1675 | + if (! $datetime instanceof EE_Datetime) { |
|
| 1676 | + throw new UnexpectedEntityException( |
|
| 1677 | + $datetime, |
|
| 1678 | + 'EE_Datetime', |
|
| 1679 | + sprintf( |
|
| 1680 | + __('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'), |
|
| 1681 | + $this->name() |
|
| 1682 | + ) |
|
| 1683 | + ); |
|
| 1684 | + } |
|
| 1685 | + $event = $datetime->event(); |
|
| 1686 | + if (! $event instanceof EE_Event) { |
|
| 1687 | + throw new UnexpectedEntityException( |
|
| 1688 | + $event, |
|
| 1689 | + 'EE_Event', |
|
| 1690 | + sprintf( |
|
| 1691 | + __('The ticket (%s) is not associated with a valid event.', 'event_espresso'), |
|
| 1692 | + $this->name() |
|
| 1693 | + ) |
|
| 1694 | + ); |
|
| 1695 | + } |
|
| 1696 | + return $event; |
|
| 1697 | + } |
|
| 1698 | + |
|
| 1699 | + |
|
| 1700 | + /** |
|
| 1701 | + * Implementation of the EEI_Event_Relation interface method |
|
| 1702 | + * |
|
| 1703 | + * @return string |
|
| 1704 | + * @throws UnexpectedEntityException |
|
| 1705 | + * @throws EE_Error |
|
| 1706 | + * @throws ReflectionException |
|
| 1707 | + * @see EEI_Event_Relation for comments |
|
| 1708 | + */ |
|
| 1709 | + public function get_event_name() |
|
| 1710 | + { |
|
| 1711 | + $event = $this->get_related_event(); |
|
| 1712 | + return $event instanceof EE_Event ? $event->name() : ''; |
|
| 1713 | + } |
|
| 1714 | + |
|
| 1715 | + |
|
| 1716 | + /** |
|
| 1717 | + * Implementation of the EEI_Event_Relation interface method |
|
| 1718 | + * |
|
| 1719 | + * @return int |
|
| 1720 | + * @throws UnexpectedEntityException |
|
| 1721 | + * @throws EE_Error |
|
| 1722 | + * @throws ReflectionException |
|
| 1723 | + * @see EEI_Event_Relation for comments |
|
| 1724 | + */ |
|
| 1725 | + public function get_event_ID() |
|
| 1726 | + { |
|
| 1727 | + $event = $this->get_related_event(); |
|
| 1728 | + return $event instanceof EE_Event ? $event->ID() : 0; |
|
| 1729 | + } |
|
| 1730 | + |
|
| 1731 | + |
|
| 1732 | + /** |
|
| 1733 | + * This simply returns whether a ticket can be permanently deleted or not. |
|
| 1734 | + * The criteria for determining this is whether the ticket has any related registrations. |
|
| 1735 | + * If there are none then it can be permanently deleted. |
|
| 1736 | + * |
|
| 1737 | + * @return bool |
|
| 1738 | + * @throws EE_Error |
|
| 1739 | + * @throws ReflectionException |
|
| 1740 | + */ |
|
| 1741 | + public function is_permanently_deleteable() |
|
| 1742 | + { |
|
| 1743 | + return $this->count_registrations() === 0; |
|
| 1744 | + } |
|
| 1745 | + |
|
| 1746 | + |
|
| 1747 | + /** |
|
| 1748 | + * @return int |
|
| 1749 | + * @throws EE_Error |
|
| 1750 | + * @throws ReflectionException |
|
| 1751 | + * @since $VID:$ |
|
| 1752 | + */ |
|
| 1753 | + public function visibility(): int |
|
| 1754 | + { |
|
| 1755 | + return $this->get('TKT_visibility'); |
|
| 1756 | + } |
|
| 1757 | + |
|
| 1758 | + |
|
| 1759 | + /** |
|
| 1760 | + * @return int |
|
| 1761 | + * @throws EE_Error |
|
| 1762 | + * @throws ReflectionException |
|
| 1763 | + * @since $VID:$ |
|
| 1764 | + */ |
|
| 1765 | + public function isHidden(): int |
|
| 1766 | + { |
|
| 1767 | + return $this->visibility() === EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE; |
|
| 1768 | + } |
|
| 1769 | + |
|
| 1770 | + |
|
| 1771 | + /** |
|
| 1772 | + * @return int |
|
| 1773 | + * @throws EE_Error |
|
| 1774 | + * @throws ReflectionException |
|
| 1775 | + * @since $VID:$ |
|
| 1776 | + */ |
|
| 1777 | + public function isNotHidden(): int |
|
| 1778 | + { |
|
| 1779 | + return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE; |
|
| 1780 | + } |
|
| 1781 | + |
|
| 1782 | + |
|
| 1783 | + /** |
|
| 1784 | + * @return int |
|
| 1785 | + * @throws EE_Error |
|
| 1786 | + * @throws ReflectionException |
|
| 1787 | + * @since $VID:$ |
|
| 1788 | + */ |
|
| 1789 | + public function isPublicOnly(): int |
|
| 1790 | + { |
|
| 1791 | + return $this->isNotHidden() && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_PUBLIC_VALUE; |
|
| 1792 | + } |
|
| 1793 | + |
|
| 1794 | + |
|
| 1795 | + /** |
|
| 1796 | + * @return int |
|
| 1797 | + * @throws EE_Error |
|
| 1798 | + * @throws ReflectionException |
|
| 1799 | + * @since $VID:$ |
|
| 1800 | + */ |
|
| 1801 | + public function isMembersOnly(): int |
|
| 1802 | + { |
|
| 1803 | + return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_PUBLIC_VALUE |
|
| 1804 | + && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_MEMBERS_ONLY_VALUE; |
|
| 1805 | + } |
|
| 1806 | + |
|
| 1807 | + |
|
| 1808 | + /** |
|
| 1809 | + * @return int |
|
| 1810 | + * @throws EE_Error |
|
| 1811 | + * @throws ReflectionException |
|
| 1812 | + * @since $VID:$ |
|
| 1813 | + */ |
|
| 1814 | + public function isAdminsOnly(): int |
|
| 1815 | + { |
|
| 1816 | + return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_MEMBERS_ONLY_VALUE |
|
| 1817 | + && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_ADMINS_ONLY_VALUE; |
|
| 1818 | + } |
|
| 1819 | + |
|
| 1820 | + |
|
| 1821 | + /** |
|
| 1822 | + * @return int |
|
| 1823 | + * @throws EE_Error |
|
| 1824 | + * @throws ReflectionException |
|
| 1825 | + * @since $VID:$ |
|
| 1826 | + */ |
|
| 1827 | + public function isAdminUiOnly(): int |
|
| 1828 | + { |
|
| 1829 | + return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_ADMINS_ONLY_VALUE |
|
| 1830 | + && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_ADMIN_UI_ONLY_VALUE; |
|
| 1831 | + } |
|
| 1832 | + |
|
| 1833 | + |
|
| 1834 | + /** |
|
| 1835 | + * @param int $visibility |
|
| 1836 | + * @throws EE_Error |
|
| 1837 | + * @throws ReflectionException |
|
| 1838 | + * @since $VID:$ |
|
| 1839 | + */ |
|
| 1840 | + public function set_visibility(int $visibility) |
|
| 1841 | + { |
|
| 1842 | + |
|
| 1843 | + $ticket_visibility_options = $this->_model->ticketVisibilityOptions(); |
|
| 1844 | + $ticket_visibility = -1; |
|
| 1845 | + foreach ($ticket_visibility_options as $ticket_visibility_option) { |
|
| 1846 | + if ($visibility === $ticket_visibility_option) { |
|
| 1847 | + $ticket_visibility = $visibility; |
|
| 1848 | + } |
|
| 1849 | + } |
|
| 1850 | + if ($ticket_visibility === -1) { |
|
| 1851 | + throw new DomainException( |
|
| 1852 | + sprintf( |
|
| 1853 | + esc_html__( |
|
| 1854 | + 'The supplied ticket visibility setting of "%1$s" is not valid. It needs to match one of the keys in the following array:%2$s %3$s ', |
|
| 1855 | + 'event_espresso' |
|
| 1856 | + ), |
|
| 1857 | + $visibility, |
|
| 1858 | + '<br />', |
|
| 1859 | + var_export($ticket_visibility_options, true) |
|
| 1860 | + ) |
|
| 1861 | + ); |
|
| 1862 | + } |
|
| 1863 | + $this->set('TKT_visibility', $ticket_visibility); |
|
| 1864 | + } |
|
| 1865 | + |
|
| 1866 | + |
|
| 1867 | + /******************************************************************* |
|
| 1868 | 1868 | *********************** DEPRECATED METHODS ********************** |
| 1869 | 1869 | *******************************************************************/ |
| 1870 | 1870 | |
| 1871 | 1871 | |
| 1872 | - /** |
|
| 1873 | - * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its |
|
| 1874 | - * associated datetimes. |
|
| 1875 | - * |
|
| 1876 | - * @param int $qty |
|
| 1877 | - * @return void |
|
| 1878 | - * @throws EE_Error |
|
| 1879 | - * @throws InvalidArgumentException |
|
| 1880 | - * @throws InvalidDataTypeException |
|
| 1881 | - * @throws InvalidInterfaceException |
|
| 1882 | - * @throws ReflectionException |
|
| 1883 | - * @deprecated 4.9.80.p |
|
| 1884 | - */ |
|
| 1885 | - public function increase_sold($qty = 1) |
|
| 1886 | - { |
|
| 1887 | - EE_Error::doing_it_wrong( |
|
| 1888 | - __FUNCTION__, |
|
| 1889 | - esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'), |
|
| 1890 | - '4.9.80.p', |
|
| 1891 | - '5.0.0.p' |
|
| 1892 | - ); |
|
| 1893 | - $this->increaseSold($qty); |
|
| 1894 | - } |
|
| 1895 | - |
|
| 1896 | - |
|
| 1897 | - /** |
|
| 1898 | - * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty. |
|
| 1899 | - * |
|
| 1900 | - * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts), |
|
| 1901 | - * Negative means to decreases old counts (and increase reserved counts). |
|
| 1902 | - * @throws EE_Error |
|
| 1903 | - * @throws InvalidArgumentException |
|
| 1904 | - * @throws InvalidDataTypeException |
|
| 1905 | - * @throws InvalidInterfaceException |
|
| 1906 | - * @throws ReflectionException |
|
| 1907 | - * @deprecated 4.9.80.p |
|
| 1908 | - */ |
|
| 1909 | - protected function _increase_sold_for_datetimes($qty) |
|
| 1910 | - { |
|
| 1911 | - EE_Error::doing_it_wrong( |
|
| 1912 | - __FUNCTION__, |
|
| 1913 | - esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'), |
|
| 1914 | - '4.9.80.p', |
|
| 1915 | - '5.0.0.p' |
|
| 1916 | - ); |
|
| 1917 | - $this->increaseSoldForDatetimes($qty); |
|
| 1918 | - } |
|
| 1919 | - |
|
| 1920 | - |
|
| 1921 | - /** |
|
| 1922 | - * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the |
|
| 1923 | - * DB and then updates the model objects. |
|
| 1924 | - * Does not affect the reserved counts. |
|
| 1925 | - * |
|
| 1926 | - * @param int $qty |
|
| 1927 | - * @return void |
|
| 1928 | - * @throws EE_Error |
|
| 1929 | - * @throws InvalidArgumentException |
|
| 1930 | - * @throws InvalidDataTypeException |
|
| 1931 | - * @throws InvalidInterfaceException |
|
| 1932 | - * @throws ReflectionException |
|
| 1933 | - * @deprecated 4.9.80.p |
|
| 1934 | - */ |
|
| 1935 | - public function decrease_sold($qty = 1) |
|
| 1936 | - { |
|
| 1937 | - EE_Error::doing_it_wrong( |
|
| 1938 | - __FUNCTION__, |
|
| 1939 | - esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'), |
|
| 1940 | - '4.9.80.p', |
|
| 1941 | - '5.0.0.p' |
|
| 1942 | - ); |
|
| 1943 | - $this->decreaseSold($qty); |
|
| 1944 | - } |
|
| 1945 | - |
|
| 1946 | - |
|
| 1947 | - /** |
|
| 1948 | - * Decreases sold on related datetimes |
|
| 1949 | - * |
|
| 1950 | - * @param int $qty |
|
| 1951 | - * @return void |
|
| 1952 | - * @throws EE_Error |
|
| 1953 | - * @throws InvalidArgumentException |
|
| 1954 | - * @throws InvalidDataTypeException |
|
| 1955 | - * @throws InvalidInterfaceException |
|
| 1956 | - * @throws ReflectionException |
|
| 1957 | - * @deprecated 4.9.80.p |
|
| 1958 | - */ |
|
| 1959 | - protected function _decrease_sold_for_datetimes($qty = 1) |
|
| 1960 | - { |
|
| 1961 | - EE_Error::doing_it_wrong( |
|
| 1962 | - __FUNCTION__, |
|
| 1963 | - esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'), |
|
| 1964 | - '4.9.80.p', |
|
| 1965 | - '5.0.0.p' |
|
| 1966 | - ); |
|
| 1967 | - $this->decreaseSoldForDatetimes($qty); |
|
| 1968 | - } |
|
| 1969 | - |
|
| 1970 | - |
|
| 1971 | - /** |
|
| 1972 | - * Increments reserved by amount passed by $qty, and persists it immediately to the database. |
|
| 1973 | - * |
|
| 1974 | - * @param int $qty |
|
| 1975 | - * @param string $source |
|
| 1976 | - * @return bool whether we successfully reserved the ticket or not. |
|
| 1977 | - * @throws EE_Error |
|
| 1978 | - * @throws InvalidArgumentException |
|
| 1979 | - * @throws ReflectionException |
|
| 1980 | - * @throws InvalidDataTypeException |
|
| 1981 | - * @throws InvalidInterfaceException |
|
| 1982 | - * @deprecated 4.9.80.p |
|
| 1983 | - */ |
|
| 1984 | - public function increase_reserved($qty = 1, $source = 'unknown') |
|
| 1985 | - { |
|
| 1986 | - EE_Error::doing_it_wrong( |
|
| 1987 | - __FUNCTION__, |
|
| 1988 | - esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'), |
|
| 1989 | - '4.9.80.p', |
|
| 1990 | - '5.0.0.p' |
|
| 1991 | - ); |
|
| 1992 | - return $this->increaseReserved($qty); |
|
| 1993 | - } |
|
| 1994 | - |
|
| 1995 | - |
|
| 1996 | - /** |
|
| 1997 | - * Increases sold on related datetimes |
|
| 1998 | - * |
|
| 1999 | - * @param int $qty |
|
| 2000 | - * @return boolean indicating success |
|
| 2001 | - * @throws EE_Error |
|
| 2002 | - * @throws InvalidArgumentException |
|
| 2003 | - * @throws InvalidDataTypeException |
|
| 2004 | - * @throws InvalidInterfaceException |
|
| 2005 | - * @throws ReflectionException |
|
| 2006 | - * @deprecated 4.9.80.p |
|
| 2007 | - */ |
|
| 2008 | - protected function _increase_reserved_for_datetimes($qty = 1) |
|
| 2009 | - { |
|
| 2010 | - EE_Error::doing_it_wrong( |
|
| 2011 | - __FUNCTION__, |
|
| 2012 | - esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'), |
|
| 2013 | - '4.9.80.p', |
|
| 2014 | - '5.0.0.p' |
|
| 2015 | - ); |
|
| 2016 | - return $this->increaseReservedForDatetimes($qty); |
|
| 2017 | - } |
|
| 2018 | - |
|
| 2019 | - |
|
| 2020 | - /** |
|
| 2021 | - * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database. |
|
| 2022 | - * |
|
| 2023 | - * @param int $qty |
|
| 2024 | - * @param bool $adjust_datetimes |
|
| 2025 | - * @param string $source |
|
| 2026 | - * @return void |
|
| 2027 | - * @throws EE_Error |
|
| 2028 | - * @throws InvalidArgumentException |
|
| 2029 | - * @throws ReflectionException |
|
| 2030 | - * @throws InvalidDataTypeException |
|
| 2031 | - * @throws InvalidInterfaceException |
|
| 2032 | - * @deprecated 4.9.80.p |
|
| 2033 | - */ |
|
| 2034 | - public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown') |
|
| 2035 | - { |
|
| 2036 | - EE_Error::doing_it_wrong( |
|
| 2037 | - __FUNCTION__, |
|
| 2038 | - esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'), |
|
| 2039 | - '4.9.80.p', |
|
| 2040 | - '5.0.0.p' |
|
| 2041 | - ); |
|
| 2042 | - $this->decreaseReserved($qty); |
|
| 2043 | - } |
|
| 2044 | - |
|
| 2045 | - |
|
| 2046 | - /** |
|
| 2047 | - * Decreases reserved on related datetimes |
|
| 2048 | - * |
|
| 2049 | - * @param int $qty |
|
| 2050 | - * @return void |
|
| 2051 | - * @throws EE_Error |
|
| 2052 | - * @throws InvalidArgumentException |
|
| 2053 | - * @throws ReflectionException |
|
| 2054 | - * @throws InvalidDataTypeException |
|
| 2055 | - * @throws InvalidInterfaceException |
|
| 2056 | - * @deprecated 4.9.80.p |
|
| 2057 | - */ |
|
| 2058 | - protected function _decrease_reserved_for_datetimes($qty = 1) |
|
| 2059 | - { |
|
| 2060 | - EE_Error::doing_it_wrong( |
|
| 2061 | - __FUNCTION__, |
|
| 2062 | - esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'), |
|
| 2063 | - '4.9.80.p', |
|
| 2064 | - '5.0.0.p' |
|
| 2065 | - ); |
|
| 2066 | - $this->decreaseReservedForDatetimes($qty); |
|
| 2067 | - } |
|
| 1872 | + /** |
|
| 1873 | + * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its |
|
| 1874 | + * associated datetimes. |
|
| 1875 | + * |
|
| 1876 | + * @param int $qty |
|
| 1877 | + * @return void |
|
| 1878 | + * @throws EE_Error |
|
| 1879 | + * @throws InvalidArgumentException |
|
| 1880 | + * @throws InvalidDataTypeException |
|
| 1881 | + * @throws InvalidInterfaceException |
|
| 1882 | + * @throws ReflectionException |
|
| 1883 | + * @deprecated 4.9.80.p |
|
| 1884 | + */ |
|
| 1885 | + public function increase_sold($qty = 1) |
|
| 1886 | + { |
|
| 1887 | + EE_Error::doing_it_wrong( |
|
| 1888 | + __FUNCTION__, |
|
| 1889 | + esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'), |
|
| 1890 | + '4.9.80.p', |
|
| 1891 | + '5.0.0.p' |
|
| 1892 | + ); |
|
| 1893 | + $this->increaseSold($qty); |
|
| 1894 | + } |
|
| 1895 | + |
|
| 1896 | + |
|
| 1897 | + /** |
|
| 1898 | + * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty. |
|
| 1899 | + * |
|
| 1900 | + * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts), |
|
| 1901 | + * Negative means to decreases old counts (and increase reserved counts). |
|
| 1902 | + * @throws EE_Error |
|
| 1903 | + * @throws InvalidArgumentException |
|
| 1904 | + * @throws InvalidDataTypeException |
|
| 1905 | + * @throws InvalidInterfaceException |
|
| 1906 | + * @throws ReflectionException |
|
| 1907 | + * @deprecated 4.9.80.p |
|
| 1908 | + */ |
|
| 1909 | + protected function _increase_sold_for_datetimes($qty) |
|
| 1910 | + { |
|
| 1911 | + EE_Error::doing_it_wrong( |
|
| 1912 | + __FUNCTION__, |
|
| 1913 | + esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'), |
|
| 1914 | + '4.9.80.p', |
|
| 1915 | + '5.0.0.p' |
|
| 1916 | + ); |
|
| 1917 | + $this->increaseSoldForDatetimes($qty); |
|
| 1918 | + } |
|
| 1919 | + |
|
| 1920 | + |
|
| 1921 | + /** |
|
| 1922 | + * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the |
|
| 1923 | + * DB and then updates the model objects. |
|
| 1924 | + * Does not affect the reserved counts. |
|
| 1925 | + * |
|
| 1926 | + * @param int $qty |
|
| 1927 | + * @return void |
|
| 1928 | + * @throws EE_Error |
|
| 1929 | + * @throws InvalidArgumentException |
|
| 1930 | + * @throws InvalidDataTypeException |
|
| 1931 | + * @throws InvalidInterfaceException |
|
| 1932 | + * @throws ReflectionException |
|
| 1933 | + * @deprecated 4.9.80.p |
|
| 1934 | + */ |
|
| 1935 | + public function decrease_sold($qty = 1) |
|
| 1936 | + { |
|
| 1937 | + EE_Error::doing_it_wrong( |
|
| 1938 | + __FUNCTION__, |
|
| 1939 | + esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'), |
|
| 1940 | + '4.9.80.p', |
|
| 1941 | + '5.0.0.p' |
|
| 1942 | + ); |
|
| 1943 | + $this->decreaseSold($qty); |
|
| 1944 | + } |
|
| 1945 | + |
|
| 1946 | + |
|
| 1947 | + /** |
|
| 1948 | + * Decreases sold on related datetimes |
|
| 1949 | + * |
|
| 1950 | + * @param int $qty |
|
| 1951 | + * @return void |
|
| 1952 | + * @throws EE_Error |
|
| 1953 | + * @throws InvalidArgumentException |
|
| 1954 | + * @throws InvalidDataTypeException |
|
| 1955 | + * @throws InvalidInterfaceException |
|
| 1956 | + * @throws ReflectionException |
|
| 1957 | + * @deprecated 4.9.80.p |
|
| 1958 | + */ |
|
| 1959 | + protected function _decrease_sold_for_datetimes($qty = 1) |
|
| 1960 | + { |
|
| 1961 | + EE_Error::doing_it_wrong( |
|
| 1962 | + __FUNCTION__, |
|
| 1963 | + esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'), |
|
| 1964 | + '4.9.80.p', |
|
| 1965 | + '5.0.0.p' |
|
| 1966 | + ); |
|
| 1967 | + $this->decreaseSoldForDatetimes($qty); |
|
| 1968 | + } |
|
| 1969 | + |
|
| 1970 | + |
|
| 1971 | + /** |
|
| 1972 | + * Increments reserved by amount passed by $qty, and persists it immediately to the database. |
|
| 1973 | + * |
|
| 1974 | + * @param int $qty |
|
| 1975 | + * @param string $source |
|
| 1976 | + * @return bool whether we successfully reserved the ticket or not. |
|
| 1977 | + * @throws EE_Error |
|
| 1978 | + * @throws InvalidArgumentException |
|
| 1979 | + * @throws ReflectionException |
|
| 1980 | + * @throws InvalidDataTypeException |
|
| 1981 | + * @throws InvalidInterfaceException |
|
| 1982 | + * @deprecated 4.9.80.p |
|
| 1983 | + */ |
|
| 1984 | + public function increase_reserved($qty = 1, $source = 'unknown') |
|
| 1985 | + { |
|
| 1986 | + EE_Error::doing_it_wrong( |
|
| 1987 | + __FUNCTION__, |
|
| 1988 | + esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'), |
|
| 1989 | + '4.9.80.p', |
|
| 1990 | + '5.0.0.p' |
|
| 1991 | + ); |
|
| 1992 | + return $this->increaseReserved($qty); |
|
| 1993 | + } |
|
| 1994 | + |
|
| 1995 | + |
|
| 1996 | + /** |
|
| 1997 | + * Increases sold on related datetimes |
|
| 1998 | + * |
|
| 1999 | + * @param int $qty |
|
| 2000 | + * @return boolean indicating success |
|
| 2001 | + * @throws EE_Error |
|
| 2002 | + * @throws InvalidArgumentException |
|
| 2003 | + * @throws InvalidDataTypeException |
|
| 2004 | + * @throws InvalidInterfaceException |
|
| 2005 | + * @throws ReflectionException |
|
| 2006 | + * @deprecated 4.9.80.p |
|
| 2007 | + */ |
|
| 2008 | + protected function _increase_reserved_for_datetimes($qty = 1) |
|
| 2009 | + { |
|
| 2010 | + EE_Error::doing_it_wrong( |
|
| 2011 | + __FUNCTION__, |
|
| 2012 | + esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'), |
|
| 2013 | + '4.9.80.p', |
|
| 2014 | + '5.0.0.p' |
|
| 2015 | + ); |
|
| 2016 | + return $this->increaseReservedForDatetimes($qty); |
|
| 2017 | + } |
|
| 2018 | + |
|
| 2019 | + |
|
| 2020 | + /** |
|
| 2021 | + * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database. |
|
| 2022 | + * |
|
| 2023 | + * @param int $qty |
|
| 2024 | + * @param bool $adjust_datetimes |
|
| 2025 | + * @param string $source |
|
| 2026 | + * @return void |
|
| 2027 | + * @throws EE_Error |
|
| 2028 | + * @throws InvalidArgumentException |
|
| 2029 | + * @throws ReflectionException |
|
| 2030 | + * @throws InvalidDataTypeException |
|
| 2031 | + * @throws InvalidInterfaceException |
|
| 2032 | + * @deprecated 4.9.80.p |
|
| 2033 | + */ |
|
| 2034 | + public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown') |
|
| 2035 | + { |
|
| 2036 | + EE_Error::doing_it_wrong( |
|
| 2037 | + __FUNCTION__, |
|
| 2038 | + esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'), |
|
| 2039 | + '4.9.80.p', |
|
| 2040 | + '5.0.0.p' |
|
| 2041 | + ); |
|
| 2042 | + $this->decreaseReserved($qty); |
|
| 2043 | + } |
|
| 2044 | + |
|
| 2045 | + |
|
| 2046 | + /** |
|
| 2047 | + * Decreases reserved on related datetimes |
|
| 2048 | + * |
|
| 2049 | + * @param int $qty |
|
| 2050 | + * @return void |
|
| 2051 | + * @throws EE_Error |
|
| 2052 | + * @throws InvalidArgumentException |
|
| 2053 | + * @throws ReflectionException |
|
| 2054 | + * @throws InvalidDataTypeException |
|
| 2055 | + * @throws InvalidInterfaceException |
|
| 2056 | + * @deprecated 4.9.80.p |
|
| 2057 | + */ |
|
| 2058 | + protected function _decrease_reserved_for_datetimes($qty = 1) |
|
| 2059 | + { |
|
| 2060 | + EE_Error::doing_it_wrong( |
|
| 2061 | + __FUNCTION__, |
|
| 2062 | + esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'), |
|
| 2063 | + '4.9.80.p', |
|
| 2064 | + '5.0.0.p' |
|
| 2065 | + ); |
|
| 2066 | + $this->decreaseReservedForDatetimes($qty); |
|
| 2067 | + } |
|
| 2068 | 2068 | } |
@@ -13,1705 +13,1705 @@ |
||
| 13 | 13 | class EE_Transaction extends EE_Base_Class implements EEI_Transaction |
| 14 | 14 | { |
| 15 | 15 | |
| 16 | - /** |
|
| 17 | - * The length of time in seconds that a lock is applied before being considered expired. |
|
| 18 | - * It is not long because a transaction should only be locked for the duration of the request that locked it |
|
| 19 | - */ |
|
| 20 | - const LOCK_EXPIRATION = 2; |
|
| 21 | - |
|
| 22 | - /** |
|
| 23 | - * txn status upon initial construction. |
|
| 24 | - * |
|
| 25 | - * @var string |
|
| 26 | - */ |
|
| 27 | - protected $_old_txn_status; |
|
| 28 | - |
|
| 29 | - |
|
| 30 | - /** |
|
| 31 | - * @param array $props_n_values incoming values |
|
| 32 | - * @param string $timezone incoming timezone |
|
| 33 | - * (if not set the timezone set for the website will be used.) |
|
| 34 | - * @param array $date_formats incoming date_formats in an array where the first value is the |
|
| 35 | - * date_format and the second value is the time format |
|
| 36 | - * @return EE_Transaction |
|
| 37 | - * @throws EE_Error |
|
| 38 | - * @throws InvalidArgumentException |
|
| 39 | - * @throws InvalidDataTypeException |
|
| 40 | - * @throws InvalidInterfaceException |
|
| 41 | - * @throws ReflectionException |
|
| 42 | - */ |
|
| 43 | - public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
| 44 | - { |
|
| 45 | - $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats); |
|
| 46 | - $txn = $has_object |
|
| 47 | - ? $has_object |
|
| 48 | - : new self($props_n_values, false, $timezone, $date_formats); |
|
| 49 | - if (! $has_object) { |
|
| 50 | - $txn->set_old_txn_status($txn->status_ID()); |
|
| 51 | - } |
|
| 52 | - return $txn; |
|
| 53 | - } |
|
| 54 | - |
|
| 55 | - |
|
| 56 | - /** |
|
| 57 | - * @param array $props_n_values incoming values from the database |
|
| 58 | - * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
| 59 | - * the website will be used. |
|
| 60 | - * @return EE_Transaction |
|
| 61 | - * @throws EE_Error |
|
| 62 | - * @throws InvalidArgumentException |
|
| 63 | - * @throws InvalidDataTypeException |
|
| 64 | - * @throws InvalidInterfaceException |
|
| 65 | - * @throws ReflectionException |
|
| 66 | - */ |
|
| 67 | - public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
| 68 | - { |
|
| 69 | - $txn = new self($props_n_values, true, $timezone); |
|
| 70 | - $txn->set_old_txn_status($txn->status_ID()); |
|
| 71 | - return $txn; |
|
| 72 | - } |
|
| 73 | - |
|
| 74 | - |
|
| 75 | - /** |
|
| 76 | - * Sets a meta field indicating that this TXN is locked and should not be updated in the db. |
|
| 77 | - * If a lock has already been set, then we will attempt to remove it in case it has expired. |
|
| 78 | - * If that also fails, then an exception is thrown. |
|
| 79 | - * |
|
| 80 | - * @throws EE_Error |
|
| 81 | - * @throws InvalidArgumentException |
|
| 82 | - * @throws InvalidDataTypeException |
|
| 83 | - * @throws InvalidInterfaceException |
|
| 84 | - * @throws ReflectionException |
|
| 85 | - */ |
|
| 86 | - public function lock() |
|
| 87 | - { |
|
| 88 | - // attempt to set lock, but if that fails... |
|
| 89 | - if (! $this->add_extra_meta('lock', time(), true)) { |
|
| 90 | - // then attempt to remove the lock in case it is expired |
|
| 91 | - if ($this->_remove_expired_lock()) { |
|
| 92 | - // if removal was successful, then try setting lock again |
|
| 93 | - $this->lock(); |
|
| 94 | - } else { |
|
| 95 | - // but if the lock can not be removed, then throw an exception |
|
| 96 | - throw new EE_Error( |
|
| 97 | - sprintf( |
|
| 98 | - __( |
|
| 99 | - 'Could not lock Transaction %1$d because it is already locked, meaning another part of the system is currently editing it. It should already be unlocked by the time you read this, so please refresh the page and try again.', |
|
| 100 | - 'event_espresso' |
|
| 101 | - ), |
|
| 102 | - $this->ID() |
|
| 103 | - ) |
|
| 104 | - ); |
|
| 105 | - } |
|
| 106 | - } |
|
| 107 | - } |
|
| 108 | - |
|
| 109 | - |
|
| 110 | - /** |
|
| 111 | - * removes transaction lock applied in EE_Transaction::lock() |
|
| 112 | - * |
|
| 113 | - * @return int |
|
| 114 | - * @throws EE_Error |
|
| 115 | - * @throws InvalidArgumentException |
|
| 116 | - * @throws InvalidDataTypeException |
|
| 117 | - * @throws InvalidInterfaceException |
|
| 118 | - * @throws ReflectionException |
|
| 119 | - */ |
|
| 120 | - public function unlock() |
|
| 121 | - { |
|
| 122 | - return $this->delete_extra_meta('lock'); |
|
| 123 | - } |
|
| 124 | - |
|
| 125 | - |
|
| 126 | - /** |
|
| 127 | - * Decides whether or not now is the right time to update the transaction. |
|
| 128 | - * This is useful because we don't always know if it is safe to update the transaction |
|
| 129 | - * and its related data. why? |
|
| 130 | - * because it's possible that the transaction is being used in another |
|
| 131 | - * request and could overwrite anything we save. |
|
| 132 | - * So we want to only update the txn once we know that won't happen. |
|
| 133 | - * We also check that the lock isn't expired, and remove it if it is |
|
| 134 | - * |
|
| 135 | - * @return boolean |
|
| 136 | - * @throws EE_Error |
|
| 137 | - * @throws InvalidArgumentException |
|
| 138 | - * @throws InvalidDataTypeException |
|
| 139 | - * @throws InvalidInterfaceException |
|
| 140 | - * @throws ReflectionException |
|
| 141 | - */ |
|
| 142 | - public function is_locked() |
|
| 143 | - { |
|
| 144 | - // if TXN is not locked, then return false immediately |
|
| 145 | - if (! $this->_get_lock()) { |
|
| 146 | - return false; |
|
| 147 | - } |
|
| 148 | - // if not, then let's try and remove the lock in case it's expired... |
|
| 149 | - // _remove_expired_lock() returns 0 when lock is valid (ie: removed = false) |
|
| 150 | - // and a positive number if the lock was removed (ie: number of locks deleted), |
|
| 151 | - // so we need to return the opposite |
|
| 152 | - return ! $this->_remove_expired_lock() ? true : false; |
|
| 153 | - } |
|
| 154 | - |
|
| 155 | - |
|
| 156 | - /** |
|
| 157 | - * Gets the meta field indicating that this TXN is locked |
|
| 158 | - * |
|
| 159 | - * @return int |
|
| 160 | - * @throws EE_Error |
|
| 161 | - * @throws InvalidArgumentException |
|
| 162 | - * @throws InvalidDataTypeException |
|
| 163 | - * @throws InvalidInterfaceException |
|
| 164 | - * @throws ReflectionException |
|
| 165 | - */ |
|
| 166 | - protected function _get_lock() |
|
| 167 | - { |
|
| 168 | - return (int) $this->get_extra_meta('lock', true, 0); |
|
| 169 | - } |
|
| 170 | - |
|
| 171 | - |
|
| 172 | - /** |
|
| 173 | - * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated |
|
| 174 | - * |
|
| 175 | - * @return int |
|
| 176 | - * @throws EE_Error |
|
| 177 | - * @throws InvalidArgumentException |
|
| 178 | - * @throws InvalidDataTypeException |
|
| 179 | - * @throws InvalidInterfaceException |
|
| 180 | - * @throws ReflectionException |
|
| 181 | - */ |
|
| 182 | - protected function _remove_expired_lock() |
|
| 183 | - { |
|
| 184 | - $locked = $this->_get_lock(); |
|
| 185 | - if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) { |
|
| 186 | - return $this->unlock(); |
|
| 187 | - } |
|
| 188 | - return 0; |
|
| 189 | - } |
|
| 190 | - |
|
| 191 | - |
|
| 192 | - /** |
|
| 193 | - * Set transaction total |
|
| 194 | - * |
|
| 195 | - * @param float $total total value of transaction |
|
| 196 | - * @throws EE_Error |
|
| 197 | - * @throws InvalidArgumentException |
|
| 198 | - * @throws InvalidDataTypeException |
|
| 199 | - * @throws InvalidInterfaceException |
|
| 200 | - * @throws ReflectionException |
|
| 201 | - */ |
|
| 202 | - public function set_total($total = 0.00) |
|
| 203 | - { |
|
| 204 | - $this->set('TXN_total', (float) $total); |
|
| 205 | - } |
|
| 206 | - |
|
| 207 | - |
|
| 208 | - /** |
|
| 209 | - * Set Total Amount Paid to Date |
|
| 210 | - * |
|
| 211 | - * @param float $total_paid total amount paid to date (sum of all payments) |
|
| 212 | - * @throws EE_Error |
|
| 213 | - * @throws InvalidArgumentException |
|
| 214 | - * @throws InvalidDataTypeException |
|
| 215 | - * @throws InvalidInterfaceException |
|
| 216 | - * @throws ReflectionException |
|
| 217 | - */ |
|
| 218 | - public function set_paid($total_paid = 0.00) |
|
| 219 | - { |
|
| 220 | - $this->set('TXN_paid', (float) $total_paid); |
|
| 221 | - } |
|
| 222 | - |
|
| 223 | - |
|
| 224 | - /** |
|
| 225 | - * Set transaction status |
|
| 226 | - * |
|
| 227 | - * @param string $status whether the transaction is open, declined, accepted, |
|
| 228 | - * or any number of custom values that can be set |
|
| 229 | - * @throws EE_Error |
|
| 230 | - * @throws InvalidArgumentException |
|
| 231 | - * @throws InvalidDataTypeException |
|
| 232 | - * @throws InvalidInterfaceException |
|
| 233 | - * @throws ReflectionException |
|
| 234 | - */ |
|
| 235 | - public function set_status($status = '') |
|
| 236 | - { |
|
| 237 | - $this->set('STS_ID', $status); |
|
| 238 | - } |
|
| 239 | - |
|
| 240 | - |
|
| 241 | - /** |
|
| 242 | - * Set hash salt |
|
| 243 | - * |
|
| 244 | - * @param string $hash_salt required for some payment gateways |
|
| 245 | - * @throws EE_Error |
|
| 246 | - * @throws InvalidArgumentException |
|
| 247 | - * @throws InvalidDataTypeException |
|
| 248 | - * @throws InvalidInterfaceException |
|
| 249 | - * @throws ReflectionException |
|
| 250 | - */ |
|
| 251 | - public function set_hash_salt($hash_salt = '') |
|
| 252 | - { |
|
| 253 | - $this->set('TXN_hash_salt', $hash_salt); |
|
| 254 | - } |
|
| 255 | - |
|
| 256 | - |
|
| 257 | - /** |
|
| 258 | - * Sets TXN_reg_steps array |
|
| 259 | - * |
|
| 260 | - * @param array $txn_reg_steps |
|
| 261 | - * @throws EE_Error |
|
| 262 | - * @throws InvalidArgumentException |
|
| 263 | - * @throws InvalidDataTypeException |
|
| 264 | - * @throws InvalidInterfaceException |
|
| 265 | - * @throws ReflectionException |
|
| 266 | - */ |
|
| 267 | - public function set_reg_steps(array $txn_reg_steps) |
|
| 268 | - { |
|
| 269 | - $this->set('TXN_reg_steps', $txn_reg_steps); |
|
| 270 | - } |
|
| 271 | - |
|
| 272 | - |
|
| 273 | - /** |
|
| 274 | - * Gets TXN_reg_steps |
|
| 275 | - * |
|
| 276 | - * @return array |
|
| 277 | - * @throws EE_Error |
|
| 278 | - * @throws InvalidArgumentException |
|
| 279 | - * @throws InvalidDataTypeException |
|
| 280 | - * @throws InvalidInterfaceException |
|
| 281 | - * @throws ReflectionException |
|
| 282 | - */ |
|
| 283 | - public function reg_steps() |
|
| 284 | - { |
|
| 285 | - $TXN_reg_steps = $this->get('TXN_reg_steps'); |
|
| 286 | - return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array(); |
|
| 287 | - } |
|
| 288 | - |
|
| 289 | - |
|
| 290 | - /** |
|
| 291 | - * @return string of transaction's total cost, with currency symbol and decimal |
|
| 292 | - * @throws EE_Error |
|
| 293 | - * @throws InvalidArgumentException |
|
| 294 | - * @throws InvalidDataTypeException |
|
| 295 | - * @throws InvalidInterfaceException |
|
| 296 | - * @throws ReflectionException |
|
| 297 | - */ |
|
| 298 | - public function pretty_total() |
|
| 299 | - { |
|
| 300 | - return $this->get_pretty('TXN_total'); |
|
| 301 | - } |
|
| 302 | - |
|
| 303 | - |
|
| 304 | - /** |
|
| 305 | - * Gets the amount paid in a pretty string (formatted and with currency symbol) |
|
| 306 | - * |
|
| 307 | - * @return string |
|
| 308 | - * @throws EE_Error |
|
| 309 | - * @throws InvalidArgumentException |
|
| 310 | - * @throws InvalidDataTypeException |
|
| 311 | - * @throws InvalidInterfaceException |
|
| 312 | - * @throws ReflectionException |
|
| 313 | - */ |
|
| 314 | - public function pretty_paid() |
|
| 315 | - { |
|
| 316 | - return $this->get_pretty('TXN_paid'); |
|
| 317 | - } |
|
| 318 | - |
|
| 319 | - |
|
| 320 | - /** |
|
| 321 | - * calculate the amount remaining for this transaction and return; |
|
| 322 | - * |
|
| 323 | - * @return float amount remaining |
|
| 324 | - * @throws EE_Error |
|
| 325 | - * @throws InvalidArgumentException |
|
| 326 | - * @throws InvalidDataTypeException |
|
| 327 | - * @throws InvalidInterfaceException |
|
| 328 | - * @throws ReflectionException |
|
| 329 | - */ |
|
| 330 | - public function remaining() |
|
| 331 | - { |
|
| 332 | - return $this->total() - $this->paid(); |
|
| 333 | - } |
|
| 334 | - |
|
| 335 | - |
|
| 336 | - /** |
|
| 337 | - * get Transaction Total |
|
| 338 | - * |
|
| 339 | - * @return float |
|
| 340 | - * @throws EE_Error |
|
| 341 | - * @throws InvalidArgumentException |
|
| 342 | - * @throws InvalidDataTypeException |
|
| 343 | - * @throws InvalidInterfaceException |
|
| 344 | - * @throws ReflectionException |
|
| 345 | - */ |
|
| 346 | - public function total() |
|
| 347 | - { |
|
| 348 | - return (float) $this->get('TXN_total'); |
|
| 349 | - } |
|
| 350 | - |
|
| 351 | - |
|
| 352 | - /** |
|
| 353 | - * get Total Amount Paid to Date |
|
| 354 | - * |
|
| 355 | - * @return float |
|
| 356 | - * @throws EE_Error |
|
| 357 | - * @throws InvalidArgumentException |
|
| 358 | - * @throws InvalidDataTypeException |
|
| 359 | - * @throws InvalidInterfaceException |
|
| 360 | - * @throws ReflectionException |
|
| 361 | - */ |
|
| 362 | - public function paid() |
|
| 363 | - { |
|
| 364 | - return (float) $this->get('TXN_paid'); |
|
| 365 | - } |
|
| 366 | - |
|
| 367 | - |
|
| 368 | - /** |
|
| 369 | - * @return mixed|null |
|
| 370 | - * @throws EE_Error |
|
| 371 | - * @throws InvalidArgumentException |
|
| 372 | - * @throws InvalidDataTypeException |
|
| 373 | - * @throws InvalidInterfaceException |
|
| 374 | - * @throws ReflectionException |
|
| 375 | - */ |
|
| 376 | - public function get_cart_session() |
|
| 377 | - { |
|
| 378 | - $session_data = (array) $this->get('TXN_session_data'); |
|
| 379 | - return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart |
|
| 380 | - ? $session_data['cart'] |
|
| 381 | - : null; |
|
| 382 | - } |
|
| 383 | - |
|
| 384 | - |
|
| 385 | - /** |
|
| 386 | - * get Transaction session data |
|
| 387 | - * |
|
| 388 | - * @return array|mixed |
|
| 389 | - * @throws EE_Error |
|
| 390 | - * @throws InvalidArgumentException |
|
| 391 | - * @throws InvalidDataTypeException |
|
| 392 | - * @throws InvalidInterfaceException |
|
| 393 | - * @throws ReflectionException |
|
| 394 | - */ |
|
| 395 | - public function session_data() |
|
| 396 | - { |
|
| 397 | - $session_data = $this->get('TXN_session_data'); |
|
| 398 | - if (empty($session_data)) { |
|
| 399 | - $session_data = array( |
|
| 400 | - 'id' => null, |
|
| 401 | - 'user_id' => null, |
|
| 402 | - 'ip_address' => null, |
|
| 403 | - 'user_agent' => null, |
|
| 404 | - 'init_access' => null, |
|
| 405 | - 'last_access' => null, |
|
| 406 | - 'pages_visited' => array(), |
|
| 407 | - ); |
|
| 408 | - } |
|
| 409 | - return $session_data; |
|
| 410 | - } |
|
| 411 | - |
|
| 412 | - |
|
| 413 | - /** |
|
| 414 | - * Set session data within the TXN object |
|
| 415 | - * |
|
| 416 | - * @param EE_Session|array $session_data |
|
| 417 | - * @throws EE_Error |
|
| 418 | - * @throws InvalidArgumentException |
|
| 419 | - * @throws InvalidDataTypeException |
|
| 420 | - * @throws InvalidInterfaceException |
|
| 421 | - * @throws ReflectionException |
|
| 422 | - */ |
|
| 423 | - public function set_txn_session_data($session_data) |
|
| 424 | - { |
|
| 425 | - if ($session_data instanceof EE_Session) { |
|
| 426 | - $this->set('TXN_session_data', $session_data->get_session_data(null, true)); |
|
| 427 | - } else { |
|
| 428 | - $this->set('TXN_session_data', $session_data); |
|
| 429 | - } |
|
| 430 | - } |
|
| 431 | - |
|
| 432 | - |
|
| 433 | - /** |
|
| 434 | - * get Transaction hash salt |
|
| 435 | - * |
|
| 436 | - * @return mixed |
|
| 437 | - * @throws EE_Error |
|
| 438 | - * @throws InvalidArgumentException |
|
| 439 | - * @throws InvalidDataTypeException |
|
| 440 | - * @throws InvalidInterfaceException |
|
| 441 | - * @throws ReflectionException |
|
| 442 | - */ |
|
| 443 | - public function hash_salt_() |
|
| 444 | - { |
|
| 445 | - return $this->get('TXN_hash_salt'); |
|
| 446 | - } |
|
| 447 | - |
|
| 448 | - |
|
| 449 | - /** |
|
| 450 | - * Returns the transaction datetime as either: |
|
| 451 | - * - unix timestamp format ($format = false, $gmt = true) |
|
| 452 | - * - formatted date string including the UTC (timezone) offset ($format = true ($gmt |
|
| 453 | - * has no affect with this option)), this also may include a timezone abbreviation if the |
|
| 454 | - * set timezone in this class differs from what the timezone is on the blog. |
|
| 455 | - * - formatted date string including the UTC (timezone) offset (default). |
|
| 456 | - * |
|
| 457 | - * @param boolean $format - whether to return a unix timestamp (default) or formatted date string |
|
| 458 | - * @param boolean $gmt - whether to return a unix timestamp with UTC offset applied (default) |
|
| 459 | - * or no UTC offset applied |
|
| 460 | - * @return string | int |
|
| 461 | - * @throws EE_Error |
|
| 462 | - * @throws InvalidArgumentException |
|
| 463 | - * @throws InvalidDataTypeException |
|
| 464 | - * @throws InvalidInterfaceException |
|
| 465 | - * @throws ReflectionException |
|
| 466 | - */ |
|
| 467 | - public function datetime($format = false, $gmt = false) |
|
| 468 | - { |
|
| 469 | - if ($format) { |
|
| 470 | - return $this->get_pretty('TXN_timestamp'); |
|
| 471 | - } |
|
| 472 | - if ($gmt) { |
|
| 473 | - return $this->get_raw('TXN_timestamp'); |
|
| 474 | - } |
|
| 475 | - return $this->get('TXN_timestamp'); |
|
| 476 | - } |
|
| 477 | - |
|
| 478 | - |
|
| 479 | - /** |
|
| 480 | - * Gets registrations on this transaction |
|
| 481 | - * |
|
| 482 | - * @param array $query_params array of query parameters |
|
| 483 | - * @param boolean $get_cached TRUE to retrieve cached registrations or FALSE to pull from the db |
|
| 484 | - * @return EE_Base_Class[]|EE_Registration[] |
|
| 485 | - * @throws EE_Error |
|
| 486 | - * @throws InvalidArgumentException |
|
| 487 | - * @throws InvalidDataTypeException |
|
| 488 | - * @throws InvalidInterfaceException |
|
| 489 | - * @throws ReflectionException |
|
| 490 | - */ |
|
| 491 | - public function registrations($query_params = array(), $get_cached = false) |
|
| 492 | - { |
|
| 493 | - $query_params = (empty($query_params) || ! is_array($query_params)) |
|
| 494 | - ? array( |
|
| 495 | - 'order_by' => array( |
|
| 496 | - 'Event.EVT_name' => 'ASC', |
|
| 497 | - 'Attendee.ATT_lname' => 'ASC', |
|
| 498 | - 'Attendee.ATT_fname' => 'ASC', |
|
| 499 | - ), |
|
| 500 | - ) |
|
| 501 | - : $query_params; |
|
| 502 | - $query_params = $get_cached ? array() : $query_params; |
|
| 503 | - return $this->get_many_related('Registration', $query_params); |
|
| 504 | - } |
|
| 505 | - |
|
| 506 | - |
|
| 507 | - /** |
|
| 508 | - * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event |
|
| 509 | - * function for getting attendees and how many registrations they each have for an event) |
|
| 510 | - * |
|
| 511 | - * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT' |
|
| 512 | - * @throws EE_Error |
|
| 513 | - * @throws InvalidArgumentException |
|
| 514 | - * @throws InvalidDataTypeException |
|
| 515 | - * @throws InvalidInterfaceException |
|
| 516 | - * @throws ReflectionException |
|
| 517 | - */ |
|
| 518 | - public function attendees() |
|
| 519 | - { |
|
| 520 | - return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID()))); |
|
| 521 | - } |
|
| 522 | - |
|
| 523 | - |
|
| 524 | - /** |
|
| 525 | - * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default |
|
| 526 | - * |
|
| 527 | - * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 528 | - * @return EE_Base_Class[]|EE_Payment[] |
|
| 529 | - * @throws EE_Error |
|
| 530 | - * @throws InvalidArgumentException |
|
| 531 | - * @throws InvalidDataTypeException |
|
| 532 | - * @throws InvalidInterfaceException |
|
| 533 | - * @throws ReflectionException |
|
| 534 | - */ |
|
| 535 | - public function payments($query_params = array()) |
|
| 536 | - { |
|
| 537 | - return $this->get_many_related('Payment', $query_params); |
|
| 538 | - } |
|
| 539 | - |
|
| 540 | - |
|
| 541 | - /** |
|
| 542 | - * gets only approved payments for this transaction |
|
| 543 | - * |
|
| 544 | - * @return EE_Base_Class[]|EE_Payment[] |
|
| 545 | - * @throws EE_Error |
|
| 546 | - * @throws InvalidArgumentException |
|
| 547 | - * @throws ReflectionException |
|
| 548 | - * @throws InvalidDataTypeException |
|
| 549 | - * @throws InvalidInterfaceException |
|
| 550 | - */ |
|
| 551 | - public function approved_payments() |
|
| 552 | - { |
|
| 553 | - EE_Registry::instance()->load_model('Payment'); |
|
| 554 | - return $this->get_many_related( |
|
| 555 | - 'Payment', |
|
| 556 | - array( |
|
| 557 | - array('STS_ID' => EEM_Payment::status_id_approved), |
|
| 558 | - 'order_by' => array('PAY_timestamp' => 'DESC'), |
|
| 559 | - ) |
|
| 560 | - ); |
|
| 561 | - } |
|
| 562 | - |
|
| 563 | - |
|
| 564 | - /** |
|
| 565 | - * Gets all payments which have not been approved |
|
| 566 | - * |
|
| 567 | - * @return EE_Base_Class[]|EEI_Payment[] |
|
| 568 | - * @throws EE_Error if a model is misconfigured somehow |
|
| 569 | - * @throws InvalidArgumentException |
|
| 570 | - * @throws InvalidDataTypeException |
|
| 571 | - * @throws InvalidInterfaceException |
|
| 572 | - * @throws ReflectionException |
|
| 573 | - */ |
|
| 574 | - public function pending_payments() |
|
| 575 | - { |
|
| 576 | - return $this->get_many_related( |
|
| 577 | - 'Payment', |
|
| 578 | - array( |
|
| 579 | - array( |
|
| 580 | - 'STS_ID' => EEM_Payment::status_id_pending, |
|
| 581 | - ), |
|
| 582 | - 'order_by' => array( |
|
| 583 | - 'PAY_timestamp' => 'DESC', |
|
| 584 | - ), |
|
| 585 | - ) |
|
| 586 | - ); |
|
| 587 | - } |
|
| 588 | - |
|
| 589 | - |
|
| 590 | - /** |
|
| 591 | - * echoes $this->pretty_status() |
|
| 592 | - * |
|
| 593 | - * @param bool $show_icons |
|
| 594 | - * @throws EE_Error |
|
| 595 | - * @throws InvalidArgumentException |
|
| 596 | - * @throws InvalidDataTypeException |
|
| 597 | - * @throws InvalidInterfaceException |
|
| 598 | - * @throws ReflectionException |
|
| 599 | - */ |
|
| 600 | - public function e_pretty_status($show_icons = false) |
|
| 601 | - { |
|
| 602 | - echo $this->pretty_status($show_icons); |
|
| 603 | - } |
|
| 604 | - |
|
| 605 | - |
|
| 606 | - /** |
|
| 607 | - * returns a pretty version of the status, good for displaying to users |
|
| 608 | - * |
|
| 609 | - * @param bool $show_icons |
|
| 610 | - * @return string |
|
| 611 | - * @throws EE_Error |
|
| 612 | - * @throws InvalidArgumentException |
|
| 613 | - * @throws InvalidDataTypeException |
|
| 614 | - * @throws InvalidInterfaceException |
|
| 615 | - * @throws ReflectionException |
|
| 616 | - */ |
|
| 617 | - public function pretty_status($show_icons = false) |
|
| 618 | - { |
|
| 619 | - $status = EEM_Status::instance()->localized_status( |
|
| 620 | - array($this->status_ID() => __('unknown', 'event_espresso')), |
|
| 621 | - false, |
|
| 622 | - 'sentence' |
|
| 623 | - ); |
|
| 624 | - $icon = ''; |
|
| 625 | - switch ($this->status_ID()) { |
|
| 626 | - case EEM_Transaction::complete_status_code: |
|
| 627 | - $icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : ''; |
|
| 628 | - break; |
|
| 629 | - case EEM_Transaction::incomplete_status_code: |
|
| 630 | - $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>' |
|
| 631 | - : ''; |
|
| 632 | - break; |
|
| 633 | - case EEM_Transaction::abandoned_status_code: |
|
| 634 | - $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : ''; |
|
| 635 | - break; |
|
| 636 | - case EEM_Transaction::failed_status_code: |
|
| 637 | - $icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : ''; |
|
| 638 | - break; |
|
| 639 | - case EEM_Transaction::overpaid_status_code: |
|
| 640 | - $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : ''; |
|
| 641 | - break; |
|
| 642 | - } |
|
| 643 | - return $icon . $status[ $this->status_ID() ]; |
|
| 644 | - } |
|
| 645 | - |
|
| 646 | - |
|
| 647 | - /** |
|
| 648 | - * get Transaction Status |
|
| 649 | - * |
|
| 650 | - * @return mixed |
|
| 651 | - * @throws EE_Error |
|
| 652 | - * @throws InvalidArgumentException |
|
| 653 | - * @throws InvalidDataTypeException |
|
| 654 | - * @throws InvalidInterfaceException |
|
| 655 | - * @throws ReflectionException |
|
| 656 | - */ |
|
| 657 | - public function status_ID() |
|
| 658 | - { |
|
| 659 | - return $this->get('STS_ID'); |
|
| 660 | - } |
|
| 661 | - |
|
| 662 | - |
|
| 663 | - /** |
|
| 664 | - * Returns TRUE or FALSE for whether or not this transaction cost any money |
|
| 665 | - * |
|
| 666 | - * @return boolean |
|
| 667 | - * @throws EE_Error |
|
| 668 | - * @throws InvalidArgumentException |
|
| 669 | - * @throws InvalidDataTypeException |
|
| 670 | - * @throws InvalidInterfaceException |
|
| 671 | - * @throws ReflectionException |
|
| 672 | - */ |
|
| 673 | - public function is_free() |
|
| 674 | - { |
|
| 675 | - return EEH_Money::compare_floats($this->get('TXN_total'), 0, '=='); |
|
| 676 | - } |
|
| 677 | - |
|
| 678 | - |
|
| 679 | - /** |
|
| 680 | - * Returns whether this transaction is complete |
|
| 681 | - * Useful in templates and other logic for deciding if we should ask for another payment... |
|
| 682 | - * |
|
| 683 | - * @return boolean |
|
| 684 | - * @throws EE_Error |
|
| 685 | - * @throws InvalidArgumentException |
|
| 686 | - * @throws InvalidDataTypeException |
|
| 687 | - * @throws InvalidInterfaceException |
|
| 688 | - * @throws ReflectionException |
|
| 689 | - */ |
|
| 690 | - public function is_completed() |
|
| 691 | - { |
|
| 692 | - return $this->status_ID() === EEM_Transaction::complete_status_code; |
|
| 693 | - } |
|
| 694 | - |
|
| 695 | - |
|
| 696 | - /** |
|
| 697 | - * Returns whether this transaction is incomplete |
|
| 698 | - * Useful in templates and other logic for deciding if we should ask for another payment... |
|
| 699 | - * |
|
| 700 | - * @return boolean |
|
| 701 | - * @throws EE_Error |
|
| 702 | - * @throws InvalidArgumentException |
|
| 703 | - * @throws InvalidDataTypeException |
|
| 704 | - * @throws InvalidInterfaceException |
|
| 705 | - * @throws ReflectionException |
|
| 706 | - */ |
|
| 707 | - public function is_incomplete() |
|
| 708 | - { |
|
| 709 | - return $this->status_ID() === EEM_Transaction::incomplete_status_code; |
|
| 710 | - } |
|
| 711 | - |
|
| 712 | - |
|
| 713 | - /** |
|
| 714 | - * Returns whether this transaction is overpaid |
|
| 715 | - * Useful in templates and other logic for deciding if monies need to be refunded |
|
| 716 | - * |
|
| 717 | - * @return boolean |
|
| 718 | - * @throws EE_Error |
|
| 719 | - * @throws InvalidArgumentException |
|
| 720 | - * @throws InvalidDataTypeException |
|
| 721 | - * @throws InvalidInterfaceException |
|
| 722 | - * @throws ReflectionException |
|
| 723 | - */ |
|
| 724 | - public function is_overpaid() |
|
| 725 | - { |
|
| 726 | - return $this->status_ID() === EEM_Transaction::overpaid_status_code; |
|
| 727 | - } |
|
| 728 | - |
|
| 729 | - |
|
| 730 | - /** |
|
| 731 | - * Returns whether this transaction was abandoned |
|
| 732 | - * meaning that the transaction/registration process was somehow interrupted and never completed |
|
| 733 | - * but that contact information exists for at least one registrant |
|
| 734 | - * |
|
| 735 | - * @return boolean |
|
| 736 | - * @throws EE_Error |
|
| 737 | - * @throws InvalidArgumentException |
|
| 738 | - * @throws InvalidDataTypeException |
|
| 739 | - * @throws InvalidInterfaceException |
|
| 740 | - * @throws ReflectionException |
|
| 741 | - */ |
|
| 742 | - public function is_abandoned() |
|
| 743 | - { |
|
| 744 | - return $this->status_ID() === EEM_Transaction::abandoned_status_code; |
|
| 745 | - } |
|
| 746 | - |
|
| 747 | - |
|
| 748 | - /** |
|
| 749 | - * Returns whether this transaction failed |
|
| 750 | - * meaning that the transaction/registration process was somehow interrupted and never completed |
|
| 751 | - * and that NO contact information exists for any registrants |
|
| 752 | - * |
|
| 753 | - * @return boolean |
|
| 754 | - * @throws EE_Error |
|
| 755 | - * @throws InvalidArgumentException |
|
| 756 | - * @throws InvalidDataTypeException |
|
| 757 | - * @throws InvalidInterfaceException |
|
| 758 | - * @throws ReflectionException |
|
| 759 | - */ |
|
| 760 | - public function failed() |
|
| 761 | - { |
|
| 762 | - return $this->status_ID() === EEM_Transaction::failed_status_code; |
|
| 763 | - } |
|
| 764 | - |
|
| 765 | - |
|
| 766 | - /** |
|
| 767 | - * This returns the url for the invoice of this transaction |
|
| 768 | - * |
|
| 769 | - * @param string $type 'html' or 'pdf' (default is pdf) |
|
| 770 | - * @return string |
|
| 771 | - * @throws EE_Error |
|
| 772 | - * @throws InvalidArgumentException |
|
| 773 | - * @throws InvalidDataTypeException |
|
| 774 | - * @throws InvalidInterfaceException |
|
| 775 | - * @throws ReflectionException |
|
| 776 | - */ |
|
| 777 | - public function invoice_url($type = 'html') |
|
| 778 | - { |
|
| 779 | - $REG = $this->primary_registration(); |
|
| 780 | - if (! $REG instanceof EE_Registration) { |
|
| 781 | - return ''; |
|
| 782 | - } |
|
| 783 | - return $REG->invoice_url($type); |
|
| 784 | - } |
|
| 785 | - |
|
| 786 | - |
|
| 787 | - /** |
|
| 788 | - * Gets the primary registration only |
|
| 789 | - * |
|
| 790 | - * @return EE_Base_Class|EE_Registration |
|
| 791 | - * @throws EE_Error |
|
| 792 | - * @throws InvalidArgumentException |
|
| 793 | - * @throws InvalidDataTypeException |
|
| 794 | - * @throws InvalidInterfaceException |
|
| 795 | - * @throws ReflectionException |
|
| 796 | - */ |
|
| 797 | - public function primary_registration() |
|
| 798 | - { |
|
| 799 | - $registrations = (array) $this->get_many_related( |
|
| 800 | - 'Registration', |
|
| 801 | - array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT)) |
|
| 802 | - ); |
|
| 803 | - foreach ($registrations as $registration) { |
|
| 804 | - // valid registration that is NOT cancelled or declined ? |
|
| 805 | - if ( |
|
| 806 | - $registration instanceof EE_Registration |
|
| 807 | - && ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true) |
|
| 808 | - ) { |
|
| 809 | - return $registration; |
|
| 810 | - } |
|
| 811 | - } |
|
| 812 | - // nothing valid found, so just return first thing from array of results |
|
| 813 | - return reset($registrations); |
|
| 814 | - } |
|
| 815 | - |
|
| 816 | - |
|
| 817 | - /** |
|
| 818 | - * Gets the URL for viewing the receipt |
|
| 819 | - * |
|
| 820 | - * @param string $type 'pdf' or 'html' (default is 'html') |
|
| 821 | - * @return string |
|
| 822 | - * @throws EE_Error |
|
| 823 | - * @throws InvalidArgumentException |
|
| 824 | - * @throws InvalidDataTypeException |
|
| 825 | - * @throws InvalidInterfaceException |
|
| 826 | - * @throws ReflectionException |
|
| 827 | - */ |
|
| 828 | - public function receipt_url($type = 'html') |
|
| 829 | - { |
|
| 830 | - $REG = $this->primary_registration(); |
|
| 831 | - if (! $REG instanceof EE_Registration) { |
|
| 832 | - return ''; |
|
| 833 | - } |
|
| 834 | - return $REG->receipt_url($type); |
|
| 835 | - } |
|
| 836 | - |
|
| 837 | - |
|
| 838 | - /** |
|
| 839 | - * Gets the URL of the thank you page with this registration REG_url_link added as |
|
| 840 | - * a query parameter |
|
| 841 | - * |
|
| 842 | - * @return string |
|
| 843 | - * @throws EE_Error |
|
| 844 | - * @throws InvalidArgumentException |
|
| 845 | - * @throws InvalidDataTypeException |
|
| 846 | - * @throws InvalidInterfaceException |
|
| 847 | - * @throws ReflectionException |
|
| 848 | - */ |
|
| 849 | - public function payment_overview_url() |
|
| 850 | - { |
|
| 851 | - $primary_registration = $this->primary_registration(); |
|
| 852 | - return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false; |
|
| 853 | - } |
|
| 854 | - |
|
| 855 | - |
|
| 856 | - /** |
|
| 857 | - * @return string |
|
| 858 | - * @throws EE_Error |
|
| 859 | - * @throws InvalidArgumentException |
|
| 860 | - * @throws InvalidDataTypeException |
|
| 861 | - * @throws InvalidInterfaceException |
|
| 862 | - * @throws ReflectionException |
|
| 863 | - */ |
|
| 864 | - public function gateway_response_on_transaction() |
|
| 865 | - { |
|
| 866 | - $payment = $this->get_first_related('Payment'); |
|
| 867 | - return $payment instanceof EE_Payment ? $payment->gateway_response() : ''; |
|
| 868 | - } |
|
| 869 | - |
|
| 870 | - |
|
| 871 | - /** |
|
| 872 | - * Get the status object of this object |
|
| 873 | - * |
|
| 874 | - * @return EE_Base_Class|EE_Status |
|
| 875 | - * @throws EE_Error |
|
| 876 | - * @throws InvalidArgumentException |
|
| 877 | - * @throws InvalidDataTypeException |
|
| 878 | - * @throws InvalidInterfaceException |
|
| 879 | - * @throws ReflectionException |
|
| 880 | - */ |
|
| 881 | - public function status_obj() |
|
| 882 | - { |
|
| 883 | - return $this->get_first_related('Status'); |
|
| 884 | - } |
|
| 885 | - |
|
| 886 | - |
|
| 887 | - /** |
|
| 888 | - * Gets all the extra meta info on this payment |
|
| 889 | - * |
|
| 890 | - * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 891 | - * @return EE_Base_Class[]|EE_Extra_Meta |
|
| 892 | - * @throws EE_Error |
|
| 893 | - * @throws InvalidArgumentException |
|
| 894 | - * @throws InvalidDataTypeException |
|
| 895 | - * @throws InvalidInterfaceException |
|
| 896 | - * @throws ReflectionException |
|
| 897 | - */ |
|
| 898 | - public function extra_meta($query_params = array()) |
|
| 899 | - { |
|
| 900 | - return $this->get_many_related('Extra_Meta', $query_params); |
|
| 901 | - } |
|
| 902 | - |
|
| 903 | - |
|
| 904 | - /** |
|
| 905 | - * Wrapper for _add_relation_to |
|
| 906 | - * |
|
| 907 | - * @param EE_Registration $registration |
|
| 908 | - * @return EE_Base_Class the relation was added to |
|
| 909 | - * @throws EE_Error |
|
| 910 | - * @throws InvalidArgumentException |
|
| 911 | - * @throws InvalidDataTypeException |
|
| 912 | - * @throws InvalidInterfaceException |
|
| 913 | - * @throws ReflectionException |
|
| 914 | - */ |
|
| 915 | - public function add_registration(EE_Registration $registration) |
|
| 916 | - { |
|
| 917 | - return $this->_add_relation_to($registration, 'Registration'); |
|
| 918 | - } |
|
| 919 | - |
|
| 920 | - |
|
| 921 | - /** |
|
| 922 | - * Removes the given registration from being related (even before saving this transaction). |
|
| 923 | - * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations |
|
| 924 | - * |
|
| 925 | - * @param int $registration_or_id |
|
| 926 | - * @return EE_Base_Class that was removed from being related |
|
| 927 | - * @throws EE_Error |
|
| 928 | - * @throws InvalidArgumentException |
|
| 929 | - * @throws InvalidDataTypeException |
|
| 930 | - * @throws InvalidInterfaceException |
|
| 931 | - * @throws ReflectionException |
|
| 932 | - */ |
|
| 933 | - public function remove_registration_with_id($registration_or_id) |
|
| 934 | - { |
|
| 935 | - return $this->_remove_relation_to($registration_or_id, 'Registration'); |
|
| 936 | - } |
|
| 937 | - |
|
| 938 | - |
|
| 939 | - /** |
|
| 940 | - * Gets all the line items which are for ACTUAL items |
|
| 941 | - * |
|
| 942 | - * @return EE_Line_Item[] |
|
| 943 | - * @throws EE_Error |
|
| 944 | - * @throws InvalidArgumentException |
|
| 945 | - * @throws InvalidDataTypeException |
|
| 946 | - * @throws InvalidInterfaceException |
|
| 947 | - * @throws ReflectionException |
|
| 948 | - */ |
|
| 949 | - public function items_purchased() |
|
| 950 | - { |
|
| 951 | - return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item))); |
|
| 952 | - } |
|
| 953 | - |
|
| 954 | - |
|
| 955 | - /** |
|
| 956 | - * Wrapper for _add_relation_to |
|
| 957 | - * |
|
| 958 | - * @param EE_Line_Item $line_item |
|
| 959 | - * @return EE_Base_Class the relation was added to |
|
| 960 | - * @throws EE_Error |
|
| 961 | - * @throws InvalidArgumentException |
|
| 962 | - * @throws InvalidDataTypeException |
|
| 963 | - * @throws InvalidInterfaceException |
|
| 964 | - * @throws ReflectionException |
|
| 965 | - */ |
|
| 966 | - public function add_line_item(EE_Line_Item $line_item) |
|
| 967 | - { |
|
| 968 | - return $this->_add_relation_to($line_item, 'Line_Item'); |
|
| 969 | - } |
|
| 970 | - |
|
| 971 | - |
|
| 972 | - /** |
|
| 973 | - * Gets ALL the line items related to this transaction (unstructured) |
|
| 974 | - * |
|
| 975 | - * @param array $query_params |
|
| 976 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 977 | - * @throws EE_Error |
|
| 978 | - * @throws InvalidArgumentException |
|
| 979 | - * @throws InvalidDataTypeException |
|
| 980 | - * @throws InvalidInterfaceException |
|
| 981 | - * @throws ReflectionException |
|
| 982 | - */ |
|
| 983 | - public function line_items($query_params = array()) |
|
| 984 | - { |
|
| 985 | - return $this->get_many_related('Line_Item', $query_params); |
|
| 986 | - } |
|
| 987 | - |
|
| 988 | - |
|
| 989 | - /** |
|
| 990 | - * Gets all the line items which are taxes on the total |
|
| 991 | - * |
|
| 992 | - * @return EE_Line_Item[] |
|
| 993 | - * @throws EE_Error |
|
| 994 | - * @throws InvalidArgumentException |
|
| 995 | - * @throws InvalidDataTypeException |
|
| 996 | - * @throws InvalidInterfaceException |
|
| 997 | - * @throws ReflectionException |
|
| 998 | - */ |
|
| 999 | - public function tax_items() |
|
| 1000 | - { |
|
| 1001 | - return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax))); |
|
| 1002 | - } |
|
| 1003 | - |
|
| 1004 | - |
|
| 1005 | - /** |
|
| 1006 | - * Gets the total line item (which is a parent of all other related line items, |
|
| 1007 | - * meaning it takes them all into account on its total) |
|
| 1008 | - * |
|
| 1009 | - * @param bool $create_if_not_found |
|
| 1010 | - * @return EE_Line_Item|null |
|
| 1011 | - * @throws EE_Error |
|
| 1012 | - * @throws InvalidArgumentException |
|
| 1013 | - * @throws InvalidDataTypeException |
|
| 1014 | - * @throws InvalidInterfaceException |
|
| 1015 | - * @throws ReflectionException |
|
| 1016 | - */ |
|
| 1017 | - public function total_line_item(bool $create_if_not_found = true): ?EE_Line_Item |
|
| 1018 | - { |
|
| 1019 | - $item = $this->get_first_related('Line_Item', [['LIN_type' => EEM_Line_Item::type_total]]); |
|
| 1020 | - if ($item instanceof EE_Line_Item) { |
|
| 1021 | - return $item; |
|
| 1022 | - } |
|
| 1023 | - return $create_if_not_found ? EEH_Line_Item::create_total_line_item($this) : null; |
|
| 1024 | - } |
|
| 1025 | - |
|
| 1026 | - |
|
| 1027 | - /** |
|
| 1028 | - * Returns the total amount of tax on this transaction |
|
| 1029 | - * (assumes there's only one tax subtotal line item) |
|
| 1030 | - * |
|
| 1031 | - * @return float |
|
| 1032 | - * @throws EE_Error |
|
| 1033 | - * @throws InvalidArgumentException |
|
| 1034 | - * @throws InvalidDataTypeException |
|
| 1035 | - * @throws InvalidInterfaceException |
|
| 1036 | - * @throws ReflectionException |
|
| 1037 | - */ |
|
| 1038 | - public function tax_total() |
|
| 1039 | - { |
|
| 1040 | - $tax_line_item = $this->tax_total_line_item(); |
|
| 1041 | - if ($tax_line_item) { |
|
| 1042 | - return (float) $tax_line_item->total(); |
|
| 1043 | - } |
|
| 1044 | - return (float) 0; |
|
| 1045 | - } |
|
| 1046 | - |
|
| 1047 | - |
|
| 1048 | - /** |
|
| 1049 | - * Gets the tax subtotal line item (assumes there's only one) |
|
| 1050 | - * |
|
| 1051 | - * @return EE_Line_Item |
|
| 1052 | - * @throws EE_Error |
|
| 1053 | - * @throws InvalidArgumentException |
|
| 1054 | - * @throws InvalidDataTypeException |
|
| 1055 | - * @throws InvalidInterfaceException |
|
| 1056 | - * @throws ReflectionException |
|
| 1057 | - */ |
|
| 1058 | - public function tax_total_line_item() |
|
| 1059 | - { |
|
| 1060 | - return EEH_Line_Item::get_taxes_subtotal($this->total_line_item()); |
|
| 1061 | - } |
|
| 1062 | - |
|
| 1063 | - |
|
| 1064 | - /** |
|
| 1065 | - * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee. |
|
| 1066 | - * |
|
| 1067 | - * @return EE_Form_Section_Proper |
|
| 1068 | - * @throws EE_Error |
|
| 1069 | - * @throws InvalidArgumentException |
|
| 1070 | - * @throws InvalidDataTypeException |
|
| 1071 | - * @throws InvalidInterfaceException |
|
| 1072 | - * @throws ReflectionException |
|
| 1073 | - */ |
|
| 1074 | - public function billing_info() |
|
| 1075 | - { |
|
| 1076 | - $payment_method = $this->payment_method(); |
|
| 1077 | - if (! $payment_method) { |
|
| 1078 | - EE_Error::add_error( |
|
| 1079 | - __( |
|
| 1080 | - 'Could not find billing info for transaction because no gateway has been used for it yet', |
|
| 1081 | - 'event_espresso' |
|
| 1082 | - ), |
|
| 1083 | - __FILE__, |
|
| 1084 | - __FUNCTION__, |
|
| 1085 | - __LINE__ |
|
| 1086 | - ); |
|
| 1087 | - return null; |
|
| 1088 | - } |
|
| 1089 | - $primary_reg = $this->primary_registration(); |
|
| 1090 | - if (! $primary_reg) { |
|
| 1091 | - EE_Error::add_error( |
|
| 1092 | - __( |
|
| 1093 | - 'Cannot get billing info for gateway %s on transaction because no primary registration exists', |
|
| 1094 | - 'event_espresso' |
|
| 1095 | - ), |
|
| 1096 | - __FILE__, |
|
| 1097 | - __FUNCTION__, |
|
| 1098 | - __LINE__ |
|
| 1099 | - ); |
|
| 1100 | - return null; |
|
| 1101 | - } |
|
| 1102 | - $attendee = $primary_reg->attendee(); |
|
| 1103 | - if (! $attendee) { |
|
| 1104 | - EE_Error::add_error( |
|
| 1105 | - __( |
|
| 1106 | - 'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists', |
|
| 1107 | - 'event_espresso' |
|
| 1108 | - ), |
|
| 1109 | - __FILE__, |
|
| 1110 | - __FUNCTION__, |
|
| 1111 | - __LINE__ |
|
| 1112 | - ); |
|
| 1113 | - return null; |
|
| 1114 | - } |
|
| 1115 | - return $attendee->billing_info_for_payment_method($payment_method); |
|
| 1116 | - } |
|
| 1117 | - |
|
| 1118 | - |
|
| 1119 | - /** |
|
| 1120 | - * Gets PMD_ID |
|
| 1121 | - * |
|
| 1122 | - * @return int |
|
| 1123 | - * @throws EE_Error |
|
| 1124 | - * @throws InvalidArgumentException |
|
| 1125 | - * @throws InvalidDataTypeException |
|
| 1126 | - * @throws InvalidInterfaceException |
|
| 1127 | - * @throws ReflectionException |
|
| 1128 | - */ |
|
| 1129 | - public function payment_method_ID() |
|
| 1130 | - { |
|
| 1131 | - return $this->get('PMD_ID'); |
|
| 1132 | - } |
|
| 1133 | - |
|
| 1134 | - |
|
| 1135 | - /** |
|
| 1136 | - * Sets PMD_ID |
|
| 1137 | - * |
|
| 1138 | - * @param int $PMD_ID |
|
| 1139 | - * @throws EE_Error |
|
| 1140 | - * @throws InvalidArgumentException |
|
| 1141 | - * @throws InvalidDataTypeException |
|
| 1142 | - * @throws InvalidInterfaceException |
|
| 1143 | - * @throws ReflectionException |
|
| 1144 | - */ |
|
| 1145 | - public function set_payment_method_ID($PMD_ID) |
|
| 1146 | - { |
|
| 1147 | - $this->set('PMD_ID', $PMD_ID); |
|
| 1148 | - } |
|
| 1149 | - |
|
| 1150 | - |
|
| 1151 | - /** |
|
| 1152 | - * Gets the last-used payment method on this transaction |
|
| 1153 | - * (we COULD just use the last-made payment, but some payment methods, namely |
|
| 1154 | - * offline ones, dont' create payments) |
|
| 1155 | - * |
|
| 1156 | - * @return EE_Payment_Method |
|
| 1157 | - * @throws EE_Error |
|
| 1158 | - * @throws InvalidArgumentException |
|
| 1159 | - * @throws InvalidDataTypeException |
|
| 1160 | - * @throws InvalidInterfaceException |
|
| 1161 | - * @throws ReflectionException |
|
| 1162 | - */ |
|
| 1163 | - public function payment_method() |
|
| 1164 | - { |
|
| 1165 | - $pm = $this->get_first_related('Payment_Method'); |
|
| 1166 | - if ($pm instanceof EE_Payment_Method) { |
|
| 1167 | - return $pm; |
|
| 1168 | - } |
|
| 1169 | - $last_payment = $this->last_payment(); |
|
| 1170 | - if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) { |
|
| 1171 | - return $last_payment->payment_method(); |
|
| 1172 | - } |
|
| 1173 | - return null; |
|
| 1174 | - } |
|
| 1175 | - |
|
| 1176 | - |
|
| 1177 | - /** |
|
| 1178 | - * Gets the last payment made |
|
| 1179 | - * |
|
| 1180 | - * @return EE_Base_Class|EE_Payment |
|
| 1181 | - * @throws EE_Error |
|
| 1182 | - * @throws InvalidArgumentException |
|
| 1183 | - * @throws InvalidDataTypeException |
|
| 1184 | - * @throws InvalidInterfaceException |
|
| 1185 | - * @throws ReflectionException |
|
| 1186 | - */ |
|
| 1187 | - public function last_payment() |
|
| 1188 | - { |
|
| 1189 | - return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc'))); |
|
| 1190 | - } |
|
| 1191 | - |
|
| 1192 | - |
|
| 1193 | - /** |
|
| 1194 | - * Gets all the line items which are unrelated to tickets on this transaction |
|
| 1195 | - * |
|
| 1196 | - * @return EE_Line_Item[] |
|
| 1197 | - * @throws EE_Error |
|
| 1198 | - * @throws InvalidArgumentException |
|
| 1199 | - * @throws InvalidDataTypeException |
|
| 1200 | - * @throws InvalidInterfaceException |
|
| 1201 | - * @throws ReflectionException |
|
| 1202 | - */ |
|
| 1203 | - public function non_ticket_line_items() |
|
| 1204 | - { |
|
| 1205 | - return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID()); |
|
| 1206 | - } |
|
| 1207 | - |
|
| 1208 | - |
|
| 1209 | - /** |
|
| 1210 | - * possibly toggles TXN status |
|
| 1211 | - * |
|
| 1212 | - * @param boolean $update whether to save the TXN |
|
| 1213 | - * @return bool whether the TXN was saved |
|
| 1214 | - * @throws EE_Error |
|
| 1215 | - * @throws InvalidArgumentException |
|
| 1216 | - * @throws InvalidDataTypeException |
|
| 1217 | - * @throws InvalidInterfaceException |
|
| 1218 | - * @throws ReflectionException |
|
| 1219 | - * @throws RuntimeException |
|
| 1220 | - */ |
|
| 1221 | - public function update_status_based_on_total_paid($update = true) |
|
| 1222 | - { |
|
| 1223 | - // set transaction status based on comparison of TXN_paid vs TXN_total |
|
| 1224 | - if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) { |
|
| 1225 | - $new_txn_status = EEM_Transaction::overpaid_status_code; |
|
| 1226 | - } elseif (EEH_Money::compare_floats($this->paid(), $this->total())) { |
|
| 1227 | - $new_txn_status = EEM_Transaction::complete_status_code; |
|
| 1228 | - } elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) { |
|
| 1229 | - $new_txn_status = EEM_Transaction::incomplete_status_code; |
|
| 1230 | - } else { |
|
| 1231 | - throw new RuntimeException( |
|
| 1232 | - __('The total paid calculation for this transaction is inaccurate.', 'event_espresso') |
|
| 1233 | - ); |
|
| 1234 | - } |
|
| 1235 | - if ($new_txn_status !== $this->status_ID()) { |
|
| 1236 | - $this->set_status($new_txn_status); |
|
| 1237 | - if ($update) { |
|
| 1238 | - return $this->save() ? true : false; |
|
| 1239 | - } |
|
| 1240 | - } |
|
| 1241 | - return false; |
|
| 1242 | - } |
|
| 1243 | - |
|
| 1244 | - |
|
| 1245 | - /** |
|
| 1246 | - * Updates the transaction's status and total_paid based on all the payments |
|
| 1247 | - * that apply to it |
|
| 1248 | - * |
|
| 1249 | - * @deprecated |
|
| 1250 | - * @return array|bool |
|
| 1251 | - * @throws EE_Error |
|
| 1252 | - * @throws InvalidArgumentException |
|
| 1253 | - * @throws ReflectionException |
|
| 1254 | - * @throws InvalidDataTypeException |
|
| 1255 | - * @throws InvalidInterfaceException |
|
| 1256 | - */ |
|
| 1257 | - public function update_based_on_payments() |
|
| 1258 | - { |
|
| 1259 | - EE_Error::doing_it_wrong( |
|
| 1260 | - __CLASS__ . '::' . __FUNCTION__, |
|
| 1261 | - sprintf( |
|
| 1262 | - __('This method is deprecated. Please use "%s" instead', 'event_espresso'), |
|
| 1263 | - 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()' |
|
| 1264 | - ), |
|
| 1265 | - '4.6.0' |
|
| 1266 | - ); |
|
| 1267 | - /** @type EE_Transaction_Processor $transaction_processor */ |
|
| 1268 | - $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
| 1269 | - return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this); |
|
| 1270 | - } |
|
| 1271 | - |
|
| 1272 | - |
|
| 1273 | - /** |
|
| 1274 | - * @return string |
|
| 1275 | - */ |
|
| 1276 | - public function old_txn_status() |
|
| 1277 | - { |
|
| 1278 | - return $this->_old_txn_status; |
|
| 1279 | - } |
|
| 1280 | - |
|
| 1281 | - |
|
| 1282 | - /** |
|
| 1283 | - * @param string $old_txn_status |
|
| 1284 | - */ |
|
| 1285 | - public function set_old_txn_status($old_txn_status) |
|
| 1286 | - { |
|
| 1287 | - // only set the first time |
|
| 1288 | - if ($this->_old_txn_status === null) { |
|
| 1289 | - $this->_old_txn_status = $old_txn_status; |
|
| 1290 | - } |
|
| 1291 | - } |
|
| 1292 | - |
|
| 1293 | - |
|
| 1294 | - /** |
|
| 1295 | - * reg_status_updated |
|
| 1296 | - * |
|
| 1297 | - * @return bool |
|
| 1298 | - * @throws EE_Error |
|
| 1299 | - * @throws InvalidArgumentException |
|
| 1300 | - * @throws InvalidDataTypeException |
|
| 1301 | - * @throws InvalidInterfaceException |
|
| 1302 | - * @throws ReflectionException |
|
| 1303 | - */ |
|
| 1304 | - public function txn_status_updated() |
|
| 1305 | - { |
|
| 1306 | - return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null; |
|
| 1307 | - } |
|
| 1308 | - |
|
| 1309 | - |
|
| 1310 | - /** |
|
| 1311 | - * _reg_steps_completed |
|
| 1312 | - * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed, |
|
| 1313 | - * if a $reg_step_slug is provided, then this step will be skipped when testing for completion |
|
| 1314 | - * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion |
|
| 1315 | - * |
|
| 1316 | - * @param string $reg_step_slug |
|
| 1317 | - * @param bool $check_all |
|
| 1318 | - * @return bool|int |
|
| 1319 | - * @throws EE_Error |
|
| 1320 | - * @throws InvalidArgumentException |
|
| 1321 | - * @throws InvalidDataTypeException |
|
| 1322 | - * @throws InvalidInterfaceException |
|
| 1323 | - * @throws ReflectionException |
|
| 1324 | - */ |
|
| 1325 | - private function _reg_steps_completed($reg_step_slug = '', $check_all = true) |
|
| 1326 | - { |
|
| 1327 | - $reg_steps = $this->reg_steps(); |
|
| 1328 | - if (! is_array($reg_steps) || empty($reg_steps)) { |
|
| 1329 | - return false; |
|
| 1330 | - } |
|
| 1331 | - // loop thru reg steps array) |
|
| 1332 | - foreach ($reg_steps as $slug => $reg_step_completed) { |
|
| 1333 | - // if NOT checking ALL steps (only checking one step) |
|
| 1334 | - if (! $check_all) { |
|
| 1335 | - // and this is the one |
|
| 1336 | - if ($slug === $reg_step_slug) { |
|
| 1337 | - return $reg_step_completed; |
|
| 1338 | - } |
|
| 1339 | - // skip to next reg step in loop |
|
| 1340 | - continue; |
|
| 1341 | - } |
|
| 1342 | - // $check_all must be true, else we would never have gotten to this point |
|
| 1343 | - if ($slug === $reg_step_slug) { |
|
| 1344 | - // if we reach this point, then we are testing either: |
|
| 1345 | - // all_reg_steps_completed_except() or |
|
| 1346 | - // all_reg_steps_completed_except_final_step(), |
|
| 1347 | - // and since this is the reg step EXCEPTION being tested |
|
| 1348 | - // we want to return true (yes true) if this reg step is NOT completed |
|
| 1349 | - // ie: "is everything completed except the final step?" |
|
| 1350 | - // "that is correct... the final step is not completed, but all others are." |
|
| 1351 | - return $reg_step_completed !== true; |
|
| 1352 | - } |
|
| 1353 | - if ($reg_step_completed !== true) { |
|
| 1354 | - // if any reg step is NOT completed, then ALL steps are not completed |
|
| 1355 | - return false; |
|
| 1356 | - } |
|
| 1357 | - } |
|
| 1358 | - return true; |
|
| 1359 | - } |
|
| 1360 | - |
|
| 1361 | - |
|
| 1362 | - /** |
|
| 1363 | - * all_reg_steps_completed |
|
| 1364 | - * returns: |
|
| 1365 | - * true if ALL reg steps have been marked as completed |
|
| 1366 | - * or false if any step is not completed |
|
| 1367 | - * |
|
| 1368 | - * @return bool |
|
| 1369 | - * @throws EE_Error |
|
| 1370 | - * @throws InvalidArgumentException |
|
| 1371 | - * @throws InvalidDataTypeException |
|
| 1372 | - * @throws InvalidInterfaceException |
|
| 1373 | - * @throws ReflectionException |
|
| 1374 | - */ |
|
| 1375 | - public function all_reg_steps_completed() |
|
| 1376 | - { |
|
| 1377 | - return $this->_reg_steps_completed(); |
|
| 1378 | - } |
|
| 1379 | - |
|
| 1380 | - |
|
| 1381 | - /** |
|
| 1382 | - * all_reg_steps_completed_except |
|
| 1383 | - * returns: |
|
| 1384 | - * true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed |
|
| 1385 | - * or false if any other step is not completed |
|
| 1386 | - * or false if ALL steps are completed including the exception you are testing !!! |
|
| 1387 | - * |
|
| 1388 | - * @param string $exception |
|
| 1389 | - * @return bool |
|
| 1390 | - * @throws EE_Error |
|
| 1391 | - * @throws InvalidArgumentException |
|
| 1392 | - * @throws InvalidDataTypeException |
|
| 1393 | - * @throws InvalidInterfaceException |
|
| 1394 | - * @throws ReflectionException |
|
| 1395 | - */ |
|
| 1396 | - public function all_reg_steps_completed_except($exception = '') |
|
| 1397 | - { |
|
| 1398 | - return $this->_reg_steps_completed($exception); |
|
| 1399 | - } |
|
| 1400 | - |
|
| 1401 | - |
|
| 1402 | - /** |
|
| 1403 | - * all_reg_steps_completed_except |
|
| 1404 | - * returns: |
|
| 1405 | - * true if ALL reg steps, except the final step, have been marked as completed |
|
| 1406 | - * or false if any step is not completed |
|
| 1407 | - * or false if ALL steps are completed including the final step !!! |
|
| 1408 | - * |
|
| 1409 | - * @return bool |
|
| 1410 | - * @throws EE_Error |
|
| 1411 | - * @throws InvalidArgumentException |
|
| 1412 | - * @throws InvalidDataTypeException |
|
| 1413 | - * @throws InvalidInterfaceException |
|
| 1414 | - * @throws ReflectionException |
|
| 1415 | - */ |
|
| 1416 | - public function all_reg_steps_completed_except_final_step() |
|
| 1417 | - { |
|
| 1418 | - return $this->_reg_steps_completed('finalize_registration'); |
|
| 1419 | - } |
|
| 1420 | - |
|
| 1421 | - |
|
| 1422 | - /** |
|
| 1423 | - * reg_step_completed |
|
| 1424 | - * returns: |
|
| 1425 | - * true if a specific reg step has been marked as completed |
|
| 1426 | - * a Unix timestamp if it has been initialized but not yet completed, |
|
| 1427 | - * or false if it has not yet been initialized |
|
| 1428 | - * |
|
| 1429 | - * @param string $reg_step_slug |
|
| 1430 | - * @return bool|int |
|
| 1431 | - * @throws EE_Error |
|
| 1432 | - * @throws InvalidArgumentException |
|
| 1433 | - * @throws InvalidDataTypeException |
|
| 1434 | - * @throws InvalidInterfaceException |
|
| 1435 | - * @throws ReflectionException |
|
| 1436 | - */ |
|
| 1437 | - public function reg_step_completed($reg_step_slug) |
|
| 1438 | - { |
|
| 1439 | - return $this->_reg_steps_completed($reg_step_slug, false); |
|
| 1440 | - } |
|
| 1441 | - |
|
| 1442 | - |
|
| 1443 | - /** |
|
| 1444 | - * completed_final_reg_step |
|
| 1445 | - * returns: |
|
| 1446 | - * true if the finalize_registration reg step has been marked as completed |
|
| 1447 | - * a Unix timestamp if it has been initialized but not yet completed, |
|
| 1448 | - * or false if it has not yet been initialized |
|
| 1449 | - * |
|
| 1450 | - * @return bool|int |
|
| 1451 | - * @throws EE_Error |
|
| 1452 | - * @throws InvalidArgumentException |
|
| 1453 | - * @throws InvalidDataTypeException |
|
| 1454 | - * @throws InvalidInterfaceException |
|
| 1455 | - * @throws ReflectionException |
|
| 1456 | - */ |
|
| 1457 | - public function final_reg_step_completed() |
|
| 1458 | - { |
|
| 1459 | - return $this->_reg_steps_completed('finalize_registration', false); |
|
| 1460 | - } |
|
| 1461 | - |
|
| 1462 | - |
|
| 1463 | - /** |
|
| 1464 | - * set_reg_step_initiated |
|
| 1465 | - * given a valid TXN_reg_step, this sets it's value to a unix timestamp |
|
| 1466 | - * |
|
| 1467 | - * @param string $reg_step_slug |
|
| 1468 | - * @return boolean |
|
| 1469 | - * @throws EE_Error |
|
| 1470 | - * @throws InvalidArgumentException |
|
| 1471 | - * @throws InvalidDataTypeException |
|
| 1472 | - * @throws InvalidInterfaceException |
|
| 1473 | - * @throws ReflectionException |
|
| 1474 | - */ |
|
| 1475 | - public function set_reg_step_initiated($reg_step_slug) |
|
| 1476 | - { |
|
| 1477 | - return $this->_set_reg_step_completed_status($reg_step_slug, time()); |
|
| 1478 | - } |
|
| 1479 | - |
|
| 1480 | - |
|
| 1481 | - /** |
|
| 1482 | - * set_reg_step_completed |
|
| 1483 | - * given a valid TXN_reg_step, this sets the step as completed |
|
| 1484 | - * |
|
| 1485 | - * @param string $reg_step_slug |
|
| 1486 | - * @return boolean |
|
| 1487 | - * @throws EE_Error |
|
| 1488 | - * @throws InvalidArgumentException |
|
| 1489 | - * @throws InvalidDataTypeException |
|
| 1490 | - * @throws InvalidInterfaceException |
|
| 1491 | - * @throws ReflectionException |
|
| 1492 | - */ |
|
| 1493 | - public function set_reg_step_completed($reg_step_slug) |
|
| 1494 | - { |
|
| 1495 | - return $this->_set_reg_step_completed_status($reg_step_slug, true); |
|
| 1496 | - } |
|
| 1497 | - |
|
| 1498 | - |
|
| 1499 | - /** |
|
| 1500 | - * set_reg_step_completed |
|
| 1501 | - * given a valid TXN_reg_step slug, this sets the step as NOT completed |
|
| 1502 | - * |
|
| 1503 | - * @param string $reg_step_slug |
|
| 1504 | - * @return boolean |
|
| 1505 | - * @throws EE_Error |
|
| 1506 | - * @throws InvalidArgumentException |
|
| 1507 | - * @throws InvalidDataTypeException |
|
| 1508 | - * @throws InvalidInterfaceException |
|
| 1509 | - * @throws ReflectionException |
|
| 1510 | - */ |
|
| 1511 | - public function set_reg_step_not_completed($reg_step_slug) |
|
| 1512 | - { |
|
| 1513 | - return $this->_set_reg_step_completed_status($reg_step_slug, false); |
|
| 1514 | - } |
|
| 1515 | - |
|
| 1516 | - |
|
| 1517 | - /** |
|
| 1518 | - * set_reg_step_completed |
|
| 1519 | - * given a valid reg step slug, this sets the TXN_reg_step completed status which is either: |
|
| 1520 | - * |
|
| 1521 | - * @param string $reg_step_slug |
|
| 1522 | - * @param boolean|int $status |
|
| 1523 | - * @return boolean |
|
| 1524 | - * @throws EE_Error |
|
| 1525 | - * @throws InvalidArgumentException |
|
| 1526 | - * @throws InvalidDataTypeException |
|
| 1527 | - * @throws InvalidInterfaceException |
|
| 1528 | - * @throws ReflectionException |
|
| 1529 | - */ |
|
| 1530 | - private function _set_reg_step_completed_status($reg_step_slug, $status) |
|
| 1531 | - { |
|
| 1532 | - // validate status |
|
| 1533 | - $status = is_bool($status) || is_int($status) ? $status : false; |
|
| 1534 | - // get reg steps array |
|
| 1535 | - $txn_reg_steps = $this->reg_steps(); |
|
| 1536 | - // if reg step does NOT exist |
|
| 1537 | - if (! isset($txn_reg_steps[ $reg_step_slug ])) { |
|
| 1538 | - return false; |
|
| 1539 | - } |
|
| 1540 | - // if we're trying to complete a step that is already completed |
|
| 1541 | - if ($txn_reg_steps[ $reg_step_slug ] === true) { |
|
| 1542 | - return true; |
|
| 1543 | - } |
|
| 1544 | - // if we're trying to complete a step that hasn't even started |
|
| 1545 | - if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) { |
|
| 1546 | - return false; |
|
| 1547 | - } |
|
| 1548 | - // if current status value matches the incoming value (no change) |
|
| 1549 | - // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890 |
|
| 1550 | - if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) { |
|
| 1551 | - // this will happen in cases where multiple AJAX requests occur during the same step |
|
| 1552 | - return true; |
|
| 1553 | - } |
|
| 1554 | - // if we're trying to set a start time, but it has already been set... |
|
| 1555 | - if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) { |
|
| 1556 | - // skip the update below, but don't return FALSE so that errors won't be displayed |
|
| 1557 | - return true; |
|
| 1558 | - } |
|
| 1559 | - // update completed status |
|
| 1560 | - $txn_reg_steps[ $reg_step_slug ] = $status; |
|
| 1561 | - $this->set_reg_steps($txn_reg_steps); |
|
| 1562 | - $this->save(); |
|
| 1563 | - return true; |
|
| 1564 | - } |
|
| 1565 | - |
|
| 1566 | - |
|
| 1567 | - /** |
|
| 1568 | - * remove_reg_step |
|
| 1569 | - * given a valid TXN_reg_step slug, this will remove (unset) |
|
| 1570 | - * the reg step from the TXN reg step array |
|
| 1571 | - * |
|
| 1572 | - * @param string $reg_step_slug |
|
| 1573 | - * @return void |
|
| 1574 | - * @throws EE_Error |
|
| 1575 | - * @throws InvalidArgumentException |
|
| 1576 | - * @throws InvalidDataTypeException |
|
| 1577 | - * @throws InvalidInterfaceException |
|
| 1578 | - * @throws ReflectionException |
|
| 1579 | - */ |
|
| 1580 | - public function remove_reg_step($reg_step_slug) |
|
| 1581 | - { |
|
| 1582 | - // get reg steps array |
|
| 1583 | - $txn_reg_steps = $this->reg_steps(); |
|
| 1584 | - unset($txn_reg_steps[ $reg_step_slug ]); |
|
| 1585 | - $this->set_reg_steps($txn_reg_steps); |
|
| 1586 | - } |
|
| 1587 | - |
|
| 1588 | - |
|
| 1589 | - /** |
|
| 1590 | - * toggle_failed_transaction_status |
|
| 1591 | - * upgrades a TXNs status from failed to abandoned, |
|
| 1592 | - * meaning that contact information has been captured for at least one registrant |
|
| 1593 | - * |
|
| 1594 | - * @param bool $save |
|
| 1595 | - * @return bool |
|
| 1596 | - * @throws EE_Error |
|
| 1597 | - * @throws InvalidArgumentException |
|
| 1598 | - * @throws InvalidDataTypeException |
|
| 1599 | - * @throws InvalidInterfaceException |
|
| 1600 | - * @throws ReflectionException |
|
| 1601 | - */ |
|
| 1602 | - public function toggle_failed_transaction_status($save = true) |
|
| 1603 | - { |
|
| 1604 | - // if TXN status is still set as "failed"... |
|
| 1605 | - if ($this->status_ID() === EEM_Transaction::failed_status_code) { |
|
| 1606 | - $this->set_status(EEM_Transaction::abandoned_status_code); |
|
| 1607 | - if ($save) { |
|
| 1608 | - $this->save(); |
|
| 1609 | - } |
|
| 1610 | - return true; |
|
| 1611 | - } |
|
| 1612 | - return false; |
|
| 1613 | - } |
|
| 1614 | - |
|
| 1615 | - |
|
| 1616 | - /** |
|
| 1617 | - * toggle_abandoned_transaction_status |
|
| 1618 | - * upgrades a TXNs status from failed or abandoned to incomplete |
|
| 1619 | - * |
|
| 1620 | - * @return bool |
|
| 1621 | - * @throws EE_Error |
|
| 1622 | - * @throws InvalidArgumentException |
|
| 1623 | - * @throws InvalidDataTypeException |
|
| 1624 | - * @throws InvalidInterfaceException |
|
| 1625 | - * @throws ReflectionException |
|
| 1626 | - */ |
|
| 1627 | - public function toggle_abandoned_transaction_status() |
|
| 1628 | - { |
|
| 1629 | - // if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"... |
|
| 1630 | - $txn_status = $this->status_ID(); |
|
| 1631 | - if ( |
|
| 1632 | - $txn_status === EEM_Transaction::failed_status_code |
|
| 1633 | - || $txn_status === EEM_Transaction::abandoned_status_code |
|
| 1634 | - ) { |
|
| 1635 | - // if a contact record for the primary registrant has been created |
|
| 1636 | - if ( |
|
| 1637 | - $this->primary_registration() instanceof EE_Registration |
|
| 1638 | - && $this->primary_registration()->attendee() instanceof EE_Attendee |
|
| 1639 | - ) { |
|
| 1640 | - $this->set_status(EEM_Transaction::incomplete_status_code); |
|
| 1641 | - } else { |
|
| 1642 | - // no contact record? yer abandoned! |
|
| 1643 | - $this->set_status(EEM_Transaction::abandoned_status_code); |
|
| 1644 | - } |
|
| 1645 | - return true; |
|
| 1646 | - } |
|
| 1647 | - return false; |
|
| 1648 | - } |
|
| 1649 | - |
|
| 1650 | - |
|
| 1651 | - /** |
|
| 1652 | - * checks if an Abandoned TXN has any related payments, and if so, |
|
| 1653 | - * updates the TXN status based on the amount paid |
|
| 1654 | - * |
|
| 1655 | - * @throws EE_Error |
|
| 1656 | - * @throws InvalidDataTypeException |
|
| 1657 | - * @throws InvalidInterfaceException |
|
| 1658 | - * @throws InvalidArgumentException |
|
| 1659 | - * @throws RuntimeException |
|
| 1660 | - * @throws ReflectionException |
|
| 1661 | - */ |
|
| 1662 | - public function verify_abandoned_transaction_status() |
|
| 1663 | - { |
|
| 1664 | - if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) { |
|
| 1665 | - return; |
|
| 1666 | - } |
|
| 1667 | - $payments = $this->get_many_related('Payment'); |
|
| 1668 | - if (! empty($payments)) { |
|
| 1669 | - foreach ($payments as $payment) { |
|
| 1670 | - if ($payment instanceof EE_Payment) { |
|
| 1671 | - // kk this TXN should NOT be abandoned |
|
| 1672 | - $this->update_status_based_on_total_paid(); |
|
| 1673 | - if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) { |
|
| 1674 | - EE_Error::add_attention( |
|
| 1675 | - sprintf( |
|
| 1676 | - esc_html__( |
|
| 1677 | - 'The status for Transaction #%1$d has been updated from "Abandoned" to "%2$s", because at least one payment has been made towards it. If the payment appears in the "Payment Details" table below, you may need to edit its status and/or other details as well.', |
|
| 1678 | - 'event_espresso' |
|
| 1679 | - ), |
|
| 1680 | - $this->ID(), |
|
| 1681 | - $this->pretty_status() |
|
| 1682 | - ) |
|
| 1683 | - ); |
|
| 1684 | - } |
|
| 1685 | - // get final reg step status |
|
| 1686 | - $finalized = $this->final_reg_step_completed(); |
|
| 1687 | - // if the 'finalize_registration' step has been initiated (has a timestamp) |
|
| 1688 | - // but has not yet been fully completed (TRUE) |
|
| 1689 | - if (is_int($finalized) && $finalized !== false && $finalized !== true) { |
|
| 1690 | - $this->set_reg_step_completed('finalize_registration'); |
|
| 1691 | - $this->save(); |
|
| 1692 | - } |
|
| 1693 | - } |
|
| 1694 | - } |
|
| 1695 | - } |
|
| 1696 | - } |
|
| 1697 | - |
|
| 1698 | - |
|
| 1699 | - /** |
|
| 1700 | - * @since 4.10.4.p |
|
| 1701 | - * @throws EE_Error |
|
| 1702 | - * @throws InvalidArgumentException |
|
| 1703 | - * @throws InvalidDataTypeException |
|
| 1704 | - * @throws InvalidInterfaceException |
|
| 1705 | - * @throws ReflectionException |
|
| 1706 | - * @throws RuntimeException |
|
| 1707 | - */ |
|
| 1708 | - public function recalculateLineItems() |
|
| 1709 | - { |
|
| 1710 | - $total_line_item = $this->total_line_item(false); |
|
| 1711 | - if ($total_line_item instanceof EE_Line_Item) { |
|
| 1712 | - EEH_Line_Item::resetIsTaxableForTickets($total_line_item); |
|
| 1713 | - return EEH_Line_Item::apply_taxes($total_line_item, true); |
|
| 1714 | - } |
|
| 1715 | - return false; |
|
| 1716 | - } |
|
| 16 | + /** |
|
| 17 | + * The length of time in seconds that a lock is applied before being considered expired. |
|
| 18 | + * It is not long because a transaction should only be locked for the duration of the request that locked it |
|
| 19 | + */ |
|
| 20 | + const LOCK_EXPIRATION = 2; |
|
| 21 | + |
|
| 22 | + /** |
|
| 23 | + * txn status upon initial construction. |
|
| 24 | + * |
|
| 25 | + * @var string |
|
| 26 | + */ |
|
| 27 | + protected $_old_txn_status; |
|
| 28 | + |
|
| 29 | + |
|
| 30 | + /** |
|
| 31 | + * @param array $props_n_values incoming values |
|
| 32 | + * @param string $timezone incoming timezone |
|
| 33 | + * (if not set the timezone set for the website will be used.) |
|
| 34 | + * @param array $date_formats incoming date_formats in an array where the first value is the |
|
| 35 | + * date_format and the second value is the time format |
|
| 36 | + * @return EE_Transaction |
|
| 37 | + * @throws EE_Error |
|
| 38 | + * @throws InvalidArgumentException |
|
| 39 | + * @throws InvalidDataTypeException |
|
| 40 | + * @throws InvalidInterfaceException |
|
| 41 | + * @throws ReflectionException |
|
| 42 | + */ |
|
| 43 | + public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
| 44 | + { |
|
| 45 | + $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats); |
|
| 46 | + $txn = $has_object |
|
| 47 | + ? $has_object |
|
| 48 | + : new self($props_n_values, false, $timezone, $date_formats); |
|
| 49 | + if (! $has_object) { |
|
| 50 | + $txn->set_old_txn_status($txn->status_ID()); |
|
| 51 | + } |
|
| 52 | + return $txn; |
|
| 53 | + } |
|
| 54 | + |
|
| 55 | + |
|
| 56 | + /** |
|
| 57 | + * @param array $props_n_values incoming values from the database |
|
| 58 | + * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
| 59 | + * the website will be used. |
|
| 60 | + * @return EE_Transaction |
|
| 61 | + * @throws EE_Error |
|
| 62 | + * @throws InvalidArgumentException |
|
| 63 | + * @throws InvalidDataTypeException |
|
| 64 | + * @throws InvalidInterfaceException |
|
| 65 | + * @throws ReflectionException |
|
| 66 | + */ |
|
| 67 | + public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
| 68 | + { |
|
| 69 | + $txn = new self($props_n_values, true, $timezone); |
|
| 70 | + $txn->set_old_txn_status($txn->status_ID()); |
|
| 71 | + return $txn; |
|
| 72 | + } |
|
| 73 | + |
|
| 74 | + |
|
| 75 | + /** |
|
| 76 | + * Sets a meta field indicating that this TXN is locked and should not be updated in the db. |
|
| 77 | + * If a lock has already been set, then we will attempt to remove it in case it has expired. |
|
| 78 | + * If that also fails, then an exception is thrown. |
|
| 79 | + * |
|
| 80 | + * @throws EE_Error |
|
| 81 | + * @throws InvalidArgumentException |
|
| 82 | + * @throws InvalidDataTypeException |
|
| 83 | + * @throws InvalidInterfaceException |
|
| 84 | + * @throws ReflectionException |
|
| 85 | + */ |
|
| 86 | + public function lock() |
|
| 87 | + { |
|
| 88 | + // attempt to set lock, but if that fails... |
|
| 89 | + if (! $this->add_extra_meta('lock', time(), true)) { |
|
| 90 | + // then attempt to remove the lock in case it is expired |
|
| 91 | + if ($this->_remove_expired_lock()) { |
|
| 92 | + // if removal was successful, then try setting lock again |
|
| 93 | + $this->lock(); |
|
| 94 | + } else { |
|
| 95 | + // but if the lock can not be removed, then throw an exception |
|
| 96 | + throw new EE_Error( |
|
| 97 | + sprintf( |
|
| 98 | + __( |
|
| 99 | + 'Could not lock Transaction %1$d because it is already locked, meaning another part of the system is currently editing it. It should already be unlocked by the time you read this, so please refresh the page and try again.', |
|
| 100 | + 'event_espresso' |
|
| 101 | + ), |
|
| 102 | + $this->ID() |
|
| 103 | + ) |
|
| 104 | + ); |
|
| 105 | + } |
|
| 106 | + } |
|
| 107 | + } |
|
| 108 | + |
|
| 109 | + |
|
| 110 | + /** |
|
| 111 | + * removes transaction lock applied in EE_Transaction::lock() |
|
| 112 | + * |
|
| 113 | + * @return int |
|
| 114 | + * @throws EE_Error |
|
| 115 | + * @throws InvalidArgumentException |
|
| 116 | + * @throws InvalidDataTypeException |
|
| 117 | + * @throws InvalidInterfaceException |
|
| 118 | + * @throws ReflectionException |
|
| 119 | + */ |
|
| 120 | + public function unlock() |
|
| 121 | + { |
|
| 122 | + return $this->delete_extra_meta('lock'); |
|
| 123 | + } |
|
| 124 | + |
|
| 125 | + |
|
| 126 | + /** |
|
| 127 | + * Decides whether or not now is the right time to update the transaction. |
|
| 128 | + * This is useful because we don't always know if it is safe to update the transaction |
|
| 129 | + * and its related data. why? |
|
| 130 | + * because it's possible that the transaction is being used in another |
|
| 131 | + * request and could overwrite anything we save. |
|
| 132 | + * So we want to only update the txn once we know that won't happen. |
|
| 133 | + * We also check that the lock isn't expired, and remove it if it is |
|
| 134 | + * |
|
| 135 | + * @return boolean |
|
| 136 | + * @throws EE_Error |
|
| 137 | + * @throws InvalidArgumentException |
|
| 138 | + * @throws InvalidDataTypeException |
|
| 139 | + * @throws InvalidInterfaceException |
|
| 140 | + * @throws ReflectionException |
|
| 141 | + */ |
|
| 142 | + public function is_locked() |
|
| 143 | + { |
|
| 144 | + // if TXN is not locked, then return false immediately |
|
| 145 | + if (! $this->_get_lock()) { |
|
| 146 | + return false; |
|
| 147 | + } |
|
| 148 | + // if not, then let's try and remove the lock in case it's expired... |
|
| 149 | + // _remove_expired_lock() returns 0 when lock is valid (ie: removed = false) |
|
| 150 | + // and a positive number if the lock was removed (ie: number of locks deleted), |
|
| 151 | + // so we need to return the opposite |
|
| 152 | + return ! $this->_remove_expired_lock() ? true : false; |
|
| 153 | + } |
|
| 154 | + |
|
| 155 | + |
|
| 156 | + /** |
|
| 157 | + * Gets the meta field indicating that this TXN is locked |
|
| 158 | + * |
|
| 159 | + * @return int |
|
| 160 | + * @throws EE_Error |
|
| 161 | + * @throws InvalidArgumentException |
|
| 162 | + * @throws InvalidDataTypeException |
|
| 163 | + * @throws InvalidInterfaceException |
|
| 164 | + * @throws ReflectionException |
|
| 165 | + */ |
|
| 166 | + protected function _get_lock() |
|
| 167 | + { |
|
| 168 | + return (int) $this->get_extra_meta('lock', true, 0); |
|
| 169 | + } |
|
| 170 | + |
|
| 171 | + |
|
| 172 | + /** |
|
| 173 | + * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated |
|
| 174 | + * |
|
| 175 | + * @return int |
|
| 176 | + * @throws EE_Error |
|
| 177 | + * @throws InvalidArgumentException |
|
| 178 | + * @throws InvalidDataTypeException |
|
| 179 | + * @throws InvalidInterfaceException |
|
| 180 | + * @throws ReflectionException |
|
| 181 | + */ |
|
| 182 | + protected function _remove_expired_lock() |
|
| 183 | + { |
|
| 184 | + $locked = $this->_get_lock(); |
|
| 185 | + if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) { |
|
| 186 | + return $this->unlock(); |
|
| 187 | + } |
|
| 188 | + return 0; |
|
| 189 | + } |
|
| 190 | + |
|
| 191 | + |
|
| 192 | + /** |
|
| 193 | + * Set transaction total |
|
| 194 | + * |
|
| 195 | + * @param float $total total value of transaction |
|
| 196 | + * @throws EE_Error |
|
| 197 | + * @throws InvalidArgumentException |
|
| 198 | + * @throws InvalidDataTypeException |
|
| 199 | + * @throws InvalidInterfaceException |
|
| 200 | + * @throws ReflectionException |
|
| 201 | + */ |
|
| 202 | + public function set_total($total = 0.00) |
|
| 203 | + { |
|
| 204 | + $this->set('TXN_total', (float) $total); |
|
| 205 | + } |
|
| 206 | + |
|
| 207 | + |
|
| 208 | + /** |
|
| 209 | + * Set Total Amount Paid to Date |
|
| 210 | + * |
|
| 211 | + * @param float $total_paid total amount paid to date (sum of all payments) |
|
| 212 | + * @throws EE_Error |
|
| 213 | + * @throws InvalidArgumentException |
|
| 214 | + * @throws InvalidDataTypeException |
|
| 215 | + * @throws InvalidInterfaceException |
|
| 216 | + * @throws ReflectionException |
|
| 217 | + */ |
|
| 218 | + public function set_paid($total_paid = 0.00) |
|
| 219 | + { |
|
| 220 | + $this->set('TXN_paid', (float) $total_paid); |
|
| 221 | + } |
|
| 222 | + |
|
| 223 | + |
|
| 224 | + /** |
|
| 225 | + * Set transaction status |
|
| 226 | + * |
|
| 227 | + * @param string $status whether the transaction is open, declined, accepted, |
|
| 228 | + * or any number of custom values that can be set |
|
| 229 | + * @throws EE_Error |
|
| 230 | + * @throws InvalidArgumentException |
|
| 231 | + * @throws InvalidDataTypeException |
|
| 232 | + * @throws InvalidInterfaceException |
|
| 233 | + * @throws ReflectionException |
|
| 234 | + */ |
|
| 235 | + public function set_status($status = '') |
|
| 236 | + { |
|
| 237 | + $this->set('STS_ID', $status); |
|
| 238 | + } |
|
| 239 | + |
|
| 240 | + |
|
| 241 | + /** |
|
| 242 | + * Set hash salt |
|
| 243 | + * |
|
| 244 | + * @param string $hash_salt required for some payment gateways |
|
| 245 | + * @throws EE_Error |
|
| 246 | + * @throws InvalidArgumentException |
|
| 247 | + * @throws InvalidDataTypeException |
|
| 248 | + * @throws InvalidInterfaceException |
|
| 249 | + * @throws ReflectionException |
|
| 250 | + */ |
|
| 251 | + public function set_hash_salt($hash_salt = '') |
|
| 252 | + { |
|
| 253 | + $this->set('TXN_hash_salt', $hash_salt); |
|
| 254 | + } |
|
| 255 | + |
|
| 256 | + |
|
| 257 | + /** |
|
| 258 | + * Sets TXN_reg_steps array |
|
| 259 | + * |
|
| 260 | + * @param array $txn_reg_steps |
|
| 261 | + * @throws EE_Error |
|
| 262 | + * @throws InvalidArgumentException |
|
| 263 | + * @throws InvalidDataTypeException |
|
| 264 | + * @throws InvalidInterfaceException |
|
| 265 | + * @throws ReflectionException |
|
| 266 | + */ |
|
| 267 | + public function set_reg_steps(array $txn_reg_steps) |
|
| 268 | + { |
|
| 269 | + $this->set('TXN_reg_steps', $txn_reg_steps); |
|
| 270 | + } |
|
| 271 | + |
|
| 272 | + |
|
| 273 | + /** |
|
| 274 | + * Gets TXN_reg_steps |
|
| 275 | + * |
|
| 276 | + * @return array |
|
| 277 | + * @throws EE_Error |
|
| 278 | + * @throws InvalidArgumentException |
|
| 279 | + * @throws InvalidDataTypeException |
|
| 280 | + * @throws InvalidInterfaceException |
|
| 281 | + * @throws ReflectionException |
|
| 282 | + */ |
|
| 283 | + public function reg_steps() |
|
| 284 | + { |
|
| 285 | + $TXN_reg_steps = $this->get('TXN_reg_steps'); |
|
| 286 | + return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array(); |
|
| 287 | + } |
|
| 288 | + |
|
| 289 | + |
|
| 290 | + /** |
|
| 291 | + * @return string of transaction's total cost, with currency symbol and decimal |
|
| 292 | + * @throws EE_Error |
|
| 293 | + * @throws InvalidArgumentException |
|
| 294 | + * @throws InvalidDataTypeException |
|
| 295 | + * @throws InvalidInterfaceException |
|
| 296 | + * @throws ReflectionException |
|
| 297 | + */ |
|
| 298 | + public function pretty_total() |
|
| 299 | + { |
|
| 300 | + return $this->get_pretty('TXN_total'); |
|
| 301 | + } |
|
| 302 | + |
|
| 303 | + |
|
| 304 | + /** |
|
| 305 | + * Gets the amount paid in a pretty string (formatted and with currency symbol) |
|
| 306 | + * |
|
| 307 | + * @return string |
|
| 308 | + * @throws EE_Error |
|
| 309 | + * @throws InvalidArgumentException |
|
| 310 | + * @throws InvalidDataTypeException |
|
| 311 | + * @throws InvalidInterfaceException |
|
| 312 | + * @throws ReflectionException |
|
| 313 | + */ |
|
| 314 | + public function pretty_paid() |
|
| 315 | + { |
|
| 316 | + return $this->get_pretty('TXN_paid'); |
|
| 317 | + } |
|
| 318 | + |
|
| 319 | + |
|
| 320 | + /** |
|
| 321 | + * calculate the amount remaining for this transaction and return; |
|
| 322 | + * |
|
| 323 | + * @return float amount remaining |
|
| 324 | + * @throws EE_Error |
|
| 325 | + * @throws InvalidArgumentException |
|
| 326 | + * @throws InvalidDataTypeException |
|
| 327 | + * @throws InvalidInterfaceException |
|
| 328 | + * @throws ReflectionException |
|
| 329 | + */ |
|
| 330 | + public function remaining() |
|
| 331 | + { |
|
| 332 | + return $this->total() - $this->paid(); |
|
| 333 | + } |
|
| 334 | + |
|
| 335 | + |
|
| 336 | + /** |
|
| 337 | + * get Transaction Total |
|
| 338 | + * |
|
| 339 | + * @return float |
|
| 340 | + * @throws EE_Error |
|
| 341 | + * @throws InvalidArgumentException |
|
| 342 | + * @throws InvalidDataTypeException |
|
| 343 | + * @throws InvalidInterfaceException |
|
| 344 | + * @throws ReflectionException |
|
| 345 | + */ |
|
| 346 | + public function total() |
|
| 347 | + { |
|
| 348 | + return (float) $this->get('TXN_total'); |
|
| 349 | + } |
|
| 350 | + |
|
| 351 | + |
|
| 352 | + /** |
|
| 353 | + * get Total Amount Paid to Date |
|
| 354 | + * |
|
| 355 | + * @return float |
|
| 356 | + * @throws EE_Error |
|
| 357 | + * @throws InvalidArgumentException |
|
| 358 | + * @throws InvalidDataTypeException |
|
| 359 | + * @throws InvalidInterfaceException |
|
| 360 | + * @throws ReflectionException |
|
| 361 | + */ |
|
| 362 | + public function paid() |
|
| 363 | + { |
|
| 364 | + return (float) $this->get('TXN_paid'); |
|
| 365 | + } |
|
| 366 | + |
|
| 367 | + |
|
| 368 | + /** |
|
| 369 | + * @return mixed|null |
|
| 370 | + * @throws EE_Error |
|
| 371 | + * @throws InvalidArgumentException |
|
| 372 | + * @throws InvalidDataTypeException |
|
| 373 | + * @throws InvalidInterfaceException |
|
| 374 | + * @throws ReflectionException |
|
| 375 | + */ |
|
| 376 | + public function get_cart_session() |
|
| 377 | + { |
|
| 378 | + $session_data = (array) $this->get('TXN_session_data'); |
|
| 379 | + return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart |
|
| 380 | + ? $session_data['cart'] |
|
| 381 | + : null; |
|
| 382 | + } |
|
| 383 | + |
|
| 384 | + |
|
| 385 | + /** |
|
| 386 | + * get Transaction session data |
|
| 387 | + * |
|
| 388 | + * @return array|mixed |
|
| 389 | + * @throws EE_Error |
|
| 390 | + * @throws InvalidArgumentException |
|
| 391 | + * @throws InvalidDataTypeException |
|
| 392 | + * @throws InvalidInterfaceException |
|
| 393 | + * @throws ReflectionException |
|
| 394 | + */ |
|
| 395 | + public function session_data() |
|
| 396 | + { |
|
| 397 | + $session_data = $this->get('TXN_session_data'); |
|
| 398 | + if (empty($session_data)) { |
|
| 399 | + $session_data = array( |
|
| 400 | + 'id' => null, |
|
| 401 | + 'user_id' => null, |
|
| 402 | + 'ip_address' => null, |
|
| 403 | + 'user_agent' => null, |
|
| 404 | + 'init_access' => null, |
|
| 405 | + 'last_access' => null, |
|
| 406 | + 'pages_visited' => array(), |
|
| 407 | + ); |
|
| 408 | + } |
|
| 409 | + return $session_data; |
|
| 410 | + } |
|
| 411 | + |
|
| 412 | + |
|
| 413 | + /** |
|
| 414 | + * Set session data within the TXN object |
|
| 415 | + * |
|
| 416 | + * @param EE_Session|array $session_data |
|
| 417 | + * @throws EE_Error |
|
| 418 | + * @throws InvalidArgumentException |
|
| 419 | + * @throws InvalidDataTypeException |
|
| 420 | + * @throws InvalidInterfaceException |
|
| 421 | + * @throws ReflectionException |
|
| 422 | + */ |
|
| 423 | + public function set_txn_session_data($session_data) |
|
| 424 | + { |
|
| 425 | + if ($session_data instanceof EE_Session) { |
|
| 426 | + $this->set('TXN_session_data', $session_data->get_session_data(null, true)); |
|
| 427 | + } else { |
|
| 428 | + $this->set('TXN_session_data', $session_data); |
|
| 429 | + } |
|
| 430 | + } |
|
| 431 | + |
|
| 432 | + |
|
| 433 | + /** |
|
| 434 | + * get Transaction hash salt |
|
| 435 | + * |
|
| 436 | + * @return mixed |
|
| 437 | + * @throws EE_Error |
|
| 438 | + * @throws InvalidArgumentException |
|
| 439 | + * @throws InvalidDataTypeException |
|
| 440 | + * @throws InvalidInterfaceException |
|
| 441 | + * @throws ReflectionException |
|
| 442 | + */ |
|
| 443 | + public function hash_salt_() |
|
| 444 | + { |
|
| 445 | + return $this->get('TXN_hash_salt'); |
|
| 446 | + } |
|
| 447 | + |
|
| 448 | + |
|
| 449 | + /** |
|
| 450 | + * Returns the transaction datetime as either: |
|
| 451 | + * - unix timestamp format ($format = false, $gmt = true) |
|
| 452 | + * - formatted date string including the UTC (timezone) offset ($format = true ($gmt |
|
| 453 | + * has no affect with this option)), this also may include a timezone abbreviation if the |
|
| 454 | + * set timezone in this class differs from what the timezone is on the blog. |
|
| 455 | + * - formatted date string including the UTC (timezone) offset (default). |
|
| 456 | + * |
|
| 457 | + * @param boolean $format - whether to return a unix timestamp (default) or formatted date string |
|
| 458 | + * @param boolean $gmt - whether to return a unix timestamp with UTC offset applied (default) |
|
| 459 | + * or no UTC offset applied |
|
| 460 | + * @return string | int |
|
| 461 | + * @throws EE_Error |
|
| 462 | + * @throws InvalidArgumentException |
|
| 463 | + * @throws InvalidDataTypeException |
|
| 464 | + * @throws InvalidInterfaceException |
|
| 465 | + * @throws ReflectionException |
|
| 466 | + */ |
|
| 467 | + public function datetime($format = false, $gmt = false) |
|
| 468 | + { |
|
| 469 | + if ($format) { |
|
| 470 | + return $this->get_pretty('TXN_timestamp'); |
|
| 471 | + } |
|
| 472 | + if ($gmt) { |
|
| 473 | + return $this->get_raw('TXN_timestamp'); |
|
| 474 | + } |
|
| 475 | + return $this->get('TXN_timestamp'); |
|
| 476 | + } |
|
| 477 | + |
|
| 478 | + |
|
| 479 | + /** |
|
| 480 | + * Gets registrations on this transaction |
|
| 481 | + * |
|
| 482 | + * @param array $query_params array of query parameters |
|
| 483 | + * @param boolean $get_cached TRUE to retrieve cached registrations or FALSE to pull from the db |
|
| 484 | + * @return EE_Base_Class[]|EE_Registration[] |
|
| 485 | + * @throws EE_Error |
|
| 486 | + * @throws InvalidArgumentException |
|
| 487 | + * @throws InvalidDataTypeException |
|
| 488 | + * @throws InvalidInterfaceException |
|
| 489 | + * @throws ReflectionException |
|
| 490 | + */ |
|
| 491 | + public function registrations($query_params = array(), $get_cached = false) |
|
| 492 | + { |
|
| 493 | + $query_params = (empty($query_params) || ! is_array($query_params)) |
|
| 494 | + ? array( |
|
| 495 | + 'order_by' => array( |
|
| 496 | + 'Event.EVT_name' => 'ASC', |
|
| 497 | + 'Attendee.ATT_lname' => 'ASC', |
|
| 498 | + 'Attendee.ATT_fname' => 'ASC', |
|
| 499 | + ), |
|
| 500 | + ) |
|
| 501 | + : $query_params; |
|
| 502 | + $query_params = $get_cached ? array() : $query_params; |
|
| 503 | + return $this->get_many_related('Registration', $query_params); |
|
| 504 | + } |
|
| 505 | + |
|
| 506 | + |
|
| 507 | + /** |
|
| 508 | + * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event |
|
| 509 | + * function for getting attendees and how many registrations they each have for an event) |
|
| 510 | + * |
|
| 511 | + * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT' |
|
| 512 | + * @throws EE_Error |
|
| 513 | + * @throws InvalidArgumentException |
|
| 514 | + * @throws InvalidDataTypeException |
|
| 515 | + * @throws InvalidInterfaceException |
|
| 516 | + * @throws ReflectionException |
|
| 517 | + */ |
|
| 518 | + public function attendees() |
|
| 519 | + { |
|
| 520 | + return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID()))); |
|
| 521 | + } |
|
| 522 | + |
|
| 523 | + |
|
| 524 | + /** |
|
| 525 | + * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default |
|
| 526 | + * |
|
| 527 | + * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 528 | + * @return EE_Base_Class[]|EE_Payment[] |
|
| 529 | + * @throws EE_Error |
|
| 530 | + * @throws InvalidArgumentException |
|
| 531 | + * @throws InvalidDataTypeException |
|
| 532 | + * @throws InvalidInterfaceException |
|
| 533 | + * @throws ReflectionException |
|
| 534 | + */ |
|
| 535 | + public function payments($query_params = array()) |
|
| 536 | + { |
|
| 537 | + return $this->get_many_related('Payment', $query_params); |
|
| 538 | + } |
|
| 539 | + |
|
| 540 | + |
|
| 541 | + /** |
|
| 542 | + * gets only approved payments for this transaction |
|
| 543 | + * |
|
| 544 | + * @return EE_Base_Class[]|EE_Payment[] |
|
| 545 | + * @throws EE_Error |
|
| 546 | + * @throws InvalidArgumentException |
|
| 547 | + * @throws ReflectionException |
|
| 548 | + * @throws InvalidDataTypeException |
|
| 549 | + * @throws InvalidInterfaceException |
|
| 550 | + */ |
|
| 551 | + public function approved_payments() |
|
| 552 | + { |
|
| 553 | + EE_Registry::instance()->load_model('Payment'); |
|
| 554 | + return $this->get_many_related( |
|
| 555 | + 'Payment', |
|
| 556 | + array( |
|
| 557 | + array('STS_ID' => EEM_Payment::status_id_approved), |
|
| 558 | + 'order_by' => array('PAY_timestamp' => 'DESC'), |
|
| 559 | + ) |
|
| 560 | + ); |
|
| 561 | + } |
|
| 562 | + |
|
| 563 | + |
|
| 564 | + /** |
|
| 565 | + * Gets all payments which have not been approved |
|
| 566 | + * |
|
| 567 | + * @return EE_Base_Class[]|EEI_Payment[] |
|
| 568 | + * @throws EE_Error if a model is misconfigured somehow |
|
| 569 | + * @throws InvalidArgumentException |
|
| 570 | + * @throws InvalidDataTypeException |
|
| 571 | + * @throws InvalidInterfaceException |
|
| 572 | + * @throws ReflectionException |
|
| 573 | + */ |
|
| 574 | + public function pending_payments() |
|
| 575 | + { |
|
| 576 | + return $this->get_many_related( |
|
| 577 | + 'Payment', |
|
| 578 | + array( |
|
| 579 | + array( |
|
| 580 | + 'STS_ID' => EEM_Payment::status_id_pending, |
|
| 581 | + ), |
|
| 582 | + 'order_by' => array( |
|
| 583 | + 'PAY_timestamp' => 'DESC', |
|
| 584 | + ), |
|
| 585 | + ) |
|
| 586 | + ); |
|
| 587 | + } |
|
| 588 | + |
|
| 589 | + |
|
| 590 | + /** |
|
| 591 | + * echoes $this->pretty_status() |
|
| 592 | + * |
|
| 593 | + * @param bool $show_icons |
|
| 594 | + * @throws EE_Error |
|
| 595 | + * @throws InvalidArgumentException |
|
| 596 | + * @throws InvalidDataTypeException |
|
| 597 | + * @throws InvalidInterfaceException |
|
| 598 | + * @throws ReflectionException |
|
| 599 | + */ |
|
| 600 | + public function e_pretty_status($show_icons = false) |
|
| 601 | + { |
|
| 602 | + echo $this->pretty_status($show_icons); |
|
| 603 | + } |
|
| 604 | + |
|
| 605 | + |
|
| 606 | + /** |
|
| 607 | + * returns a pretty version of the status, good for displaying to users |
|
| 608 | + * |
|
| 609 | + * @param bool $show_icons |
|
| 610 | + * @return string |
|
| 611 | + * @throws EE_Error |
|
| 612 | + * @throws InvalidArgumentException |
|
| 613 | + * @throws InvalidDataTypeException |
|
| 614 | + * @throws InvalidInterfaceException |
|
| 615 | + * @throws ReflectionException |
|
| 616 | + */ |
|
| 617 | + public function pretty_status($show_icons = false) |
|
| 618 | + { |
|
| 619 | + $status = EEM_Status::instance()->localized_status( |
|
| 620 | + array($this->status_ID() => __('unknown', 'event_espresso')), |
|
| 621 | + false, |
|
| 622 | + 'sentence' |
|
| 623 | + ); |
|
| 624 | + $icon = ''; |
|
| 625 | + switch ($this->status_ID()) { |
|
| 626 | + case EEM_Transaction::complete_status_code: |
|
| 627 | + $icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : ''; |
|
| 628 | + break; |
|
| 629 | + case EEM_Transaction::incomplete_status_code: |
|
| 630 | + $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>' |
|
| 631 | + : ''; |
|
| 632 | + break; |
|
| 633 | + case EEM_Transaction::abandoned_status_code: |
|
| 634 | + $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : ''; |
|
| 635 | + break; |
|
| 636 | + case EEM_Transaction::failed_status_code: |
|
| 637 | + $icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : ''; |
|
| 638 | + break; |
|
| 639 | + case EEM_Transaction::overpaid_status_code: |
|
| 640 | + $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : ''; |
|
| 641 | + break; |
|
| 642 | + } |
|
| 643 | + return $icon . $status[ $this->status_ID() ]; |
|
| 644 | + } |
|
| 645 | + |
|
| 646 | + |
|
| 647 | + /** |
|
| 648 | + * get Transaction Status |
|
| 649 | + * |
|
| 650 | + * @return mixed |
|
| 651 | + * @throws EE_Error |
|
| 652 | + * @throws InvalidArgumentException |
|
| 653 | + * @throws InvalidDataTypeException |
|
| 654 | + * @throws InvalidInterfaceException |
|
| 655 | + * @throws ReflectionException |
|
| 656 | + */ |
|
| 657 | + public function status_ID() |
|
| 658 | + { |
|
| 659 | + return $this->get('STS_ID'); |
|
| 660 | + } |
|
| 661 | + |
|
| 662 | + |
|
| 663 | + /** |
|
| 664 | + * Returns TRUE or FALSE for whether or not this transaction cost any money |
|
| 665 | + * |
|
| 666 | + * @return boolean |
|
| 667 | + * @throws EE_Error |
|
| 668 | + * @throws InvalidArgumentException |
|
| 669 | + * @throws InvalidDataTypeException |
|
| 670 | + * @throws InvalidInterfaceException |
|
| 671 | + * @throws ReflectionException |
|
| 672 | + */ |
|
| 673 | + public function is_free() |
|
| 674 | + { |
|
| 675 | + return EEH_Money::compare_floats($this->get('TXN_total'), 0, '=='); |
|
| 676 | + } |
|
| 677 | + |
|
| 678 | + |
|
| 679 | + /** |
|
| 680 | + * Returns whether this transaction is complete |
|
| 681 | + * Useful in templates and other logic for deciding if we should ask for another payment... |
|
| 682 | + * |
|
| 683 | + * @return boolean |
|
| 684 | + * @throws EE_Error |
|
| 685 | + * @throws InvalidArgumentException |
|
| 686 | + * @throws InvalidDataTypeException |
|
| 687 | + * @throws InvalidInterfaceException |
|
| 688 | + * @throws ReflectionException |
|
| 689 | + */ |
|
| 690 | + public function is_completed() |
|
| 691 | + { |
|
| 692 | + return $this->status_ID() === EEM_Transaction::complete_status_code; |
|
| 693 | + } |
|
| 694 | + |
|
| 695 | + |
|
| 696 | + /** |
|
| 697 | + * Returns whether this transaction is incomplete |
|
| 698 | + * Useful in templates and other logic for deciding if we should ask for another payment... |
|
| 699 | + * |
|
| 700 | + * @return boolean |
|
| 701 | + * @throws EE_Error |
|
| 702 | + * @throws InvalidArgumentException |
|
| 703 | + * @throws InvalidDataTypeException |
|
| 704 | + * @throws InvalidInterfaceException |
|
| 705 | + * @throws ReflectionException |
|
| 706 | + */ |
|
| 707 | + public function is_incomplete() |
|
| 708 | + { |
|
| 709 | + return $this->status_ID() === EEM_Transaction::incomplete_status_code; |
|
| 710 | + } |
|
| 711 | + |
|
| 712 | + |
|
| 713 | + /** |
|
| 714 | + * Returns whether this transaction is overpaid |
|
| 715 | + * Useful in templates and other logic for deciding if monies need to be refunded |
|
| 716 | + * |
|
| 717 | + * @return boolean |
|
| 718 | + * @throws EE_Error |
|
| 719 | + * @throws InvalidArgumentException |
|
| 720 | + * @throws InvalidDataTypeException |
|
| 721 | + * @throws InvalidInterfaceException |
|
| 722 | + * @throws ReflectionException |
|
| 723 | + */ |
|
| 724 | + public function is_overpaid() |
|
| 725 | + { |
|
| 726 | + return $this->status_ID() === EEM_Transaction::overpaid_status_code; |
|
| 727 | + } |
|
| 728 | + |
|
| 729 | + |
|
| 730 | + /** |
|
| 731 | + * Returns whether this transaction was abandoned |
|
| 732 | + * meaning that the transaction/registration process was somehow interrupted and never completed |
|
| 733 | + * but that contact information exists for at least one registrant |
|
| 734 | + * |
|
| 735 | + * @return boolean |
|
| 736 | + * @throws EE_Error |
|
| 737 | + * @throws InvalidArgumentException |
|
| 738 | + * @throws InvalidDataTypeException |
|
| 739 | + * @throws InvalidInterfaceException |
|
| 740 | + * @throws ReflectionException |
|
| 741 | + */ |
|
| 742 | + public function is_abandoned() |
|
| 743 | + { |
|
| 744 | + return $this->status_ID() === EEM_Transaction::abandoned_status_code; |
|
| 745 | + } |
|
| 746 | + |
|
| 747 | + |
|
| 748 | + /** |
|
| 749 | + * Returns whether this transaction failed |
|
| 750 | + * meaning that the transaction/registration process was somehow interrupted and never completed |
|
| 751 | + * and that NO contact information exists for any registrants |
|
| 752 | + * |
|
| 753 | + * @return boolean |
|
| 754 | + * @throws EE_Error |
|
| 755 | + * @throws InvalidArgumentException |
|
| 756 | + * @throws InvalidDataTypeException |
|
| 757 | + * @throws InvalidInterfaceException |
|
| 758 | + * @throws ReflectionException |
|
| 759 | + */ |
|
| 760 | + public function failed() |
|
| 761 | + { |
|
| 762 | + return $this->status_ID() === EEM_Transaction::failed_status_code; |
|
| 763 | + } |
|
| 764 | + |
|
| 765 | + |
|
| 766 | + /** |
|
| 767 | + * This returns the url for the invoice of this transaction |
|
| 768 | + * |
|
| 769 | + * @param string $type 'html' or 'pdf' (default is pdf) |
|
| 770 | + * @return string |
|
| 771 | + * @throws EE_Error |
|
| 772 | + * @throws InvalidArgumentException |
|
| 773 | + * @throws InvalidDataTypeException |
|
| 774 | + * @throws InvalidInterfaceException |
|
| 775 | + * @throws ReflectionException |
|
| 776 | + */ |
|
| 777 | + public function invoice_url($type = 'html') |
|
| 778 | + { |
|
| 779 | + $REG = $this->primary_registration(); |
|
| 780 | + if (! $REG instanceof EE_Registration) { |
|
| 781 | + return ''; |
|
| 782 | + } |
|
| 783 | + return $REG->invoice_url($type); |
|
| 784 | + } |
|
| 785 | + |
|
| 786 | + |
|
| 787 | + /** |
|
| 788 | + * Gets the primary registration only |
|
| 789 | + * |
|
| 790 | + * @return EE_Base_Class|EE_Registration |
|
| 791 | + * @throws EE_Error |
|
| 792 | + * @throws InvalidArgumentException |
|
| 793 | + * @throws InvalidDataTypeException |
|
| 794 | + * @throws InvalidInterfaceException |
|
| 795 | + * @throws ReflectionException |
|
| 796 | + */ |
|
| 797 | + public function primary_registration() |
|
| 798 | + { |
|
| 799 | + $registrations = (array) $this->get_many_related( |
|
| 800 | + 'Registration', |
|
| 801 | + array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT)) |
|
| 802 | + ); |
|
| 803 | + foreach ($registrations as $registration) { |
|
| 804 | + // valid registration that is NOT cancelled or declined ? |
|
| 805 | + if ( |
|
| 806 | + $registration instanceof EE_Registration |
|
| 807 | + && ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true) |
|
| 808 | + ) { |
|
| 809 | + return $registration; |
|
| 810 | + } |
|
| 811 | + } |
|
| 812 | + // nothing valid found, so just return first thing from array of results |
|
| 813 | + return reset($registrations); |
|
| 814 | + } |
|
| 815 | + |
|
| 816 | + |
|
| 817 | + /** |
|
| 818 | + * Gets the URL for viewing the receipt |
|
| 819 | + * |
|
| 820 | + * @param string $type 'pdf' or 'html' (default is 'html') |
|
| 821 | + * @return string |
|
| 822 | + * @throws EE_Error |
|
| 823 | + * @throws InvalidArgumentException |
|
| 824 | + * @throws InvalidDataTypeException |
|
| 825 | + * @throws InvalidInterfaceException |
|
| 826 | + * @throws ReflectionException |
|
| 827 | + */ |
|
| 828 | + public function receipt_url($type = 'html') |
|
| 829 | + { |
|
| 830 | + $REG = $this->primary_registration(); |
|
| 831 | + if (! $REG instanceof EE_Registration) { |
|
| 832 | + return ''; |
|
| 833 | + } |
|
| 834 | + return $REG->receipt_url($type); |
|
| 835 | + } |
|
| 836 | + |
|
| 837 | + |
|
| 838 | + /** |
|
| 839 | + * Gets the URL of the thank you page with this registration REG_url_link added as |
|
| 840 | + * a query parameter |
|
| 841 | + * |
|
| 842 | + * @return string |
|
| 843 | + * @throws EE_Error |
|
| 844 | + * @throws InvalidArgumentException |
|
| 845 | + * @throws InvalidDataTypeException |
|
| 846 | + * @throws InvalidInterfaceException |
|
| 847 | + * @throws ReflectionException |
|
| 848 | + */ |
|
| 849 | + public function payment_overview_url() |
|
| 850 | + { |
|
| 851 | + $primary_registration = $this->primary_registration(); |
|
| 852 | + return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false; |
|
| 853 | + } |
|
| 854 | + |
|
| 855 | + |
|
| 856 | + /** |
|
| 857 | + * @return string |
|
| 858 | + * @throws EE_Error |
|
| 859 | + * @throws InvalidArgumentException |
|
| 860 | + * @throws InvalidDataTypeException |
|
| 861 | + * @throws InvalidInterfaceException |
|
| 862 | + * @throws ReflectionException |
|
| 863 | + */ |
|
| 864 | + public function gateway_response_on_transaction() |
|
| 865 | + { |
|
| 866 | + $payment = $this->get_first_related('Payment'); |
|
| 867 | + return $payment instanceof EE_Payment ? $payment->gateway_response() : ''; |
|
| 868 | + } |
|
| 869 | + |
|
| 870 | + |
|
| 871 | + /** |
|
| 872 | + * Get the status object of this object |
|
| 873 | + * |
|
| 874 | + * @return EE_Base_Class|EE_Status |
|
| 875 | + * @throws EE_Error |
|
| 876 | + * @throws InvalidArgumentException |
|
| 877 | + * @throws InvalidDataTypeException |
|
| 878 | + * @throws InvalidInterfaceException |
|
| 879 | + * @throws ReflectionException |
|
| 880 | + */ |
|
| 881 | + public function status_obj() |
|
| 882 | + { |
|
| 883 | + return $this->get_first_related('Status'); |
|
| 884 | + } |
|
| 885 | + |
|
| 886 | + |
|
| 887 | + /** |
|
| 888 | + * Gets all the extra meta info on this payment |
|
| 889 | + * |
|
| 890 | + * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 891 | + * @return EE_Base_Class[]|EE_Extra_Meta |
|
| 892 | + * @throws EE_Error |
|
| 893 | + * @throws InvalidArgumentException |
|
| 894 | + * @throws InvalidDataTypeException |
|
| 895 | + * @throws InvalidInterfaceException |
|
| 896 | + * @throws ReflectionException |
|
| 897 | + */ |
|
| 898 | + public function extra_meta($query_params = array()) |
|
| 899 | + { |
|
| 900 | + return $this->get_many_related('Extra_Meta', $query_params); |
|
| 901 | + } |
|
| 902 | + |
|
| 903 | + |
|
| 904 | + /** |
|
| 905 | + * Wrapper for _add_relation_to |
|
| 906 | + * |
|
| 907 | + * @param EE_Registration $registration |
|
| 908 | + * @return EE_Base_Class the relation was added to |
|
| 909 | + * @throws EE_Error |
|
| 910 | + * @throws InvalidArgumentException |
|
| 911 | + * @throws InvalidDataTypeException |
|
| 912 | + * @throws InvalidInterfaceException |
|
| 913 | + * @throws ReflectionException |
|
| 914 | + */ |
|
| 915 | + public function add_registration(EE_Registration $registration) |
|
| 916 | + { |
|
| 917 | + return $this->_add_relation_to($registration, 'Registration'); |
|
| 918 | + } |
|
| 919 | + |
|
| 920 | + |
|
| 921 | + /** |
|
| 922 | + * Removes the given registration from being related (even before saving this transaction). |
|
| 923 | + * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations |
|
| 924 | + * |
|
| 925 | + * @param int $registration_or_id |
|
| 926 | + * @return EE_Base_Class that was removed from being related |
|
| 927 | + * @throws EE_Error |
|
| 928 | + * @throws InvalidArgumentException |
|
| 929 | + * @throws InvalidDataTypeException |
|
| 930 | + * @throws InvalidInterfaceException |
|
| 931 | + * @throws ReflectionException |
|
| 932 | + */ |
|
| 933 | + public function remove_registration_with_id($registration_or_id) |
|
| 934 | + { |
|
| 935 | + return $this->_remove_relation_to($registration_or_id, 'Registration'); |
|
| 936 | + } |
|
| 937 | + |
|
| 938 | + |
|
| 939 | + /** |
|
| 940 | + * Gets all the line items which are for ACTUAL items |
|
| 941 | + * |
|
| 942 | + * @return EE_Line_Item[] |
|
| 943 | + * @throws EE_Error |
|
| 944 | + * @throws InvalidArgumentException |
|
| 945 | + * @throws InvalidDataTypeException |
|
| 946 | + * @throws InvalidInterfaceException |
|
| 947 | + * @throws ReflectionException |
|
| 948 | + */ |
|
| 949 | + public function items_purchased() |
|
| 950 | + { |
|
| 951 | + return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item))); |
|
| 952 | + } |
|
| 953 | + |
|
| 954 | + |
|
| 955 | + /** |
|
| 956 | + * Wrapper for _add_relation_to |
|
| 957 | + * |
|
| 958 | + * @param EE_Line_Item $line_item |
|
| 959 | + * @return EE_Base_Class the relation was added to |
|
| 960 | + * @throws EE_Error |
|
| 961 | + * @throws InvalidArgumentException |
|
| 962 | + * @throws InvalidDataTypeException |
|
| 963 | + * @throws InvalidInterfaceException |
|
| 964 | + * @throws ReflectionException |
|
| 965 | + */ |
|
| 966 | + public function add_line_item(EE_Line_Item $line_item) |
|
| 967 | + { |
|
| 968 | + return $this->_add_relation_to($line_item, 'Line_Item'); |
|
| 969 | + } |
|
| 970 | + |
|
| 971 | + |
|
| 972 | + /** |
|
| 973 | + * Gets ALL the line items related to this transaction (unstructured) |
|
| 974 | + * |
|
| 975 | + * @param array $query_params |
|
| 976 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 977 | + * @throws EE_Error |
|
| 978 | + * @throws InvalidArgumentException |
|
| 979 | + * @throws InvalidDataTypeException |
|
| 980 | + * @throws InvalidInterfaceException |
|
| 981 | + * @throws ReflectionException |
|
| 982 | + */ |
|
| 983 | + public function line_items($query_params = array()) |
|
| 984 | + { |
|
| 985 | + return $this->get_many_related('Line_Item', $query_params); |
|
| 986 | + } |
|
| 987 | + |
|
| 988 | + |
|
| 989 | + /** |
|
| 990 | + * Gets all the line items which are taxes on the total |
|
| 991 | + * |
|
| 992 | + * @return EE_Line_Item[] |
|
| 993 | + * @throws EE_Error |
|
| 994 | + * @throws InvalidArgumentException |
|
| 995 | + * @throws InvalidDataTypeException |
|
| 996 | + * @throws InvalidInterfaceException |
|
| 997 | + * @throws ReflectionException |
|
| 998 | + */ |
|
| 999 | + public function tax_items() |
|
| 1000 | + { |
|
| 1001 | + return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax))); |
|
| 1002 | + } |
|
| 1003 | + |
|
| 1004 | + |
|
| 1005 | + /** |
|
| 1006 | + * Gets the total line item (which is a parent of all other related line items, |
|
| 1007 | + * meaning it takes them all into account on its total) |
|
| 1008 | + * |
|
| 1009 | + * @param bool $create_if_not_found |
|
| 1010 | + * @return EE_Line_Item|null |
|
| 1011 | + * @throws EE_Error |
|
| 1012 | + * @throws InvalidArgumentException |
|
| 1013 | + * @throws InvalidDataTypeException |
|
| 1014 | + * @throws InvalidInterfaceException |
|
| 1015 | + * @throws ReflectionException |
|
| 1016 | + */ |
|
| 1017 | + public function total_line_item(bool $create_if_not_found = true): ?EE_Line_Item |
|
| 1018 | + { |
|
| 1019 | + $item = $this->get_first_related('Line_Item', [['LIN_type' => EEM_Line_Item::type_total]]); |
|
| 1020 | + if ($item instanceof EE_Line_Item) { |
|
| 1021 | + return $item; |
|
| 1022 | + } |
|
| 1023 | + return $create_if_not_found ? EEH_Line_Item::create_total_line_item($this) : null; |
|
| 1024 | + } |
|
| 1025 | + |
|
| 1026 | + |
|
| 1027 | + /** |
|
| 1028 | + * Returns the total amount of tax on this transaction |
|
| 1029 | + * (assumes there's only one tax subtotal line item) |
|
| 1030 | + * |
|
| 1031 | + * @return float |
|
| 1032 | + * @throws EE_Error |
|
| 1033 | + * @throws InvalidArgumentException |
|
| 1034 | + * @throws InvalidDataTypeException |
|
| 1035 | + * @throws InvalidInterfaceException |
|
| 1036 | + * @throws ReflectionException |
|
| 1037 | + */ |
|
| 1038 | + public function tax_total() |
|
| 1039 | + { |
|
| 1040 | + $tax_line_item = $this->tax_total_line_item(); |
|
| 1041 | + if ($tax_line_item) { |
|
| 1042 | + return (float) $tax_line_item->total(); |
|
| 1043 | + } |
|
| 1044 | + return (float) 0; |
|
| 1045 | + } |
|
| 1046 | + |
|
| 1047 | + |
|
| 1048 | + /** |
|
| 1049 | + * Gets the tax subtotal line item (assumes there's only one) |
|
| 1050 | + * |
|
| 1051 | + * @return EE_Line_Item |
|
| 1052 | + * @throws EE_Error |
|
| 1053 | + * @throws InvalidArgumentException |
|
| 1054 | + * @throws InvalidDataTypeException |
|
| 1055 | + * @throws InvalidInterfaceException |
|
| 1056 | + * @throws ReflectionException |
|
| 1057 | + */ |
|
| 1058 | + public function tax_total_line_item() |
|
| 1059 | + { |
|
| 1060 | + return EEH_Line_Item::get_taxes_subtotal($this->total_line_item()); |
|
| 1061 | + } |
|
| 1062 | + |
|
| 1063 | + |
|
| 1064 | + /** |
|
| 1065 | + * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee. |
|
| 1066 | + * |
|
| 1067 | + * @return EE_Form_Section_Proper |
|
| 1068 | + * @throws EE_Error |
|
| 1069 | + * @throws InvalidArgumentException |
|
| 1070 | + * @throws InvalidDataTypeException |
|
| 1071 | + * @throws InvalidInterfaceException |
|
| 1072 | + * @throws ReflectionException |
|
| 1073 | + */ |
|
| 1074 | + public function billing_info() |
|
| 1075 | + { |
|
| 1076 | + $payment_method = $this->payment_method(); |
|
| 1077 | + if (! $payment_method) { |
|
| 1078 | + EE_Error::add_error( |
|
| 1079 | + __( |
|
| 1080 | + 'Could not find billing info for transaction because no gateway has been used for it yet', |
|
| 1081 | + 'event_espresso' |
|
| 1082 | + ), |
|
| 1083 | + __FILE__, |
|
| 1084 | + __FUNCTION__, |
|
| 1085 | + __LINE__ |
|
| 1086 | + ); |
|
| 1087 | + return null; |
|
| 1088 | + } |
|
| 1089 | + $primary_reg = $this->primary_registration(); |
|
| 1090 | + if (! $primary_reg) { |
|
| 1091 | + EE_Error::add_error( |
|
| 1092 | + __( |
|
| 1093 | + 'Cannot get billing info for gateway %s on transaction because no primary registration exists', |
|
| 1094 | + 'event_espresso' |
|
| 1095 | + ), |
|
| 1096 | + __FILE__, |
|
| 1097 | + __FUNCTION__, |
|
| 1098 | + __LINE__ |
|
| 1099 | + ); |
|
| 1100 | + return null; |
|
| 1101 | + } |
|
| 1102 | + $attendee = $primary_reg->attendee(); |
|
| 1103 | + if (! $attendee) { |
|
| 1104 | + EE_Error::add_error( |
|
| 1105 | + __( |
|
| 1106 | + 'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists', |
|
| 1107 | + 'event_espresso' |
|
| 1108 | + ), |
|
| 1109 | + __FILE__, |
|
| 1110 | + __FUNCTION__, |
|
| 1111 | + __LINE__ |
|
| 1112 | + ); |
|
| 1113 | + return null; |
|
| 1114 | + } |
|
| 1115 | + return $attendee->billing_info_for_payment_method($payment_method); |
|
| 1116 | + } |
|
| 1117 | + |
|
| 1118 | + |
|
| 1119 | + /** |
|
| 1120 | + * Gets PMD_ID |
|
| 1121 | + * |
|
| 1122 | + * @return int |
|
| 1123 | + * @throws EE_Error |
|
| 1124 | + * @throws InvalidArgumentException |
|
| 1125 | + * @throws InvalidDataTypeException |
|
| 1126 | + * @throws InvalidInterfaceException |
|
| 1127 | + * @throws ReflectionException |
|
| 1128 | + */ |
|
| 1129 | + public function payment_method_ID() |
|
| 1130 | + { |
|
| 1131 | + return $this->get('PMD_ID'); |
|
| 1132 | + } |
|
| 1133 | + |
|
| 1134 | + |
|
| 1135 | + /** |
|
| 1136 | + * Sets PMD_ID |
|
| 1137 | + * |
|
| 1138 | + * @param int $PMD_ID |
|
| 1139 | + * @throws EE_Error |
|
| 1140 | + * @throws InvalidArgumentException |
|
| 1141 | + * @throws InvalidDataTypeException |
|
| 1142 | + * @throws InvalidInterfaceException |
|
| 1143 | + * @throws ReflectionException |
|
| 1144 | + */ |
|
| 1145 | + public function set_payment_method_ID($PMD_ID) |
|
| 1146 | + { |
|
| 1147 | + $this->set('PMD_ID', $PMD_ID); |
|
| 1148 | + } |
|
| 1149 | + |
|
| 1150 | + |
|
| 1151 | + /** |
|
| 1152 | + * Gets the last-used payment method on this transaction |
|
| 1153 | + * (we COULD just use the last-made payment, but some payment methods, namely |
|
| 1154 | + * offline ones, dont' create payments) |
|
| 1155 | + * |
|
| 1156 | + * @return EE_Payment_Method |
|
| 1157 | + * @throws EE_Error |
|
| 1158 | + * @throws InvalidArgumentException |
|
| 1159 | + * @throws InvalidDataTypeException |
|
| 1160 | + * @throws InvalidInterfaceException |
|
| 1161 | + * @throws ReflectionException |
|
| 1162 | + */ |
|
| 1163 | + public function payment_method() |
|
| 1164 | + { |
|
| 1165 | + $pm = $this->get_first_related('Payment_Method'); |
|
| 1166 | + if ($pm instanceof EE_Payment_Method) { |
|
| 1167 | + return $pm; |
|
| 1168 | + } |
|
| 1169 | + $last_payment = $this->last_payment(); |
|
| 1170 | + if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) { |
|
| 1171 | + return $last_payment->payment_method(); |
|
| 1172 | + } |
|
| 1173 | + return null; |
|
| 1174 | + } |
|
| 1175 | + |
|
| 1176 | + |
|
| 1177 | + /** |
|
| 1178 | + * Gets the last payment made |
|
| 1179 | + * |
|
| 1180 | + * @return EE_Base_Class|EE_Payment |
|
| 1181 | + * @throws EE_Error |
|
| 1182 | + * @throws InvalidArgumentException |
|
| 1183 | + * @throws InvalidDataTypeException |
|
| 1184 | + * @throws InvalidInterfaceException |
|
| 1185 | + * @throws ReflectionException |
|
| 1186 | + */ |
|
| 1187 | + public function last_payment() |
|
| 1188 | + { |
|
| 1189 | + return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc'))); |
|
| 1190 | + } |
|
| 1191 | + |
|
| 1192 | + |
|
| 1193 | + /** |
|
| 1194 | + * Gets all the line items which are unrelated to tickets on this transaction |
|
| 1195 | + * |
|
| 1196 | + * @return EE_Line_Item[] |
|
| 1197 | + * @throws EE_Error |
|
| 1198 | + * @throws InvalidArgumentException |
|
| 1199 | + * @throws InvalidDataTypeException |
|
| 1200 | + * @throws InvalidInterfaceException |
|
| 1201 | + * @throws ReflectionException |
|
| 1202 | + */ |
|
| 1203 | + public function non_ticket_line_items() |
|
| 1204 | + { |
|
| 1205 | + return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID()); |
|
| 1206 | + } |
|
| 1207 | + |
|
| 1208 | + |
|
| 1209 | + /** |
|
| 1210 | + * possibly toggles TXN status |
|
| 1211 | + * |
|
| 1212 | + * @param boolean $update whether to save the TXN |
|
| 1213 | + * @return bool whether the TXN was saved |
|
| 1214 | + * @throws EE_Error |
|
| 1215 | + * @throws InvalidArgumentException |
|
| 1216 | + * @throws InvalidDataTypeException |
|
| 1217 | + * @throws InvalidInterfaceException |
|
| 1218 | + * @throws ReflectionException |
|
| 1219 | + * @throws RuntimeException |
|
| 1220 | + */ |
|
| 1221 | + public function update_status_based_on_total_paid($update = true) |
|
| 1222 | + { |
|
| 1223 | + // set transaction status based on comparison of TXN_paid vs TXN_total |
|
| 1224 | + if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) { |
|
| 1225 | + $new_txn_status = EEM_Transaction::overpaid_status_code; |
|
| 1226 | + } elseif (EEH_Money::compare_floats($this->paid(), $this->total())) { |
|
| 1227 | + $new_txn_status = EEM_Transaction::complete_status_code; |
|
| 1228 | + } elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) { |
|
| 1229 | + $new_txn_status = EEM_Transaction::incomplete_status_code; |
|
| 1230 | + } else { |
|
| 1231 | + throw new RuntimeException( |
|
| 1232 | + __('The total paid calculation for this transaction is inaccurate.', 'event_espresso') |
|
| 1233 | + ); |
|
| 1234 | + } |
|
| 1235 | + if ($new_txn_status !== $this->status_ID()) { |
|
| 1236 | + $this->set_status($new_txn_status); |
|
| 1237 | + if ($update) { |
|
| 1238 | + return $this->save() ? true : false; |
|
| 1239 | + } |
|
| 1240 | + } |
|
| 1241 | + return false; |
|
| 1242 | + } |
|
| 1243 | + |
|
| 1244 | + |
|
| 1245 | + /** |
|
| 1246 | + * Updates the transaction's status and total_paid based on all the payments |
|
| 1247 | + * that apply to it |
|
| 1248 | + * |
|
| 1249 | + * @deprecated |
|
| 1250 | + * @return array|bool |
|
| 1251 | + * @throws EE_Error |
|
| 1252 | + * @throws InvalidArgumentException |
|
| 1253 | + * @throws ReflectionException |
|
| 1254 | + * @throws InvalidDataTypeException |
|
| 1255 | + * @throws InvalidInterfaceException |
|
| 1256 | + */ |
|
| 1257 | + public function update_based_on_payments() |
|
| 1258 | + { |
|
| 1259 | + EE_Error::doing_it_wrong( |
|
| 1260 | + __CLASS__ . '::' . __FUNCTION__, |
|
| 1261 | + sprintf( |
|
| 1262 | + __('This method is deprecated. Please use "%s" instead', 'event_espresso'), |
|
| 1263 | + 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()' |
|
| 1264 | + ), |
|
| 1265 | + '4.6.0' |
|
| 1266 | + ); |
|
| 1267 | + /** @type EE_Transaction_Processor $transaction_processor */ |
|
| 1268 | + $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
| 1269 | + return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this); |
|
| 1270 | + } |
|
| 1271 | + |
|
| 1272 | + |
|
| 1273 | + /** |
|
| 1274 | + * @return string |
|
| 1275 | + */ |
|
| 1276 | + public function old_txn_status() |
|
| 1277 | + { |
|
| 1278 | + return $this->_old_txn_status; |
|
| 1279 | + } |
|
| 1280 | + |
|
| 1281 | + |
|
| 1282 | + /** |
|
| 1283 | + * @param string $old_txn_status |
|
| 1284 | + */ |
|
| 1285 | + public function set_old_txn_status($old_txn_status) |
|
| 1286 | + { |
|
| 1287 | + // only set the first time |
|
| 1288 | + if ($this->_old_txn_status === null) { |
|
| 1289 | + $this->_old_txn_status = $old_txn_status; |
|
| 1290 | + } |
|
| 1291 | + } |
|
| 1292 | + |
|
| 1293 | + |
|
| 1294 | + /** |
|
| 1295 | + * reg_status_updated |
|
| 1296 | + * |
|
| 1297 | + * @return bool |
|
| 1298 | + * @throws EE_Error |
|
| 1299 | + * @throws InvalidArgumentException |
|
| 1300 | + * @throws InvalidDataTypeException |
|
| 1301 | + * @throws InvalidInterfaceException |
|
| 1302 | + * @throws ReflectionException |
|
| 1303 | + */ |
|
| 1304 | + public function txn_status_updated() |
|
| 1305 | + { |
|
| 1306 | + return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null; |
|
| 1307 | + } |
|
| 1308 | + |
|
| 1309 | + |
|
| 1310 | + /** |
|
| 1311 | + * _reg_steps_completed |
|
| 1312 | + * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed, |
|
| 1313 | + * if a $reg_step_slug is provided, then this step will be skipped when testing for completion |
|
| 1314 | + * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion |
|
| 1315 | + * |
|
| 1316 | + * @param string $reg_step_slug |
|
| 1317 | + * @param bool $check_all |
|
| 1318 | + * @return bool|int |
|
| 1319 | + * @throws EE_Error |
|
| 1320 | + * @throws InvalidArgumentException |
|
| 1321 | + * @throws InvalidDataTypeException |
|
| 1322 | + * @throws InvalidInterfaceException |
|
| 1323 | + * @throws ReflectionException |
|
| 1324 | + */ |
|
| 1325 | + private function _reg_steps_completed($reg_step_slug = '', $check_all = true) |
|
| 1326 | + { |
|
| 1327 | + $reg_steps = $this->reg_steps(); |
|
| 1328 | + if (! is_array($reg_steps) || empty($reg_steps)) { |
|
| 1329 | + return false; |
|
| 1330 | + } |
|
| 1331 | + // loop thru reg steps array) |
|
| 1332 | + foreach ($reg_steps as $slug => $reg_step_completed) { |
|
| 1333 | + // if NOT checking ALL steps (only checking one step) |
|
| 1334 | + if (! $check_all) { |
|
| 1335 | + // and this is the one |
|
| 1336 | + if ($slug === $reg_step_slug) { |
|
| 1337 | + return $reg_step_completed; |
|
| 1338 | + } |
|
| 1339 | + // skip to next reg step in loop |
|
| 1340 | + continue; |
|
| 1341 | + } |
|
| 1342 | + // $check_all must be true, else we would never have gotten to this point |
|
| 1343 | + if ($slug === $reg_step_slug) { |
|
| 1344 | + // if we reach this point, then we are testing either: |
|
| 1345 | + // all_reg_steps_completed_except() or |
|
| 1346 | + // all_reg_steps_completed_except_final_step(), |
|
| 1347 | + // and since this is the reg step EXCEPTION being tested |
|
| 1348 | + // we want to return true (yes true) if this reg step is NOT completed |
|
| 1349 | + // ie: "is everything completed except the final step?" |
|
| 1350 | + // "that is correct... the final step is not completed, but all others are." |
|
| 1351 | + return $reg_step_completed !== true; |
|
| 1352 | + } |
|
| 1353 | + if ($reg_step_completed !== true) { |
|
| 1354 | + // if any reg step is NOT completed, then ALL steps are not completed |
|
| 1355 | + return false; |
|
| 1356 | + } |
|
| 1357 | + } |
|
| 1358 | + return true; |
|
| 1359 | + } |
|
| 1360 | + |
|
| 1361 | + |
|
| 1362 | + /** |
|
| 1363 | + * all_reg_steps_completed |
|
| 1364 | + * returns: |
|
| 1365 | + * true if ALL reg steps have been marked as completed |
|
| 1366 | + * or false if any step is not completed |
|
| 1367 | + * |
|
| 1368 | + * @return bool |
|
| 1369 | + * @throws EE_Error |
|
| 1370 | + * @throws InvalidArgumentException |
|
| 1371 | + * @throws InvalidDataTypeException |
|
| 1372 | + * @throws InvalidInterfaceException |
|
| 1373 | + * @throws ReflectionException |
|
| 1374 | + */ |
|
| 1375 | + public function all_reg_steps_completed() |
|
| 1376 | + { |
|
| 1377 | + return $this->_reg_steps_completed(); |
|
| 1378 | + } |
|
| 1379 | + |
|
| 1380 | + |
|
| 1381 | + /** |
|
| 1382 | + * all_reg_steps_completed_except |
|
| 1383 | + * returns: |
|
| 1384 | + * true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed |
|
| 1385 | + * or false if any other step is not completed |
|
| 1386 | + * or false if ALL steps are completed including the exception you are testing !!! |
|
| 1387 | + * |
|
| 1388 | + * @param string $exception |
|
| 1389 | + * @return bool |
|
| 1390 | + * @throws EE_Error |
|
| 1391 | + * @throws InvalidArgumentException |
|
| 1392 | + * @throws InvalidDataTypeException |
|
| 1393 | + * @throws InvalidInterfaceException |
|
| 1394 | + * @throws ReflectionException |
|
| 1395 | + */ |
|
| 1396 | + public function all_reg_steps_completed_except($exception = '') |
|
| 1397 | + { |
|
| 1398 | + return $this->_reg_steps_completed($exception); |
|
| 1399 | + } |
|
| 1400 | + |
|
| 1401 | + |
|
| 1402 | + /** |
|
| 1403 | + * all_reg_steps_completed_except |
|
| 1404 | + * returns: |
|
| 1405 | + * true if ALL reg steps, except the final step, have been marked as completed |
|
| 1406 | + * or false if any step is not completed |
|
| 1407 | + * or false if ALL steps are completed including the final step !!! |
|
| 1408 | + * |
|
| 1409 | + * @return bool |
|
| 1410 | + * @throws EE_Error |
|
| 1411 | + * @throws InvalidArgumentException |
|
| 1412 | + * @throws InvalidDataTypeException |
|
| 1413 | + * @throws InvalidInterfaceException |
|
| 1414 | + * @throws ReflectionException |
|
| 1415 | + */ |
|
| 1416 | + public function all_reg_steps_completed_except_final_step() |
|
| 1417 | + { |
|
| 1418 | + return $this->_reg_steps_completed('finalize_registration'); |
|
| 1419 | + } |
|
| 1420 | + |
|
| 1421 | + |
|
| 1422 | + /** |
|
| 1423 | + * reg_step_completed |
|
| 1424 | + * returns: |
|
| 1425 | + * true if a specific reg step has been marked as completed |
|
| 1426 | + * a Unix timestamp if it has been initialized but not yet completed, |
|
| 1427 | + * or false if it has not yet been initialized |
|
| 1428 | + * |
|
| 1429 | + * @param string $reg_step_slug |
|
| 1430 | + * @return bool|int |
|
| 1431 | + * @throws EE_Error |
|
| 1432 | + * @throws InvalidArgumentException |
|
| 1433 | + * @throws InvalidDataTypeException |
|
| 1434 | + * @throws InvalidInterfaceException |
|
| 1435 | + * @throws ReflectionException |
|
| 1436 | + */ |
|
| 1437 | + public function reg_step_completed($reg_step_slug) |
|
| 1438 | + { |
|
| 1439 | + return $this->_reg_steps_completed($reg_step_slug, false); |
|
| 1440 | + } |
|
| 1441 | + |
|
| 1442 | + |
|
| 1443 | + /** |
|
| 1444 | + * completed_final_reg_step |
|
| 1445 | + * returns: |
|
| 1446 | + * true if the finalize_registration reg step has been marked as completed |
|
| 1447 | + * a Unix timestamp if it has been initialized but not yet completed, |
|
| 1448 | + * or false if it has not yet been initialized |
|
| 1449 | + * |
|
| 1450 | + * @return bool|int |
|
| 1451 | + * @throws EE_Error |
|
| 1452 | + * @throws InvalidArgumentException |
|
| 1453 | + * @throws InvalidDataTypeException |
|
| 1454 | + * @throws InvalidInterfaceException |
|
| 1455 | + * @throws ReflectionException |
|
| 1456 | + */ |
|
| 1457 | + public function final_reg_step_completed() |
|
| 1458 | + { |
|
| 1459 | + return $this->_reg_steps_completed('finalize_registration', false); |
|
| 1460 | + } |
|
| 1461 | + |
|
| 1462 | + |
|
| 1463 | + /** |
|
| 1464 | + * set_reg_step_initiated |
|
| 1465 | + * given a valid TXN_reg_step, this sets it's value to a unix timestamp |
|
| 1466 | + * |
|
| 1467 | + * @param string $reg_step_slug |
|
| 1468 | + * @return boolean |
|
| 1469 | + * @throws EE_Error |
|
| 1470 | + * @throws InvalidArgumentException |
|
| 1471 | + * @throws InvalidDataTypeException |
|
| 1472 | + * @throws InvalidInterfaceException |
|
| 1473 | + * @throws ReflectionException |
|
| 1474 | + */ |
|
| 1475 | + public function set_reg_step_initiated($reg_step_slug) |
|
| 1476 | + { |
|
| 1477 | + return $this->_set_reg_step_completed_status($reg_step_slug, time()); |
|
| 1478 | + } |
|
| 1479 | + |
|
| 1480 | + |
|
| 1481 | + /** |
|
| 1482 | + * set_reg_step_completed |
|
| 1483 | + * given a valid TXN_reg_step, this sets the step as completed |
|
| 1484 | + * |
|
| 1485 | + * @param string $reg_step_slug |
|
| 1486 | + * @return boolean |
|
| 1487 | + * @throws EE_Error |
|
| 1488 | + * @throws InvalidArgumentException |
|
| 1489 | + * @throws InvalidDataTypeException |
|
| 1490 | + * @throws InvalidInterfaceException |
|
| 1491 | + * @throws ReflectionException |
|
| 1492 | + */ |
|
| 1493 | + public function set_reg_step_completed($reg_step_slug) |
|
| 1494 | + { |
|
| 1495 | + return $this->_set_reg_step_completed_status($reg_step_slug, true); |
|
| 1496 | + } |
|
| 1497 | + |
|
| 1498 | + |
|
| 1499 | + /** |
|
| 1500 | + * set_reg_step_completed |
|
| 1501 | + * given a valid TXN_reg_step slug, this sets the step as NOT completed |
|
| 1502 | + * |
|
| 1503 | + * @param string $reg_step_slug |
|
| 1504 | + * @return boolean |
|
| 1505 | + * @throws EE_Error |
|
| 1506 | + * @throws InvalidArgumentException |
|
| 1507 | + * @throws InvalidDataTypeException |
|
| 1508 | + * @throws InvalidInterfaceException |
|
| 1509 | + * @throws ReflectionException |
|
| 1510 | + */ |
|
| 1511 | + public function set_reg_step_not_completed($reg_step_slug) |
|
| 1512 | + { |
|
| 1513 | + return $this->_set_reg_step_completed_status($reg_step_slug, false); |
|
| 1514 | + } |
|
| 1515 | + |
|
| 1516 | + |
|
| 1517 | + /** |
|
| 1518 | + * set_reg_step_completed |
|
| 1519 | + * given a valid reg step slug, this sets the TXN_reg_step completed status which is either: |
|
| 1520 | + * |
|
| 1521 | + * @param string $reg_step_slug |
|
| 1522 | + * @param boolean|int $status |
|
| 1523 | + * @return boolean |
|
| 1524 | + * @throws EE_Error |
|
| 1525 | + * @throws InvalidArgumentException |
|
| 1526 | + * @throws InvalidDataTypeException |
|
| 1527 | + * @throws InvalidInterfaceException |
|
| 1528 | + * @throws ReflectionException |
|
| 1529 | + */ |
|
| 1530 | + private function _set_reg_step_completed_status($reg_step_slug, $status) |
|
| 1531 | + { |
|
| 1532 | + // validate status |
|
| 1533 | + $status = is_bool($status) || is_int($status) ? $status : false; |
|
| 1534 | + // get reg steps array |
|
| 1535 | + $txn_reg_steps = $this->reg_steps(); |
|
| 1536 | + // if reg step does NOT exist |
|
| 1537 | + if (! isset($txn_reg_steps[ $reg_step_slug ])) { |
|
| 1538 | + return false; |
|
| 1539 | + } |
|
| 1540 | + // if we're trying to complete a step that is already completed |
|
| 1541 | + if ($txn_reg_steps[ $reg_step_slug ] === true) { |
|
| 1542 | + return true; |
|
| 1543 | + } |
|
| 1544 | + // if we're trying to complete a step that hasn't even started |
|
| 1545 | + if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) { |
|
| 1546 | + return false; |
|
| 1547 | + } |
|
| 1548 | + // if current status value matches the incoming value (no change) |
|
| 1549 | + // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890 |
|
| 1550 | + if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) { |
|
| 1551 | + // this will happen in cases where multiple AJAX requests occur during the same step |
|
| 1552 | + return true; |
|
| 1553 | + } |
|
| 1554 | + // if we're trying to set a start time, but it has already been set... |
|
| 1555 | + if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) { |
|
| 1556 | + // skip the update below, but don't return FALSE so that errors won't be displayed |
|
| 1557 | + return true; |
|
| 1558 | + } |
|
| 1559 | + // update completed status |
|
| 1560 | + $txn_reg_steps[ $reg_step_slug ] = $status; |
|
| 1561 | + $this->set_reg_steps($txn_reg_steps); |
|
| 1562 | + $this->save(); |
|
| 1563 | + return true; |
|
| 1564 | + } |
|
| 1565 | + |
|
| 1566 | + |
|
| 1567 | + /** |
|
| 1568 | + * remove_reg_step |
|
| 1569 | + * given a valid TXN_reg_step slug, this will remove (unset) |
|
| 1570 | + * the reg step from the TXN reg step array |
|
| 1571 | + * |
|
| 1572 | + * @param string $reg_step_slug |
|
| 1573 | + * @return void |
|
| 1574 | + * @throws EE_Error |
|
| 1575 | + * @throws InvalidArgumentException |
|
| 1576 | + * @throws InvalidDataTypeException |
|
| 1577 | + * @throws InvalidInterfaceException |
|
| 1578 | + * @throws ReflectionException |
|
| 1579 | + */ |
|
| 1580 | + public function remove_reg_step($reg_step_slug) |
|
| 1581 | + { |
|
| 1582 | + // get reg steps array |
|
| 1583 | + $txn_reg_steps = $this->reg_steps(); |
|
| 1584 | + unset($txn_reg_steps[ $reg_step_slug ]); |
|
| 1585 | + $this->set_reg_steps($txn_reg_steps); |
|
| 1586 | + } |
|
| 1587 | + |
|
| 1588 | + |
|
| 1589 | + /** |
|
| 1590 | + * toggle_failed_transaction_status |
|
| 1591 | + * upgrades a TXNs status from failed to abandoned, |
|
| 1592 | + * meaning that contact information has been captured for at least one registrant |
|
| 1593 | + * |
|
| 1594 | + * @param bool $save |
|
| 1595 | + * @return bool |
|
| 1596 | + * @throws EE_Error |
|
| 1597 | + * @throws InvalidArgumentException |
|
| 1598 | + * @throws InvalidDataTypeException |
|
| 1599 | + * @throws InvalidInterfaceException |
|
| 1600 | + * @throws ReflectionException |
|
| 1601 | + */ |
|
| 1602 | + public function toggle_failed_transaction_status($save = true) |
|
| 1603 | + { |
|
| 1604 | + // if TXN status is still set as "failed"... |
|
| 1605 | + if ($this->status_ID() === EEM_Transaction::failed_status_code) { |
|
| 1606 | + $this->set_status(EEM_Transaction::abandoned_status_code); |
|
| 1607 | + if ($save) { |
|
| 1608 | + $this->save(); |
|
| 1609 | + } |
|
| 1610 | + return true; |
|
| 1611 | + } |
|
| 1612 | + return false; |
|
| 1613 | + } |
|
| 1614 | + |
|
| 1615 | + |
|
| 1616 | + /** |
|
| 1617 | + * toggle_abandoned_transaction_status |
|
| 1618 | + * upgrades a TXNs status from failed or abandoned to incomplete |
|
| 1619 | + * |
|
| 1620 | + * @return bool |
|
| 1621 | + * @throws EE_Error |
|
| 1622 | + * @throws InvalidArgumentException |
|
| 1623 | + * @throws InvalidDataTypeException |
|
| 1624 | + * @throws InvalidInterfaceException |
|
| 1625 | + * @throws ReflectionException |
|
| 1626 | + */ |
|
| 1627 | + public function toggle_abandoned_transaction_status() |
|
| 1628 | + { |
|
| 1629 | + // if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"... |
|
| 1630 | + $txn_status = $this->status_ID(); |
|
| 1631 | + if ( |
|
| 1632 | + $txn_status === EEM_Transaction::failed_status_code |
|
| 1633 | + || $txn_status === EEM_Transaction::abandoned_status_code |
|
| 1634 | + ) { |
|
| 1635 | + // if a contact record for the primary registrant has been created |
|
| 1636 | + if ( |
|
| 1637 | + $this->primary_registration() instanceof EE_Registration |
|
| 1638 | + && $this->primary_registration()->attendee() instanceof EE_Attendee |
|
| 1639 | + ) { |
|
| 1640 | + $this->set_status(EEM_Transaction::incomplete_status_code); |
|
| 1641 | + } else { |
|
| 1642 | + // no contact record? yer abandoned! |
|
| 1643 | + $this->set_status(EEM_Transaction::abandoned_status_code); |
|
| 1644 | + } |
|
| 1645 | + return true; |
|
| 1646 | + } |
|
| 1647 | + return false; |
|
| 1648 | + } |
|
| 1649 | + |
|
| 1650 | + |
|
| 1651 | + /** |
|
| 1652 | + * checks if an Abandoned TXN has any related payments, and if so, |
|
| 1653 | + * updates the TXN status based on the amount paid |
|
| 1654 | + * |
|
| 1655 | + * @throws EE_Error |
|
| 1656 | + * @throws InvalidDataTypeException |
|
| 1657 | + * @throws InvalidInterfaceException |
|
| 1658 | + * @throws InvalidArgumentException |
|
| 1659 | + * @throws RuntimeException |
|
| 1660 | + * @throws ReflectionException |
|
| 1661 | + */ |
|
| 1662 | + public function verify_abandoned_transaction_status() |
|
| 1663 | + { |
|
| 1664 | + if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) { |
|
| 1665 | + return; |
|
| 1666 | + } |
|
| 1667 | + $payments = $this->get_many_related('Payment'); |
|
| 1668 | + if (! empty($payments)) { |
|
| 1669 | + foreach ($payments as $payment) { |
|
| 1670 | + if ($payment instanceof EE_Payment) { |
|
| 1671 | + // kk this TXN should NOT be abandoned |
|
| 1672 | + $this->update_status_based_on_total_paid(); |
|
| 1673 | + if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) { |
|
| 1674 | + EE_Error::add_attention( |
|
| 1675 | + sprintf( |
|
| 1676 | + esc_html__( |
|
| 1677 | + 'The status for Transaction #%1$d has been updated from "Abandoned" to "%2$s", because at least one payment has been made towards it. If the payment appears in the "Payment Details" table below, you may need to edit its status and/or other details as well.', |
|
| 1678 | + 'event_espresso' |
|
| 1679 | + ), |
|
| 1680 | + $this->ID(), |
|
| 1681 | + $this->pretty_status() |
|
| 1682 | + ) |
|
| 1683 | + ); |
|
| 1684 | + } |
|
| 1685 | + // get final reg step status |
|
| 1686 | + $finalized = $this->final_reg_step_completed(); |
|
| 1687 | + // if the 'finalize_registration' step has been initiated (has a timestamp) |
|
| 1688 | + // but has not yet been fully completed (TRUE) |
|
| 1689 | + if (is_int($finalized) && $finalized !== false && $finalized !== true) { |
|
| 1690 | + $this->set_reg_step_completed('finalize_registration'); |
|
| 1691 | + $this->save(); |
|
| 1692 | + } |
|
| 1693 | + } |
|
| 1694 | + } |
|
| 1695 | + } |
|
| 1696 | + } |
|
| 1697 | + |
|
| 1698 | + |
|
| 1699 | + /** |
|
| 1700 | + * @since 4.10.4.p |
|
| 1701 | + * @throws EE_Error |
|
| 1702 | + * @throws InvalidArgumentException |
|
| 1703 | + * @throws InvalidDataTypeException |
|
| 1704 | + * @throws InvalidInterfaceException |
|
| 1705 | + * @throws ReflectionException |
|
| 1706 | + * @throws RuntimeException |
|
| 1707 | + */ |
|
| 1708 | + public function recalculateLineItems() |
|
| 1709 | + { |
|
| 1710 | + $total_line_item = $this->total_line_item(false); |
|
| 1711 | + if ($total_line_item instanceof EE_Line_Item) { |
|
| 1712 | + EEH_Line_Item::resetIsTaxableForTickets($total_line_item); |
|
| 1713 | + return EEH_Line_Item::apply_taxes($total_line_item, true); |
|
| 1714 | + } |
|
| 1715 | + return false; |
|
| 1716 | + } |
|
| 1717 | 1717 | } |
@@ -46,7 +46,7 @@ discard block |
||
| 46 | 46 | $txn = $has_object |
| 47 | 47 | ? $has_object |
| 48 | 48 | : new self($props_n_values, false, $timezone, $date_formats); |
| 49 | - if (! $has_object) { |
|
| 49 | + if ( ! $has_object) { |
|
| 50 | 50 | $txn->set_old_txn_status($txn->status_ID()); |
| 51 | 51 | } |
| 52 | 52 | return $txn; |
@@ -86,7 +86,7 @@ discard block |
||
| 86 | 86 | public function lock() |
| 87 | 87 | { |
| 88 | 88 | // attempt to set lock, but if that fails... |
| 89 | - if (! $this->add_extra_meta('lock', time(), true)) { |
|
| 89 | + if ( ! $this->add_extra_meta('lock', time(), true)) { |
|
| 90 | 90 | // then attempt to remove the lock in case it is expired |
| 91 | 91 | if ($this->_remove_expired_lock()) { |
| 92 | 92 | // if removal was successful, then try setting lock again |
@@ -142,7 +142,7 @@ discard block |
||
| 142 | 142 | public function is_locked() |
| 143 | 143 | { |
| 144 | 144 | // if TXN is not locked, then return false immediately |
| 145 | - if (! $this->_get_lock()) { |
|
| 145 | + if ( ! $this->_get_lock()) { |
|
| 146 | 146 | return false; |
| 147 | 147 | } |
| 148 | 148 | // if not, then let's try and remove the lock in case it's expired... |
@@ -640,7 +640,7 @@ discard block |
||
| 640 | 640 | $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : ''; |
| 641 | 641 | break; |
| 642 | 642 | } |
| 643 | - return $icon . $status[ $this->status_ID() ]; |
|
| 643 | + return $icon.$status[$this->status_ID()]; |
|
| 644 | 644 | } |
| 645 | 645 | |
| 646 | 646 | |
@@ -777,7 +777,7 @@ discard block |
||
| 777 | 777 | public function invoice_url($type = 'html') |
| 778 | 778 | { |
| 779 | 779 | $REG = $this->primary_registration(); |
| 780 | - if (! $REG instanceof EE_Registration) { |
|
| 780 | + if ( ! $REG instanceof EE_Registration) { |
|
| 781 | 781 | return ''; |
| 782 | 782 | } |
| 783 | 783 | return $REG->invoice_url($type); |
@@ -828,7 +828,7 @@ discard block |
||
| 828 | 828 | public function receipt_url($type = 'html') |
| 829 | 829 | { |
| 830 | 830 | $REG = $this->primary_registration(); |
| 831 | - if (! $REG instanceof EE_Registration) { |
|
| 831 | + if ( ! $REG instanceof EE_Registration) { |
|
| 832 | 832 | return ''; |
| 833 | 833 | } |
| 834 | 834 | return $REG->receipt_url($type); |
@@ -1074,7 +1074,7 @@ discard block |
||
| 1074 | 1074 | public function billing_info() |
| 1075 | 1075 | { |
| 1076 | 1076 | $payment_method = $this->payment_method(); |
| 1077 | - if (! $payment_method) { |
|
| 1077 | + if ( ! $payment_method) { |
|
| 1078 | 1078 | EE_Error::add_error( |
| 1079 | 1079 | __( |
| 1080 | 1080 | 'Could not find billing info for transaction because no gateway has been used for it yet', |
@@ -1087,7 +1087,7 @@ discard block |
||
| 1087 | 1087 | return null; |
| 1088 | 1088 | } |
| 1089 | 1089 | $primary_reg = $this->primary_registration(); |
| 1090 | - if (! $primary_reg) { |
|
| 1090 | + if ( ! $primary_reg) { |
|
| 1091 | 1091 | EE_Error::add_error( |
| 1092 | 1092 | __( |
| 1093 | 1093 | 'Cannot get billing info for gateway %s on transaction because no primary registration exists', |
@@ -1100,7 +1100,7 @@ discard block |
||
| 1100 | 1100 | return null; |
| 1101 | 1101 | } |
| 1102 | 1102 | $attendee = $primary_reg->attendee(); |
| 1103 | - if (! $attendee) { |
|
| 1103 | + if ( ! $attendee) { |
|
| 1104 | 1104 | EE_Error::add_error( |
| 1105 | 1105 | __( |
| 1106 | 1106 | 'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists', |
@@ -1257,7 +1257,7 @@ discard block |
||
| 1257 | 1257 | public function update_based_on_payments() |
| 1258 | 1258 | { |
| 1259 | 1259 | EE_Error::doing_it_wrong( |
| 1260 | - __CLASS__ . '::' . __FUNCTION__, |
|
| 1260 | + __CLASS__.'::'.__FUNCTION__, |
|
| 1261 | 1261 | sprintf( |
| 1262 | 1262 | __('This method is deprecated. Please use "%s" instead', 'event_espresso'), |
| 1263 | 1263 | 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()' |
@@ -1325,13 +1325,13 @@ discard block |
||
| 1325 | 1325 | private function _reg_steps_completed($reg_step_slug = '', $check_all = true) |
| 1326 | 1326 | { |
| 1327 | 1327 | $reg_steps = $this->reg_steps(); |
| 1328 | - if (! is_array($reg_steps) || empty($reg_steps)) { |
|
| 1328 | + if ( ! is_array($reg_steps) || empty($reg_steps)) { |
|
| 1329 | 1329 | return false; |
| 1330 | 1330 | } |
| 1331 | 1331 | // loop thru reg steps array) |
| 1332 | 1332 | foreach ($reg_steps as $slug => $reg_step_completed) { |
| 1333 | 1333 | // if NOT checking ALL steps (only checking one step) |
| 1334 | - if (! $check_all) { |
|
| 1334 | + if ( ! $check_all) { |
|
| 1335 | 1335 | // and this is the one |
| 1336 | 1336 | if ($slug === $reg_step_slug) { |
| 1337 | 1337 | return $reg_step_completed; |
@@ -1534,30 +1534,30 @@ discard block |
||
| 1534 | 1534 | // get reg steps array |
| 1535 | 1535 | $txn_reg_steps = $this->reg_steps(); |
| 1536 | 1536 | // if reg step does NOT exist |
| 1537 | - if (! isset($txn_reg_steps[ $reg_step_slug ])) { |
|
| 1537 | + if ( ! isset($txn_reg_steps[$reg_step_slug])) { |
|
| 1538 | 1538 | return false; |
| 1539 | 1539 | } |
| 1540 | 1540 | // if we're trying to complete a step that is already completed |
| 1541 | - if ($txn_reg_steps[ $reg_step_slug ] === true) { |
|
| 1541 | + if ($txn_reg_steps[$reg_step_slug] === true) { |
|
| 1542 | 1542 | return true; |
| 1543 | 1543 | } |
| 1544 | 1544 | // if we're trying to complete a step that hasn't even started |
| 1545 | - if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) { |
|
| 1545 | + if ($status === true && $txn_reg_steps[$reg_step_slug] === false) { |
|
| 1546 | 1546 | return false; |
| 1547 | 1547 | } |
| 1548 | 1548 | // if current status value matches the incoming value (no change) |
| 1549 | 1549 | // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890 |
| 1550 | - if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) { |
|
| 1550 | + if ((int) $txn_reg_steps[$reg_step_slug] === (int) $status) { |
|
| 1551 | 1551 | // this will happen in cases where multiple AJAX requests occur during the same step |
| 1552 | 1552 | return true; |
| 1553 | 1553 | } |
| 1554 | 1554 | // if we're trying to set a start time, but it has already been set... |
| 1555 | - if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) { |
|
| 1555 | + if (is_numeric($status) && is_numeric($txn_reg_steps[$reg_step_slug])) { |
|
| 1556 | 1556 | // skip the update below, but don't return FALSE so that errors won't be displayed |
| 1557 | 1557 | return true; |
| 1558 | 1558 | } |
| 1559 | 1559 | // update completed status |
| 1560 | - $txn_reg_steps[ $reg_step_slug ] = $status; |
|
| 1560 | + $txn_reg_steps[$reg_step_slug] = $status; |
|
| 1561 | 1561 | $this->set_reg_steps($txn_reg_steps); |
| 1562 | 1562 | $this->save(); |
| 1563 | 1563 | return true; |
@@ -1581,7 +1581,7 @@ discard block |
||
| 1581 | 1581 | { |
| 1582 | 1582 | // get reg steps array |
| 1583 | 1583 | $txn_reg_steps = $this->reg_steps(); |
| 1584 | - unset($txn_reg_steps[ $reg_step_slug ]); |
|
| 1584 | + unset($txn_reg_steps[$reg_step_slug]); |
|
| 1585 | 1585 | $this->set_reg_steps($txn_reg_steps); |
| 1586 | 1586 | } |
| 1587 | 1587 | |
@@ -1665,12 +1665,12 @@ discard block |
||
| 1665 | 1665 | return; |
| 1666 | 1666 | } |
| 1667 | 1667 | $payments = $this->get_many_related('Payment'); |
| 1668 | - if (! empty($payments)) { |
|
| 1668 | + if ( ! empty($payments)) { |
|
| 1669 | 1669 | foreach ($payments as $payment) { |
| 1670 | 1670 | if ($payment instanceof EE_Payment) { |
| 1671 | 1671 | // kk this TXN should NOT be abandoned |
| 1672 | 1672 | $this->update_status_based_on_total_paid(); |
| 1673 | - if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) { |
|
| 1673 | + if ( ! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) { |
|
| 1674 | 1674 | EE_Error::add_attention( |
| 1675 | 1675 | sprintf( |
| 1676 | 1676 | esc_html__( |
@@ -16,1592 +16,1592 @@ |
||
| 16 | 16 | class EE_Line_Item extends EE_Base_Class implements EEI_Line_Item |
| 17 | 17 | { |
| 18 | 18 | |
| 19 | - /** |
|
| 20 | - * for children line items (currently not a normal relation) |
|
| 21 | - * |
|
| 22 | - * @type EE_Line_Item[] |
|
| 23 | - */ |
|
| 24 | - protected $_children = array(); |
|
| 25 | - |
|
| 26 | - /** |
|
| 27 | - * for the parent line item |
|
| 28 | - * |
|
| 29 | - * @var EE_Line_Item |
|
| 30 | - */ |
|
| 31 | - protected $_parent; |
|
| 32 | - |
|
| 33 | - /** |
|
| 34 | - * @var LineItemCalculator |
|
| 35 | - */ |
|
| 36 | - protected $calculator; |
|
| 37 | - |
|
| 38 | - |
|
| 39 | - /** |
|
| 40 | - * @param array $props_n_values incoming values |
|
| 41 | - * @param string $timezone incoming timezone (if not set the timezone set for the website will be |
|
| 42 | - * used.) |
|
| 43 | - * @param array $date_formats incoming date_formats in an array where the first value is the |
|
| 44 | - * date_format and the second value is the time format |
|
| 45 | - * @return EE_Line_Item |
|
| 46 | - * @throws EE_Error |
|
| 47 | - * @throws InvalidArgumentException |
|
| 48 | - * @throws InvalidDataTypeException |
|
| 49 | - * @throws InvalidInterfaceException |
|
| 50 | - * @throws ReflectionException |
|
| 51 | - */ |
|
| 52 | - public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
| 53 | - { |
|
| 54 | - $has_object = parent::_check_for_object( |
|
| 55 | - $props_n_values, |
|
| 56 | - __CLASS__, |
|
| 57 | - $timezone, |
|
| 58 | - $date_formats |
|
| 59 | - ); |
|
| 60 | - return $has_object |
|
| 61 | - ? $has_object |
|
| 62 | - : new self($props_n_values, false, $timezone); |
|
| 63 | - } |
|
| 64 | - |
|
| 65 | - |
|
| 66 | - /** |
|
| 67 | - * @param array $props_n_values incoming values from the database |
|
| 68 | - * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
| 69 | - * the website will be used. |
|
| 70 | - * @return EE_Line_Item |
|
| 71 | - * @throws EE_Error |
|
| 72 | - * @throws InvalidArgumentException |
|
| 73 | - * @throws InvalidDataTypeException |
|
| 74 | - * @throws InvalidInterfaceException |
|
| 75 | - * @throws ReflectionException |
|
| 76 | - */ |
|
| 77 | - public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
| 78 | - { |
|
| 79 | - return new self($props_n_values, true, $timezone); |
|
| 80 | - } |
|
| 81 | - |
|
| 82 | - |
|
| 83 | - /** |
|
| 84 | - * Adds some defaults if they're not specified |
|
| 85 | - * |
|
| 86 | - * @param array $fieldValues |
|
| 87 | - * @param bool $bydb |
|
| 88 | - * @param string $timezone |
|
| 89 | - * @throws EE_Error |
|
| 90 | - * @throws InvalidArgumentException |
|
| 91 | - * @throws InvalidDataTypeException |
|
| 92 | - * @throws InvalidInterfaceException |
|
| 93 | - * @throws ReflectionException |
|
| 94 | - */ |
|
| 95 | - protected function __construct($fieldValues = array(), $bydb = false, $timezone = '') |
|
| 96 | - { |
|
| 97 | - $this->calculator = LoaderFactory::getShared(LineItemCalculator::class); |
|
| 98 | - parent::__construct($fieldValues, $bydb, $timezone); |
|
| 99 | - if (! $this->get('LIN_code')) { |
|
| 100 | - $this->set_code($this->generate_code()); |
|
| 101 | - } |
|
| 102 | - } |
|
| 103 | - |
|
| 104 | - |
|
| 105 | - /** |
|
| 106 | - * Gets ID |
|
| 107 | - * |
|
| 108 | - * @return int |
|
| 109 | - * @throws EE_Error |
|
| 110 | - * @throws InvalidArgumentException |
|
| 111 | - * @throws InvalidDataTypeException |
|
| 112 | - * @throws InvalidInterfaceException |
|
| 113 | - * @throws ReflectionException |
|
| 114 | - */ |
|
| 115 | - public function ID() |
|
| 116 | - { |
|
| 117 | - return $this->get('LIN_ID'); |
|
| 118 | - } |
|
| 119 | - |
|
| 120 | - |
|
| 121 | - /** |
|
| 122 | - * Gets TXN_ID |
|
| 123 | - * |
|
| 124 | - * @return int |
|
| 125 | - * @throws EE_Error |
|
| 126 | - * @throws InvalidArgumentException |
|
| 127 | - * @throws InvalidDataTypeException |
|
| 128 | - * @throws InvalidInterfaceException |
|
| 129 | - * @throws ReflectionException |
|
| 130 | - */ |
|
| 131 | - public function TXN_ID() |
|
| 132 | - { |
|
| 133 | - return $this->get('TXN_ID'); |
|
| 134 | - } |
|
| 135 | - |
|
| 136 | - |
|
| 137 | - /** |
|
| 138 | - * Sets TXN_ID |
|
| 139 | - * |
|
| 140 | - * @param int $TXN_ID |
|
| 141 | - * @throws EE_Error |
|
| 142 | - * @throws InvalidArgumentException |
|
| 143 | - * @throws InvalidDataTypeException |
|
| 144 | - * @throws InvalidInterfaceException |
|
| 145 | - * @throws ReflectionException |
|
| 146 | - */ |
|
| 147 | - public function set_TXN_ID($TXN_ID) |
|
| 148 | - { |
|
| 149 | - $this->set('TXN_ID', $TXN_ID); |
|
| 150 | - } |
|
| 151 | - |
|
| 152 | - |
|
| 153 | - /** |
|
| 154 | - * Gets name |
|
| 155 | - * |
|
| 156 | - * @return string |
|
| 157 | - * @throws EE_Error |
|
| 158 | - * @throws InvalidArgumentException |
|
| 159 | - * @throws InvalidDataTypeException |
|
| 160 | - * @throws InvalidInterfaceException |
|
| 161 | - * @throws ReflectionException |
|
| 162 | - */ |
|
| 163 | - public function name() |
|
| 164 | - { |
|
| 165 | - $name = $this->get('LIN_name'); |
|
| 166 | - if (! $name) { |
|
| 167 | - $name = ucwords(str_replace('-', ' ', $this->type())); |
|
| 168 | - } |
|
| 169 | - return $name; |
|
| 170 | - } |
|
| 171 | - |
|
| 172 | - |
|
| 173 | - /** |
|
| 174 | - * Sets name |
|
| 175 | - * |
|
| 176 | - * @param string $name |
|
| 177 | - * @throws EE_Error |
|
| 178 | - * @throws InvalidArgumentException |
|
| 179 | - * @throws InvalidDataTypeException |
|
| 180 | - * @throws InvalidInterfaceException |
|
| 181 | - * @throws ReflectionException |
|
| 182 | - */ |
|
| 183 | - public function set_name($name) |
|
| 184 | - { |
|
| 185 | - $this->set('LIN_name', $name); |
|
| 186 | - } |
|
| 187 | - |
|
| 188 | - |
|
| 189 | - /** |
|
| 190 | - * Gets desc |
|
| 191 | - * |
|
| 192 | - * @return string |
|
| 193 | - * @throws EE_Error |
|
| 194 | - * @throws InvalidArgumentException |
|
| 195 | - * @throws InvalidDataTypeException |
|
| 196 | - * @throws InvalidInterfaceException |
|
| 197 | - * @throws ReflectionException |
|
| 198 | - */ |
|
| 199 | - public function desc() |
|
| 200 | - { |
|
| 201 | - return $this->get('LIN_desc'); |
|
| 202 | - } |
|
| 203 | - |
|
| 204 | - |
|
| 205 | - /** |
|
| 206 | - * Sets desc |
|
| 207 | - * |
|
| 208 | - * @param string $desc |
|
| 209 | - * @throws EE_Error |
|
| 210 | - * @throws InvalidArgumentException |
|
| 211 | - * @throws InvalidDataTypeException |
|
| 212 | - * @throws InvalidInterfaceException |
|
| 213 | - * @throws ReflectionException |
|
| 214 | - */ |
|
| 215 | - public function set_desc($desc) |
|
| 216 | - { |
|
| 217 | - $this->set('LIN_desc', $desc); |
|
| 218 | - } |
|
| 219 | - |
|
| 220 | - |
|
| 221 | - /** |
|
| 222 | - * Gets quantity |
|
| 223 | - * |
|
| 224 | - * @return int |
|
| 225 | - * @throws EE_Error |
|
| 226 | - * @throws InvalidArgumentException |
|
| 227 | - * @throws InvalidDataTypeException |
|
| 228 | - * @throws InvalidInterfaceException |
|
| 229 | - * @throws ReflectionException |
|
| 230 | - */ |
|
| 231 | - public function quantity(): int |
|
| 232 | - { |
|
| 233 | - return (int) $this->get('LIN_quantity'); |
|
| 234 | - } |
|
| 235 | - |
|
| 236 | - |
|
| 237 | - /** |
|
| 238 | - * Sets quantity |
|
| 239 | - * |
|
| 240 | - * @param int $quantity |
|
| 241 | - * @throws EE_Error |
|
| 242 | - * @throws InvalidArgumentException |
|
| 243 | - * @throws InvalidDataTypeException |
|
| 244 | - * @throws InvalidInterfaceException |
|
| 245 | - * @throws ReflectionException |
|
| 246 | - */ |
|
| 247 | - public function set_quantity($quantity) |
|
| 248 | - { |
|
| 249 | - $this->set('LIN_quantity', max($quantity, 0)); |
|
| 250 | - } |
|
| 251 | - |
|
| 252 | - |
|
| 253 | - /** |
|
| 254 | - * Gets item_id |
|
| 255 | - * |
|
| 256 | - * @return string |
|
| 257 | - * @throws EE_Error |
|
| 258 | - * @throws InvalidArgumentException |
|
| 259 | - * @throws InvalidDataTypeException |
|
| 260 | - * @throws InvalidInterfaceException |
|
| 261 | - * @throws ReflectionException |
|
| 262 | - */ |
|
| 263 | - public function OBJ_ID() |
|
| 264 | - { |
|
| 265 | - return $this->get('OBJ_ID'); |
|
| 266 | - } |
|
| 267 | - |
|
| 268 | - |
|
| 269 | - /** |
|
| 270 | - * Sets item_id |
|
| 271 | - * |
|
| 272 | - * @param string $item_id |
|
| 273 | - * @throws EE_Error |
|
| 274 | - * @throws InvalidArgumentException |
|
| 275 | - * @throws InvalidDataTypeException |
|
| 276 | - * @throws InvalidInterfaceException |
|
| 277 | - * @throws ReflectionException |
|
| 278 | - */ |
|
| 279 | - public function set_OBJ_ID($item_id) |
|
| 280 | - { |
|
| 281 | - $this->set('OBJ_ID', $item_id); |
|
| 282 | - } |
|
| 283 | - |
|
| 284 | - |
|
| 285 | - /** |
|
| 286 | - * Gets item_type |
|
| 287 | - * |
|
| 288 | - * @return string |
|
| 289 | - * @throws EE_Error |
|
| 290 | - * @throws InvalidArgumentException |
|
| 291 | - * @throws InvalidDataTypeException |
|
| 292 | - * @throws InvalidInterfaceException |
|
| 293 | - * @throws ReflectionException |
|
| 294 | - */ |
|
| 295 | - public function OBJ_type() |
|
| 296 | - { |
|
| 297 | - return $this->get('OBJ_type'); |
|
| 298 | - } |
|
| 299 | - |
|
| 300 | - |
|
| 301 | - /** |
|
| 302 | - * Gets item_type |
|
| 303 | - * |
|
| 304 | - * @return string |
|
| 305 | - * @throws EE_Error |
|
| 306 | - * @throws InvalidArgumentException |
|
| 307 | - * @throws InvalidDataTypeException |
|
| 308 | - * @throws InvalidInterfaceException |
|
| 309 | - * @throws ReflectionException |
|
| 310 | - */ |
|
| 311 | - public function OBJ_type_i18n() |
|
| 312 | - { |
|
| 313 | - $obj_type = $this->OBJ_type(); |
|
| 314 | - switch ($obj_type) { |
|
| 315 | - case EEM_Line_Item::OBJ_TYPE_EVENT: |
|
| 316 | - $obj_type = esc_html__('Event', 'event_espresso'); |
|
| 317 | - break; |
|
| 318 | - case EEM_Line_Item::OBJ_TYPE_PRICE: |
|
| 319 | - $obj_type = esc_html__('Price', 'event_espresso'); |
|
| 320 | - break; |
|
| 321 | - case EEM_Line_Item::OBJ_TYPE_PROMOTION: |
|
| 322 | - $obj_type = esc_html__('Promotion', 'event_espresso'); |
|
| 323 | - break; |
|
| 324 | - case EEM_Line_Item::OBJ_TYPE_TICKET: |
|
| 325 | - $obj_type = esc_html__('Ticket', 'event_espresso'); |
|
| 326 | - break; |
|
| 327 | - case EEM_Line_Item::OBJ_TYPE_TRANSACTION: |
|
| 328 | - $obj_type = esc_html__('Transaction', 'event_espresso'); |
|
| 329 | - break; |
|
| 330 | - } |
|
| 331 | - return apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this); |
|
| 332 | - } |
|
| 333 | - |
|
| 334 | - |
|
| 335 | - /** |
|
| 336 | - * Sets item_type |
|
| 337 | - * |
|
| 338 | - * @param string $OBJ_type |
|
| 339 | - * @throws EE_Error |
|
| 340 | - * @throws InvalidArgumentException |
|
| 341 | - * @throws InvalidDataTypeException |
|
| 342 | - * @throws InvalidInterfaceException |
|
| 343 | - * @throws ReflectionException |
|
| 344 | - */ |
|
| 345 | - public function set_OBJ_type($OBJ_type) |
|
| 346 | - { |
|
| 347 | - $this->set('OBJ_type', $OBJ_type); |
|
| 348 | - } |
|
| 349 | - |
|
| 350 | - |
|
| 351 | - /** |
|
| 352 | - * Gets unit_price |
|
| 353 | - * |
|
| 354 | - * @return float |
|
| 355 | - * @throws EE_Error |
|
| 356 | - * @throws InvalidArgumentException |
|
| 357 | - * @throws InvalidDataTypeException |
|
| 358 | - * @throws InvalidInterfaceException |
|
| 359 | - * @throws ReflectionException |
|
| 360 | - */ |
|
| 361 | - public function unit_price() |
|
| 362 | - { |
|
| 363 | - return $this->get('LIN_unit_price'); |
|
| 364 | - } |
|
| 365 | - |
|
| 366 | - |
|
| 367 | - /** |
|
| 368 | - * Sets unit_price |
|
| 369 | - * |
|
| 370 | - * @param float $unit_price |
|
| 371 | - * @throws EE_Error |
|
| 372 | - * @throws InvalidArgumentException |
|
| 373 | - * @throws InvalidDataTypeException |
|
| 374 | - * @throws InvalidInterfaceException |
|
| 375 | - * @throws ReflectionException |
|
| 376 | - */ |
|
| 377 | - public function set_unit_price($unit_price) |
|
| 378 | - { |
|
| 379 | - $this->set('LIN_unit_price', $unit_price); |
|
| 380 | - } |
|
| 381 | - |
|
| 382 | - |
|
| 383 | - /** |
|
| 384 | - * Checks if this item is a percentage modifier or not |
|
| 385 | - * |
|
| 386 | - * @return boolean |
|
| 387 | - * @throws EE_Error |
|
| 388 | - * @throws InvalidArgumentException |
|
| 389 | - * @throws InvalidDataTypeException |
|
| 390 | - * @throws InvalidInterfaceException |
|
| 391 | - * @throws ReflectionException |
|
| 392 | - */ |
|
| 393 | - public function is_percent() |
|
| 394 | - { |
|
| 395 | - if ($this->is_tax_sub_total()) { |
|
| 396 | - // tax subtotals HAVE a percent on them, that percentage only applies |
|
| 397 | - // to taxable items, so its' an exception. Treat it like a flat line item |
|
| 398 | - return false; |
|
| 399 | - } |
|
| 400 | - $unit_price = abs($this->get('LIN_unit_price')); |
|
| 401 | - $percent = abs($this->get('LIN_percent')); |
|
| 402 | - if ($unit_price < .001 && $percent) { |
|
| 403 | - return true; |
|
| 404 | - } |
|
| 405 | - if ($unit_price >= .001 && ! $percent) { |
|
| 406 | - return false; |
|
| 407 | - } |
|
| 408 | - if ($unit_price >= .001 && $percent) { |
|
| 409 | - throw new EE_Error( |
|
| 410 | - sprintf( |
|
| 411 | - esc_html__( |
|
| 412 | - 'A Line Item can not have a unit price of (%s) AND a percent (%s)!', |
|
| 413 | - 'event_espresso' |
|
| 414 | - ), |
|
| 415 | - $unit_price, |
|
| 416 | - $percent |
|
| 417 | - ) |
|
| 418 | - ); |
|
| 419 | - } |
|
| 420 | - // if they're both 0, assume its not a percent item |
|
| 421 | - return false; |
|
| 422 | - } |
|
| 423 | - |
|
| 424 | - |
|
| 425 | - /** |
|
| 426 | - * Gets percent (between 100-.001) |
|
| 427 | - * |
|
| 428 | - * @return float |
|
| 429 | - * @throws EE_Error |
|
| 430 | - * @throws InvalidArgumentException |
|
| 431 | - * @throws InvalidDataTypeException |
|
| 432 | - * @throws InvalidInterfaceException |
|
| 433 | - * @throws ReflectionException |
|
| 434 | - */ |
|
| 435 | - public function percent() |
|
| 436 | - { |
|
| 437 | - return $this->get('LIN_percent'); |
|
| 438 | - } |
|
| 439 | - |
|
| 440 | - |
|
| 441 | - /** |
|
| 442 | - * Sets percent (between 100-0.01) |
|
| 443 | - * |
|
| 444 | - * @param float $percent |
|
| 445 | - * @throws EE_Error |
|
| 446 | - * @throws InvalidArgumentException |
|
| 447 | - * @throws InvalidDataTypeException |
|
| 448 | - * @throws InvalidInterfaceException |
|
| 449 | - * @throws ReflectionException |
|
| 450 | - */ |
|
| 451 | - public function set_percent($percent) |
|
| 452 | - { |
|
| 453 | - $this->set('LIN_percent', $percent); |
|
| 454 | - } |
|
| 455 | - |
|
| 456 | - |
|
| 457 | - /** |
|
| 458 | - * Gets total |
|
| 459 | - * |
|
| 460 | - * @return float |
|
| 461 | - * @throws EE_Error |
|
| 462 | - * @throws InvalidArgumentException |
|
| 463 | - * @throws InvalidDataTypeException |
|
| 464 | - * @throws InvalidInterfaceException |
|
| 465 | - * @throws ReflectionException |
|
| 466 | - */ |
|
| 467 | - public function pretaxTotal(): float |
|
| 468 | - { |
|
| 469 | - return $this->get('LIN_pretax'); |
|
| 470 | - } |
|
| 471 | - |
|
| 472 | - |
|
| 473 | - /** |
|
| 474 | - * Sets total |
|
| 475 | - * |
|
| 476 | - * @param float $pretax_total |
|
| 477 | - * @throws EE_Error |
|
| 478 | - * @throws InvalidArgumentException |
|
| 479 | - * @throws InvalidDataTypeException |
|
| 480 | - * @throws InvalidInterfaceException |
|
| 481 | - * @throws ReflectionException |
|
| 482 | - */ |
|
| 483 | - public function setPretaxTotal(float $pretax_total) |
|
| 484 | - { |
|
| 485 | - $this->set('LIN_pretax', $pretax_total); |
|
| 486 | - } |
|
| 487 | - |
|
| 488 | - |
|
| 489 | - /** |
|
| 490 | - * Gets total |
|
| 491 | - * |
|
| 492 | - * @return float |
|
| 493 | - * @throws EE_Error |
|
| 494 | - * @throws InvalidArgumentException |
|
| 495 | - * @throws InvalidDataTypeException |
|
| 496 | - * @throws InvalidInterfaceException |
|
| 497 | - * @throws ReflectionException |
|
| 498 | - */ |
|
| 499 | - public function total() |
|
| 500 | - { |
|
| 501 | - return $this->get('LIN_total'); |
|
| 502 | - } |
|
| 503 | - |
|
| 504 | - |
|
| 505 | - /** |
|
| 506 | - * Sets total |
|
| 507 | - * |
|
| 508 | - * @param float $total |
|
| 509 | - * @throws EE_Error |
|
| 510 | - * @throws InvalidArgumentException |
|
| 511 | - * @throws InvalidDataTypeException |
|
| 512 | - * @throws InvalidInterfaceException |
|
| 513 | - * @throws ReflectionException |
|
| 514 | - */ |
|
| 515 | - public function set_total($total) |
|
| 516 | - { |
|
| 517 | - $this->set('LIN_total', $total); |
|
| 518 | - } |
|
| 519 | - |
|
| 520 | - |
|
| 521 | - /** |
|
| 522 | - * Gets order |
|
| 523 | - * |
|
| 524 | - * @return int |
|
| 525 | - * @throws EE_Error |
|
| 526 | - * @throws InvalidArgumentException |
|
| 527 | - * @throws InvalidDataTypeException |
|
| 528 | - * @throws InvalidInterfaceException |
|
| 529 | - * @throws ReflectionException |
|
| 530 | - */ |
|
| 531 | - public function order() |
|
| 532 | - { |
|
| 533 | - return $this->get('LIN_order'); |
|
| 534 | - } |
|
| 535 | - |
|
| 536 | - |
|
| 537 | - /** |
|
| 538 | - * Sets order |
|
| 539 | - * |
|
| 540 | - * @param int $order |
|
| 541 | - * @throws EE_Error |
|
| 542 | - * @throws InvalidArgumentException |
|
| 543 | - * @throws InvalidDataTypeException |
|
| 544 | - * @throws InvalidInterfaceException |
|
| 545 | - * @throws ReflectionException |
|
| 546 | - */ |
|
| 547 | - public function set_order($order) |
|
| 548 | - { |
|
| 549 | - $this->set('LIN_order', $order); |
|
| 550 | - } |
|
| 551 | - |
|
| 552 | - |
|
| 553 | - /** |
|
| 554 | - * Gets parent |
|
| 555 | - * |
|
| 556 | - * @return int |
|
| 557 | - * @throws EE_Error |
|
| 558 | - * @throws InvalidArgumentException |
|
| 559 | - * @throws InvalidDataTypeException |
|
| 560 | - * @throws InvalidInterfaceException |
|
| 561 | - * @throws ReflectionException |
|
| 562 | - */ |
|
| 563 | - public function parent_ID() |
|
| 564 | - { |
|
| 565 | - return $this->get('LIN_parent'); |
|
| 566 | - } |
|
| 567 | - |
|
| 568 | - |
|
| 569 | - /** |
|
| 570 | - * Sets parent |
|
| 571 | - * |
|
| 572 | - * @param int $parent |
|
| 573 | - * @throws EE_Error |
|
| 574 | - * @throws InvalidArgumentException |
|
| 575 | - * @throws InvalidDataTypeException |
|
| 576 | - * @throws InvalidInterfaceException |
|
| 577 | - * @throws ReflectionException |
|
| 578 | - */ |
|
| 579 | - public function set_parent_ID($parent) |
|
| 580 | - { |
|
| 581 | - $this->set('LIN_parent', $parent); |
|
| 582 | - } |
|
| 583 | - |
|
| 584 | - |
|
| 585 | - /** |
|
| 586 | - * Gets type |
|
| 587 | - * |
|
| 588 | - * @return string |
|
| 589 | - * @throws EE_Error |
|
| 590 | - * @throws InvalidArgumentException |
|
| 591 | - * @throws InvalidDataTypeException |
|
| 592 | - * @throws InvalidInterfaceException |
|
| 593 | - * @throws ReflectionException |
|
| 594 | - */ |
|
| 595 | - public function type() |
|
| 596 | - { |
|
| 597 | - return $this->get('LIN_type'); |
|
| 598 | - } |
|
| 599 | - |
|
| 600 | - |
|
| 601 | - /** |
|
| 602 | - * Sets type |
|
| 603 | - * |
|
| 604 | - * @param string $type |
|
| 605 | - * @throws EE_Error |
|
| 606 | - * @throws InvalidArgumentException |
|
| 607 | - * @throws InvalidDataTypeException |
|
| 608 | - * @throws InvalidInterfaceException |
|
| 609 | - * @throws ReflectionException |
|
| 610 | - */ |
|
| 611 | - public function set_type($type) |
|
| 612 | - { |
|
| 613 | - $this->set('LIN_type', $type); |
|
| 614 | - } |
|
| 615 | - |
|
| 616 | - |
|
| 617 | - /** |
|
| 618 | - * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\ |
|
| 619 | - * 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 |
|
| 620 | - * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()` |
|
| 621 | - * or indirectly by `EE_Line_item::add_child_line_item()`) |
|
| 622 | - * |
|
| 623 | - * @return EE_Base_Class|EE_Line_Item |
|
| 624 | - * @throws EE_Error |
|
| 625 | - * @throws InvalidArgumentException |
|
| 626 | - * @throws InvalidDataTypeException |
|
| 627 | - * @throws InvalidInterfaceException |
|
| 628 | - * @throws ReflectionException |
|
| 629 | - */ |
|
| 630 | - public function parent() |
|
| 631 | - { |
|
| 632 | - return $this->ID() |
|
| 633 | - ? $this->get_model()->get_one_by_ID($this->parent_ID()) |
|
| 634 | - : $this->_parent; |
|
| 635 | - } |
|
| 636 | - |
|
| 637 | - |
|
| 638 | - /** |
|
| 639 | - * Gets ALL the children of this line item (ie, all the parts that contribute towards this total). |
|
| 640 | - * |
|
| 641 | - * @return EE_Line_Item[] |
|
| 642 | - * @throws EE_Error |
|
| 643 | - * @throws InvalidArgumentException |
|
| 644 | - * @throws InvalidDataTypeException |
|
| 645 | - * @throws InvalidInterfaceException |
|
| 646 | - * @throws ReflectionException |
|
| 647 | - */ |
|
| 648 | - public function children(array $query_params = []): array |
|
| 649 | - { |
|
| 650 | - if ($this->ID()) { |
|
| 651 | - // ensure where params are an array |
|
| 652 | - $query_params[0] = $query_params[0] ?? []; |
|
| 653 | - // add defaults for line item parent and orderby |
|
| 654 | - $query_params[0] += ['LIN_parent' => $this->ID()]; |
|
| 655 | - $query_params += ['order_by' => ['LIN_order' => 'ASC']]; |
|
| 656 | - return $this->get_model()->get_all($query_params); |
|
| 657 | - } |
|
| 658 | - if (! is_array($this->_children)) { |
|
| 659 | - $this->_children = array(); |
|
| 660 | - } |
|
| 661 | - return $this->_children; |
|
| 662 | - } |
|
| 663 | - |
|
| 664 | - |
|
| 665 | - /** |
|
| 666 | - * Gets code |
|
| 667 | - * |
|
| 668 | - * @return string |
|
| 669 | - * @throws EE_Error |
|
| 670 | - * @throws InvalidArgumentException |
|
| 671 | - * @throws InvalidDataTypeException |
|
| 672 | - * @throws InvalidInterfaceException |
|
| 673 | - * @throws ReflectionException |
|
| 674 | - */ |
|
| 675 | - public function code() |
|
| 676 | - { |
|
| 677 | - return $this->get('LIN_code'); |
|
| 678 | - } |
|
| 679 | - |
|
| 680 | - |
|
| 681 | - /** |
|
| 682 | - * Sets code |
|
| 683 | - * |
|
| 684 | - * @param string $code |
|
| 685 | - * @throws EE_Error |
|
| 686 | - * @throws InvalidArgumentException |
|
| 687 | - * @throws InvalidDataTypeException |
|
| 688 | - * @throws InvalidInterfaceException |
|
| 689 | - * @throws ReflectionException |
|
| 690 | - */ |
|
| 691 | - public function set_code($code) |
|
| 692 | - { |
|
| 693 | - $this->set('LIN_code', $code); |
|
| 694 | - } |
|
| 695 | - |
|
| 696 | - |
|
| 697 | - /** |
|
| 698 | - * Gets is_taxable |
|
| 699 | - * |
|
| 700 | - * @return boolean |
|
| 701 | - * @throws EE_Error |
|
| 702 | - * @throws InvalidArgumentException |
|
| 703 | - * @throws InvalidDataTypeException |
|
| 704 | - * @throws InvalidInterfaceException |
|
| 705 | - * @throws ReflectionException |
|
| 706 | - */ |
|
| 707 | - public function is_taxable() |
|
| 708 | - { |
|
| 709 | - return $this->get('LIN_is_taxable'); |
|
| 710 | - } |
|
| 711 | - |
|
| 712 | - |
|
| 713 | - /** |
|
| 714 | - * Sets is_taxable |
|
| 715 | - * |
|
| 716 | - * @param boolean $is_taxable |
|
| 717 | - * @throws EE_Error |
|
| 718 | - * @throws InvalidArgumentException |
|
| 719 | - * @throws InvalidDataTypeException |
|
| 720 | - * @throws InvalidInterfaceException |
|
| 721 | - * @throws ReflectionException |
|
| 722 | - */ |
|
| 723 | - public function set_is_taxable($is_taxable) |
|
| 724 | - { |
|
| 725 | - $this->set('LIN_is_taxable', $is_taxable); |
|
| 726 | - } |
|
| 727 | - |
|
| 728 | - |
|
| 729 | - /** |
|
| 730 | - * Gets the object that this model-joins-to. |
|
| 731 | - * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on |
|
| 732 | - * EEM_Promotion_Object |
|
| 733 | - * Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object |
|
| 734 | - * |
|
| 735 | - * @return EE_Base_Class | NULL |
|
| 736 | - * @throws EE_Error |
|
| 737 | - * @throws InvalidArgumentException |
|
| 738 | - * @throws InvalidDataTypeException |
|
| 739 | - * @throws InvalidInterfaceException |
|
| 740 | - * @throws ReflectionException |
|
| 741 | - */ |
|
| 742 | - public function get_object() |
|
| 743 | - { |
|
| 744 | - $model_name_of_related_obj = $this->OBJ_type(); |
|
| 745 | - return $this->get_model()->has_relation($model_name_of_related_obj) |
|
| 746 | - ? $this->get_first_related($model_name_of_related_obj) |
|
| 747 | - : null; |
|
| 748 | - } |
|
| 749 | - |
|
| 750 | - |
|
| 751 | - /** |
|
| 752 | - * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket. |
|
| 753 | - * (IE, if this line item is for a price or something else, will return NULL) |
|
| 754 | - * |
|
| 755 | - * @param array $query_params |
|
| 756 | - * @return EE_Base_Class|EE_Ticket |
|
| 757 | - * @throws EE_Error |
|
| 758 | - * @throws InvalidArgumentException |
|
| 759 | - * @throws InvalidDataTypeException |
|
| 760 | - * @throws InvalidInterfaceException |
|
| 761 | - * @throws ReflectionException |
|
| 762 | - */ |
|
| 763 | - public function ticket($query_params = array()) |
|
| 764 | - { |
|
| 765 | - // we're going to assume that when this method is called |
|
| 766 | - // we always want to receive the attached ticket EVEN if that ticket is archived. |
|
| 767 | - // This can be overridden via the incoming $query_params argument |
|
| 768 | - $remove_defaults = array('default_where_conditions' => 'none'); |
|
| 769 | - $query_params = array_merge($remove_defaults, $query_params); |
|
| 770 | - return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TICKET, $query_params); |
|
| 771 | - } |
|
| 772 | - |
|
| 773 | - |
|
| 774 | - /** |
|
| 775 | - * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket |
|
| 776 | - * |
|
| 777 | - * @return EE_Datetime | NULL |
|
| 778 | - * @throws EE_Error |
|
| 779 | - * @throws InvalidArgumentException |
|
| 780 | - * @throws InvalidDataTypeException |
|
| 781 | - * @throws InvalidInterfaceException |
|
| 782 | - * @throws ReflectionException |
|
| 783 | - */ |
|
| 784 | - public function get_ticket_datetime() |
|
| 785 | - { |
|
| 786 | - if ($this->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
| 787 | - $ticket = $this->ticket(); |
|
| 788 | - if ($ticket instanceof EE_Ticket) { |
|
| 789 | - $datetime = $ticket->first_datetime(); |
|
| 790 | - if ($datetime instanceof EE_Datetime) { |
|
| 791 | - return $datetime; |
|
| 792 | - } |
|
| 793 | - } |
|
| 794 | - } |
|
| 795 | - return null; |
|
| 796 | - } |
|
| 797 | - |
|
| 798 | - |
|
| 799 | - /** |
|
| 800 | - * Gets the event's name that's related to the ticket, if this is for |
|
| 801 | - * a ticket |
|
| 802 | - * |
|
| 803 | - * @return string |
|
| 804 | - * @throws EE_Error |
|
| 805 | - * @throws InvalidArgumentException |
|
| 806 | - * @throws InvalidDataTypeException |
|
| 807 | - * @throws InvalidInterfaceException |
|
| 808 | - * @throws ReflectionException |
|
| 809 | - */ |
|
| 810 | - public function ticket_event_name() |
|
| 811 | - { |
|
| 812 | - $event_name = esc_html__('Unknown', 'event_espresso'); |
|
| 813 | - $event = $this->ticket_event(); |
|
| 814 | - if ($event instanceof EE_Event) { |
|
| 815 | - $event_name = $event->name(); |
|
| 816 | - } |
|
| 817 | - return $event_name; |
|
| 818 | - } |
|
| 819 | - |
|
| 820 | - |
|
| 821 | - /** |
|
| 822 | - * Gets the event that's related to the ticket, if this line item represents a ticket. |
|
| 823 | - * |
|
| 824 | - * @return EE_Event|null |
|
| 825 | - * @throws EE_Error |
|
| 826 | - * @throws InvalidArgumentException |
|
| 827 | - * @throws InvalidDataTypeException |
|
| 828 | - * @throws InvalidInterfaceException |
|
| 829 | - * @throws ReflectionException |
|
| 830 | - */ |
|
| 831 | - public function ticket_event() |
|
| 832 | - { |
|
| 833 | - $event = null; |
|
| 834 | - $ticket = $this->ticket(); |
|
| 835 | - if ($ticket instanceof EE_Ticket) { |
|
| 836 | - $datetime = $ticket->first_datetime(); |
|
| 837 | - if ($datetime instanceof EE_Datetime) { |
|
| 838 | - $event = $datetime->event(); |
|
| 839 | - } |
|
| 840 | - } |
|
| 841 | - return $event; |
|
| 842 | - } |
|
| 843 | - |
|
| 844 | - |
|
| 845 | - /** |
|
| 846 | - * Gets the first datetime for this lien item, assuming it's for a ticket |
|
| 847 | - * |
|
| 848 | - * @param string $date_format |
|
| 849 | - * @param string $time_format |
|
| 850 | - * @return string |
|
| 851 | - * @throws EE_Error |
|
| 852 | - * @throws InvalidArgumentException |
|
| 853 | - * @throws InvalidDataTypeException |
|
| 854 | - * @throws InvalidInterfaceException |
|
| 855 | - * @throws ReflectionException |
|
| 856 | - */ |
|
| 857 | - public function ticket_datetime_start($date_format = '', $time_format = '') |
|
| 858 | - { |
|
| 859 | - $first_datetime_string = esc_html__('Unknown', 'event_espresso'); |
|
| 860 | - $datetime = $this->get_ticket_datetime(); |
|
| 861 | - if ($datetime) { |
|
| 862 | - $first_datetime_string = $datetime->start_date_and_time($date_format, $time_format); |
|
| 863 | - } |
|
| 864 | - return $first_datetime_string; |
|
| 865 | - } |
|
| 866 | - |
|
| 867 | - |
|
| 868 | - /** |
|
| 869 | - * Adds the line item as a child to this line item. If there is another child line |
|
| 870 | - * item with the same LIN_code, it is overwritten by this new one |
|
| 871 | - * |
|
| 872 | - * @param EE_Line_Item $line_item |
|
| 873 | - * @param bool $set_order |
|
| 874 | - * @return bool success |
|
| 875 | - * @throws EE_Error |
|
| 876 | - * @throws InvalidArgumentException |
|
| 877 | - * @throws InvalidDataTypeException |
|
| 878 | - * @throws InvalidInterfaceException |
|
| 879 | - * @throws ReflectionException |
|
| 880 | - */ |
|
| 881 | - public function add_child_line_item(EE_Line_Item $line_item, $set_order = true) |
|
| 882 | - { |
|
| 883 | - // should we calculate the LIN_order for this line item ? |
|
| 884 | - if ($set_order || $line_item->order() === null) { |
|
| 885 | - $line_item->set_order(count($this->children())); |
|
| 886 | - } |
|
| 887 | - if ($this->ID()) { |
|
| 888 | - // check for any duplicate line items (with the same code), if so, this replaces it |
|
| 889 | - $line_item_with_same_code = $this->get_child_line_item($line_item->code()); |
|
| 890 | - if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) { |
|
| 891 | - $this->delete_child_line_item($line_item_with_same_code->code()); |
|
| 892 | - } |
|
| 893 | - $line_item->set_parent_ID($this->ID()); |
|
| 894 | - if ($this->TXN_ID()) { |
|
| 895 | - $line_item->set_TXN_ID($this->TXN_ID()); |
|
| 896 | - } |
|
| 897 | - return $line_item->save(); |
|
| 898 | - } |
|
| 899 | - $this->_children[ $line_item->code() ] = $line_item; |
|
| 900 | - if ($line_item->parent() !== $this) { |
|
| 901 | - $line_item->set_parent($this); |
|
| 902 | - } |
|
| 903 | - return true; |
|
| 904 | - } |
|
| 905 | - |
|
| 906 | - |
|
| 907 | - /** |
|
| 908 | - * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation. |
|
| 909 | - * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save() |
|
| 910 | - * However, if this line item is NOT saved to the DB, this just caches the parent on |
|
| 911 | - * the EE_Line_Item::_parent property. |
|
| 912 | - * |
|
| 913 | - * @param EE_Line_Item $line_item |
|
| 914 | - * @throws EE_Error |
|
| 915 | - * @throws InvalidArgumentException |
|
| 916 | - * @throws InvalidDataTypeException |
|
| 917 | - * @throws InvalidInterfaceException |
|
| 918 | - * @throws ReflectionException |
|
| 919 | - */ |
|
| 920 | - public function set_parent($line_item) |
|
| 921 | - { |
|
| 922 | - if ($this->ID()) { |
|
| 923 | - if (! $line_item->ID()) { |
|
| 924 | - $line_item->save(); |
|
| 925 | - } |
|
| 926 | - $this->set_parent_ID($line_item->ID()); |
|
| 927 | - $this->save(); |
|
| 928 | - } else { |
|
| 929 | - $this->_parent = $line_item; |
|
| 930 | - $this->set_parent_ID($line_item->ID()); |
|
| 931 | - } |
|
| 932 | - } |
|
| 933 | - |
|
| 934 | - |
|
| 935 | - /** |
|
| 936 | - * Gets the child line item as specified by its code. Because this returns an object (by reference) |
|
| 937 | - * you can modify this child line item and the parent (this object) can know about them |
|
| 938 | - * because it also has a reference to that line item |
|
| 939 | - * |
|
| 940 | - * @param string $code |
|
| 941 | - * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
| 942 | - * @throws EE_Error |
|
| 943 | - * @throws InvalidArgumentException |
|
| 944 | - * @throws InvalidDataTypeException |
|
| 945 | - * @throws InvalidInterfaceException |
|
| 946 | - * @throws ReflectionException |
|
| 947 | - */ |
|
| 948 | - public function get_child_line_item($code) |
|
| 949 | - { |
|
| 950 | - if ($this->ID()) { |
|
| 951 | - return $this->get_model()->get_one( |
|
| 952 | - array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code)) |
|
| 953 | - ); |
|
| 954 | - } |
|
| 955 | - return isset($this->_children[ $code ]) |
|
| 956 | - ? $this->_children[ $code ] |
|
| 957 | - : null; |
|
| 958 | - } |
|
| 959 | - |
|
| 960 | - |
|
| 961 | - /** |
|
| 962 | - * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD |
|
| 963 | - * cached on it) |
|
| 964 | - * |
|
| 965 | - * @return int |
|
| 966 | - * @throws EE_Error |
|
| 967 | - * @throws InvalidArgumentException |
|
| 968 | - * @throws InvalidDataTypeException |
|
| 969 | - * @throws InvalidInterfaceException |
|
| 970 | - * @throws ReflectionException |
|
| 971 | - */ |
|
| 972 | - public function delete_children_line_items() |
|
| 973 | - { |
|
| 974 | - if ($this->ID()) { |
|
| 975 | - return $this->get_model()->delete(array(array('LIN_parent' => $this->ID()))); |
|
| 976 | - } |
|
| 977 | - $count = count($this->_children); |
|
| 978 | - $this->_children = array(); |
|
| 979 | - return $count; |
|
| 980 | - } |
|
| 981 | - |
|
| 982 | - |
|
| 983 | - /** |
|
| 984 | - * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line |
|
| 985 | - * HAS NOT been saved to the DB, removes the child line item with index $code. |
|
| 986 | - * Also searches through the child's children for a matching line item. However, once a line item has been found |
|
| 987 | - * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be |
|
| 988 | - * deleted) |
|
| 989 | - * |
|
| 990 | - * @param string $code |
|
| 991 | - * @param bool $stop_search_once_found |
|
| 992 | - * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to |
|
| 993 | - * the DB yet) |
|
| 994 | - * @throws EE_Error |
|
| 995 | - * @throws InvalidArgumentException |
|
| 996 | - * @throws InvalidDataTypeException |
|
| 997 | - * @throws InvalidInterfaceException |
|
| 998 | - * @throws ReflectionException |
|
| 999 | - */ |
|
| 1000 | - public function delete_child_line_item($code, $stop_search_once_found = true) |
|
| 1001 | - { |
|
| 1002 | - if ($this->ID()) { |
|
| 1003 | - $items_deleted = 0; |
|
| 1004 | - if ($this->code() === $code) { |
|
| 1005 | - $items_deleted += EEH_Line_Item::delete_all_child_items($this); |
|
| 1006 | - $items_deleted += (int) $this->delete(); |
|
| 1007 | - if ($stop_search_once_found) { |
|
| 1008 | - return $items_deleted; |
|
| 1009 | - } |
|
| 1010 | - } |
|
| 1011 | - foreach ($this->children() as $child_line_item) { |
|
| 1012 | - $items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found); |
|
| 1013 | - } |
|
| 1014 | - return $items_deleted; |
|
| 1015 | - } |
|
| 1016 | - if (isset($this->_children[ $code ])) { |
|
| 1017 | - unset($this->_children[ $code ]); |
|
| 1018 | - return 1; |
|
| 1019 | - } |
|
| 1020 | - return 0; |
|
| 1021 | - } |
|
| 1022 | - |
|
| 1023 | - |
|
| 1024 | - /** |
|
| 1025 | - * If this line item is in the database, is of the type subtotal, and |
|
| 1026 | - * has no children, why do we have it? It should be deleted so this function |
|
| 1027 | - * does that |
|
| 1028 | - * |
|
| 1029 | - * @return boolean |
|
| 1030 | - * @throws EE_Error |
|
| 1031 | - * @throws InvalidArgumentException |
|
| 1032 | - * @throws InvalidDataTypeException |
|
| 1033 | - * @throws InvalidInterfaceException |
|
| 1034 | - * @throws ReflectionException |
|
| 1035 | - */ |
|
| 1036 | - public function delete_if_childless_subtotal() |
|
| 1037 | - { |
|
| 1038 | - if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && ! $this->children()) { |
|
| 1039 | - return $this->delete(); |
|
| 1040 | - } |
|
| 1041 | - return false; |
|
| 1042 | - } |
|
| 1043 | - |
|
| 1044 | - |
|
| 1045 | - /** |
|
| 1046 | - * Creates a code and returns a string. doesn't assign the code to this model object |
|
| 1047 | - * |
|
| 1048 | - * @return string |
|
| 1049 | - * @throws EE_Error |
|
| 1050 | - * @throws InvalidArgumentException |
|
| 1051 | - * @throws InvalidDataTypeException |
|
| 1052 | - * @throws InvalidInterfaceException |
|
| 1053 | - * @throws ReflectionException |
|
| 1054 | - */ |
|
| 1055 | - public function generate_code() |
|
| 1056 | - { |
|
| 1057 | - // each line item in the cart requires a unique identifier |
|
| 1058 | - return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime()); |
|
| 1059 | - } |
|
| 1060 | - |
|
| 1061 | - |
|
| 1062 | - /** |
|
| 1063 | - * @return bool |
|
| 1064 | - * @throws EE_Error |
|
| 1065 | - * @throws InvalidArgumentException |
|
| 1066 | - * @throws InvalidDataTypeException |
|
| 1067 | - * @throws InvalidInterfaceException |
|
| 1068 | - * @throws ReflectionException |
|
| 1069 | - */ |
|
| 1070 | - public function isGlobalTax(): bool |
|
| 1071 | - { |
|
| 1072 | - return $this->type() === EEM_Line_Item::type_tax; |
|
| 1073 | - } |
|
| 1074 | - |
|
| 1075 | - |
|
| 1076 | - /** |
|
| 1077 | - * @return bool |
|
| 1078 | - * @throws EE_Error |
|
| 1079 | - * @throws InvalidArgumentException |
|
| 1080 | - * @throws InvalidDataTypeException |
|
| 1081 | - * @throws InvalidInterfaceException |
|
| 1082 | - * @throws ReflectionException |
|
| 1083 | - */ |
|
| 1084 | - public function isSubTax(): bool |
|
| 1085 | - { |
|
| 1086 | - return $this->type() === EEM_Line_Item::type_sub_tax; |
|
| 1087 | - } |
|
| 1088 | - |
|
| 1089 | - |
|
| 1090 | - /** |
|
| 1091 | - * returns true if this is a line item with a direct descendent of the type sub-tax |
|
| 1092 | - * |
|
| 1093 | - * @return array |
|
| 1094 | - * @throws EE_Error |
|
| 1095 | - * @throws InvalidArgumentException |
|
| 1096 | - * @throws InvalidDataTypeException |
|
| 1097 | - * @throws InvalidInterfaceException |
|
| 1098 | - * @throws ReflectionException |
|
| 1099 | - */ |
|
| 1100 | - public function getSubTaxes(): array |
|
| 1101 | - { |
|
| 1102 | - if (! $this->is_line_item()) { |
|
| 1103 | - return []; |
|
| 1104 | - } |
|
| 1105 | - return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_sub_tax); |
|
| 1106 | - } |
|
| 1107 | - |
|
| 1108 | - |
|
| 1109 | - /** |
|
| 1110 | - * returns true if this is a line item with a direct descendent of the type sub-tax |
|
| 1111 | - * |
|
| 1112 | - * @return bool |
|
| 1113 | - * @throws EE_Error |
|
| 1114 | - * @throws InvalidArgumentException |
|
| 1115 | - * @throws InvalidDataTypeException |
|
| 1116 | - * @throws InvalidInterfaceException |
|
| 1117 | - * @throws ReflectionException |
|
| 1118 | - */ |
|
| 1119 | - public function hasSubTaxes(): bool |
|
| 1120 | - { |
|
| 1121 | - if (! $this->is_line_item()) { |
|
| 1122 | - return false; |
|
| 1123 | - } |
|
| 1124 | - $sub_taxes = $this->getSubTaxes(); |
|
| 1125 | - return ! empty($sub_taxes); |
|
| 1126 | - } |
|
| 1127 | - |
|
| 1128 | - |
|
| 1129 | - /** |
|
| 1130 | - * @return bool |
|
| 1131 | - * @throws EE_Error |
|
| 1132 | - * @throws ReflectionException |
|
| 1133 | - * @deprecated $VID:$ |
|
| 1134 | - */ |
|
| 1135 | - public function is_tax(): bool |
|
| 1136 | - { |
|
| 1137 | - return $this->isGlobalTax(); |
|
| 1138 | - } |
|
| 1139 | - |
|
| 1140 | - |
|
| 1141 | - /** |
|
| 1142 | - * @return bool |
|
| 1143 | - * @throws EE_Error |
|
| 1144 | - * @throws InvalidArgumentException |
|
| 1145 | - * @throws InvalidDataTypeException |
|
| 1146 | - * @throws InvalidInterfaceException |
|
| 1147 | - * @throws ReflectionException |
|
| 1148 | - */ |
|
| 1149 | - public function is_tax_sub_total() |
|
| 1150 | - { |
|
| 1151 | - return $this->type() === EEM_Line_Item::type_tax_sub_total; |
|
| 1152 | - } |
|
| 1153 | - |
|
| 1154 | - |
|
| 1155 | - /** |
|
| 1156 | - * @return bool |
|
| 1157 | - * @throws EE_Error |
|
| 1158 | - * @throws InvalidArgumentException |
|
| 1159 | - * @throws InvalidDataTypeException |
|
| 1160 | - * @throws InvalidInterfaceException |
|
| 1161 | - * @throws ReflectionException |
|
| 1162 | - */ |
|
| 1163 | - public function is_line_item() |
|
| 1164 | - { |
|
| 1165 | - return $this->type() === EEM_Line_Item::type_line_item; |
|
| 1166 | - } |
|
| 1167 | - |
|
| 1168 | - |
|
| 1169 | - /** |
|
| 1170 | - * @return bool |
|
| 1171 | - * @throws EE_Error |
|
| 1172 | - * @throws InvalidArgumentException |
|
| 1173 | - * @throws InvalidDataTypeException |
|
| 1174 | - * @throws InvalidInterfaceException |
|
| 1175 | - * @throws ReflectionException |
|
| 1176 | - */ |
|
| 1177 | - public function is_sub_line_item() |
|
| 1178 | - { |
|
| 1179 | - return $this->type() === EEM_Line_Item::type_sub_line_item; |
|
| 1180 | - } |
|
| 1181 | - |
|
| 1182 | - |
|
| 1183 | - /** |
|
| 1184 | - * @return bool |
|
| 1185 | - * @throws EE_Error |
|
| 1186 | - * @throws InvalidArgumentException |
|
| 1187 | - * @throws InvalidDataTypeException |
|
| 1188 | - * @throws InvalidInterfaceException |
|
| 1189 | - * @throws ReflectionException |
|
| 1190 | - */ |
|
| 1191 | - public function is_sub_total() |
|
| 1192 | - { |
|
| 1193 | - return $this->type() === EEM_Line_Item::type_sub_total; |
|
| 1194 | - } |
|
| 1195 | - |
|
| 1196 | - |
|
| 1197 | - /** |
|
| 1198 | - * Whether or not this line item is a cancellation line item |
|
| 1199 | - * |
|
| 1200 | - * @return boolean |
|
| 1201 | - * @throws EE_Error |
|
| 1202 | - * @throws InvalidArgumentException |
|
| 1203 | - * @throws InvalidDataTypeException |
|
| 1204 | - * @throws InvalidInterfaceException |
|
| 1205 | - * @throws ReflectionException |
|
| 1206 | - */ |
|
| 1207 | - public function is_cancellation() |
|
| 1208 | - { |
|
| 1209 | - return EEM_Line_Item::type_cancellation === $this->type(); |
|
| 1210 | - } |
|
| 1211 | - |
|
| 1212 | - |
|
| 1213 | - /** |
|
| 1214 | - * @return bool |
|
| 1215 | - * @throws EE_Error |
|
| 1216 | - * @throws InvalidArgumentException |
|
| 1217 | - * @throws InvalidDataTypeException |
|
| 1218 | - * @throws InvalidInterfaceException |
|
| 1219 | - * @throws ReflectionException |
|
| 1220 | - */ |
|
| 1221 | - public function is_total() |
|
| 1222 | - { |
|
| 1223 | - return $this->type() === EEM_Line_Item::type_total; |
|
| 1224 | - } |
|
| 1225 | - |
|
| 1226 | - |
|
| 1227 | - /** |
|
| 1228 | - * @return bool |
|
| 1229 | - * @throws EE_Error |
|
| 1230 | - * @throws InvalidArgumentException |
|
| 1231 | - * @throws InvalidDataTypeException |
|
| 1232 | - * @throws InvalidInterfaceException |
|
| 1233 | - * @throws ReflectionException |
|
| 1234 | - */ |
|
| 1235 | - public function is_cancelled() |
|
| 1236 | - { |
|
| 1237 | - return $this->type() === EEM_Line_Item::type_cancellation; |
|
| 1238 | - } |
|
| 1239 | - |
|
| 1240 | - |
|
| 1241 | - /** |
|
| 1242 | - * @return string like '2, 004.00', formatted according to the localized currency |
|
| 1243 | - * @throws EE_Error |
|
| 1244 | - * @throws InvalidArgumentException |
|
| 1245 | - * @throws InvalidDataTypeException |
|
| 1246 | - * @throws InvalidInterfaceException |
|
| 1247 | - * @throws ReflectionException |
|
| 1248 | - */ |
|
| 1249 | - public function unit_price_no_code() |
|
| 1250 | - { |
|
| 1251 | - return $this->get_pretty('LIN_unit_price', 'no_currency_code'); |
|
| 1252 | - } |
|
| 1253 | - |
|
| 1254 | - |
|
| 1255 | - /** |
|
| 1256 | - * @return string like '2, 004.00', formatted according to the localized currency |
|
| 1257 | - * @throws EE_Error |
|
| 1258 | - * @throws InvalidArgumentException |
|
| 1259 | - * @throws InvalidDataTypeException |
|
| 1260 | - * @throws InvalidInterfaceException |
|
| 1261 | - * @throws ReflectionException |
|
| 1262 | - */ |
|
| 1263 | - public function total_no_code() |
|
| 1264 | - { |
|
| 1265 | - return $this->get_pretty('LIN_total', 'no_currency_code'); |
|
| 1266 | - } |
|
| 1267 | - |
|
| 1268 | - |
|
| 1269 | - /** |
|
| 1270 | - * Gets the final total on this item, taking taxes into account. |
|
| 1271 | - * Has the side-effect of setting the sub-total as it was just calculated. |
|
| 1272 | - * If this is used on a grand-total line item, also updates the transaction's |
|
| 1273 | - * TXN_total (provided this line item is allowed to persist, otherwise we don't |
|
| 1274 | - * want to change a persistable transaction with info from a non-persistent line item) |
|
| 1275 | - * |
|
| 1276 | - * @param bool $update_txn_status |
|
| 1277 | - * @return float |
|
| 1278 | - * @throws EE_Error |
|
| 1279 | - * @throws InvalidArgumentException |
|
| 1280 | - * @throws InvalidDataTypeException |
|
| 1281 | - * @throws InvalidInterfaceException |
|
| 1282 | - * @throws ReflectionException |
|
| 1283 | - * @throws RuntimeException |
|
| 1284 | - */ |
|
| 1285 | - public function recalculate_total_including_taxes(bool $update_txn_status = false): float |
|
| 1286 | - { |
|
| 1287 | - $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this); |
|
| 1288 | - return $this->calculator->recalculateTotalIncludingTaxes($grand_total_line_item, $update_txn_status); |
|
| 1289 | - } |
|
| 1290 | - |
|
| 1291 | - |
|
| 1292 | - /** |
|
| 1293 | - * Recursively goes through all the children and recalculates sub-totals EXCEPT for |
|
| 1294 | - * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its |
|
| 1295 | - * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and |
|
| 1296 | - * when this is called on the grand total |
|
| 1297 | - * |
|
| 1298 | - * @return float |
|
| 1299 | - * @throws EE_Error |
|
| 1300 | - * @throws InvalidArgumentException |
|
| 1301 | - * @throws InvalidDataTypeException |
|
| 1302 | - * @throws InvalidInterfaceException |
|
| 1303 | - * @throws ReflectionException |
|
| 1304 | - */ |
|
| 1305 | - public function recalculate_pre_tax_total(): float |
|
| 1306 | - { |
|
| 1307 | - $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this); |
|
| 1308 | - [$total] = $this->calculator->recalculateLineItemTotals($grand_total_line_item); |
|
| 1309 | - return $total; |
|
| 1310 | - } |
|
| 1311 | - |
|
| 1312 | - |
|
| 1313 | - /** |
|
| 1314 | - * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets |
|
| 1315 | - * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items |
|
| 1316 | - * and tax sub-total if already in the DB |
|
| 1317 | - * |
|
| 1318 | - * @return float |
|
| 1319 | - * @throws EE_Error |
|
| 1320 | - * @throws InvalidArgumentException |
|
| 1321 | - * @throws InvalidDataTypeException |
|
| 1322 | - * @throws InvalidInterfaceException |
|
| 1323 | - * @throws ReflectionException |
|
| 1324 | - */ |
|
| 1325 | - public function recalculate_taxes_and_tax_total(): float |
|
| 1326 | - { |
|
| 1327 | - $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this); |
|
| 1328 | - return $this->calculator->recalculateTaxesAndTaxTotal($grand_total_line_item); |
|
| 1329 | - } |
|
| 1330 | - |
|
| 1331 | - |
|
| 1332 | - /** |
|
| 1333 | - * Gets the total tax on this line item. Assumes taxes have already been calculated using |
|
| 1334 | - * recalculate_taxes_and_total |
|
| 1335 | - * |
|
| 1336 | - * @return float |
|
| 1337 | - * @throws EE_Error |
|
| 1338 | - * @throws InvalidArgumentException |
|
| 1339 | - * @throws InvalidDataTypeException |
|
| 1340 | - * @throws InvalidInterfaceException |
|
| 1341 | - * @throws ReflectionException |
|
| 1342 | - */ |
|
| 1343 | - public function get_total_tax() |
|
| 1344 | - { |
|
| 1345 | - $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this); |
|
| 1346 | - return $this->calculator->recalculateTaxesAndTaxTotal($grand_total_line_item); |
|
| 1347 | - } |
|
| 1348 | - |
|
| 1349 | - |
|
| 1350 | - /** |
|
| 1351 | - * Gets the total for all the items purchased only |
|
| 1352 | - * |
|
| 1353 | - * @return float |
|
| 1354 | - * @throws EE_Error |
|
| 1355 | - * @throws InvalidArgumentException |
|
| 1356 | - * @throws InvalidDataTypeException |
|
| 1357 | - * @throws InvalidInterfaceException |
|
| 1358 | - * @throws ReflectionException |
|
| 1359 | - */ |
|
| 1360 | - public function get_items_total() |
|
| 1361 | - { |
|
| 1362 | - // by default, let's make sure we're consistent with the existing line item |
|
| 1363 | - if ($this->is_total()) { |
|
| 1364 | - return $this->pretaxTotal(); |
|
| 1365 | - } |
|
| 1366 | - $total = 0; |
|
| 1367 | - foreach ($this->get_items() as $item) { |
|
| 1368 | - if ($item instanceof EE_Line_Item) { |
|
| 1369 | - $total += $item->pretaxTotal(); |
|
| 1370 | - } |
|
| 1371 | - } |
|
| 1372 | - return $total; |
|
| 1373 | - } |
|
| 1374 | - |
|
| 1375 | - |
|
| 1376 | - /** |
|
| 1377 | - * Gets all the descendants (ie, children or children of children etc) that |
|
| 1378 | - * are of the type 'tax' |
|
| 1379 | - * |
|
| 1380 | - * @return EE_Line_Item[] |
|
| 1381 | - * @throws EE_Error |
|
| 1382 | - */ |
|
| 1383 | - public function tax_descendants() |
|
| 1384 | - { |
|
| 1385 | - return EEH_Line_Item::get_tax_descendants($this); |
|
| 1386 | - } |
|
| 1387 | - |
|
| 1388 | - |
|
| 1389 | - /** |
|
| 1390 | - * Gets all the real items purchased which are children of this item |
|
| 1391 | - * |
|
| 1392 | - * @return EE_Line_Item[] |
|
| 1393 | - * @throws EE_Error |
|
| 1394 | - */ |
|
| 1395 | - public function get_items() |
|
| 1396 | - { |
|
| 1397 | - return EEH_Line_Item::get_line_item_descendants($this); |
|
| 1398 | - } |
|
| 1399 | - |
|
| 1400 | - |
|
| 1401 | - /** |
|
| 1402 | - * Returns the amount taxable among this line item's children (or if it has no children, |
|
| 1403 | - * how much of it is taxable). Does not recalculate totals or subtotals. |
|
| 1404 | - * If the taxable total is negative, (eg, if none of the tickets were taxable, |
|
| 1405 | - * but there is a "Taxable" discount), returns 0. |
|
| 1406 | - * |
|
| 1407 | - * @return float |
|
| 1408 | - * @throws EE_Error |
|
| 1409 | - * @throws InvalidArgumentException |
|
| 1410 | - * @throws InvalidDataTypeException |
|
| 1411 | - * @throws InvalidInterfaceException |
|
| 1412 | - * @throws ReflectionException |
|
| 1413 | - */ |
|
| 1414 | - public function taxable_total(): float |
|
| 1415 | - { |
|
| 1416 | - return $this->calculator->taxableAmountForGlobalTaxes($this); |
|
| 1417 | - } |
|
| 1418 | - |
|
| 1419 | - |
|
| 1420 | - /** |
|
| 1421 | - * Gets the transaction for this line item |
|
| 1422 | - * |
|
| 1423 | - * @return EE_Base_Class|EE_Transaction |
|
| 1424 | - * @throws EE_Error |
|
| 1425 | - * @throws InvalidArgumentException |
|
| 1426 | - * @throws InvalidDataTypeException |
|
| 1427 | - * @throws InvalidInterfaceException |
|
| 1428 | - * @throws ReflectionException |
|
| 1429 | - */ |
|
| 1430 | - public function transaction() |
|
| 1431 | - { |
|
| 1432 | - return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TRANSACTION); |
|
| 1433 | - } |
|
| 1434 | - |
|
| 1435 | - |
|
| 1436 | - /** |
|
| 1437 | - * Saves this line item to the DB, and recursively saves its descendants. |
|
| 1438 | - * Because there currently is no proper parent-child relation on the model, |
|
| 1439 | - * save_this_and_cached() will NOT save the descendants. |
|
| 1440 | - * Also sets the transaction on this line item and all its descendants before saving |
|
| 1441 | - * |
|
| 1442 | - * @param int $txn_id if none is provided, assumes $this->TXN_ID() |
|
| 1443 | - * @return int count of items saved |
|
| 1444 | - * @throws EE_Error |
|
| 1445 | - * @throws InvalidArgumentException |
|
| 1446 | - * @throws InvalidDataTypeException |
|
| 1447 | - * @throws InvalidInterfaceException |
|
| 1448 | - * @throws ReflectionException |
|
| 1449 | - */ |
|
| 1450 | - public function save_this_and_descendants_to_txn($txn_id = null) |
|
| 1451 | - { |
|
| 1452 | - $count = 0; |
|
| 1453 | - if (! $txn_id) { |
|
| 1454 | - $txn_id = $this->TXN_ID(); |
|
| 1455 | - } |
|
| 1456 | - $this->set_TXN_ID($txn_id); |
|
| 1457 | - $children = $this->children(); |
|
| 1458 | - $count += $this->save() |
|
| 1459 | - ? 1 |
|
| 1460 | - : 0; |
|
| 1461 | - foreach ($children as $child_line_item) { |
|
| 1462 | - if ($child_line_item instanceof EE_Line_Item) { |
|
| 1463 | - $child_line_item->set_parent_ID($this->ID()); |
|
| 1464 | - $count += $child_line_item->save_this_and_descendants_to_txn($txn_id); |
|
| 1465 | - } |
|
| 1466 | - } |
|
| 1467 | - return $count; |
|
| 1468 | - } |
|
| 1469 | - |
|
| 1470 | - |
|
| 1471 | - /** |
|
| 1472 | - * Saves this line item to the DB, and recursively saves its descendants. |
|
| 1473 | - * |
|
| 1474 | - * @return int count of items saved |
|
| 1475 | - * @throws EE_Error |
|
| 1476 | - * @throws InvalidArgumentException |
|
| 1477 | - * @throws InvalidDataTypeException |
|
| 1478 | - * @throws InvalidInterfaceException |
|
| 1479 | - * @throws ReflectionException |
|
| 1480 | - */ |
|
| 1481 | - public function save_this_and_descendants() |
|
| 1482 | - { |
|
| 1483 | - $count = 0; |
|
| 1484 | - $children = $this->children(); |
|
| 1485 | - $count += $this->save() |
|
| 1486 | - ? 1 |
|
| 1487 | - : 0; |
|
| 1488 | - foreach ($children as $child_line_item) { |
|
| 1489 | - if ($child_line_item instanceof EE_Line_Item) { |
|
| 1490 | - $child_line_item->set_parent_ID($this->ID()); |
|
| 1491 | - $count += $child_line_item->save_this_and_descendants(); |
|
| 1492 | - } |
|
| 1493 | - } |
|
| 1494 | - return $count; |
|
| 1495 | - } |
|
| 1496 | - |
|
| 1497 | - |
|
| 1498 | - /** |
|
| 1499 | - * returns the cancellation line item if this item was cancelled |
|
| 1500 | - * |
|
| 1501 | - * @return EE_Line_Item[] |
|
| 1502 | - * @throws InvalidArgumentException |
|
| 1503 | - * @throws InvalidInterfaceException |
|
| 1504 | - * @throws InvalidDataTypeException |
|
| 1505 | - * @throws ReflectionException |
|
| 1506 | - * @throws EE_Error |
|
| 1507 | - */ |
|
| 1508 | - public function get_cancellations() |
|
| 1509 | - { |
|
| 1510 | - return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation); |
|
| 1511 | - } |
|
| 1512 | - |
|
| 1513 | - |
|
| 1514 | - /** |
|
| 1515 | - * If this item has an ID, then this saves it again to update the db |
|
| 1516 | - * |
|
| 1517 | - * @return int count of items saved |
|
| 1518 | - * @throws EE_Error |
|
| 1519 | - * @throws InvalidArgumentException |
|
| 1520 | - * @throws InvalidDataTypeException |
|
| 1521 | - * @throws InvalidInterfaceException |
|
| 1522 | - * @throws ReflectionException |
|
| 1523 | - */ |
|
| 1524 | - public function maybe_save() |
|
| 1525 | - { |
|
| 1526 | - if ($this->ID()) { |
|
| 1527 | - return $this->save(); |
|
| 1528 | - } |
|
| 1529 | - return false; |
|
| 1530 | - } |
|
| 1531 | - |
|
| 1532 | - |
|
| 1533 | - /** |
|
| 1534 | - * clears the cached children and parent from the line item |
|
| 1535 | - * |
|
| 1536 | - * @return void |
|
| 1537 | - */ |
|
| 1538 | - public function clear_related_line_item_cache() |
|
| 1539 | - { |
|
| 1540 | - $this->_children = array(); |
|
| 1541 | - $this->_parent = null; |
|
| 1542 | - } |
|
| 1543 | - |
|
| 1544 | - |
|
| 1545 | - /** |
|
| 1546 | - * @param bool $raw |
|
| 1547 | - * @return int |
|
| 1548 | - * @throws EE_Error |
|
| 1549 | - * @throws InvalidArgumentException |
|
| 1550 | - * @throws InvalidDataTypeException |
|
| 1551 | - * @throws InvalidInterfaceException |
|
| 1552 | - * @throws ReflectionException |
|
| 1553 | - */ |
|
| 1554 | - public function timestamp($raw = false) |
|
| 1555 | - { |
|
| 1556 | - return $raw |
|
| 1557 | - ? $this->get_raw('LIN_timestamp') |
|
| 1558 | - : $this->get('LIN_timestamp'); |
|
| 1559 | - } |
|
| 1560 | - |
|
| 1561 | - |
|
| 1562 | - |
|
| 1563 | - |
|
| 1564 | - /************************* DEPRECATED *************************/ |
|
| 1565 | - /** |
|
| 1566 | - * @deprecated 4.6.0 |
|
| 1567 | - * @param string $type one of the constants on EEM_Line_Item |
|
| 1568 | - * @return EE_Line_Item[] |
|
| 1569 | - * @throws EE_Error |
|
| 1570 | - */ |
|
| 1571 | - protected function _get_descendants_of_type($type) |
|
| 1572 | - { |
|
| 1573 | - EE_Error::doing_it_wrong( |
|
| 1574 | - 'EE_Line_Item::_get_descendants_of_type()', |
|
| 1575 | - sprintf( |
|
| 1576 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 1577 | - 'EEH_Line_Item::get_descendants_of_type()' |
|
| 1578 | - ), |
|
| 1579 | - '4.6.0' |
|
| 1580 | - ); |
|
| 1581 | - return EEH_Line_Item::get_descendants_of_type($this, $type); |
|
| 1582 | - } |
|
| 1583 | - |
|
| 1584 | - |
|
| 1585 | - /** |
|
| 1586 | - * @deprecated 4.6.0 |
|
| 1587 | - * @param string $type like one of the EEM_Line_Item::type_* |
|
| 1588 | - * @return EE_Line_Item |
|
| 1589 | - * @throws EE_Error |
|
| 1590 | - * @throws InvalidArgumentException |
|
| 1591 | - * @throws InvalidDataTypeException |
|
| 1592 | - * @throws InvalidInterfaceException |
|
| 1593 | - * @throws ReflectionException |
|
| 1594 | - */ |
|
| 1595 | - public function get_nearest_descendant_of_type($type) |
|
| 1596 | - { |
|
| 1597 | - EE_Error::doing_it_wrong( |
|
| 1598 | - 'EE_Line_Item::get_nearest_descendant_of_type()', |
|
| 1599 | - sprintf( |
|
| 1600 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 1601 | - 'EEH_Line_Item::get_nearest_descendant_of_type()' |
|
| 1602 | - ), |
|
| 1603 | - '4.6.0' |
|
| 1604 | - ); |
|
| 1605 | - return EEH_Line_Item::get_nearest_descendant_of_type($this, $type); |
|
| 1606 | - } |
|
| 19 | + /** |
|
| 20 | + * for children line items (currently not a normal relation) |
|
| 21 | + * |
|
| 22 | + * @type EE_Line_Item[] |
|
| 23 | + */ |
|
| 24 | + protected $_children = array(); |
|
| 25 | + |
|
| 26 | + /** |
|
| 27 | + * for the parent line item |
|
| 28 | + * |
|
| 29 | + * @var EE_Line_Item |
|
| 30 | + */ |
|
| 31 | + protected $_parent; |
|
| 32 | + |
|
| 33 | + /** |
|
| 34 | + * @var LineItemCalculator |
|
| 35 | + */ |
|
| 36 | + protected $calculator; |
|
| 37 | + |
|
| 38 | + |
|
| 39 | + /** |
|
| 40 | + * @param array $props_n_values incoming values |
|
| 41 | + * @param string $timezone incoming timezone (if not set the timezone set for the website will be |
|
| 42 | + * used.) |
|
| 43 | + * @param array $date_formats incoming date_formats in an array where the first value is the |
|
| 44 | + * date_format and the second value is the time format |
|
| 45 | + * @return EE_Line_Item |
|
| 46 | + * @throws EE_Error |
|
| 47 | + * @throws InvalidArgumentException |
|
| 48 | + * @throws InvalidDataTypeException |
|
| 49 | + * @throws InvalidInterfaceException |
|
| 50 | + * @throws ReflectionException |
|
| 51 | + */ |
|
| 52 | + public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
| 53 | + { |
|
| 54 | + $has_object = parent::_check_for_object( |
|
| 55 | + $props_n_values, |
|
| 56 | + __CLASS__, |
|
| 57 | + $timezone, |
|
| 58 | + $date_formats |
|
| 59 | + ); |
|
| 60 | + return $has_object |
|
| 61 | + ? $has_object |
|
| 62 | + : new self($props_n_values, false, $timezone); |
|
| 63 | + } |
|
| 64 | + |
|
| 65 | + |
|
| 66 | + /** |
|
| 67 | + * @param array $props_n_values incoming values from the database |
|
| 68 | + * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
| 69 | + * the website will be used. |
|
| 70 | + * @return EE_Line_Item |
|
| 71 | + * @throws EE_Error |
|
| 72 | + * @throws InvalidArgumentException |
|
| 73 | + * @throws InvalidDataTypeException |
|
| 74 | + * @throws InvalidInterfaceException |
|
| 75 | + * @throws ReflectionException |
|
| 76 | + */ |
|
| 77 | + public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
| 78 | + { |
|
| 79 | + return new self($props_n_values, true, $timezone); |
|
| 80 | + } |
|
| 81 | + |
|
| 82 | + |
|
| 83 | + /** |
|
| 84 | + * Adds some defaults if they're not specified |
|
| 85 | + * |
|
| 86 | + * @param array $fieldValues |
|
| 87 | + * @param bool $bydb |
|
| 88 | + * @param string $timezone |
|
| 89 | + * @throws EE_Error |
|
| 90 | + * @throws InvalidArgumentException |
|
| 91 | + * @throws InvalidDataTypeException |
|
| 92 | + * @throws InvalidInterfaceException |
|
| 93 | + * @throws ReflectionException |
|
| 94 | + */ |
|
| 95 | + protected function __construct($fieldValues = array(), $bydb = false, $timezone = '') |
|
| 96 | + { |
|
| 97 | + $this->calculator = LoaderFactory::getShared(LineItemCalculator::class); |
|
| 98 | + parent::__construct($fieldValues, $bydb, $timezone); |
|
| 99 | + if (! $this->get('LIN_code')) { |
|
| 100 | + $this->set_code($this->generate_code()); |
|
| 101 | + } |
|
| 102 | + } |
|
| 103 | + |
|
| 104 | + |
|
| 105 | + /** |
|
| 106 | + * Gets ID |
|
| 107 | + * |
|
| 108 | + * @return int |
|
| 109 | + * @throws EE_Error |
|
| 110 | + * @throws InvalidArgumentException |
|
| 111 | + * @throws InvalidDataTypeException |
|
| 112 | + * @throws InvalidInterfaceException |
|
| 113 | + * @throws ReflectionException |
|
| 114 | + */ |
|
| 115 | + public function ID() |
|
| 116 | + { |
|
| 117 | + return $this->get('LIN_ID'); |
|
| 118 | + } |
|
| 119 | + |
|
| 120 | + |
|
| 121 | + /** |
|
| 122 | + * Gets TXN_ID |
|
| 123 | + * |
|
| 124 | + * @return int |
|
| 125 | + * @throws EE_Error |
|
| 126 | + * @throws InvalidArgumentException |
|
| 127 | + * @throws InvalidDataTypeException |
|
| 128 | + * @throws InvalidInterfaceException |
|
| 129 | + * @throws ReflectionException |
|
| 130 | + */ |
|
| 131 | + public function TXN_ID() |
|
| 132 | + { |
|
| 133 | + return $this->get('TXN_ID'); |
|
| 134 | + } |
|
| 135 | + |
|
| 136 | + |
|
| 137 | + /** |
|
| 138 | + * Sets TXN_ID |
|
| 139 | + * |
|
| 140 | + * @param int $TXN_ID |
|
| 141 | + * @throws EE_Error |
|
| 142 | + * @throws InvalidArgumentException |
|
| 143 | + * @throws InvalidDataTypeException |
|
| 144 | + * @throws InvalidInterfaceException |
|
| 145 | + * @throws ReflectionException |
|
| 146 | + */ |
|
| 147 | + public function set_TXN_ID($TXN_ID) |
|
| 148 | + { |
|
| 149 | + $this->set('TXN_ID', $TXN_ID); |
|
| 150 | + } |
|
| 151 | + |
|
| 152 | + |
|
| 153 | + /** |
|
| 154 | + * Gets name |
|
| 155 | + * |
|
| 156 | + * @return string |
|
| 157 | + * @throws EE_Error |
|
| 158 | + * @throws InvalidArgumentException |
|
| 159 | + * @throws InvalidDataTypeException |
|
| 160 | + * @throws InvalidInterfaceException |
|
| 161 | + * @throws ReflectionException |
|
| 162 | + */ |
|
| 163 | + public function name() |
|
| 164 | + { |
|
| 165 | + $name = $this->get('LIN_name'); |
|
| 166 | + if (! $name) { |
|
| 167 | + $name = ucwords(str_replace('-', ' ', $this->type())); |
|
| 168 | + } |
|
| 169 | + return $name; |
|
| 170 | + } |
|
| 171 | + |
|
| 172 | + |
|
| 173 | + /** |
|
| 174 | + * Sets name |
|
| 175 | + * |
|
| 176 | + * @param string $name |
|
| 177 | + * @throws EE_Error |
|
| 178 | + * @throws InvalidArgumentException |
|
| 179 | + * @throws InvalidDataTypeException |
|
| 180 | + * @throws InvalidInterfaceException |
|
| 181 | + * @throws ReflectionException |
|
| 182 | + */ |
|
| 183 | + public function set_name($name) |
|
| 184 | + { |
|
| 185 | + $this->set('LIN_name', $name); |
|
| 186 | + } |
|
| 187 | + |
|
| 188 | + |
|
| 189 | + /** |
|
| 190 | + * Gets desc |
|
| 191 | + * |
|
| 192 | + * @return string |
|
| 193 | + * @throws EE_Error |
|
| 194 | + * @throws InvalidArgumentException |
|
| 195 | + * @throws InvalidDataTypeException |
|
| 196 | + * @throws InvalidInterfaceException |
|
| 197 | + * @throws ReflectionException |
|
| 198 | + */ |
|
| 199 | + public function desc() |
|
| 200 | + { |
|
| 201 | + return $this->get('LIN_desc'); |
|
| 202 | + } |
|
| 203 | + |
|
| 204 | + |
|
| 205 | + /** |
|
| 206 | + * Sets desc |
|
| 207 | + * |
|
| 208 | + * @param string $desc |
|
| 209 | + * @throws EE_Error |
|
| 210 | + * @throws InvalidArgumentException |
|
| 211 | + * @throws InvalidDataTypeException |
|
| 212 | + * @throws InvalidInterfaceException |
|
| 213 | + * @throws ReflectionException |
|
| 214 | + */ |
|
| 215 | + public function set_desc($desc) |
|
| 216 | + { |
|
| 217 | + $this->set('LIN_desc', $desc); |
|
| 218 | + } |
|
| 219 | + |
|
| 220 | + |
|
| 221 | + /** |
|
| 222 | + * Gets quantity |
|
| 223 | + * |
|
| 224 | + * @return int |
|
| 225 | + * @throws EE_Error |
|
| 226 | + * @throws InvalidArgumentException |
|
| 227 | + * @throws InvalidDataTypeException |
|
| 228 | + * @throws InvalidInterfaceException |
|
| 229 | + * @throws ReflectionException |
|
| 230 | + */ |
|
| 231 | + public function quantity(): int |
|
| 232 | + { |
|
| 233 | + return (int) $this->get('LIN_quantity'); |
|
| 234 | + } |
|
| 235 | + |
|
| 236 | + |
|
| 237 | + /** |
|
| 238 | + * Sets quantity |
|
| 239 | + * |
|
| 240 | + * @param int $quantity |
|
| 241 | + * @throws EE_Error |
|
| 242 | + * @throws InvalidArgumentException |
|
| 243 | + * @throws InvalidDataTypeException |
|
| 244 | + * @throws InvalidInterfaceException |
|
| 245 | + * @throws ReflectionException |
|
| 246 | + */ |
|
| 247 | + public function set_quantity($quantity) |
|
| 248 | + { |
|
| 249 | + $this->set('LIN_quantity', max($quantity, 0)); |
|
| 250 | + } |
|
| 251 | + |
|
| 252 | + |
|
| 253 | + /** |
|
| 254 | + * Gets item_id |
|
| 255 | + * |
|
| 256 | + * @return string |
|
| 257 | + * @throws EE_Error |
|
| 258 | + * @throws InvalidArgumentException |
|
| 259 | + * @throws InvalidDataTypeException |
|
| 260 | + * @throws InvalidInterfaceException |
|
| 261 | + * @throws ReflectionException |
|
| 262 | + */ |
|
| 263 | + public function OBJ_ID() |
|
| 264 | + { |
|
| 265 | + return $this->get('OBJ_ID'); |
|
| 266 | + } |
|
| 267 | + |
|
| 268 | + |
|
| 269 | + /** |
|
| 270 | + * Sets item_id |
|
| 271 | + * |
|
| 272 | + * @param string $item_id |
|
| 273 | + * @throws EE_Error |
|
| 274 | + * @throws InvalidArgumentException |
|
| 275 | + * @throws InvalidDataTypeException |
|
| 276 | + * @throws InvalidInterfaceException |
|
| 277 | + * @throws ReflectionException |
|
| 278 | + */ |
|
| 279 | + public function set_OBJ_ID($item_id) |
|
| 280 | + { |
|
| 281 | + $this->set('OBJ_ID', $item_id); |
|
| 282 | + } |
|
| 283 | + |
|
| 284 | + |
|
| 285 | + /** |
|
| 286 | + * Gets item_type |
|
| 287 | + * |
|
| 288 | + * @return string |
|
| 289 | + * @throws EE_Error |
|
| 290 | + * @throws InvalidArgumentException |
|
| 291 | + * @throws InvalidDataTypeException |
|
| 292 | + * @throws InvalidInterfaceException |
|
| 293 | + * @throws ReflectionException |
|
| 294 | + */ |
|
| 295 | + public function OBJ_type() |
|
| 296 | + { |
|
| 297 | + return $this->get('OBJ_type'); |
|
| 298 | + } |
|
| 299 | + |
|
| 300 | + |
|
| 301 | + /** |
|
| 302 | + * Gets item_type |
|
| 303 | + * |
|
| 304 | + * @return string |
|
| 305 | + * @throws EE_Error |
|
| 306 | + * @throws InvalidArgumentException |
|
| 307 | + * @throws InvalidDataTypeException |
|
| 308 | + * @throws InvalidInterfaceException |
|
| 309 | + * @throws ReflectionException |
|
| 310 | + */ |
|
| 311 | + public function OBJ_type_i18n() |
|
| 312 | + { |
|
| 313 | + $obj_type = $this->OBJ_type(); |
|
| 314 | + switch ($obj_type) { |
|
| 315 | + case EEM_Line_Item::OBJ_TYPE_EVENT: |
|
| 316 | + $obj_type = esc_html__('Event', 'event_espresso'); |
|
| 317 | + break; |
|
| 318 | + case EEM_Line_Item::OBJ_TYPE_PRICE: |
|
| 319 | + $obj_type = esc_html__('Price', 'event_espresso'); |
|
| 320 | + break; |
|
| 321 | + case EEM_Line_Item::OBJ_TYPE_PROMOTION: |
|
| 322 | + $obj_type = esc_html__('Promotion', 'event_espresso'); |
|
| 323 | + break; |
|
| 324 | + case EEM_Line_Item::OBJ_TYPE_TICKET: |
|
| 325 | + $obj_type = esc_html__('Ticket', 'event_espresso'); |
|
| 326 | + break; |
|
| 327 | + case EEM_Line_Item::OBJ_TYPE_TRANSACTION: |
|
| 328 | + $obj_type = esc_html__('Transaction', 'event_espresso'); |
|
| 329 | + break; |
|
| 330 | + } |
|
| 331 | + return apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this); |
|
| 332 | + } |
|
| 333 | + |
|
| 334 | + |
|
| 335 | + /** |
|
| 336 | + * Sets item_type |
|
| 337 | + * |
|
| 338 | + * @param string $OBJ_type |
|
| 339 | + * @throws EE_Error |
|
| 340 | + * @throws InvalidArgumentException |
|
| 341 | + * @throws InvalidDataTypeException |
|
| 342 | + * @throws InvalidInterfaceException |
|
| 343 | + * @throws ReflectionException |
|
| 344 | + */ |
|
| 345 | + public function set_OBJ_type($OBJ_type) |
|
| 346 | + { |
|
| 347 | + $this->set('OBJ_type', $OBJ_type); |
|
| 348 | + } |
|
| 349 | + |
|
| 350 | + |
|
| 351 | + /** |
|
| 352 | + * Gets unit_price |
|
| 353 | + * |
|
| 354 | + * @return float |
|
| 355 | + * @throws EE_Error |
|
| 356 | + * @throws InvalidArgumentException |
|
| 357 | + * @throws InvalidDataTypeException |
|
| 358 | + * @throws InvalidInterfaceException |
|
| 359 | + * @throws ReflectionException |
|
| 360 | + */ |
|
| 361 | + public function unit_price() |
|
| 362 | + { |
|
| 363 | + return $this->get('LIN_unit_price'); |
|
| 364 | + } |
|
| 365 | + |
|
| 366 | + |
|
| 367 | + /** |
|
| 368 | + * Sets unit_price |
|
| 369 | + * |
|
| 370 | + * @param float $unit_price |
|
| 371 | + * @throws EE_Error |
|
| 372 | + * @throws InvalidArgumentException |
|
| 373 | + * @throws InvalidDataTypeException |
|
| 374 | + * @throws InvalidInterfaceException |
|
| 375 | + * @throws ReflectionException |
|
| 376 | + */ |
|
| 377 | + public function set_unit_price($unit_price) |
|
| 378 | + { |
|
| 379 | + $this->set('LIN_unit_price', $unit_price); |
|
| 380 | + } |
|
| 381 | + |
|
| 382 | + |
|
| 383 | + /** |
|
| 384 | + * Checks if this item is a percentage modifier or not |
|
| 385 | + * |
|
| 386 | + * @return boolean |
|
| 387 | + * @throws EE_Error |
|
| 388 | + * @throws InvalidArgumentException |
|
| 389 | + * @throws InvalidDataTypeException |
|
| 390 | + * @throws InvalidInterfaceException |
|
| 391 | + * @throws ReflectionException |
|
| 392 | + */ |
|
| 393 | + public function is_percent() |
|
| 394 | + { |
|
| 395 | + if ($this->is_tax_sub_total()) { |
|
| 396 | + // tax subtotals HAVE a percent on them, that percentage only applies |
|
| 397 | + // to taxable items, so its' an exception. Treat it like a flat line item |
|
| 398 | + return false; |
|
| 399 | + } |
|
| 400 | + $unit_price = abs($this->get('LIN_unit_price')); |
|
| 401 | + $percent = abs($this->get('LIN_percent')); |
|
| 402 | + if ($unit_price < .001 && $percent) { |
|
| 403 | + return true; |
|
| 404 | + } |
|
| 405 | + if ($unit_price >= .001 && ! $percent) { |
|
| 406 | + return false; |
|
| 407 | + } |
|
| 408 | + if ($unit_price >= .001 && $percent) { |
|
| 409 | + throw new EE_Error( |
|
| 410 | + sprintf( |
|
| 411 | + esc_html__( |
|
| 412 | + 'A Line Item can not have a unit price of (%s) AND a percent (%s)!', |
|
| 413 | + 'event_espresso' |
|
| 414 | + ), |
|
| 415 | + $unit_price, |
|
| 416 | + $percent |
|
| 417 | + ) |
|
| 418 | + ); |
|
| 419 | + } |
|
| 420 | + // if they're both 0, assume its not a percent item |
|
| 421 | + return false; |
|
| 422 | + } |
|
| 423 | + |
|
| 424 | + |
|
| 425 | + /** |
|
| 426 | + * Gets percent (between 100-.001) |
|
| 427 | + * |
|
| 428 | + * @return float |
|
| 429 | + * @throws EE_Error |
|
| 430 | + * @throws InvalidArgumentException |
|
| 431 | + * @throws InvalidDataTypeException |
|
| 432 | + * @throws InvalidInterfaceException |
|
| 433 | + * @throws ReflectionException |
|
| 434 | + */ |
|
| 435 | + public function percent() |
|
| 436 | + { |
|
| 437 | + return $this->get('LIN_percent'); |
|
| 438 | + } |
|
| 439 | + |
|
| 440 | + |
|
| 441 | + /** |
|
| 442 | + * Sets percent (between 100-0.01) |
|
| 443 | + * |
|
| 444 | + * @param float $percent |
|
| 445 | + * @throws EE_Error |
|
| 446 | + * @throws InvalidArgumentException |
|
| 447 | + * @throws InvalidDataTypeException |
|
| 448 | + * @throws InvalidInterfaceException |
|
| 449 | + * @throws ReflectionException |
|
| 450 | + */ |
|
| 451 | + public function set_percent($percent) |
|
| 452 | + { |
|
| 453 | + $this->set('LIN_percent', $percent); |
|
| 454 | + } |
|
| 455 | + |
|
| 456 | + |
|
| 457 | + /** |
|
| 458 | + * Gets total |
|
| 459 | + * |
|
| 460 | + * @return float |
|
| 461 | + * @throws EE_Error |
|
| 462 | + * @throws InvalidArgumentException |
|
| 463 | + * @throws InvalidDataTypeException |
|
| 464 | + * @throws InvalidInterfaceException |
|
| 465 | + * @throws ReflectionException |
|
| 466 | + */ |
|
| 467 | + public function pretaxTotal(): float |
|
| 468 | + { |
|
| 469 | + return $this->get('LIN_pretax'); |
|
| 470 | + } |
|
| 471 | + |
|
| 472 | + |
|
| 473 | + /** |
|
| 474 | + * Sets total |
|
| 475 | + * |
|
| 476 | + * @param float $pretax_total |
|
| 477 | + * @throws EE_Error |
|
| 478 | + * @throws InvalidArgumentException |
|
| 479 | + * @throws InvalidDataTypeException |
|
| 480 | + * @throws InvalidInterfaceException |
|
| 481 | + * @throws ReflectionException |
|
| 482 | + */ |
|
| 483 | + public function setPretaxTotal(float $pretax_total) |
|
| 484 | + { |
|
| 485 | + $this->set('LIN_pretax', $pretax_total); |
|
| 486 | + } |
|
| 487 | + |
|
| 488 | + |
|
| 489 | + /** |
|
| 490 | + * Gets total |
|
| 491 | + * |
|
| 492 | + * @return float |
|
| 493 | + * @throws EE_Error |
|
| 494 | + * @throws InvalidArgumentException |
|
| 495 | + * @throws InvalidDataTypeException |
|
| 496 | + * @throws InvalidInterfaceException |
|
| 497 | + * @throws ReflectionException |
|
| 498 | + */ |
|
| 499 | + public function total() |
|
| 500 | + { |
|
| 501 | + return $this->get('LIN_total'); |
|
| 502 | + } |
|
| 503 | + |
|
| 504 | + |
|
| 505 | + /** |
|
| 506 | + * Sets total |
|
| 507 | + * |
|
| 508 | + * @param float $total |
|
| 509 | + * @throws EE_Error |
|
| 510 | + * @throws InvalidArgumentException |
|
| 511 | + * @throws InvalidDataTypeException |
|
| 512 | + * @throws InvalidInterfaceException |
|
| 513 | + * @throws ReflectionException |
|
| 514 | + */ |
|
| 515 | + public function set_total($total) |
|
| 516 | + { |
|
| 517 | + $this->set('LIN_total', $total); |
|
| 518 | + } |
|
| 519 | + |
|
| 520 | + |
|
| 521 | + /** |
|
| 522 | + * Gets order |
|
| 523 | + * |
|
| 524 | + * @return int |
|
| 525 | + * @throws EE_Error |
|
| 526 | + * @throws InvalidArgumentException |
|
| 527 | + * @throws InvalidDataTypeException |
|
| 528 | + * @throws InvalidInterfaceException |
|
| 529 | + * @throws ReflectionException |
|
| 530 | + */ |
|
| 531 | + public function order() |
|
| 532 | + { |
|
| 533 | + return $this->get('LIN_order'); |
|
| 534 | + } |
|
| 535 | + |
|
| 536 | + |
|
| 537 | + /** |
|
| 538 | + * Sets order |
|
| 539 | + * |
|
| 540 | + * @param int $order |
|
| 541 | + * @throws EE_Error |
|
| 542 | + * @throws InvalidArgumentException |
|
| 543 | + * @throws InvalidDataTypeException |
|
| 544 | + * @throws InvalidInterfaceException |
|
| 545 | + * @throws ReflectionException |
|
| 546 | + */ |
|
| 547 | + public function set_order($order) |
|
| 548 | + { |
|
| 549 | + $this->set('LIN_order', $order); |
|
| 550 | + } |
|
| 551 | + |
|
| 552 | + |
|
| 553 | + /** |
|
| 554 | + * Gets parent |
|
| 555 | + * |
|
| 556 | + * @return int |
|
| 557 | + * @throws EE_Error |
|
| 558 | + * @throws InvalidArgumentException |
|
| 559 | + * @throws InvalidDataTypeException |
|
| 560 | + * @throws InvalidInterfaceException |
|
| 561 | + * @throws ReflectionException |
|
| 562 | + */ |
|
| 563 | + public function parent_ID() |
|
| 564 | + { |
|
| 565 | + return $this->get('LIN_parent'); |
|
| 566 | + } |
|
| 567 | + |
|
| 568 | + |
|
| 569 | + /** |
|
| 570 | + * Sets parent |
|
| 571 | + * |
|
| 572 | + * @param int $parent |
|
| 573 | + * @throws EE_Error |
|
| 574 | + * @throws InvalidArgumentException |
|
| 575 | + * @throws InvalidDataTypeException |
|
| 576 | + * @throws InvalidInterfaceException |
|
| 577 | + * @throws ReflectionException |
|
| 578 | + */ |
|
| 579 | + public function set_parent_ID($parent) |
|
| 580 | + { |
|
| 581 | + $this->set('LIN_parent', $parent); |
|
| 582 | + } |
|
| 583 | + |
|
| 584 | + |
|
| 585 | + /** |
|
| 586 | + * Gets type |
|
| 587 | + * |
|
| 588 | + * @return string |
|
| 589 | + * @throws EE_Error |
|
| 590 | + * @throws InvalidArgumentException |
|
| 591 | + * @throws InvalidDataTypeException |
|
| 592 | + * @throws InvalidInterfaceException |
|
| 593 | + * @throws ReflectionException |
|
| 594 | + */ |
|
| 595 | + public function type() |
|
| 596 | + { |
|
| 597 | + return $this->get('LIN_type'); |
|
| 598 | + } |
|
| 599 | + |
|
| 600 | + |
|
| 601 | + /** |
|
| 602 | + * Sets type |
|
| 603 | + * |
|
| 604 | + * @param string $type |
|
| 605 | + * @throws EE_Error |
|
| 606 | + * @throws InvalidArgumentException |
|
| 607 | + * @throws InvalidDataTypeException |
|
| 608 | + * @throws InvalidInterfaceException |
|
| 609 | + * @throws ReflectionException |
|
| 610 | + */ |
|
| 611 | + public function set_type($type) |
|
| 612 | + { |
|
| 613 | + $this->set('LIN_type', $type); |
|
| 614 | + } |
|
| 615 | + |
|
| 616 | + |
|
| 617 | + /** |
|
| 618 | + * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\ |
|
| 619 | + * 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 |
|
| 620 | + * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()` |
|
| 621 | + * or indirectly by `EE_Line_item::add_child_line_item()`) |
|
| 622 | + * |
|
| 623 | + * @return EE_Base_Class|EE_Line_Item |
|
| 624 | + * @throws EE_Error |
|
| 625 | + * @throws InvalidArgumentException |
|
| 626 | + * @throws InvalidDataTypeException |
|
| 627 | + * @throws InvalidInterfaceException |
|
| 628 | + * @throws ReflectionException |
|
| 629 | + */ |
|
| 630 | + public function parent() |
|
| 631 | + { |
|
| 632 | + return $this->ID() |
|
| 633 | + ? $this->get_model()->get_one_by_ID($this->parent_ID()) |
|
| 634 | + : $this->_parent; |
|
| 635 | + } |
|
| 636 | + |
|
| 637 | + |
|
| 638 | + /** |
|
| 639 | + * Gets ALL the children of this line item (ie, all the parts that contribute towards this total). |
|
| 640 | + * |
|
| 641 | + * @return EE_Line_Item[] |
|
| 642 | + * @throws EE_Error |
|
| 643 | + * @throws InvalidArgumentException |
|
| 644 | + * @throws InvalidDataTypeException |
|
| 645 | + * @throws InvalidInterfaceException |
|
| 646 | + * @throws ReflectionException |
|
| 647 | + */ |
|
| 648 | + public function children(array $query_params = []): array |
|
| 649 | + { |
|
| 650 | + if ($this->ID()) { |
|
| 651 | + // ensure where params are an array |
|
| 652 | + $query_params[0] = $query_params[0] ?? []; |
|
| 653 | + // add defaults for line item parent and orderby |
|
| 654 | + $query_params[0] += ['LIN_parent' => $this->ID()]; |
|
| 655 | + $query_params += ['order_by' => ['LIN_order' => 'ASC']]; |
|
| 656 | + return $this->get_model()->get_all($query_params); |
|
| 657 | + } |
|
| 658 | + if (! is_array($this->_children)) { |
|
| 659 | + $this->_children = array(); |
|
| 660 | + } |
|
| 661 | + return $this->_children; |
|
| 662 | + } |
|
| 663 | + |
|
| 664 | + |
|
| 665 | + /** |
|
| 666 | + * Gets code |
|
| 667 | + * |
|
| 668 | + * @return string |
|
| 669 | + * @throws EE_Error |
|
| 670 | + * @throws InvalidArgumentException |
|
| 671 | + * @throws InvalidDataTypeException |
|
| 672 | + * @throws InvalidInterfaceException |
|
| 673 | + * @throws ReflectionException |
|
| 674 | + */ |
|
| 675 | + public function code() |
|
| 676 | + { |
|
| 677 | + return $this->get('LIN_code'); |
|
| 678 | + } |
|
| 679 | + |
|
| 680 | + |
|
| 681 | + /** |
|
| 682 | + * Sets code |
|
| 683 | + * |
|
| 684 | + * @param string $code |
|
| 685 | + * @throws EE_Error |
|
| 686 | + * @throws InvalidArgumentException |
|
| 687 | + * @throws InvalidDataTypeException |
|
| 688 | + * @throws InvalidInterfaceException |
|
| 689 | + * @throws ReflectionException |
|
| 690 | + */ |
|
| 691 | + public function set_code($code) |
|
| 692 | + { |
|
| 693 | + $this->set('LIN_code', $code); |
|
| 694 | + } |
|
| 695 | + |
|
| 696 | + |
|
| 697 | + /** |
|
| 698 | + * Gets is_taxable |
|
| 699 | + * |
|
| 700 | + * @return boolean |
|
| 701 | + * @throws EE_Error |
|
| 702 | + * @throws InvalidArgumentException |
|
| 703 | + * @throws InvalidDataTypeException |
|
| 704 | + * @throws InvalidInterfaceException |
|
| 705 | + * @throws ReflectionException |
|
| 706 | + */ |
|
| 707 | + public function is_taxable() |
|
| 708 | + { |
|
| 709 | + return $this->get('LIN_is_taxable'); |
|
| 710 | + } |
|
| 711 | + |
|
| 712 | + |
|
| 713 | + /** |
|
| 714 | + * Sets is_taxable |
|
| 715 | + * |
|
| 716 | + * @param boolean $is_taxable |
|
| 717 | + * @throws EE_Error |
|
| 718 | + * @throws InvalidArgumentException |
|
| 719 | + * @throws InvalidDataTypeException |
|
| 720 | + * @throws InvalidInterfaceException |
|
| 721 | + * @throws ReflectionException |
|
| 722 | + */ |
|
| 723 | + public function set_is_taxable($is_taxable) |
|
| 724 | + { |
|
| 725 | + $this->set('LIN_is_taxable', $is_taxable); |
|
| 726 | + } |
|
| 727 | + |
|
| 728 | + |
|
| 729 | + /** |
|
| 730 | + * Gets the object that this model-joins-to. |
|
| 731 | + * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on |
|
| 732 | + * EEM_Promotion_Object |
|
| 733 | + * Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object |
|
| 734 | + * |
|
| 735 | + * @return EE_Base_Class | NULL |
|
| 736 | + * @throws EE_Error |
|
| 737 | + * @throws InvalidArgumentException |
|
| 738 | + * @throws InvalidDataTypeException |
|
| 739 | + * @throws InvalidInterfaceException |
|
| 740 | + * @throws ReflectionException |
|
| 741 | + */ |
|
| 742 | + public function get_object() |
|
| 743 | + { |
|
| 744 | + $model_name_of_related_obj = $this->OBJ_type(); |
|
| 745 | + return $this->get_model()->has_relation($model_name_of_related_obj) |
|
| 746 | + ? $this->get_first_related($model_name_of_related_obj) |
|
| 747 | + : null; |
|
| 748 | + } |
|
| 749 | + |
|
| 750 | + |
|
| 751 | + /** |
|
| 752 | + * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket. |
|
| 753 | + * (IE, if this line item is for a price or something else, will return NULL) |
|
| 754 | + * |
|
| 755 | + * @param array $query_params |
|
| 756 | + * @return EE_Base_Class|EE_Ticket |
|
| 757 | + * @throws EE_Error |
|
| 758 | + * @throws InvalidArgumentException |
|
| 759 | + * @throws InvalidDataTypeException |
|
| 760 | + * @throws InvalidInterfaceException |
|
| 761 | + * @throws ReflectionException |
|
| 762 | + */ |
|
| 763 | + public function ticket($query_params = array()) |
|
| 764 | + { |
|
| 765 | + // we're going to assume that when this method is called |
|
| 766 | + // we always want to receive the attached ticket EVEN if that ticket is archived. |
|
| 767 | + // This can be overridden via the incoming $query_params argument |
|
| 768 | + $remove_defaults = array('default_where_conditions' => 'none'); |
|
| 769 | + $query_params = array_merge($remove_defaults, $query_params); |
|
| 770 | + return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TICKET, $query_params); |
|
| 771 | + } |
|
| 772 | + |
|
| 773 | + |
|
| 774 | + /** |
|
| 775 | + * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket |
|
| 776 | + * |
|
| 777 | + * @return EE_Datetime | NULL |
|
| 778 | + * @throws EE_Error |
|
| 779 | + * @throws InvalidArgumentException |
|
| 780 | + * @throws InvalidDataTypeException |
|
| 781 | + * @throws InvalidInterfaceException |
|
| 782 | + * @throws ReflectionException |
|
| 783 | + */ |
|
| 784 | + public function get_ticket_datetime() |
|
| 785 | + { |
|
| 786 | + if ($this->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
| 787 | + $ticket = $this->ticket(); |
|
| 788 | + if ($ticket instanceof EE_Ticket) { |
|
| 789 | + $datetime = $ticket->first_datetime(); |
|
| 790 | + if ($datetime instanceof EE_Datetime) { |
|
| 791 | + return $datetime; |
|
| 792 | + } |
|
| 793 | + } |
|
| 794 | + } |
|
| 795 | + return null; |
|
| 796 | + } |
|
| 797 | + |
|
| 798 | + |
|
| 799 | + /** |
|
| 800 | + * Gets the event's name that's related to the ticket, if this is for |
|
| 801 | + * a ticket |
|
| 802 | + * |
|
| 803 | + * @return string |
|
| 804 | + * @throws EE_Error |
|
| 805 | + * @throws InvalidArgumentException |
|
| 806 | + * @throws InvalidDataTypeException |
|
| 807 | + * @throws InvalidInterfaceException |
|
| 808 | + * @throws ReflectionException |
|
| 809 | + */ |
|
| 810 | + public function ticket_event_name() |
|
| 811 | + { |
|
| 812 | + $event_name = esc_html__('Unknown', 'event_espresso'); |
|
| 813 | + $event = $this->ticket_event(); |
|
| 814 | + if ($event instanceof EE_Event) { |
|
| 815 | + $event_name = $event->name(); |
|
| 816 | + } |
|
| 817 | + return $event_name; |
|
| 818 | + } |
|
| 819 | + |
|
| 820 | + |
|
| 821 | + /** |
|
| 822 | + * Gets the event that's related to the ticket, if this line item represents a ticket. |
|
| 823 | + * |
|
| 824 | + * @return EE_Event|null |
|
| 825 | + * @throws EE_Error |
|
| 826 | + * @throws InvalidArgumentException |
|
| 827 | + * @throws InvalidDataTypeException |
|
| 828 | + * @throws InvalidInterfaceException |
|
| 829 | + * @throws ReflectionException |
|
| 830 | + */ |
|
| 831 | + public function ticket_event() |
|
| 832 | + { |
|
| 833 | + $event = null; |
|
| 834 | + $ticket = $this->ticket(); |
|
| 835 | + if ($ticket instanceof EE_Ticket) { |
|
| 836 | + $datetime = $ticket->first_datetime(); |
|
| 837 | + if ($datetime instanceof EE_Datetime) { |
|
| 838 | + $event = $datetime->event(); |
|
| 839 | + } |
|
| 840 | + } |
|
| 841 | + return $event; |
|
| 842 | + } |
|
| 843 | + |
|
| 844 | + |
|
| 845 | + /** |
|
| 846 | + * Gets the first datetime for this lien item, assuming it's for a ticket |
|
| 847 | + * |
|
| 848 | + * @param string $date_format |
|
| 849 | + * @param string $time_format |
|
| 850 | + * @return string |
|
| 851 | + * @throws EE_Error |
|
| 852 | + * @throws InvalidArgumentException |
|
| 853 | + * @throws InvalidDataTypeException |
|
| 854 | + * @throws InvalidInterfaceException |
|
| 855 | + * @throws ReflectionException |
|
| 856 | + */ |
|
| 857 | + public function ticket_datetime_start($date_format = '', $time_format = '') |
|
| 858 | + { |
|
| 859 | + $first_datetime_string = esc_html__('Unknown', 'event_espresso'); |
|
| 860 | + $datetime = $this->get_ticket_datetime(); |
|
| 861 | + if ($datetime) { |
|
| 862 | + $first_datetime_string = $datetime->start_date_and_time($date_format, $time_format); |
|
| 863 | + } |
|
| 864 | + return $first_datetime_string; |
|
| 865 | + } |
|
| 866 | + |
|
| 867 | + |
|
| 868 | + /** |
|
| 869 | + * Adds the line item as a child to this line item. If there is another child line |
|
| 870 | + * item with the same LIN_code, it is overwritten by this new one |
|
| 871 | + * |
|
| 872 | + * @param EE_Line_Item $line_item |
|
| 873 | + * @param bool $set_order |
|
| 874 | + * @return bool success |
|
| 875 | + * @throws EE_Error |
|
| 876 | + * @throws InvalidArgumentException |
|
| 877 | + * @throws InvalidDataTypeException |
|
| 878 | + * @throws InvalidInterfaceException |
|
| 879 | + * @throws ReflectionException |
|
| 880 | + */ |
|
| 881 | + public function add_child_line_item(EE_Line_Item $line_item, $set_order = true) |
|
| 882 | + { |
|
| 883 | + // should we calculate the LIN_order for this line item ? |
|
| 884 | + if ($set_order || $line_item->order() === null) { |
|
| 885 | + $line_item->set_order(count($this->children())); |
|
| 886 | + } |
|
| 887 | + if ($this->ID()) { |
|
| 888 | + // check for any duplicate line items (with the same code), if so, this replaces it |
|
| 889 | + $line_item_with_same_code = $this->get_child_line_item($line_item->code()); |
|
| 890 | + if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) { |
|
| 891 | + $this->delete_child_line_item($line_item_with_same_code->code()); |
|
| 892 | + } |
|
| 893 | + $line_item->set_parent_ID($this->ID()); |
|
| 894 | + if ($this->TXN_ID()) { |
|
| 895 | + $line_item->set_TXN_ID($this->TXN_ID()); |
|
| 896 | + } |
|
| 897 | + return $line_item->save(); |
|
| 898 | + } |
|
| 899 | + $this->_children[ $line_item->code() ] = $line_item; |
|
| 900 | + if ($line_item->parent() !== $this) { |
|
| 901 | + $line_item->set_parent($this); |
|
| 902 | + } |
|
| 903 | + return true; |
|
| 904 | + } |
|
| 905 | + |
|
| 906 | + |
|
| 907 | + /** |
|
| 908 | + * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation. |
|
| 909 | + * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save() |
|
| 910 | + * However, if this line item is NOT saved to the DB, this just caches the parent on |
|
| 911 | + * the EE_Line_Item::_parent property. |
|
| 912 | + * |
|
| 913 | + * @param EE_Line_Item $line_item |
|
| 914 | + * @throws EE_Error |
|
| 915 | + * @throws InvalidArgumentException |
|
| 916 | + * @throws InvalidDataTypeException |
|
| 917 | + * @throws InvalidInterfaceException |
|
| 918 | + * @throws ReflectionException |
|
| 919 | + */ |
|
| 920 | + public function set_parent($line_item) |
|
| 921 | + { |
|
| 922 | + if ($this->ID()) { |
|
| 923 | + if (! $line_item->ID()) { |
|
| 924 | + $line_item->save(); |
|
| 925 | + } |
|
| 926 | + $this->set_parent_ID($line_item->ID()); |
|
| 927 | + $this->save(); |
|
| 928 | + } else { |
|
| 929 | + $this->_parent = $line_item; |
|
| 930 | + $this->set_parent_ID($line_item->ID()); |
|
| 931 | + } |
|
| 932 | + } |
|
| 933 | + |
|
| 934 | + |
|
| 935 | + /** |
|
| 936 | + * Gets the child line item as specified by its code. Because this returns an object (by reference) |
|
| 937 | + * you can modify this child line item and the parent (this object) can know about them |
|
| 938 | + * because it also has a reference to that line item |
|
| 939 | + * |
|
| 940 | + * @param string $code |
|
| 941 | + * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
| 942 | + * @throws EE_Error |
|
| 943 | + * @throws InvalidArgumentException |
|
| 944 | + * @throws InvalidDataTypeException |
|
| 945 | + * @throws InvalidInterfaceException |
|
| 946 | + * @throws ReflectionException |
|
| 947 | + */ |
|
| 948 | + public function get_child_line_item($code) |
|
| 949 | + { |
|
| 950 | + if ($this->ID()) { |
|
| 951 | + return $this->get_model()->get_one( |
|
| 952 | + array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code)) |
|
| 953 | + ); |
|
| 954 | + } |
|
| 955 | + return isset($this->_children[ $code ]) |
|
| 956 | + ? $this->_children[ $code ] |
|
| 957 | + : null; |
|
| 958 | + } |
|
| 959 | + |
|
| 960 | + |
|
| 961 | + /** |
|
| 962 | + * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD |
|
| 963 | + * cached on it) |
|
| 964 | + * |
|
| 965 | + * @return int |
|
| 966 | + * @throws EE_Error |
|
| 967 | + * @throws InvalidArgumentException |
|
| 968 | + * @throws InvalidDataTypeException |
|
| 969 | + * @throws InvalidInterfaceException |
|
| 970 | + * @throws ReflectionException |
|
| 971 | + */ |
|
| 972 | + public function delete_children_line_items() |
|
| 973 | + { |
|
| 974 | + if ($this->ID()) { |
|
| 975 | + return $this->get_model()->delete(array(array('LIN_parent' => $this->ID()))); |
|
| 976 | + } |
|
| 977 | + $count = count($this->_children); |
|
| 978 | + $this->_children = array(); |
|
| 979 | + return $count; |
|
| 980 | + } |
|
| 981 | + |
|
| 982 | + |
|
| 983 | + /** |
|
| 984 | + * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line |
|
| 985 | + * HAS NOT been saved to the DB, removes the child line item with index $code. |
|
| 986 | + * Also searches through the child's children for a matching line item. However, once a line item has been found |
|
| 987 | + * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be |
|
| 988 | + * deleted) |
|
| 989 | + * |
|
| 990 | + * @param string $code |
|
| 991 | + * @param bool $stop_search_once_found |
|
| 992 | + * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to |
|
| 993 | + * the DB yet) |
|
| 994 | + * @throws EE_Error |
|
| 995 | + * @throws InvalidArgumentException |
|
| 996 | + * @throws InvalidDataTypeException |
|
| 997 | + * @throws InvalidInterfaceException |
|
| 998 | + * @throws ReflectionException |
|
| 999 | + */ |
|
| 1000 | + public function delete_child_line_item($code, $stop_search_once_found = true) |
|
| 1001 | + { |
|
| 1002 | + if ($this->ID()) { |
|
| 1003 | + $items_deleted = 0; |
|
| 1004 | + if ($this->code() === $code) { |
|
| 1005 | + $items_deleted += EEH_Line_Item::delete_all_child_items($this); |
|
| 1006 | + $items_deleted += (int) $this->delete(); |
|
| 1007 | + if ($stop_search_once_found) { |
|
| 1008 | + return $items_deleted; |
|
| 1009 | + } |
|
| 1010 | + } |
|
| 1011 | + foreach ($this->children() as $child_line_item) { |
|
| 1012 | + $items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found); |
|
| 1013 | + } |
|
| 1014 | + return $items_deleted; |
|
| 1015 | + } |
|
| 1016 | + if (isset($this->_children[ $code ])) { |
|
| 1017 | + unset($this->_children[ $code ]); |
|
| 1018 | + return 1; |
|
| 1019 | + } |
|
| 1020 | + return 0; |
|
| 1021 | + } |
|
| 1022 | + |
|
| 1023 | + |
|
| 1024 | + /** |
|
| 1025 | + * If this line item is in the database, is of the type subtotal, and |
|
| 1026 | + * has no children, why do we have it? It should be deleted so this function |
|
| 1027 | + * does that |
|
| 1028 | + * |
|
| 1029 | + * @return boolean |
|
| 1030 | + * @throws EE_Error |
|
| 1031 | + * @throws InvalidArgumentException |
|
| 1032 | + * @throws InvalidDataTypeException |
|
| 1033 | + * @throws InvalidInterfaceException |
|
| 1034 | + * @throws ReflectionException |
|
| 1035 | + */ |
|
| 1036 | + public function delete_if_childless_subtotal() |
|
| 1037 | + { |
|
| 1038 | + if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && ! $this->children()) { |
|
| 1039 | + return $this->delete(); |
|
| 1040 | + } |
|
| 1041 | + return false; |
|
| 1042 | + } |
|
| 1043 | + |
|
| 1044 | + |
|
| 1045 | + /** |
|
| 1046 | + * Creates a code and returns a string. doesn't assign the code to this model object |
|
| 1047 | + * |
|
| 1048 | + * @return string |
|
| 1049 | + * @throws EE_Error |
|
| 1050 | + * @throws InvalidArgumentException |
|
| 1051 | + * @throws InvalidDataTypeException |
|
| 1052 | + * @throws InvalidInterfaceException |
|
| 1053 | + * @throws ReflectionException |
|
| 1054 | + */ |
|
| 1055 | + public function generate_code() |
|
| 1056 | + { |
|
| 1057 | + // each line item in the cart requires a unique identifier |
|
| 1058 | + return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime()); |
|
| 1059 | + } |
|
| 1060 | + |
|
| 1061 | + |
|
| 1062 | + /** |
|
| 1063 | + * @return bool |
|
| 1064 | + * @throws EE_Error |
|
| 1065 | + * @throws InvalidArgumentException |
|
| 1066 | + * @throws InvalidDataTypeException |
|
| 1067 | + * @throws InvalidInterfaceException |
|
| 1068 | + * @throws ReflectionException |
|
| 1069 | + */ |
|
| 1070 | + public function isGlobalTax(): bool |
|
| 1071 | + { |
|
| 1072 | + return $this->type() === EEM_Line_Item::type_tax; |
|
| 1073 | + } |
|
| 1074 | + |
|
| 1075 | + |
|
| 1076 | + /** |
|
| 1077 | + * @return bool |
|
| 1078 | + * @throws EE_Error |
|
| 1079 | + * @throws InvalidArgumentException |
|
| 1080 | + * @throws InvalidDataTypeException |
|
| 1081 | + * @throws InvalidInterfaceException |
|
| 1082 | + * @throws ReflectionException |
|
| 1083 | + */ |
|
| 1084 | + public function isSubTax(): bool |
|
| 1085 | + { |
|
| 1086 | + return $this->type() === EEM_Line_Item::type_sub_tax; |
|
| 1087 | + } |
|
| 1088 | + |
|
| 1089 | + |
|
| 1090 | + /** |
|
| 1091 | + * returns true if this is a line item with a direct descendent of the type sub-tax |
|
| 1092 | + * |
|
| 1093 | + * @return array |
|
| 1094 | + * @throws EE_Error |
|
| 1095 | + * @throws InvalidArgumentException |
|
| 1096 | + * @throws InvalidDataTypeException |
|
| 1097 | + * @throws InvalidInterfaceException |
|
| 1098 | + * @throws ReflectionException |
|
| 1099 | + */ |
|
| 1100 | + public function getSubTaxes(): array |
|
| 1101 | + { |
|
| 1102 | + if (! $this->is_line_item()) { |
|
| 1103 | + return []; |
|
| 1104 | + } |
|
| 1105 | + return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_sub_tax); |
|
| 1106 | + } |
|
| 1107 | + |
|
| 1108 | + |
|
| 1109 | + /** |
|
| 1110 | + * returns true if this is a line item with a direct descendent of the type sub-tax |
|
| 1111 | + * |
|
| 1112 | + * @return bool |
|
| 1113 | + * @throws EE_Error |
|
| 1114 | + * @throws InvalidArgumentException |
|
| 1115 | + * @throws InvalidDataTypeException |
|
| 1116 | + * @throws InvalidInterfaceException |
|
| 1117 | + * @throws ReflectionException |
|
| 1118 | + */ |
|
| 1119 | + public function hasSubTaxes(): bool |
|
| 1120 | + { |
|
| 1121 | + if (! $this->is_line_item()) { |
|
| 1122 | + return false; |
|
| 1123 | + } |
|
| 1124 | + $sub_taxes = $this->getSubTaxes(); |
|
| 1125 | + return ! empty($sub_taxes); |
|
| 1126 | + } |
|
| 1127 | + |
|
| 1128 | + |
|
| 1129 | + /** |
|
| 1130 | + * @return bool |
|
| 1131 | + * @throws EE_Error |
|
| 1132 | + * @throws ReflectionException |
|
| 1133 | + * @deprecated $VID:$ |
|
| 1134 | + */ |
|
| 1135 | + public function is_tax(): bool |
|
| 1136 | + { |
|
| 1137 | + return $this->isGlobalTax(); |
|
| 1138 | + } |
|
| 1139 | + |
|
| 1140 | + |
|
| 1141 | + /** |
|
| 1142 | + * @return bool |
|
| 1143 | + * @throws EE_Error |
|
| 1144 | + * @throws InvalidArgumentException |
|
| 1145 | + * @throws InvalidDataTypeException |
|
| 1146 | + * @throws InvalidInterfaceException |
|
| 1147 | + * @throws ReflectionException |
|
| 1148 | + */ |
|
| 1149 | + public function is_tax_sub_total() |
|
| 1150 | + { |
|
| 1151 | + return $this->type() === EEM_Line_Item::type_tax_sub_total; |
|
| 1152 | + } |
|
| 1153 | + |
|
| 1154 | + |
|
| 1155 | + /** |
|
| 1156 | + * @return bool |
|
| 1157 | + * @throws EE_Error |
|
| 1158 | + * @throws InvalidArgumentException |
|
| 1159 | + * @throws InvalidDataTypeException |
|
| 1160 | + * @throws InvalidInterfaceException |
|
| 1161 | + * @throws ReflectionException |
|
| 1162 | + */ |
|
| 1163 | + public function is_line_item() |
|
| 1164 | + { |
|
| 1165 | + return $this->type() === EEM_Line_Item::type_line_item; |
|
| 1166 | + } |
|
| 1167 | + |
|
| 1168 | + |
|
| 1169 | + /** |
|
| 1170 | + * @return bool |
|
| 1171 | + * @throws EE_Error |
|
| 1172 | + * @throws InvalidArgumentException |
|
| 1173 | + * @throws InvalidDataTypeException |
|
| 1174 | + * @throws InvalidInterfaceException |
|
| 1175 | + * @throws ReflectionException |
|
| 1176 | + */ |
|
| 1177 | + public function is_sub_line_item() |
|
| 1178 | + { |
|
| 1179 | + return $this->type() === EEM_Line_Item::type_sub_line_item; |
|
| 1180 | + } |
|
| 1181 | + |
|
| 1182 | + |
|
| 1183 | + /** |
|
| 1184 | + * @return bool |
|
| 1185 | + * @throws EE_Error |
|
| 1186 | + * @throws InvalidArgumentException |
|
| 1187 | + * @throws InvalidDataTypeException |
|
| 1188 | + * @throws InvalidInterfaceException |
|
| 1189 | + * @throws ReflectionException |
|
| 1190 | + */ |
|
| 1191 | + public function is_sub_total() |
|
| 1192 | + { |
|
| 1193 | + return $this->type() === EEM_Line_Item::type_sub_total; |
|
| 1194 | + } |
|
| 1195 | + |
|
| 1196 | + |
|
| 1197 | + /** |
|
| 1198 | + * Whether or not this line item is a cancellation line item |
|
| 1199 | + * |
|
| 1200 | + * @return boolean |
|
| 1201 | + * @throws EE_Error |
|
| 1202 | + * @throws InvalidArgumentException |
|
| 1203 | + * @throws InvalidDataTypeException |
|
| 1204 | + * @throws InvalidInterfaceException |
|
| 1205 | + * @throws ReflectionException |
|
| 1206 | + */ |
|
| 1207 | + public function is_cancellation() |
|
| 1208 | + { |
|
| 1209 | + return EEM_Line_Item::type_cancellation === $this->type(); |
|
| 1210 | + } |
|
| 1211 | + |
|
| 1212 | + |
|
| 1213 | + /** |
|
| 1214 | + * @return bool |
|
| 1215 | + * @throws EE_Error |
|
| 1216 | + * @throws InvalidArgumentException |
|
| 1217 | + * @throws InvalidDataTypeException |
|
| 1218 | + * @throws InvalidInterfaceException |
|
| 1219 | + * @throws ReflectionException |
|
| 1220 | + */ |
|
| 1221 | + public function is_total() |
|
| 1222 | + { |
|
| 1223 | + return $this->type() === EEM_Line_Item::type_total; |
|
| 1224 | + } |
|
| 1225 | + |
|
| 1226 | + |
|
| 1227 | + /** |
|
| 1228 | + * @return bool |
|
| 1229 | + * @throws EE_Error |
|
| 1230 | + * @throws InvalidArgumentException |
|
| 1231 | + * @throws InvalidDataTypeException |
|
| 1232 | + * @throws InvalidInterfaceException |
|
| 1233 | + * @throws ReflectionException |
|
| 1234 | + */ |
|
| 1235 | + public function is_cancelled() |
|
| 1236 | + { |
|
| 1237 | + return $this->type() === EEM_Line_Item::type_cancellation; |
|
| 1238 | + } |
|
| 1239 | + |
|
| 1240 | + |
|
| 1241 | + /** |
|
| 1242 | + * @return string like '2, 004.00', formatted according to the localized currency |
|
| 1243 | + * @throws EE_Error |
|
| 1244 | + * @throws InvalidArgumentException |
|
| 1245 | + * @throws InvalidDataTypeException |
|
| 1246 | + * @throws InvalidInterfaceException |
|
| 1247 | + * @throws ReflectionException |
|
| 1248 | + */ |
|
| 1249 | + public function unit_price_no_code() |
|
| 1250 | + { |
|
| 1251 | + return $this->get_pretty('LIN_unit_price', 'no_currency_code'); |
|
| 1252 | + } |
|
| 1253 | + |
|
| 1254 | + |
|
| 1255 | + /** |
|
| 1256 | + * @return string like '2, 004.00', formatted according to the localized currency |
|
| 1257 | + * @throws EE_Error |
|
| 1258 | + * @throws InvalidArgumentException |
|
| 1259 | + * @throws InvalidDataTypeException |
|
| 1260 | + * @throws InvalidInterfaceException |
|
| 1261 | + * @throws ReflectionException |
|
| 1262 | + */ |
|
| 1263 | + public function total_no_code() |
|
| 1264 | + { |
|
| 1265 | + return $this->get_pretty('LIN_total', 'no_currency_code'); |
|
| 1266 | + } |
|
| 1267 | + |
|
| 1268 | + |
|
| 1269 | + /** |
|
| 1270 | + * Gets the final total on this item, taking taxes into account. |
|
| 1271 | + * Has the side-effect of setting the sub-total as it was just calculated. |
|
| 1272 | + * If this is used on a grand-total line item, also updates the transaction's |
|
| 1273 | + * TXN_total (provided this line item is allowed to persist, otherwise we don't |
|
| 1274 | + * want to change a persistable transaction with info from a non-persistent line item) |
|
| 1275 | + * |
|
| 1276 | + * @param bool $update_txn_status |
|
| 1277 | + * @return float |
|
| 1278 | + * @throws EE_Error |
|
| 1279 | + * @throws InvalidArgumentException |
|
| 1280 | + * @throws InvalidDataTypeException |
|
| 1281 | + * @throws InvalidInterfaceException |
|
| 1282 | + * @throws ReflectionException |
|
| 1283 | + * @throws RuntimeException |
|
| 1284 | + */ |
|
| 1285 | + public function recalculate_total_including_taxes(bool $update_txn_status = false): float |
|
| 1286 | + { |
|
| 1287 | + $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this); |
|
| 1288 | + return $this->calculator->recalculateTotalIncludingTaxes($grand_total_line_item, $update_txn_status); |
|
| 1289 | + } |
|
| 1290 | + |
|
| 1291 | + |
|
| 1292 | + /** |
|
| 1293 | + * Recursively goes through all the children and recalculates sub-totals EXCEPT for |
|
| 1294 | + * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its |
|
| 1295 | + * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and |
|
| 1296 | + * when this is called on the grand total |
|
| 1297 | + * |
|
| 1298 | + * @return float |
|
| 1299 | + * @throws EE_Error |
|
| 1300 | + * @throws InvalidArgumentException |
|
| 1301 | + * @throws InvalidDataTypeException |
|
| 1302 | + * @throws InvalidInterfaceException |
|
| 1303 | + * @throws ReflectionException |
|
| 1304 | + */ |
|
| 1305 | + public function recalculate_pre_tax_total(): float |
|
| 1306 | + { |
|
| 1307 | + $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this); |
|
| 1308 | + [$total] = $this->calculator->recalculateLineItemTotals($grand_total_line_item); |
|
| 1309 | + return $total; |
|
| 1310 | + } |
|
| 1311 | + |
|
| 1312 | + |
|
| 1313 | + /** |
|
| 1314 | + * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets |
|
| 1315 | + * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items |
|
| 1316 | + * and tax sub-total if already in the DB |
|
| 1317 | + * |
|
| 1318 | + * @return float |
|
| 1319 | + * @throws EE_Error |
|
| 1320 | + * @throws InvalidArgumentException |
|
| 1321 | + * @throws InvalidDataTypeException |
|
| 1322 | + * @throws InvalidInterfaceException |
|
| 1323 | + * @throws ReflectionException |
|
| 1324 | + */ |
|
| 1325 | + public function recalculate_taxes_and_tax_total(): float |
|
| 1326 | + { |
|
| 1327 | + $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this); |
|
| 1328 | + return $this->calculator->recalculateTaxesAndTaxTotal($grand_total_line_item); |
|
| 1329 | + } |
|
| 1330 | + |
|
| 1331 | + |
|
| 1332 | + /** |
|
| 1333 | + * Gets the total tax on this line item. Assumes taxes have already been calculated using |
|
| 1334 | + * recalculate_taxes_and_total |
|
| 1335 | + * |
|
| 1336 | + * @return float |
|
| 1337 | + * @throws EE_Error |
|
| 1338 | + * @throws InvalidArgumentException |
|
| 1339 | + * @throws InvalidDataTypeException |
|
| 1340 | + * @throws InvalidInterfaceException |
|
| 1341 | + * @throws ReflectionException |
|
| 1342 | + */ |
|
| 1343 | + public function get_total_tax() |
|
| 1344 | + { |
|
| 1345 | + $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this); |
|
| 1346 | + return $this->calculator->recalculateTaxesAndTaxTotal($grand_total_line_item); |
|
| 1347 | + } |
|
| 1348 | + |
|
| 1349 | + |
|
| 1350 | + /** |
|
| 1351 | + * Gets the total for all the items purchased only |
|
| 1352 | + * |
|
| 1353 | + * @return float |
|
| 1354 | + * @throws EE_Error |
|
| 1355 | + * @throws InvalidArgumentException |
|
| 1356 | + * @throws InvalidDataTypeException |
|
| 1357 | + * @throws InvalidInterfaceException |
|
| 1358 | + * @throws ReflectionException |
|
| 1359 | + */ |
|
| 1360 | + public function get_items_total() |
|
| 1361 | + { |
|
| 1362 | + // by default, let's make sure we're consistent with the existing line item |
|
| 1363 | + if ($this->is_total()) { |
|
| 1364 | + return $this->pretaxTotal(); |
|
| 1365 | + } |
|
| 1366 | + $total = 0; |
|
| 1367 | + foreach ($this->get_items() as $item) { |
|
| 1368 | + if ($item instanceof EE_Line_Item) { |
|
| 1369 | + $total += $item->pretaxTotal(); |
|
| 1370 | + } |
|
| 1371 | + } |
|
| 1372 | + return $total; |
|
| 1373 | + } |
|
| 1374 | + |
|
| 1375 | + |
|
| 1376 | + /** |
|
| 1377 | + * Gets all the descendants (ie, children or children of children etc) that |
|
| 1378 | + * are of the type 'tax' |
|
| 1379 | + * |
|
| 1380 | + * @return EE_Line_Item[] |
|
| 1381 | + * @throws EE_Error |
|
| 1382 | + */ |
|
| 1383 | + public function tax_descendants() |
|
| 1384 | + { |
|
| 1385 | + return EEH_Line_Item::get_tax_descendants($this); |
|
| 1386 | + } |
|
| 1387 | + |
|
| 1388 | + |
|
| 1389 | + /** |
|
| 1390 | + * Gets all the real items purchased which are children of this item |
|
| 1391 | + * |
|
| 1392 | + * @return EE_Line_Item[] |
|
| 1393 | + * @throws EE_Error |
|
| 1394 | + */ |
|
| 1395 | + public function get_items() |
|
| 1396 | + { |
|
| 1397 | + return EEH_Line_Item::get_line_item_descendants($this); |
|
| 1398 | + } |
|
| 1399 | + |
|
| 1400 | + |
|
| 1401 | + /** |
|
| 1402 | + * Returns the amount taxable among this line item's children (or if it has no children, |
|
| 1403 | + * how much of it is taxable). Does not recalculate totals or subtotals. |
|
| 1404 | + * If the taxable total is negative, (eg, if none of the tickets were taxable, |
|
| 1405 | + * but there is a "Taxable" discount), returns 0. |
|
| 1406 | + * |
|
| 1407 | + * @return float |
|
| 1408 | + * @throws EE_Error |
|
| 1409 | + * @throws InvalidArgumentException |
|
| 1410 | + * @throws InvalidDataTypeException |
|
| 1411 | + * @throws InvalidInterfaceException |
|
| 1412 | + * @throws ReflectionException |
|
| 1413 | + */ |
|
| 1414 | + public function taxable_total(): float |
|
| 1415 | + { |
|
| 1416 | + return $this->calculator->taxableAmountForGlobalTaxes($this); |
|
| 1417 | + } |
|
| 1418 | + |
|
| 1419 | + |
|
| 1420 | + /** |
|
| 1421 | + * Gets the transaction for this line item |
|
| 1422 | + * |
|
| 1423 | + * @return EE_Base_Class|EE_Transaction |
|
| 1424 | + * @throws EE_Error |
|
| 1425 | + * @throws InvalidArgumentException |
|
| 1426 | + * @throws InvalidDataTypeException |
|
| 1427 | + * @throws InvalidInterfaceException |
|
| 1428 | + * @throws ReflectionException |
|
| 1429 | + */ |
|
| 1430 | + public function transaction() |
|
| 1431 | + { |
|
| 1432 | + return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TRANSACTION); |
|
| 1433 | + } |
|
| 1434 | + |
|
| 1435 | + |
|
| 1436 | + /** |
|
| 1437 | + * Saves this line item to the DB, and recursively saves its descendants. |
|
| 1438 | + * Because there currently is no proper parent-child relation on the model, |
|
| 1439 | + * save_this_and_cached() will NOT save the descendants. |
|
| 1440 | + * Also sets the transaction on this line item and all its descendants before saving |
|
| 1441 | + * |
|
| 1442 | + * @param int $txn_id if none is provided, assumes $this->TXN_ID() |
|
| 1443 | + * @return int count of items saved |
|
| 1444 | + * @throws EE_Error |
|
| 1445 | + * @throws InvalidArgumentException |
|
| 1446 | + * @throws InvalidDataTypeException |
|
| 1447 | + * @throws InvalidInterfaceException |
|
| 1448 | + * @throws ReflectionException |
|
| 1449 | + */ |
|
| 1450 | + public function save_this_and_descendants_to_txn($txn_id = null) |
|
| 1451 | + { |
|
| 1452 | + $count = 0; |
|
| 1453 | + if (! $txn_id) { |
|
| 1454 | + $txn_id = $this->TXN_ID(); |
|
| 1455 | + } |
|
| 1456 | + $this->set_TXN_ID($txn_id); |
|
| 1457 | + $children = $this->children(); |
|
| 1458 | + $count += $this->save() |
|
| 1459 | + ? 1 |
|
| 1460 | + : 0; |
|
| 1461 | + foreach ($children as $child_line_item) { |
|
| 1462 | + if ($child_line_item instanceof EE_Line_Item) { |
|
| 1463 | + $child_line_item->set_parent_ID($this->ID()); |
|
| 1464 | + $count += $child_line_item->save_this_and_descendants_to_txn($txn_id); |
|
| 1465 | + } |
|
| 1466 | + } |
|
| 1467 | + return $count; |
|
| 1468 | + } |
|
| 1469 | + |
|
| 1470 | + |
|
| 1471 | + /** |
|
| 1472 | + * Saves this line item to the DB, and recursively saves its descendants. |
|
| 1473 | + * |
|
| 1474 | + * @return int count of items saved |
|
| 1475 | + * @throws EE_Error |
|
| 1476 | + * @throws InvalidArgumentException |
|
| 1477 | + * @throws InvalidDataTypeException |
|
| 1478 | + * @throws InvalidInterfaceException |
|
| 1479 | + * @throws ReflectionException |
|
| 1480 | + */ |
|
| 1481 | + public function save_this_and_descendants() |
|
| 1482 | + { |
|
| 1483 | + $count = 0; |
|
| 1484 | + $children = $this->children(); |
|
| 1485 | + $count += $this->save() |
|
| 1486 | + ? 1 |
|
| 1487 | + : 0; |
|
| 1488 | + foreach ($children as $child_line_item) { |
|
| 1489 | + if ($child_line_item instanceof EE_Line_Item) { |
|
| 1490 | + $child_line_item->set_parent_ID($this->ID()); |
|
| 1491 | + $count += $child_line_item->save_this_and_descendants(); |
|
| 1492 | + } |
|
| 1493 | + } |
|
| 1494 | + return $count; |
|
| 1495 | + } |
|
| 1496 | + |
|
| 1497 | + |
|
| 1498 | + /** |
|
| 1499 | + * returns the cancellation line item if this item was cancelled |
|
| 1500 | + * |
|
| 1501 | + * @return EE_Line_Item[] |
|
| 1502 | + * @throws InvalidArgumentException |
|
| 1503 | + * @throws InvalidInterfaceException |
|
| 1504 | + * @throws InvalidDataTypeException |
|
| 1505 | + * @throws ReflectionException |
|
| 1506 | + * @throws EE_Error |
|
| 1507 | + */ |
|
| 1508 | + public function get_cancellations() |
|
| 1509 | + { |
|
| 1510 | + return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation); |
|
| 1511 | + } |
|
| 1512 | + |
|
| 1513 | + |
|
| 1514 | + /** |
|
| 1515 | + * If this item has an ID, then this saves it again to update the db |
|
| 1516 | + * |
|
| 1517 | + * @return int count of items saved |
|
| 1518 | + * @throws EE_Error |
|
| 1519 | + * @throws InvalidArgumentException |
|
| 1520 | + * @throws InvalidDataTypeException |
|
| 1521 | + * @throws InvalidInterfaceException |
|
| 1522 | + * @throws ReflectionException |
|
| 1523 | + */ |
|
| 1524 | + public function maybe_save() |
|
| 1525 | + { |
|
| 1526 | + if ($this->ID()) { |
|
| 1527 | + return $this->save(); |
|
| 1528 | + } |
|
| 1529 | + return false; |
|
| 1530 | + } |
|
| 1531 | + |
|
| 1532 | + |
|
| 1533 | + /** |
|
| 1534 | + * clears the cached children and parent from the line item |
|
| 1535 | + * |
|
| 1536 | + * @return void |
|
| 1537 | + */ |
|
| 1538 | + public function clear_related_line_item_cache() |
|
| 1539 | + { |
|
| 1540 | + $this->_children = array(); |
|
| 1541 | + $this->_parent = null; |
|
| 1542 | + } |
|
| 1543 | + |
|
| 1544 | + |
|
| 1545 | + /** |
|
| 1546 | + * @param bool $raw |
|
| 1547 | + * @return int |
|
| 1548 | + * @throws EE_Error |
|
| 1549 | + * @throws InvalidArgumentException |
|
| 1550 | + * @throws InvalidDataTypeException |
|
| 1551 | + * @throws InvalidInterfaceException |
|
| 1552 | + * @throws ReflectionException |
|
| 1553 | + */ |
|
| 1554 | + public function timestamp($raw = false) |
|
| 1555 | + { |
|
| 1556 | + return $raw |
|
| 1557 | + ? $this->get_raw('LIN_timestamp') |
|
| 1558 | + : $this->get('LIN_timestamp'); |
|
| 1559 | + } |
|
| 1560 | + |
|
| 1561 | + |
|
| 1562 | + |
|
| 1563 | + |
|
| 1564 | + /************************* DEPRECATED *************************/ |
|
| 1565 | + /** |
|
| 1566 | + * @deprecated 4.6.0 |
|
| 1567 | + * @param string $type one of the constants on EEM_Line_Item |
|
| 1568 | + * @return EE_Line_Item[] |
|
| 1569 | + * @throws EE_Error |
|
| 1570 | + */ |
|
| 1571 | + protected function _get_descendants_of_type($type) |
|
| 1572 | + { |
|
| 1573 | + EE_Error::doing_it_wrong( |
|
| 1574 | + 'EE_Line_Item::_get_descendants_of_type()', |
|
| 1575 | + sprintf( |
|
| 1576 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 1577 | + 'EEH_Line_Item::get_descendants_of_type()' |
|
| 1578 | + ), |
|
| 1579 | + '4.6.0' |
|
| 1580 | + ); |
|
| 1581 | + return EEH_Line_Item::get_descendants_of_type($this, $type); |
|
| 1582 | + } |
|
| 1583 | + |
|
| 1584 | + |
|
| 1585 | + /** |
|
| 1586 | + * @deprecated 4.6.0 |
|
| 1587 | + * @param string $type like one of the EEM_Line_Item::type_* |
|
| 1588 | + * @return EE_Line_Item |
|
| 1589 | + * @throws EE_Error |
|
| 1590 | + * @throws InvalidArgumentException |
|
| 1591 | + * @throws InvalidDataTypeException |
|
| 1592 | + * @throws InvalidInterfaceException |
|
| 1593 | + * @throws ReflectionException |
|
| 1594 | + */ |
|
| 1595 | + public function get_nearest_descendant_of_type($type) |
|
| 1596 | + { |
|
| 1597 | + EE_Error::doing_it_wrong( |
|
| 1598 | + 'EE_Line_Item::get_nearest_descendant_of_type()', |
|
| 1599 | + sprintf( |
|
| 1600 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 1601 | + 'EEH_Line_Item::get_nearest_descendant_of_type()' |
|
| 1602 | + ), |
|
| 1603 | + '4.6.0' |
|
| 1604 | + ); |
|
| 1605 | + return EEH_Line_Item::get_nearest_descendant_of_type($this, $type); |
|
| 1606 | + } |
|
| 1607 | 1607 | } |
@@ -96,7 +96,7 @@ discard block |
||
| 96 | 96 | { |
| 97 | 97 | $this->calculator = LoaderFactory::getShared(LineItemCalculator::class); |
| 98 | 98 | parent::__construct($fieldValues, $bydb, $timezone); |
| 99 | - if (! $this->get('LIN_code')) { |
|
| 99 | + if ( ! $this->get('LIN_code')) { |
|
| 100 | 100 | $this->set_code($this->generate_code()); |
| 101 | 101 | } |
| 102 | 102 | } |
@@ -163,7 +163,7 @@ discard block |
||
| 163 | 163 | public function name() |
| 164 | 164 | { |
| 165 | 165 | $name = $this->get('LIN_name'); |
| 166 | - if (! $name) { |
|
| 166 | + if ( ! $name) { |
|
| 167 | 167 | $name = ucwords(str_replace('-', ' ', $this->type())); |
| 168 | 168 | } |
| 169 | 169 | return $name; |
@@ -655,7 +655,7 @@ discard block |
||
| 655 | 655 | $query_params += ['order_by' => ['LIN_order' => 'ASC']]; |
| 656 | 656 | return $this->get_model()->get_all($query_params); |
| 657 | 657 | } |
| 658 | - if (! is_array($this->_children)) { |
|
| 658 | + if ( ! is_array($this->_children)) { |
|
| 659 | 659 | $this->_children = array(); |
| 660 | 660 | } |
| 661 | 661 | return $this->_children; |
@@ -896,7 +896,7 @@ discard block |
||
| 896 | 896 | } |
| 897 | 897 | return $line_item->save(); |
| 898 | 898 | } |
| 899 | - $this->_children[ $line_item->code() ] = $line_item; |
|
| 899 | + $this->_children[$line_item->code()] = $line_item; |
|
| 900 | 900 | if ($line_item->parent() !== $this) { |
| 901 | 901 | $line_item->set_parent($this); |
| 902 | 902 | } |
@@ -920,7 +920,7 @@ discard block |
||
| 920 | 920 | public function set_parent($line_item) |
| 921 | 921 | { |
| 922 | 922 | if ($this->ID()) { |
| 923 | - if (! $line_item->ID()) { |
|
| 923 | + if ( ! $line_item->ID()) { |
|
| 924 | 924 | $line_item->save(); |
| 925 | 925 | } |
| 926 | 926 | $this->set_parent_ID($line_item->ID()); |
@@ -952,8 +952,8 @@ discard block |
||
| 952 | 952 | array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code)) |
| 953 | 953 | ); |
| 954 | 954 | } |
| 955 | - return isset($this->_children[ $code ]) |
|
| 956 | - ? $this->_children[ $code ] |
|
| 955 | + return isset($this->_children[$code]) |
|
| 956 | + ? $this->_children[$code] |
|
| 957 | 957 | : null; |
| 958 | 958 | } |
| 959 | 959 | |
@@ -1013,8 +1013,8 @@ discard block |
||
| 1013 | 1013 | } |
| 1014 | 1014 | return $items_deleted; |
| 1015 | 1015 | } |
| 1016 | - if (isset($this->_children[ $code ])) { |
|
| 1017 | - unset($this->_children[ $code ]); |
|
| 1016 | + if (isset($this->_children[$code])) { |
|
| 1017 | + unset($this->_children[$code]); |
|
| 1018 | 1018 | return 1; |
| 1019 | 1019 | } |
| 1020 | 1020 | return 0; |
@@ -1055,7 +1055,7 @@ discard block |
||
| 1055 | 1055 | public function generate_code() |
| 1056 | 1056 | { |
| 1057 | 1057 | // each line item in the cart requires a unique identifier |
| 1058 | - return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime()); |
|
| 1058 | + return md5($this->get('OBJ_type').$this->get('OBJ_ID').microtime()); |
|
| 1059 | 1059 | } |
| 1060 | 1060 | |
| 1061 | 1061 | |
@@ -1099,7 +1099,7 @@ discard block |
||
| 1099 | 1099 | */ |
| 1100 | 1100 | public function getSubTaxes(): array |
| 1101 | 1101 | { |
| 1102 | - if (! $this->is_line_item()) { |
|
| 1102 | + if ( ! $this->is_line_item()) { |
|
| 1103 | 1103 | return []; |
| 1104 | 1104 | } |
| 1105 | 1105 | return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_sub_tax); |
@@ -1118,7 +1118,7 @@ discard block |
||
| 1118 | 1118 | */ |
| 1119 | 1119 | public function hasSubTaxes(): bool |
| 1120 | 1120 | { |
| 1121 | - if (! $this->is_line_item()) { |
|
| 1121 | + if ( ! $this->is_line_item()) { |
|
| 1122 | 1122 | return false; |
| 1123 | 1123 | } |
| 1124 | 1124 | $sub_taxes = $this->getSubTaxes(); |
@@ -1450,7 +1450,7 @@ discard block |
||
| 1450 | 1450 | public function save_this_and_descendants_to_txn($txn_id = null) |
| 1451 | 1451 | { |
| 1452 | 1452 | $count = 0; |
| 1453 | - if (! $txn_id) { |
|
| 1453 | + if ( ! $txn_id) { |
|
| 1454 | 1454 | $txn_id = $this->TXN_ID(); |
| 1455 | 1455 | } |
| 1456 | 1456 | $this->set_TXN_ID($txn_id); |
@@ -22,1067 +22,1067 @@ |
||
| 22 | 22 | class EE_Dependency_Map |
| 23 | 23 | { |
| 24 | 24 | |
| 25 | - /** |
|
| 26 | - * This means that the requested class dependency is not present in the dependency map |
|
| 27 | - */ |
|
| 28 | - const not_registered = 0; |
|
| 29 | - |
|
| 30 | - /** |
|
| 31 | - * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class. |
|
| 32 | - */ |
|
| 33 | - const load_new_object = 1; |
|
| 34 | - |
|
| 35 | - /** |
|
| 36 | - * This instructs class loaders to return a previously instantiated and cached object for the requested class. |
|
| 37 | - * IF a previously instantiated object does not exist, a new one will be created and added to the cache. |
|
| 38 | - */ |
|
| 39 | - const load_from_cache = 2; |
|
| 40 | - |
|
| 41 | - /** |
|
| 42 | - * When registering a dependency, |
|
| 43 | - * this indicates to keep any existing dependencies that already exist, |
|
| 44 | - * and simply discard any new dependencies declared in the incoming data |
|
| 45 | - */ |
|
| 46 | - const KEEP_EXISTING_DEPENDENCIES = 0; |
|
| 47 | - |
|
| 48 | - /** |
|
| 49 | - * When registering a dependency, |
|
| 50 | - * this indicates to overwrite any existing dependencies that already exist using the incoming data |
|
| 51 | - */ |
|
| 52 | - const OVERWRITE_DEPENDENCIES = 1; |
|
| 53 | - |
|
| 54 | - /** |
|
| 55 | - * @type EE_Dependency_Map $_instance |
|
| 56 | - */ |
|
| 57 | - protected static $_instance; |
|
| 58 | - |
|
| 59 | - /** |
|
| 60 | - * @var ClassInterfaceCache $class_cache |
|
| 61 | - */ |
|
| 62 | - private $class_cache; |
|
| 63 | - |
|
| 64 | - /** |
|
| 65 | - * @type RequestInterface $request |
|
| 66 | - */ |
|
| 67 | - protected $request; |
|
| 68 | - |
|
| 69 | - /** |
|
| 70 | - * @type LegacyRequestInterface $legacy_request |
|
| 71 | - */ |
|
| 72 | - protected $legacy_request; |
|
| 73 | - |
|
| 74 | - /** |
|
| 75 | - * @type ResponseInterface $response |
|
| 76 | - */ |
|
| 77 | - protected $response; |
|
| 78 | - |
|
| 79 | - /** |
|
| 80 | - * @type LoaderInterface $loader |
|
| 81 | - */ |
|
| 82 | - protected $loader; |
|
| 83 | - |
|
| 84 | - /** |
|
| 85 | - * @type array $_dependency_map |
|
| 86 | - */ |
|
| 87 | - protected $_dependency_map = []; |
|
| 88 | - |
|
| 89 | - /** |
|
| 90 | - * @type array $_class_loaders |
|
| 91 | - */ |
|
| 92 | - protected $_class_loaders = []; |
|
| 93 | - |
|
| 94 | - |
|
| 95 | - /** |
|
| 96 | - * EE_Dependency_Map constructor. |
|
| 97 | - * |
|
| 98 | - * @param ClassInterfaceCache $class_cache |
|
| 99 | - */ |
|
| 100 | - protected function __construct(ClassInterfaceCache $class_cache) |
|
| 101 | - { |
|
| 102 | - $this->class_cache = $class_cache; |
|
| 103 | - do_action('EE_Dependency_Map____construct', $this); |
|
| 104 | - } |
|
| 105 | - |
|
| 106 | - |
|
| 107 | - /** |
|
| 108 | - * @return void |
|
| 109 | - * @throws InvalidAliasException |
|
| 110 | - */ |
|
| 111 | - public function initialize() |
|
| 112 | - { |
|
| 113 | - $this->_register_core_dependencies(); |
|
| 114 | - $this->_register_core_class_loaders(); |
|
| 115 | - $this->_register_core_aliases(); |
|
| 116 | - } |
|
| 117 | - |
|
| 118 | - |
|
| 119 | - /** |
|
| 120 | - * @singleton method used to instantiate class object |
|
| 121 | - * @param ClassInterfaceCache|null $class_cache |
|
| 122 | - * @return EE_Dependency_Map |
|
| 123 | - */ |
|
| 124 | - public static function instance(ClassInterfaceCache $class_cache = null) |
|
| 125 | - { |
|
| 126 | - // check if class object is instantiated, and instantiated properly |
|
| 127 | - if ( |
|
| 128 | - ! EE_Dependency_Map::$_instance instanceof EE_Dependency_Map |
|
| 129 | - && $class_cache instanceof ClassInterfaceCache |
|
| 130 | - ) { |
|
| 131 | - EE_Dependency_Map::$_instance = new EE_Dependency_Map($class_cache); |
|
| 132 | - } |
|
| 133 | - return EE_Dependency_Map::$_instance; |
|
| 134 | - } |
|
| 135 | - |
|
| 136 | - |
|
| 137 | - /** |
|
| 138 | - * @param RequestInterface $request |
|
| 139 | - */ |
|
| 140 | - public function setRequest(RequestInterface $request) |
|
| 141 | - { |
|
| 142 | - $this->request = $request; |
|
| 143 | - } |
|
| 144 | - |
|
| 145 | - |
|
| 146 | - /** |
|
| 147 | - * @param LegacyRequestInterface $legacy_request |
|
| 148 | - */ |
|
| 149 | - public function setLegacyRequest(LegacyRequestInterface $legacy_request) |
|
| 150 | - { |
|
| 151 | - $this->legacy_request = $legacy_request; |
|
| 152 | - } |
|
| 153 | - |
|
| 154 | - |
|
| 155 | - /** |
|
| 156 | - * @param ResponseInterface $response |
|
| 157 | - */ |
|
| 158 | - public function setResponse(ResponseInterface $response) |
|
| 159 | - { |
|
| 160 | - $this->response = $response; |
|
| 161 | - } |
|
| 162 | - |
|
| 163 | - |
|
| 164 | - /** |
|
| 165 | - * @param LoaderInterface $loader |
|
| 166 | - */ |
|
| 167 | - public function setLoader(LoaderInterface $loader) |
|
| 168 | - { |
|
| 169 | - $this->loader = $loader; |
|
| 170 | - } |
|
| 171 | - |
|
| 172 | - |
|
| 173 | - /** |
|
| 174 | - * @param string $class |
|
| 175 | - * @param array $dependencies |
|
| 176 | - * @param int $overwrite |
|
| 177 | - * @return bool |
|
| 178 | - */ |
|
| 179 | - public static function register_dependencies( |
|
| 180 | - $class, |
|
| 181 | - array $dependencies, |
|
| 182 | - $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES |
|
| 183 | - ) { |
|
| 184 | - return EE_Dependency_Map::$_instance->registerDependencies($class, $dependencies, $overwrite); |
|
| 185 | - } |
|
| 186 | - |
|
| 187 | - |
|
| 188 | - /** |
|
| 189 | - * Assigns an array of class names and corresponding load sources (new or cached) |
|
| 190 | - * to the class specified by the first parameter. |
|
| 191 | - * IMPORTANT !!! |
|
| 192 | - * The order of elements in the incoming $dependencies array MUST match |
|
| 193 | - * the order of the constructor parameters for the class in question. |
|
| 194 | - * This is especially important when overriding any existing dependencies that are registered. |
|
| 195 | - * the third parameter controls whether any duplicate dependencies are overwritten or not. |
|
| 196 | - * |
|
| 197 | - * @param string $class |
|
| 198 | - * @param array $dependencies |
|
| 199 | - * @param int $overwrite |
|
| 200 | - * @return bool |
|
| 201 | - */ |
|
| 202 | - public function registerDependencies( |
|
| 203 | - $class, |
|
| 204 | - array $dependencies, |
|
| 205 | - $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES |
|
| 206 | - ) { |
|
| 207 | - $class = trim($class, '\\'); |
|
| 208 | - $registered = false; |
|
| 209 | - if (empty(EE_Dependency_Map::$_instance->_dependency_map[ $class ])) { |
|
| 210 | - EE_Dependency_Map::$_instance->_dependency_map[ $class ] = []; |
|
| 211 | - } |
|
| 212 | - // we need to make sure that any aliases used when registering a dependency |
|
| 213 | - // get resolved to the correct class name |
|
| 214 | - foreach ($dependencies as $dependency => $load_source) { |
|
| 215 | - $alias = EE_Dependency_Map::$_instance->getFqnForAlias($dependency); |
|
| 216 | - if ( |
|
| 217 | - $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES |
|
| 218 | - || ! isset(EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $alias ]) |
|
| 219 | - ) { |
|
| 220 | - unset($dependencies[ $dependency ]); |
|
| 221 | - $dependencies[ $alias ] = $load_source; |
|
| 222 | - $registered = true; |
|
| 223 | - } |
|
| 224 | - } |
|
| 225 | - // now add our two lists of dependencies together. |
|
| 226 | - // using Union (+=) favours the arrays in precedence from left to right, |
|
| 227 | - // so $dependencies is NOT overwritten because it is listed first |
|
| 228 | - // ie: with A = B + C, entries in B take precedence over duplicate entries in C |
|
| 229 | - // Union is way faster than array_merge() but should be used with caution... |
|
| 230 | - // especially with numerically indexed arrays |
|
| 231 | - $dependencies += EE_Dependency_Map::$_instance->_dependency_map[ $class ]; |
|
| 232 | - // now we need to ensure that the resulting dependencies |
|
| 233 | - // array only has the entries that are required for the class |
|
| 234 | - // so first count how many dependencies were originally registered for the class |
|
| 235 | - $dependency_count = count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]); |
|
| 236 | - // if that count is non-zero (meaning dependencies were already registered) |
|
| 237 | - EE_Dependency_Map::$_instance->_dependency_map[ $class ] = $dependency_count |
|
| 238 | - // then truncate the final array to match that count |
|
| 239 | - ? array_slice($dependencies, 0, $dependency_count) |
|
| 240 | - // otherwise just take the incoming array because nothing previously existed |
|
| 241 | - : $dependencies; |
|
| 242 | - return $registered; |
|
| 243 | - } |
|
| 244 | - |
|
| 245 | - |
|
| 246 | - /** |
|
| 247 | - * @param string $class_name |
|
| 248 | - * @param string $loader |
|
| 249 | - * @return bool |
|
| 250 | - * @throws DomainException |
|
| 251 | - */ |
|
| 252 | - public static function register_class_loader($class_name, $loader = 'load_core') |
|
| 253 | - { |
|
| 254 | - return EE_Dependency_Map::$_instance->registerClassLoader($class_name, $loader); |
|
| 255 | - } |
|
| 256 | - |
|
| 257 | - |
|
| 258 | - /** |
|
| 259 | - * @param string $class_name |
|
| 260 | - * @param string $loader |
|
| 261 | - * @return bool |
|
| 262 | - * @throws DomainException |
|
| 263 | - */ |
|
| 264 | - public function registerClassLoader($class_name, $loader = 'load_core') |
|
| 265 | - { |
|
| 266 | - if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) { |
|
| 267 | - throw new DomainException( |
|
| 268 | - esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso') |
|
| 269 | - ); |
|
| 270 | - } |
|
| 271 | - // check that loader is callable or method starts with "load_" and exists in EE_Registry |
|
| 272 | - if ( |
|
| 273 | - ! is_callable($loader) |
|
| 274 | - && ( |
|
| 275 | - strpos($loader, 'load_') !== 0 |
|
| 276 | - || ! method_exists('EE_Registry', $loader) |
|
| 277 | - ) |
|
| 278 | - ) { |
|
| 279 | - throw new DomainException( |
|
| 280 | - sprintf( |
|
| 281 | - esc_html__( |
|
| 282 | - '"%1$s" is not a valid loader method on EE_Registry.', |
|
| 283 | - 'event_espresso' |
|
| 284 | - ), |
|
| 285 | - $loader |
|
| 286 | - ) |
|
| 287 | - ); |
|
| 288 | - } |
|
| 289 | - $class_name = EE_Dependency_Map::$_instance->getFqnForAlias($class_name); |
|
| 290 | - if (! isset(EE_Dependency_Map::$_instance->_class_loaders[ $class_name ])) { |
|
| 291 | - EE_Dependency_Map::$_instance->_class_loaders[ $class_name ] = $loader; |
|
| 292 | - return true; |
|
| 293 | - } |
|
| 294 | - return false; |
|
| 295 | - } |
|
| 296 | - |
|
| 297 | - |
|
| 298 | - /** |
|
| 299 | - * @return array |
|
| 300 | - */ |
|
| 301 | - public function dependency_map() |
|
| 302 | - { |
|
| 303 | - return $this->_dependency_map; |
|
| 304 | - } |
|
| 305 | - |
|
| 306 | - |
|
| 307 | - /** |
|
| 308 | - * returns TRUE if dependency map contains a listing for the provided class name |
|
| 309 | - * |
|
| 310 | - * @param string $class_name |
|
| 311 | - * @return boolean |
|
| 312 | - */ |
|
| 313 | - public function has($class_name = '') |
|
| 314 | - { |
|
| 315 | - // all legacy models have the same dependencies |
|
| 316 | - if (strpos($class_name, 'EEM_') === 0) { |
|
| 317 | - $class_name = 'LEGACY_MODELS'; |
|
| 318 | - } |
|
| 319 | - return isset($this->_dependency_map[ $class_name ]); |
|
| 320 | - } |
|
| 321 | - |
|
| 322 | - |
|
| 323 | - /** |
|
| 324 | - * returns TRUE if dependency map contains a listing for the provided class name AND dependency |
|
| 325 | - * |
|
| 326 | - * @param string $class_name |
|
| 327 | - * @param string $dependency |
|
| 328 | - * @return bool |
|
| 329 | - */ |
|
| 330 | - public function has_dependency_for_class($class_name = '', $dependency = '') |
|
| 331 | - { |
|
| 332 | - // all legacy models have the same dependencies |
|
| 333 | - if (strpos($class_name, 'EEM_') === 0) { |
|
| 334 | - $class_name = 'LEGACY_MODELS'; |
|
| 335 | - } |
|
| 336 | - $dependency = $this->getFqnForAlias($dependency, $class_name); |
|
| 337 | - return isset($this->_dependency_map[ $class_name ][ $dependency ]); |
|
| 338 | - } |
|
| 339 | - |
|
| 340 | - |
|
| 341 | - /** |
|
| 342 | - * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned |
|
| 343 | - * |
|
| 344 | - * @param string $class_name |
|
| 345 | - * @param string $dependency |
|
| 346 | - * @return int |
|
| 347 | - */ |
|
| 348 | - public function loading_strategy_for_class_dependency($class_name = '', $dependency = '') |
|
| 349 | - { |
|
| 350 | - // all legacy models have the same dependencies |
|
| 351 | - if (strpos($class_name, 'EEM_') === 0) { |
|
| 352 | - $class_name = 'LEGACY_MODELS'; |
|
| 353 | - } |
|
| 354 | - $dependency = $this->getFqnForAlias($dependency); |
|
| 355 | - return $this->has_dependency_for_class($class_name, $dependency) |
|
| 356 | - ? $this->_dependency_map[ $class_name ][ $dependency ] |
|
| 357 | - : EE_Dependency_Map::not_registered; |
|
| 358 | - } |
|
| 359 | - |
|
| 360 | - |
|
| 361 | - /** |
|
| 362 | - * @param string $class_name |
|
| 363 | - * @return string | Closure |
|
| 364 | - */ |
|
| 365 | - public function class_loader($class_name) |
|
| 366 | - { |
|
| 367 | - // all legacy models use load_model() |
|
| 368 | - if (strpos($class_name, 'EEM_') === 0) { |
|
| 369 | - return 'load_model'; |
|
| 370 | - } |
|
| 371 | - // EE_CPT_*_Strategy classes like EE_CPT_Event_Strategy, EE_CPT_Venue_Strategy, etc |
|
| 372 | - // perform strpos() first to avoid loading regex every time we load a class |
|
| 373 | - if ( |
|
| 374 | - strpos($class_name, 'EE_CPT_') === 0 |
|
| 375 | - && preg_match('/^EE_CPT_([a-zA-Z]+)_Strategy$/', $class_name) |
|
| 376 | - ) { |
|
| 377 | - return 'load_core'; |
|
| 378 | - } |
|
| 379 | - $class_name = $this->getFqnForAlias($class_name); |
|
| 380 | - return isset($this->_class_loaders[ $class_name ]) ? $this->_class_loaders[ $class_name ] : ''; |
|
| 381 | - } |
|
| 382 | - |
|
| 383 | - |
|
| 384 | - /** |
|
| 385 | - * @return array |
|
| 386 | - */ |
|
| 387 | - public function class_loaders() |
|
| 388 | - { |
|
| 389 | - return $this->_class_loaders; |
|
| 390 | - } |
|
| 391 | - |
|
| 392 | - |
|
| 393 | - /** |
|
| 394 | - * adds an alias for a classname |
|
| 395 | - * |
|
| 396 | - * @param string $fqcn the class name that should be used (concrete class to replace interface) |
|
| 397 | - * @param string $alias the class name that would be type hinted for (abstract parent or interface) |
|
| 398 | - * @param string $for_class the class that has the dependency (is type hinting for the interface) |
|
| 399 | - * @throws InvalidAliasException |
|
| 400 | - */ |
|
| 401 | - public function add_alias($fqcn, $alias, $for_class = '') |
|
| 402 | - { |
|
| 403 | - $this->class_cache->addAlias($fqcn, $alias, $for_class); |
|
| 404 | - } |
|
| 405 | - |
|
| 406 | - |
|
| 407 | - /** |
|
| 408 | - * Returns TRUE if the provided fully qualified name IS an alias |
|
| 409 | - * WHY? |
|
| 410 | - * Because if a class is type hinting for a concretion, |
|
| 411 | - * then why would we need to find another class to supply it? |
|
| 412 | - * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`, |
|
| 413 | - * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`. |
|
| 414 | - * Don't go looking for some substitute. |
|
| 415 | - * Whereas if a class is type hinting for an interface... |
|
| 416 | - * then we need to find an actual class to use. |
|
| 417 | - * So the interface IS the alias for some other FQN, |
|
| 418 | - * and we need to find out if `Fully/Qualified/Namespace/SomeInterface` |
|
| 419 | - * represents some other class. |
|
| 420 | - * |
|
| 421 | - * @param string $fqn |
|
| 422 | - * @param string $for_class |
|
| 423 | - * @return bool |
|
| 424 | - */ |
|
| 425 | - public function isAlias($fqn = '', $for_class = '') |
|
| 426 | - { |
|
| 427 | - return $this->class_cache->isAlias($fqn, $for_class); |
|
| 428 | - } |
|
| 429 | - |
|
| 430 | - |
|
| 431 | - /** |
|
| 432 | - * Returns a FQN for provided alias if one exists, otherwise returns the original $alias |
|
| 433 | - * functions recursively, so that multiple aliases can be used to drill down to a FQN |
|
| 434 | - * for example: |
|
| 435 | - * if the following two entries were added to the _aliases array: |
|
| 436 | - * array( |
|
| 437 | - * 'interface_alias' => 'some\namespace\interface' |
|
| 438 | - * 'some\namespace\interface' => 'some\namespace\classname' |
|
| 439 | - * ) |
|
| 440 | - * then one could use EE_Registry::instance()->create( 'interface_alias' ) |
|
| 441 | - * to load an instance of 'some\namespace\classname' |
|
| 442 | - * |
|
| 443 | - * @param string $alias |
|
| 444 | - * @param string $for_class |
|
| 445 | - * @return string |
|
| 446 | - */ |
|
| 447 | - public function getFqnForAlias($alias = '', $for_class = '') |
|
| 448 | - { |
|
| 449 | - return (string) $this->class_cache->getFqnForAlias($alias, $for_class); |
|
| 450 | - } |
|
| 451 | - |
|
| 452 | - |
|
| 453 | - /** |
|
| 454 | - * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache, |
|
| 455 | - * if one exists, or whether a new object should be generated every time the requested class is loaded. |
|
| 456 | - * This is done by using the following class constants: |
|
| 457 | - * EE_Dependency_Map::load_from_cache - loads previously instantiated object |
|
| 458 | - * EE_Dependency_Map::load_new_object - generates a new object every time |
|
| 459 | - */ |
|
| 460 | - protected function _register_core_dependencies() |
|
| 461 | - { |
|
| 462 | - $this->_dependency_map = [ |
|
| 463 | - 'EE_Request_Handler' => [ |
|
| 464 | - 'EE_Request' => EE_Dependency_Map::load_from_cache, |
|
| 465 | - ], |
|
| 466 | - 'EE_System' => [ |
|
| 467 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 468 | - 'EE_Maintenance_Mode' => EE_Dependency_Map::load_from_cache, |
|
| 469 | - 'EE_Registry' => EE_Dependency_Map::load_from_cache, |
|
| 470 | - 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 471 | - 'EventEspresso\core\services\routing\Router' => EE_Dependency_Map::load_from_cache, |
|
| 472 | - ], |
|
| 473 | - 'EE_Admin' => [ |
|
| 474 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 475 | - 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 476 | - ], |
|
| 477 | - 'EE_Cart' => [ |
|
| 478 | - 'EE_Session' => EE_Dependency_Map::load_from_cache, |
|
| 479 | - ], |
|
| 480 | - 'EE_Messenger_Collection_Loader' => [ |
|
| 481 | - 'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object, |
|
| 482 | - ], |
|
| 483 | - 'EE_Message_Type_Collection_Loader' => [ |
|
| 484 | - 'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object, |
|
| 485 | - ], |
|
| 486 | - 'EE_Message_Resource_Manager' => [ |
|
| 487 | - 'EE_Messenger_Collection_Loader' => EE_Dependency_Map::load_new_object, |
|
| 488 | - 'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object, |
|
| 489 | - 'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache, |
|
| 490 | - ], |
|
| 491 | - 'EE_Message_Factory' => [ |
|
| 492 | - 'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache, |
|
| 493 | - ], |
|
| 494 | - 'EE_messages' => [ |
|
| 495 | - 'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache, |
|
| 496 | - ], |
|
| 497 | - 'EE_Messages_Generator' => [ |
|
| 498 | - 'EE_Messages_Queue' => EE_Dependency_Map::load_new_object, |
|
| 499 | - 'EE_Messages_Data_Handler_Collection' => EE_Dependency_Map::load_new_object, |
|
| 500 | - 'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object, |
|
| 501 | - 'EEH_Parse_Shortcodes' => EE_Dependency_Map::load_from_cache, |
|
| 502 | - ], |
|
| 503 | - 'EE_Messages_Processor' => [ |
|
| 504 | - 'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache, |
|
| 505 | - ], |
|
| 506 | - 'EE_Messages_Queue' => [ |
|
| 507 | - 'EE_Message_Repository' => EE_Dependency_Map::load_new_object, |
|
| 508 | - ], |
|
| 509 | - 'EE_Messages_Template_Defaults' => [ |
|
| 510 | - 'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache, |
|
| 511 | - 'EEM_Message_Template' => EE_Dependency_Map::load_from_cache, |
|
| 512 | - ], |
|
| 513 | - 'EE_Message_To_Generate_From_Request' => [ |
|
| 514 | - 'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache, |
|
| 515 | - 'EE_Request_Handler' => EE_Dependency_Map::load_from_cache, |
|
| 516 | - ], |
|
| 517 | - 'EventEspresso\core\services\commands\CommandBus' => [ |
|
| 518 | - 'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache, |
|
| 519 | - ], |
|
| 520 | - 'EventEspresso\services\commands\CommandHandler' => [ |
|
| 521 | - 'EE_Registry' => EE_Dependency_Map::load_from_cache, |
|
| 522 | - 'CommandBusInterface' => EE_Dependency_Map::load_from_cache, |
|
| 523 | - ], |
|
| 524 | - 'EventEspresso\core\services\commands\CommandHandlerManager' => [ |
|
| 525 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 526 | - ], |
|
| 527 | - 'EventEspresso\core\services\commands\CompositeCommandHandler' => [ |
|
| 528 | - 'EventEspresso\core\services\commands\CommandBus' => EE_Dependency_Map::load_from_cache, |
|
| 529 | - 'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache, |
|
| 530 | - ], |
|
| 531 | - 'EventEspresso\core\services\commands\CommandFactory' => [ |
|
| 532 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 533 | - ], |
|
| 534 | - 'EventEspresso\core\services\commands\middleware\CapChecker' => [ |
|
| 535 | - 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache, |
|
| 536 | - ], |
|
| 537 | - 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => [ |
|
| 538 | - 'EE_Capabilities' => EE_Dependency_Map::load_from_cache, |
|
| 539 | - ], |
|
| 540 | - 'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker' => [ |
|
| 541 | - 'EE_Capabilities' => EE_Dependency_Map::load_from_cache, |
|
| 542 | - ], |
|
| 543 | - 'EventEspresso\core\services\commands\registration\CreateRegistrationCommandHandler' => [ |
|
| 544 | - 'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache, |
|
| 545 | - ], |
|
| 546 | - 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommandHandler' => [ |
|
| 547 | - 'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache, |
|
| 548 | - ], |
|
| 549 | - 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommandHandler' => [ |
|
| 550 | - 'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache, |
|
| 551 | - ], |
|
| 552 | - 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler' => [ |
|
| 553 | - 'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache, |
|
| 554 | - ], |
|
| 555 | - 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => [ |
|
| 556 | - 'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache, |
|
| 557 | - ], |
|
| 558 | - 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommandHandler' => [ |
|
| 559 | - 'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache, |
|
| 560 | - ], |
|
| 561 | - 'EventEspresso\core\services\commands\ticket\CancelTicketLineItemCommandHandler' => [ |
|
| 562 | - 'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache, |
|
| 563 | - ], |
|
| 564 | - 'EventEspresso\core\domain\services\registration\CancelRegistrationService' => [ |
|
| 565 | - 'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache, |
|
| 566 | - ], |
|
| 567 | - 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler' => [ |
|
| 568 | - 'EEM_Attendee' => EE_Dependency_Map::load_from_cache, |
|
| 569 | - ], |
|
| 570 | - 'EventEspresso\core\services\database\TableManager' => [ |
|
| 571 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 572 | - ], |
|
| 573 | - 'EE_Data_Migration_Class_Base' => [ |
|
| 574 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 575 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 576 | - ], |
|
| 577 | - 'EE_DMS_Core_4_1_0' => [ |
|
| 578 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 579 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 580 | - ], |
|
| 581 | - 'EE_DMS_Core_4_2_0' => [ |
|
| 582 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 583 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 584 | - ], |
|
| 585 | - 'EE_DMS_Core_4_3_0' => [ |
|
| 586 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 587 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 588 | - ], |
|
| 589 | - 'EE_DMS_Core_4_4_0' => [ |
|
| 590 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 591 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 592 | - ], |
|
| 593 | - 'EE_DMS_Core_4_5_0' => [ |
|
| 594 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 595 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 596 | - ], |
|
| 597 | - 'EE_DMS_Core_4_6_0' => [ |
|
| 598 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 599 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 600 | - ], |
|
| 601 | - 'EE_DMS_Core_4_7_0' => [ |
|
| 602 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 603 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 604 | - ], |
|
| 605 | - 'EE_DMS_Core_4_8_0' => [ |
|
| 606 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 607 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 608 | - ], |
|
| 609 | - 'EE_DMS_Core_4_9_0' => [ |
|
| 610 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 611 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 612 | - ], |
|
| 613 | - 'EE_DMS_Core_4_10_0' => [ |
|
| 614 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 615 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 616 | - 'EE_DMS_Core_4_9_0' => EE_Dependency_Map::load_from_cache, |
|
| 617 | - ], |
|
| 618 | - 'EE_DMS_Core_4_11_0' => [ |
|
| 619 | - 'EE_DMS_Core_4_10_0' => EE_Dependency_Map::load_from_cache, |
|
| 620 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 621 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 622 | - ], |
|
| 623 | - 'EE_DMS_Core_4_12_0' => [ |
|
| 624 | - 'EE_DMS_Core_4_11_0' => EE_Dependency_Map::load_from_cache, |
|
| 625 | - 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 626 | - 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 627 | - ], |
|
| 628 | - 'EventEspresso\core\services\assets\Registry' => [ |
|
| 629 | - 'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_new_object, |
|
| 630 | - 'EventEspresso\core\services\assets\AssetManifest' => EE_Dependency_Map::load_from_cache, |
|
| 631 | - ], |
|
| 632 | - 'EventEspresso\core\services\cache\BasicCacheManager' => [ |
|
| 633 | - 'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache, |
|
| 634 | - ], |
|
| 635 | - 'EventEspresso\core\services\cache\PostRelatedCacheManager' => [ |
|
| 636 | - 'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache, |
|
| 637 | - ], |
|
| 638 | - 'EventEspresso\core\domain\services\validation\email\EmailValidationService' => [ |
|
| 639 | - 'EE_Registration_Config' => EE_Dependency_Map::load_from_cache, |
|
| 640 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 641 | - ], |
|
| 642 | - 'EventEspresso\core\domain\values\EmailAddress' => [ |
|
| 643 | - null, |
|
| 644 | - 'EventEspresso\core\domain\services\validation\email\EmailValidationService' => EE_Dependency_Map::load_from_cache, |
|
| 645 | - ], |
|
| 646 | - 'EventEspresso\core\services\orm\ModelFieldFactory' => [ |
|
| 647 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 648 | - ], |
|
| 649 | - 'LEGACY_MODELS' => [ |
|
| 650 | - null, |
|
| 651 | - 'EventEspresso\core\services\database\ModelFieldFactory' => EE_Dependency_Map::load_from_cache, |
|
| 652 | - ], |
|
| 653 | - 'EE_Module_Request_Router' => [ |
|
| 654 | - 'EE_Request' => EE_Dependency_Map::load_from_cache, |
|
| 655 | - ], |
|
| 656 | - 'EE_Registration_Processor' => [ |
|
| 657 | - 'EE_Request' => EE_Dependency_Map::load_from_cache, |
|
| 658 | - ], |
|
| 659 | - 'EventEspresso\core\services\notifications\PersistentAdminNoticeManager' => [ |
|
| 660 | - null, |
|
| 661 | - 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache, |
|
| 662 | - 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 663 | - ], |
|
| 664 | - 'EventEspresso\caffeinated\modules\recaptcha_invisible\InvisibleRecaptcha' => [ |
|
| 665 | - 'EE_Registration_Config' => EE_Dependency_Map::load_from_cache, |
|
| 666 | - 'EE_Session' => EE_Dependency_Map::load_from_cache, |
|
| 667 | - ], |
|
| 668 | - 'EventEspresso\modules\ticket_selector\DisplayTicketSelector' => [ |
|
| 669 | - 'EventEspresso\core\domain\entities\users\CurrentUser' => EE_Dependency_Map::load_from_cache, |
|
| 670 | - ], |
|
| 671 | - 'EventEspresso\modules\ticket_selector\ProcessTicketSelector' => [ |
|
| 672 | - 'EE_Core_Config' => EE_Dependency_Map::load_from_cache, |
|
| 673 | - 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 674 | - 'EE_Session' => EE_Dependency_Map::load_from_cache, |
|
| 675 | - 'EEM_Ticket' => EE_Dependency_Map::load_from_cache, |
|
| 676 | - 'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker' => EE_Dependency_Map::load_from_cache, |
|
| 677 | - ], |
|
| 678 | - 'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker' => [ |
|
| 679 | - 'EEM_Datetime' => EE_Dependency_Map::load_from_cache, |
|
| 680 | - ], |
|
| 681 | - 'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => [ |
|
| 682 | - 'EE_Core_Config' => EE_Dependency_Map::load_from_cache, |
|
| 683 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 684 | - ], |
|
| 685 | - 'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes' => [ |
|
| 686 | - 'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache, |
|
| 687 | - ], |
|
| 688 | - 'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies' => [ |
|
| 689 | - 'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache, |
|
| 690 | - ], |
|
| 691 | - 'EE_CPT_Strategy' => [ |
|
| 692 | - 'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache, |
|
| 693 | - 'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache, |
|
| 694 | - ], |
|
| 695 | - 'EventEspresso\core\services\loaders\ObjectIdentifier' => [ |
|
| 696 | - 'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache, |
|
| 697 | - ], |
|
| 698 | - 'EventEspresso\core\CPTs\CptQueryModifier' => [ |
|
| 699 | - null, |
|
| 700 | - null, |
|
| 701 | - null, |
|
| 702 | - 'EE_Request_Handler' => EE_Dependency_Map::load_from_cache, |
|
| 703 | - 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 704 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 705 | - ], |
|
| 706 | - 'EventEspresso\core\services\dependencies\DependencyResolver' => [ |
|
| 707 | - 'EventEspresso\core\services\container\Mirror' => EE_Dependency_Map::load_from_cache, |
|
| 708 | - 'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache, |
|
| 709 | - 'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache, |
|
| 710 | - ], |
|
| 711 | - 'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver' => [ |
|
| 712 | - 'EventEspresso\core\services\container\Mirror' => EE_Dependency_Map::load_from_cache, |
|
| 713 | - 'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache, |
|
| 714 | - 'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache, |
|
| 715 | - ], |
|
| 716 | - 'EventEspresso\core\services\routing\RouteMatchSpecificationFactory' => [ |
|
| 717 | - 'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver' => EE_Dependency_Map::load_from_cache, |
|
| 718 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 719 | - ], |
|
| 720 | - 'EventEspresso\core\services\routing\RouteMatchSpecificationManager' => [ |
|
| 721 | - 'EventEspresso\core\services\routing\RouteMatchSpecificationCollection' => EE_Dependency_Map::load_from_cache, |
|
| 722 | - 'EventEspresso\core\services\routing\RouteMatchSpecificationFactory' => EE_Dependency_Map::load_from_cache, |
|
| 723 | - ], |
|
| 724 | - 'EE_URL_Validation_Strategy' => [ |
|
| 725 | - null, |
|
| 726 | - null, |
|
| 727 | - 'EventEspresso\core\services\validators\URLValidator' => EE_Dependency_Map::load_from_cache, |
|
| 728 | - ], |
|
| 729 | - 'EventEspresso\core\services\request\files\FilesDataHandler' => [ |
|
| 730 | - 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 731 | - ], |
|
| 732 | - 'EventEspressoBatchRequest\BatchRequestProcessor' => [ |
|
| 733 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 734 | - ], |
|
| 735 | - 'EventEspresso\core\domain\services\converters\RestApiSpoofer' => [ |
|
| 736 | - 'WP_REST_Server' => EE_Dependency_Map::load_from_cache, |
|
| 737 | - 'EED_Core_Rest_Api' => EE_Dependency_Map::load_from_cache, |
|
| 738 | - 'EventEspresso\core\libraries\rest_api\controllers\model\Read' => EE_Dependency_Map::load_from_cache, |
|
| 739 | - null, |
|
| 740 | - ], |
|
| 741 | - 'EventEspresso\core\services\routing\RouteHandler' => [ |
|
| 742 | - 'EventEspresso\core\services\json\JsonDataNodeHandler' => EE_Dependency_Map::load_from_cache, |
|
| 743 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 744 | - 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 745 | - 'EventEspresso\core\services\routing\RouteCollection' => EE_Dependency_Map::load_from_cache, |
|
| 746 | - ], |
|
| 747 | - 'EventEspresso\core\services\json\JsonDataNodeHandler' => [ |
|
| 748 | - 'EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache, |
|
| 749 | - ], |
|
| 750 | - 'EventEspresso\core\services\routing\Router' => [ |
|
| 751 | - 'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache, |
|
| 752 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 753 | - 'EventEspresso\core\services\routing\RouteHandler' => EE_Dependency_Map::load_from_cache, |
|
| 754 | - ], |
|
| 755 | - 'EventEspresso\core\services\assets\AssetManifest' => [ |
|
| 756 | - 'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache, |
|
| 757 | - ], |
|
| 758 | - 'EventEspresso\core\services\assets\AssetManifestFactory' => [ |
|
| 759 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 760 | - ], |
|
| 761 | - 'EventEspresso\core\services\assets\BaristaFactory' => [ |
|
| 762 | - 'EventEspresso\core\services\assets\AssetManifestFactory' => EE_Dependency_Map::load_from_cache, |
|
| 763 | - 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 764 | - ], |
|
| 765 | - 'EventEspresso\core\domain\services\capabilities\FeatureFlags' => [ |
|
| 766 | - 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache, |
|
| 767 | - ], |
|
| 768 | - 'EventEspresso\core\services\addon\AddonManager' => [ |
|
| 769 | - 'EventEspresso\core\services\addon\AddonCollection' => EE_Dependency_Map::load_from_cache, |
|
| 770 | - 'EventEspresso\core\Psr4Autoloader' => EE_Dependency_Map::load_from_cache, |
|
| 771 | - 'EventEspresso\core\services\addon\api\v1\RegisterAddon' => EE_Dependency_Map::load_from_cache, |
|
| 772 | - 'EventEspresso\core\services\addon\api\IncompatibleAddonHandler' => EE_Dependency_Map::load_from_cache, |
|
| 773 | - 'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler' => EE_Dependency_Map::load_from_cache, |
|
| 774 | - ], |
|
| 775 | - 'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler' => [ |
|
| 776 | - 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 777 | - ], |
|
| 778 | - 'EventEspressoBatchRequest\JobHandlers\ExecuteBatchDeletion' => [ |
|
| 779 | - 'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache |
|
| 780 | - ], |
|
| 781 | - 'EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion' => [ |
|
| 782 | - 'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache |
|
| 783 | - ], |
|
| 784 | - 'EventEspresso\core\domain\services\admin\events\data\PreviewDeletion' => [ |
|
| 785 | - 'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache, |
|
| 786 | - 'EEM_Event' => EE_Dependency_Map::load_from_cache, |
|
| 787 | - 'EEM_Datetime' => EE_Dependency_Map::load_from_cache, |
|
| 788 | - 'EEM_Registration' => EE_Dependency_Map::load_from_cache |
|
| 789 | - ], |
|
| 790 | - 'EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion' => [ |
|
| 791 | - 'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache, |
|
| 792 | - ], |
|
| 793 | - 'EventEspresso\core\domain\entities\users\CurrentUser' => [ |
|
| 794 | - 'EventEspresso\core\domain\entities\users\EventManagers' => EE_Dependency_Map::load_from_cache, |
|
| 795 | - ], |
|
| 796 | - 'EventEspresso\core\services\form\meta\InputTypes' => [ |
|
| 797 | - 'EventEspresso\core\services\form\meta\inputs\Block' => EE_Dependency_Map::load_from_cache, |
|
| 798 | - 'EventEspresso\core\services\form\meta\inputs\Button' => EE_Dependency_Map::load_from_cache, |
|
| 799 | - 'EventEspresso\core\services\form\meta\inputs\DateTime' => EE_Dependency_Map::load_from_cache, |
|
| 800 | - 'EventEspresso\core\services\form\meta\inputs\Input' => EE_Dependency_Map::load_from_cache, |
|
| 801 | - 'EventEspresso\core\services\form\meta\inputs\Number' => EE_Dependency_Map::load_from_cache, |
|
| 802 | - 'EventEspresso\core\services\form\meta\inputs\Phone' => EE_Dependency_Map::load_from_cache, |
|
| 803 | - 'EventEspresso\core\services\form\meta\inputs\Select' => EE_Dependency_Map::load_from_cache, |
|
| 804 | - 'EventEspresso\core\services\form\meta\inputs\Text' => EE_Dependency_Map::load_from_cache, |
|
| 805 | - ], |
|
| 806 | - 'EventEspresso\core\domain\services\registration\form\v1\RegFormDependencyHandler' => [ |
|
| 807 | - 'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache, |
|
| 808 | - ], |
|
| 809 | - 'EventEspresso\core\services\calculators\LineItemCalculator' => [ |
|
| 810 | - 'EventEspresso\core\services\helpers\DecimalValues' => EE_Dependency_Map::load_from_cache, |
|
| 811 | - ], |
|
| 812 | - 'EventEspresso\core\services\helpers\DecimalValues' => [ |
|
| 813 | - 'EE_Currency_Config' => EE_Dependency_Map::load_from_cache, |
|
| 814 | - ], |
|
| 815 | - ]; |
|
| 816 | - } |
|
| 817 | - |
|
| 818 | - |
|
| 819 | - /** |
|
| 820 | - * Registers how core classes are loaded. |
|
| 821 | - * This can either be done by simply providing the name of one of the EE_Registry loader methods such as: |
|
| 822 | - * 'EE_Request_Handler' => 'load_core' |
|
| 823 | - * 'EE_Messages_Queue' => 'load_lib' |
|
| 824 | - * 'EEH_Debug_Tools' => 'load_helper' |
|
| 825 | - * or, if greater control is required, by providing a custom closure. For example: |
|
| 826 | - * 'Some_Class' => function () { |
|
| 827 | - * return new Some_Class(); |
|
| 828 | - * }, |
|
| 829 | - * This is required for instantiating dependencies |
|
| 830 | - * where an interface has been type hinted in a class constructor. For example: |
|
| 831 | - * 'Required_Interface' => function () { |
|
| 832 | - * return new A_Class_That_Implements_Required_Interface(); |
|
| 833 | - * }, |
|
| 834 | - */ |
|
| 835 | - protected function _register_core_class_loaders() |
|
| 836 | - { |
|
| 837 | - $this->_class_loaders = [ |
|
| 838 | - // load_core |
|
| 839 | - 'EE_Dependency_Map' => function () { |
|
| 840 | - return $this; |
|
| 841 | - }, |
|
| 842 | - 'EE_Capabilities' => 'load_core', |
|
| 843 | - 'EE_Encryption' => 'load_core', |
|
| 844 | - 'EE_Front_Controller' => 'load_core', |
|
| 845 | - 'EE_Module_Request_Router' => 'load_core', |
|
| 846 | - 'EE_Registry' => 'load_core', |
|
| 847 | - 'EE_Request' => function () { |
|
| 848 | - return $this->legacy_request; |
|
| 849 | - }, |
|
| 850 | - 'EventEspresso\core\services\request\Request' => function () { |
|
| 851 | - return $this->request; |
|
| 852 | - }, |
|
| 853 | - 'EventEspresso\core\services\request\Response' => function () { |
|
| 854 | - return $this->response; |
|
| 855 | - }, |
|
| 856 | - 'EE_Base' => 'load_core', |
|
| 857 | - 'EE_Request_Handler' => 'load_core', |
|
| 858 | - 'EE_Session' => 'load_core', |
|
| 859 | - 'EE_Cron_Tasks' => 'load_core', |
|
| 860 | - 'EE_System' => 'load_core', |
|
| 861 | - 'EE_Maintenance_Mode' => 'load_core', |
|
| 862 | - 'EE_Register_CPTs' => 'load_core', |
|
| 863 | - 'EE_Admin' => 'load_core', |
|
| 864 | - 'EE_CPT_Strategy' => 'load_core', |
|
| 865 | - // load_class |
|
| 866 | - 'EE_Registration_Processor' => 'load_class', |
|
| 867 | - // load_lib |
|
| 868 | - 'EE_Message_Resource_Manager' => 'load_lib', |
|
| 869 | - 'EE_Message_Type_Collection' => 'load_lib', |
|
| 870 | - 'EE_Message_Type_Collection_Loader' => 'load_lib', |
|
| 871 | - 'EE_Messenger_Collection' => 'load_lib', |
|
| 872 | - 'EE_Messenger_Collection_Loader' => 'load_lib', |
|
| 873 | - 'EE_Messages_Processor' => 'load_lib', |
|
| 874 | - 'EE_Message_Repository' => 'load_lib', |
|
| 875 | - 'EE_Messages_Queue' => 'load_lib', |
|
| 876 | - 'EE_Messages_Data_Handler_Collection' => 'load_lib', |
|
| 877 | - 'EE_Message_Template_Group_Collection' => 'load_lib', |
|
| 878 | - 'EE_Payment_Method_Manager' => 'load_lib', |
|
| 879 | - 'EE_DMS_Core_4_1_0' => 'load_dms', |
|
| 880 | - 'EE_DMS_Core_4_2_0' => 'load_dms', |
|
| 881 | - 'EE_DMS_Core_4_3_0' => 'load_dms', |
|
| 882 | - 'EE_DMS_Core_4_5_0' => 'load_dms', |
|
| 883 | - 'EE_DMS_Core_4_6_0' => 'load_dms', |
|
| 884 | - 'EE_DMS_Core_4_7_0' => 'load_dms', |
|
| 885 | - 'EE_DMS_Core_4_8_0' => 'load_dms', |
|
| 886 | - 'EE_DMS_Core_4_9_0' => 'load_dms', |
|
| 887 | - 'EE_DMS_Core_4_10_0' => 'load_dms', |
|
| 888 | - 'EE_DMS_Core_4_11_0' => 'load_dms', |
|
| 889 | - 'EE_DMS_Core_4_12_0' => 'load_dms', |
|
| 890 | - 'EE_Messages_Generator' => static function () { |
|
| 891 | - return EE_Registry::instance()->load_lib( |
|
| 892 | - 'Messages_Generator', |
|
| 893 | - [], |
|
| 894 | - false, |
|
| 895 | - false |
|
| 896 | - ); |
|
| 897 | - }, |
|
| 898 | - 'EE_Messages_Template_Defaults' => static function ($arguments = []) { |
|
| 899 | - return EE_Registry::instance()->load_lib( |
|
| 900 | - 'Messages_Template_Defaults', |
|
| 901 | - $arguments, |
|
| 902 | - false, |
|
| 903 | - false |
|
| 904 | - ); |
|
| 905 | - }, |
|
| 906 | - // load_helper |
|
| 907 | - 'EEH_Parse_Shortcodes' => static function () { |
|
| 908 | - if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) { |
|
| 909 | - return new EEH_Parse_Shortcodes(); |
|
| 910 | - } |
|
| 911 | - return null; |
|
| 912 | - }, |
|
| 913 | - 'EE_Template_Config' => static function () { |
|
| 914 | - return EE_Config::instance()->template_settings; |
|
| 915 | - }, |
|
| 916 | - 'EE_Currency_Config' => static function () { |
|
| 917 | - return EE_Config::instance()->currency; |
|
| 918 | - }, |
|
| 919 | - 'EE_Registration_Config' => static function () { |
|
| 920 | - return EE_Config::instance()->registration; |
|
| 921 | - }, |
|
| 922 | - 'EE_Core_Config' => static function () { |
|
| 923 | - return EE_Config::instance()->core; |
|
| 924 | - }, |
|
| 925 | - 'EventEspresso\core\services\loaders\Loader' => static function () { |
|
| 926 | - return LoaderFactory::getLoader(); |
|
| 927 | - }, |
|
| 928 | - 'EE_Network_Config' => static function () { |
|
| 929 | - return EE_Network_Config::instance(); |
|
| 930 | - }, |
|
| 931 | - 'EE_Config' => static function () { |
|
| 932 | - return EE_Config::instance(); |
|
| 933 | - }, |
|
| 934 | - 'EventEspresso\core\domain\Domain' => static function () { |
|
| 935 | - return DomainFactory::getEventEspressoCoreDomain(); |
|
| 936 | - }, |
|
| 937 | - 'EE_Admin_Config' => static function () { |
|
| 938 | - return EE_Config::instance()->admin; |
|
| 939 | - }, |
|
| 940 | - 'EE_Organization_Config' => static function () { |
|
| 941 | - return EE_Config::instance()->organization; |
|
| 942 | - }, |
|
| 943 | - 'EE_Network_Core_Config' => static function () { |
|
| 944 | - return EE_Network_Config::instance()->core; |
|
| 945 | - }, |
|
| 946 | - 'EE_Environment_Config' => static function () { |
|
| 947 | - return EE_Config::instance()->environment; |
|
| 948 | - }, |
|
| 949 | - 'EED_Core_Rest_Api' => static function () { |
|
| 950 | - return EED_Core_Rest_Api::instance(); |
|
| 951 | - }, |
|
| 952 | - 'WP_REST_Server' => static function () { |
|
| 953 | - return rest_get_server(); |
|
| 954 | - }, |
|
| 955 | - 'EventEspresso\core\Psr4Autoloader' => static function () { |
|
| 956 | - return EE_Psr4AutoloaderInit::psr4_loader(); |
|
| 957 | - }, |
|
| 958 | - ]; |
|
| 959 | - } |
|
| 960 | - |
|
| 961 | - |
|
| 962 | - /** |
|
| 963 | - * can be used for supplying alternate names for classes, |
|
| 964 | - * or for connecting interface names to instantiable classes |
|
| 965 | - * |
|
| 966 | - * @throws InvalidAliasException |
|
| 967 | - */ |
|
| 968 | - protected function _register_core_aliases() |
|
| 969 | - { |
|
| 970 | - $aliases = [ |
|
| 971 | - 'CommandBusInterface' => 'EventEspresso\core\services\commands\CommandBusInterface', |
|
| 972 | - 'EventEspresso\core\services\commands\CommandBusInterface' => 'EventEspresso\core\services\commands\CommandBus', |
|
| 973 | - 'CommandHandlerManagerInterface' => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface', |
|
| 974 | - 'EventEspresso\core\services\commands\CommandHandlerManagerInterface' => 'EventEspresso\core\services\commands\CommandHandlerManager', |
|
| 975 | - 'CapChecker' => 'EventEspresso\core\services\commands\middleware\CapChecker', |
|
| 976 | - 'AddActionHook' => 'EventEspresso\core\services\commands\middleware\AddActionHook', |
|
| 977 | - 'CapabilitiesChecker' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker', |
|
| 978 | - 'CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface', |
|
| 979 | - 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker', |
|
| 980 | - 'CreateRegistrationService' => 'EventEspresso\core\domain\services\registration\CreateRegistrationService', |
|
| 981 | - 'CreateRegistrationCommandHandler' => 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand', |
|
| 982 | - 'CopyRegistrationDetailsCommandHandler' => 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommand', |
|
| 983 | - 'CopyRegistrationPaymentsCommandHandler' => 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommand', |
|
| 984 | - 'CancelRegistrationAndTicketLineItemCommandHandler' => 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler', |
|
| 985 | - 'UpdateRegistrationAndTransactionAfterChangeCommandHandler' => 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler', |
|
| 986 | - 'CreateTicketLineItemCommandHandler' => 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommand', |
|
| 987 | - 'CreateTransactionCommandHandler' => 'EventEspresso\core\services\commands\transaction\CreateTransactionCommandHandler', |
|
| 988 | - 'CreateAttendeeCommandHandler' => 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler', |
|
| 989 | - 'TableManager' => 'EventEspresso\core\services\database\TableManager', |
|
| 990 | - 'TableAnalysis' => 'EventEspresso\core\services\database\TableAnalysis', |
|
| 991 | - 'EspressoShortcode' => 'EventEspresso\core\services\shortcodes\EspressoShortcode', |
|
| 992 | - 'ShortcodeInterface' => 'EventEspresso\core\services\shortcodes\ShortcodeInterface', |
|
| 993 | - 'EventEspresso\core\services\shortcodes\ShortcodeInterface' => 'EventEspresso\core\services\shortcodes\EspressoShortcode', |
|
| 994 | - 'EventEspresso\core\services\cache\CacheStorageInterface' => 'EventEspresso\core\services\cache\TransientCacheStorage', |
|
| 995 | - 'LoaderInterface' => 'EventEspresso\core\services\loaders\LoaderInterface', |
|
| 996 | - 'EventEspresso\core\services\loaders\LoaderInterface' => 'EventEspresso\core\services\loaders\Loader', |
|
| 997 | - 'CommandFactoryInterface' => 'EventEspresso\core\services\commands\CommandFactoryInterface', |
|
| 998 | - 'EventEspresso\core\services\commands\CommandFactoryInterface' => 'EventEspresso\core\services\commands\CommandFactory', |
|
| 999 | - 'EmailValidatorInterface' => 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface', |
|
| 1000 | - 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface' => 'EventEspresso\core\domain\services\validation\email\EmailValidationService', |
|
| 1001 | - 'NoticeConverterInterface' => 'EventEspresso\core\services\notices\NoticeConverterInterface', |
|
| 1002 | - 'EventEspresso\core\services\notices\NoticeConverterInterface' => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors', |
|
| 1003 | - 'NoticesContainerInterface' => 'EventEspresso\core\services\notices\NoticesContainerInterface', |
|
| 1004 | - 'EventEspresso\core\services\notices\NoticesContainerInterface' => 'EventEspresso\core\services\notices\NoticesContainer', |
|
| 1005 | - 'EventEspresso\core\services\request\RequestInterface' => 'EventEspresso\core\services\request\Request', |
|
| 1006 | - 'EventEspresso\core\services\request\ResponseInterface' => 'EventEspresso\core\services\request\Response', |
|
| 1007 | - 'EventEspresso\core\domain\DomainInterface' => 'EventEspresso\core\domain\Domain', |
|
| 1008 | - 'Registration_Processor' => 'EE_Registration_Processor', |
|
| 1009 | - 'EventEspresso\core\services\assets\AssetManifestInterface' => 'EventEspresso\core\services\assets\AssetManifest', |
|
| 1010 | - ]; |
|
| 1011 | - foreach ($aliases as $alias => $fqn) { |
|
| 1012 | - if (is_array($fqn)) { |
|
| 1013 | - foreach ($fqn as $class => $for_class) { |
|
| 1014 | - $this->class_cache->addAlias($class, $alias, $for_class); |
|
| 1015 | - } |
|
| 1016 | - continue; |
|
| 1017 | - } |
|
| 1018 | - $this->class_cache->addAlias($fqn, $alias); |
|
| 1019 | - } |
|
| 1020 | - if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) { |
|
| 1021 | - $this->class_cache->addAlias( |
|
| 1022 | - 'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices', |
|
| 1023 | - 'EventEspresso\core\services\notices\NoticeConverterInterface' |
|
| 1024 | - ); |
|
| 1025 | - } |
|
| 1026 | - } |
|
| 1027 | - |
|
| 1028 | - |
|
| 1029 | - /** |
|
| 1030 | - * This is used to reset the internal map and class_loaders to their original default state at the beginning of the |
|
| 1031 | - * request Primarily used by unit tests. |
|
| 1032 | - */ |
|
| 1033 | - public function reset() |
|
| 1034 | - { |
|
| 1035 | - $this->_register_core_class_loaders(); |
|
| 1036 | - $this->_register_core_dependencies(); |
|
| 1037 | - } |
|
| 1038 | - |
|
| 1039 | - |
|
| 1040 | - /** |
|
| 1041 | - * PLZ NOTE: a better name for this method would be is_alias() |
|
| 1042 | - * because it returns TRUE if the provided fully qualified name IS an alias |
|
| 1043 | - * WHY? |
|
| 1044 | - * Because if a class is type hinting for a concretion, |
|
| 1045 | - * then why would we need to find another class to supply it? |
|
| 1046 | - * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`, |
|
| 1047 | - * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`. |
|
| 1048 | - * Don't go looking for some substitute. |
|
| 1049 | - * Whereas if a class is type hinting for an interface... |
|
| 1050 | - * then we need to find an actual class to use. |
|
| 1051 | - * So the interface IS the alias for some other FQN, |
|
| 1052 | - * and we need to find out if `Fully/Qualified/Namespace/SomeInterface` |
|
| 1053 | - * represents some other class. |
|
| 1054 | - * |
|
| 1055 | - * @param string $fqn |
|
| 1056 | - * @param string $for_class |
|
| 1057 | - * @return bool |
|
| 1058 | - * @deprecated 4.9.62.p |
|
| 1059 | - */ |
|
| 1060 | - public function has_alias($fqn = '', $for_class = '') |
|
| 1061 | - { |
|
| 1062 | - return $this->isAlias($fqn, $for_class); |
|
| 1063 | - } |
|
| 1064 | - |
|
| 1065 | - |
|
| 1066 | - /** |
|
| 1067 | - * PLZ NOTE: a better name for this method would be get_fqn_for_alias() |
|
| 1068 | - * because it returns a FQN for provided alias if one exists, otherwise returns the original $alias |
|
| 1069 | - * functions recursively, so that multiple aliases can be used to drill down to a FQN |
|
| 1070 | - * for example: |
|
| 1071 | - * if the following two entries were added to the _aliases array: |
|
| 1072 | - * array( |
|
| 1073 | - * 'interface_alias' => 'some\namespace\interface' |
|
| 1074 | - * 'some\namespace\interface' => 'some\namespace\classname' |
|
| 1075 | - * ) |
|
| 1076 | - * then one could use EE_Registry::instance()->create( 'interface_alias' ) |
|
| 1077 | - * to load an instance of 'some\namespace\classname' |
|
| 1078 | - * |
|
| 1079 | - * @param string $alias |
|
| 1080 | - * @param string $for_class |
|
| 1081 | - * @return string |
|
| 1082 | - * @deprecated 4.9.62.p |
|
| 1083 | - */ |
|
| 1084 | - public function get_alias($alias = '', $for_class = '') |
|
| 1085 | - { |
|
| 1086 | - return $this->getFqnForAlias($alias, $for_class); |
|
| 1087 | - } |
|
| 25 | + /** |
|
| 26 | + * This means that the requested class dependency is not present in the dependency map |
|
| 27 | + */ |
|
| 28 | + const not_registered = 0; |
|
| 29 | + |
|
| 30 | + /** |
|
| 31 | + * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class. |
|
| 32 | + */ |
|
| 33 | + const load_new_object = 1; |
|
| 34 | + |
|
| 35 | + /** |
|
| 36 | + * This instructs class loaders to return a previously instantiated and cached object for the requested class. |
|
| 37 | + * IF a previously instantiated object does not exist, a new one will be created and added to the cache. |
|
| 38 | + */ |
|
| 39 | + const load_from_cache = 2; |
|
| 40 | + |
|
| 41 | + /** |
|
| 42 | + * When registering a dependency, |
|
| 43 | + * this indicates to keep any existing dependencies that already exist, |
|
| 44 | + * and simply discard any new dependencies declared in the incoming data |
|
| 45 | + */ |
|
| 46 | + const KEEP_EXISTING_DEPENDENCIES = 0; |
|
| 47 | + |
|
| 48 | + /** |
|
| 49 | + * When registering a dependency, |
|
| 50 | + * this indicates to overwrite any existing dependencies that already exist using the incoming data |
|
| 51 | + */ |
|
| 52 | + const OVERWRITE_DEPENDENCIES = 1; |
|
| 53 | + |
|
| 54 | + /** |
|
| 55 | + * @type EE_Dependency_Map $_instance |
|
| 56 | + */ |
|
| 57 | + protected static $_instance; |
|
| 58 | + |
|
| 59 | + /** |
|
| 60 | + * @var ClassInterfaceCache $class_cache |
|
| 61 | + */ |
|
| 62 | + private $class_cache; |
|
| 63 | + |
|
| 64 | + /** |
|
| 65 | + * @type RequestInterface $request |
|
| 66 | + */ |
|
| 67 | + protected $request; |
|
| 68 | + |
|
| 69 | + /** |
|
| 70 | + * @type LegacyRequestInterface $legacy_request |
|
| 71 | + */ |
|
| 72 | + protected $legacy_request; |
|
| 73 | + |
|
| 74 | + /** |
|
| 75 | + * @type ResponseInterface $response |
|
| 76 | + */ |
|
| 77 | + protected $response; |
|
| 78 | + |
|
| 79 | + /** |
|
| 80 | + * @type LoaderInterface $loader |
|
| 81 | + */ |
|
| 82 | + protected $loader; |
|
| 83 | + |
|
| 84 | + /** |
|
| 85 | + * @type array $_dependency_map |
|
| 86 | + */ |
|
| 87 | + protected $_dependency_map = []; |
|
| 88 | + |
|
| 89 | + /** |
|
| 90 | + * @type array $_class_loaders |
|
| 91 | + */ |
|
| 92 | + protected $_class_loaders = []; |
|
| 93 | + |
|
| 94 | + |
|
| 95 | + /** |
|
| 96 | + * EE_Dependency_Map constructor. |
|
| 97 | + * |
|
| 98 | + * @param ClassInterfaceCache $class_cache |
|
| 99 | + */ |
|
| 100 | + protected function __construct(ClassInterfaceCache $class_cache) |
|
| 101 | + { |
|
| 102 | + $this->class_cache = $class_cache; |
|
| 103 | + do_action('EE_Dependency_Map____construct', $this); |
|
| 104 | + } |
|
| 105 | + |
|
| 106 | + |
|
| 107 | + /** |
|
| 108 | + * @return void |
|
| 109 | + * @throws InvalidAliasException |
|
| 110 | + */ |
|
| 111 | + public function initialize() |
|
| 112 | + { |
|
| 113 | + $this->_register_core_dependencies(); |
|
| 114 | + $this->_register_core_class_loaders(); |
|
| 115 | + $this->_register_core_aliases(); |
|
| 116 | + } |
|
| 117 | + |
|
| 118 | + |
|
| 119 | + /** |
|
| 120 | + * @singleton method used to instantiate class object |
|
| 121 | + * @param ClassInterfaceCache|null $class_cache |
|
| 122 | + * @return EE_Dependency_Map |
|
| 123 | + */ |
|
| 124 | + public static function instance(ClassInterfaceCache $class_cache = null) |
|
| 125 | + { |
|
| 126 | + // check if class object is instantiated, and instantiated properly |
|
| 127 | + if ( |
|
| 128 | + ! EE_Dependency_Map::$_instance instanceof EE_Dependency_Map |
|
| 129 | + && $class_cache instanceof ClassInterfaceCache |
|
| 130 | + ) { |
|
| 131 | + EE_Dependency_Map::$_instance = new EE_Dependency_Map($class_cache); |
|
| 132 | + } |
|
| 133 | + return EE_Dependency_Map::$_instance; |
|
| 134 | + } |
|
| 135 | + |
|
| 136 | + |
|
| 137 | + /** |
|
| 138 | + * @param RequestInterface $request |
|
| 139 | + */ |
|
| 140 | + public function setRequest(RequestInterface $request) |
|
| 141 | + { |
|
| 142 | + $this->request = $request; |
|
| 143 | + } |
|
| 144 | + |
|
| 145 | + |
|
| 146 | + /** |
|
| 147 | + * @param LegacyRequestInterface $legacy_request |
|
| 148 | + */ |
|
| 149 | + public function setLegacyRequest(LegacyRequestInterface $legacy_request) |
|
| 150 | + { |
|
| 151 | + $this->legacy_request = $legacy_request; |
|
| 152 | + } |
|
| 153 | + |
|
| 154 | + |
|
| 155 | + /** |
|
| 156 | + * @param ResponseInterface $response |
|
| 157 | + */ |
|
| 158 | + public function setResponse(ResponseInterface $response) |
|
| 159 | + { |
|
| 160 | + $this->response = $response; |
|
| 161 | + } |
|
| 162 | + |
|
| 163 | + |
|
| 164 | + /** |
|
| 165 | + * @param LoaderInterface $loader |
|
| 166 | + */ |
|
| 167 | + public function setLoader(LoaderInterface $loader) |
|
| 168 | + { |
|
| 169 | + $this->loader = $loader; |
|
| 170 | + } |
|
| 171 | + |
|
| 172 | + |
|
| 173 | + /** |
|
| 174 | + * @param string $class |
|
| 175 | + * @param array $dependencies |
|
| 176 | + * @param int $overwrite |
|
| 177 | + * @return bool |
|
| 178 | + */ |
|
| 179 | + public static function register_dependencies( |
|
| 180 | + $class, |
|
| 181 | + array $dependencies, |
|
| 182 | + $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES |
|
| 183 | + ) { |
|
| 184 | + return EE_Dependency_Map::$_instance->registerDependencies($class, $dependencies, $overwrite); |
|
| 185 | + } |
|
| 186 | + |
|
| 187 | + |
|
| 188 | + /** |
|
| 189 | + * Assigns an array of class names and corresponding load sources (new or cached) |
|
| 190 | + * to the class specified by the first parameter. |
|
| 191 | + * IMPORTANT !!! |
|
| 192 | + * The order of elements in the incoming $dependencies array MUST match |
|
| 193 | + * the order of the constructor parameters for the class in question. |
|
| 194 | + * This is especially important when overriding any existing dependencies that are registered. |
|
| 195 | + * the third parameter controls whether any duplicate dependencies are overwritten or not. |
|
| 196 | + * |
|
| 197 | + * @param string $class |
|
| 198 | + * @param array $dependencies |
|
| 199 | + * @param int $overwrite |
|
| 200 | + * @return bool |
|
| 201 | + */ |
|
| 202 | + public function registerDependencies( |
|
| 203 | + $class, |
|
| 204 | + array $dependencies, |
|
| 205 | + $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES |
|
| 206 | + ) { |
|
| 207 | + $class = trim($class, '\\'); |
|
| 208 | + $registered = false; |
|
| 209 | + if (empty(EE_Dependency_Map::$_instance->_dependency_map[ $class ])) { |
|
| 210 | + EE_Dependency_Map::$_instance->_dependency_map[ $class ] = []; |
|
| 211 | + } |
|
| 212 | + // we need to make sure that any aliases used when registering a dependency |
|
| 213 | + // get resolved to the correct class name |
|
| 214 | + foreach ($dependencies as $dependency => $load_source) { |
|
| 215 | + $alias = EE_Dependency_Map::$_instance->getFqnForAlias($dependency); |
|
| 216 | + if ( |
|
| 217 | + $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES |
|
| 218 | + || ! isset(EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $alias ]) |
|
| 219 | + ) { |
|
| 220 | + unset($dependencies[ $dependency ]); |
|
| 221 | + $dependencies[ $alias ] = $load_source; |
|
| 222 | + $registered = true; |
|
| 223 | + } |
|
| 224 | + } |
|
| 225 | + // now add our two lists of dependencies together. |
|
| 226 | + // using Union (+=) favours the arrays in precedence from left to right, |
|
| 227 | + // so $dependencies is NOT overwritten because it is listed first |
|
| 228 | + // ie: with A = B + C, entries in B take precedence over duplicate entries in C |
|
| 229 | + // Union is way faster than array_merge() but should be used with caution... |
|
| 230 | + // especially with numerically indexed arrays |
|
| 231 | + $dependencies += EE_Dependency_Map::$_instance->_dependency_map[ $class ]; |
|
| 232 | + // now we need to ensure that the resulting dependencies |
|
| 233 | + // array only has the entries that are required for the class |
|
| 234 | + // so first count how many dependencies were originally registered for the class |
|
| 235 | + $dependency_count = count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]); |
|
| 236 | + // if that count is non-zero (meaning dependencies were already registered) |
|
| 237 | + EE_Dependency_Map::$_instance->_dependency_map[ $class ] = $dependency_count |
|
| 238 | + // then truncate the final array to match that count |
|
| 239 | + ? array_slice($dependencies, 0, $dependency_count) |
|
| 240 | + // otherwise just take the incoming array because nothing previously existed |
|
| 241 | + : $dependencies; |
|
| 242 | + return $registered; |
|
| 243 | + } |
|
| 244 | + |
|
| 245 | + |
|
| 246 | + /** |
|
| 247 | + * @param string $class_name |
|
| 248 | + * @param string $loader |
|
| 249 | + * @return bool |
|
| 250 | + * @throws DomainException |
|
| 251 | + */ |
|
| 252 | + public static function register_class_loader($class_name, $loader = 'load_core') |
|
| 253 | + { |
|
| 254 | + return EE_Dependency_Map::$_instance->registerClassLoader($class_name, $loader); |
|
| 255 | + } |
|
| 256 | + |
|
| 257 | + |
|
| 258 | + /** |
|
| 259 | + * @param string $class_name |
|
| 260 | + * @param string $loader |
|
| 261 | + * @return bool |
|
| 262 | + * @throws DomainException |
|
| 263 | + */ |
|
| 264 | + public function registerClassLoader($class_name, $loader = 'load_core') |
|
| 265 | + { |
|
| 266 | + if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) { |
|
| 267 | + throw new DomainException( |
|
| 268 | + esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso') |
|
| 269 | + ); |
|
| 270 | + } |
|
| 271 | + // check that loader is callable or method starts with "load_" and exists in EE_Registry |
|
| 272 | + if ( |
|
| 273 | + ! is_callable($loader) |
|
| 274 | + && ( |
|
| 275 | + strpos($loader, 'load_') !== 0 |
|
| 276 | + || ! method_exists('EE_Registry', $loader) |
|
| 277 | + ) |
|
| 278 | + ) { |
|
| 279 | + throw new DomainException( |
|
| 280 | + sprintf( |
|
| 281 | + esc_html__( |
|
| 282 | + '"%1$s" is not a valid loader method on EE_Registry.', |
|
| 283 | + 'event_espresso' |
|
| 284 | + ), |
|
| 285 | + $loader |
|
| 286 | + ) |
|
| 287 | + ); |
|
| 288 | + } |
|
| 289 | + $class_name = EE_Dependency_Map::$_instance->getFqnForAlias($class_name); |
|
| 290 | + if (! isset(EE_Dependency_Map::$_instance->_class_loaders[ $class_name ])) { |
|
| 291 | + EE_Dependency_Map::$_instance->_class_loaders[ $class_name ] = $loader; |
|
| 292 | + return true; |
|
| 293 | + } |
|
| 294 | + return false; |
|
| 295 | + } |
|
| 296 | + |
|
| 297 | + |
|
| 298 | + /** |
|
| 299 | + * @return array |
|
| 300 | + */ |
|
| 301 | + public function dependency_map() |
|
| 302 | + { |
|
| 303 | + return $this->_dependency_map; |
|
| 304 | + } |
|
| 305 | + |
|
| 306 | + |
|
| 307 | + /** |
|
| 308 | + * returns TRUE if dependency map contains a listing for the provided class name |
|
| 309 | + * |
|
| 310 | + * @param string $class_name |
|
| 311 | + * @return boolean |
|
| 312 | + */ |
|
| 313 | + public function has($class_name = '') |
|
| 314 | + { |
|
| 315 | + // all legacy models have the same dependencies |
|
| 316 | + if (strpos($class_name, 'EEM_') === 0) { |
|
| 317 | + $class_name = 'LEGACY_MODELS'; |
|
| 318 | + } |
|
| 319 | + return isset($this->_dependency_map[ $class_name ]); |
|
| 320 | + } |
|
| 321 | + |
|
| 322 | + |
|
| 323 | + /** |
|
| 324 | + * returns TRUE if dependency map contains a listing for the provided class name AND dependency |
|
| 325 | + * |
|
| 326 | + * @param string $class_name |
|
| 327 | + * @param string $dependency |
|
| 328 | + * @return bool |
|
| 329 | + */ |
|
| 330 | + public function has_dependency_for_class($class_name = '', $dependency = '') |
|
| 331 | + { |
|
| 332 | + // all legacy models have the same dependencies |
|
| 333 | + if (strpos($class_name, 'EEM_') === 0) { |
|
| 334 | + $class_name = 'LEGACY_MODELS'; |
|
| 335 | + } |
|
| 336 | + $dependency = $this->getFqnForAlias($dependency, $class_name); |
|
| 337 | + return isset($this->_dependency_map[ $class_name ][ $dependency ]); |
|
| 338 | + } |
|
| 339 | + |
|
| 340 | + |
|
| 341 | + /** |
|
| 342 | + * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned |
|
| 343 | + * |
|
| 344 | + * @param string $class_name |
|
| 345 | + * @param string $dependency |
|
| 346 | + * @return int |
|
| 347 | + */ |
|
| 348 | + public function loading_strategy_for_class_dependency($class_name = '', $dependency = '') |
|
| 349 | + { |
|
| 350 | + // all legacy models have the same dependencies |
|
| 351 | + if (strpos($class_name, 'EEM_') === 0) { |
|
| 352 | + $class_name = 'LEGACY_MODELS'; |
|
| 353 | + } |
|
| 354 | + $dependency = $this->getFqnForAlias($dependency); |
|
| 355 | + return $this->has_dependency_for_class($class_name, $dependency) |
|
| 356 | + ? $this->_dependency_map[ $class_name ][ $dependency ] |
|
| 357 | + : EE_Dependency_Map::not_registered; |
|
| 358 | + } |
|
| 359 | + |
|
| 360 | + |
|
| 361 | + /** |
|
| 362 | + * @param string $class_name |
|
| 363 | + * @return string | Closure |
|
| 364 | + */ |
|
| 365 | + public function class_loader($class_name) |
|
| 366 | + { |
|
| 367 | + // all legacy models use load_model() |
|
| 368 | + if (strpos($class_name, 'EEM_') === 0) { |
|
| 369 | + return 'load_model'; |
|
| 370 | + } |
|
| 371 | + // EE_CPT_*_Strategy classes like EE_CPT_Event_Strategy, EE_CPT_Venue_Strategy, etc |
|
| 372 | + // perform strpos() first to avoid loading regex every time we load a class |
|
| 373 | + if ( |
|
| 374 | + strpos($class_name, 'EE_CPT_') === 0 |
|
| 375 | + && preg_match('/^EE_CPT_([a-zA-Z]+)_Strategy$/', $class_name) |
|
| 376 | + ) { |
|
| 377 | + return 'load_core'; |
|
| 378 | + } |
|
| 379 | + $class_name = $this->getFqnForAlias($class_name); |
|
| 380 | + return isset($this->_class_loaders[ $class_name ]) ? $this->_class_loaders[ $class_name ] : ''; |
|
| 381 | + } |
|
| 382 | + |
|
| 383 | + |
|
| 384 | + /** |
|
| 385 | + * @return array |
|
| 386 | + */ |
|
| 387 | + public function class_loaders() |
|
| 388 | + { |
|
| 389 | + return $this->_class_loaders; |
|
| 390 | + } |
|
| 391 | + |
|
| 392 | + |
|
| 393 | + /** |
|
| 394 | + * adds an alias for a classname |
|
| 395 | + * |
|
| 396 | + * @param string $fqcn the class name that should be used (concrete class to replace interface) |
|
| 397 | + * @param string $alias the class name that would be type hinted for (abstract parent or interface) |
|
| 398 | + * @param string $for_class the class that has the dependency (is type hinting for the interface) |
|
| 399 | + * @throws InvalidAliasException |
|
| 400 | + */ |
|
| 401 | + public function add_alias($fqcn, $alias, $for_class = '') |
|
| 402 | + { |
|
| 403 | + $this->class_cache->addAlias($fqcn, $alias, $for_class); |
|
| 404 | + } |
|
| 405 | + |
|
| 406 | + |
|
| 407 | + /** |
|
| 408 | + * Returns TRUE if the provided fully qualified name IS an alias |
|
| 409 | + * WHY? |
|
| 410 | + * Because if a class is type hinting for a concretion, |
|
| 411 | + * then why would we need to find another class to supply it? |
|
| 412 | + * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`, |
|
| 413 | + * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`. |
|
| 414 | + * Don't go looking for some substitute. |
|
| 415 | + * Whereas if a class is type hinting for an interface... |
|
| 416 | + * then we need to find an actual class to use. |
|
| 417 | + * So the interface IS the alias for some other FQN, |
|
| 418 | + * and we need to find out if `Fully/Qualified/Namespace/SomeInterface` |
|
| 419 | + * represents some other class. |
|
| 420 | + * |
|
| 421 | + * @param string $fqn |
|
| 422 | + * @param string $for_class |
|
| 423 | + * @return bool |
|
| 424 | + */ |
|
| 425 | + public function isAlias($fqn = '', $for_class = '') |
|
| 426 | + { |
|
| 427 | + return $this->class_cache->isAlias($fqn, $for_class); |
|
| 428 | + } |
|
| 429 | + |
|
| 430 | + |
|
| 431 | + /** |
|
| 432 | + * Returns a FQN for provided alias if one exists, otherwise returns the original $alias |
|
| 433 | + * functions recursively, so that multiple aliases can be used to drill down to a FQN |
|
| 434 | + * for example: |
|
| 435 | + * if the following two entries were added to the _aliases array: |
|
| 436 | + * array( |
|
| 437 | + * 'interface_alias' => 'some\namespace\interface' |
|
| 438 | + * 'some\namespace\interface' => 'some\namespace\classname' |
|
| 439 | + * ) |
|
| 440 | + * then one could use EE_Registry::instance()->create( 'interface_alias' ) |
|
| 441 | + * to load an instance of 'some\namespace\classname' |
|
| 442 | + * |
|
| 443 | + * @param string $alias |
|
| 444 | + * @param string $for_class |
|
| 445 | + * @return string |
|
| 446 | + */ |
|
| 447 | + public function getFqnForAlias($alias = '', $for_class = '') |
|
| 448 | + { |
|
| 449 | + return (string) $this->class_cache->getFqnForAlias($alias, $for_class); |
|
| 450 | + } |
|
| 451 | + |
|
| 452 | + |
|
| 453 | + /** |
|
| 454 | + * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache, |
|
| 455 | + * if one exists, or whether a new object should be generated every time the requested class is loaded. |
|
| 456 | + * This is done by using the following class constants: |
|
| 457 | + * EE_Dependency_Map::load_from_cache - loads previously instantiated object |
|
| 458 | + * EE_Dependency_Map::load_new_object - generates a new object every time |
|
| 459 | + */ |
|
| 460 | + protected function _register_core_dependencies() |
|
| 461 | + { |
|
| 462 | + $this->_dependency_map = [ |
|
| 463 | + 'EE_Request_Handler' => [ |
|
| 464 | + 'EE_Request' => EE_Dependency_Map::load_from_cache, |
|
| 465 | + ], |
|
| 466 | + 'EE_System' => [ |
|
| 467 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 468 | + 'EE_Maintenance_Mode' => EE_Dependency_Map::load_from_cache, |
|
| 469 | + 'EE_Registry' => EE_Dependency_Map::load_from_cache, |
|
| 470 | + 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 471 | + 'EventEspresso\core\services\routing\Router' => EE_Dependency_Map::load_from_cache, |
|
| 472 | + ], |
|
| 473 | + 'EE_Admin' => [ |
|
| 474 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 475 | + 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 476 | + ], |
|
| 477 | + 'EE_Cart' => [ |
|
| 478 | + 'EE_Session' => EE_Dependency_Map::load_from_cache, |
|
| 479 | + ], |
|
| 480 | + 'EE_Messenger_Collection_Loader' => [ |
|
| 481 | + 'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object, |
|
| 482 | + ], |
|
| 483 | + 'EE_Message_Type_Collection_Loader' => [ |
|
| 484 | + 'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object, |
|
| 485 | + ], |
|
| 486 | + 'EE_Message_Resource_Manager' => [ |
|
| 487 | + 'EE_Messenger_Collection_Loader' => EE_Dependency_Map::load_new_object, |
|
| 488 | + 'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object, |
|
| 489 | + 'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache, |
|
| 490 | + ], |
|
| 491 | + 'EE_Message_Factory' => [ |
|
| 492 | + 'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache, |
|
| 493 | + ], |
|
| 494 | + 'EE_messages' => [ |
|
| 495 | + 'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache, |
|
| 496 | + ], |
|
| 497 | + 'EE_Messages_Generator' => [ |
|
| 498 | + 'EE_Messages_Queue' => EE_Dependency_Map::load_new_object, |
|
| 499 | + 'EE_Messages_Data_Handler_Collection' => EE_Dependency_Map::load_new_object, |
|
| 500 | + 'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object, |
|
| 501 | + 'EEH_Parse_Shortcodes' => EE_Dependency_Map::load_from_cache, |
|
| 502 | + ], |
|
| 503 | + 'EE_Messages_Processor' => [ |
|
| 504 | + 'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache, |
|
| 505 | + ], |
|
| 506 | + 'EE_Messages_Queue' => [ |
|
| 507 | + 'EE_Message_Repository' => EE_Dependency_Map::load_new_object, |
|
| 508 | + ], |
|
| 509 | + 'EE_Messages_Template_Defaults' => [ |
|
| 510 | + 'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache, |
|
| 511 | + 'EEM_Message_Template' => EE_Dependency_Map::load_from_cache, |
|
| 512 | + ], |
|
| 513 | + 'EE_Message_To_Generate_From_Request' => [ |
|
| 514 | + 'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache, |
|
| 515 | + 'EE_Request_Handler' => EE_Dependency_Map::load_from_cache, |
|
| 516 | + ], |
|
| 517 | + 'EventEspresso\core\services\commands\CommandBus' => [ |
|
| 518 | + 'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache, |
|
| 519 | + ], |
|
| 520 | + 'EventEspresso\services\commands\CommandHandler' => [ |
|
| 521 | + 'EE_Registry' => EE_Dependency_Map::load_from_cache, |
|
| 522 | + 'CommandBusInterface' => EE_Dependency_Map::load_from_cache, |
|
| 523 | + ], |
|
| 524 | + 'EventEspresso\core\services\commands\CommandHandlerManager' => [ |
|
| 525 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 526 | + ], |
|
| 527 | + 'EventEspresso\core\services\commands\CompositeCommandHandler' => [ |
|
| 528 | + 'EventEspresso\core\services\commands\CommandBus' => EE_Dependency_Map::load_from_cache, |
|
| 529 | + 'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache, |
|
| 530 | + ], |
|
| 531 | + 'EventEspresso\core\services\commands\CommandFactory' => [ |
|
| 532 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 533 | + ], |
|
| 534 | + 'EventEspresso\core\services\commands\middleware\CapChecker' => [ |
|
| 535 | + 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache, |
|
| 536 | + ], |
|
| 537 | + 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => [ |
|
| 538 | + 'EE_Capabilities' => EE_Dependency_Map::load_from_cache, |
|
| 539 | + ], |
|
| 540 | + 'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker' => [ |
|
| 541 | + 'EE_Capabilities' => EE_Dependency_Map::load_from_cache, |
|
| 542 | + ], |
|
| 543 | + 'EventEspresso\core\services\commands\registration\CreateRegistrationCommandHandler' => [ |
|
| 544 | + 'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache, |
|
| 545 | + ], |
|
| 546 | + 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommandHandler' => [ |
|
| 547 | + 'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache, |
|
| 548 | + ], |
|
| 549 | + 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommandHandler' => [ |
|
| 550 | + 'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache, |
|
| 551 | + ], |
|
| 552 | + 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler' => [ |
|
| 553 | + 'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache, |
|
| 554 | + ], |
|
| 555 | + 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => [ |
|
| 556 | + 'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache, |
|
| 557 | + ], |
|
| 558 | + 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommandHandler' => [ |
|
| 559 | + 'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache, |
|
| 560 | + ], |
|
| 561 | + 'EventEspresso\core\services\commands\ticket\CancelTicketLineItemCommandHandler' => [ |
|
| 562 | + 'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache, |
|
| 563 | + ], |
|
| 564 | + 'EventEspresso\core\domain\services\registration\CancelRegistrationService' => [ |
|
| 565 | + 'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache, |
|
| 566 | + ], |
|
| 567 | + 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler' => [ |
|
| 568 | + 'EEM_Attendee' => EE_Dependency_Map::load_from_cache, |
|
| 569 | + ], |
|
| 570 | + 'EventEspresso\core\services\database\TableManager' => [ |
|
| 571 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 572 | + ], |
|
| 573 | + 'EE_Data_Migration_Class_Base' => [ |
|
| 574 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 575 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 576 | + ], |
|
| 577 | + 'EE_DMS_Core_4_1_0' => [ |
|
| 578 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 579 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 580 | + ], |
|
| 581 | + 'EE_DMS_Core_4_2_0' => [ |
|
| 582 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 583 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 584 | + ], |
|
| 585 | + 'EE_DMS_Core_4_3_0' => [ |
|
| 586 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 587 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 588 | + ], |
|
| 589 | + 'EE_DMS_Core_4_4_0' => [ |
|
| 590 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 591 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 592 | + ], |
|
| 593 | + 'EE_DMS_Core_4_5_0' => [ |
|
| 594 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 595 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 596 | + ], |
|
| 597 | + 'EE_DMS_Core_4_6_0' => [ |
|
| 598 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 599 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 600 | + ], |
|
| 601 | + 'EE_DMS_Core_4_7_0' => [ |
|
| 602 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 603 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 604 | + ], |
|
| 605 | + 'EE_DMS_Core_4_8_0' => [ |
|
| 606 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 607 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 608 | + ], |
|
| 609 | + 'EE_DMS_Core_4_9_0' => [ |
|
| 610 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 611 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 612 | + ], |
|
| 613 | + 'EE_DMS_Core_4_10_0' => [ |
|
| 614 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 615 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 616 | + 'EE_DMS_Core_4_9_0' => EE_Dependency_Map::load_from_cache, |
|
| 617 | + ], |
|
| 618 | + 'EE_DMS_Core_4_11_0' => [ |
|
| 619 | + 'EE_DMS_Core_4_10_0' => EE_Dependency_Map::load_from_cache, |
|
| 620 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 621 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 622 | + ], |
|
| 623 | + 'EE_DMS_Core_4_12_0' => [ |
|
| 624 | + 'EE_DMS_Core_4_11_0' => EE_Dependency_Map::load_from_cache, |
|
| 625 | + 'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache, |
|
| 626 | + 'EventEspresso\core\services\database\TableManager' => EE_Dependency_Map::load_from_cache, |
|
| 627 | + ], |
|
| 628 | + 'EventEspresso\core\services\assets\Registry' => [ |
|
| 629 | + 'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_new_object, |
|
| 630 | + 'EventEspresso\core\services\assets\AssetManifest' => EE_Dependency_Map::load_from_cache, |
|
| 631 | + ], |
|
| 632 | + 'EventEspresso\core\services\cache\BasicCacheManager' => [ |
|
| 633 | + 'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache, |
|
| 634 | + ], |
|
| 635 | + 'EventEspresso\core\services\cache\PostRelatedCacheManager' => [ |
|
| 636 | + 'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache, |
|
| 637 | + ], |
|
| 638 | + 'EventEspresso\core\domain\services\validation\email\EmailValidationService' => [ |
|
| 639 | + 'EE_Registration_Config' => EE_Dependency_Map::load_from_cache, |
|
| 640 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 641 | + ], |
|
| 642 | + 'EventEspresso\core\domain\values\EmailAddress' => [ |
|
| 643 | + null, |
|
| 644 | + 'EventEspresso\core\domain\services\validation\email\EmailValidationService' => EE_Dependency_Map::load_from_cache, |
|
| 645 | + ], |
|
| 646 | + 'EventEspresso\core\services\orm\ModelFieldFactory' => [ |
|
| 647 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 648 | + ], |
|
| 649 | + 'LEGACY_MODELS' => [ |
|
| 650 | + null, |
|
| 651 | + 'EventEspresso\core\services\database\ModelFieldFactory' => EE_Dependency_Map::load_from_cache, |
|
| 652 | + ], |
|
| 653 | + 'EE_Module_Request_Router' => [ |
|
| 654 | + 'EE_Request' => EE_Dependency_Map::load_from_cache, |
|
| 655 | + ], |
|
| 656 | + 'EE_Registration_Processor' => [ |
|
| 657 | + 'EE_Request' => EE_Dependency_Map::load_from_cache, |
|
| 658 | + ], |
|
| 659 | + 'EventEspresso\core\services\notifications\PersistentAdminNoticeManager' => [ |
|
| 660 | + null, |
|
| 661 | + 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache, |
|
| 662 | + 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 663 | + ], |
|
| 664 | + 'EventEspresso\caffeinated\modules\recaptcha_invisible\InvisibleRecaptcha' => [ |
|
| 665 | + 'EE_Registration_Config' => EE_Dependency_Map::load_from_cache, |
|
| 666 | + 'EE_Session' => EE_Dependency_Map::load_from_cache, |
|
| 667 | + ], |
|
| 668 | + 'EventEspresso\modules\ticket_selector\DisplayTicketSelector' => [ |
|
| 669 | + 'EventEspresso\core\domain\entities\users\CurrentUser' => EE_Dependency_Map::load_from_cache, |
|
| 670 | + ], |
|
| 671 | + 'EventEspresso\modules\ticket_selector\ProcessTicketSelector' => [ |
|
| 672 | + 'EE_Core_Config' => EE_Dependency_Map::load_from_cache, |
|
| 673 | + 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 674 | + 'EE_Session' => EE_Dependency_Map::load_from_cache, |
|
| 675 | + 'EEM_Ticket' => EE_Dependency_Map::load_from_cache, |
|
| 676 | + 'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker' => EE_Dependency_Map::load_from_cache, |
|
| 677 | + ], |
|
| 678 | + 'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker' => [ |
|
| 679 | + 'EEM_Datetime' => EE_Dependency_Map::load_from_cache, |
|
| 680 | + ], |
|
| 681 | + 'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => [ |
|
| 682 | + 'EE_Core_Config' => EE_Dependency_Map::load_from_cache, |
|
| 683 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 684 | + ], |
|
| 685 | + 'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes' => [ |
|
| 686 | + 'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache, |
|
| 687 | + ], |
|
| 688 | + 'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies' => [ |
|
| 689 | + 'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache, |
|
| 690 | + ], |
|
| 691 | + 'EE_CPT_Strategy' => [ |
|
| 692 | + 'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache, |
|
| 693 | + 'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache, |
|
| 694 | + ], |
|
| 695 | + 'EventEspresso\core\services\loaders\ObjectIdentifier' => [ |
|
| 696 | + 'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache, |
|
| 697 | + ], |
|
| 698 | + 'EventEspresso\core\CPTs\CptQueryModifier' => [ |
|
| 699 | + null, |
|
| 700 | + null, |
|
| 701 | + null, |
|
| 702 | + 'EE_Request_Handler' => EE_Dependency_Map::load_from_cache, |
|
| 703 | + 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 704 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 705 | + ], |
|
| 706 | + 'EventEspresso\core\services\dependencies\DependencyResolver' => [ |
|
| 707 | + 'EventEspresso\core\services\container\Mirror' => EE_Dependency_Map::load_from_cache, |
|
| 708 | + 'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache, |
|
| 709 | + 'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache, |
|
| 710 | + ], |
|
| 711 | + 'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver' => [ |
|
| 712 | + 'EventEspresso\core\services\container\Mirror' => EE_Dependency_Map::load_from_cache, |
|
| 713 | + 'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache, |
|
| 714 | + 'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache, |
|
| 715 | + ], |
|
| 716 | + 'EventEspresso\core\services\routing\RouteMatchSpecificationFactory' => [ |
|
| 717 | + 'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver' => EE_Dependency_Map::load_from_cache, |
|
| 718 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 719 | + ], |
|
| 720 | + 'EventEspresso\core\services\routing\RouteMatchSpecificationManager' => [ |
|
| 721 | + 'EventEspresso\core\services\routing\RouteMatchSpecificationCollection' => EE_Dependency_Map::load_from_cache, |
|
| 722 | + 'EventEspresso\core\services\routing\RouteMatchSpecificationFactory' => EE_Dependency_Map::load_from_cache, |
|
| 723 | + ], |
|
| 724 | + 'EE_URL_Validation_Strategy' => [ |
|
| 725 | + null, |
|
| 726 | + null, |
|
| 727 | + 'EventEspresso\core\services\validators\URLValidator' => EE_Dependency_Map::load_from_cache, |
|
| 728 | + ], |
|
| 729 | + 'EventEspresso\core\services\request\files\FilesDataHandler' => [ |
|
| 730 | + 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 731 | + ], |
|
| 732 | + 'EventEspressoBatchRequest\BatchRequestProcessor' => [ |
|
| 733 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 734 | + ], |
|
| 735 | + 'EventEspresso\core\domain\services\converters\RestApiSpoofer' => [ |
|
| 736 | + 'WP_REST_Server' => EE_Dependency_Map::load_from_cache, |
|
| 737 | + 'EED_Core_Rest_Api' => EE_Dependency_Map::load_from_cache, |
|
| 738 | + 'EventEspresso\core\libraries\rest_api\controllers\model\Read' => EE_Dependency_Map::load_from_cache, |
|
| 739 | + null, |
|
| 740 | + ], |
|
| 741 | + 'EventEspresso\core\services\routing\RouteHandler' => [ |
|
| 742 | + 'EventEspresso\core\services\json\JsonDataNodeHandler' => EE_Dependency_Map::load_from_cache, |
|
| 743 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 744 | + 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 745 | + 'EventEspresso\core\services\routing\RouteCollection' => EE_Dependency_Map::load_from_cache, |
|
| 746 | + ], |
|
| 747 | + 'EventEspresso\core\services\json\JsonDataNodeHandler' => [ |
|
| 748 | + 'EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache, |
|
| 749 | + ], |
|
| 750 | + 'EventEspresso\core\services\routing\Router' => [ |
|
| 751 | + 'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache, |
|
| 752 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 753 | + 'EventEspresso\core\services\routing\RouteHandler' => EE_Dependency_Map::load_from_cache, |
|
| 754 | + ], |
|
| 755 | + 'EventEspresso\core\services\assets\AssetManifest' => [ |
|
| 756 | + 'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache, |
|
| 757 | + ], |
|
| 758 | + 'EventEspresso\core\services\assets\AssetManifestFactory' => [ |
|
| 759 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 760 | + ], |
|
| 761 | + 'EventEspresso\core\services\assets\BaristaFactory' => [ |
|
| 762 | + 'EventEspresso\core\services\assets\AssetManifestFactory' => EE_Dependency_Map::load_from_cache, |
|
| 763 | + 'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache, |
|
| 764 | + ], |
|
| 765 | + 'EventEspresso\core\domain\services\capabilities\FeatureFlags' => [ |
|
| 766 | + 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache, |
|
| 767 | + ], |
|
| 768 | + 'EventEspresso\core\services\addon\AddonManager' => [ |
|
| 769 | + 'EventEspresso\core\services\addon\AddonCollection' => EE_Dependency_Map::load_from_cache, |
|
| 770 | + 'EventEspresso\core\Psr4Autoloader' => EE_Dependency_Map::load_from_cache, |
|
| 771 | + 'EventEspresso\core\services\addon\api\v1\RegisterAddon' => EE_Dependency_Map::load_from_cache, |
|
| 772 | + 'EventEspresso\core\services\addon\api\IncompatibleAddonHandler' => EE_Dependency_Map::load_from_cache, |
|
| 773 | + 'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler' => EE_Dependency_Map::load_from_cache, |
|
| 774 | + ], |
|
| 775 | + 'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler' => [ |
|
| 776 | + 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, |
|
| 777 | + ], |
|
| 778 | + 'EventEspressoBatchRequest\JobHandlers\ExecuteBatchDeletion' => [ |
|
| 779 | + 'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache |
|
| 780 | + ], |
|
| 781 | + 'EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion' => [ |
|
| 782 | + 'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache |
|
| 783 | + ], |
|
| 784 | + 'EventEspresso\core\domain\services\admin\events\data\PreviewDeletion' => [ |
|
| 785 | + 'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache, |
|
| 786 | + 'EEM_Event' => EE_Dependency_Map::load_from_cache, |
|
| 787 | + 'EEM_Datetime' => EE_Dependency_Map::load_from_cache, |
|
| 788 | + 'EEM_Registration' => EE_Dependency_Map::load_from_cache |
|
| 789 | + ], |
|
| 790 | + 'EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion' => [ |
|
| 791 | + 'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache, |
|
| 792 | + ], |
|
| 793 | + 'EventEspresso\core\domain\entities\users\CurrentUser' => [ |
|
| 794 | + 'EventEspresso\core\domain\entities\users\EventManagers' => EE_Dependency_Map::load_from_cache, |
|
| 795 | + ], |
|
| 796 | + 'EventEspresso\core\services\form\meta\InputTypes' => [ |
|
| 797 | + 'EventEspresso\core\services\form\meta\inputs\Block' => EE_Dependency_Map::load_from_cache, |
|
| 798 | + 'EventEspresso\core\services\form\meta\inputs\Button' => EE_Dependency_Map::load_from_cache, |
|
| 799 | + 'EventEspresso\core\services\form\meta\inputs\DateTime' => EE_Dependency_Map::load_from_cache, |
|
| 800 | + 'EventEspresso\core\services\form\meta\inputs\Input' => EE_Dependency_Map::load_from_cache, |
|
| 801 | + 'EventEspresso\core\services\form\meta\inputs\Number' => EE_Dependency_Map::load_from_cache, |
|
| 802 | + 'EventEspresso\core\services\form\meta\inputs\Phone' => EE_Dependency_Map::load_from_cache, |
|
| 803 | + 'EventEspresso\core\services\form\meta\inputs\Select' => EE_Dependency_Map::load_from_cache, |
|
| 804 | + 'EventEspresso\core\services\form\meta\inputs\Text' => EE_Dependency_Map::load_from_cache, |
|
| 805 | + ], |
|
| 806 | + 'EventEspresso\core\domain\services\registration\form\v1\RegFormDependencyHandler' => [ |
|
| 807 | + 'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache, |
|
| 808 | + ], |
|
| 809 | + 'EventEspresso\core\services\calculators\LineItemCalculator' => [ |
|
| 810 | + 'EventEspresso\core\services\helpers\DecimalValues' => EE_Dependency_Map::load_from_cache, |
|
| 811 | + ], |
|
| 812 | + 'EventEspresso\core\services\helpers\DecimalValues' => [ |
|
| 813 | + 'EE_Currency_Config' => EE_Dependency_Map::load_from_cache, |
|
| 814 | + ], |
|
| 815 | + ]; |
|
| 816 | + } |
|
| 817 | + |
|
| 818 | + |
|
| 819 | + /** |
|
| 820 | + * Registers how core classes are loaded. |
|
| 821 | + * This can either be done by simply providing the name of one of the EE_Registry loader methods such as: |
|
| 822 | + * 'EE_Request_Handler' => 'load_core' |
|
| 823 | + * 'EE_Messages_Queue' => 'load_lib' |
|
| 824 | + * 'EEH_Debug_Tools' => 'load_helper' |
|
| 825 | + * or, if greater control is required, by providing a custom closure. For example: |
|
| 826 | + * 'Some_Class' => function () { |
|
| 827 | + * return new Some_Class(); |
|
| 828 | + * }, |
|
| 829 | + * This is required for instantiating dependencies |
|
| 830 | + * where an interface has been type hinted in a class constructor. For example: |
|
| 831 | + * 'Required_Interface' => function () { |
|
| 832 | + * return new A_Class_That_Implements_Required_Interface(); |
|
| 833 | + * }, |
|
| 834 | + */ |
|
| 835 | + protected function _register_core_class_loaders() |
|
| 836 | + { |
|
| 837 | + $this->_class_loaders = [ |
|
| 838 | + // load_core |
|
| 839 | + 'EE_Dependency_Map' => function () { |
|
| 840 | + return $this; |
|
| 841 | + }, |
|
| 842 | + 'EE_Capabilities' => 'load_core', |
|
| 843 | + 'EE_Encryption' => 'load_core', |
|
| 844 | + 'EE_Front_Controller' => 'load_core', |
|
| 845 | + 'EE_Module_Request_Router' => 'load_core', |
|
| 846 | + 'EE_Registry' => 'load_core', |
|
| 847 | + 'EE_Request' => function () { |
|
| 848 | + return $this->legacy_request; |
|
| 849 | + }, |
|
| 850 | + 'EventEspresso\core\services\request\Request' => function () { |
|
| 851 | + return $this->request; |
|
| 852 | + }, |
|
| 853 | + 'EventEspresso\core\services\request\Response' => function () { |
|
| 854 | + return $this->response; |
|
| 855 | + }, |
|
| 856 | + 'EE_Base' => 'load_core', |
|
| 857 | + 'EE_Request_Handler' => 'load_core', |
|
| 858 | + 'EE_Session' => 'load_core', |
|
| 859 | + 'EE_Cron_Tasks' => 'load_core', |
|
| 860 | + 'EE_System' => 'load_core', |
|
| 861 | + 'EE_Maintenance_Mode' => 'load_core', |
|
| 862 | + 'EE_Register_CPTs' => 'load_core', |
|
| 863 | + 'EE_Admin' => 'load_core', |
|
| 864 | + 'EE_CPT_Strategy' => 'load_core', |
|
| 865 | + // load_class |
|
| 866 | + 'EE_Registration_Processor' => 'load_class', |
|
| 867 | + // load_lib |
|
| 868 | + 'EE_Message_Resource_Manager' => 'load_lib', |
|
| 869 | + 'EE_Message_Type_Collection' => 'load_lib', |
|
| 870 | + 'EE_Message_Type_Collection_Loader' => 'load_lib', |
|
| 871 | + 'EE_Messenger_Collection' => 'load_lib', |
|
| 872 | + 'EE_Messenger_Collection_Loader' => 'load_lib', |
|
| 873 | + 'EE_Messages_Processor' => 'load_lib', |
|
| 874 | + 'EE_Message_Repository' => 'load_lib', |
|
| 875 | + 'EE_Messages_Queue' => 'load_lib', |
|
| 876 | + 'EE_Messages_Data_Handler_Collection' => 'load_lib', |
|
| 877 | + 'EE_Message_Template_Group_Collection' => 'load_lib', |
|
| 878 | + 'EE_Payment_Method_Manager' => 'load_lib', |
|
| 879 | + 'EE_DMS_Core_4_1_0' => 'load_dms', |
|
| 880 | + 'EE_DMS_Core_4_2_0' => 'load_dms', |
|
| 881 | + 'EE_DMS_Core_4_3_0' => 'load_dms', |
|
| 882 | + 'EE_DMS_Core_4_5_0' => 'load_dms', |
|
| 883 | + 'EE_DMS_Core_4_6_0' => 'load_dms', |
|
| 884 | + 'EE_DMS_Core_4_7_0' => 'load_dms', |
|
| 885 | + 'EE_DMS_Core_4_8_0' => 'load_dms', |
|
| 886 | + 'EE_DMS_Core_4_9_0' => 'load_dms', |
|
| 887 | + 'EE_DMS_Core_4_10_0' => 'load_dms', |
|
| 888 | + 'EE_DMS_Core_4_11_0' => 'load_dms', |
|
| 889 | + 'EE_DMS_Core_4_12_0' => 'load_dms', |
|
| 890 | + 'EE_Messages_Generator' => static function () { |
|
| 891 | + return EE_Registry::instance()->load_lib( |
|
| 892 | + 'Messages_Generator', |
|
| 893 | + [], |
|
| 894 | + false, |
|
| 895 | + false |
|
| 896 | + ); |
|
| 897 | + }, |
|
| 898 | + 'EE_Messages_Template_Defaults' => static function ($arguments = []) { |
|
| 899 | + return EE_Registry::instance()->load_lib( |
|
| 900 | + 'Messages_Template_Defaults', |
|
| 901 | + $arguments, |
|
| 902 | + false, |
|
| 903 | + false |
|
| 904 | + ); |
|
| 905 | + }, |
|
| 906 | + // load_helper |
|
| 907 | + 'EEH_Parse_Shortcodes' => static function () { |
|
| 908 | + if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) { |
|
| 909 | + return new EEH_Parse_Shortcodes(); |
|
| 910 | + } |
|
| 911 | + return null; |
|
| 912 | + }, |
|
| 913 | + 'EE_Template_Config' => static function () { |
|
| 914 | + return EE_Config::instance()->template_settings; |
|
| 915 | + }, |
|
| 916 | + 'EE_Currency_Config' => static function () { |
|
| 917 | + return EE_Config::instance()->currency; |
|
| 918 | + }, |
|
| 919 | + 'EE_Registration_Config' => static function () { |
|
| 920 | + return EE_Config::instance()->registration; |
|
| 921 | + }, |
|
| 922 | + 'EE_Core_Config' => static function () { |
|
| 923 | + return EE_Config::instance()->core; |
|
| 924 | + }, |
|
| 925 | + 'EventEspresso\core\services\loaders\Loader' => static function () { |
|
| 926 | + return LoaderFactory::getLoader(); |
|
| 927 | + }, |
|
| 928 | + 'EE_Network_Config' => static function () { |
|
| 929 | + return EE_Network_Config::instance(); |
|
| 930 | + }, |
|
| 931 | + 'EE_Config' => static function () { |
|
| 932 | + return EE_Config::instance(); |
|
| 933 | + }, |
|
| 934 | + 'EventEspresso\core\domain\Domain' => static function () { |
|
| 935 | + return DomainFactory::getEventEspressoCoreDomain(); |
|
| 936 | + }, |
|
| 937 | + 'EE_Admin_Config' => static function () { |
|
| 938 | + return EE_Config::instance()->admin; |
|
| 939 | + }, |
|
| 940 | + 'EE_Organization_Config' => static function () { |
|
| 941 | + return EE_Config::instance()->organization; |
|
| 942 | + }, |
|
| 943 | + 'EE_Network_Core_Config' => static function () { |
|
| 944 | + return EE_Network_Config::instance()->core; |
|
| 945 | + }, |
|
| 946 | + 'EE_Environment_Config' => static function () { |
|
| 947 | + return EE_Config::instance()->environment; |
|
| 948 | + }, |
|
| 949 | + 'EED_Core_Rest_Api' => static function () { |
|
| 950 | + return EED_Core_Rest_Api::instance(); |
|
| 951 | + }, |
|
| 952 | + 'WP_REST_Server' => static function () { |
|
| 953 | + return rest_get_server(); |
|
| 954 | + }, |
|
| 955 | + 'EventEspresso\core\Psr4Autoloader' => static function () { |
|
| 956 | + return EE_Psr4AutoloaderInit::psr4_loader(); |
|
| 957 | + }, |
|
| 958 | + ]; |
|
| 959 | + } |
|
| 960 | + |
|
| 961 | + |
|
| 962 | + /** |
|
| 963 | + * can be used for supplying alternate names for classes, |
|
| 964 | + * or for connecting interface names to instantiable classes |
|
| 965 | + * |
|
| 966 | + * @throws InvalidAliasException |
|
| 967 | + */ |
|
| 968 | + protected function _register_core_aliases() |
|
| 969 | + { |
|
| 970 | + $aliases = [ |
|
| 971 | + 'CommandBusInterface' => 'EventEspresso\core\services\commands\CommandBusInterface', |
|
| 972 | + 'EventEspresso\core\services\commands\CommandBusInterface' => 'EventEspresso\core\services\commands\CommandBus', |
|
| 973 | + 'CommandHandlerManagerInterface' => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface', |
|
| 974 | + 'EventEspresso\core\services\commands\CommandHandlerManagerInterface' => 'EventEspresso\core\services\commands\CommandHandlerManager', |
|
| 975 | + 'CapChecker' => 'EventEspresso\core\services\commands\middleware\CapChecker', |
|
| 976 | + 'AddActionHook' => 'EventEspresso\core\services\commands\middleware\AddActionHook', |
|
| 977 | + 'CapabilitiesChecker' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker', |
|
| 978 | + 'CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface', |
|
| 979 | + 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker', |
|
| 980 | + 'CreateRegistrationService' => 'EventEspresso\core\domain\services\registration\CreateRegistrationService', |
|
| 981 | + 'CreateRegistrationCommandHandler' => 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand', |
|
| 982 | + 'CopyRegistrationDetailsCommandHandler' => 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommand', |
|
| 983 | + 'CopyRegistrationPaymentsCommandHandler' => 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommand', |
|
| 984 | + 'CancelRegistrationAndTicketLineItemCommandHandler' => 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler', |
|
| 985 | + 'UpdateRegistrationAndTransactionAfterChangeCommandHandler' => 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler', |
|
| 986 | + 'CreateTicketLineItemCommandHandler' => 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommand', |
|
| 987 | + 'CreateTransactionCommandHandler' => 'EventEspresso\core\services\commands\transaction\CreateTransactionCommandHandler', |
|
| 988 | + 'CreateAttendeeCommandHandler' => 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler', |
|
| 989 | + 'TableManager' => 'EventEspresso\core\services\database\TableManager', |
|
| 990 | + 'TableAnalysis' => 'EventEspresso\core\services\database\TableAnalysis', |
|
| 991 | + 'EspressoShortcode' => 'EventEspresso\core\services\shortcodes\EspressoShortcode', |
|
| 992 | + 'ShortcodeInterface' => 'EventEspresso\core\services\shortcodes\ShortcodeInterface', |
|
| 993 | + 'EventEspresso\core\services\shortcodes\ShortcodeInterface' => 'EventEspresso\core\services\shortcodes\EspressoShortcode', |
|
| 994 | + 'EventEspresso\core\services\cache\CacheStorageInterface' => 'EventEspresso\core\services\cache\TransientCacheStorage', |
|
| 995 | + 'LoaderInterface' => 'EventEspresso\core\services\loaders\LoaderInterface', |
|
| 996 | + 'EventEspresso\core\services\loaders\LoaderInterface' => 'EventEspresso\core\services\loaders\Loader', |
|
| 997 | + 'CommandFactoryInterface' => 'EventEspresso\core\services\commands\CommandFactoryInterface', |
|
| 998 | + 'EventEspresso\core\services\commands\CommandFactoryInterface' => 'EventEspresso\core\services\commands\CommandFactory', |
|
| 999 | + 'EmailValidatorInterface' => 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface', |
|
| 1000 | + 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface' => 'EventEspresso\core\domain\services\validation\email\EmailValidationService', |
|
| 1001 | + 'NoticeConverterInterface' => 'EventEspresso\core\services\notices\NoticeConverterInterface', |
|
| 1002 | + 'EventEspresso\core\services\notices\NoticeConverterInterface' => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors', |
|
| 1003 | + 'NoticesContainerInterface' => 'EventEspresso\core\services\notices\NoticesContainerInterface', |
|
| 1004 | + 'EventEspresso\core\services\notices\NoticesContainerInterface' => 'EventEspresso\core\services\notices\NoticesContainer', |
|
| 1005 | + 'EventEspresso\core\services\request\RequestInterface' => 'EventEspresso\core\services\request\Request', |
|
| 1006 | + 'EventEspresso\core\services\request\ResponseInterface' => 'EventEspresso\core\services\request\Response', |
|
| 1007 | + 'EventEspresso\core\domain\DomainInterface' => 'EventEspresso\core\domain\Domain', |
|
| 1008 | + 'Registration_Processor' => 'EE_Registration_Processor', |
|
| 1009 | + 'EventEspresso\core\services\assets\AssetManifestInterface' => 'EventEspresso\core\services\assets\AssetManifest', |
|
| 1010 | + ]; |
|
| 1011 | + foreach ($aliases as $alias => $fqn) { |
|
| 1012 | + if (is_array($fqn)) { |
|
| 1013 | + foreach ($fqn as $class => $for_class) { |
|
| 1014 | + $this->class_cache->addAlias($class, $alias, $for_class); |
|
| 1015 | + } |
|
| 1016 | + continue; |
|
| 1017 | + } |
|
| 1018 | + $this->class_cache->addAlias($fqn, $alias); |
|
| 1019 | + } |
|
| 1020 | + if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) { |
|
| 1021 | + $this->class_cache->addAlias( |
|
| 1022 | + 'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices', |
|
| 1023 | + 'EventEspresso\core\services\notices\NoticeConverterInterface' |
|
| 1024 | + ); |
|
| 1025 | + } |
|
| 1026 | + } |
|
| 1027 | + |
|
| 1028 | + |
|
| 1029 | + /** |
|
| 1030 | + * This is used to reset the internal map and class_loaders to their original default state at the beginning of the |
|
| 1031 | + * request Primarily used by unit tests. |
|
| 1032 | + */ |
|
| 1033 | + public function reset() |
|
| 1034 | + { |
|
| 1035 | + $this->_register_core_class_loaders(); |
|
| 1036 | + $this->_register_core_dependencies(); |
|
| 1037 | + } |
|
| 1038 | + |
|
| 1039 | + |
|
| 1040 | + /** |
|
| 1041 | + * PLZ NOTE: a better name for this method would be is_alias() |
|
| 1042 | + * because it returns TRUE if the provided fully qualified name IS an alias |
|
| 1043 | + * WHY? |
|
| 1044 | + * Because if a class is type hinting for a concretion, |
|
| 1045 | + * then why would we need to find another class to supply it? |
|
| 1046 | + * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`, |
|
| 1047 | + * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`. |
|
| 1048 | + * Don't go looking for some substitute. |
|
| 1049 | + * Whereas if a class is type hinting for an interface... |
|
| 1050 | + * then we need to find an actual class to use. |
|
| 1051 | + * So the interface IS the alias for some other FQN, |
|
| 1052 | + * and we need to find out if `Fully/Qualified/Namespace/SomeInterface` |
|
| 1053 | + * represents some other class. |
|
| 1054 | + * |
|
| 1055 | + * @param string $fqn |
|
| 1056 | + * @param string $for_class |
|
| 1057 | + * @return bool |
|
| 1058 | + * @deprecated 4.9.62.p |
|
| 1059 | + */ |
|
| 1060 | + public function has_alias($fqn = '', $for_class = '') |
|
| 1061 | + { |
|
| 1062 | + return $this->isAlias($fqn, $for_class); |
|
| 1063 | + } |
|
| 1064 | + |
|
| 1065 | + |
|
| 1066 | + /** |
|
| 1067 | + * PLZ NOTE: a better name for this method would be get_fqn_for_alias() |
|
| 1068 | + * because it returns a FQN for provided alias if one exists, otherwise returns the original $alias |
|
| 1069 | + * functions recursively, so that multiple aliases can be used to drill down to a FQN |
|
| 1070 | + * for example: |
|
| 1071 | + * if the following two entries were added to the _aliases array: |
|
| 1072 | + * array( |
|
| 1073 | + * 'interface_alias' => 'some\namespace\interface' |
|
| 1074 | + * 'some\namespace\interface' => 'some\namespace\classname' |
|
| 1075 | + * ) |
|
| 1076 | + * then one could use EE_Registry::instance()->create( 'interface_alias' ) |
|
| 1077 | + * to load an instance of 'some\namespace\classname' |
|
| 1078 | + * |
|
| 1079 | + * @param string $alias |
|
| 1080 | + * @param string $for_class |
|
| 1081 | + * @return string |
|
| 1082 | + * @deprecated 4.9.62.p |
|
| 1083 | + */ |
|
| 1084 | + public function get_alias($alias = '', $for_class = '') |
|
| 1085 | + { |
|
| 1086 | + return $this->getFqnForAlias($alias, $for_class); |
|
| 1087 | + } |
|
| 1088 | 1088 | } |
@@ -21,2132 +21,2132 @@ |
||
| 21 | 21 | */ |
| 22 | 22 | class EEH_Line_Item |
| 23 | 23 | { |
| 24 | - /** |
|
| 25 | - * @var EE_Line_Item[] |
|
| 26 | - */ |
|
| 27 | - private static $global_taxes; |
|
| 28 | - |
|
| 29 | - |
|
| 30 | - /** |
|
| 31 | - * Adds a simple item (unrelated to any other model object) to the provided PARENT line item. |
|
| 32 | - * Does NOT automatically re-calculate the line item totals or update the related transaction. |
|
| 33 | - * You should call recalculate_total_including_taxes() on the grant total line item after this |
|
| 34 | - * to update the subtotals, and EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
| 35 | - * to keep the registration final prices in-sync with the transaction's total. |
|
| 36 | - * |
|
| 37 | - * @param EE_Line_Item $parent_line_item |
|
| 38 | - * @param string $name |
|
| 39 | - * @param float $unit_price |
|
| 40 | - * @param string $description |
|
| 41 | - * @param int $quantity |
|
| 42 | - * @param boolean $taxable |
|
| 43 | - * @param string|null $code if set to a value, ensures there is only one line item with that code |
|
| 44 | - * @param bool $return_item |
|
| 45 | - * @param bool $recalculate_totals |
|
| 46 | - * @return boolean|EE_Line_Item success |
|
| 47 | - * @throws EE_Error |
|
| 48 | - * @throws ReflectionException |
|
| 49 | - */ |
|
| 50 | - public static function add_unrelated_item( |
|
| 51 | - EE_Line_Item $parent_line_item, |
|
| 52 | - string $name, |
|
| 53 | - float $unit_price, |
|
| 54 | - string $description = '', |
|
| 55 | - int $quantity = 1, |
|
| 56 | - bool $taxable = false, |
|
| 57 | - ?string $code = null, |
|
| 58 | - bool $return_item = false, |
|
| 59 | - bool $recalculate_totals = true |
|
| 60 | - ) { |
|
| 61 | - $items_subtotal = self::get_pre_tax_subtotal($parent_line_item); |
|
| 62 | - $line_item = EE_Line_Item::new_instance( |
|
| 63 | - [ |
|
| 64 | - 'LIN_name' => $name, |
|
| 65 | - 'LIN_desc' => $description, |
|
| 66 | - 'LIN_unit_price' => $unit_price, |
|
| 67 | - 'LIN_quantity' => $quantity, |
|
| 68 | - 'LIN_percent' => null, |
|
| 69 | - 'LIN_is_taxable' => $taxable, |
|
| 70 | - 'LIN_order' => $items_subtotal instanceof EE_Line_Item |
|
| 71 | - ? count($items_subtotal->children()) |
|
| 72 | - : 0, |
|
| 73 | - 'LIN_total' => (float) $unit_price * (int) $quantity, |
|
| 74 | - 'LIN_type' => EEM_Line_Item::type_line_item, |
|
| 75 | - 'LIN_code' => $code, |
|
| 76 | - ] |
|
| 77 | - ); |
|
| 78 | - $line_item = apply_filters( |
|
| 79 | - 'FHEE__EEH_Line_Item__add_unrelated_item__line_item', |
|
| 80 | - $line_item, |
|
| 81 | - $parent_line_item |
|
| 82 | - ); |
|
| 83 | - $added = self::add_item($parent_line_item, $line_item, $recalculate_totals); |
|
| 84 | - return $return_item ? $line_item : $added; |
|
| 85 | - } |
|
| 86 | - |
|
| 87 | - |
|
| 88 | - /** |
|
| 89 | - * Adds a simple item ( unrelated to any other model object) to the total line item, |
|
| 90 | - * in the correct spot in the line item tree. Does not automatically |
|
| 91 | - * re-calculate the line item totals, nor update the related transaction, nor upgrade the transaction's |
|
| 92 | - * registrations' final prices (which should probably change because of this). |
|
| 93 | - * You should call recalculate_total_including_taxes() on the grand total line item, then |
|
| 94 | - * update the transaction's total, and EE_Registration_Processor::update_registration_final_prices() |
|
| 95 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
| 96 | - * |
|
| 97 | - * @param EE_Line_Item $parent_line_item |
|
| 98 | - * @param string $name |
|
| 99 | - * @param float $percentage_amount |
|
| 100 | - * @param string $description |
|
| 101 | - * @param boolean $taxable |
|
| 102 | - * @param string|null $code |
|
| 103 | - * @param bool $return_item |
|
| 104 | - * @return boolean|EE_Line_Item success |
|
| 105 | - * @throws EE_Error |
|
| 106 | - * @throws ReflectionException |
|
| 107 | - */ |
|
| 108 | - public static function add_percentage_based_item( |
|
| 109 | - EE_Line_Item $parent_line_item, |
|
| 110 | - string $name, |
|
| 111 | - float $percentage_amount, |
|
| 112 | - string $description = '', |
|
| 113 | - bool $taxable = false, |
|
| 114 | - ?string $code = null, |
|
| 115 | - bool $return_item = false |
|
| 116 | - ) { |
|
| 117 | - $total = $percentage_amount * $parent_line_item->total() / 100; |
|
| 118 | - $line_item = EE_Line_Item::new_instance( |
|
| 119 | - [ |
|
| 120 | - 'LIN_name' => $name, |
|
| 121 | - 'LIN_desc' => $description, |
|
| 122 | - 'LIN_unit_price' => 0, |
|
| 123 | - 'LIN_percent' => $percentage_amount, |
|
| 124 | - 'LIN_quantity' => 1, |
|
| 125 | - 'LIN_is_taxable' => $taxable, |
|
| 126 | - 'LIN_total' => (float) $total, |
|
| 127 | - 'LIN_type' => EEM_Line_Item::type_line_item, |
|
| 128 | - 'LIN_parent' => $parent_line_item->ID(), |
|
| 129 | - 'LIN_code' => $code, |
|
| 130 | - ] |
|
| 131 | - ); |
|
| 132 | - $line_item = apply_filters( |
|
| 133 | - 'FHEE__EEH_Line_Item__add_percentage_based_item__line_item', |
|
| 134 | - $line_item |
|
| 135 | - ); |
|
| 136 | - $added = $parent_line_item->add_child_line_item($line_item, false); |
|
| 137 | - return $return_item ? $line_item : $added; |
|
| 138 | - } |
|
| 139 | - |
|
| 140 | - |
|
| 141 | - /** |
|
| 142 | - * Returns the new line item created by adding a purchase of the ticket |
|
| 143 | - * ensures that ticket line item is saved, and that cart total has been recalculated. |
|
| 144 | - * If this ticket has already been purchased, just increments its count. |
|
| 145 | - * Automatically re-calculates the line item totals and updates the related transaction. But |
|
| 146 | - * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
| 147 | - * should probably change because of this). |
|
| 148 | - * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
| 149 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
| 150 | - * |
|
| 151 | - * @param EE_Line_Item $total_line_item grand total line item of type EEM_Line_Item::type_total |
|
| 152 | - * @param EE_Ticket $ticket |
|
| 153 | - * @param int $qty |
|
| 154 | - * @return EE_Line_Item |
|
| 155 | - * @throws EE_Error |
|
| 156 | - * @throws InvalidArgumentException |
|
| 157 | - * @throws InvalidDataTypeException |
|
| 158 | - * @throws InvalidInterfaceException |
|
| 159 | - * @throws ReflectionException |
|
| 160 | - */ |
|
| 161 | - public static function add_ticket_purchase(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
| 162 | - { |
|
| 163 | - if (! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) { |
|
| 164 | - throw new EE_Error( |
|
| 165 | - sprintf( |
|
| 166 | - esc_html__( |
|
| 167 | - 'A valid line item total is required in order to add tickets. A line item of type "%s" was passed.', |
|
| 168 | - 'event_espresso' |
|
| 169 | - ), |
|
| 170 | - $ticket->ID(), |
|
| 171 | - $total_line_item->ID() |
|
| 172 | - ) |
|
| 173 | - ); |
|
| 174 | - } |
|
| 175 | - // either increment the qty for an existing ticket |
|
| 176 | - $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty); |
|
| 177 | - // or add a new one |
|
| 178 | - if (! $line_item instanceof EE_Line_Item) { |
|
| 179 | - $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty); |
|
| 180 | - } |
|
| 181 | - $total_line_item->recalculate_total_including_taxes(); |
|
| 182 | - return $line_item; |
|
| 183 | - } |
|
| 184 | - |
|
| 185 | - |
|
| 186 | - /** |
|
| 187 | - * Returns the new line item created by adding a purchase of the ticket |
|
| 188 | - * |
|
| 189 | - * @param EE_Line_Item $total_line_item |
|
| 190 | - * @param EE_Ticket $ticket |
|
| 191 | - * @param int $qty |
|
| 192 | - * @return EE_Line_Item |
|
| 193 | - * @throws EE_Error |
|
| 194 | - * @throws InvalidArgumentException |
|
| 195 | - * @throws InvalidDataTypeException |
|
| 196 | - * @throws InvalidInterfaceException |
|
| 197 | - * @throws ReflectionException |
|
| 198 | - */ |
|
| 199 | - public static function increment_ticket_qty_if_already_in_cart( |
|
| 200 | - EE_Line_Item $total_line_item, |
|
| 201 | - EE_Ticket $ticket, |
|
| 202 | - $qty = 1 |
|
| 203 | - ) { |
|
| 204 | - $line_item = null; |
|
| 205 | - if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) { |
|
| 206 | - $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item); |
|
| 207 | - foreach ((array) $ticket_line_items as $ticket_line_item) { |
|
| 208 | - if ( |
|
| 209 | - $ticket_line_item instanceof EE_Line_Item |
|
| 210 | - && (int) $ticket_line_item->OBJ_ID() === (int) $ticket->ID() |
|
| 211 | - ) { |
|
| 212 | - $line_item = $ticket_line_item; |
|
| 213 | - break; |
|
| 214 | - } |
|
| 215 | - } |
|
| 216 | - } |
|
| 217 | - if ($line_item instanceof EE_Line_Item) { |
|
| 218 | - EEH_Line_Item::increment_quantity($line_item, $qty); |
|
| 219 | - return $line_item; |
|
| 220 | - } |
|
| 221 | - return null; |
|
| 222 | - } |
|
| 223 | - |
|
| 224 | - |
|
| 225 | - /** |
|
| 226 | - * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
| 227 | - * Does NOT save or recalculate other line items totals |
|
| 228 | - * |
|
| 229 | - * @param EE_Line_Item $line_item |
|
| 230 | - * @param int $qty |
|
| 231 | - * @return void |
|
| 232 | - * @throws EE_Error |
|
| 233 | - * @throws InvalidArgumentException |
|
| 234 | - * @throws InvalidDataTypeException |
|
| 235 | - * @throws InvalidInterfaceException |
|
| 236 | - * @throws ReflectionException |
|
| 237 | - */ |
|
| 238 | - public static function increment_quantity(EE_Line_Item $line_item, $qty = 1) |
|
| 239 | - { |
|
| 240 | - if (! $line_item->is_percent()) { |
|
| 241 | - $qty += $line_item->quantity(); |
|
| 242 | - $line_item->set_quantity($qty); |
|
| 243 | - $line_item->set_total($line_item->unit_price() * $qty); |
|
| 244 | - $line_item->save(); |
|
| 245 | - } |
|
| 246 | - foreach ($line_item->children() as $child) { |
|
| 247 | - if ($child->is_sub_line_item()) { |
|
| 248 | - EEH_Line_Item::update_quantity($child, $qty); |
|
| 249 | - } |
|
| 250 | - } |
|
| 251 | - } |
|
| 252 | - |
|
| 253 | - |
|
| 254 | - /** |
|
| 255 | - * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
| 256 | - * Does NOT save or recalculate other line items totals |
|
| 257 | - * |
|
| 258 | - * @param EE_Line_Item $line_item |
|
| 259 | - * @param int $qty |
|
| 260 | - * @return void |
|
| 261 | - * @throws EE_Error |
|
| 262 | - * @throws InvalidArgumentException |
|
| 263 | - * @throws InvalidDataTypeException |
|
| 264 | - * @throws InvalidInterfaceException |
|
| 265 | - * @throws ReflectionException |
|
| 266 | - */ |
|
| 267 | - public static function decrement_quantity(EE_Line_Item $line_item, $qty = 1) |
|
| 268 | - { |
|
| 269 | - if (! $line_item->is_percent()) { |
|
| 270 | - $qty = $line_item->quantity() - $qty; |
|
| 271 | - $qty = max($qty, 0); |
|
| 272 | - $line_item->set_quantity($qty); |
|
| 273 | - $line_item->set_total($line_item->unit_price() * $qty); |
|
| 274 | - $line_item->save(); |
|
| 275 | - } |
|
| 276 | - foreach ($line_item->children() as $child) { |
|
| 277 | - if ($child->is_sub_line_item()) { |
|
| 278 | - EEH_Line_Item::update_quantity($child, $qty); |
|
| 279 | - } |
|
| 280 | - } |
|
| 281 | - } |
|
| 282 | - |
|
| 283 | - |
|
| 284 | - /** |
|
| 285 | - * Updates the line item and its children's quantities to the specified number. |
|
| 286 | - * Does NOT save them or recalculate totals. |
|
| 287 | - * |
|
| 288 | - * @param EE_Line_Item $line_item |
|
| 289 | - * @param int $new_quantity |
|
| 290 | - * @throws EE_Error |
|
| 291 | - * @throws InvalidArgumentException |
|
| 292 | - * @throws InvalidDataTypeException |
|
| 293 | - * @throws InvalidInterfaceException |
|
| 294 | - * @throws ReflectionException |
|
| 295 | - */ |
|
| 296 | - public static function update_quantity(EE_Line_Item $line_item, $new_quantity) |
|
| 297 | - { |
|
| 298 | - if (! $line_item->is_percent()) { |
|
| 299 | - $line_item->set_quantity($new_quantity); |
|
| 300 | - $line_item->set_total($line_item->unit_price() * $new_quantity); |
|
| 301 | - $line_item->save(); |
|
| 302 | - } |
|
| 303 | - foreach ($line_item->children() as $child) { |
|
| 304 | - if ($child->is_sub_line_item()) { |
|
| 305 | - EEH_Line_Item::update_quantity($child, $new_quantity); |
|
| 306 | - } |
|
| 307 | - } |
|
| 308 | - } |
|
| 309 | - |
|
| 310 | - |
|
| 311 | - /** |
|
| 312 | - * Returns the new line item created by adding a purchase of the ticket |
|
| 313 | - * |
|
| 314 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 315 | - * @param EE_Ticket $ticket |
|
| 316 | - * @param int $qty |
|
| 317 | - * @return EE_Line_Item |
|
| 318 | - * @throws EE_Error |
|
| 319 | - * @throws InvalidArgumentException |
|
| 320 | - * @throws InvalidDataTypeException |
|
| 321 | - * @throws InvalidInterfaceException |
|
| 322 | - * @throws ReflectionException |
|
| 323 | - */ |
|
| 324 | - public static function create_ticket_line_item(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
| 325 | - { |
|
| 326 | - $datetimes = $ticket->datetimes(); |
|
| 327 | - $first_datetime = reset($datetimes); |
|
| 328 | - $first_datetime_name = esc_html__('Event', 'event_espresso'); |
|
| 329 | - if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) { |
|
| 330 | - $first_datetime_name = $first_datetime->event()->name(); |
|
| 331 | - } |
|
| 332 | - $event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name); |
|
| 333 | - // get event subtotal line |
|
| 334 | - $events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket); |
|
| 335 | - $taxes = $ticket->tax_price_modifiers(); |
|
| 336 | - // add $ticket to cart |
|
| 337 | - $line_item = EE_Line_Item::new_instance(array( |
|
| 338 | - 'LIN_name' => $ticket->name(), |
|
| 339 | - 'LIN_desc' => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event, |
|
| 340 | - 'LIN_unit_price' => $ticket->price(), |
|
| 341 | - 'LIN_quantity' => $qty, |
|
| 342 | - 'LIN_is_taxable' => empty($taxes) && $ticket->taxable(), |
|
| 343 | - 'LIN_order' => count($events_sub_total->children()), |
|
| 344 | - 'LIN_total' => $ticket->price() * $qty, |
|
| 345 | - 'LIN_type' => EEM_Line_Item::type_line_item, |
|
| 346 | - 'OBJ_ID' => $ticket->ID(), |
|
| 347 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
| 348 | - )); |
|
| 349 | - $line_item = apply_filters( |
|
| 350 | - 'FHEE__EEH_Line_Item__create_ticket_line_item__line_item', |
|
| 351 | - $line_item |
|
| 352 | - ); |
|
| 353 | - if (!$line_item instanceof EE_Line_Item) { |
|
| 354 | - throw new DomainException( |
|
| 355 | - esc_html__('Invalid EE_Line_Item received.', 'event_espresso') |
|
| 356 | - ); |
|
| 357 | - } |
|
| 358 | - $events_sub_total->add_child_line_item($line_item); |
|
| 359 | - // now add the sub-line items |
|
| 360 | - $running_total = 0; |
|
| 361 | - $running_pre_tax_total = 0; |
|
| 362 | - foreach ($ticket->prices() as $price) { |
|
| 363 | - $sign = $price->is_discount() ? -1 : 1; |
|
| 364 | - $price_total = $price->is_percent() |
|
| 365 | - ? $running_pre_tax_total * $price->amount() / 100 |
|
| 366 | - : $price->amount() * $qty; |
|
| 367 | - if ($price->is_percent()) { |
|
| 368 | - $percent = $sign * $price->amount(); |
|
| 369 | - $unit_price = 0; |
|
| 370 | - } else { |
|
| 371 | - $percent = 0; |
|
| 372 | - $unit_price = $sign * $price->amount(); |
|
| 373 | - } |
|
| 374 | - $sub_line_item = EE_Line_Item::new_instance(array( |
|
| 375 | - 'LIN_name' => $price->name(), |
|
| 376 | - 'LIN_desc' => $price->desc(), |
|
| 377 | - 'LIN_quantity' => $price->is_percent() ? null : $qty, |
|
| 378 | - 'LIN_is_taxable' => false, |
|
| 379 | - 'LIN_order' => $price->order(), |
|
| 380 | - 'LIN_total' => $price_total, |
|
| 381 | - 'LIN_pretax' => 0, |
|
| 382 | - 'LIN_unit_price' => $unit_price, |
|
| 383 | - 'LIN_percent' => $percent, |
|
| 384 | - 'LIN_type' => $price->is_tax() ? EEM_Line_Item::type_sub_tax : EEM_Line_Item::type_sub_line_item, |
|
| 385 | - 'OBJ_ID' => $price->ID(), |
|
| 386 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PRICE, |
|
| 387 | - )); |
|
| 388 | - $sub_line_item = apply_filters( |
|
| 389 | - 'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item', |
|
| 390 | - $sub_line_item |
|
| 391 | - ); |
|
| 392 | - $running_total += $sign * $price_total; |
|
| 393 | - $running_pre_tax_total += ! $price->is_tax() ? $sign * $price_total : 0; |
|
| 394 | - $line_item->add_child_line_item($sub_line_item); |
|
| 395 | - } |
|
| 396 | - $line_item->setPretaxTotal($running_pre_tax_total); |
|
| 397 | - return $line_item; |
|
| 398 | - } |
|
| 399 | - |
|
| 400 | - |
|
| 401 | - /** |
|
| 402 | - * Adds the specified item under the pre-tax-sub-total line item. Automatically |
|
| 403 | - * re-calculates the line item totals and updates the related transaction. But |
|
| 404 | - * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
| 405 | - * should probably change because of this). |
|
| 406 | - * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
| 407 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
| 408 | - * |
|
| 409 | - * @param EE_Line_Item $total_line_item |
|
| 410 | - * @param EE_Line_Item $item to be added |
|
| 411 | - * @return boolean |
|
| 412 | - * @throws EE_Error |
|
| 413 | - * @throws InvalidArgumentException |
|
| 414 | - * @throws InvalidDataTypeException |
|
| 415 | - * @throws InvalidInterfaceException |
|
| 416 | - * @throws ReflectionException |
|
| 417 | - */ |
|
| 418 | - public static function add_item(EE_Line_Item $total_line_item, EE_Line_Item $item, $recalculate_totals = true) |
|
| 419 | - { |
|
| 420 | - $pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item); |
|
| 421 | - if ($pre_tax_subtotal instanceof EE_Line_Item) { |
|
| 422 | - $success = $pre_tax_subtotal->add_child_line_item($item); |
|
| 423 | - } else { |
|
| 424 | - return false; |
|
| 425 | - } |
|
| 426 | - if ($recalculate_totals) { |
|
| 427 | - $total_line_item->recalculate_total_including_taxes(); |
|
| 428 | - } |
|
| 429 | - return $success; |
|
| 430 | - } |
|
| 431 | - |
|
| 432 | - |
|
| 433 | - /** |
|
| 434 | - * cancels an existing ticket line item, |
|
| 435 | - * by decrementing it's quantity by 1 and adding a new "type_cancellation" sub-line-item. |
|
| 436 | - * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
| 437 | - * |
|
| 438 | - * @param EE_Line_Item $ticket_line_item |
|
| 439 | - * @param int $qty |
|
| 440 | - * @return bool success |
|
| 441 | - * @throws EE_Error |
|
| 442 | - * @throws InvalidArgumentException |
|
| 443 | - * @throws InvalidDataTypeException |
|
| 444 | - * @throws InvalidInterfaceException |
|
| 445 | - * @throws ReflectionException |
|
| 446 | - */ |
|
| 447 | - public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
| 448 | - { |
|
| 449 | - // validate incoming line_item |
|
| 450 | - if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
| 451 | - throw new EE_Error( |
|
| 452 | - sprintf( |
|
| 453 | - esc_html__( |
|
| 454 | - 'The supplied line item must have an Object Type of "Ticket", not %1$s.', |
|
| 455 | - 'event_espresso' |
|
| 456 | - ), |
|
| 457 | - $ticket_line_item->type() |
|
| 458 | - ) |
|
| 459 | - ); |
|
| 460 | - } |
|
| 461 | - if ($ticket_line_item->quantity() < $qty) { |
|
| 462 | - throw new EE_Error( |
|
| 463 | - sprintf( |
|
| 464 | - esc_html__( |
|
| 465 | - 'Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.', |
|
| 466 | - 'event_espresso' |
|
| 467 | - ), |
|
| 468 | - $qty, |
|
| 469 | - $ticket_line_item->quantity() |
|
| 470 | - ) |
|
| 471 | - ); |
|
| 472 | - } |
|
| 473 | - // decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this |
|
| 474 | - $ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty); |
|
| 475 | - foreach ($ticket_line_item->children() as $child_line_item) { |
|
| 476 | - if ( |
|
| 477 | - $child_line_item->is_sub_line_item() |
|
| 478 | - && ! $child_line_item->is_percent() |
|
| 479 | - && ! $child_line_item->is_cancellation() |
|
| 480 | - ) { |
|
| 481 | - $child_line_item->set_quantity($child_line_item->quantity() - $qty); |
|
| 482 | - } |
|
| 483 | - } |
|
| 484 | - // get cancellation sub line item |
|
| 485 | - $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
| 486 | - $ticket_line_item, |
|
| 487 | - EEM_Line_Item::type_cancellation |
|
| 488 | - ); |
|
| 489 | - $cancellation_line_item = reset($cancellation_line_item); |
|
| 490 | - // verify that this ticket was indeed previously cancelled |
|
| 491 | - if ($cancellation_line_item instanceof EE_Line_Item) { |
|
| 492 | - // increment cancelled quantity |
|
| 493 | - $cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty); |
|
| 494 | - } else { |
|
| 495 | - // create cancellation sub line item |
|
| 496 | - $cancellation_line_item = EE_Line_Item::new_instance(array( |
|
| 497 | - 'LIN_name' => esc_html__('Cancellation', 'event_espresso'), |
|
| 498 | - 'LIN_desc' => sprintf( |
|
| 499 | - esc_html_x( |
|
| 500 | - 'Cancelled %1$s : %2$s', |
|
| 501 | - 'Cancelled Ticket Name : 2015-01-01 11:11', |
|
| 502 | - 'event_espresso' |
|
| 503 | - ), |
|
| 504 | - $ticket_line_item->name(), |
|
| 505 | - current_time(get_option('date_format') . ' ' . get_option('time_format')) |
|
| 506 | - ), |
|
| 507 | - 'LIN_unit_price' => 0, // $ticket_line_item->unit_price() |
|
| 508 | - 'LIN_quantity' => $qty, |
|
| 509 | - 'LIN_is_taxable' => $ticket_line_item->is_taxable(), |
|
| 510 | - 'LIN_order' => count($ticket_line_item->children()), |
|
| 511 | - 'LIN_total' => 0, // $ticket_line_item->unit_price() |
|
| 512 | - 'LIN_type' => EEM_Line_Item::type_cancellation, |
|
| 513 | - )); |
|
| 514 | - $ticket_line_item->add_child_line_item($cancellation_line_item); |
|
| 515 | - } |
|
| 516 | - if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
| 517 | - // decrement parent line item quantity |
|
| 518 | - $event_line_item = $ticket_line_item->parent(); |
|
| 519 | - if ( |
|
| 520 | - $event_line_item instanceof EE_Line_Item |
|
| 521 | - && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
| 522 | - ) { |
|
| 523 | - $event_line_item->set_quantity($event_line_item->quantity() - $qty); |
|
| 524 | - $event_line_item->save(); |
|
| 525 | - } |
|
| 526 | - EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
| 527 | - return true; |
|
| 528 | - } |
|
| 529 | - return false; |
|
| 530 | - } |
|
| 531 | - |
|
| 532 | - |
|
| 533 | - /** |
|
| 534 | - * reinstates (un-cancels?) a previously canceled ticket line item, |
|
| 535 | - * by incrementing it's quantity by 1, and decrementing it's "type_cancellation" sub-line-item. |
|
| 536 | - * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
| 537 | - * |
|
| 538 | - * @param EE_Line_Item $ticket_line_item |
|
| 539 | - * @param int $qty |
|
| 540 | - * @return bool success |
|
| 541 | - * @throws EE_Error |
|
| 542 | - * @throws InvalidArgumentException |
|
| 543 | - * @throws InvalidDataTypeException |
|
| 544 | - * @throws InvalidInterfaceException |
|
| 545 | - * @throws ReflectionException |
|
| 546 | - */ |
|
| 547 | - public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
| 548 | - { |
|
| 549 | - // validate incoming line_item |
|
| 550 | - if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
| 551 | - throw new EE_Error( |
|
| 552 | - sprintf( |
|
| 553 | - esc_html__( |
|
| 554 | - 'The supplied line item must have an Object Type of "Ticket", not %1$s.', |
|
| 555 | - 'event_espresso' |
|
| 556 | - ), |
|
| 557 | - $ticket_line_item->type() |
|
| 558 | - ) |
|
| 559 | - ); |
|
| 560 | - } |
|
| 561 | - // get cancellation sub line item |
|
| 562 | - $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
| 563 | - $ticket_line_item, |
|
| 564 | - EEM_Line_Item::type_cancellation |
|
| 565 | - ); |
|
| 566 | - $cancellation_line_item = reset($cancellation_line_item); |
|
| 567 | - // verify that this ticket was indeed previously cancelled |
|
| 568 | - if (! $cancellation_line_item instanceof EE_Line_Item) { |
|
| 569 | - return false; |
|
| 570 | - } |
|
| 571 | - if ($cancellation_line_item->quantity() > $qty) { |
|
| 572 | - // decrement cancelled quantity |
|
| 573 | - $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
| 574 | - } elseif ($cancellation_line_item->quantity() === $qty) { |
|
| 575 | - // decrement cancelled quantity in case anyone still has the object kicking around |
|
| 576 | - $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
| 577 | - // delete because quantity will end up as 0 |
|
| 578 | - $cancellation_line_item->delete(); |
|
| 579 | - // and attempt to destroy the object, |
|
| 580 | - // even though PHP won't actually destroy it until it needs the memory |
|
| 581 | - unset($cancellation_line_item); |
|
| 582 | - } else { |
|
| 583 | - // what ?!?! negative quantity ?!?! |
|
| 584 | - throw new EE_Error( |
|
| 585 | - sprintf( |
|
| 586 | - esc_html__( |
|
| 587 | - 'Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.', |
|
| 588 | - 'event_espresso' |
|
| 589 | - ), |
|
| 590 | - $qty, |
|
| 591 | - $cancellation_line_item->quantity() |
|
| 592 | - ) |
|
| 593 | - ); |
|
| 594 | - } |
|
| 595 | - // increment ticket quantity |
|
| 596 | - $ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty); |
|
| 597 | - if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
| 598 | - // increment parent line item quantity |
|
| 599 | - $event_line_item = $ticket_line_item->parent(); |
|
| 600 | - if ( |
|
| 601 | - $event_line_item instanceof EE_Line_Item |
|
| 602 | - && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
| 603 | - ) { |
|
| 604 | - $event_line_item->set_quantity($event_line_item->quantity() + $qty); |
|
| 605 | - } |
|
| 606 | - EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
| 607 | - return true; |
|
| 608 | - } |
|
| 609 | - return false; |
|
| 610 | - } |
|
| 611 | - |
|
| 612 | - |
|
| 613 | - /** |
|
| 614 | - * calls EEH_Line_Item::find_transaction_grand_total_for_line_item() |
|
| 615 | - * then EE_Line_Item::recalculate_total_including_taxes() on the result |
|
| 616 | - * |
|
| 617 | - * @param EE_Line_Item $line_item |
|
| 618 | - * @return float |
|
| 619 | - * @throws EE_Error |
|
| 620 | - * @throws InvalidArgumentException |
|
| 621 | - * @throws InvalidDataTypeException |
|
| 622 | - * @throws InvalidInterfaceException |
|
| 623 | - * @throws ReflectionException |
|
| 624 | - */ |
|
| 625 | - public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item) |
|
| 626 | - { |
|
| 627 | - $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item); |
|
| 628 | - return $grand_total_line_item->recalculate_total_including_taxes(); |
|
| 629 | - } |
|
| 630 | - |
|
| 631 | - |
|
| 632 | - /** |
|
| 633 | - * Gets the line item which contains the subtotal of all the items |
|
| 634 | - * |
|
| 635 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 636 | - * @return EE_Line_Item |
|
| 637 | - * @throws EE_Error |
|
| 638 | - * @throws InvalidArgumentException |
|
| 639 | - * @throws InvalidDataTypeException |
|
| 640 | - * @throws InvalidInterfaceException |
|
| 641 | - * @throws ReflectionException |
|
| 642 | - */ |
|
| 643 | - public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item) |
|
| 644 | - { |
|
| 645 | - $pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal'); |
|
| 646 | - return $pre_tax_subtotal instanceof EE_Line_Item |
|
| 647 | - ? $pre_tax_subtotal |
|
| 648 | - : self::create_pre_tax_subtotal($total_line_item); |
|
| 649 | - } |
|
| 650 | - |
|
| 651 | - |
|
| 652 | - /** |
|
| 653 | - * Gets the line item for the taxes subtotal |
|
| 654 | - * |
|
| 655 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 656 | - * @return EE_Line_Item |
|
| 657 | - * @throws EE_Error |
|
| 658 | - * @throws InvalidArgumentException |
|
| 659 | - * @throws InvalidDataTypeException |
|
| 660 | - * @throws InvalidInterfaceException |
|
| 661 | - * @throws ReflectionException |
|
| 662 | - */ |
|
| 663 | - public static function get_taxes_subtotal(EE_Line_Item $total_line_item) |
|
| 664 | - { |
|
| 665 | - $taxes = $total_line_item->get_child_line_item('taxes'); |
|
| 666 | - return $taxes ? $taxes : self::create_taxes_subtotal($total_line_item); |
|
| 667 | - } |
|
| 668 | - |
|
| 669 | - |
|
| 670 | - /** |
|
| 671 | - * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object |
|
| 672 | - * |
|
| 673 | - * @param EE_Line_Item $line_item |
|
| 674 | - * @param EE_Transaction $transaction |
|
| 675 | - * @return void |
|
| 676 | - * @throws EE_Error |
|
| 677 | - * @throws InvalidArgumentException |
|
| 678 | - * @throws InvalidDataTypeException |
|
| 679 | - * @throws InvalidInterfaceException |
|
| 680 | - * @throws ReflectionException |
|
| 681 | - */ |
|
| 682 | - public static function set_TXN_ID(EE_Line_Item $line_item, $transaction = null) |
|
| 683 | - { |
|
| 684 | - if ($transaction) { |
|
| 685 | - /** @type EEM_Transaction $EEM_Transaction */ |
|
| 686 | - $EEM_Transaction = EE_Registry::instance()->load_model('Transaction'); |
|
| 687 | - $TXN_ID = $EEM_Transaction->ensure_is_ID($transaction); |
|
| 688 | - $line_item->set_TXN_ID($TXN_ID); |
|
| 689 | - } |
|
| 690 | - } |
|
| 691 | - |
|
| 692 | - |
|
| 693 | - /** |
|
| 694 | - * Creates a new default total line item for the transaction, |
|
| 695 | - * and its tickets subtotal and taxes subtotal line items (and adds the |
|
| 696 | - * existing taxes as children of the taxes subtotal line item) |
|
| 697 | - * |
|
| 698 | - * @param EE_Transaction $transaction |
|
| 699 | - * @return EE_Line_Item of type total |
|
| 700 | - * @throws EE_Error |
|
| 701 | - * @throws InvalidArgumentException |
|
| 702 | - * @throws InvalidDataTypeException |
|
| 703 | - * @throws InvalidInterfaceException |
|
| 704 | - * @throws ReflectionException |
|
| 705 | - */ |
|
| 706 | - public static function create_total_line_item($transaction = null) |
|
| 707 | - { |
|
| 708 | - $total_line_item = EE_Line_Item::new_instance(array( |
|
| 709 | - 'LIN_code' => 'total', |
|
| 710 | - 'LIN_name' => esc_html__('Grand Total', 'event_espresso'), |
|
| 711 | - 'LIN_type' => EEM_Line_Item::type_total, |
|
| 712 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TRANSACTION, |
|
| 713 | - )); |
|
| 714 | - $total_line_item = apply_filters( |
|
| 715 | - 'FHEE__EEH_Line_Item__create_total_line_item__total_line_item', |
|
| 716 | - $total_line_item |
|
| 717 | - ); |
|
| 718 | - self::set_TXN_ID($total_line_item, $transaction); |
|
| 719 | - self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
| 720 | - self::create_taxes_subtotal($total_line_item, $transaction); |
|
| 721 | - return $total_line_item; |
|
| 722 | - } |
|
| 723 | - |
|
| 724 | - |
|
| 725 | - /** |
|
| 726 | - * Creates a default items subtotal line item |
|
| 727 | - * |
|
| 728 | - * @param EE_Line_Item $total_line_item |
|
| 729 | - * @param EE_Transaction $transaction |
|
| 730 | - * @return EE_Line_Item |
|
| 731 | - * @throws EE_Error |
|
| 732 | - * @throws InvalidArgumentException |
|
| 733 | - * @throws InvalidDataTypeException |
|
| 734 | - * @throws InvalidInterfaceException |
|
| 735 | - * @throws ReflectionException |
|
| 736 | - */ |
|
| 737 | - protected static function create_pre_tax_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
| 738 | - { |
|
| 739 | - $pre_tax_line_item = EE_Line_Item::new_instance(array( |
|
| 740 | - 'LIN_code' => 'pre-tax-subtotal', |
|
| 741 | - 'LIN_name' => esc_html__('Pre-Tax Subtotal', 'event_espresso'), |
|
| 742 | - 'LIN_type' => EEM_Line_Item::type_sub_total, |
|
| 743 | - )); |
|
| 744 | - $pre_tax_line_item = apply_filters( |
|
| 745 | - 'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item', |
|
| 746 | - $pre_tax_line_item |
|
| 747 | - ); |
|
| 748 | - self::set_TXN_ID($pre_tax_line_item, $transaction); |
|
| 749 | - $total_line_item->add_child_line_item($pre_tax_line_item); |
|
| 750 | - self::create_event_subtotal($pre_tax_line_item, $transaction); |
|
| 751 | - return $pre_tax_line_item; |
|
| 752 | - } |
|
| 753 | - |
|
| 754 | - |
|
| 755 | - /** |
|
| 756 | - * Creates a line item for the taxes subtotal and finds all the tax prices |
|
| 757 | - * and applies taxes to it |
|
| 758 | - * |
|
| 759 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 760 | - * @param EE_Transaction $transaction |
|
| 761 | - * @return EE_Line_Item |
|
| 762 | - * @throws EE_Error |
|
| 763 | - * @throws InvalidArgumentException |
|
| 764 | - * @throws InvalidDataTypeException |
|
| 765 | - * @throws InvalidInterfaceException |
|
| 766 | - * @throws ReflectionException |
|
| 767 | - */ |
|
| 768 | - protected static function create_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
| 769 | - { |
|
| 770 | - $tax_line_item = EE_Line_Item::new_instance(array( |
|
| 771 | - 'LIN_code' => 'taxes', |
|
| 772 | - 'LIN_name' => esc_html__('Taxes', 'event_espresso'), |
|
| 773 | - 'LIN_type' => EEM_Line_Item::type_tax_sub_total, |
|
| 774 | - 'LIN_order' => 1000,// this should always come last |
|
| 775 | - )); |
|
| 776 | - $tax_line_item = apply_filters( |
|
| 777 | - 'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item', |
|
| 778 | - $tax_line_item |
|
| 779 | - ); |
|
| 780 | - self::set_TXN_ID($tax_line_item, $transaction); |
|
| 781 | - $total_line_item->add_child_line_item($tax_line_item); |
|
| 782 | - // and lastly, add the actual taxes |
|
| 783 | - self::apply_taxes($total_line_item); |
|
| 784 | - return $tax_line_item; |
|
| 785 | - } |
|
| 786 | - |
|
| 787 | - |
|
| 788 | - /** |
|
| 789 | - * Creates a default items subtotal line item |
|
| 790 | - * |
|
| 791 | - * @param EE_Line_Item $pre_tax_line_item |
|
| 792 | - * @param EE_Transaction $transaction |
|
| 793 | - * @param EE_Event $event |
|
| 794 | - * @return EE_Line_Item |
|
| 795 | - * @throws EE_Error |
|
| 796 | - * @throws InvalidArgumentException |
|
| 797 | - * @throws InvalidDataTypeException |
|
| 798 | - * @throws InvalidInterfaceException |
|
| 799 | - * @throws ReflectionException |
|
| 800 | - */ |
|
| 801 | - public static function create_event_subtotal(EE_Line_Item $pre_tax_line_item, $transaction = null, $event = null) |
|
| 802 | - { |
|
| 803 | - $event_line_item = EE_Line_Item::new_instance(array( |
|
| 804 | - 'LIN_code' => self::get_event_code($event), |
|
| 805 | - 'LIN_name' => self::get_event_name($event), |
|
| 806 | - 'LIN_desc' => self::get_event_desc($event), |
|
| 807 | - 'LIN_type' => EEM_Line_Item::type_sub_total, |
|
| 808 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_EVENT, |
|
| 809 | - 'OBJ_ID' => $event instanceof EE_Event ? $event->ID() : 0, |
|
| 810 | - )); |
|
| 811 | - $event_line_item = apply_filters( |
|
| 812 | - 'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item', |
|
| 813 | - $event_line_item |
|
| 814 | - ); |
|
| 815 | - self::set_TXN_ID($event_line_item, $transaction); |
|
| 816 | - $pre_tax_line_item->add_child_line_item($event_line_item); |
|
| 817 | - return $event_line_item; |
|
| 818 | - } |
|
| 819 | - |
|
| 820 | - |
|
| 821 | - /** |
|
| 822 | - * Gets what the event ticket's code SHOULD be |
|
| 823 | - * |
|
| 824 | - * @param EE_Event $event |
|
| 825 | - * @return string |
|
| 826 | - * @throws EE_Error |
|
| 827 | - */ |
|
| 828 | - public static function get_event_code($event) |
|
| 829 | - { |
|
| 830 | - return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0'); |
|
| 831 | - } |
|
| 832 | - |
|
| 833 | - |
|
| 834 | - /** |
|
| 835 | - * Gets the event name |
|
| 836 | - * |
|
| 837 | - * @param EE_Event $event |
|
| 838 | - * @return string |
|
| 839 | - * @throws EE_Error |
|
| 840 | - */ |
|
| 841 | - public static function get_event_name($event) |
|
| 842 | - { |
|
| 843 | - return $event instanceof EE_Event |
|
| 844 | - ? mb_substr($event->name(), 0, 245) |
|
| 845 | - : esc_html__('Event', 'event_espresso'); |
|
| 846 | - } |
|
| 847 | - |
|
| 848 | - |
|
| 849 | - /** |
|
| 850 | - * Gets the event excerpt |
|
| 851 | - * |
|
| 852 | - * @param EE_Event $event |
|
| 853 | - * @return string |
|
| 854 | - * @throws EE_Error |
|
| 855 | - */ |
|
| 856 | - public static function get_event_desc($event) |
|
| 857 | - { |
|
| 858 | - return $event instanceof EE_Event ? $event->short_description() : ''; |
|
| 859 | - } |
|
| 860 | - |
|
| 861 | - |
|
| 862 | - /** |
|
| 863 | - * Given the grand total line item and a ticket, finds the event sub-total |
|
| 864 | - * line item the ticket's purchase should be added onto |
|
| 865 | - * |
|
| 866 | - * @access public |
|
| 867 | - * @param EE_Line_Item $grand_total the grand total line item |
|
| 868 | - * @param EE_Ticket $ticket |
|
| 869 | - * @return EE_Line_Item |
|
| 870 | - * @throws EE_Error |
|
| 871 | - * @throws InvalidArgumentException |
|
| 872 | - * @throws InvalidDataTypeException |
|
| 873 | - * @throws InvalidInterfaceException |
|
| 874 | - * @throws ReflectionException |
|
| 875 | - */ |
|
| 876 | - public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket) |
|
| 877 | - { |
|
| 878 | - $first_datetime = $ticket->first_datetime(); |
|
| 879 | - if (! $first_datetime instanceof EE_Datetime) { |
|
| 880 | - throw new EE_Error( |
|
| 881 | - sprintf( |
|
| 882 | - __('The supplied ticket (ID %d) has no datetimes', 'event_espresso'), |
|
| 883 | - $ticket->ID() |
|
| 884 | - ) |
|
| 885 | - ); |
|
| 886 | - } |
|
| 887 | - $event = $first_datetime->event(); |
|
| 888 | - if (! $event instanceof EE_Event) { |
|
| 889 | - throw new EE_Error( |
|
| 890 | - sprintf( |
|
| 891 | - esc_html__( |
|
| 892 | - 'The supplied ticket (ID %d) has no event data associated with it.', |
|
| 893 | - 'event_espresso' |
|
| 894 | - ), |
|
| 895 | - $ticket->ID() |
|
| 896 | - ) |
|
| 897 | - ); |
|
| 898 | - } |
|
| 899 | - $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event); |
|
| 900 | - if (! $events_sub_total instanceof EE_Line_Item) { |
|
| 901 | - throw new EE_Error( |
|
| 902 | - sprintf( |
|
| 903 | - esc_html__( |
|
| 904 | - 'There is no events sub-total for ticket %s on total line item %d', |
|
| 905 | - 'event_espresso' |
|
| 906 | - ), |
|
| 907 | - $ticket->ID(), |
|
| 908 | - $grand_total->ID() |
|
| 909 | - ) |
|
| 910 | - ); |
|
| 911 | - } |
|
| 912 | - return $events_sub_total; |
|
| 913 | - } |
|
| 914 | - |
|
| 915 | - |
|
| 916 | - /** |
|
| 917 | - * Gets the event line item |
|
| 918 | - * |
|
| 919 | - * @param EE_Line_Item $grand_total |
|
| 920 | - * @param EE_Event $event |
|
| 921 | - * @return EE_Line_Item for the event subtotal which is a child of $grand_total |
|
| 922 | - * @throws EE_Error |
|
| 923 | - * @throws InvalidArgumentException |
|
| 924 | - * @throws InvalidDataTypeException |
|
| 925 | - * @throws InvalidInterfaceException |
|
| 926 | - * @throws ReflectionException |
|
| 927 | - */ |
|
| 928 | - public static function get_event_line_item(EE_Line_Item $grand_total, $event) |
|
| 929 | - { |
|
| 930 | - /** @type EE_Event $event */ |
|
| 931 | - $event = EEM_Event::instance()->ensure_is_obj($event, true); |
|
| 932 | - $event_line_item = null; |
|
| 933 | - $found = false; |
|
| 934 | - foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) { |
|
| 935 | - // default event subtotal, we should only ever find this the first time this method is called |
|
| 936 | - if (! $event_line_item->OBJ_ID()) { |
|
| 937 | - // let's use this! but first... set the event details |
|
| 938 | - EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
| 939 | - $found = true; |
|
| 940 | - break; |
|
| 941 | - } |
|
| 942 | - if ($event_line_item->OBJ_ID() === $event->ID()) { |
|
| 943 | - // found existing line item for this event in the cart, so break out of loop and use this one |
|
| 944 | - $found = true; |
|
| 945 | - break; |
|
| 946 | - } |
|
| 947 | - } |
|
| 948 | - if (! $found) { |
|
| 949 | - // there is no event sub-total yet, so add it |
|
| 950 | - $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total); |
|
| 951 | - // create a new "event" subtotal below that |
|
| 952 | - $event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event); |
|
| 953 | - // and set the event details |
|
| 954 | - EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
| 955 | - } |
|
| 956 | - return $event_line_item; |
|
| 957 | - } |
|
| 958 | - |
|
| 959 | - |
|
| 960 | - /** |
|
| 961 | - * Creates a default items subtotal line item |
|
| 962 | - * |
|
| 963 | - * @param EE_Line_Item $event_line_item |
|
| 964 | - * @param EE_Event $event |
|
| 965 | - * @param EE_Transaction $transaction |
|
| 966 | - * @return void |
|
| 967 | - * @throws EE_Error |
|
| 968 | - * @throws InvalidArgumentException |
|
| 969 | - * @throws InvalidDataTypeException |
|
| 970 | - * @throws InvalidInterfaceException |
|
| 971 | - * @throws ReflectionException |
|
| 972 | - */ |
|
| 973 | - public static function set_event_subtotal_details( |
|
| 974 | - EE_Line_Item $event_line_item, |
|
| 975 | - EE_Event $event, |
|
| 976 | - $transaction = null |
|
| 977 | - ) { |
|
| 978 | - if ($event instanceof EE_Event) { |
|
| 979 | - $event_line_item->set_code(self::get_event_code($event)); |
|
| 980 | - $event_line_item->set_name(self::get_event_name($event)); |
|
| 981 | - $event_line_item->set_desc(self::get_event_desc($event)); |
|
| 982 | - $event_line_item->set_OBJ_ID($event->ID()); |
|
| 983 | - } |
|
| 984 | - self::set_TXN_ID($event_line_item, $transaction); |
|
| 985 | - } |
|
| 986 | - |
|
| 987 | - |
|
| 988 | - /** |
|
| 989 | - * Finds what taxes should apply, adds them as tax line items under the taxes sub-total, |
|
| 990 | - * and recalculates the taxes sub-total and the grand total. Resets the taxes, so |
|
| 991 | - * any old taxes are removed |
|
| 992 | - * |
|
| 993 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 994 | - * @param bool $update_txn_status |
|
| 995 | - * @return bool |
|
| 996 | - * @throws EE_Error |
|
| 997 | - * @throws InvalidArgumentException |
|
| 998 | - * @throws InvalidDataTypeException |
|
| 999 | - * @throws InvalidInterfaceException |
|
| 1000 | - * @throws ReflectionException |
|
| 1001 | - * @throws RuntimeException |
|
| 1002 | - */ |
|
| 1003 | - public static function apply_taxes(EE_Line_Item $total_line_item, $update_txn_status = false) |
|
| 1004 | - { |
|
| 1005 | - $total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($total_line_item); |
|
| 1006 | - $taxes_line_item = self::get_taxes_subtotal($total_line_item); |
|
| 1007 | - $existing_global_taxes = $taxes_line_item->tax_descendants(); |
|
| 1008 | - $updates = false; |
|
| 1009 | - // loop thru taxes |
|
| 1010 | - $global_taxes = EEH_Line_Item::getGlobalTaxes(); |
|
| 1011 | - foreach ($global_taxes as $order => $taxes) { |
|
| 1012 | - foreach ($taxes as $tax) { |
|
| 1013 | - if ($tax instanceof EE_Price) { |
|
| 1014 | - $found = false; |
|
| 1015 | - // check if this is already an existing tax |
|
| 1016 | - foreach ($existing_global_taxes as $existing_global_tax) { |
|
| 1017 | - if ($tax->ID() === $existing_global_tax->OBJ_ID()) { |
|
| 1018 | - // maybe update the tax rate in case it has changed |
|
| 1019 | - if ($existing_global_tax->percent() !== $tax->amount()) { |
|
| 1020 | - $existing_global_tax->set_percent($tax->amount()); |
|
| 1021 | - $existing_global_tax->save(); |
|
| 1022 | - $updates = true; |
|
| 1023 | - } |
|
| 1024 | - $found = true; |
|
| 1025 | - break; |
|
| 1026 | - } |
|
| 1027 | - } |
|
| 1028 | - if (! $found) { |
|
| 1029 | - // add a new line item for this global tax |
|
| 1030 | - $tax_line_item = apply_filters( |
|
| 1031 | - 'FHEE__EEH_Line_Item__apply_taxes__tax_line_item', |
|
| 1032 | - EE_Line_Item::new_instance( |
|
| 1033 | - [ |
|
| 1034 | - 'LIN_name' => $tax->name(), |
|
| 1035 | - 'LIN_desc' => $tax->desc(), |
|
| 1036 | - 'LIN_percent' => $tax->amount(), |
|
| 1037 | - 'LIN_is_taxable' => false, |
|
| 1038 | - 'LIN_order' => $order, |
|
| 1039 | - 'LIN_total' => 0, |
|
| 1040 | - 'LIN_type' => EEM_Line_Item::type_tax, |
|
| 1041 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PRICE, |
|
| 1042 | - 'OBJ_ID' => $tax->ID(), |
|
| 1043 | - ] |
|
| 1044 | - ) |
|
| 1045 | - ); |
|
| 1046 | - $updates = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates; |
|
| 1047 | - } |
|
| 1048 | - } |
|
| 1049 | - } |
|
| 1050 | - } |
|
| 1051 | - // only recalculate totals if something changed |
|
| 1052 | - if ($updates) { |
|
| 1053 | - $total_line_item->recalculate_total_including_taxes($update_txn_status); |
|
| 1054 | - return true; |
|
| 1055 | - } |
|
| 1056 | - return false; |
|
| 1057 | - } |
|
| 1058 | - |
|
| 1059 | - |
|
| 1060 | - /** |
|
| 1061 | - * Ensures that taxes have been applied to the order, if not applies them. |
|
| 1062 | - * Returns the total amount of tax |
|
| 1063 | - * |
|
| 1064 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 1065 | - * @return float |
|
| 1066 | - * @throws EE_Error |
|
| 1067 | - * @throws InvalidArgumentException |
|
| 1068 | - * @throws InvalidDataTypeException |
|
| 1069 | - * @throws InvalidInterfaceException |
|
| 1070 | - * @throws ReflectionException |
|
| 1071 | - */ |
|
| 1072 | - public static function ensure_taxes_applied($total_line_item) |
|
| 1073 | - { |
|
| 1074 | - $taxes_subtotal = self::get_taxes_subtotal($total_line_item); |
|
| 1075 | - if (! $taxes_subtotal->children()) { |
|
| 1076 | - self::apply_taxes($total_line_item); |
|
| 1077 | - } |
|
| 1078 | - return $taxes_subtotal->total(); |
|
| 1079 | - } |
|
| 1080 | - |
|
| 1081 | - |
|
| 1082 | - /** |
|
| 1083 | - * Deletes ALL children of the passed line item |
|
| 1084 | - * |
|
| 1085 | - * @param EE_Line_Item $parent_line_item |
|
| 1086 | - * @return bool |
|
| 1087 | - * @throws EE_Error |
|
| 1088 | - * @throws InvalidArgumentException |
|
| 1089 | - * @throws InvalidDataTypeException |
|
| 1090 | - * @throws InvalidInterfaceException |
|
| 1091 | - * @throws ReflectionException |
|
| 1092 | - */ |
|
| 1093 | - public static function delete_all_child_items(EE_Line_Item $parent_line_item) |
|
| 1094 | - { |
|
| 1095 | - $deleted = 0; |
|
| 1096 | - foreach ($parent_line_item->children() as $child_line_item) { |
|
| 1097 | - if ($child_line_item instanceof EE_Line_Item) { |
|
| 1098 | - $deleted += EEH_Line_Item::delete_all_child_items($child_line_item); |
|
| 1099 | - if ($child_line_item->ID()) { |
|
| 1100 | - $child_line_item->delete(); |
|
| 1101 | - unset($child_line_item); |
|
| 1102 | - } else { |
|
| 1103 | - $parent_line_item->delete_child_line_item($child_line_item->code()); |
|
| 1104 | - } |
|
| 1105 | - $deleted++; |
|
| 1106 | - } |
|
| 1107 | - } |
|
| 1108 | - return $deleted; |
|
| 1109 | - } |
|
| 1110 | - |
|
| 1111 | - |
|
| 1112 | - /** |
|
| 1113 | - * Deletes the line items as indicated by the line item code(s) provided, |
|
| 1114 | - * regardless of where they're found in the line item tree. Automatically |
|
| 1115 | - * re-calculates the line item totals and updates the related transaction. But |
|
| 1116 | - * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
| 1117 | - * should probably change because of this). |
|
| 1118 | - * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
| 1119 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
| 1120 | - * |
|
| 1121 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 1122 | - * @param array|bool|string $line_item_codes |
|
| 1123 | - * @return int number of items successfully removed |
|
| 1124 | - * @throws EE_Error |
|
| 1125 | - */ |
|
| 1126 | - public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = false) |
|
| 1127 | - { |
|
| 1128 | - |
|
| 1129 | - if ($total_line_item->type() !== EEM_Line_Item::type_total) { |
|
| 1130 | - EE_Error::doing_it_wrong( |
|
| 1131 | - 'EEH_Line_Item::delete_items', |
|
| 1132 | - esc_html__( |
|
| 1133 | - 'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly', |
|
| 1134 | - 'event_espresso' |
|
| 1135 | - ), |
|
| 1136 | - '4.6.18' |
|
| 1137 | - ); |
|
| 1138 | - } |
|
| 1139 | - do_action('AHEE_log', __FILE__, __FUNCTION__, ''); |
|
| 1140 | - |
|
| 1141 | - // check if only a single line_item_id was passed |
|
| 1142 | - if (! empty($line_item_codes) && ! is_array($line_item_codes)) { |
|
| 1143 | - // place single line_item_id in an array to appear as multiple line_item_ids |
|
| 1144 | - $line_item_codes = array($line_item_codes); |
|
| 1145 | - } |
|
| 1146 | - $removals = 0; |
|
| 1147 | - // cycle thru line_item_ids |
|
| 1148 | - foreach ($line_item_codes as $line_item_id) { |
|
| 1149 | - $removals += $total_line_item->delete_child_line_item($line_item_id); |
|
| 1150 | - } |
|
| 1151 | - |
|
| 1152 | - if ($removals > 0) { |
|
| 1153 | - $total_line_item->recalculate_taxes_and_tax_total(); |
|
| 1154 | - return $removals; |
|
| 1155 | - } else { |
|
| 1156 | - return false; |
|
| 1157 | - } |
|
| 1158 | - } |
|
| 1159 | - |
|
| 1160 | - |
|
| 1161 | - /** |
|
| 1162 | - * Overwrites the previous tax by clearing out the old taxes, and creates a new |
|
| 1163 | - * tax and updates the total line item accordingly |
|
| 1164 | - * |
|
| 1165 | - * @param EE_Line_Item $total_line_item |
|
| 1166 | - * @param float $amount |
|
| 1167 | - * @param string $name |
|
| 1168 | - * @param string $description |
|
| 1169 | - * @param string $code |
|
| 1170 | - * @param boolean $add_to_existing_line_item |
|
| 1171 | - * if true, and a duplicate line item with the same code is found, |
|
| 1172 | - * $amount will be added onto it; otherwise will simply set the taxes to match $amount |
|
| 1173 | - * @return EE_Line_Item the new tax line item created |
|
| 1174 | - * @throws EE_Error |
|
| 1175 | - * @throws InvalidArgumentException |
|
| 1176 | - * @throws InvalidDataTypeException |
|
| 1177 | - * @throws InvalidInterfaceException |
|
| 1178 | - * @throws ReflectionException |
|
| 1179 | - */ |
|
| 1180 | - public static function set_total_tax_to( |
|
| 1181 | - EE_Line_Item $total_line_item, |
|
| 1182 | - $amount, |
|
| 1183 | - $name = null, |
|
| 1184 | - $description = null, |
|
| 1185 | - $code = null, |
|
| 1186 | - $add_to_existing_line_item = false |
|
| 1187 | - ) { |
|
| 1188 | - $tax_subtotal = self::get_taxes_subtotal($total_line_item); |
|
| 1189 | - $taxable_total = $total_line_item->taxable_total(); |
|
| 1190 | - |
|
| 1191 | - if ($add_to_existing_line_item) { |
|
| 1192 | - $new_tax = $tax_subtotal->get_child_line_item($code); |
|
| 1193 | - EEM_Line_Item::instance()->delete( |
|
| 1194 | - array(array('LIN_code' => array('!=', $code), 'LIN_parent' => $tax_subtotal->ID())) |
|
| 1195 | - ); |
|
| 1196 | - } else { |
|
| 1197 | - $new_tax = null; |
|
| 1198 | - $tax_subtotal->delete_children_line_items(); |
|
| 1199 | - } |
|
| 1200 | - if ($new_tax) { |
|
| 1201 | - $new_tax->set_total($new_tax->total() + $amount); |
|
| 1202 | - $new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0); |
|
| 1203 | - } else { |
|
| 1204 | - // no existing tax item. Create it |
|
| 1205 | - $new_tax = EE_Line_Item::new_instance(array( |
|
| 1206 | - 'TXN_ID' => $total_line_item->TXN_ID(), |
|
| 1207 | - 'LIN_name' => $name ?: esc_html__('Tax', 'event_espresso'), |
|
| 1208 | - 'LIN_desc' => $description ?: '', |
|
| 1209 | - 'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0, |
|
| 1210 | - 'LIN_total' => $amount, |
|
| 1211 | - 'LIN_parent' => $tax_subtotal->ID(), |
|
| 1212 | - 'LIN_type' => EEM_Line_Item::type_tax, |
|
| 1213 | - 'LIN_code' => $code, |
|
| 1214 | - )); |
|
| 1215 | - } |
|
| 1216 | - |
|
| 1217 | - $new_tax = apply_filters( |
|
| 1218 | - 'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal', |
|
| 1219 | - $new_tax, |
|
| 1220 | - $total_line_item |
|
| 1221 | - ); |
|
| 1222 | - $new_tax->save(); |
|
| 1223 | - $tax_subtotal->set_total($new_tax->total()); |
|
| 1224 | - $tax_subtotal->save(); |
|
| 1225 | - $total_line_item->recalculate_total_including_taxes(); |
|
| 1226 | - return $new_tax; |
|
| 1227 | - } |
|
| 1228 | - |
|
| 1229 | - |
|
| 1230 | - /** |
|
| 1231 | - * Makes all the line items which are children of $line_item taxable (or not). |
|
| 1232 | - * Does NOT save the line items |
|
| 1233 | - * |
|
| 1234 | - * @param EE_Line_Item $line_item |
|
| 1235 | - * @param boolean $taxable |
|
| 1236 | - * @param string $code_substring_for_whitelist if this string is part of the line item's code |
|
| 1237 | - * it will be whitelisted (ie, except from becoming taxable) |
|
| 1238 | - * @throws EE_Error |
|
| 1239 | - */ |
|
| 1240 | - public static function set_line_items_taxable( |
|
| 1241 | - EE_Line_Item $line_item, |
|
| 1242 | - $taxable = true, |
|
| 1243 | - $code_substring_for_whitelist = null |
|
| 1244 | - ) { |
|
| 1245 | - $whitelisted = false; |
|
| 1246 | - if ($code_substring_for_whitelist !== null) { |
|
| 1247 | - $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false; |
|
| 1248 | - } |
|
| 1249 | - if (! $whitelisted && $line_item->is_line_item()) { |
|
| 1250 | - $line_item->set_is_taxable($taxable); |
|
| 1251 | - } |
|
| 1252 | - foreach ($line_item->children() as $child_line_item) { |
|
| 1253 | - EEH_Line_Item::set_line_items_taxable( |
|
| 1254 | - $child_line_item, |
|
| 1255 | - $taxable, |
|
| 1256 | - $code_substring_for_whitelist |
|
| 1257 | - ); |
|
| 1258 | - } |
|
| 1259 | - } |
|
| 1260 | - |
|
| 1261 | - |
|
| 1262 | - /** |
|
| 1263 | - * Gets all descendants that are event subtotals |
|
| 1264 | - * |
|
| 1265 | - * @uses EEH_Line_Item::get_subtotals_of_object_type() |
|
| 1266 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1267 | - * @return EE_Line_Item[] |
|
| 1268 | - * @throws EE_Error |
|
| 1269 | - */ |
|
| 1270 | - public static function get_event_subtotals(EE_Line_Item $parent_line_item) |
|
| 1271 | - { |
|
| 1272 | - return self::get_subtotals_of_object_type($parent_line_item, EEM_Line_Item::OBJ_TYPE_EVENT); |
|
| 1273 | - } |
|
| 1274 | - |
|
| 1275 | - |
|
| 1276 | - /** |
|
| 1277 | - * Gets all descendants subtotals that match the supplied object type |
|
| 1278 | - * |
|
| 1279 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
| 1280 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1281 | - * @param string $obj_type |
|
| 1282 | - * @return EE_Line_Item[] |
|
| 1283 | - * @throws EE_Error |
|
| 1284 | - */ |
|
| 1285 | - public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
| 1286 | - { |
|
| 1287 | - return self::_get_descendants_by_type_and_object_type( |
|
| 1288 | - $parent_line_item, |
|
| 1289 | - EEM_Line_Item::type_sub_total, |
|
| 1290 | - $obj_type |
|
| 1291 | - ); |
|
| 1292 | - } |
|
| 1293 | - |
|
| 1294 | - |
|
| 1295 | - /** |
|
| 1296 | - * Gets all descendants that are tickets |
|
| 1297 | - * |
|
| 1298 | - * @uses EEH_Line_Item::get_line_items_of_object_type() |
|
| 1299 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1300 | - * @return EE_Line_Item[] |
|
| 1301 | - * @throws EE_Error |
|
| 1302 | - */ |
|
| 1303 | - public static function get_ticket_line_items(EE_Line_Item $parent_line_item) |
|
| 1304 | - { |
|
| 1305 | - return self::get_line_items_of_object_type( |
|
| 1306 | - $parent_line_item, |
|
| 1307 | - EEM_Line_Item::OBJ_TYPE_TICKET |
|
| 1308 | - ); |
|
| 1309 | - } |
|
| 1310 | - |
|
| 1311 | - |
|
| 1312 | - /** |
|
| 1313 | - * Gets all descendants subtotals that match the supplied object type |
|
| 1314 | - * |
|
| 1315 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
| 1316 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1317 | - * @param string $obj_type |
|
| 1318 | - * @return EE_Line_Item[] |
|
| 1319 | - * @throws EE_Error |
|
| 1320 | - */ |
|
| 1321 | - public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
| 1322 | - { |
|
| 1323 | - return self::_get_descendants_by_type_and_object_type( |
|
| 1324 | - $parent_line_item, |
|
| 1325 | - EEM_Line_Item::type_line_item, |
|
| 1326 | - $obj_type |
|
| 1327 | - ); |
|
| 1328 | - } |
|
| 1329 | - |
|
| 1330 | - |
|
| 1331 | - /** |
|
| 1332 | - * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax' |
|
| 1333 | - * |
|
| 1334 | - * @uses EEH_Line_Item::get_descendants_of_type() |
|
| 1335 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1336 | - * @return EE_Line_Item[] |
|
| 1337 | - * @throws EE_Error |
|
| 1338 | - */ |
|
| 1339 | - public static function get_tax_descendants(EE_Line_Item $parent_line_item) |
|
| 1340 | - { |
|
| 1341 | - return EEH_Line_Item::get_descendants_of_type( |
|
| 1342 | - $parent_line_item, |
|
| 1343 | - EEM_Line_Item::type_tax |
|
| 1344 | - ); |
|
| 1345 | - } |
|
| 1346 | - |
|
| 1347 | - |
|
| 1348 | - /** |
|
| 1349 | - * Gets all the real items purchased which are children of this item |
|
| 1350 | - * |
|
| 1351 | - * @uses EEH_Line_Item::get_descendants_of_type() |
|
| 1352 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1353 | - * @return EE_Line_Item[] |
|
| 1354 | - * @throws EE_Error |
|
| 1355 | - */ |
|
| 1356 | - public static function get_line_item_descendants(EE_Line_Item $parent_line_item) |
|
| 1357 | - { |
|
| 1358 | - return EEH_Line_Item::get_descendants_of_type( |
|
| 1359 | - $parent_line_item, |
|
| 1360 | - EEM_Line_Item::type_line_item |
|
| 1361 | - ); |
|
| 1362 | - } |
|
| 1363 | - |
|
| 1364 | - |
|
| 1365 | - /** |
|
| 1366 | - * Gets all descendants of supplied line item that match the supplied line item type |
|
| 1367 | - * |
|
| 1368 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
| 1369 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1370 | - * @param string $line_item_type one of the EEM_Line_Item constants |
|
| 1371 | - * @return EE_Line_Item[] |
|
| 1372 | - * @throws EE_Error |
|
| 1373 | - */ |
|
| 1374 | - public static function get_descendants_of_type(EE_Line_Item $parent_line_item, $line_item_type) |
|
| 1375 | - { |
|
| 1376 | - return self::_get_descendants_by_type_and_object_type( |
|
| 1377 | - $parent_line_item, |
|
| 1378 | - $line_item_type, |
|
| 1379 | - null |
|
| 1380 | - ); |
|
| 1381 | - } |
|
| 1382 | - |
|
| 1383 | - |
|
| 1384 | - /** |
|
| 1385 | - * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type |
|
| 1386 | - * as well |
|
| 1387 | - * |
|
| 1388 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1389 | - * @param string $line_item_type one of the EEM_Line_Item constants |
|
| 1390 | - * @param string | NULL $obj_type object model class name (minus prefix) or NULL to ignore object type when |
|
| 1391 | - * searching |
|
| 1392 | - * @return EE_Line_Item[] |
|
| 1393 | - * @throws EE_Error |
|
| 1394 | - */ |
|
| 1395 | - protected static function _get_descendants_by_type_and_object_type( |
|
| 1396 | - EE_Line_Item $parent_line_item, |
|
| 1397 | - $line_item_type, |
|
| 1398 | - $obj_type = null |
|
| 1399 | - ) { |
|
| 1400 | - $objects = array(); |
|
| 1401 | - foreach ($parent_line_item->children() as $child_line_item) { |
|
| 1402 | - if ($child_line_item instanceof EE_Line_Item) { |
|
| 1403 | - if ( |
|
| 1404 | - $child_line_item->type() === $line_item_type |
|
| 1405 | - && ( |
|
| 1406 | - $child_line_item->OBJ_type() === $obj_type || $obj_type === null |
|
| 1407 | - ) |
|
| 1408 | - ) { |
|
| 1409 | - $objects[] = $child_line_item; |
|
| 1410 | - } else { |
|
| 1411 | - // go-through-all-its children looking for more matches |
|
| 1412 | - $objects = array_merge( |
|
| 1413 | - $objects, |
|
| 1414 | - self::_get_descendants_by_type_and_object_type( |
|
| 1415 | - $child_line_item, |
|
| 1416 | - $line_item_type, |
|
| 1417 | - $obj_type |
|
| 1418 | - ) |
|
| 1419 | - ); |
|
| 1420 | - } |
|
| 1421 | - } |
|
| 1422 | - } |
|
| 1423 | - return $objects; |
|
| 1424 | - } |
|
| 1425 | - |
|
| 1426 | - |
|
| 1427 | - /** |
|
| 1428 | - * Gets all descendants subtotals that match the supplied object type |
|
| 1429 | - * |
|
| 1430 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
| 1431 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1432 | - * @param string $OBJ_type object type (like Event) |
|
| 1433 | - * @param array $OBJ_IDs array of OBJ_IDs |
|
| 1434 | - * @return EE_Line_Item[] |
|
| 1435 | - * @throws EE_Error |
|
| 1436 | - */ |
|
| 1437 | - public static function get_line_items_by_object_type_and_IDs( |
|
| 1438 | - EE_Line_Item $parent_line_item, |
|
| 1439 | - $OBJ_type = '', |
|
| 1440 | - $OBJ_IDs = array() |
|
| 1441 | - ) { |
|
| 1442 | - return self::_get_descendants_by_object_type_and_object_ID( |
|
| 1443 | - $parent_line_item, |
|
| 1444 | - $OBJ_type, |
|
| 1445 | - $OBJ_IDs |
|
| 1446 | - ); |
|
| 1447 | - } |
|
| 1448 | - |
|
| 1449 | - |
|
| 1450 | - /** |
|
| 1451 | - * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type |
|
| 1452 | - * as well |
|
| 1453 | - * |
|
| 1454 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1455 | - * @param string $OBJ_type object type (like Event) |
|
| 1456 | - * @param array $OBJ_IDs array of OBJ_IDs |
|
| 1457 | - * @return EE_Line_Item[] |
|
| 1458 | - * @throws EE_Error |
|
| 1459 | - */ |
|
| 1460 | - protected static function _get_descendants_by_object_type_and_object_ID( |
|
| 1461 | - EE_Line_Item $parent_line_item, |
|
| 1462 | - $OBJ_type, |
|
| 1463 | - $OBJ_IDs |
|
| 1464 | - ) { |
|
| 1465 | - $objects = array(); |
|
| 1466 | - foreach ($parent_line_item->children() as $child_line_item) { |
|
| 1467 | - if ($child_line_item instanceof EE_Line_Item) { |
|
| 1468 | - if ( |
|
| 1469 | - $child_line_item->OBJ_type() === $OBJ_type |
|
| 1470 | - && is_array($OBJ_IDs) |
|
| 1471 | - && in_array($child_line_item->OBJ_ID(), $OBJ_IDs) |
|
| 1472 | - ) { |
|
| 1473 | - $objects[] = $child_line_item; |
|
| 1474 | - } else { |
|
| 1475 | - // go-through-all-its children looking for more matches |
|
| 1476 | - $objects = array_merge( |
|
| 1477 | - $objects, |
|
| 1478 | - self::_get_descendants_by_object_type_and_object_ID( |
|
| 1479 | - $child_line_item, |
|
| 1480 | - $OBJ_type, |
|
| 1481 | - $OBJ_IDs |
|
| 1482 | - ) |
|
| 1483 | - ); |
|
| 1484 | - } |
|
| 1485 | - } |
|
| 1486 | - } |
|
| 1487 | - return $objects; |
|
| 1488 | - } |
|
| 1489 | - |
|
| 1490 | - |
|
| 1491 | - /** |
|
| 1492 | - * Uses a breadth-first-search in order to find the nearest descendant of |
|
| 1493 | - * the specified type and returns it, else NULL |
|
| 1494 | - * |
|
| 1495 | - * @uses EEH_Line_Item::_get_nearest_descendant() |
|
| 1496 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1497 | - * @param string $type like one of the EEM_Line_Item::type_* |
|
| 1498 | - * @return EE_Line_Item |
|
| 1499 | - * @throws EE_Error |
|
| 1500 | - * @throws InvalidArgumentException |
|
| 1501 | - * @throws InvalidDataTypeException |
|
| 1502 | - * @throws InvalidInterfaceException |
|
| 1503 | - * @throws ReflectionException |
|
| 1504 | - */ |
|
| 1505 | - public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, $type) |
|
| 1506 | - { |
|
| 1507 | - return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type); |
|
| 1508 | - } |
|
| 1509 | - |
|
| 1510 | - |
|
| 1511 | - /** |
|
| 1512 | - * Uses a breadth-first-search in order to find the nearest descendant |
|
| 1513 | - * having the specified LIN_code and returns it, else NULL |
|
| 1514 | - * |
|
| 1515 | - * @uses EEH_Line_Item::_get_nearest_descendant() |
|
| 1516 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1517 | - * @param string $code any value used for LIN_code |
|
| 1518 | - * @return EE_Line_Item |
|
| 1519 | - * @throws EE_Error |
|
| 1520 | - * @throws InvalidArgumentException |
|
| 1521 | - * @throws InvalidDataTypeException |
|
| 1522 | - * @throws InvalidInterfaceException |
|
| 1523 | - * @throws ReflectionException |
|
| 1524 | - */ |
|
| 1525 | - public static function get_nearest_descendant_having_code(EE_Line_Item $parent_line_item, $code) |
|
| 1526 | - { |
|
| 1527 | - return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code); |
|
| 1528 | - } |
|
| 1529 | - |
|
| 1530 | - |
|
| 1531 | - /** |
|
| 1532 | - * Uses a breadth-first-search in order to find the nearest descendant |
|
| 1533 | - * having the specified LIN_code and returns it, else NULL |
|
| 1534 | - * |
|
| 1535 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1536 | - * @param string $search_field name of EE_Line_Item property |
|
| 1537 | - * @param string $value any value stored in $search_field |
|
| 1538 | - * @return EE_Line_Item |
|
| 1539 | - * @throws EE_Error |
|
| 1540 | - * @throws InvalidArgumentException |
|
| 1541 | - * @throws InvalidDataTypeException |
|
| 1542 | - * @throws InvalidInterfaceException |
|
| 1543 | - * @throws ReflectionException |
|
| 1544 | - */ |
|
| 1545 | - protected static function _get_nearest_descendant(EE_Line_Item $parent_line_item, $search_field, $value) |
|
| 1546 | - { |
|
| 1547 | - foreach ($parent_line_item->children() as $child) { |
|
| 1548 | - if ($child->get($search_field) == $value) { |
|
| 1549 | - return $child; |
|
| 1550 | - } |
|
| 1551 | - } |
|
| 1552 | - foreach ($parent_line_item->children() as $child) { |
|
| 1553 | - $descendant_found = self::_get_nearest_descendant( |
|
| 1554 | - $child, |
|
| 1555 | - $search_field, |
|
| 1556 | - $value |
|
| 1557 | - ); |
|
| 1558 | - if ($descendant_found) { |
|
| 1559 | - return $descendant_found; |
|
| 1560 | - } |
|
| 1561 | - } |
|
| 1562 | - return null; |
|
| 1563 | - } |
|
| 1564 | - |
|
| 1565 | - |
|
| 1566 | - /** |
|
| 1567 | - * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction, |
|
| 1568 | - * else recursively walks up the line item tree until a parent of type total is found, |
|
| 1569 | - * |
|
| 1570 | - * @param EE_Line_Item $line_item |
|
| 1571 | - * @return EE_Line_Item |
|
| 1572 | - * @throws EE_Error |
|
| 1573 | - * @throws ReflectionException |
|
| 1574 | - */ |
|
| 1575 | - public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item): EE_Line_Item |
|
| 1576 | - { |
|
| 1577 | - if ($line_item->is_total()) { |
|
| 1578 | - return $line_item; |
|
| 1579 | - } |
|
| 1580 | - if ($line_item->TXN_ID()) { |
|
| 1581 | - $total_line_item = $line_item->transaction()->total_line_item(false); |
|
| 1582 | - if ($total_line_item instanceof EE_Line_Item) { |
|
| 1583 | - return $total_line_item; |
|
| 1584 | - } |
|
| 1585 | - } else { |
|
| 1586 | - $line_item_parent = $line_item->parent(); |
|
| 1587 | - if ($line_item_parent instanceof EE_Line_Item) { |
|
| 1588 | - if ($line_item_parent->is_total()) { |
|
| 1589 | - return $line_item_parent; |
|
| 1590 | - } |
|
| 1591 | - return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent); |
|
| 1592 | - } |
|
| 1593 | - } |
|
| 1594 | - throw new EE_Error( |
|
| 1595 | - sprintf( |
|
| 1596 | - esc_html__( |
|
| 1597 | - 'A valid grand total for line item %1$d was not found.', |
|
| 1598 | - 'event_espresso' |
|
| 1599 | - ), |
|
| 1600 | - $line_item->ID() |
|
| 1601 | - ) |
|
| 1602 | - ); |
|
| 1603 | - } |
|
| 1604 | - |
|
| 1605 | - |
|
| 1606 | - /** |
|
| 1607 | - * Prints out a representation of the line item tree |
|
| 1608 | - * |
|
| 1609 | - * @param EE_Line_Item $line_item |
|
| 1610 | - * @param int $indentation |
|
| 1611 | - * @return void |
|
| 1612 | - * @throws EE_Error |
|
| 1613 | - */ |
|
| 1614 | - public static function visualize(EE_Line_Item $line_item, $indentation = 0) |
|
| 1615 | - { |
|
| 1616 | - $new_line = defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
|
| 1617 | - echo $new_line; |
|
| 1618 | - if (! $indentation) { |
|
| 1619 | - echo $new_line; |
|
| 1620 | - } |
|
| 1621 | - echo str_repeat('. ', $indentation); |
|
| 1622 | - $breakdown = ''; |
|
| 1623 | - if ($line_item->is_line_item() || $line_item->is_sub_line_item() || $line_item->isSubTax()) { |
|
| 1624 | - if ($line_item->is_percent()) { |
|
| 1625 | - $breakdown = "{$line_item->percent()}%"; |
|
| 1626 | - } else { |
|
| 1627 | - $breakdown = "\${$line_item->unit_price()} x {$line_item->quantity()}"; |
|
| 1628 | - } |
|
| 1629 | - } |
|
| 1630 | - echo $line_item->name(); |
|
| 1631 | - echo " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : "; |
|
| 1632 | - echo "\${$line_item->total()}"; |
|
| 1633 | - if ($breakdown) { |
|
| 1634 | - echo " ( {$breakdown} )"; |
|
| 1635 | - } |
|
| 1636 | - if ($line_item->is_taxable()) { |
|
| 1637 | - echo ' * taxable'; |
|
| 1638 | - } |
|
| 1639 | - if ($line_item->children()) { |
|
| 1640 | - foreach ($line_item->children() as $child) { |
|
| 1641 | - self::visualize($child, $indentation + 1); |
|
| 1642 | - } |
|
| 1643 | - } |
|
| 1644 | - if (! $indentation) { |
|
| 1645 | - echo $new_line . $new_line; |
|
| 1646 | - } |
|
| 1647 | - } |
|
| 1648 | - |
|
| 1649 | - |
|
| 1650 | - /** |
|
| 1651 | - * Calculates the registration's final price, taking into account that they |
|
| 1652 | - * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes, |
|
| 1653 | - * and receive a portion of any transaction-wide discounts. |
|
| 1654 | - * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount |
|
| 1655 | - * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get |
|
| 1656 | - * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50 |
|
| 1657 | - * and brent's final price should be $5.50. |
|
| 1658 | - * In order to do this, we basically need to traverse the line item tree calculating |
|
| 1659 | - * the running totals (just as if we were recalculating the total), but when we identify |
|
| 1660 | - * regular line items, we need to keep track of their share of the grand total. |
|
| 1661 | - * Also, we need to keep track of the TAXABLE total for each ticket purchase, so |
|
| 1662 | - * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total" |
|
| 1663 | - * when there are non-taxable items; otherwise they would be the same) |
|
| 1664 | - * |
|
| 1665 | - * @param EE_Line_Item $line_item |
|
| 1666 | - * @param array $billable_ticket_quantities array of EE_Ticket IDs and their corresponding quantity that |
|
| 1667 | - * can be included in price calculations at this moment |
|
| 1668 | - * @return array keys are line items for tickets IDs and values are their share of the running total, |
|
| 1669 | - * plus the key 'total', and 'taxable' which also has keys of all |
|
| 1670 | - * the ticket IDs. |
|
| 1671 | - * Eg array( |
|
| 1672 | - * 12 => 4.3 |
|
| 1673 | - * 23 => 8.0 |
|
| 1674 | - * 'total' => 16.6, |
|
| 1675 | - * 'taxable' => array( |
|
| 1676 | - * 12 => 10, |
|
| 1677 | - * 23 => 4 |
|
| 1678 | - * ). |
|
| 1679 | - * So to find which registrations have which final price, we need |
|
| 1680 | - * to find which line item is theirs, which can be done with |
|
| 1681 | - * `EEM_Line_Item::instance()->get_line_item_for_registration( |
|
| 1682 | - * $registration );` |
|
| 1683 | - * @throws EE_Error |
|
| 1684 | - * @throws InvalidArgumentException |
|
| 1685 | - * @throws InvalidDataTypeException |
|
| 1686 | - * @throws InvalidInterfaceException |
|
| 1687 | - * @throws ReflectionException |
|
| 1688 | - */ |
|
| 1689 | - public static function calculate_reg_final_prices_per_line_item( |
|
| 1690 | - EE_Line_Item $line_item, |
|
| 1691 | - $billable_ticket_quantities = array() |
|
| 1692 | - ) { |
|
| 1693 | - $running_totals = [ |
|
| 1694 | - 'total' => 0, |
|
| 1695 | - 'taxable' => ['total' => 0] |
|
| 1696 | - ]; |
|
| 1697 | - foreach ($line_item->children() as $child_line_item) { |
|
| 1698 | - switch ($child_line_item->type()) { |
|
| 1699 | - case EEM_Line_Item::type_sub_total: |
|
| 1700 | - $running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
| 1701 | - $child_line_item, |
|
| 1702 | - $billable_ticket_quantities |
|
| 1703 | - ); |
|
| 1704 | - // combine arrays but preserve numeric keys |
|
| 1705 | - $running_totals = array_replace_recursive($running_totals_from_subtotal, $running_totals); |
|
| 1706 | - $running_totals['total'] += $running_totals_from_subtotal['total']; |
|
| 1707 | - $running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total']; |
|
| 1708 | - break; |
|
| 1709 | - |
|
| 1710 | - case EEM_Line_Item::type_tax_sub_total: |
|
| 1711 | - // find how much the taxes percentage is |
|
| 1712 | - if ($child_line_item->percent() !== 0) { |
|
| 1713 | - $tax_percent_decimal = $child_line_item->percent() / 100; |
|
| 1714 | - } else { |
|
| 1715 | - $tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100; |
|
| 1716 | - } |
|
| 1717 | - // and apply to all the taxable totals, and add to the pretax totals |
|
| 1718 | - foreach ($running_totals as $line_item_id => $this_running_total) { |
|
| 1719 | - // "total" and "taxable" array key is an exception |
|
| 1720 | - if ($line_item_id === 'taxable') { |
|
| 1721 | - continue; |
|
| 1722 | - } |
|
| 1723 | - $taxable_total = $running_totals['taxable'][ $line_item_id ]; |
|
| 1724 | - $running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal); |
|
| 1725 | - } |
|
| 1726 | - break; |
|
| 1727 | - |
|
| 1728 | - case EEM_Line_Item::type_line_item: |
|
| 1729 | - // ticket line items or ???? |
|
| 1730 | - if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
| 1731 | - // kk it's a ticket |
|
| 1732 | - if (isset($running_totals[ $child_line_item->ID() ])) { |
|
| 1733 | - // huh? that shouldn't happen. |
|
| 1734 | - $running_totals['total'] += $child_line_item->total(); |
|
| 1735 | - } else { |
|
| 1736 | - // its not in our running totals yet. great. |
|
| 1737 | - if ($child_line_item->is_taxable()) { |
|
| 1738 | - $taxable_amount = $child_line_item->unit_price(); |
|
| 1739 | - } else { |
|
| 1740 | - $taxable_amount = 0; |
|
| 1741 | - } |
|
| 1742 | - // are we only calculating totals for some tickets? |
|
| 1743 | - if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) { |
|
| 1744 | - $quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ]; |
|
| 1745 | - $running_totals[ $child_line_item->ID() ] = $quantity |
|
| 1746 | - ? $child_line_item->unit_price() |
|
| 1747 | - : 0; |
|
| 1748 | - $running_totals['taxable'][ $child_line_item->ID() ] = $quantity |
|
| 1749 | - ? $taxable_amount |
|
| 1750 | - : 0; |
|
| 1751 | - } else { |
|
| 1752 | - $quantity = $child_line_item->quantity(); |
|
| 1753 | - $running_totals[ $child_line_item->ID() ] = $child_line_item->unit_price(); |
|
| 1754 | - $running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount; |
|
| 1755 | - } |
|
| 1756 | - $running_totals['taxable']['total'] += $taxable_amount * $quantity; |
|
| 1757 | - $running_totals['total'] += $child_line_item->unit_price() * $quantity; |
|
| 1758 | - } |
|
| 1759 | - } else { |
|
| 1760 | - // it's some other type of item added to the cart |
|
| 1761 | - // it should affect the running totals |
|
| 1762 | - // basically we want to convert it into a PERCENT modifier. Because |
|
| 1763 | - // more clearly affect all registration's final price equally |
|
| 1764 | - $line_items_percent_of_running_total = $running_totals['total'] > 0 |
|
| 1765 | - ? ($child_line_item->total() / $running_totals['total']) + 1 |
|
| 1766 | - : 1; |
|
| 1767 | - foreach ($running_totals as $line_item_id => $this_running_total) { |
|
| 1768 | - // the "taxable" array key is an exception |
|
| 1769 | - if ($line_item_id === 'taxable') { |
|
| 1770 | - continue; |
|
| 1771 | - } |
|
| 1772 | - // update the running totals |
|
| 1773 | - // yes this actually even works for the running grand total! |
|
| 1774 | - $running_totals[ $line_item_id ] = |
|
| 1775 | - $line_items_percent_of_running_total * $this_running_total; |
|
| 1776 | - |
|
| 1777 | - if ($child_line_item->is_taxable()) { |
|
| 1778 | - $running_totals['taxable'][ $line_item_id ] = |
|
| 1779 | - $line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ]; |
|
| 1780 | - } |
|
| 1781 | - } |
|
| 1782 | - } |
|
| 1783 | - break; |
|
| 1784 | - } |
|
| 1785 | - } |
|
| 1786 | - return $running_totals; |
|
| 1787 | - } |
|
| 1788 | - |
|
| 1789 | - |
|
| 1790 | - /** |
|
| 1791 | - * @param EE_Line_Item $total_line_item |
|
| 1792 | - * @param EE_Line_Item $ticket_line_item |
|
| 1793 | - * @return float | null |
|
| 1794 | - * @throws EE_Error |
|
| 1795 | - * @throws InvalidArgumentException |
|
| 1796 | - * @throws InvalidDataTypeException |
|
| 1797 | - * @throws InvalidInterfaceException |
|
| 1798 | - * @throws OutOfRangeException |
|
| 1799 | - * @throws ReflectionException |
|
| 1800 | - */ |
|
| 1801 | - public static function calculate_final_price_for_ticket_line_item( |
|
| 1802 | - EE_Line_Item $total_line_item, |
|
| 1803 | - EE_Line_Item $ticket_line_item |
|
| 1804 | - ) { |
|
| 1805 | - static $final_prices_per_ticket_line_item = array(); |
|
| 1806 | - if (empty($final_prices_per_ticket_line_item) || empty($final_prices_per_ticket_line_item[ $total_line_item->ID() ])) { |
|
| 1807 | - $final_prices_per_ticket_line_item[ $total_line_item->ID() ] = EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
| 1808 | - $total_line_item |
|
| 1809 | - ); |
|
| 1810 | - } |
|
| 1811 | - // ok now find this new registration's final price |
|
| 1812 | - if (isset($final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ])) { |
|
| 1813 | - return $final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ]; |
|
| 1814 | - } |
|
| 1815 | - $message = sprintf( |
|
| 1816 | - esc_html__( |
|
| 1817 | - 'The final price for the ticket line item (ID:%1$d) on the total line item (ID:%2$d) could not be calculated.', |
|
| 1818 | - 'event_espresso' |
|
| 1819 | - ), |
|
| 1820 | - $ticket_line_item->ID(), |
|
| 1821 | - $total_line_item->ID() |
|
| 1822 | - ); |
|
| 1823 | - if (WP_DEBUG) { |
|
| 1824 | - $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true); |
|
| 1825 | - throw new OutOfRangeException($message); |
|
| 1826 | - } |
|
| 1827 | - EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message); |
|
| 1828 | - return null; |
|
| 1829 | - } |
|
| 1830 | - |
|
| 1831 | - |
|
| 1832 | - /** |
|
| 1833 | - * Creates a duplicate of the line item tree, except only includes billable items |
|
| 1834 | - * and the portion of line items attributed to billable things |
|
| 1835 | - * |
|
| 1836 | - * @param EE_Line_Item $line_item |
|
| 1837 | - * @param EE_Registration[] $registrations |
|
| 1838 | - * @return EE_Line_Item |
|
| 1839 | - * @throws EE_Error |
|
| 1840 | - * @throws InvalidArgumentException |
|
| 1841 | - * @throws InvalidDataTypeException |
|
| 1842 | - * @throws InvalidInterfaceException |
|
| 1843 | - * @throws ReflectionException |
|
| 1844 | - */ |
|
| 1845 | - public static function billable_line_item_tree(EE_Line_Item $line_item, $registrations) |
|
| 1846 | - { |
|
| 1847 | - $copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations); |
|
| 1848 | - foreach ($line_item->children() as $child_li) { |
|
| 1849 | - $copy_li->add_child_line_item( |
|
| 1850 | - EEH_Line_Item::billable_line_item_tree($child_li, $registrations) |
|
| 1851 | - ); |
|
| 1852 | - } |
|
| 1853 | - // if this is the grand total line item, make sure the totals all add up |
|
| 1854 | - // (we could have duplicated this logic AS we copied the line items, but |
|
| 1855 | - // it seems DRYer this way) |
|
| 1856 | - if ($copy_li->type() === EEM_Line_Item::type_total) { |
|
| 1857 | - $copy_li->recalculate_total_including_taxes(); |
|
| 1858 | - } |
|
| 1859 | - return $copy_li; |
|
| 1860 | - } |
|
| 1861 | - |
|
| 1862 | - |
|
| 1863 | - /** |
|
| 1864 | - * Creates a new, unsaved line item from $line_item that factors in the |
|
| 1865 | - * number of billable registrations on $registrations. |
|
| 1866 | - * |
|
| 1867 | - * @param EE_Line_Item $line_item |
|
| 1868 | - * @param EE_Registration[] $registrations |
|
| 1869 | - * @return EE_Line_Item |
|
| 1870 | - * @throws EE_Error |
|
| 1871 | - * @throws InvalidArgumentException |
|
| 1872 | - * @throws InvalidDataTypeException |
|
| 1873 | - * @throws InvalidInterfaceException |
|
| 1874 | - * @throws ReflectionException |
|
| 1875 | - */ |
|
| 1876 | - public static function billable_line_item(EE_Line_Item $line_item, $registrations) |
|
| 1877 | - { |
|
| 1878 | - $new_li_fields = $line_item->model_field_array(); |
|
| 1879 | - if ( |
|
| 1880 | - $line_item->type() === EEM_Line_Item::type_line_item && |
|
| 1881 | - $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
| 1882 | - ) { |
|
| 1883 | - $count = 0; |
|
| 1884 | - foreach ($registrations as $registration) { |
|
| 1885 | - if ( |
|
| 1886 | - $line_item->OBJ_ID() === $registration->ticket_ID() && |
|
| 1887 | - in_array( |
|
| 1888 | - $registration->status_ID(), |
|
| 1889 | - EEM_Registration::reg_statuses_that_allow_payment(), |
|
| 1890 | - true |
|
| 1891 | - ) |
|
| 1892 | - ) { |
|
| 1893 | - $count++; |
|
| 1894 | - } |
|
| 1895 | - } |
|
| 1896 | - $new_li_fields['LIN_quantity'] = $count; |
|
| 1897 | - } |
|
| 1898 | - // don't set the total. We'll leave that up to the code that calculates it |
|
| 1899 | - unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']); |
|
| 1900 | - return EE_Line_Item::new_instance($new_li_fields); |
|
| 1901 | - } |
|
| 1902 | - |
|
| 1903 | - |
|
| 1904 | - /** |
|
| 1905 | - * Returns a modified line item tree where all the subtotals which have a total of 0 |
|
| 1906 | - * are removed, and line items with a quantity of 0 |
|
| 1907 | - * |
|
| 1908 | - * @param EE_Line_Item $line_item |null |
|
| 1909 | - * @return EE_Line_Item|null |
|
| 1910 | - * @throws EE_Error |
|
| 1911 | - * @throws InvalidArgumentException |
|
| 1912 | - * @throws InvalidDataTypeException |
|
| 1913 | - * @throws InvalidInterfaceException |
|
| 1914 | - * @throws ReflectionException |
|
| 1915 | - */ |
|
| 1916 | - public static function non_empty_line_items(EE_Line_Item $line_item) |
|
| 1917 | - { |
|
| 1918 | - $copied_li = EEH_Line_Item::non_empty_line_item($line_item); |
|
| 1919 | - if ($copied_li === null) { |
|
| 1920 | - return null; |
|
| 1921 | - } |
|
| 1922 | - // if this is an event subtotal, we want to only include it if it |
|
| 1923 | - // has a non-zero total and at least one ticket line item child |
|
| 1924 | - $ticket_children = 0; |
|
| 1925 | - foreach ($line_item->children() as $child_li) { |
|
| 1926 | - $child_li_copy = EEH_Line_Item::non_empty_line_items($child_li); |
|
| 1927 | - if ($child_li_copy !== null) { |
|
| 1928 | - $copied_li->add_child_line_item($child_li_copy); |
|
| 1929 | - if ( |
|
| 1930 | - $child_li_copy->type() === EEM_Line_Item::type_line_item && |
|
| 1931 | - $child_li_copy->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
| 1932 | - ) { |
|
| 1933 | - $ticket_children++; |
|
| 1934 | - } |
|
| 1935 | - } |
|
| 1936 | - } |
|
| 1937 | - // if this is an event subtotal with NO ticket children |
|
| 1938 | - // we basically want to ignore it |
|
| 1939 | - if ( |
|
| 1940 | - $ticket_children === 0 |
|
| 1941 | - && $line_item->type() === EEM_Line_Item::type_sub_total |
|
| 1942 | - && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
| 1943 | - && $line_item->total() === 0 |
|
| 1944 | - ) { |
|
| 1945 | - return null; |
|
| 1946 | - } |
|
| 1947 | - return $copied_li; |
|
| 1948 | - } |
|
| 1949 | - |
|
| 1950 | - |
|
| 1951 | - /** |
|
| 1952 | - * Creates a new, unsaved line item, but if it's a ticket line item |
|
| 1953 | - * with a total of 0, or a subtotal of 0, returns null instead |
|
| 1954 | - * |
|
| 1955 | - * @param EE_Line_Item $line_item |
|
| 1956 | - * @return EE_Line_Item |
|
| 1957 | - * @throws EE_Error |
|
| 1958 | - * @throws InvalidArgumentException |
|
| 1959 | - * @throws InvalidDataTypeException |
|
| 1960 | - * @throws InvalidInterfaceException |
|
| 1961 | - * @throws ReflectionException |
|
| 1962 | - */ |
|
| 1963 | - public static function non_empty_line_item(EE_Line_Item $line_item) |
|
| 1964 | - { |
|
| 1965 | - if ( |
|
| 1966 | - $line_item->type() === EEM_Line_Item::type_line_item |
|
| 1967 | - && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
| 1968 | - && $line_item->quantity() === 0 |
|
| 1969 | - ) { |
|
| 1970 | - return null; |
|
| 1971 | - } |
|
| 1972 | - $new_li_fields = $line_item->model_field_array(); |
|
| 1973 | - // don't set the total. We'll leave that up to the code that calculates it |
|
| 1974 | - unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']); |
|
| 1975 | - return EE_Line_Item::new_instance($new_li_fields); |
|
| 1976 | - } |
|
| 1977 | - |
|
| 1978 | - |
|
| 1979 | - /** |
|
| 1980 | - * Cycles through all of the ticket line items for the supplied total line item |
|
| 1981 | - * and ensures that the line item's "is_taxable" field matches that of its corresponding ticket |
|
| 1982 | - * |
|
| 1983 | - * @param EE_Line_Item $total_line_item |
|
| 1984 | - * @since 4.9.79.p |
|
| 1985 | - * @throws EE_Error |
|
| 1986 | - * @throws InvalidArgumentException |
|
| 1987 | - * @throws InvalidDataTypeException |
|
| 1988 | - * @throws InvalidInterfaceException |
|
| 1989 | - * @throws ReflectionException |
|
| 1990 | - */ |
|
| 1991 | - public static function resetIsTaxableForTickets(EE_Line_Item $total_line_item) |
|
| 1992 | - { |
|
| 1993 | - $ticket_line_items = self::get_ticket_line_items($total_line_item); |
|
| 1994 | - foreach ($ticket_line_items as $ticket_line_item) { |
|
| 1995 | - if ( |
|
| 1996 | - $ticket_line_item instanceof EE_Line_Item |
|
| 1997 | - && $ticket_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
| 1998 | - ) { |
|
| 1999 | - $ticket = $ticket_line_item->ticket(); |
|
| 2000 | - if ($ticket instanceof EE_Ticket && $ticket->taxable() !== $ticket_line_item->is_taxable()) { |
|
| 2001 | - $ticket_line_item->set_is_taxable($ticket->taxable()); |
|
| 2002 | - $ticket_line_item->save(); |
|
| 2003 | - } |
|
| 2004 | - } |
|
| 2005 | - } |
|
| 2006 | - } |
|
| 2007 | - |
|
| 2008 | - |
|
| 2009 | - /** |
|
| 2010 | - * @return EE_Line_Item[] |
|
| 2011 | - * @throws EE_Error |
|
| 2012 | - * @throws ReflectionException |
|
| 2013 | - * @since $VID:$ |
|
| 2014 | - */ |
|
| 2015 | - private static function getGlobalTaxes(): array |
|
| 2016 | - { |
|
| 2017 | - if (EEH_Line_Item::$global_taxes === null) { |
|
| 2018 | - |
|
| 2019 | - /** @type EEM_Price $EEM_Price */ |
|
| 2020 | - $EEM_Price = EE_Registry::instance()->load_model('Price'); |
|
| 2021 | - // get array of taxes via Price Model |
|
| 2022 | - EEH_Line_Item::$global_taxes = $EEM_Price->get_all_prices_that_are_taxes(); |
|
| 2023 | - ksort(EEH_Line_Item::$global_taxes); |
|
| 2024 | - } |
|
| 2025 | - return EEH_Line_Item::$global_taxes; |
|
| 2026 | - } |
|
| 2027 | - |
|
| 2028 | - |
|
| 2029 | - |
|
| 2030 | - /**************************************** @DEPRECATED METHODS *************************************** */ |
|
| 2031 | - /** |
|
| 2032 | - * @deprecated |
|
| 2033 | - * @param EE_Line_Item $total_line_item |
|
| 2034 | - * @return EE_Line_Item |
|
| 2035 | - * @throws EE_Error |
|
| 2036 | - * @throws InvalidArgumentException |
|
| 2037 | - * @throws InvalidDataTypeException |
|
| 2038 | - * @throws InvalidInterfaceException |
|
| 2039 | - * @throws ReflectionException |
|
| 2040 | - */ |
|
| 2041 | - public static function get_items_subtotal(EE_Line_Item $total_line_item) |
|
| 2042 | - { |
|
| 2043 | - EE_Error::doing_it_wrong( |
|
| 2044 | - 'EEH_Line_Item::get_items_subtotal()', |
|
| 2045 | - sprintf( |
|
| 2046 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 2047 | - 'EEH_Line_Item::get_pre_tax_subtotal()' |
|
| 2048 | - ), |
|
| 2049 | - '4.6.0' |
|
| 2050 | - ); |
|
| 2051 | - return self::get_pre_tax_subtotal($total_line_item); |
|
| 2052 | - } |
|
| 2053 | - |
|
| 2054 | - |
|
| 2055 | - /** |
|
| 2056 | - * @deprecated |
|
| 2057 | - * @param EE_Transaction $transaction |
|
| 2058 | - * @return EE_Line_Item |
|
| 2059 | - * @throws EE_Error |
|
| 2060 | - * @throws InvalidArgumentException |
|
| 2061 | - * @throws InvalidDataTypeException |
|
| 2062 | - * @throws InvalidInterfaceException |
|
| 2063 | - * @throws ReflectionException |
|
| 2064 | - */ |
|
| 2065 | - public static function create_default_total_line_item($transaction = null) |
|
| 2066 | - { |
|
| 2067 | - EE_Error::doing_it_wrong( |
|
| 2068 | - 'EEH_Line_Item::create_default_total_line_item()', |
|
| 2069 | - sprintf( |
|
| 2070 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 2071 | - 'EEH_Line_Item::create_total_line_item()' |
|
| 2072 | - ), |
|
| 2073 | - '4.6.0' |
|
| 2074 | - ); |
|
| 2075 | - return self::create_total_line_item($transaction); |
|
| 2076 | - } |
|
| 2077 | - |
|
| 2078 | - |
|
| 2079 | - /** |
|
| 2080 | - * @deprecated |
|
| 2081 | - * @param EE_Line_Item $total_line_item |
|
| 2082 | - * @param EE_Transaction $transaction |
|
| 2083 | - * @return EE_Line_Item |
|
| 2084 | - * @throws EE_Error |
|
| 2085 | - * @throws InvalidArgumentException |
|
| 2086 | - * @throws InvalidDataTypeException |
|
| 2087 | - * @throws InvalidInterfaceException |
|
| 2088 | - * @throws ReflectionException |
|
| 2089 | - */ |
|
| 2090 | - public static function create_default_tickets_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
| 2091 | - { |
|
| 2092 | - EE_Error::doing_it_wrong( |
|
| 2093 | - 'EEH_Line_Item::create_default_tickets_subtotal()', |
|
| 2094 | - sprintf( |
|
| 2095 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 2096 | - 'EEH_Line_Item::create_pre_tax_subtotal()' |
|
| 2097 | - ), |
|
| 2098 | - '4.6.0' |
|
| 2099 | - ); |
|
| 2100 | - return self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
| 2101 | - } |
|
| 2102 | - |
|
| 2103 | - |
|
| 2104 | - /** |
|
| 2105 | - * @deprecated |
|
| 2106 | - * @param EE_Line_Item $total_line_item |
|
| 2107 | - * @param EE_Transaction $transaction |
|
| 2108 | - * @return EE_Line_Item |
|
| 2109 | - * @throws EE_Error |
|
| 2110 | - * @throws InvalidArgumentException |
|
| 2111 | - * @throws InvalidDataTypeException |
|
| 2112 | - * @throws InvalidInterfaceException |
|
| 2113 | - * @throws ReflectionException |
|
| 2114 | - */ |
|
| 2115 | - public static function create_default_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
| 2116 | - { |
|
| 2117 | - EE_Error::doing_it_wrong( |
|
| 2118 | - 'EEH_Line_Item::create_default_taxes_subtotal()', |
|
| 2119 | - sprintf( |
|
| 2120 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 2121 | - 'EEH_Line_Item::create_taxes_subtotal()' |
|
| 2122 | - ), |
|
| 2123 | - '4.6.0' |
|
| 2124 | - ); |
|
| 2125 | - return self::create_taxes_subtotal($total_line_item, $transaction); |
|
| 2126 | - } |
|
| 2127 | - |
|
| 2128 | - |
|
| 2129 | - /** |
|
| 2130 | - * @deprecated |
|
| 2131 | - * @param EE_Line_Item $total_line_item |
|
| 2132 | - * @param EE_Transaction $transaction |
|
| 2133 | - * @return EE_Line_Item |
|
| 2134 | - * @throws EE_Error |
|
| 2135 | - * @throws InvalidArgumentException |
|
| 2136 | - * @throws InvalidDataTypeException |
|
| 2137 | - * @throws InvalidInterfaceException |
|
| 2138 | - * @throws ReflectionException |
|
| 2139 | - */ |
|
| 2140 | - public static function create_default_event_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
| 2141 | - { |
|
| 2142 | - EE_Error::doing_it_wrong( |
|
| 2143 | - 'EEH_Line_Item::create_default_event_subtotal()', |
|
| 2144 | - sprintf( |
|
| 2145 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 2146 | - 'EEH_Line_Item::create_event_subtotal()' |
|
| 2147 | - ), |
|
| 2148 | - '4.6.0' |
|
| 2149 | - ); |
|
| 2150 | - return self::create_event_subtotal($total_line_item, $transaction); |
|
| 2151 | - } |
|
| 24 | + /** |
|
| 25 | + * @var EE_Line_Item[] |
|
| 26 | + */ |
|
| 27 | + private static $global_taxes; |
|
| 28 | + |
|
| 29 | + |
|
| 30 | + /** |
|
| 31 | + * Adds a simple item (unrelated to any other model object) to the provided PARENT line item. |
|
| 32 | + * Does NOT automatically re-calculate the line item totals or update the related transaction. |
|
| 33 | + * You should call recalculate_total_including_taxes() on the grant total line item after this |
|
| 34 | + * to update the subtotals, and EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
| 35 | + * to keep the registration final prices in-sync with the transaction's total. |
|
| 36 | + * |
|
| 37 | + * @param EE_Line_Item $parent_line_item |
|
| 38 | + * @param string $name |
|
| 39 | + * @param float $unit_price |
|
| 40 | + * @param string $description |
|
| 41 | + * @param int $quantity |
|
| 42 | + * @param boolean $taxable |
|
| 43 | + * @param string|null $code if set to a value, ensures there is only one line item with that code |
|
| 44 | + * @param bool $return_item |
|
| 45 | + * @param bool $recalculate_totals |
|
| 46 | + * @return boolean|EE_Line_Item success |
|
| 47 | + * @throws EE_Error |
|
| 48 | + * @throws ReflectionException |
|
| 49 | + */ |
|
| 50 | + public static function add_unrelated_item( |
|
| 51 | + EE_Line_Item $parent_line_item, |
|
| 52 | + string $name, |
|
| 53 | + float $unit_price, |
|
| 54 | + string $description = '', |
|
| 55 | + int $quantity = 1, |
|
| 56 | + bool $taxable = false, |
|
| 57 | + ?string $code = null, |
|
| 58 | + bool $return_item = false, |
|
| 59 | + bool $recalculate_totals = true |
|
| 60 | + ) { |
|
| 61 | + $items_subtotal = self::get_pre_tax_subtotal($parent_line_item); |
|
| 62 | + $line_item = EE_Line_Item::new_instance( |
|
| 63 | + [ |
|
| 64 | + 'LIN_name' => $name, |
|
| 65 | + 'LIN_desc' => $description, |
|
| 66 | + 'LIN_unit_price' => $unit_price, |
|
| 67 | + 'LIN_quantity' => $quantity, |
|
| 68 | + 'LIN_percent' => null, |
|
| 69 | + 'LIN_is_taxable' => $taxable, |
|
| 70 | + 'LIN_order' => $items_subtotal instanceof EE_Line_Item |
|
| 71 | + ? count($items_subtotal->children()) |
|
| 72 | + : 0, |
|
| 73 | + 'LIN_total' => (float) $unit_price * (int) $quantity, |
|
| 74 | + 'LIN_type' => EEM_Line_Item::type_line_item, |
|
| 75 | + 'LIN_code' => $code, |
|
| 76 | + ] |
|
| 77 | + ); |
|
| 78 | + $line_item = apply_filters( |
|
| 79 | + 'FHEE__EEH_Line_Item__add_unrelated_item__line_item', |
|
| 80 | + $line_item, |
|
| 81 | + $parent_line_item |
|
| 82 | + ); |
|
| 83 | + $added = self::add_item($parent_line_item, $line_item, $recalculate_totals); |
|
| 84 | + return $return_item ? $line_item : $added; |
|
| 85 | + } |
|
| 86 | + |
|
| 87 | + |
|
| 88 | + /** |
|
| 89 | + * Adds a simple item ( unrelated to any other model object) to the total line item, |
|
| 90 | + * in the correct spot in the line item tree. Does not automatically |
|
| 91 | + * re-calculate the line item totals, nor update the related transaction, nor upgrade the transaction's |
|
| 92 | + * registrations' final prices (which should probably change because of this). |
|
| 93 | + * You should call recalculate_total_including_taxes() on the grand total line item, then |
|
| 94 | + * update the transaction's total, and EE_Registration_Processor::update_registration_final_prices() |
|
| 95 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
| 96 | + * |
|
| 97 | + * @param EE_Line_Item $parent_line_item |
|
| 98 | + * @param string $name |
|
| 99 | + * @param float $percentage_amount |
|
| 100 | + * @param string $description |
|
| 101 | + * @param boolean $taxable |
|
| 102 | + * @param string|null $code |
|
| 103 | + * @param bool $return_item |
|
| 104 | + * @return boolean|EE_Line_Item success |
|
| 105 | + * @throws EE_Error |
|
| 106 | + * @throws ReflectionException |
|
| 107 | + */ |
|
| 108 | + public static function add_percentage_based_item( |
|
| 109 | + EE_Line_Item $parent_line_item, |
|
| 110 | + string $name, |
|
| 111 | + float $percentage_amount, |
|
| 112 | + string $description = '', |
|
| 113 | + bool $taxable = false, |
|
| 114 | + ?string $code = null, |
|
| 115 | + bool $return_item = false |
|
| 116 | + ) { |
|
| 117 | + $total = $percentage_amount * $parent_line_item->total() / 100; |
|
| 118 | + $line_item = EE_Line_Item::new_instance( |
|
| 119 | + [ |
|
| 120 | + 'LIN_name' => $name, |
|
| 121 | + 'LIN_desc' => $description, |
|
| 122 | + 'LIN_unit_price' => 0, |
|
| 123 | + 'LIN_percent' => $percentage_amount, |
|
| 124 | + 'LIN_quantity' => 1, |
|
| 125 | + 'LIN_is_taxable' => $taxable, |
|
| 126 | + 'LIN_total' => (float) $total, |
|
| 127 | + 'LIN_type' => EEM_Line_Item::type_line_item, |
|
| 128 | + 'LIN_parent' => $parent_line_item->ID(), |
|
| 129 | + 'LIN_code' => $code, |
|
| 130 | + ] |
|
| 131 | + ); |
|
| 132 | + $line_item = apply_filters( |
|
| 133 | + 'FHEE__EEH_Line_Item__add_percentage_based_item__line_item', |
|
| 134 | + $line_item |
|
| 135 | + ); |
|
| 136 | + $added = $parent_line_item->add_child_line_item($line_item, false); |
|
| 137 | + return $return_item ? $line_item : $added; |
|
| 138 | + } |
|
| 139 | + |
|
| 140 | + |
|
| 141 | + /** |
|
| 142 | + * Returns the new line item created by adding a purchase of the ticket |
|
| 143 | + * ensures that ticket line item is saved, and that cart total has been recalculated. |
|
| 144 | + * If this ticket has already been purchased, just increments its count. |
|
| 145 | + * Automatically re-calculates the line item totals and updates the related transaction. But |
|
| 146 | + * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
| 147 | + * should probably change because of this). |
|
| 148 | + * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
| 149 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
| 150 | + * |
|
| 151 | + * @param EE_Line_Item $total_line_item grand total line item of type EEM_Line_Item::type_total |
|
| 152 | + * @param EE_Ticket $ticket |
|
| 153 | + * @param int $qty |
|
| 154 | + * @return EE_Line_Item |
|
| 155 | + * @throws EE_Error |
|
| 156 | + * @throws InvalidArgumentException |
|
| 157 | + * @throws InvalidDataTypeException |
|
| 158 | + * @throws InvalidInterfaceException |
|
| 159 | + * @throws ReflectionException |
|
| 160 | + */ |
|
| 161 | + public static function add_ticket_purchase(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
| 162 | + { |
|
| 163 | + if (! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) { |
|
| 164 | + throw new EE_Error( |
|
| 165 | + sprintf( |
|
| 166 | + esc_html__( |
|
| 167 | + 'A valid line item total is required in order to add tickets. A line item of type "%s" was passed.', |
|
| 168 | + 'event_espresso' |
|
| 169 | + ), |
|
| 170 | + $ticket->ID(), |
|
| 171 | + $total_line_item->ID() |
|
| 172 | + ) |
|
| 173 | + ); |
|
| 174 | + } |
|
| 175 | + // either increment the qty for an existing ticket |
|
| 176 | + $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty); |
|
| 177 | + // or add a new one |
|
| 178 | + if (! $line_item instanceof EE_Line_Item) { |
|
| 179 | + $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty); |
|
| 180 | + } |
|
| 181 | + $total_line_item->recalculate_total_including_taxes(); |
|
| 182 | + return $line_item; |
|
| 183 | + } |
|
| 184 | + |
|
| 185 | + |
|
| 186 | + /** |
|
| 187 | + * Returns the new line item created by adding a purchase of the ticket |
|
| 188 | + * |
|
| 189 | + * @param EE_Line_Item $total_line_item |
|
| 190 | + * @param EE_Ticket $ticket |
|
| 191 | + * @param int $qty |
|
| 192 | + * @return EE_Line_Item |
|
| 193 | + * @throws EE_Error |
|
| 194 | + * @throws InvalidArgumentException |
|
| 195 | + * @throws InvalidDataTypeException |
|
| 196 | + * @throws InvalidInterfaceException |
|
| 197 | + * @throws ReflectionException |
|
| 198 | + */ |
|
| 199 | + public static function increment_ticket_qty_if_already_in_cart( |
|
| 200 | + EE_Line_Item $total_line_item, |
|
| 201 | + EE_Ticket $ticket, |
|
| 202 | + $qty = 1 |
|
| 203 | + ) { |
|
| 204 | + $line_item = null; |
|
| 205 | + if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) { |
|
| 206 | + $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item); |
|
| 207 | + foreach ((array) $ticket_line_items as $ticket_line_item) { |
|
| 208 | + if ( |
|
| 209 | + $ticket_line_item instanceof EE_Line_Item |
|
| 210 | + && (int) $ticket_line_item->OBJ_ID() === (int) $ticket->ID() |
|
| 211 | + ) { |
|
| 212 | + $line_item = $ticket_line_item; |
|
| 213 | + break; |
|
| 214 | + } |
|
| 215 | + } |
|
| 216 | + } |
|
| 217 | + if ($line_item instanceof EE_Line_Item) { |
|
| 218 | + EEH_Line_Item::increment_quantity($line_item, $qty); |
|
| 219 | + return $line_item; |
|
| 220 | + } |
|
| 221 | + return null; |
|
| 222 | + } |
|
| 223 | + |
|
| 224 | + |
|
| 225 | + /** |
|
| 226 | + * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
| 227 | + * Does NOT save or recalculate other line items totals |
|
| 228 | + * |
|
| 229 | + * @param EE_Line_Item $line_item |
|
| 230 | + * @param int $qty |
|
| 231 | + * @return void |
|
| 232 | + * @throws EE_Error |
|
| 233 | + * @throws InvalidArgumentException |
|
| 234 | + * @throws InvalidDataTypeException |
|
| 235 | + * @throws InvalidInterfaceException |
|
| 236 | + * @throws ReflectionException |
|
| 237 | + */ |
|
| 238 | + public static function increment_quantity(EE_Line_Item $line_item, $qty = 1) |
|
| 239 | + { |
|
| 240 | + if (! $line_item->is_percent()) { |
|
| 241 | + $qty += $line_item->quantity(); |
|
| 242 | + $line_item->set_quantity($qty); |
|
| 243 | + $line_item->set_total($line_item->unit_price() * $qty); |
|
| 244 | + $line_item->save(); |
|
| 245 | + } |
|
| 246 | + foreach ($line_item->children() as $child) { |
|
| 247 | + if ($child->is_sub_line_item()) { |
|
| 248 | + EEH_Line_Item::update_quantity($child, $qty); |
|
| 249 | + } |
|
| 250 | + } |
|
| 251 | + } |
|
| 252 | + |
|
| 253 | + |
|
| 254 | + /** |
|
| 255 | + * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
| 256 | + * Does NOT save or recalculate other line items totals |
|
| 257 | + * |
|
| 258 | + * @param EE_Line_Item $line_item |
|
| 259 | + * @param int $qty |
|
| 260 | + * @return void |
|
| 261 | + * @throws EE_Error |
|
| 262 | + * @throws InvalidArgumentException |
|
| 263 | + * @throws InvalidDataTypeException |
|
| 264 | + * @throws InvalidInterfaceException |
|
| 265 | + * @throws ReflectionException |
|
| 266 | + */ |
|
| 267 | + public static function decrement_quantity(EE_Line_Item $line_item, $qty = 1) |
|
| 268 | + { |
|
| 269 | + if (! $line_item->is_percent()) { |
|
| 270 | + $qty = $line_item->quantity() - $qty; |
|
| 271 | + $qty = max($qty, 0); |
|
| 272 | + $line_item->set_quantity($qty); |
|
| 273 | + $line_item->set_total($line_item->unit_price() * $qty); |
|
| 274 | + $line_item->save(); |
|
| 275 | + } |
|
| 276 | + foreach ($line_item->children() as $child) { |
|
| 277 | + if ($child->is_sub_line_item()) { |
|
| 278 | + EEH_Line_Item::update_quantity($child, $qty); |
|
| 279 | + } |
|
| 280 | + } |
|
| 281 | + } |
|
| 282 | + |
|
| 283 | + |
|
| 284 | + /** |
|
| 285 | + * Updates the line item and its children's quantities to the specified number. |
|
| 286 | + * Does NOT save them or recalculate totals. |
|
| 287 | + * |
|
| 288 | + * @param EE_Line_Item $line_item |
|
| 289 | + * @param int $new_quantity |
|
| 290 | + * @throws EE_Error |
|
| 291 | + * @throws InvalidArgumentException |
|
| 292 | + * @throws InvalidDataTypeException |
|
| 293 | + * @throws InvalidInterfaceException |
|
| 294 | + * @throws ReflectionException |
|
| 295 | + */ |
|
| 296 | + public static function update_quantity(EE_Line_Item $line_item, $new_quantity) |
|
| 297 | + { |
|
| 298 | + if (! $line_item->is_percent()) { |
|
| 299 | + $line_item->set_quantity($new_quantity); |
|
| 300 | + $line_item->set_total($line_item->unit_price() * $new_quantity); |
|
| 301 | + $line_item->save(); |
|
| 302 | + } |
|
| 303 | + foreach ($line_item->children() as $child) { |
|
| 304 | + if ($child->is_sub_line_item()) { |
|
| 305 | + EEH_Line_Item::update_quantity($child, $new_quantity); |
|
| 306 | + } |
|
| 307 | + } |
|
| 308 | + } |
|
| 309 | + |
|
| 310 | + |
|
| 311 | + /** |
|
| 312 | + * Returns the new line item created by adding a purchase of the ticket |
|
| 313 | + * |
|
| 314 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 315 | + * @param EE_Ticket $ticket |
|
| 316 | + * @param int $qty |
|
| 317 | + * @return EE_Line_Item |
|
| 318 | + * @throws EE_Error |
|
| 319 | + * @throws InvalidArgumentException |
|
| 320 | + * @throws InvalidDataTypeException |
|
| 321 | + * @throws InvalidInterfaceException |
|
| 322 | + * @throws ReflectionException |
|
| 323 | + */ |
|
| 324 | + public static function create_ticket_line_item(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
| 325 | + { |
|
| 326 | + $datetimes = $ticket->datetimes(); |
|
| 327 | + $first_datetime = reset($datetimes); |
|
| 328 | + $first_datetime_name = esc_html__('Event', 'event_espresso'); |
|
| 329 | + if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) { |
|
| 330 | + $first_datetime_name = $first_datetime->event()->name(); |
|
| 331 | + } |
|
| 332 | + $event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name); |
|
| 333 | + // get event subtotal line |
|
| 334 | + $events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket); |
|
| 335 | + $taxes = $ticket->tax_price_modifiers(); |
|
| 336 | + // add $ticket to cart |
|
| 337 | + $line_item = EE_Line_Item::new_instance(array( |
|
| 338 | + 'LIN_name' => $ticket->name(), |
|
| 339 | + 'LIN_desc' => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event, |
|
| 340 | + 'LIN_unit_price' => $ticket->price(), |
|
| 341 | + 'LIN_quantity' => $qty, |
|
| 342 | + 'LIN_is_taxable' => empty($taxes) && $ticket->taxable(), |
|
| 343 | + 'LIN_order' => count($events_sub_total->children()), |
|
| 344 | + 'LIN_total' => $ticket->price() * $qty, |
|
| 345 | + 'LIN_type' => EEM_Line_Item::type_line_item, |
|
| 346 | + 'OBJ_ID' => $ticket->ID(), |
|
| 347 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
| 348 | + )); |
|
| 349 | + $line_item = apply_filters( |
|
| 350 | + 'FHEE__EEH_Line_Item__create_ticket_line_item__line_item', |
|
| 351 | + $line_item |
|
| 352 | + ); |
|
| 353 | + if (!$line_item instanceof EE_Line_Item) { |
|
| 354 | + throw new DomainException( |
|
| 355 | + esc_html__('Invalid EE_Line_Item received.', 'event_espresso') |
|
| 356 | + ); |
|
| 357 | + } |
|
| 358 | + $events_sub_total->add_child_line_item($line_item); |
|
| 359 | + // now add the sub-line items |
|
| 360 | + $running_total = 0; |
|
| 361 | + $running_pre_tax_total = 0; |
|
| 362 | + foreach ($ticket->prices() as $price) { |
|
| 363 | + $sign = $price->is_discount() ? -1 : 1; |
|
| 364 | + $price_total = $price->is_percent() |
|
| 365 | + ? $running_pre_tax_total * $price->amount() / 100 |
|
| 366 | + : $price->amount() * $qty; |
|
| 367 | + if ($price->is_percent()) { |
|
| 368 | + $percent = $sign * $price->amount(); |
|
| 369 | + $unit_price = 0; |
|
| 370 | + } else { |
|
| 371 | + $percent = 0; |
|
| 372 | + $unit_price = $sign * $price->amount(); |
|
| 373 | + } |
|
| 374 | + $sub_line_item = EE_Line_Item::new_instance(array( |
|
| 375 | + 'LIN_name' => $price->name(), |
|
| 376 | + 'LIN_desc' => $price->desc(), |
|
| 377 | + 'LIN_quantity' => $price->is_percent() ? null : $qty, |
|
| 378 | + 'LIN_is_taxable' => false, |
|
| 379 | + 'LIN_order' => $price->order(), |
|
| 380 | + 'LIN_total' => $price_total, |
|
| 381 | + 'LIN_pretax' => 0, |
|
| 382 | + 'LIN_unit_price' => $unit_price, |
|
| 383 | + 'LIN_percent' => $percent, |
|
| 384 | + 'LIN_type' => $price->is_tax() ? EEM_Line_Item::type_sub_tax : EEM_Line_Item::type_sub_line_item, |
|
| 385 | + 'OBJ_ID' => $price->ID(), |
|
| 386 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PRICE, |
|
| 387 | + )); |
|
| 388 | + $sub_line_item = apply_filters( |
|
| 389 | + 'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item', |
|
| 390 | + $sub_line_item |
|
| 391 | + ); |
|
| 392 | + $running_total += $sign * $price_total; |
|
| 393 | + $running_pre_tax_total += ! $price->is_tax() ? $sign * $price_total : 0; |
|
| 394 | + $line_item->add_child_line_item($sub_line_item); |
|
| 395 | + } |
|
| 396 | + $line_item->setPretaxTotal($running_pre_tax_total); |
|
| 397 | + return $line_item; |
|
| 398 | + } |
|
| 399 | + |
|
| 400 | + |
|
| 401 | + /** |
|
| 402 | + * Adds the specified item under the pre-tax-sub-total line item. Automatically |
|
| 403 | + * re-calculates the line item totals and updates the related transaction. But |
|
| 404 | + * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
| 405 | + * should probably change because of this). |
|
| 406 | + * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
| 407 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
| 408 | + * |
|
| 409 | + * @param EE_Line_Item $total_line_item |
|
| 410 | + * @param EE_Line_Item $item to be added |
|
| 411 | + * @return boolean |
|
| 412 | + * @throws EE_Error |
|
| 413 | + * @throws InvalidArgumentException |
|
| 414 | + * @throws InvalidDataTypeException |
|
| 415 | + * @throws InvalidInterfaceException |
|
| 416 | + * @throws ReflectionException |
|
| 417 | + */ |
|
| 418 | + public static function add_item(EE_Line_Item $total_line_item, EE_Line_Item $item, $recalculate_totals = true) |
|
| 419 | + { |
|
| 420 | + $pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item); |
|
| 421 | + if ($pre_tax_subtotal instanceof EE_Line_Item) { |
|
| 422 | + $success = $pre_tax_subtotal->add_child_line_item($item); |
|
| 423 | + } else { |
|
| 424 | + return false; |
|
| 425 | + } |
|
| 426 | + if ($recalculate_totals) { |
|
| 427 | + $total_line_item->recalculate_total_including_taxes(); |
|
| 428 | + } |
|
| 429 | + return $success; |
|
| 430 | + } |
|
| 431 | + |
|
| 432 | + |
|
| 433 | + /** |
|
| 434 | + * cancels an existing ticket line item, |
|
| 435 | + * by decrementing it's quantity by 1 and adding a new "type_cancellation" sub-line-item. |
|
| 436 | + * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
| 437 | + * |
|
| 438 | + * @param EE_Line_Item $ticket_line_item |
|
| 439 | + * @param int $qty |
|
| 440 | + * @return bool success |
|
| 441 | + * @throws EE_Error |
|
| 442 | + * @throws InvalidArgumentException |
|
| 443 | + * @throws InvalidDataTypeException |
|
| 444 | + * @throws InvalidInterfaceException |
|
| 445 | + * @throws ReflectionException |
|
| 446 | + */ |
|
| 447 | + public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
| 448 | + { |
|
| 449 | + // validate incoming line_item |
|
| 450 | + if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
| 451 | + throw new EE_Error( |
|
| 452 | + sprintf( |
|
| 453 | + esc_html__( |
|
| 454 | + 'The supplied line item must have an Object Type of "Ticket", not %1$s.', |
|
| 455 | + 'event_espresso' |
|
| 456 | + ), |
|
| 457 | + $ticket_line_item->type() |
|
| 458 | + ) |
|
| 459 | + ); |
|
| 460 | + } |
|
| 461 | + if ($ticket_line_item->quantity() < $qty) { |
|
| 462 | + throw new EE_Error( |
|
| 463 | + sprintf( |
|
| 464 | + esc_html__( |
|
| 465 | + 'Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.', |
|
| 466 | + 'event_espresso' |
|
| 467 | + ), |
|
| 468 | + $qty, |
|
| 469 | + $ticket_line_item->quantity() |
|
| 470 | + ) |
|
| 471 | + ); |
|
| 472 | + } |
|
| 473 | + // decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this |
|
| 474 | + $ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty); |
|
| 475 | + foreach ($ticket_line_item->children() as $child_line_item) { |
|
| 476 | + if ( |
|
| 477 | + $child_line_item->is_sub_line_item() |
|
| 478 | + && ! $child_line_item->is_percent() |
|
| 479 | + && ! $child_line_item->is_cancellation() |
|
| 480 | + ) { |
|
| 481 | + $child_line_item->set_quantity($child_line_item->quantity() - $qty); |
|
| 482 | + } |
|
| 483 | + } |
|
| 484 | + // get cancellation sub line item |
|
| 485 | + $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
| 486 | + $ticket_line_item, |
|
| 487 | + EEM_Line_Item::type_cancellation |
|
| 488 | + ); |
|
| 489 | + $cancellation_line_item = reset($cancellation_line_item); |
|
| 490 | + // verify that this ticket was indeed previously cancelled |
|
| 491 | + if ($cancellation_line_item instanceof EE_Line_Item) { |
|
| 492 | + // increment cancelled quantity |
|
| 493 | + $cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty); |
|
| 494 | + } else { |
|
| 495 | + // create cancellation sub line item |
|
| 496 | + $cancellation_line_item = EE_Line_Item::new_instance(array( |
|
| 497 | + 'LIN_name' => esc_html__('Cancellation', 'event_espresso'), |
|
| 498 | + 'LIN_desc' => sprintf( |
|
| 499 | + esc_html_x( |
|
| 500 | + 'Cancelled %1$s : %2$s', |
|
| 501 | + 'Cancelled Ticket Name : 2015-01-01 11:11', |
|
| 502 | + 'event_espresso' |
|
| 503 | + ), |
|
| 504 | + $ticket_line_item->name(), |
|
| 505 | + current_time(get_option('date_format') . ' ' . get_option('time_format')) |
|
| 506 | + ), |
|
| 507 | + 'LIN_unit_price' => 0, // $ticket_line_item->unit_price() |
|
| 508 | + 'LIN_quantity' => $qty, |
|
| 509 | + 'LIN_is_taxable' => $ticket_line_item->is_taxable(), |
|
| 510 | + 'LIN_order' => count($ticket_line_item->children()), |
|
| 511 | + 'LIN_total' => 0, // $ticket_line_item->unit_price() |
|
| 512 | + 'LIN_type' => EEM_Line_Item::type_cancellation, |
|
| 513 | + )); |
|
| 514 | + $ticket_line_item->add_child_line_item($cancellation_line_item); |
|
| 515 | + } |
|
| 516 | + if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
| 517 | + // decrement parent line item quantity |
|
| 518 | + $event_line_item = $ticket_line_item->parent(); |
|
| 519 | + if ( |
|
| 520 | + $event_line_item instanceof EE_Line_Item |
|
| 521 | + && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
| 522 | + ) { |
|
| 523 | + $event_line_item->set_quantity($event_line_item->quantity() - $qty); |
|
| 524 | + $event_line_item->save(); |
|
| 525 | + } |
|
| 526 | + EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
| 527 | + return true; |
|
| 528 | + } |
|
| 529 | + return false; |
|
| 530 | + } |
|
| 531 | + |
|
| 532 | + |
|
| 533 | + /** |
|
| 534 | + * reinstates (un-cancels?) a previously canceled ticket line item, |
|
| 535 | + * by incrementing it's quantity by 1, and decrementing it's "type_cancellation" sub-line-item. |
|
| 536 | + * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
| 537 | + * |
|
| 538 | + * @param EE_Line_Item $ticket_line_item |
|
| 539 | + * @param int $qty |
|
| 540 | + * @return bool success |
|
| 541 | + * @throws EE_Error |
|
| 542 | + * @throws InvalidArgumentException |
|
| 543 | + * @throws InvalidDataTypeException |
|
| 544 | + * @throws InvalidInterfaceException |
|
| 545 | + * @throws ReflectionException |
|
| 546 | + */ |
|
| 547 | + public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
| 548 | + { |
|
| 549 | + // validate incoming line_item |
|
| 550 | + if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
| 551 | + throw new EE_Error( |
|
| 552 | + sprintf( |
|
| 553 | + esc_html__( |
|
| 554 | + 'The supplied line item must have an Object Type of "Ticket", not %1$s.', |
|
| 555 | + 'event_espresso' |
|
| 556 | + ), |
|
| 557 | + $ticket_line_item->type() |
|
| 558 | + ) |
|
| 559 | + ); |
|
| 560 | + } |
|
| 561 | + // get cancellation sub line item |
|
| 562 | + $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
| 563 | + $ticket_line_item, |
|
| 564 | + EEM_Line_Item::type_cancellation |
|
| 565 | + ); |
|
| 566 | + $cancellation_line_item = reset($cancellation_line_item); |
|
| 567 | + // verify that this ticket was indeed previously cancelled |
|
| 568 | + if (! $cancellation_line_item instanceof EE_Line_Item) { |
|
| 569 | + return false; |
|
| 570 | + } |
|
| 571 | + if ($cancellation_line_item->quantity() > $qty) { |
|
| 572 | + // decrement cancelled quantity |
|
| 573 | + $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
| 574 | + } elseif ($cancellation_line_item->quantity() === $qty) { |
|
| 575 | + // decrement cancelled quantity in case anyone still has the object kicking around |
|
| 576 | + $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
| 577 | + // delete because quantity will end up as 0 |
|
| 578 | + $cancellation_line_item->delete(); |
|
| 579 | + // and attempt to destroy the object, |
|
| 580 | + // even though PHP won't actually destroy it until it needs the memory |
|
| 581 | + unset($cancellation_line_item); |
|
| 582 | + } else { |
|
| 583 | + // what ?!?! negative quantity ?!?! |
|
| 584 | + throw new EE_Error( |
|
| 585 | + sprintf( |
|
| 586 | + esc_html__( |
|
| 587 | + 'Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.', |
|
| 588 | + 'event_espresso' |
|
| 589 | + ), |
|
| 590 | + $qty, |
|
| 591 | + $cancellation_line_item->quantity() |
|
| 592 | + ) |
|
| 593 | + ); |
|
| 594 | + } |
|
| 595 | + // increment ticket quantity |
|
| 596 | + $ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty); |
|
| 597 | + if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
| 598 | + // increment parent line item quantity |
|
| 599 | + $event_line_item = $ticket_line_item->parent(); |
|
| 600 | + if ( |
|
| 601 | + $event_line_item instanceof EE_Line_Item |
|
| 602 | + && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
| 603 | + ) { |
|
| 604 | + $event_line_item->set_quantity($event_line_item->quantity() + $qty); |
|
| 605 | + } |
|
| 606 | + EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
| 607 | + return true; |
|
| 608 | + } |
|
| 609 | + return false; |
|
| 610 | + } |
|
| 611 | + |
|
| 612 | + |
|
| 613 | + /** |
|
| 614 | + * calls EEH_Line_Item::find_transaction_grand_total_for_line_item() |
|
| 615 | + * then EE_Line_Item::recalculate_total_including_taxes() on the result |
|
| 616 | + * |
|
| 617 | + * @param EE_Line_Item $line_item |
|
| 618 | + * @return float |
|
| 619 | + * @throws EE_Error |
|
| 620 | + * @throws InvalidArgumentException |
|
| 621 | + * @throws InvalidDataTypeException |
|
| 622 | + * @throws InvalidInterfaceException |
|
| 623 | + * @throws ReflectionException |
|
| 624 | + */ |
|
| 625 | + public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item) |
|
| 626 | + { |
|
| 627 | + $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item); |
|
| 628 | + return $grand_total_line_item->recalculate_total_including_taxes(); |
|
| 629 | + } |
|
| 630 | + |
|
| 631 | + |
|
| 632 | + /** |
|
| 633 | + * Gets the line item which contains the subtotal of all the items |
|
| 634 | + * |
|
| 635 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 636 | + * @return EE_Line_Item |
|
| 637 | + * @throws EE_Error |
|
| 638 | + * @throws InvalidArgumentException |
|
| 639 | + * @throws InvalidDataTypeException |
|
| 640 | + * @throws InvalidInterfaceException |
|
| 641 | + * @throws ReflectionException |
|
| 642 | + */ |
|
| 643 | + public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item) |
|
| 644 | + { |
|
| 645 | + $pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal'); |
|
| 646 | + return $pre_tax_subtotal instanceof EE_Line_Item |
|
| 647 | + ? $pre_tax_subtotal |
|
| 648 | + : self::create_pre_tax_subtotal($total_line_item); |
|
| 649 | + } |
|
| 650 | + |
|
| 651 | + |
|
| 652 | + /** |
|
| 653 | + * Gets the line item for the taxes subtotal |
|
| 654 | + * |
|
| 655 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 656 | + * @return EE_Line_Item |
|
| 657 | + * @throws EE_Error |
|
| 658 | + * @throws InvalidArgumentException |
|
| 659 | + * @throws InvalidDataTypeException |
|
| 660 | + * @throws InvalidInterfaceException |
|
| 661 | + * @throws ReflectionException |
|
| 662 | + */ |
|
| 663 | + public static function get_taxes_subtotal(EE_Line_Item $total_line_item) |
|
| 664 | + { |
|
| 665 | + $taxes = $total_line_item->get_child_line_item('taxes'); |
|
| 666 | + return $taxes ? $taxes : self::create_taxes_subtotal($total_line_item); |
|
| 667 | + } |
|
| 668 | + |
|
| 669 | + |
|
| 670 | + /** |
|
| 671 | + * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object |
|
| 672 | + * |
|
| 673 | + * @param EE_Line_Item $line_item |
|
| 674 | + * @param EE_Transaction $transaction |
|
| 675 | + * @return void |
|
| 676 | + * @throws EE_Error |
|
| 677 | + * @throws InvalidArgumentException |
|
| 678 | + * @throws InvalidDataTypeException |
|
| 679 | + * @throws InvalidInterfaceException |
|
| 680 | + * @throws ReflectionException |
|
| 681 | + */ |
|
| 682 | + public static function set_TXN_ID(EE_Line_Item $line_item, $transaction = null) |
|
| 683 | + { |
|
| 684 | + if ($transaction) { |
|
| 685 | + /** @type EEM_Transaction $EEM_Transaction */ |
|
| 686 | + $EEM_Transaction = EE_Registry::instance()->load_model('Transaction'); |
|
| 687 | + $TXN_ID = $EEM_Transaction->ensure_is_ID($transaction); |
|
| 688 | + $line_item->set_TXN_ID($TXN_ID); |
|
| 689 | + } |
|
| 690 | + } |
|
| 691 | + |
|
| 692 | + |
|
| 693 | + /** |
|
| 694 | + * Creates a new default total line item for the transaction, |
|
| 695 | + * and its tickets subtotal and taxes subtotal line items (and adds the |
|
| 696 | + * existing taxes as children of the taxes subtotal line item) |
|
| 697 | + * |
|
| 698 | + * @param EE_Transaction $transaction |
|
| 699 | + * @return EE_Line_Item of type total |
|
| 700 | + * @throws EE_Error |
|
| 701 | + * @throws InvalidArgumentException |
|
| 702 | + * @throws InvalidDataTypeException |
|
| 703 | + * @throws InvalidInterfaceException |
|
| 704 | + * @throws ReflectionException |
|
| 705 | + */ |
|
| 706 | + public static function create_total_line_item($transaction = null) |
|
| 707 | + { |
|
| 708 | + $total_line_item = EE_Line_Item::new_instance(array( |
|
| 709 | + 'LIN_code' => 'total', |
|
| 710 | + 'LIN_name' => esc_html__('Grand Total', 'event_espresso'), |
|
| 711 | + 'LIN_type' => EEM_Line_Item::type_total, |
|
| 712 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TRANSACTION, |
|
| 713 | + )); |
|
| 714 | + $total_line_item = apply_filters( |
|
| 715 | + 'FHEE__EEH_Line_Item__create_total_line_item__total_line_item', |
|
| 716 | + $total_line_item |
|
| 717 | + ); |
|
| 718 | + self::set_TXN_ID($total_line_item, $transaction); |
|
| 719 | + self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
| 720 | + self::create_taxes_subtotal($total_line_item, $transaction); |
|
| 721 | + return $total_line_item; |
|
| 722 | + } |
|
| 723 | + |
|
| 724 | + |
|
| 725 | + /** |
|
| 726 | + * Creates a default items subtotal line item |
|
| 727 | + * |
|
| 728 | + * @param EE_Line_Item $total_line_item |
|
| 729 | + * @param EE_Transaction $transaction |
|
| 730 | + * @return EE_Line_Item |
|
| 731 | + * @throws EE_Error |
|
| 732 | + * @throws InvalidArgumentException |
|
| 733 | + * @throws InvalidDataTypeException |
|
| 734 | + * @throws InvalidInterfaceException |
|
| 735 | + * @throws ReflectionException |
|
| 736 | + */ |
|
| 737 | + protected static function create_pre_tax_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
| 738 | + { |
|
| 739 | + $pre_tax_line_item = EE_Line_Item::new_instance(array( |
|
| 740 | + 'LIN_code' => 'pre-tax-subtotal', |
|
| 741 | + 'LIN_name' => esc_html__('Pre-Tax Subtotal', 'event_espresso'), |
|
| 742 | + 'LIN_type' => EEM_Line_Item::type_sub_total, |
|
| 743 | + )); |
|
| 744 | + $pre_tax_line_item = apply_filters( |
|
| 745 | + 'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item', |
|
| 746 | + $pre_tax_line_item |
|
| 747 | + ); |
|
| 748 | + self::set_TXN_ID($pre_tax_line_item, $transaction); |
|
| 749 | + $total_line_item->add_child_line_item($pre_tax_line_item); |
|
| 750 | + self::create_event_subtotal($pre_tax_line_item, $transaction); |
|
| 751 | + return $pre_tax_line_item; |
|
| 752 | + } |
|
| 753 | + |
|
| 754 | + |
|
| 755 | + /** |
|
| 756 | + * Creates a line item for the taxes subtotal and finds all the tax prices |
|
| 757 | + * and applies taxes to it |
|
| 758 | + * |
|
| 759 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 760 | + * @param EE_Transaction $transaction |
|
| 761 | + * @return EE_Line_Item |
|
| 762 | + * @throws EE_Error |
|
| 763 | + * @throws InvalidArgumentException |
|
| 764 | + * @throws InvalidDataTypeException |
|
| 765 | + * @throws InvalidInterfaceException |
|
| 766 | + * @throws ReflectionException |
|
| 767 | + */ |
|
| 768 | + protected static function create_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
| 769 | + { |
|
| 770 | + $tax_line_item = EE_Line_Item::new_instance(array( |
|
| 771 | + 'LIN_code' => 'taxes', |
|
| 772 | + 'LIN_name' => esc_html__('Taxes', 'event_espresso'), |
|
| 773 | + 'LIN_type' => EEM_Line_Item::type_tax_sub_total, |
|
| 774 | + 'LIN_order' => 1000,// this should always come last |
|
| 775 | + )); |
|
| 776 | + $tax_line_item = apply_filters( |
|
| 777 | + 'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item', |
|
| 778 | + $tax_line_item |
|
| 779 | + ); |
|
| 780 | + self::set_TXN_ID($tax_line_item, $transaction); |
|
| 781 | + $total_line_item->add_child_line_item($tax_line_item); |
|
| 782 | + // and lastly, add the actual taxes |
|
| 783 | + self::apply_taxes($total_line_item); |
|
| 784 | + return $tax_line_item; |
|
| 785 | + } |
|
| 786 | + |
|
| 787 | + |
|
| 788 | + /** |
|
| 789 | + * Creates a default items subtotal line item |
|
| 790 | + * |
|
| 791 | + * @param EE_Line_Item $pre_tax_line_item |
|
| 792 | + * @param EE_Transaction $transaction |
|
| 793 | + * @param EE_Event $event |
|
| 794 | + * @return EE_Line_Item |
|
| 795 | + * @throws EE_Error |
|
| 796 | + * @throws InvalidArgumentException |
|
| 797 | + * @throws InvalidDataTypeException |
|
| 798 | + * @throws InvalidInterfaceException |
|
| 799 | + * @throws ReflectionException |
|
| 800 | + */ |
|
| 801 | + public static function create_event_subtotal(EE_Line_Item $pre_tax_line_item, $transaction = null, $event = null) |
|
| 802 | + { |
|
| 803 | + $event_line_item = EE_Line_Item::new_instance(array( |
|
| 804 | + 'LIN_code' => self::get_event_code($event), |
|
| 805 | + 'LIN_name' => self::get_event_name($event), |
|
| 806 | + 'LIN_desc' => self::get_event_desc($event), |
|
| 807 | + 'LIN_type' => EEM_Line_Item::type_sub_total, |
|
| 808 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_EVENT, |
|
| 809 | + 'OBJ_ID' => $event instanceof EE_Event ? $event->ID() : 0, |
|
| 810 | + )); |
|
| 811 | + $event_line_item = apply_filters( |
|
| 812 | + 'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item', |
|
| 813 | + $event_line_item |
|
| 814 | + ); |
|
| 815 | + self::set_TXN_ID($event_line_item, $transaction); |
|
| 816 | + $pre_tax_line_item->add_child_line_item($event_line_item); |
|
| 817 | + return $event_line_item; |
|
| 818 | + } |
|
| 819 | + |
|
| 820 | + |
|
| 821 | + /** |
|
| 822 | + * Gets what the event ticket's code SHOULD be |
|
| 823 | + * |
|
| 824 | + * @param EE_Event $event |
|
| 825 | + * @return string |
|
| 826 | + * @throws EE_Error |
|
| 827 | + */ |
|
| 828 | + public static function get_event_code($event) |
|
| 829 | + { |
|
| 830 | + return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0'); |
|
| 831 | + } |
|
| 832 | + |
|
| 833 | + |
|
| 834 | + /** |
|
| 835 | + * Gets the event name |
|
| 836 | + * |
|
| 837 | + * @param EE_Event $event |
|
| 838 | + * @return string |
|
| 839 | + * @throws EE_Error |
|
| 840 | + */ |
|
| 841 | + public static function get_event_name($event) |
|
| 842 | + { |
|
| 843 | + return $event instanceof EE_Event |
|
| 844 | + ? mb_substr($event->name(), 0, 245) |
|
| 845 | + : esc_html__('Event', 'event_espresso'); |
|
| 846 | + } |
|
| 847 | + |
|
| 848 | + |
|
| 849 | + /** |
|
| 850 | + * Gets the event excerpt |
|
| 851 | + * |
|
| 852 | + * @param EE_Event $event |
|
| 853 | + * @return string |
|
| 854 | + * @throws EE_Error |
|
| 855 | + */ |
|
| 856 | + public static function get_event_desc($event) |
|
| 857 | + { |
|
| 858 | + return $event instanceof EE_Event ? $event->short_description() : ''; |
|
| 859 | + } |
|
| 860 | + |
|
| 861 | + |
|
| 862 | + /** |
|
| 863 | + * Given the grand total line item and a ticket, finds the event sub-total |
|
| 864 | + * line item the ticket's purchase should be added onto |
|
| 865 | + * |
|
| 866 | + * @access public |
|
| 867 | + * @param EE_Line_Item $grand_total the grand total line item |
|
| 868 | + * @param EE_Ticket $ticket |
|
| 869 | + * @return EE_Line_Item |
|
| 870 | + * @throws EE_Error |
|
| 871 | + * @throws InvalidArgumentException |
|
| 872 | + * @throws InvalidDataTypeException |
|
| 873 | + * @throws InvalidInterfaceException |
|
| 874 | + * @throws ReflectionException |
|
| 875 | + */ |
|
| 876 | + public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket) |
|
| 877 | + { |
|
| 878 | + $first_datetime = $ticket->first_datetime(); |
|
| 879 | + if (! $first_datetime instanceof EE_Datetime) { |
|
| 880 | + throw new EE_Error( |
|
| 881 | + sprintf( |
|
| 882 | + __('The supplied ticket (ID %d) has no datetimes', 'event_espresso'), |
|
| 883 | + $ticket->ID() |
|
| 884 | + ) |
|
| 885 | + ); |
|
| 886 | + } |
|
| 887 | + $event = $first_datetime->event(); |
|
| 888 | + if (! $event instanceof EE_Event) { |
|
| 889 | + throw new EE_Error( |
|
| 890 | + sprintf( |
|
| 891 | + esc_html__( |
|
| 892 | + 'The supplied ticket (ID %d) has no event data associated with it.', |
|
| 893 | + 'event_espresso' |
|
| 894 | + ), |
|
| 895 | + $ticket->ID() |
|
| 896 | + ) |
|
| 897 | + ); |
|
| 898 | + } |
|
| 899 | + $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event); |
|
| 900 | + if (! $events_sub_total instanceof EE_Line_Item) { |
|
| 901 | + throw new EE_Error( |
|
| 902 | + sprintf( |
|
| 903 | + esc_html__( |
|
| 904 | + 'There is no events sub-total for ticket %s on total line item %d', |
|
| 905 | + 'event_espresso' |
|
| 906 | + ), |
|
| 907 | + $ticket->ID(), |
|
| 908 | + $grand_total->ID() |
|
| 909 | + ) |
|
| 910 | + ); |
|
| 911 | + } |
|
| 912 | + return $events_sub_total; |
|
| 913 | + } |
|
| 914 | + |
|
| 915 | + |
|
| 916 | + /** |
|
| 917 | + * Gets the event line item |
|
| 918 | + * |
|
| 919 | + * @param EE_Line_Item $grand_total |
|
| 920 | + * @param EE_Event $event |
|
| 921 | + * @return EE_Line_Item for the event subtotal which is a child of $grand_total |
|
| 922 | + * @throws EE_Error |
|
| 923 | + * @throws InvalidArgumentException |
|
| 924 | + * @throws InvalidDataTypeException |
|
| 925 | + * @throws InvalidInterfaceException |
|
| 926 | + * @throws ReflectionException |
|
| 927 | + */ |
|
| 928 | + public static function get_event_line_item(EE_Line_Item $grand_total, $event) |
|
| 929 | + { |
|
| 930 | + /** @type EE_Event $event */ |
|
| 931 | + $event = EEM_Event::instance()->ensure_is_obj($event, true); |
|
| 932 | + $event_line_item = null; |
|
| 933 | + $found = false; |
|
| 934 | + foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) { |
|
| 935 | + // default event subtotal, we should only ever find this the first time this method is called |
|
| 936 | + if (! $event_line_item->OBJ_ID()) { |
|
| 937 | + // let's use this! but first... set the event details |
|
| 938 | + EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
| 939 | + $found = true; |
|
| 940 | + break; |
|
| 941 | + } |
|
| 942 | + if ($event_line_item->OBJ_ID() === $event->ID()) { |
|
| 943 | + // found existing line item for this event in the cart, so break out of loop and use this one |
|
| 944 | + $found = true; |
|
| 945 | + break; |
|
| 946 | + } |
|
| 947 | + } |
|
| 948 | + if (! $found) { |
|
| 949 | + // there is no event sub-total yet, so add it |
|
| 950 | + $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total); |
|
| 951 | + // create a new "event" subtotal below that |
|
| 952 | + $event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event); |
|
| 953 | + // and set the event details |
|
| 954 | + EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
| 955 | + } |
|
| 956 | + return $event_line_item; |
|
| 957 | + } |
|
| 958 | + |
|
| 959 | + |
|
| 960 | + /** |
|
| 961 | + * Creates a default items subtotal line item |
|
| 962 | + * |
|
| 963 | + * @param EE_Line_Item $event_line_item |
|
| 964 | + * @param EE_Event $event |
|
| 965 | + * @param EE_Transaction $transaction |
|
| 966 | + * @return void |
|
| 967 | + * @throws EE_Error |
|
| 968 | + * @throws InvalidArgumentException |
|
| 969 | + * @throws InvalidDataTypeException |
|
| 970 | + * @throws InvalidInterfaceException |
|
| 971 | + * @throws ReflectionException |
|
| 972 | + */ |
|
| 973 | + public static function set_event_subtotal_details( |
|
| 974 | + EE_Line_Item $event_line_item, |
|
| 975 | + EE_Event $event, |
|
| 976 | + $transaction = null |
|
| 977 | + ) { |
|
| 978 | + if ($event instanceof EE_Event) { |
|
| 979 | + $event_line_item->set_code(self::get_event_code($event)); |
|
| 980 | + $event_line_item->set_name(self::get_event_name($event)); |
|
| 981 | + $event_line_item->set_desc(self::get_event_desc($event)); |
|
| 982 | + $event_line_item->set_OBJ_ID($event->ID()); |
|
| 983 | + } |
|
| 984 | + self::set_TXN_ID($event_line_item, $transaction); |
|
| 985 | + } |
|
| 986 | + |
|
| 987 | + |
|
| 988 | + /** |
|
| 989 | + * Finds what taxes should apply, adds them as tax line items under the taxes sub-total, |
|
| 990 | + * and recalculates the taxes sub-total and the grand total. Resets the taxes, so |
|
| 991 | + * any old taxes are removed |
|
| 992 | + * |
|
| 993 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 994 | + * @param bool $update_txn_status |
|
| 995 | + * @return bool |
|
| 996 | + * @throws EE_Error |
|
| 997 | + * @throws InvalidArgumentException |
|
| 998 | + * @throws InvalidDataTypeException |
|
| 999 | + * @throws InvalidInterfaceException |
|
| 1000 | + * @throws ReflectionException |
|
| 1001 | + * @throws RuntimeException |
|
| 1002 | + */ |
|
| 1003 | + public static function apply_taxes(EE_Line_Item $total_line_item, $update_txn_status = false) |
|
| 1004 | + { |
|
| 1005 | + $total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($total_line_item); |
|
| 1006 | + $taxes_line_item = self::get_taxes_subtotal($total_line_item); |
|
| 1007 | + $existing_global_taxes = $taxes_line_item->tax_descendants(); |
|
| 1008 | + $updates = false; |
|
| 1009 | + // loop thru taxes |
|
| 1010 | + $global_taxes = EEH_Line_Item::getGlobalTaxes(); |
|
| 1011 | + foreach ($global_taxes as $order => $taxes) { |
|
| 1012 | + foreach ($taxes as $tax) { |
|
| 1013 | + if ($tax instanceof EE_Price) { |
|
| 1014 | + $found = false; |
|
| 1015 | + // check if this is already an existing tax |
|
| 1016 | + foreach ($existing_global_taxes as $existing_global_tax) { |
|
| 1017 | + if ($tax->ID() === $existing_global_tax->OBJ_ID()) { |
|
| 1018 | + // maybe update the tax rate in case it has changed |
|
| 1019 | + if ($existing_global_tax->percent() !== $tax->amount()) { |
|
| 1020 | + $existing_global_tax->set_percent($tax->amount()); |
|
| 1021 | + $existing_global_tax->save(); |
|
| 1022 | + $updates = true; |
|
| 1023 | + } |
|
| 1024 | + $found = true; |
|
| 1025 | + break; |
|
| 1026 | + } |
|
| 1027 | + } |
|
| 1028 | + if (! $found) { |
|
| 1029 | + // add a new line item for this global tax |
|
| 1030 | + $tax_line_item = apply_filters( |
|
| 1031 | + 'FHEE__EEH_Line_Item__apply_taxes__tax_line_item', |
|
| 1032 | + EE_Line_Item::new_instance( |
|
| 1033 | + [ |
|
| 1034 | + 'LIN_name' => $tax->name(), |
|
| 1035 | + 'LIN_desc' => $tax->desc(), |
|
| 1036 | + 'LIN_percent' => $tax->amount(), |
|
| 1037 | + 'LIN_is_taxable' => false, |
|
| 1038 | + 'LIN_order' => $order, |
|
| 1039 | + 'LIN_total' => 0, |
|
| 1040 | + 'LIN_type' => EEM_Line_Item::type_tax, |
|
| 1041 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PRICE, |
|
| 1042 | + 'OBJ_ID' => $tax->ID(), |
|
| 1043 | + ] |
|
| 1044 | + ) |
|
| 1045 | + ); |
|
| 1046 | + $updates = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates; |
|
| 1047 | + } |
|
| 1048 | + } |
|
| 1049 | + } |
|
| 1050 | + } |
|
| 1051 | + // only recalculate totals if something changed |
|
| 1052 | + if ($updates) { |
|
| 1053 | + $total_line_item->recalculate_total_including_taxes($update_txn_status); |
|
| 1054 | + return true; |
|
| 1055 | + } |
|
| 1056 | + return false; |
|
| 1057 | + } |
|
| 1058 | + |
|
| 1059 | + |
|
| 1060 | + /** |
|
| 1061 | + * Ensures that taxes have been applied to the order, if not applies them. |
|
| 1062 | + * Returns the total amount of tax |
|
| 1063 | + * |
|
| 1064 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 1065 | + * @return float |
|
| 1066 | + * @throws EE_Error |
|
| 1067 | + * @throws InvalidArgumentException |
|
| 1068 | + * @throws InvalidDataTypeException |
|
| 1069 | + * @throws InvalidInterfaceException |
|
| 1070 | + * @throws ReflectionException |
|
| 1071 | + */ |
|
| 1072 | + public static function ensure_taxes_applied($total_line_item) |
|
| 1073 | + { |
|
| 1074 | + $taxes_subtotal = self::get_taxes_subtotal($total_line_item); |
|
| 1075 | + if (! $taxes_subtotal->children()) { |
|
| 1076 | + self::apply_taxes($total_line_item); |
|
| 1077 | + } |
|
| 1078 | + return $taxes_subtotal->total(); |
|
| 1079 | + } |
|
| 1080 | + |
|
| 1081 | + |
|
| 1082 | + /** |
|
| 1083 | + * Deletes ALL children of the passed line item |
|
| 1084 | + * |
|
| 1085 | + * @param EE_Line_Item $parent_line_item |
|
| 1086 | + * @return bool |
|
| 1087 | + * @throws EE_Error |
|
| 1088 | + * @throws InvalidArgumentException |
|
| 1089 | + * @throws InvalidDataTypeException |
|
| 1090 | + * @throws InvalidInterfaceException |
|
| 1091 | + * @throws ReflectionException |
|
| 1092 | + */ |
|
| 1093 | + public static function delete_all_child_items(EE_Line_Item $parent_line_item) |
|
| 1094 | + { |
|
| 1095 | + $deleted = 0; |
|
| 1096 | + foreach ($parent_line_item->children() as $child_line_item) { |
|
| 1097 | + if ($child_line_item instanceof EE_Line_Item) { |
|
| 1098 | + $deleted += EEH_Line_Item::delete_all_child_items($child_line_item); |
|
| 1099 | + if ($child_line_item->ID()) { |
|
| 1100 | + $child_line_item->delete(); |
|
| 1101 | + unset($child_line_item); |
|
| 1102 | + } else { |
|
| 1103 | + $parent_line_item->delete_child_line_item($child_line_item->code()); |
|
| 1104 | + } |
|
| 1105 | + $deleted++; |
|
| 1106 | + } |
|
| 1107 | + } |
|
| 1108 | + return $deleted; |
|
| 1109 | + } |
|
| 1110 | + |
|
| 1111 | + |
|
| 1112 | + /** |
|
| 1113 | + * Deletes the line items as indicated by the line item code(s) provided, |
|
| 1114 | + * regardless of where they're found in the line item tree. Automatically |
|
| 1115 | + * re-calculates the line item totals and updates the related transaction. But |
|
| 1116 | + * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
| 1117 | + * should probably change because of this). |
|
| 1118 | + * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
| 1119 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
| 1120 | + * |
|
| 1121 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
| 1122 | + * @param array|bool|string $line_item_codes |
|
| 1123 | + * @return int number of items successfully removed |
|
| 1124 | + * @throws EE_Error |
|
| 1125 | + */ |
|
| 1126 | + public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = false) |
|
| 1127 | + { |
|
| 1128 | + |
|
| 1129 | + if ($total_line_item->type() !== EEM_Line_Item::type_total) { |
|
| 1130 | + EE_Error::doing_it_wrong( |
|
| 1131 | + 'EEH_Line_Item::delete_items', |
|
| 1132 | + esc_html__( |
|
| 1133 | + 'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly', |
|
| 1134 | + 'event_espresso' |
|
| 1135 | + ), |
|
| 1136 | + '4.6.18' |
|
| 1137 | + ); |
|
| 1138 | + } |
|
| 1139 | + do_action('AHEE_log', __FILE__, __FUNCTION__, ''); |
|
| 1140 | + |
|
| 1141 | + // check if only a single line_item_id was passed |
|
| 1142 | + if (! empty($line_item_codes) && ! is_array($line_item_codes)) { |
|
| 1143 | + // place single line_item_id in an array to appear as multiple line_item_ids |
|
| 1144 | + $line_item_codes = array($line_item_codes); |
|
| 1145 | + } |
|
| 1146 | + $removals = 0; |
|
| 1147 | + // cycle thru line_item_ids |
|
| 1148 | + foreach ($line_item_codes as $line_item_id) { |
|
| 1149 | + $removals += $total_line_item->delete_child_line_item($line_item_id); |
|
| 1150 | + } |
|
| 1151 | + |
|
| 1152 | + if ($removals > 0) { |
|
| 1153 | + $total_line_item->recalculate_taxes_and_tax_total(); |
|
| 1154 | + return $removals; |
|
| 1155 | + } else { |
|
| 1156 | + return false; |
|
| 1157 | + } |
|
| 1158 | + } |
|
| 1159 | + |
|
| 1160 | + |
|
| 1161 | + /** |
|
| 1162 | + * Overwrites the previous tax by clearing out the old taxes, and creates a new |
|
| 1163 | + * tax and updates the total line item accordingly |
|
| 1164 | + * |
|
| 1165 | + * @param EE_Line_Item $total_line_item |
|
| 1166 | + * @param float $amount |
|
| 1167 | + * @param string $name |
|
| 1168 | + * @param string $description |
|
| 1169 | + * @param string $code |
|
| 1170 | + * @param boolean $add_to_existing_line_item |
|
| 1171 | + * if true, and a duplicate line item with the same code is found, |
|
| 1172 | + * $amount will be added onto it; otherwise will simply set the taxes to match $amount |
|
| 1173 | + * @return EE_Line_Item the new tax line item created |
|
| 1174 | + * @throws EE_Error |
|
| 1175 | + * @throws InvalidArgumentException |
|
| 1176 | + * @throws InvalidDataTypeException |
|
| 1177 | + * @throws InvalidInterfaceException |
|
| 1178 | + * @throws ReflectionException |
|
| 1179 | + */ |
|
| 1180 | + public static function set_total_tax_to( |
|
| 1181 | + EE_Line_Item $total_line_item, |
|
| 1182 | + $amount, |
|
| 1183 | + $name = null, |
|
| 1184 | + $description = null, |
|
| 1185 | + $code = null, |
|
| 1186 | + $add_to_existing_line_item = false |
|
| 1187 | + ) { |
|
| 1188 | + $tax_subtotal = self::get_taxes_subtotal($total_line_item); |
|
| 1189 | + $taxable_total = $total_line_item->taxable_total(); |
|
| 1190 | + |
|
| 1191 | + if ($add_to_existing_line_item) { |
|
| 1192 | + $new_tax = $tax_subtotal->get_child_line_item($code); |
|
| 1193 | + EEM_Line_Item::instance()->delete( |
|
| 1194 | + array(array('LIN_code' => array('!=', $code), 'LIN_parent' => $tax_subtotal->ID())) |
|
| 1195 | + ); |
|
| 1196 | + } else { |
|
| 1197 | + $new_tax = null; |
|
| 1198 | + $tax_subtotal->delete_children_line_items(); |
|
| 1199 | + } |
|
| 1200 | + if ($new_tax) { |
|
| 1201 | + $new_tax->set_total($new_tax->total() + $amount); |
|
| 1202 | + $new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0); |
|
| 1203 | + } else { |
|
| 1204 | + // no existing tax item. Create it |
|
| 1205 | + $new_tax = EE_Line_Item::new_instance(array( |
|
| 1206 | + 'TXN_ID' => $total_line_item->TXN_ID(), |
|
| 1207 | + 'LIN_name' => $name ?: esc_html__('Tax', 'event_espresso'), |
|
| 1208 | + 'LIN_desc' => $description ?: '', |
|
| 1209 | + 'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0, |
|
| 1210 | + 'LIN_total' => $amount, |
|
| 1211 | + 'LIN_parent' => $tax_subtotal->ID(), |
|
| 1212 | + 'LIN_type' => EEM_Line_Item::type_tax, |
|
| 1213 | + 'LIN_code' => $code, |
|
| 1214 | + )); |
|
| 1215 | + } |
|
| 1216 | + |
|
| 1217 | + $new_tax = apply_filters( |
|
| 1218 | + 'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal', |
|
| 1219 | + $new_tax, |
|
| 1220 | + $total_line_item |
|
| 1221 | + ); |
|
| 1222 | + $new_tax->save(); |
|
| 1223 | + $tax_subtotal->set_total($new_tax->total()); |
|
| 1224 | + $tax_subtotal->save(); |
|
| 1225 | + $total_line_item->recalculate_total_including_taxes(); |
|
| 1226 | + return $new_tax; |
|
| 1227 | + } |
|
| 1228 | + |
|
| 1229 | + |
|
| 1230 | + /** |
|
| 1231 | + * Makes all the line items which are children of $line_item taxable (or not). |
|
| 1232 | + * Does NOT save the line items |
|
| 1233 | + * |
|
| 1234 | + * @param EE_Line_Item $line_item |
|
| 1235 | + * @param boolean $taxable |
|
| 1236 | + * @param string $code_substring_for_whitelist if this string is part of the line item's code |
|
| 1237 | + * it will be whitelisted (ie, except from becoming taxable) |
|
| 1238 | + * @throws EE_Error |
|
| 1239 | + */ |
|
| 1240 | + public static function set_line_items_taxable( |
|
| 1241 | + EE_Line_Item $line_item, |
|
| 1242 | + $taxable = true, |
|
| 1243 | + $code_substring_for_whitelist = null |
|
| 1244 | + ) { |
|
| 1245 | + $whitelisted = false; |
|
| 1246 | + if ($code_substring_for_whitelist !== null) { |
|
| 1247 | + $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false; |
|
| 1248 | + } |
|
| 1249 | + if (! $whitelisted && $line_item->is_line_item()) { |
|
| 1250 | + $line_item->set_is_taxable($taxable); |
|
| 1251 | + } |
|
| 1252 | + foreach ($line_item->children() as $child_line_item) { |
|
| 1253 | + EEH_Line_Item::set_line_items_taxable( |
|
| 1254 | + $child_line_item, |
|
| 1255 | + $taxable, |
|
| 1256 | + $code_substring_for_whitelist |
|
| 1257 | + ); |
|
| 1258 | + } |
|
| 1259 | + } |
|
| 1260 | + |
|
| 1261 | + |
|
| 1262 | + /** |
|
| 1263 | + * Gets all descendants that are event subtotals |
|
| 1264 | + * |
|
| 1265 | + * @uses EEH_Line_Item::get_subtotals_of_object_type() |
|
| 1266 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1267 | + * @return EE_Line_Item[] |
|
| 1268 | + * @throws EE_Error |
|
| 1269 | + */ |
|
| 1270 | + public static function get_event_subtotals(EE_Line_Item $parent_line_item) |
|
| 1271 | + { |
|
| 1272 | + return self::get_subtotals_of_object_type($parent_line_item, EEM_Line_Item::OBJ_TYPE_EVENT); |
|
| 1273 | + } |
|
| 1274 | + |
|
| 1275 | + |
|
| 1276 | + /** |
|
| 1277 | + * Gets all descendants subtotals that match the supplied object type |
|
| 1278 | + * |
|
| 1279 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
| 1280 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1281 | + * @param string $obj_type |
|
| 1282 | + * @return EE_Line_Item[] |
|
| 1283 | + * @throws EE_Error |
|
| 1284 | + */ |
|
| 1285 | + public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
| 1286 | + { |
|
| 1287 | + return self::_get_descendants_by_type_and_object_type( |
|
| 1288 | + $parent_line_item, |
|
| 1289 | + EEM_Line_Item::type_sub_total, |
|
| 1290 | + $obj_type |
|
| 1291 | + ); |
|
| 1292 | + } |
|
| 1293 | + |
|
| 1294 | + |
|
| 1295 | + /** |
|
| 1296 | + * Gets all descendants that are tickets |
|
| 1297 | + * |
|
| 1298 | + * @uses EEH_Line_Item::get_line_items_of_object_type() |
|
| 1299 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1300 | + * @return EE_Line_Item[] |
|
| 1301 | + * @throws EE_Error |
|
| 1302 | + */ |
|
| 1303 | + public static function get_ticket_line_items(EE_Line_Item $parent_line_item) |
|
| 1304 | + { |
|
| 1305 | + return self::get_line_items_of_object_type( |
|
| 1306 | + $parent_line_item, |
|
| 1307 | + EEM_Line_Item::OBJ_TYPE_TICKET |
|
| 1308 | + ); |
|
| 1309 | + } |
|
| 1310 | + |
|
| 1311 | + |
|
| 1312 | + /** |
|
| 1313 | + * Gets all descendants subtotals that match the supplied object type |
|
| 1314 | + * |
|
| 1315 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
| 1316 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1317 | + * @param string $obj_type |
|
| 1318 | + * @return EE_Line_Item[] |
|
| 1319 | + * @throws EE_Error |
|
| 1320 | + */ |
|
| 1321 | + public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
| 1322 | + { |
|
| 1323 | + return self::_get_descendants_by_type_and_object_type( |
|
| 1324 | + $parent_line_item, |
|
| 1325 | + EEM_Line_Item::type_line_item, |
|
| 1326 | + $obj_type |
|
| 1327 | + ); |
|
| 1328 | + } |
|
| 1329 | + |
|
| 1330 | + |
|
| 1331 | + /** |
|
| 1332 | + * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax' |
|
| 1333 | + * |
|
| 1334 | + * @uses EEH_Line_Item::get_descendants_of_type() |
|
| 1335 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1336 | + * @return EE_Line_Item[] |
|
| 1337 | + * @throws EE_Error |
|
| 1338 | + */ |
|
| 1339 | + public static function get_tax_descendants(EE_Line_Item $parent_line_item) |
|
| 1340 | + { |
|
| 1341 | + return EEH_Line_Item::get_descendants_of_type( |
|
| 1342 | + $parent_line_item, |
|
| 1343 | + EEM_Line_Item::type_tax |
|
| 1344 | + ); |
|
| 1345 | + } |
|
| 1346 | + |
|
| 1347 | + |
|
| 1348 | + /** |
|
| 1349 | + * Gets all the real items purchased which are children of this item |
|
| 1350 | + * |
|
| 1351 | + * @uses EEH_Line_Item::get_descendants_of_type() |
|
| 1352 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1353 | + * @return EE_Line_Item[] |
|
| 1354 | + * @throws EE_Error |
|
| 1355 | + */ |
|
| 1356 | + public static function get_line_item_descendants(EE_Line_Item $parent_line_item) |
|
| 1357 | + { |
|
| 1358 | + return EEH_Line_Item::get_descendants_of_type( |
|
| 1359 | + $parent_line_item, |
|
| 1360 | + EEM_Line_Item::type_line_item |
|
| 1361 | + ); |
|
| 1362 | + } |
|
| 1363 | + |
|
| 1364 | + |
|
| 1365 | + /** |
|
| 1366 | + * Gets all descendants of supplied line item that match the supplied line item type |
|
| 1367 | + * |
|
| 1368 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
| 1369 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1370 | + * @param string $line_item_type one of the EEM_Line_Item constants |
|
| 1371 | + * @return EE_Line_Item[] |
|
| 1372 | + * @throws EE_Error |
|
| 1373 | + */ |
|
| 1374 | + public static function get_descendants_of_type(EE_Line_Item $parent_line_item, $line_item_type) |
|
| 1375 | + { |
|
| 1376 | + return self::_get_descendants_by_type_and_object_type( |
|
| 1377 | + $parent_line_item, |
|
| 1378 | + $line_item_type, |
|
| 1379 | + null |
|
| 1380 | + ); |
|
| 1381 | + } |
|
| 1382 | + |
|
| 1383 | + |
|
| 1384 | + /** |
|
| 1385 | + * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type |
|
| 1386 | + * as well |
|
| 1387 | + * |
|
| 1388 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1389 | + * @param string $line_item_type one of the EEM_Line_Item constants |
|
| 1390 | + * @param string | NULL $obj_type object model class name (minus prefix) or NULL to ignore object type when |
|
| 1391 | + * searching |
|
| 1392 | + * @return EE_Line_Item[] |
|
| 1393 | + * @throws EE_Error |
|
| 1394 | + */ |
|
| 1395 | + protected static function _get_descendants_by_type_and_object_type( |
|
| 1396 | + EE_Line_Item $parent_line_item, |
|
| 1397 | + $line_item_type, |
|
| 1398 | + $obj_type = null |
|
| 1399 | + ) { |
|
| 1400 | + $objects = array(); |
|
| 1401 | + foreach ($parent_line_item->children() as $child_line_item) { |
|
| 1402 | + if ($child_line_item instanceof EE_Line_Item) { |
|
| 1403 | + if ( |
|
| 1404 | + $child_line_item->type() === $line_item_type |
|
| 1405 | + && ( |
|
| 1406 | + $child_line_item->OBJ_type() === $obj_type || $obj_type === null |
|
| 1407 | + ) |
|
| 1408 | + ) { |
|
| 1409 | + $objects[] = $child_line_item; |
|
| 1410 | + } else { |
|
| 1411 | + // go-through-all-its children looking for more matches |
|
| 1412 | + $objects = array_merge( |
|
| 1413 | + $objects, |
|
| 1414 | + self::_get_descendants_by_type_and_object_type( |
|
| 1415 | + $child_line_item, |
|
| 1416 | + $line_item_type, |
|
| 1417 | + $obj_type |
|
| 1418 | + ) |
|
| 1419 | + ); |
|
| 1420 | + } |
|
| 1421 | + } |
|
| 1422 | + } |
|
| 1423 | + return $objects; |
|
| 1424 | + } |
|
| 1425 | + |
|
| 1426 | + |
|
| 1427 | + /** |
|
| 1428 | + * Gets all descendants subtotals that match the supplied object type |
|
| 1429 | + * |
|
| 1430 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
| 1431 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1432 | + * @param string $OBJ_type object type (like Event) |
|
| 1433 | + * @param array $OBJ_IDs array of OBJ_IDs |
|
| 1434 | + * @return EE_Line_Item[] |
|
| 1435 | + * @throws EE_Error |
|
| 1436 | + */ |
|
| 1437 | + public static function get_line_items_by_object_type_and_IDs( |
|
| 1438 | + EE_Line_Item $parent_line_item, |
|
| 1439 | + $OBJ_type = '', |
|
| 1440 | + $OBJ_IDs = array() |
|
| 1441 | + ) { |
|
| 1442 | + return self::_get_descendants_by_object_type_and_object_ID( |
|
| 1443 | + $parent_line_item, |
|
| 1444 | + $OBJ_type, |
|
| 1445 | + $OBJ_IDs |
|
| 1446 | + ); |
|
| 1447 | + } |
|
| 1448 | + |
|
| 1449 | + |
|
| 1450 | + /** |
|
| 1451 | + * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type |
|
| 1452 | + * as well |
|
| 1453 | + * |
|
| 1454 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1455 | + * @param string $OBJ_type object type (like Event) |
|
| 1456 | + * @param array $OBJ_IDs array of OBJ_IDs |
|
| 1457 | + * @return EE_Line_Item[] |
|
| 1458 | + * @throws EE_Error |
|
| 1459 | + */ |
|
| 1460 | + protected static function _get_descendants_by_object_type_and_object_ID( |
|
| 1461 | + EE_Line_Item $parent_line_item, |
|
| 1462 | + $OBJ_type, |
|
| 1463 | + $OBJ_IDs |
|
| 1464 | + ) { |
|
| 1465 | + $objects = array(); |
|
| 1466 | + foreach ($parent_line_item->children() as $child_line_item) { |
|
| 1467 | + if ($child_line_item instanceof EE_Line_Item) { |
|
| 1468 | + if ( |
|
| 1469 | + $child_line_item->OBJ_type() === $OBJ_type |
|
| 1470 | + && is_array($OBJ_IDs) |
|
| 1471 | + && in_array($child_line_item->OBJ_ID(), $OBJ_IDs) |
|
| 1472 | + ) { |
|
| 1473 | + $objects[] = $child_line_item; |
|
| 1474 | + } else { |
|
| 1475 | + // go-through-all-its children looking for more matches |
|
| 1476 | + $objects = array_merge( |
|
| 1477 | + $objects, |
|
| 1478 | + self::_get_descendants_by_object_type_and_object_ID( |
|
| 1479 | + $child_line_item, |
|
| 1480 | + $OBJ_type, |
|
| 1481 | + $OBJ_IDs |
|
| 1482 | + ) |
|
| 1483 | + ); |
|
| 1484 | + } |
|
| 1485 | + } |
|
| 1486 | + } |
|
| 1487 | + return $objects; |
|
| 1488 | + } |
|
| 1489 | + |
|
| 1490 | + |
|
| 1491 | + /** |
|
| 1492 | + * Uses a breadth-first-search in order to find the nearest descendant of |
|
| 1493 | + * the specified type and returns it, else NULL |
|
| 1494 | + * |
|
| 1495 | + * @uses EEH_Line_Item::_get_nearest_descendant() |
|
| 1496 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1497 | + * @param string $type like one of the EEM_Line_Item::type_* |
|
| 1498 | + * @return EE_Line_Item |
|
| 1499 | + * @throws EE_Error |
|
| 1500 | + * @throws InvalidArgumentException |
|
| 1501 | + * @throws InvalidDataTypeException |
|
| 1502 | + * @throws InvalidInterfaceException |
|
| 1503 | + * @throws ReflectionException |
|
| 1504 | + */ |
|
| 1505 | + public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, $type) |
|
| 1506 | + { |
|
| 1507 | + return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type); |
|
| 1508 | + } |
|
| 1509 | + |
|
| 1510 | + |
|
| 1511 | + /** |
|
| 1512 | + * Uses a breadth-first-search in order to find the nearest descendant |
|
| 1513 | + * having the specified LIN_code and returns it, else NULL |
|
| 1514 | + * |
|
| 1515 | + * @uses EEH_Line_Item::_get_nearest_descendant() |
|
| 1516 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1517 | + * @param string $code any value used for LIN_code |
|
| 1518 | + * @return EE_Line_Item |
|
| 1519 | + * @throws EE_Error |
|
| 1520 | + * @throws InvalidArgumentException |
|
| 1521 | + * @throws InvalidDataTypeException |
|
| 1522 | + * @throws InvalidInterfaceException |
|
| 1523 | + * @throws ReflectionException |
|
| 1524 | + */ |
|
| 1525 | + public static function get_nearest_descendant_having_code(EE_Line_Item $parent_line_item, $code) |
|
| 1526 | + { |
|
| 1527 | + return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code); |
|
| 1528 | + } |
|
| 1529 | + |
|
| 1530 | + |
|
| 1531 | + /** |
|
| 1532 | + * Uses a breadth-first-search in order to find the nearest descendant |
|
| 1533 | + * having the specified LIN_code and returns it, else NULL |
|
| 1534 | + * |
|
| 1535 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
| 1536 | + * @param string $search_field name of EE_Line_Item property |
|
| 1537 | + * @param string $value any value stored in $search_field |
|
| 1538 | + * @return EE_Line_Item |
|
| 1539 | + * @throws EE_Error |
|
| 1540 | + * @throws InvalidArgumentException |
|
| 1541 | + * @throws InvalidDataTypeException |
|
| 1542 | + * @throws InvalidInterfaceException |
|
| 1543 | + * @throws ReflectionException |
|
| 1544 | + */ |
|
| 1545 | + protected static function _get_nearest_descendant(EE_Line_Item $parent_line_item, $search_field, $value) |
|
| 1546 | + { |
|
| 1547 | + foreach ($parent_line_item->children() as $child) { |
|
| 1548 | + if ($child->get($search_field) == $value) { |
|
| 1549 | + return $child; |
|
| 1550 | + } |
|
| 1551 | + } |
|
| 1552 | + foreach ($parent_line_item->children() as $child) { |
|
| 1553 | + $descendant_found = self::_get_nearest_descendant( |
|
| 1554 | + $child, |
|
| 1555 | + $search_field, |
|
| 1556 | + $value |
|
| 1557 | + ); |
|
| 1558 | + if ($descendant_found) { |
|
| 1559 | + return $descendant_found; |
|
| 1560 | + } |
|
| 1561 | + } |
|
| 1562 | + return null; |
|
| 1563 | + } |
|
| 1564 | + |
|
| 1565 | + |
|
| 1566 | + /** |
|
| 1567 | + * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction, |
|
| 1568 | + * else recursively walks up the line item tree until a parent of type total is found, |
|
| 1569 | + * |
|
| 1570 | + * @param EE_Line_Item $line_item |
|
| 1571 | + * @return EE_Line_Item |
|
| 1572 | + * @throws EE_Error |
|
| 1573 | + * @throws ReflectionException |
|
| 1574 | + */ |
|
| 1575 | + public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item): EE_Line_Item |
|
| 1576 | + { |
|
| 1577 | + if ($line_item->is_total()) { |
|
| 1578 | + return $line_item; |
|
| 1579 | + } |
|
| 1580 | + if ($line_item->TXN_ID()) { |
|
| 1581 | + $total_line_item = $line_item->transaction()->total_line_item(false); |
|
| 1582 | + if ($total_line_item instanceof EE_Line_Item) { |
|
| 1583 | + return $total_line_item; |
|
| 1584 | + } |
|
| 1585 | + } else { |
|
| 1586 | + $line_item_parent = $line_item->parent(); |
|
| 1587 | + if ($line_item_parent instanceof EE_Line_Item) { |
|
| 1588 | + if ($line_item_parent->is_total()) { |
|
| 1589 | + return $line_item_parent; |
|
| 1590 | + } |
|
| 1591 | + return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent); |
|
| 1592 | + } |
|
| 1593 | + } |
|
| 1594 | + throw new EE_Error( |
|
| 1595 | + sprintf( |
|
| 1596 | + esc_html__( |
|
| 1597 | + 'A valid grand total for line item %1$d was not found.', |
|
| 1598 | + 'event_espresso' |
|
| 1599 | + ), |
|
| 1600 | + $line_item->ID() |
|
| 1601 | + ) |
|
| 1602 | + ); |
|
| 1603 | + } |
|
| 1604 | + |
|
| 1605 | + |
|
| 1606 | + /** |
|
| 1607 | + * Prints out a representation of the line item tree |
|
| 1608 | + * |
|
| 1609 | + * @param EE_Line_Item $line_item |
|
| 1610 | + * @param int $indentation |
|
| 1611 | + * @return void |
|
| 1612 | + * @throws EE_Error |
|
| 1613 | + */ |
|
| 1614 | + public static function visualize(EE_Line_Item $line_item, $indentation = 0) |
|
| 1615 | + { |
|
| 1616 | + $new_line = defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
|
| 1617 | + echo $new_line; |
|
| 1618 | + if (! $indentation) { |
|
| 1619 | + echo $new_line; |
|
| 1620 | + } |
|
| 1621 | + echo str_repeat('. ', $indentation); |
|
| 1622 | + $breakdown = ''; |
|
| 1623 | + if ($line_item->is_line_item() || $line_item->is_sub_line_item() || $line_item->isSubTax()) { |
|
| 1624 | + if ($line_item->is_percent()) { |
|
| 1625 | + $breakdown = "{$line_item->percent()}%"; |
|
| 1626 | + } else { |
|
| 1627 | + $breakdown = "\${$line_item->unit_price()} x {$line_item->quantity()}"; |
|
| 1628 | + } |
|
| 1629 | + } |
|
| 1630 | + echo $line_item->name(); |
|
| 1631 | + echo " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : "; |
|
| 1632 | + echo "\${$line_item->total()}"; |
|
| 1633 | + if ($breakdown) { |
|
| 1634 | + echo " ( {$breakdown} )"; |
|
| 1635 | + } |
|
| 1636 | + if ($line_item->is_taxable()) { |
|
| 1637 | + echo ' * taxable'; |
|
| 1638 | + } |
|
| 1639 | + if ($line_item->children()) { |
|
| 1640 | + foreach ($line_item->children() as $child) { |
|
| 1641 | + self::visualize($child, $indentation + 1); |
|
| 1642 | + } |
|
| 1643 | + } |
|
| 1644 | + if (! $indentation) { |
|
| 1645 | + echo $new_line . $new_line; |
|
| 1646 | + } |
|
| 1647 | + } |
|
| 1648 | + |
|
| 1649 | + |
|
| 1650 | + /** |
|
| 1651 | + * Calculates the registration's final price, taking into account that they |
|
| 1652 | + * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes, |
|
| 1653 | + * and receive a portion of any transaction-wide discounts. |
|
| 1654 | + * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount |
|
| 1655 | + * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get |
|
| 1656 | + * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50 |
|
| 1657 | + * and brent's final price should be $5.50. |
|
| 1658 | + * In order to do this, we basically need to traverse the line item tree calculating |
|
| 1659 | + * the running totals (just as if we were recalculating the total), but when we identify |
|
| 1660 | + * regular line items, we need to keep track of their share of the grand total. |
|
| 1661 | + * Also, we need to keep track of the TAXABLE total for each ticket purchase, so |
|
| 1662 | + * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total" |
|
| 1663 | + * when there are non-taxable items; otherwise they would be the same) |
|
| 1664 | + * |
|
| 1665 | + * @param EE_Line_Item $line_item |
|
| 1666 | + * @param array $billable_ticket_quantities array of EE_Ticket IDs and their corresponding quantity that |
|
| 1667 | + * can be included in price calculations at this moment |
|
| 1668 | + * @return array keys are line items for tickets IDs and values are their share of the running total, |
|
| 1669 | + * plus the key 'total', and 'taxable' which also has keys of all |
|
| 1670 | + * the ticket IDs. |
|
| 1671 | + * Eg array( |
|
| 1672 | + * 12 => 4.3 |
|
| 1673 | + * 23 => 8.0 |
|
| 1674 | + * 'total' => 16.6, |
|
| 1675 | + * 'taxable' => array( |
|
| 1676 | + * 12 => 10, |
|
| 1677 | + * 23 => 4 |
|
| 1678 | + * ). |
|
| 1679 | + * So to find which registrations have which final price, we need |
|
| 1680 | + * to find which line item is theirs, which can be done with |
|
| 1681 | + * `EEM_Line_Item::instance()->get_line_item_for_registration( |
|
| 1682 | + * $registration );` |
|
| 1683 | + * @throws EE_Error |
|
| 1684 | + * @throws InvalidArgumentException |
|
| 1685 | + * @throws InvalidDataTypeException |
|
| 1686 | + * @throws InvalidInterfaceException |
|
| 1687 | + * @throws ReflectionException |
|
| 1688 | + */ |
|
| 1689 | + public static function calculate_reg_final_prices_per_line_item( |
|
| 1690 | + EE_Line_Item $line_item, |
|
| 1691 | + $billable_ticket_quantities = array() |
|
| 1692 | + ) { |
|
| 1693 | + $running_totals = [ |
|
| 1694 | + 'total' => 0, |
|
| 1695 | + 'taxable' => ['total' => 0] |
|
| 1696 | + ]; |
|
| 1697 | + foreach ($line_item->children() as $child_line_item) { |
|
| 1698 | + switch ($child_line_item->type()) { |
|
| 1699 | + case EEM_Line_Item::type_sub_total: |
|
| 1700 | + $running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
| 1701 | + $child_line_item, |
|
| 1702 | + $billable_ticket_quantities |
|
| 1703 | + ); |
|
| 1704 | + // combine arrays but preserve numeric keys |
|
| 1705 | + $running_totals = array_replace_recursive($running_totals_from_subtotal, $running_totals); |
|
| 1706 | + $running_totals['total'] += $running_totals_from_subtotal['total']; |
|
| 1707 | + $running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total']; |
|
| 1708 | + break; |
|
| 1709 | + |
|
| 1710 | + case EEM_Line_Item::type_tax_sub_total: |
|
| 1711 | + // find how much the taxes percentage is |
|
| 1712 | + if ($child_line_item->percent() !== 0) { |
|
| 1713 | + $tax_percent_decimal = $child_line_item->percent() / 100; |
|
| 1714 | + } else { |
|
| 1715 | + $tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100; |
|
| 1716 | + } |
|
| 1717 | + // and apply to all the taxable totals, and add to the pretax totals |
|
| 1718 | + foreach ($running_totals as $line_item_id => $this_running_total) { |
|
| 1719 | + // "total" and "taxable" array key is an exception |
|
| 1720 | + if ($line_item_id === 'taxable') { |
|
| 1721 | + continue; |
|
| 1722 | + } |
|
| 1723 | + $taxable_total = $running_totals['taxable'][ $line_item_id ]; |
|
| 1724 | + $running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal); |
|
| 1725 | + } |
|
| 1726 | + break; |
|
| 1727 | + |
|
| 1728 | + case EEM_Line_Item::type_line_item: |
|
| 1729 | + // ticket line items or ???? |
|
| 1730 | + if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
| 1731 | + // kk it's a ticket |
|
| 1732 | + if (isset($running_totals[ $child_line_item->ID() ])) { |
|
| 1733 | + // huh? that shouldn't happen. |
|
| 1734 | + $running_totals['total'] += $child_line_item->total(); |
|
| 1735 | + } else { |
|
| 1736 | + // its not in our running totals yet. great. |
|
| 1737 | + if ($child_line_item->is_taxable()) { |
|
| 1738 | + $taxable_amount = $child_line_item->unit_price(); |
|
| 1739 | + } else { |
|
| 1740 | + $taxable_amount = 0; |
|
| 1741 | + } |
|
| 1742 | + // are we only calculating totals for some tickets? |
|
| 1743 | + if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) { |
|
| 1744 | + $quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ]; |
|
| 1745 | + $running_totals[ $child_line_item->ID() ] = $quantity |
|
| 1746 | + ? $child_line_item->unit_price() |
|
| 1747 | + : 0; |
|
| 1748 | + $running_totals['taxable'][ $child_line_item->ID() ] = $quantity |
|
| 1749 | + ? $taxable_amount |
|
| 1750 | + : 0; |
|
| 1751 | + } else { |
|
| 1752 | + $quantity = $child_line_item->quantity(); |
|
| 1753 | + $running_totals[ $child_line_item->ID() ] = $child_line_item->unit_price(); |
|
| 1754 | + $running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount; |
|
| 1755 | + } |
|
| 1756 | + $running_totals['taxable']['total'] += $taxable_amount * $quantity; |
|
| 1757 | + $running_totals['total'] += $child_line_item->unit_price() * $quantity; |
|
| 1758 | + } |
|
| 1759 | + } else { |
|
| 1760 | + // it's some other type of item added to the cart |
|
| 1761 | + // it should affect the running totals |
|
| 1762 | + // basically we want to convert it into a PERCENT modifier. Because |
|
| 1763 | + // more clearly affect all registration's final price equally |
|
| 1764 | + $line_items_percent_of_running_total = $running_totals['total'] > 0 |
|
| 1765 | + ? ($child_line_item->total() / $running_totals['total']) + 1 |
|
| 1766 | + : 1; |
|
| 1767 | + foreach ($running_totals as $line_item_id => $this_running_total) { |
|
| 1768 | + // the "taxable" array key is an exception |
|
| 1769 | + if ($line_item_id === 'taxable') { |
|
| 1770 | + continue; |
|
| 1771 | + } |
|
| 1772 | + // update the running totals |
|
| 1773 | + // yes this actually even works for the running grand total! |
|
| 1774 | + $running_totals[ $line_item_id ] = |
|
| 1775 | + $line_items_percent_of_running_total * $this_running_total; |
|
| 1776 | + |
|
| 1777 | + if ($child_line_item->is_taxable()) { |
|
| 1778 | + $running_totals['taxable'][ $line_item_id ] = |
|
| 1779 | + $line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ]; |
|
| 1780 | + } |
|
| 1781 | + } |
|
| 1782 | + } |
|
| 1783 | + break; |
|
| 1784 | + } |
|
| 1785 | + } |
|
| 1786 | + return $running_totals; |
|
| 1787 | + } |
|
| 1788 | + |
|
| 1789 | + |
|
| 1790 | + /** |
|
| 1791 | + * @param EE_Line_Item $total_line_item |
|
| 1792 | + * @param EE_Line_Item $ticket_line_item |
|
| 1793 | + * @return float | null |
|
| 1794 | + * @throws EE_Error |
|
| 1795 | + * @throws InvalidArgumentException |
|
| 1796 | + * @throws InvalidDataTypeException |
|
| 1797 | + * @throws InvalidInterfaceException |
|
| 1798 | + * @throws OutOfRangeException |
|
| 1799 | + * @throws ReflectionException |
|
| 1800 | + */ |
|
| 1801 | + public static function calculate_final_price_for_ticket_line_item( |
|
| 1802 | + EE_Line_Item $total_line_item, |
|
| 1803 | + EE_Line_Item $ticket_line_item |
|
| 1804 | + ) { |
|
| 1805 | + static $final_prices_per_ticket_line_item = array(); |
|
| 1806 | + if (empty($final_prices_per_ticket_line_item) || empty($final_prices_per_ticket_line_item[ $total_line_item->ID() ])) { |
|
| 1807 | + $final_prices_per_ticket_line_item[ $total_line_item->ID() ] = EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
| 1808 | + $total_line_item |
|
| 1809 | + ); |
|
| 1810 | + } |
|
| 1811 | + // ok now find this new registration's final price |
|
| 1812 | + if (isset($final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ])) { |
|
| 1813 | + return $final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ]; |
|
| 1814 | + } |
|
| 1815 | + $message = sprintf( |
|
| 1816 | + esc_html__( |
|
| 1817 | + 'The final price for the ticket line item (ID:%1$d) on the total line item (ID:%2$d) could not be calculated.', |
|
| 1818 | + 'event_espresso' |
|
| 1819 | + ), |
|
| 1820 | + $ticket_line_item->ID(), |
|
| 1821 | + $total_line_item->ID() |
|
| 1822 | + ); |
|
| 1823 | + if (WP_DEBUG) { |
|
| 1824 | + $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true); |
|
| 1825 | + throw new OutOfRangeException($message); |
|
| 1826 | + } |
|
| 1827 | + EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message); |
|
| 1828 | + return null; |
|
| 1829 | + } |
|
| 1830 | + |
|
| 1831 | + |
|
| 1832 | + /** |
|
| 1833 | + * Creates a duplicate of the line item tree, except only includes billable items |
|
| 1834 | + * and the portion of line items attributed to billable things |
|
| 1835 | + * |
|
| 1836 | + * @param EE_Line_Item $line_item |
|
| 1837 | + * @param EE_Registration[] $registrations |
|
| 1838 | + * @return EE_Line_Item |
|
| 1839 | + * @throws EE_Error |
|
| 1840 | + * @throws InvalidArgumentException |
|
| 1841 | + * @throws InvalidDataTypeException |
|
| 1842 | + * @throws InvalidInterfaceException |
|
| 1843 | + * @throws ReflectionException |
|
| 1844 | + */ |
|
| 1845 | + public static function billable_line_item_tree(EE_Line_Item $line_item, $registrations) |
|
| 1846 | + { |
|
| 1847 | + $copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations); |
|
| 1848 | + foreach ($line_item->children() as $child_li) { |
|
| 1849 | + $copy_li->add_child_line_item( |
|
| 1850 | + EEH_Line_Item::billable_line_item_tree($child_li, $registrations) |
|
| 1851 | + ); |
|
| 1852 | + } |
|
| 1853 | + // if this is the grand total line item, make sure the totals all add up |
|
| 1854 | + // (we could have duplicated this logic AS we copied the line items, but |
|
| 1855 | + // it seems DRYer this way) |
|
| 1856 | + if ($copy_li->type() === EEM_Line_Item::type_total) { |
|
| 1857 | + $copy_li->recalculate_total_including_taxes(); |
|
| 1858 | + } |
|
| 1859 | + return $copy_li; |
|
| 1860 | + } |
|
| 1861 | + |
|
| 1862 | + |
|
| 1863 | + /** |
|
| 1864 | + * Creates a new, unsaved line item from $line_item that factors in the |
|
| 1865 | + * number of billable registrations on $registrations. |
|
| 1866 | + * |
|
| 1867 | + * @param EE_Line_Item $line_item |
|
| 1868 | + * @param EE_Registration[] $registrations |
|
| 1869 | + * @return EE_Line_Item |
|
| 1870 | + * @throws EE_Error |
|
| 1871 | + * @throws InvalidArgumentException |
|
| 1872 | + * @throws InvalidDataTypeException |
|
| 1873 | + * @throws InvalidInterfaceException |
|
| 1874 | + * @throws ReflectionException |
|
| 1875 | + */ |
|
| 1876 | + public static function billable_line_item(EE_Line_Item $line_item, $registrations) |
|
| 1877 | + { |
|
| 1878 | + $new_li_fields = $line_item->model_field_array(); |
|
| 1879 | + if ( |
|
| 1880 | + $line_item->type() === EEM_Line_Item::type_line_item && |
|
| 1881 | + $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
| 1882 | + ) { |
|
| 1883 | + $count = 0; |
|
| 1884 | + foreach ($registrations as $registration) { |
|
| 1885 | + if ( |
|
| 1886 | + $line_item->OBJ_ID() === $registration->ticket_ID() && |
|
| 1887 | + in_array( |
|
| 1888 | + $registration->status_ID(), |
|
| 1889 | + EEM_Registration::reg_statuses_that_allow_payment(), |
|
| 1890 | + true |
|
| 1891 | + ) |
|
| 1892 | + ) { |
|
| 1893 | + $count++; |
|
| 1894 | + } |
|
| 1895 | + } |
|
| 1896 | + $new_li_fields['LIN_quantity'] = $count; |
|
| 1897 | + } |
|
| 1898 | + // don't set the total. We'll leave that up to the code that calculates it |
|
| 1899 | + unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']); |
|
| 1900 | + return EE_Line_Item::new_instance($new_li_fields); |
|
| 1901 | + } |
|
| 1902 | + |
|
| 1903 | + |
|
| 1904 | + /** |
|
| 1905 | + * Returns a modified line item tree where all the subtotals which have a total of 0 |
|
| 1906 | + * are removed, and line items with a quantity of 0 |
|
| 1907 | + * |
|
| 1908 | + * @param EE_Line_Item $line_item |null |
|
| 1909 | + * @return EE_Line_Item|null |
|
| 1910 | + * @throws EE_Error |
|
| 1911 | + * @throws InvalidArgumentException |
|
| 1912 | + * @throws InvalidDataTypeException |
|
| 1913 | + * @throws InvalidInterfaceException |
|
| 1914 | + * @throws ReflectionException |
|
| 1915 | + */ |
|
| 1916 | + public static function non_empty_line_items(EE_Line_Item $line_item) |
|
| 1917 | + { |
|
| 1918 | + $copied_li = EEH_Line_Item::non_empty_line_item($line_item); |
|
| 1919 | + if ($copied_li === null) { |
|
| 1920 | + return null; |
|
| 1921 | + } |
|
| 1922 | + // if this is an event subtotal, we want to only include it if it |
|
| 1923 | + // has a non-zero total and at least one ticket line item child |
|
| 1924 | + $ticket_children = 0; |
|
| 1925 | + foreach ($line_item->children() as $child_li) { |
|
| 1926 | + $child_li_copy = EEH_Line_Item::non_empty_line_items($child_li); |
|
| 1927 | + if ($child_li_copy !== null) { |
|
| 1928 | + $copied_li->add_child_line_item($child_li_copy); |
|
| 1929 | + if ( |
|
| 1930 | + $child_li_copy->type() === EEM_Line_Item::type_line_item && |
|
| 1931 | + $child_li_copy->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
| 1932 | + ) { |
|
| 1933 | + $ticket_children++; |
|
| 1934 | + } |
|
| 1935 | + } |
|
| 1936 | + } |
|
| 1937 | + // if this is an event subtotal with NO ticket children |
|
| 1938 | + // we basically want to ignore it |
|
| 1939 | + if ( |
|
| 1940 | + $ticket_children === 0 |
|
| 1941 | + && $line_item->type() === EEM_Line_Item::type_sub_total |
|
| 1942 | + && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
| 1943 | + && $line_item->total() === 0 |
|
| 1944 | + ) { |
|
| 1945 | + return null; |
|
| 1946 | + } |
|
| 1947 | + return $copied_li; |
|
| 1948 | + } |
|
| 1949 | + |
|
| 1950 | + |
|
| 1951 | + /** |
|
| 1952 | + * Creates a new, unsaved line item, but if it's a ticket line item |
|
| 1953 | + * with a total of 0, or a subtotal of 0, returns null instead |
|
| 1954 | + * |
|
| 1955 | + * @param EE_Line_Item $line_item |
|
| 1956 | + * @return EE_Line_Item |
|
| 1957 | + * @throws EE_Error |
|
| 1958 | + * @throws InvalidArgumentException |
|
| 1959 | + * @throws InvalidDataTypeException |
|
| 1960 | + * @throws InvalidInterfaceException |
|
| 1961 | + * @throws ReflectionException |
|
| 1962 | + */ |
|
| 1963 | + public static function non_empty_line_item(EE_Line_Item $line_item) |
|
| 1964 | + { |
|
| 1965 | + if ( |
|
| 1966 | + $line_item->type() === EEM_Line_Item::type_line_item |
|
| 1967 | + && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
| 1968 | + && $line_item->quantity() === 0 |
|
| 1969 | + ) { |
|
| 1970 | + return null; |
|
| 1971 | + } |
|
| 1972 | + $new_li_fields = $line_item->model_field_array(); |
|
| 1973 | + // don't set the total. We'll leave that up to the code that calculates it |
|
| 1974 | + unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']); |
|
| 1975 | + return EE_Line_Item::new_instance($new_li_fields); |
|
| 1976 | + } |
|
| 1977 | + |
|
| 1978 | + |
|
| 1979 | + /** |
|
| 1980 | + * Cycles through all of the ticket line items for the supplied total line item |
|
| 1981 | + * and ensures that the line item's "is_taxable" field matches that of its corresponding ticket |
|
| 1982 | + * |
|
| 1983 | + * @param EE_Line_Item $total_line_item |
|
| 1984 | + * @since 4.9.79.p |
|
| 1985 | + * @throws EE_Error |
|
| 1986 | + * @throws InvalidArgumentException |
|
| 1987 | + * @throws InvalidDataTypeException |
|
| 1988 | + * @throws InvalidInterfaceException |
|
| 1989 | + * @throws ReflectionException |
|
| 1990 | + */ |
|
| 1991 | + public static function resetIsTaxableForTickets(EE_Line_Item $total_line_item) |
|
| 1992 | + { |
|
| 1993 | + $ticket_line_items = self::get_ticket_line_items($total_line_item); |
|
| 1994 | + foreach ($ticket_line_items as $ticket_line_item) { |
|
| 1995 | + if ( |
|
| 1996 | + $ticket_line_item instanceof EE_Line_Item |
|
| 1997 | + && $ticket_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
| 1998 | + ) { |
|
| 1999 | + $ticket = $ticket_line_item->ticket(); |
|
| 2000 | + if ($ticket instanceof EE_Ticket && $ticket->taxable() !== $ticket_line_item->is_taxable()) { |
|
| 2001 | + $ticket_line_item->set_is_taxable($ticket->taxable()); |
|
| 2002 | + $ticket_line_item->save(); |
|
| 2003 | + } |
|
| 2004 | + } |
|
| 2005 | + } |
|
| 2006 | + } |
|
| 2007 | + |
|
| 2008 | + |
|
| 2009 | + /** |
|
| 2010 | + * @return EE_Line_Item[] |
|
| 2011 | + * @throws EE_Error |
|
| 2012 | + * @throws ReflectionException |
|
| 2013 | + * @since $VID:$ |
|
| 2014 | + */ |
|
| 2015 | + private static function getGlobalTaxes(): array |
|
| 2016 | + { |
|
| 2017 | + if (EEH_Line_Item::$global_taxes === null) { |
|
| 2018 | + |
|
| 2019 | + /** @type EEM_Price $EEM_Price */ |
|
| 2020 | + $EEM_Price = EE_Registry::instance()->load_model('Price'); |
|
| 2021 | + // get array of taxes via Price Model |
|
| 2022 | + EEH_Line_Item::$global_taxes = $EEM_Price->get_all_prices_that_are_taxes(); |
|
| 2023 | + ksort(EEH_Line_Item::$global_taxes); |
|
| 2024 | + } |
|
| 2025 | + return EEH_Line_Item::$global_taxes; |
|
| 2026 | + } |
|
| 2027 | + |
|
| 2028 | + |
|
| 2029 | + |
|
| 2030 | + /**************************************** @DEPRECATED METHODS *************************************** */ |
|
| 2031 | + /** |
|
| 2032 | + * @deprecated |
|
| 2033 | + * @param EE_Line_Item $total_line_item |
|
| 2034 | + * @return EE_Line_Item |
|
| 2035 | + * @throws EE_Error |
|
| 2036 | + * @throws InvalidArgumentException |
|
| 2037 | + * @throws InvalidDataTypeException |
|
| 2038 | + * @throws InvalidInterfaceException |
|
| 2039 | + * @throws ReflectionException |
|
| 2040 | + */ |
|
| 2041 | + public static function get_items_subtotal(EE_Line_Item $total_line_item) |
|
| 2042 | + { |
|
| 2043 | + EE_Error::doing_it_wrong( |
|
| 2044 | + 'EEH_Line_Item::get_items_subtotal()', |
|
| 2045 | + sprintf( |
|
| 2046 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 2047 | + 'EEH_Line_Item::get_pre_tax_subtotal()' |
|
| 2048 | + ), |
|
| 2049 | + '4.6.0' |
|
| 2050 | + ); |
|
| 2051 | + return self::get_pre_tax_subtotal($total_line_item); |
|
| 2052 | + } |
|
| 2053 | + |
|
| 2054 | + |
|
| 2055 | + /** |
|
| 2056 | + * @deprecated |
|
| 2057 | + * @param EE_Transaction $transaction |
|
| 2058 | + * @return EE_Line_Item |
|
| 2059 | + * @throws EE_Error |
|
| 2060 | + * @throws InvalidArgumentException |
|
| 2061 | + * @throws InvalidDataTypeException |
|
| 2062 | + * @throws InvalidInterfaceException |
|
| 2063 | + * @throws ReflectionException |
|
| 2064 | + */ |
|
| 2065 | + public static function create_default_total_line_item($transaction = null) |
|
| 2066 | + { |
|
| 2067 | + EE_Error::doing_it_wrong( |
|
| 2068 | + 'EEH_Line_Item::create_default_total_line_item()', |
|
| 2069 | + sprintf( |
|
| 2070 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 2071 | + 'EEH_Line_Item::create_total_line_item()' |
|
| 2072 | + ), |
|
| 2073 | + '4.6.0' |
|
| 2074 | + ); |
|
| 2075 | + return self::create_total_line_item($transaction); |
|
| 2076 | + } |
|
| 2077 | + |
|
| 2078 | + |
|
| 2079 | + /** |
|
| 2080 | + * @deprecated |
|
| 2081 | + * @param EE_Line_Item $total_line_item |
|
| 2082 | + * @param EE_Transaction $transaction |
|
| 2083 | + * @return EE_Line_Item |
|
| 2084 | + * @throws EE_Error |
|
| 2085 | + * @throws InvalidArgumentException |
|
| 2086 | + * @throws InvalidDataTypeException |
|
| 2087 | + * @throws InvalidInterfaceException |
|
| 2088 | + * @throws ReflectionException |
|
| 2089 | + */ |
|
| 2090 | + public static function create_default_tickets_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
| 2091 | + { |
|
| 2092 | + EE_Error::doing_it_wrong( |
|
| 2093 | + 'EEH_Line_Item::create_default_tickets_subtotal()', |
|
| 2094 | + sprintf( |
|
| 2095 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 2096 | + 'EEH_Line_Item::create_pre_tax_subtotal()' |
|
| 2097 | + ), |
|
| 2098 | + '4.6.0' |
|
| 2099 | + ); |
|
| 2100 | + return self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
| 2101 | + } |
|
| 2102 | + |
|
| 2103 | + |
|
| 2104 | + /** |
|
| 2105 | + * @deprecated |
|
| 2106 | + * @param EE_Line_Item $total_line_item |
|
| 2107 | + * @param EE_Transaction $transaction |
|
| 2108 | + * @return EE_Line_Item |
|
| 2109 | + * @throws EE_Error |
|
| 2110 | + * @throws InvalidArgumentException |
|
| 2111 | + * @throws InvalidDataTypeException |
|
| 2112 | + * @throws InvalidInterfaceException |
|
| 2113 | + * @throws ReflectionException |
|
| 2114 | + */ |
|
| 2115 | + public static function create_default_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
| 2116 | + { |
|
| 2117 | + EE_Error::doing_it_wrong( |
|
| 2118 | + 'EEH_Line_Item::create_default_taxes_subtotal()', |
|
| 2119 | + sprintf( |
|
| 2120 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 2121 | + 'EEH_Line_Item::create_taxes_subtotal()' |
|
| 2122 | + ), |
|
| 2123 | + '4.6.0' |
|
| 2124 | + ); |
|
| 2125 | + return self::create_taxes_subtotal($total_line_item, $transaction); |
|
| 2126 | + } |
|
| 2127 | + |
|
| 2128 | + |
|
| 2129 | + /** |
|
| 2130 | + * @deprecated |
|
| 2131 | + * @param EE_Line_Item $total_line_item |
|
| 2132 | + * @param EE_Transaction $transaction |
|
| 2133 | + * @return EE_Line_Item |
|
| 2134 | + * @throws EE_Error |
|
| 2135 | + * @throws InvalidArgumentException |
|
| 2136 | + * @throws InvalidDataTypeException |
|
| 2137 | + * @throws InvalidInterfaceException |
|
| 2138 | + * @throws ReflectionException |
|
| 2139 | + */ |
|
| 2140 | + public static function create_default_event_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
| 2141 | + { |
|
| 2142 | + EE_Error::doing_it_wrong( |
|
| 2143 | + 'EEH_Line_Item::create_default_event_subtotal()', |
|
| 2144 | + sprintf( |
|
| 2145 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
| 2146 | + 'EEH_Line_Item::create_event_subtotal()' |
|
| 2147 | + ), |
|
| 2148 | + '4.6.0' |
|
| 2149 | + ); |
|
| 2150 | + return self::create_event_subtotal($total_line_item, $transaction); |
|
| 2151 | + } |
|
| 2152 | 2152 | } |
@@ -75,12 +75,12 @@ discard block |
||
| 75 | 75 | 'LIN_code' => $code, |
| 76 | 76 | ] |
| 77 | 77 | ); |
| 78 | - $line_item = apply_filters( |
|
| 78 | + $line_item = apply_filters( |
|
| 79 | 79 | 'FHEE__EEH_Line_Item__add_unrelated_item__line_item', |
| 80 | 80 | $line_item, |
| 81 | 81 | $parent_line_item |
| 82 | 82 | ); |
| 83 | - $added = self::add_item($parent_line_item, $line_item, $recalculate_totals); |
|
| 83 | + $added = self::add_item($parent_line_item, $line_item, $recalculate_totals); |
|
| 84 | 84 | return $return_item ? $line_item : $added; |
| 85 | 85 | } |
| 86 | 86 | |
@@ -133,7 +133,7 @@ discard block |
||
| 133 | 133 | 'FHEE__EEH_Line_Item__add_percentage_based_item__line_item', |
| 134 | 134 | $line_item |
| 135 | 135 | ); |
| 136 | - $added = $parent_line_item->add_child_line_item($line_item, false); |
|
| 136 | + $added = $parent_line_item->add_child_line_item($line_item, false); |
|
| 137 | 137 | return $return_item ? $line_item : $added; |
| 138 | 138 | } |
| 139 | 139 | |
@@ -160,7 +160,7 @@ discard block |
||
| 160 | 160 | */ |
| 161 | 161 | public static function add_ticket_purchase(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
| 162 | 162 | { |
| 163 | - if (! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) { |
|
| 163 | + if ( ! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) { |
|
| 164 | 164 | throw new EE_Error( |
| 165 | 165 | sprintf( |
| 166 | 166 | esc_html__( |
@@ -175,7 +175,7 @@ discard block |
||
| 175 | 175 | // either increment the qty for an existing ticket |
| 176 | 176 | $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty); |
| 177 | 177 | // or add a new one |
| 178 | - if (! $line_item instanceof EE_Line_Item) { |
|
| 178 | + if ( ! $line_item instanceof EE_Line_Item) { |
|
| 179 | 179 | $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty); |
| 180 | 180 | } |
| 181 | 181 | $total_line_item->recalculate_total_including_taxes(); |
@@ -237,7 +237,7 @@ discard block |
||
| 237 | 237 | */ |
| 238 | 238 | public static function increment_quantity(EE_Line_Item $line_item, $qty = 1) |
| 239 | 239 | { |
| 240 | - if (! $line_item->is_percent()) { |
|
| 240 | + if ( ! $line_item->is_percent()) { |
|
| 241 | 241 | $qty += $line_item->quantity(); |
| 242 | 242 | $line_item->set_quantity($qty); |
| 243 | 243 | $line_item->set_total($line_item->unit_price() * $qty); |
@@ -266,7 +266,7 @@ discard block |
||
| 266 | 266 | */ |
| 267 | 267 | public static function decrement_quantity(EE_Line_Item $line_item, $qty = 1) |
| 268 | 268 | { |
| 269 | - if (! $line_item->is_percent()) { |
|
| 269 | + if ( ! $line_item->is_percent()) { |
|
| 270 | 270 | $qty = $line_item->quantity() - $qty; |
| 271 | 271 | $qty = max($qty, 0); |
| 272 | 272 | $line_item->set_quantity($qty); |
@@ -295,7 +295,7 @@ discard block |
||
| 295 | 295 | */ |
| 296 | 296 | public static function update_quantity(EE_Line_Item $line_item, $new_quantity) |
| 297 | 297 | { |
| 298 | - if (! $line_item->is_percent()) { |
|
| 298 | + if ( ! $line_item->is_percent()) { |
|
| 299 | 299 | $line_item->set_quantity($new_quantity); |
| 300 | 300 | $line_item->set_total($line_item->unit_price() * $new_quantity); |
| 301 | 301 | $line_item->save(); |
@@ -336,7 +336,7 @@ discard block |
||
| 336 | 336 | // add $ticket to cart |
| 337 | 337 | $line_item = EE_Line_Item::new_instance(array( |
| 338 | 338 | 'LIN_name' => $ticket->name(), |
| 339 | - 'LIN_desc' => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event, |
|
| 339 | + 'LIN_desc' => $ticket->description() !== '' ? $ticket->description().' '.$event : $event, |
|
| 340 | 340 | 'LIN_unit_price' => $ticket->price(), |
| 341 | 341 | 'LIN_quantity' => $qty, |
| 342 | 342 | 'LIN_is_taxable' => empty($taxes) && $ticket->taxable(), |
@@ -350,7 +350,7 @@ discard block |
||
| 350 | 350 | 'FHEE__EEH_Line_Item__create_ticket_line_item__line_item', |
| 351 | 351 | $line_item |
| 352 | 352 | ); |
| 353 | - if (!$line_item instanceof EE_Line_Item) { |
|
| 353 | + if ( ! $line_item instanceof EE_Line_Item) { |
|
| 354 | 354 | throw new DomainException( |
| 355 | 355 | esc_html__('Invalid EE_Line_Item received.', 'event_espresso') |
| 356 | 356 | ); |
@@ -502,7 +502,7 @@ discard block |
||
| 502 | 502 | 'event_espresso' |
| 503 | 503 | ), |
| 504 | 504 | $ticket_line_item->name(), |
| 505 | - current_time(get_option('date_format') . ' ' . get_option('time_format')) |
|
| 505 | + current_time(get_option('date_format').' '.get_option('time_format')) |
|
| 506 | 506 | ), |
| 507 | 507 | 'LIN_unit_price' => 0, // $ticket_line_item->unit_price() |
| 508 | 508 | 'LIN_quantity' => $qty, |
@@ -565,7 +565,7 @@ discard block |
||
| 565 | 565 | ); |
| 566 | 566 | $cancellation_line_item = reset($cancellation_line_item); |
| 567 | 567 | // verify that this ticket was indeed previously cancelled |
| 568 | - if (! $cancellation_line_item instanceof EE_Line_Item) { |
|
| 568 | + if ( ! $cancellation_line_item instanceof EE_Line_Item) { |
|
| 569 | 569 | return false; |
| 570 | 570 | } |
| 571 | 571 | if ($cancellation_line_item->quantity() > $qty) { |
@@ -771,7 +771,7 @@ discard block |
||
| 771 | 771 | 'LIN_code' => 'taxes', |
| 772 | 772 | 'LIN_name' => esc_html__('Taxes', 'event_espresso'), |
| 773 | 773 | 'LIN_type' => EEM_Line_Item::type_tax_sub_total, |
| 774 | - 'LIN_order' => 1000,// this should always come last |
|
| 774 | + 'LIN_order' => 1000, // this should always come last |
|
| 775 | 775 | )); |
| 776 | 776 | $tax_line_item = apply_filters( |
| 777 | 777 | 'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item', |
@@ -827,7 +827,7 @@ discard block |
||
| 827 | 827 | */ |
| 828 | 828 | public static function get_event_code($event) |
| 829 | 829 | { |
| 830 | - return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0'); |
|
| 830 | + return 'event-'.($event instanceof EE_Event ? $event->ID() : '0'); |
|
| 831 | 831 | } |
| 832 | 832 | |
| 833 | 833 | |
@@ -876,7 +876,7 @@ discard block |
||
| 876 | 876 | public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket) |
| 877 | 877 | { |
| 878 | 878 | $first_datetime = $ticket->first_datetime(); |
| 879 | - if (! $first_datetime instanceof EE_Datetime) { |
|
| 879 | + if ( ! $first_datetime instanceof EE_Datetime) { |
|
| 880 | 880 | throw new EE_Error( |
| 881 | 881 | sprintf( |
| 882 | 882 | __('The supplied ticket (ID %d) has no datetimes', 'event_espresso'), |
@@ -885,7 +885,7 @@ discard block |
||
| 885 | 885 | ); |
| 886 | 886 | } |
| 887 | 887 | $event = $first_datetime->event(); |
| 888 | - if (! $event instanceof EE_Event) { |
|
| 888 | + if ( ! $event instanceof EE_Event) { |
|
| 889 | 889 | throw new EE_Error( |
| 890 | 890 | sprintf( |
| 891 | 891 | esc_html__( |
@@ -897,7 +897,7 @@ discard block |
||
| 897 | 897 | ); |
| 898 | 898 | } |
| 899 | 899 | $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event); |
| 900 | - if (! $events_sub_total instanceof EE_Line_Item) { |
|
| 900 | + if ( ! $events_sub_total instanceof EE_Line_Item) { |
|
| 901 | 901 | throw new EE_Error( |
| 902 | 902 | sprintf( |
| 903 | 903 | esc_html__( |
@@ -933,7 +933,7 @@ discard block |
||
| 933 | 933 | $found = false; |
| 934 | 934 | foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) { |
| 935 | 935 | // default event subtotal, we should only ever find this the first time this method is called |
| 936 | - if (! $event_line_item->OBJ_ID()) { |
|
| 936 | + if ( ! $event_line_item->OBJ_ID()) { |
|
| 937 | 937 | // let's use this! but first... set the event details |
| 938 | 938 | EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
| 939 | 939 | $found = true; |
@@ -945,7 +945,7 @@ discard block |
||
| 945 | 945 | break; |
| 946 | 946 | } |
| 947 | 947 | } |
| 948 | - if (! $found) { |
|
| 948 | + if ( ! $found) { |
|
| 949 | 949 | // there is no event sub-total yet, so add it |
| 950 | 950 | $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total); |
| 951 | 951 | // create a new "event" subtotal below that |
@@ -1025,7 +1025,7 @@ discard block |
||
| 1025 | 1025 | break; |
| 1026 | 1026 | } |
| 1027 | 1027 | } |
| 1028 | - if (! $found) { |
|
| 1028 | + if ( ! $found) { |
|
| 1029 | 1029 | // add a new line item for this global tax |
| 1030 | 1030 | $tax_line_item = apply_filters( |
| 1031 | 1031 | 'FHEE__EEH_Line_Item__apply_taxes__tax_line_item', |
@@ -1072,7 +1072,7 @@ discard block |
||
| 1072 | 1072 | public static function ensure_taxes_applied($total_line_item) |
| 1073 | 1073 | { |
| 1074 | 1074 | $taxes_subtotal = self::get_taxes_subtotal($total_line_item); |
| 1075 | - if (! $taxes_subtotal->children()) { |
|
| 1075 | + if ( ! $taxes_subtotal->children()) { |
|
| 1076 | 1076 | self::apply_taxes($total_line_item); |
| 1077 | 1077 | } |
| 1078 | 1078 | return $taxes_subtotal->total(); |
@@ -1139,7 +1139,7 @@ discard block |
||
| 1139 | 1139 | do_action('AHEE_log', __FILE__, __FUNCTION__, ''); |
| 1140 | 1140 | |
| 1141 | 1141 | // check if only a single line_item_id was passed |
| 1142 | - if (! empty($line_item_codes) && ! is_array($line_item_codes)) { |
|
| 1142 | + if ( ! empty($line_item_codes) && ! is_array($line_item_codes)) { |
|
| 1143 | 1143 | // place single line_item_id in an array to appear as multiple line_item_ids |
| 1144 | 1144 | $line_item_codes = array($line_item_codes); |
| 1145 | 1145 | } |
@@ -1246,7 +1246,7 @@ discard block |
||
| 1246 | 1246 | if ($code_substring_for_whitelist !== null) { |
| 1247 | 1247 | $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false; |
| 1248 | 1248 | } |
| 1249 | - if (! $whitelisted && $line_item->is_line_item()) { |
|
| 1249 | + if ( ! $whitelisted && $line_item->is_line_item()) { |
|
| 1250 | 1250 | $line_item->set_is_taxable($taxable); |
| 1251 | 1251 | } |
| 1252 | 1252 | foreach ($line_item->children() as $child_line_item) { |
@@ -1615,7 +1615,7 @@ discard block |
||
| 1615 | 1615 | { |
| 1616 | 1616 | $new_line = defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
| 1617 | 1617 | echo $new_line; |
| 1618 | - if (! $indentation) { |
|
| 1618 | + if ( ! $indentation) { |
|
| 1619 | 1619 | echo $new_line; |
| 1620 | 1620 | } |
| 1621 | 1621 | echo str_repeat('. ', $indentation); |
@@ -1641,8 +1641,8 @@ discard block |
||
| 1641 | 1641 | self::visualize($child, $indentation + 1); |
| 1642 | 1642 | } |
| 1643 | 1643 | } |
| 1644 | - if (! $indentation) { |
|
| 1645 | - echo $new_line . $new_line; |
|
| 1644 | + if ( ! $indentation) { |
|
| 1645 | + echo $new_line.$new_line; |
|
| 1646 | 1646 | } |
| 1647 | 1647 | } |
| 1648 | 1648 | |
@@ -1720,8 +1720,8 @@ discard block |
||
| 1720 | 1720 | if ($line_item_id === 'taxable') { |
| 1721 | 1721 | continue; |
| 1722 | 1722 | } |
| 1723 | - $taxable_total = $running_totals['taxable'][ $line_item_id ]; |
|
| 1724 | - $running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal); |
|
| 1723 | + $taxable_total = $running_totals['taxable'][$line_item_id]; |
|
| 1724 | + $running_totals[$line_item_id] += ($taxable_total * $tax_percent_decimal); |
|
| 1725 | 1725 | } |
| 1726 | 1726 | break; |
| 1727 | 1727 | |
@@ -1729,7 +1729,7 @@ discard block |
||
| 1729 | 1729 | // ticket line items or ???? |
| 1730 | 1730 | if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) { |
| 1731 | 1731 | // kk it's a ticket |
| 1732 | - if (isset($running_totals[ $child_line_item->ID() ])) { |
|
| 1732 | + if (isset($running_totals[$child_line_item->ID()])) { |
|
| 1733 | 1733 | // huh? that shouldn't happen. |
| 1734 | 1734 | $running_totals['total'] += $child_line_item->total(); |
| 1735 | 1735 | } else { |
@@ -1740,18 +1740,18 @@ discard block |
||
| 1740 | 1740 | $taxable_amount = 0; |
| 1741 | 1741 | } |
| 1742 | 1742 | // are we only calculating totals for some tickets? |
| 1743 | - if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) { |
|
| 1744 | - $quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ]; |
|
| 1745 | - $running_totals[ $child_line_item->ID() ] = $quantity |
|
| 1743 | + if (isset($billable_ticket_quantities[$child_line_item->OBJ_ID()])) { |
|
| 1744 | + $quantity = $billable_ticket_quantities[$child_line_item->OBJ_ID()]; |
|
| 1745 | + $running_totals[$child_line_item->ID()] = $quantity |
|
| 1746 | 1746 | ? $child_line_item->unit_price() |
| 1747 | 1747 | : 0; |
| 1748 | - $running_totals['taxable'][ $child_line_item->ID() ] = $quantity |
|
| 1748 | + $running_totals['taxable'][$child_line_item->ID()] = $quantity |
|
| 1749 | 1749 | ? $taxable_amount |
| 1750 | 1750 | : 0; |
| 1751 | 1751 | } else { |
| 1752 | 1752 | $quantity = $child_line_item->quantity(); |
| 1753 | - $running_totals[ $child_line_item->ID() ] = $child_line_item->unit_price(); |
|
| 1754 | - $running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount; |
|
| 1753 | + $running_totals[$child_line_item->ID()] = $child_line_item->unit_price(); |
|
| 1754 | + $running_totals['taxable'][$child_line_item->ID()] = $taxable_amount; |
|
| 1755 | 1755 | } |
| 1756 | 1756 | $running_totals['taxable']['total'] += $taxable_amount * $quantity; |
| 1757 | 1757 | $running_totals['total'] += $child_line_item->unit_price() * $quantity; |
@@ -1771,12 +1771,12 @@ discard block |
||
| 1771 | 1771 | } |
| 1772 | 1772 | // update the running totals |
| 1773 | 1773 | // yes this actually even works for the running grand total! |
| 1774 | - $running_totals[ $line_item_id ] = |
|
| 1774 | + $running_totals[$line_item_id] = |
|
| 1775 | 1775 | $line_items_percent_of_running_total * $this_running_total; |
| 1776 | 1776 | |
| 1777 | 1777 | if ($child_line_item->is_taxable()) { |
| 1778 | - $running_totals['taxable'][ $line_item_id ] = |
|
| 1779 | - $line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ]; |
|
| 1778 | + $running_totals['taxable'][$line_item_id] = |
|
| 1779 | + $line_items_percent_of_running_total * $running_totals['taxable'][$line_item_id]; |
|
| 1780 | 1780 | } |
| 1781 | 1781 | } |
| 1782 | 1782 | } |
@@ -1803,14 +1803,14 @@ discard block |
||
| 1803 | 1803 | EE_Line_Item $ticket_line_item |
| 1804 | 1804 | ) { |
| 1805 | 1805 | static $final_prices_per_ticket_line_item = array(); |
| 1806 | - if (empty($final_prices_per_ticket_line_item) || empty($final_prices_per_ticket_line_item[ $total_line_item->ID() ])) { |
|
| 1807 | - $final_prices_per_ticket_line_item[ $total_line_item->ID() ] = EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
| 1806 | + if (empty($final_prices_per_ticket_line_item) || empty($final_prices_per_ticket_line_item[$total_line_item->ID()])) { |
|
| 1807 | + $final_prices_per_ticket_line_item[$total_line_item->ID()] = EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
| 1808 | 1808 | $total_line_item |
| 1809 | 1809 | ); |
| 1810 | 1810 | } |
| 1811 | 1811 | // ok now find this new registration's final price |
| 1812 | - if (isset($final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ])) { |
|
| 1813 | - return $final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ]; |
|
| 1812 | + if (isset($final_prices_per_ticket_line_item[$total_line_item->ID()][$ticket_line_item->ID()])) { |
|
| 1813 | + return $final_prices_per_ticket_line_item[$total_line_item->ID()][$ticket_line_item->ID()]; |
|
| 1814 | 1814 | } |
| 1815 | 1815 | $message = sprintf( |
| 1816 | 1816 | esc_html__( |
@@ -1821,7 +1821,7 @@ discard block |
||
| 1821 | 1821 | $total_line_item->ID() |
| 1822 | 1822 | ); |
| 1823 | 1823 | if (WP_DEBUG) { |
| 1824 | - $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true); |
|
| 1824 | + $message .= '<br>'.print_r($final_prices_per_ticket_line_item, true); |
|
| 1825 | 1825 | throw new OutOfRangeException($message); |
| 1826 | 1826 | } |
| 1827 | 1827 | EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message); |
@@ -9,86 +9,86 @@ |
||
| 9 | 9 | */ |
| 10 | 10 | class EE_Money_Field extends EE_Float_Field |
| 11 | 11 | { |
| 12 | - /** |
|
| 13 | - * @var DecimalValues |
|
| 14 | - */ |
|
| 15 | - protected $decimal_values; |
|
| 12 | + /** |
|
| 13 | + * @var DecimalValues |
|
| 14 | + */ |
|
| 15 | + protected $decimal_values; |
|
| 16 | 16 | |
| 17 | - /** |
|
| 18 | - * @param string $table_column |
|
| 19 | - * @param string $nicename |
|
| 20 | - * @param bool $nullable |
|
| 21 | - * @param null $default_value |
|
| 22 | - */ |
|
| 23 | - public function __construct($table_column, $nicename, $nullable, $default_value = null) |
|
| 24 | - { |
|
| 25 | - parent::__construct($table_column, $nicename, $nullable, $default_value); |
|
| 26 | - $this->setSchemaType('object'); |
|
| 27 | - $this->decimal_values = LoaderFactory::getShared(DecimalValues::class); |
|
| 28 | - } |
|
| 17 | + /** |
|
| 18 | + * @param string $table_column |
|
| 19 | + * @param string $nicename |
|
| 20 | + * @param bool $nullable |
|
| 21 | + * @param null $default_value |
|
| 22 | + */ |
|
| 23 | + public function __construct($table_column, $nicename, $nullable, $default_value = null) |
|
| 24 | + { |
|
| 25 | + parent::__construct($table_column, $nicename, $nullable, $default_value); |
|
| 26 | + $this->setSchemaType('object'); |
|
| 27 | + $this->decimal_values = LoaderFactory::getShared(DecimalValues::class); |
|
| 28 | + } |
|
| 29 | 29 | |
| 30 | 30 | |
| 31 | - /** |
|
| 32 | - * Schemas: |
|
| 33 | - * 'localized_float': "3,023.00" |
|
| 34 | - * 'no_currency_code': "$3,023.00" |
|
| 35 | - * null: "$3,023.00<span>USD</span>" |
|
| 36 | - * |
|
| 37 | - * @param string $value_on_field_to_be_outputted |
|
| 38 | - * @param string $schema |
|
| 39 | - * @return string |
|
| 40 | - * @throws EE_Error |
|
| 41 | - */ |
|
| 42 | - public function prepare_for_pretty_echoing($value_on_field_to_be_outputted, $schema = null): string |
|
| 43 | - { |
|
| 44 | - if ($schema == 'localized_float') { |
|
| 45 | - return parent::prepare_for_pretty_echoing($value_on_field_to_be_outputted); |
|
| 46 | - } |
|
| 47 | - $display_code = $schema !== 'no_currency_code'; |
|
| 48 | - // we don't use the $pretty_float because format_currency will take care of it. |
|
| 49 | - return EEH_Template::format_currency($value_on_field_to_be_outputted, false, $display_code); |
|
| 50 | - } |
|
| 31 | + /** |
|
| 32 | + * Schemas: |
|
| 33 | + * 'localized_float': "3,023.00" |
|
| 34 | + * 'no_currency_code': "$3,023.00" |
|
| 35 | + * null: "$3,023.00<span>USD</span>" |
|
| 36 | + * |
|
| 37 | + * @param string $value_on_field_to_be_outputted |
|
| 38 | + * @param string $schema |
|
| 39 | + * @return string |
|
| 40 | + * @throws EE_Error |
|
| 41 | + */ |
|
| 42 | + public function prepare_for_pretty_echoing($value_on_field_to_be_outputted, $schema = null): string |
|
| 43 | + { |
|
| 44 | + if ($schema == 'localized_float') { |
|
| 45 | + return parent::prepare_for_pretty_echoing($value_on_field_to_be_outputted); |
|
| 46 | + } |
|
| 47 | + $display_code = $schema !== 'no_currency_code'; |
|
| 48 | + // we don't use the $pretty_float because format_currency will take care of it. |
|
| 49 | + return EEH_Template::format_currency($value_on_field_to_be_outputted, false, $display_code); |
|
| 50 | + } |
|
| 51 | 51 | |
| 52 | 52 | |
| 53 | - /** |
|
| 54 | - * If provided with a string, strips out money-related formatting to turn it into a proper float. |
|
| 55 | - * Rounds the float to the correct number of decimal places for this country's currency. |
|
| 56 | - * Also, interprets periods and commas according to the country's currency settings. |
|
| 57 | - * So if you want to pass in a string that NEEDS to interpret periods as decimal marks, call floatval() on it first. |
|
| 58 | - * |
|
| 59 | - * @param string $value_inputted_for_field_on_model_object |
|
| 60 | - * @return float |
|
| 61 | - */ |
|
| 62 | - public function prepare_for_set($value_inputted_for_field_on_model_object): float |
|
| 63 | - { |
|
| 64 | - // now it's a float-style string or number |
|
| 65 | - $float_val = parent::prepare_for_set($value_inputted_for_field_on_model_object); |
|
| 66 | - // round to the correctly number of decimal places for this currency |
|
| 67 | - return $this->decimal_values->roundDecimalValue($float_val); |
|
| 68 | - } |
|
| 53 | + /** |
|
| 54 | + * If provided with a string, strips out money-related formatting to turn it into a proper float. |
|
| 55 | + * Rounds the float to the correct number of decimal places for this country's currency. |
|
| 56 | + * Also, interprets periods and commas according to the country's currency settings. |
|
| 57 | + * So if you want to pass in a string that NEEDS to interpret periods as decimal marks, call floatval() on it first. |
|
| 58 | + * |
|
| 59 | + * @param string $value_inputted_for_field_on_model_object |
|
| 60 | + * @return float |
|
| 61 | + */ |
|
| 62 | + public function prepare_for_set($value_inputted_for_field_on_model_object): float |
|
| 63 | + { |
|
| 64 | + // now it's a float-style string or number |
|
| 65 | + $float_val = parent::prepare_for_set($value_inputted_for_field_on_model_object); |
|
| 66 | + // round to the correctly number of decimal places for this currency |
|
| 67 | + return $this->decimal_values->roundDecimalValue($float_val); |
|
| 68 | + } |
|
| 69 | 69 | |
| 70 | 70 | |
| 71 | - /** |
|
| 72 | - * @return array[] |
|
| 73 | - */ |
|
| 74 | - public function getSchemaProperties(): array |
|
| 75 | - { |
|
| 76 | - return [ |
|
| 77 | - 'raw' => [ |
|
| 78 | - 'description' => sprintf( |
|
| 79 | - __('%s - the raw value as it exists in the database as a simple float.', 'event_espresso'), |
|
| 80 | - $this->get_nicename() |
|
| 81 | - ), |
|
| 82 | - 'type' => 'number', |
|
| 83 | - ], |
|
| 84 | - 'pretty' => [ |
|
| 85 | - 'description' => sprintf( |
|
| 86 | - __('%s - formatted for display in the set currency and decimal places.', 'event_espresso'), |
|
| 87 | - $this->get_nicename() |
|
| 88 | - ), |
|
| 89 | - 'type' => 'string', |
|
| 90 | - 'format' => 'money', |
|
| 91 | - ], |
|
| 92 | - ]; |
|
| 93 | - } |
|
| 71 | + /** |
|
| 72 | + * @return array[] |
|
| 73 | + */ |
|
| 74 | + public function getSchemaProperties(): array |
|
| 75 | + { |
|
| 76 | + return [ |
|
| 77 | + 'raw' => [ |
|
| 78 | + 'description' => sprintf( |
|
| 79 | + __('%s - the raw value as it exists in the database as a simple float.', 'event_espresso'), |
|
| 80 | + $this->get_nicename() |
|
| 81 | + ), |
|
| 82 | + 'type' => 'number', |
|
| 83 | + ], |
|
| 84 | + 'pretty' => [ |
|
| 85 | + 'description' => sprintf( |
|
| 86 | + __('%s - formatted for display in the set currency and decimal places.', 'event_espresso'), |
|
| 87 | + $this->get_nicename() |
|
| 88 | + ), |
|
| 89 | + 'type' => 'string', |
|
| 90 | + 'format' => 'money', |
|
| 91 | + ], |
|
| 92 | + ]; |
|
| 93 | + } |
|
| 94 | 94 | } |
@@ -16,160 +16,160 @@ |
||
| 16 | 16 | abstract class EE_Object_Collection extends SplObjectStorage implements EEI_Collection |
| 17 | 17 | { |
| 18 | 18 | |
| 19 | - /** |
|
| 20 | - * an interface (or class) name to be used for restricting the type of objects added to the storage |
|
| 21 | - * this should be set from within the child class constructor |
|
| 22 | - * |
|
| 23 | - * @type string $interface |
|
| 24 | - */ |
|
| 25 | - protected $interface; |
|
| 26 | - |
|
| 27 | - |
|
| 28 | - /** |
|
| 29 | - * add |
|
| 30 | - * |
|
| 31 | - * attaches an object to the Collection |
|
| 32 | - * and sets any supplied data associated with the current iterator entry |
|
| 33 | - * by calling EE_Object_Collection::set_info() |
|
| 34 | - * |
|
| 35 | - * @access public |
|
| 36 | - * @param object $object |
|
| 37 | - * @param mixed $info |
|
| 38 | - * @return bool |
|
| 39 | - */ |
|
| 40 | - public function add($object, $info = null) |
|
| 41 | - { |
|
| 42 | - $class = $this->interface; |
|
| 43 | - if (! $object instanceof $class) { |
|
| 44 | - return false; |
|
| 45 | - } |
|
| 46 | - $this->attach($object); |
|
| 47 | - $this->set_info($object, $info); |
|
| 48 | - return $this->contains($object); |
|
| 49 | - } |
|
| 50 | - |
|
| 51 | - |
|
| 52 | - /** |
|
| 53 | - * set_info |
|
| 54 | - * |
|
| 55 | - * Sets the data associated with an object in the Collection |
|
| 56 | - * if no $info is supplied, then the spl_object_hash() is used |
|
| 57 | - * |
|
| 58 | - * @access public |
|
| 59 | - * @param object $object |
|
| 60 | - * @param mixed $info |
|
| 61 | - * @return bool |
|
| 62 | - */ |
|
| 63 | - public function set_info($object, $info = null) |
|
| 64 | - { |
|
| 65 | - $info = ! empty($info) ? $info : spl_object_hash($object); |
|
| 66 | - $this->rewind(); |
|
| 67 | - while ($this->valid()) { |
|
| 68 | - if ($object === $this->current()) { |
|
| 69 | - $this->setInfo($info); |
|
| 70 | - $this->rewind(); |
|
| 71 | - return true; |
|
| 72 | - } |
|
| 73 | - $this->next(); |
|
| 74 | - } |
|
| 75 | - return false; |
|
| 76 | - } |
|
| 77 | - |
|
| 78 | - |
|
| 79 | - /** |
|
| 80 | - * get_by_info |
|
| 81 | - * |
|
| 82 | - * finds and returns an object in the Collection based on the info that was set using addObject() |
|
| 83 | - * PLZ NOTE: the pointer is reset to the beginning of the collection before returning |
|
| 84 | - * |
|
| 85 | - * @access public |
|
| 86 | - * @param mixed |
|
| 87 | - * @return null | object |
|
| 88 | - */ |
|
| 89 | - public function get_by_info($info) |
|
| 90 | - { |
|
| 91 | - $this->rewind(); |
|
| 92 | - while ($this->valid()) { |
|
| 93 | - if ($info === $this->getInfo()) { |
|
| 94 | - $object = $this->current(); |
|
| 95 | - $this->rewind(); |
|
| 96 | - return $object; |
|
| 97 | - } |
|
| 98 | - $this->next(); |
|
| 99 | - } |
|
| 100 | - return null; |
|
| 101 | - } |
|
| 102 | - |
|
| 103 | - |
|
| 104 | - /** |
|
| 105 | - * has |
|
| 106 | - * |
|
| 107 | - * returns TRUE or FALSE depending on whether the supplied object is within the Collection |
|
| 108 | - * |
|
| 109 | - * @access public |
|
| 110 | - * @param object $object |
|
| 111 | - * @return bool |
|
| 112 | - */ |
|
| 113 | - public function has($object) |
|
| 114 | - { |
|
| 115 | - return $this->contains($object); |
|
| 116 | - } |
|
| 117 | - |
|
| 118 | - |
|
| 119 | - /** |
|
| 120 | - * remove |
|
| 121 | - * |
|
| 122 | - * detaches an object from the Collection |
|
| 123 | - * |
|
| 124 | - * @access public |
|
| 125 | - * @param $object |
|
| 126 | - * @return bool |
|
| 127 | - */ |
|
| 128 | - public function remove($object) |
|
| 129 | - { |
|
| 130 | - $this->detach($object); |
|
| 131 | - return true; |
|
| 132 | - } |
|
| 133 | - |
|
| 134 | - |
|
| 135 | - /** |
|
| 136 | - * set_current |
|
| 137 | - * |
|
| 138 | - * advances pointer to the provided object |
|
| 139 | - * |
|
| 140 | - * @access public |
|
| 141 | - * @param $object |
|
| 142 | - * @return void |
|
| 143 | - */ |
|
| 144 | - public function set_current($object) |
|
| 145 | - { |
|
| 146 | - $this->rewind(); |
|
| 147 | - while ($this->valid()) { |
|
| 148 | - if ($this->current() === $object) { |
|
| 149 | - break; |
|
| 150 | - } |
|
| 151 | - $this->next(); |
|
| 152 | - } |
|
| 153 | - } |
|
| 154 | - |
|
| 155 | - |
|
| 156 | - /** |
|
| 157 | - * set_current_by_info |
|
| 158 | - * |
|
| 159 | - * advances pointer to the object whose info matches that which was provided |
|
| 160 | - * |
|
| 161 | - * @access public |
|
| 162 | - * @param $info |
|
| 163 | - * @return void |
|
| 164 | - */ |
|
| 165 | - public function set_current_by_info($info) |
|
| 166 | - { |
|
| 167 | - $this->rewind(); |
|
| 168 | - while ($this->valid()) { |
|
| 169 | - if ($info === $this->getInfo()) { |
|
| 170 | - break; |
|
| 171 | - } |
|
| 172 | - $this->next(); |
|
| 173 | - } |
|
| 174 | - } |
|
| 19 | + /** |
|
| 20 | + * an interface (or class) name to be used for restricting the type of objects added to the storage |
|
| 21 | + * this should be set from within the child class constructor |
|
| 22 | + * |
|
| 23 | + * @type string $interface |
|
| 24 | + */ |
|
| 25 | + protected $interface; |
|
| 26 | + |
|
| 27 | + |
|
| 28 | + /** |
|
| 29 | + * add |
|
| 30 | + * |
|
| 31 | + * attaches an object to the Collection |
|
| 32 | + * and sets any supplied data associated with the current iterator entry |
|
| 33 | + * by calling EE_Object_Collection::set_info() |
|
| 34 | + * |
|
| 35 | + * @access public |
|
| 36 | + * @param object $object |
|
| 37 | + * @param mixed $info |
|
| 38 | + * @return bool |
|
| 39 | + */ |
|
| 40 | + public function add($object, $info = null) |
|
| 41 | + { |
|
| 42 | + $class = $this->interface; |
|
| 43 | + if (! $object instanceof $class) { |
|
| 44 | + return false; |
|
| 45 | + } |
|
| 46 | + $this->attach($object); |
|
| 47 | + $this->set_info($object, $info); |
|
| 48 | + return $this->contains($object); |
|
| 49 | + } |
|
| 50 | + |
|
| 51 | + |
|
| 52 | + /** |
|
| 53 | + * set_info |
|
| 54 | + * |
|
| 55 | + * Sets the data associated with an object in the Collection |
|
| 56 | + * if no $info is supplied, then the spl_object_hash() is used |
|
| 57 | + * |
|
| 58 | + * @access public |
|
| 59 | + * @param object $object |
|
| 60 | + * @param mixed $info |
|
| 61 | + * @return bool |
|
| 62 | + */ |
|
| 63 | + public function set_info($object, $info = null) |
|
| 64 | + { |
|
| 65 | + $info = ! empty($info) ? $info : spl_object_hash($object); |
|
| 66 | + $this->rewind(); |
|
| 67 | + while ($this->valid()) { |
|
| 68 | + if ($object === $this->current()) { |
|
| 69 | + $this->setInfo($info); |
|
| 70 | + $this->rewind(); |
|
| 71 | + return true; |
|
| 72 | + } |
|
| 73 | + $this->next(); |
|
| 74 | + } |
|
| 75 | + return false; |
|
| 76 | + } |
|
| 77 | + |
|
| 78 | + |
|
| 79 | + /** |
|
| 80 | + * get_by_info |
|
| 81 | + * |
|
| 82 | + * finds and returns an object in the Collection based on the info that was set using addObject() |
|
| 83 | + * PLZ NOTE: the pointer is reset to the beginning of the collection before returning |
|
| 84 | + * |
|
| 85 | + * @access public |
|
| 86 | + * @param mixed |
|
| 87 | + * @return null | object |
|
| 88 | + */ |
|
| 89 | + public function get_by_info($info) |
|
| 90 | + { |
|
| 91 | + $this->rewind(); |
|
| 92 | + while ($this->valid()) { |
|
| 93 | + if ($info === $this->getInfo()) { |
|
| 94 | + $object = $this->current(); |
|
| 95 | + $this->rewind(); |
|
| 96 | + return $object; |
|
| 97 | + } |
|
| 98 | + $this->next(); |
|
| 99 | + } |
|
| 100 | + return null; |
|
| 101 | + } |
|
| 102 | + |
|
| 103 | + |
|
| 104 | + /** |
|
| 105 | + * has |
|
| 106 | + * |
|
| 107 | + * returns TRUE or FALSE depending on whether the supplied object is within the Collection |
|
| 108 | + * |
|
| 109 | + * @access public |
|
| 110 | + * @param object $object |
|
| 111 | + * @return bool |
|
| 112 | + */ |
|
| 113 | + public function has($object) |
|
| 114 | + { |
|
| 115 | + return $this->contains($object); |
|
| 116 | + } |
|
| 117 | + |
|
| 118 | + |
|
| 119 | + /** |
|
| 120 | + * remove |
|
| 121 | + * |
|
| 122 | + * detaches an object from the Collection |
|
| 123 | + * |
|
| 124 | + * @access public |
|
| 125 | + * @param $object |
|
| 126 | + * @return bool |
|
| 127 | + */ |
|
| 128 | + public function remove($object) |
|
| 129 | + { |
|
| 130 | + $this->detach($object); |
|
| 131 | + return true; |
|
| 132 | + } |
|
| 133 | + |
|
| 134 | + |
|
| 135 | + /** |
|
| 136 | + * set_current |
|
| 137 | + * |
|
| 138 | + * advances pointer to the provided object |
|
| 139 | + * |
|
| 140 | + * @access public |
|
| 141 | + * @param $object |
|
| 142 | + * @return void |
|
| 143 | + */ |
|
| 144 | + public function set_current($object) |
|
| 145 | + { |
|
| 146 | + $this->rewind(); |
|
| 147 | + while ($this->valid()) { |
|
| 148 | + if ($this->current() === $object) { |
|
| 149 | + break; |
|
| 150 | + } |
|
| 151 | + $this->next(); |
|
| 152 | + } |
|
| 153 | + } |
|
| 154 | + |
|
| 155 | + |
|
| 156 | + /** |
|
| 157 | + * set_current_by_info |
|
| 158 | + * |
|
| 159 | + * advances pointer to the object whose info matches that which was provided |
|
| 160 | + * |
|
| 161 | + * @access public |
|
| 162 | + * @param $info |
|
| 163 | + * @return void |
|
| 164 | + */ |
|
| 165 | + public function set_current_by_info($info) |
|
| 166 | + { |
|
| 167 | + $this->rewind(); |
|
| 168 | + while ($this->valid()) { |
|
| 169 | + if ($info === $this->getInfo()) { |
|
| 170 | + break; |
|
| 171 | + } |
|
| 172 | + $this->next(); |
|
| 173 | + } |
|
| 174 | + } |
|
| 175 | 175 | } |