Completed
Branch FET/rule-specific-exclusions-l... (334422)
by
unknown
17:10 queued 32s
created
core/db_classes/EE_Price_Type.class.php 1 patch
Indentation   +159 added lines, -159 removed lines patch added patch discarded remove patch
@@ -10,163 +10,163 @@
 block discarded – undo
10 10
 class EE_Price_Type extends EE_Soft_Delete_Base_Class
11 11
 {
12 12
 
13
-    /**
14
-     * @param array $props_n_values
15
-     * @return EE_Price_Type
16
-     */
17
-    public static function new_instance($props_n_values = array())
18
-    {
19
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__);
20
-        return $has_object ? $has_object : new self($props_n_values);
21
-    }
22
-
23
-
24
-    /**
25
-     * @param array $props_n_values
26
-     * @return EE_Price_Type
27
-     */
28
-    public static function new_instance_from_db($props_n_values = array())
29
-    {
30
-        return new self($props_n_values, true);
31
-    }
32
-
33
-
34
-    /**
35
-     *        Set Price Type Name
36
-     *
37
-     * @access        public
38
-     * @param        string $PRT_name
39
-     */
40
-    public function set_name($PRT_name = '')
41
-    {
42
-        $this->set('PRT_name', $PRT_name);
43
-    }
44
-
45
-
46
-    /**
47
-     *        Set Price Type a percent
48
-     *
49
-     * @access        public
50
-     * @param        bool $PRT_is_percent
51
-     */
52
-    public function set_is_percent($PRT_is_percent = false)
53
-    {
54
-        $this->set('PRT_is_percent', $PRT_is_percent);
55
-    }
56
-
57
-
58
-    /**
59
-     *        Set Price Type order
60
-     *
61
-     * @access        public
62
-     * @param        int $PRT_order
63
-     */
64
-    public function set_order($PRT_order = 0)
65
-    {
66
-        $this->set('PRT_order', $PRT_order);
67
-    }
68
-
69
-
70
-    /**
71
-     *
72
-     */
73
-    public function move_to_trash()
74
-    {
75
-        $this->set('PRT_deleted', true);
76
-    }
77
-
78
-
79
-    /**
80
-     *
81
-     */
82
-    public function restore_from_trash()
83
-    {
84
-        $this->set('PRT_deleted', false);
85
-    }
86
-
87
-
88
-    /**
89
-     *        get Price Type Name
90
-     *
91
-     * @access        public
92
-     */
93
-    public function name()
94
-    {
95
-        return $this->get('PRT_name');
96
-    }
97
-
98
-
99
-    /**
100
-     *        get is Price Type a discount?
101
-     *
102
-     * @access        public
103
-     */
104
-    public function base_type()
105
-    {
106
-        return $this->get('PBT_ID');
107
-    }
108
-
109
-
110
-    /**
111
-     * @return mixed
112
-     */
113
-    public function base_type_name()
114
-    {
115
-        return $this->get_pretty('PBT_ID');
116
-    }
117
-
118
-
119
-    /**
120
-     *        get is Price Type a percent?
121
-     *
122
-     * @access        public
123
-     */
124
-    public function is_percent()
125
-    {
126
-        return $this->get('PRT_is_percent');
127
-    }
128
-
129
-
130
-    /**
131
-     * @return bool
132
-     */
133
-    public function is_discount()
134
-    {
135
-        return $this->get('PBT_ID') == 2 ? true : false;
136
-    }
137
-
138
-
139
-    /**
140
-     * get the author of the price type.
141
-     *
142
-     * @since 4.5.0
143
-     *
144
-     * @return int
145
-     */
146
-    public function wp_user()
147
-    {
148
-        return $this->get('PRT_wp_user');
149
-    }
150
-
151
-
152
-    /**
153
-     *        get Price Type order
154
-     *
155
-     * @access        public
156
-     */
157
-    public function order()
158
-    {
159
-        return $this->get('PRT_order');
160
-    }
161
-
162
-
163
-    /**
164
-     *        get  is Price Type deleted ?
165
-     *
166
-     * @access        public
167
-     */
168
-    public function deleted()
169
-    {
170
-        return $this->get('PRT_deleted');
171
-    }
13
+	/**
14
+	 * @param array $props_n_values
15
+	 * @return EE_Price_Type
16
+	 */
17
+	public static function new_instance($props_n_values = array())
18
+	{
19
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__);
20
+		return $has_object ? $has_object : new self($props_n_values);
21
+	}
22
+
23
+
24
+	/**
25
+	 * @param array $props_n_values
26
+	 * @return EE_Price_Type
27
+	 */
28
+	public static function new_instance_from_db($props_n_values = array())
29
+	{
30
+		return new self($props_n_values, true);
31
+	}
32
+
33
+
34
+	/**
35
+	 *        Set Price Type Name
36
+	 *
37
+	 * @access        public
38
+	 * @param        string $PRT_name
39
+	 */
40
+	public function set_name($PRT_name = '')
41
+	{
42
+		$this->set('PRT_name', $PRT_name);
43
+	}
44
+
45
+
46
+	/**
47
+	 *        Set Price Type a percent
48
+	 *
49
+	 * @access        public
50
+	 * @param        bool $PRT_is_percent
51
+	 */
52
+	public function set_is_percent($PRT_is_percent = false)
53
+	{
54
+		$this->set('PRT_is_percent', $PRT_is_percent);
55
+	}
56
+
57
+
58
+	/**
59
+	 *        Set Price Type order
60
+	 *
61
+	 * @access        public
62
+	 * @param        int $PRT_order
63
+	 */
64
+	public function set_order($PRT_order = 0)
65
+	{
66
+		$this->set('PRT_order', $PRT_order);
67
+	}
68
+
69
+
70
+	/**
71
+	 *
72
+	 */
73
+	public function move_to_trash()
74
+	{
75
+		$this->set('PRT_deleted', true);
76
+	}
77
+
78
+
79
+	/**
80
+	 *
81
+	 */
82
+	public function restore_from_trash()
83
+	{
84
+		$this->set('PRT_deleted', false);
85
+	}
86
+
87
+
88
+	/**
89
+	 *        get Price Type Name
90
+	 *
91
+	 * @access        public
92
+	 */
93
+	public function name()
94
+	{
95
+		return $this->get('PRT_name');
96
+	}
97
+
98
+
99
+	/**
100
+	 *        get is Price Type a discount?
101
+	 *
102
+	 * @access        public
103
+	 */
104
+	public function base_type()
105
+	{
106
+		return $this->get('PBT_ID');
107
+	}
108
+
109
+
110
+	/**
111
+	 * @return mixed
112
+	 */
113
+	public function base_type_name()
114
+	{
115
+		return $this->get_pretty('PBT_ID');
116
+	}
117
+
118
+
119
+	/**
120
+	 *        get is Price Type a percent?
121
+	 *
122
+	 * @access        public
123
+	 */
124
+	public function is_percent()
125
+	{
126
+		return $this->get('PRT_is_percent');
127
+	}
128
+
129
+
130
+	/**
131
+	 * @return bool
132
+	 */
133
+	public function is_discount()
134
+	{
135
+		return $this->get('PBT_ID') == 2 ? true : false;
136
+	}
137
+
138
+
139
+	/**
140
+	 * get the author of the price type.
141
+	 *
142
+	 * @since 4.5.0
143
+	 *
144
+	 * @return int
145
+	 */
146
+	public function wp_user()
147
+	{
148
+		return $this->get('PRT_wp_user');
149
+	}
150
+
151
+
152
+	/**
153
+	 *        get Price Type order
154
+	 *
155
+	 * @access        public
156
+	 */
157
+	public function order()
158
+	{
159
+		return $this->get('PRT_order');
160
+	}
161
+
162
+
163
+	/**
164
+	 *        get  is Price Type deleted ?
165
+	 *
166
+	 * @access        public
167
+	 */
168
+	public function deleted()
169
+	{
170
+		return $this->get('PRT_deleted');
171
+	}
172 172
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Transaction.class.php 2 patches
Indentation   +1390 added lines, -1390 removed lines patch added patch discarded remove patch
@@ -13,1394 +13,1394 @@
 block discarded – undo
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
-     */
39
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
40
-    {
41
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
42
-        $txn = $has_object
43
-            ? $has_object
44
-            : new self($props_n_values, false, $timezone, $date_formats);
45
-        if (! $has_object) {
46
-            $txn->set_old_txn_status($txn->status_ID());
47
-        }
48
-        return $txn;
49
-    }
50
-
51
-
52
-    /**
53
-     * @param array  $props_n_values  incoming values from the database
54
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
55
-     *                                the website will be used.
56
-     * @return EE_Transaction
57
-     * @throws EE_Error
58
-     */
59
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
60
-    {
61
-        $txn = new self($props_n_values, true, $timezone);
62
-        $txn->set_old_txn_status($txn->status_ID());
63
-        return $txn;
64
-    }
65
-
66
-
67
-    /**
68
-     * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
69
-     * If a lock has already been set, then we will attempt to remove it in case it has expired.
70
-     * If that also fails, then an exception is thrown.
71
-     *
72
-     * @throws EE_Error
73
-     */
74
-    public function lock()
75
-    {
76
-        // attempt to set lock, but if that fails...
77
-        if (! $this->add_extra_meta('lock', time(), true)) {
78
-            // then attempt to remove the lock in case it is expired
79
-            if ($this->_remove_expired_lock()) {
80
-                // if removal was successful, then try setting lock again
81
-                $this->lock();
82
-            } else {
83
-                // but if the lock can not be removed, then throw an exception
84
-                throw new EE_Error(
85
-                    sprintf(
86
-                        __(
87
-                            '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.',
88
-                            'event_espresso'
89
-                        ),
90
-                        $this->ID()
91
-                    )
92
-                );
93
-            }
94
-        }
95
-    }
96
-
97
-
98
-    /**
99
-     * removes transaction lock applied in EE_Transaction::lock()
100
-     *
101
-     * @return int
102
-     * @throws EE_Error
103
-     */
104
-    public function unlock()
105
-    {
106
-        return $this->delete_extra_meta('lock');
107
-    }
108
-
109
-
110
-    /**
111
-     * Decides whether or not now is the right time to update the transaction.
112
-     * This is useful because we don't always know if it is safe to update the transaction
113
-     * and its related data. why?
114
-     * because it's possible that the transaction is being used in another
115
-     * request and could overwrite anything we save.
116
-     * So we want to only update the txn once we know that won't happen.
117
-     * We also check that the lock isn't expired, and remove it if it is
118
-     *
119
-     * @return boolean
120
-     * @throws EE_Error
121
-     */
122
-    public function is_locked()
123
-    {
124
-        // if TXN is not locked, then return false immediately
125
-        if (! $this->_get_lock()) {
126
-            return false;
127
-        }
128
-        // if not, then let's try and remove the lock in case it's expired...
129
-        // _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
130
-        // and a positive number if the lock was removed (ie: number of locks deleted),
131
-        // so we need to return the opposite
132
-        return ! $this->_remove_expired_lock() ? true : false;
133
-    }
134
-
135
-
136
-    /**
137
-     * Gets the meta field indicating that this TXN is locked
138
-     *
139
-     * @return int
140
-     * @throws EE_Error
141
-     */
142
-    protected function _get_lock()
143
-    {
144
-        return (int) $this->get_extra_meta('lock', true, 0);
145
-    }
146
-
147
-
148
-    /**
149
-     * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
150
-     *
151
-     * @return int
152
-     * @throws EE_Error
153
-     */
154
-    protected function _remove_expired_lock()
155
-    {
156
-        $locked = $this->_get_lock();
157
-        if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
158
-            return $this->unlock();
159
-        }
160
-        return 0;
161
-    }
162
-
163
-
164
-    /**
165
-     * Set transaction total
166
-     *
167
-     * @param float $total total value of transaction
168
-     * @throws EE_Error
169
-     */
170
-    public function set_total($total = 0.00)
171
-    {
172
-        $this->set('TXN_total', (float) $total);
173
-    }
174
-
175
-
176
-    /**
177
-     * Set Total Amount Paid to Date
178
-     *
179
-     * @param float $total_paid total amount paid to date (sum of all payments)
180
-     * @throws EE_Error
181
-     */
182
-    public function set_paid($total_paid = 0.00)
183
-    {
184
-        $this->set('TXN_paid', (float) $total_paid);
185
-    }
186
-
187
-
188
-    /**
189
-     * Set transaction status
190
-     *
191
-     * @param string $status        whether the transaction is open, declined, accepted,
192
-     *                              or any number of custom values that can be set
193
-     * @throws EE_Error
194
-     */
195
-    public function set_status($status = '')
196
-    {
197
-        $this->set('STS_ID', $status);
198
-    }
199
-
200
-
201
-    /**
202
-     * Set hash salt
203
-     *
204
-     * @param string $hash_salt required for some payment gateways
205
-     * @throws EE_Error
206
-     */
207
-    public function set_hash_salt($hash_salt = '')
208
-    {
209
-        $this->set('TXN_hash_salt', $hash_salt);
210
-    }
211
-
212
-
213
-    /**
214
-     * Sets TXN_reg_steps array
215
-     *
216
-     * @param array $txn_reg_steps
217
-     * @throws EE_Error
218
-     */
219
-    public function set_reg_steps(array $txn_reg_steps)
220
-    {
221
-        $this->set('TXN_reg_steps', $txn_reg_steps);
222
-    }
223
-
224
-
225
-    /**
226
-     * Gets TXN_reg_steps
227
-     *
228
-     * @return array
229
-     * @throws EE_Error
230
-     */
231
-    public function reg_steps()
232
-    {
233
-        $TXN_reg_steps = $this->get('TXN_reg_steps');
234
-        return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array();
235
-    }
236
-
237
-
238
-    /**
239
-     * @return string of transaction's total cost, with currency symbol and decimal
240
-     * @throws EE_Error
241
-     */
242
-    public function pretty_total()
243
-    {
244
-        return $this->get_pretty('TXN_total');
245
-    }
246
-
247
-
248
-    /**
249
-     * Gets the amount paid in a pretty string (formatted and with currency symbol)
250
-     *
251
-     * @return string
252
-     * @throws EE_Error
253
-     */
254
-    public function pretty_paid()
255
-    {
256
-        return $this->get_pretty('TXN_paid');
257
-    }
258
-
259
-
260
-    /**
261
-     * calculate the amount remaining for this transaction and return;
262
-     *
263
-     * @return float amount remaining
264
-     * @throws EE_Error
265
-     */
266
-    public function remaining()
267
-    {
268
-        return $this->total() - $this->paid();
269
-    }
270
-
271
-
272
-    /**
273
-     * get Transaction Total
274
-     *
275
-     * @return float
276
-     * @throws EE_Error
277
-     */
278
-    public function total()
279
-    {
280
-        return (float) $this->get('TXN_total');
281
-    }
282
-
283
-
284
-    /**
285
-     * get Total Amount Paid to Date
286
-     *
287
-     * @return float
288
-     * @throws EE_Error
289
-     */
290
-    public function paid()
291
-    {
292
-        return (float) $this->get('TXN_paid');
293
-    }
294
-
295
-
296
-    /**
297
-     * @throws EE_Error
298
-     */
299
-    public function get_cart_session()
300
-    {
301
-        $session_data = (array) $this->get('TXN_session_data');
302
-        return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
303
-            ? $session_data['cart']
304
-            : null;
305
-    }
306
-
307
-
308
-    /**
309
-     * get Transaction session data
310
-     *
311
-     * @throws EE_Error
312
-     */
313
-    public function session_data()
314
-    {
315
-        $session_data = $this->get('TXN_session_data');
316
-        if (empty($session_data)) {
317
-            $session_data = array(
318
-                'id'            => null,
319
-                'user_id'       => null,
320
-                'ip_address'    => null,
321
-                'user_agent'    => null,
322
-                'init_access'   => null,
323
-                'last_access'   => null,
324
-                'pages_visited' => array(),
325
-            );
326
-        }
327
-        return $session_data;
328
-    }
329
-
330
-
331
-    /**
332
-     * Set session data within the TXN object
333
-     *
334
-     * @param EE_Session|array $session_data
335
-     * @throws EE_Error
336
-     */
337
-    public function set_txn_session_data($session_data)
338
-    {
339
-        if ($session_data instanceof EE_Session) {
340
-            $this->set('TXN_session_data', $session_data->get_session_data(null, true));
341
-        } else {
342
-            $this->set('TXN_session_data', $session_data);
343
-        }
344
-    }
345
-
346
-
347
-    /**
348
-     * get Transaction hash salt
349
-     *
350
-     * @throws EE_Error
351
-     */
352
-    public function hash_salt_()
353
-    {
354
-        return $this->get('TXN_hash_salt');
355
-    }
356
-
357
-
358
-    /**
359
-     * Returns the transaction datetime as either:
360
-     *            - unix timestamp format ($format = false, $gmt = true)
361
-     *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
362
-     *              has no affect with this option)), this also may include a timezone abbreviation if the
363
-     *              set timezone in this class differs from what the timezone is on the blog.
364
-     *            - formatted date string including the UTC (timezone) offset (default).
365
-     *
366
-     * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
367
-     * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
368
-     *                          or no UTC offset applied
369
-     * @return string | int
370
-     * @throws EE_Error
371
-     */
372
-    public function datetime($format = false, $gmt = false)
373
-    {
374
-        if ($format) {
375
-            return $this->get_pretty('TXN_timestamp');
376
-        }
377
-        if ($gmt) {
378
-            return $this->get_raw('TXN_timestamp');
379
-        }
380
-        return $this->get('TXN_timestamp');
381
-    }
382
-
383
-
384
-    /**
385
-     * Gets registrations on this transaction
386
-     *
387
-     * @param array   $query_params array of query parameters
388
-     * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
389
-     * @return EE_Base_Class[]|EE_Registration[]
390
-     * @throws EE_Error
391
-     */
392
-    public function registrations($query_params = array(), $get_cached = false)
393
-    {
394
-        $query_params = (empty($query_params) || ! is_array($query_params))
395
-            ? array(
396
-                'order_by' => array(
397
-                    'Event.EVT_name'     => 'ASC',
398
-                    'Attendee.ATT_lname' => 'ASC',
399
-                    'Attendee.ATT_fname' => 'ASC',
400
-                ),
401
-            )
402
-            : $query_params;
403
-        $query_params = $get_cached ? array() : $query_params;
404
-        return $this->get_many_related('Registration', $query_params);
405
-    }
406
-
407
-
408
-    /**
409
-     * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
410
-     * function for getting attendees and how many registrations they each have for an event)
411
-     *
412
-     * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
413
-     * @throws EE_Error
414
-     */
415
-    public function attendees()
416
-    {
417
-        return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID())));
418
-    }
419
-
420
-
421
-    /**
422
-     * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
423
-     *
424
-     * @param array $query_params like EEM_Base::get_all
425
-     * @return EE_Base_Class[]|EE_Payment[]
426
-     * @throws EE_Error
427
-     */
428
-    public function payments($query_params = array())
429
-    {
430
-        return $this->get_many_related('Payment', $query_params);
431
-    }
432
-
433
-
434
-    /**
435
-     * gets only approved payments for this transaction
436
-     *
437
-     * @return EE_Base_Class[]|EE_Payment[]
438
-     * @throws EE_Error
439
-     * @throws InvalidArgumentException
440
-     * @throws ReflectionException
441
-     * @throws InvalidDataTypeException
442
-     * @throws InvalidInterfaceException
443
-     */
444
-    public function approved_payments()
445
-    {
446
-        EE_Registry::instance()->load_model('Payment');
447
-        return $this->get_many_related(
448
-            'Payment',
449
-            array(
450
-                array('STS_ID' => EEM_Payment::status_id_approved),
451
-                'order_by' => array('PAY_timestamp' => 'DESC'),
452
-            )
453
-        );
454
-    }
455
-
456
-
457
-    /**
458
-     * Gets all payments which have not been approved
459
-     *
460
-     * @return EE_Base_Class[]|EEI_Payment[]
461
-     * @throws EE_Error if a model is misconfigured somehow
462
-     */
463
-    public function pending_payments()
464
-    {
465
-        return $this->get_many_related(
466
-            'Payment',
467
-            array(
468
-                array(
469
-                    'STS_ID' => EEM_Payment::status_id_pending,
470
-                ),
471
-                'order_by' => array(
472
-                    'PAY_timestamp' => 'DESC',
473
-                ),
474
-            )
475
-        );
476
-    }
477
-
478
-
479
-    /**
480
-     * echoes $this->pretty_status()
481
-     *
482
-     * @param bool $show_icons
483
-     * @throws EE_Error
484
-     * @throws InvalidArgumentException
485
-     * @throws InvalidDataTypeException
486
-     * @throws InvalidInterfaceException
487
-     */
488
-    public function e_pretty_status($show_icons = false)
489
-    {
490
-        echo $this->pretty_status($show_icons);
491
-    }
492
-
493
-
494
-    /**
495
-     * returns a pretty version of the status, good for displaying to users
496
-     *
497
-     * @param bool $show_icons
498
-     * @return string
499
-     * @throws EE_Error
500
-     * @throws InvalidArgumentException
501
-     * @throws InvalidDataTypeException
502
-     * @throws InvalidInterfaceException
503
-     */
504
-    public function pretty_status($show_icons = false)
505
-    {
506
-        $status = EEM_Status::instance()->localized_status(
507
-            array($this->status_ID() => __('unknown', 'event_espresso')),
508
-            false,
509
-            'sentence'
510
-        );
511
-        $icon = '';
512
-        switch ($this->status_ID()) {
513
-            case EEM_Transaction::complete_status_code:
514
-                $icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
515
-                break;
516
-            case EEM_Transaction::incomplete_status_code:
517
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
518
-                    : '';
519
-                break;
520
-            case EEM_Transaction::abandoned_status_code:
521
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
522
-                break;
523
-            case EEM_Transaction::failed_status_code:
524
-                $icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
525
-                break;
526
-            case EEM_Transaction::overpaid_status_code:
527
-                $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
528
-                break;
529
-        }
530
-        return $icon . $status[ $this->status_ID() ];
531
-    }
532
-
533
-
534
-    /**
535
-     * get Transaction Status
536
-     *
537
-     * @throws EE_Error
538
-     */
539
-    public function status_ID()
540
-    {
541
-        return $this->get('STS_ID');
542
-    }
543
-
544
-
545
-    /**
546
-     * Returns TRUE or FALSE for whether or not this transaction cost any money
547
-     *
548
-     * @return boolean
549
-     * @throws EE_Error
550
-     */
551
-    public function is_free()
552
-    {
553
-        return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
554
-    }
555
-
556
-
557
-    /**
558
-     * Returns whether this transaction is complete
559
-     * Useful in templates and other logic for deciding if we should ask for another payment...
560
-     *
561
-     * @return boolean
562
-     * @throws EE_Error
563
-     */
564
-    public function is_completed()
565
-    {
566
-        return $this->status_ID() === EEM_Transaction::complete_status_code;
567
-    }
568
-
569
-
570
-    /**
571
-     * Returns whether this transaction is incomplete
572
-     * Useful in templates and other logic for deciding if we should ask for another payment...
573
-     *
574
-     * @return boolean
575
-     * @throws EE_Error
576
-     */
577
-    public function is_incomplete()
578
-    {
579
-        return $this->status_ID() === EEM_Transaction::incomplete_status_code;
580
-    }
581
-
582
-
583
-    /**
584
-     * Returns whether this transaction is overpaid
585
-     * Useful in templates and other logic for deciding if monies need to be refunded
586
-     *
587
-     * @return boolean
588
-     * @throws EE_Error
589
-     */
590
-    public function is_overpaid()
591
-    {
592
-        return $this->status_ID() === EEM_Transaction::overpaid_status_code;
593
-    }
594
-
595
-
596
-    /**
597
-     * Returns whether this transaction was abandoned
598
-     * meaning that the transaction/registration process was somehow interrupted and never completed
599
-     * but that contact information exists for at least one registrant
600
-     *
601
-     * @return boolean
602
-     * @throws EE_Error
603
-     */
604
-    public function is_abandoned()
605
-    {
606
-        return $this->status_ID() === EEM_Transaction::abandoned_status_code;
607
-    }
608
-
609
-
610
-    /**
611
-     * Returns whether this transaction failed
612
-     * meaning that the transaction/registration process was somehow interrupted and never completed
613
-     * and that NO contact information exists for any registrants
614
-     *
615
-     * @return boolean
616
-     * @throws EE_Error
617
-     */
618
-    public function failed()
619
-    {
620
-        return $this->status_ID() === EEM_Transaction::failed_status_code;
621
-    }
622
-
623
-
624
-    /**
625
-     * This returns the url for the invoice of this transaction
626
-     *
627
-     * @param string $type 'html' or 'pdf' (default is pdf)
628
-     * @return string
629
-     * @throws EE_Error
630
-     */
631
-    public function invoice_url($type = 'html')
632
-    {
633
-        $REG = $this->primary_registration();
634
-        if (! $REG instanceof EE_Registration) {
635
-            return '';
636
-        }
637
-        return $REG->invoice_url($type);
638
-    }
639
-
640
-
641
-    /**
642
-     * Gets the primary registration only
643
-     *
644
-     * @return EE_Base_Class|EE_Registration
645
-     * @throws EE_Error
646
-     */
647
-    public function primary_registration()
648
-    {
649
-        $registrations = (array) $this->get_many_related(
650
-            'Registration',
651
-            array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT))
652
-        );
653
-        foreach ($registrations as $registration) {
654
-            // valid registration that is NOT cancelled or declined ?
655
-            if ($registration instanceof EE_Registration
656
-                && ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
657
-            ) {
658
-                return $registration;
659
-            }
660
-        }
661
-        // nothing valid found, so just return first thing from array of results
662
-        return reset($registrations);
663
-    }
664
-
665
-
666
-    /**
667
-     * Gets the URL for viewing the receipt
668
-     *
669
-     * @param string $type 'pdf' or 'html' (default is 'html')
670
-     * @return string
671
-     * @throws EE_Error
672
-     */
673
-    public function receipt_url($type = 'html')
674
-    {
675
-        $REG = $this->primary_registration();
676
-        if (! $REG instanceof EE_Registration) {
677
-            return '';
678
-        }
679
-        return $REG->receipt_url($type);
680
-    }
681
-
682
-
683
-    /**
684
-     * Gets the URL of the thank you page with this registration REG_url_link added as
685
-     * a query parameter
686
-     *
687
-     * @return string
688
-     * @throws EE_Error
689
-     */
690
-    public function payment_overview_url()
691
-    {
692
-        $primary_registration = $this->primary_registration();
693
-        return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
694
-    }
695
-
696
-
697
-    /**
698
-     * @return string
699
-     * @throws EE_Error
700
-     */
701
-    public function gateway_response_on_transaction()
702
-    {
703
-        $payment = $this->get_first_related('Payment');
704
-        return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
705
-    }
706
-
707
-
708
-    /**
709
-     * Get the status object of this object
710
-     *
711
-     * @return EE_Base_Class|EE_Status
712
-     * @throws EE_Error
713
-     */
714
-    public function status_obj()
715
-    {
716
-        return $this->get_first_related('Status');
717
-    }
718
-
719
-
720
-    /**
721
-     * Gets all the extra meta info on this payment
722
-     *
723
-     * @param array $query_params like EEM_Base::get_all
724
-     * @return EE_Base_Class[]|EE_Extra_Meta
725
-     * @throws EE_Error
726
-     */
727
-    public function extra_meta($query_params = array())
728
-    {
729
-        return $this->get_many_related('Extra_Meta', $query_params);
730
-    }
731
-
732
-
733
-    /**
734
-     * Wrapper for _add_relation_to
735
-     *
736
-     * @param EE_Registration $registration
737
-     * @return EE_Base_Class the relation was added to
738
-     * @throws EE_Error
739
-     */
740
-    public function add_registration(EE_Registration $registration)
741
-    {
742
-        return $this->_add_relation_to($registration, 'Registration');
743
-    }
744
-
745
-
746
-    /**
747
-     * Removes the given registration from being related (even before saving this transaction).
748
-     * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
749
-     *
750
-     * @param int $registration_or_id
751
-     * @return EE_Base_Class that was removed from being related
752
-     * @throws EE_Error
753
-     */
754
-    public function remove_registration_with_id($registration_or_id)
755
-    {
756
-        return $this->_remove_relation_to($registration_or_id, 'Registration');
757
-    }
758
-
759
-
760
-    /**
761
-     * Gets all the line items which are for ACTUAL items
762
-     *
763
-     * @return EE_Line_Item[]
764
-     * @throws EE_Error
765
-     */
766
-    public function items_purchased()
767
-    {
768
-        return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item)));
769
-    }
770
-
771
-
772
-    /**
773
-     * Wrapper for _add_relation_to
774
-     *
775
-     * @param EE_Line_Item $line_item
776
-     * @return EE_Base_Class the relation was added to
777
-     * @throws EE_Error
778
-     */
779
-    public function add_line_item(EE_Line_Item $line_item)
780
-    {
781
-        return $this->_add_relation_to($line_item, 'Line_Item');
782
-    }
783
-
784
-
785
-    /**
786
-     * Gets ALL the line items related to this transaction (unstructured)
787
-     *
788
-     * @param array $query_params
789
-     * @return EE_Base_Class[]|EE_Line_Item[]
790
-     * @throws EE_Error
791
-     */
792
-    public function line_items($query_params = array())
793
-    {
794
-        return $this->get_many_related('Line_Item', $query_params);
795
-    }
796
-
797
-
798
-    /**
799
-     * Gets all the line items which are taxes on the total
800
-     *
801
-     * @return EE_Line_Item[]
802
-     * @throws EE_Error
803
-     */
804
-    public function tax_items()
805
-    {
806
-        return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax)));
807
-    }
808
-
809
-
810
-    /**
811
-     * Gets the total line item (which is a parent of all other related line items,
812
-     * meaning it takes them all into account on its total)
813
-     *
814
-     * @param bool $create_if_not_found
815
-     * @return \EE_Line_Item
816
-     * @throws EE_Error
817
-     */
818
-    public function total_line_item($create_if_not_found = true)
819
-    {
820
-        $item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
821
-        if (! $item && $create_if_not_found) {
822
-            $item = EEH_Line_Item::create_total_line_item($this);
823
-        }
824
-        return $item;
825
-    }
826
-
827
-
828
-    /**
829
-     * Returns the total amount of tax on this transaction
830
-     * (assumes there's only one tax subtotal line item)
831
-     *
832
-     * @return float
833
-     * @throws EE_Error
834
-     */
835
-    public function tax_total()
836
-    {
837
-        $tax_line_item = $this->tax_total_line_item();
838
-        if ($tax_line_item) {
839
-            return (float) $tax_line_item->total();
840
-        }
841
-        return (float) 0;
842
-    }
843
-
844
-
845
-    /**
846
-     * Gets the tax subtotal line item (assumes there's only one)
847
-     *
848
-     * @return EE_Line_Item
849
-     * @throws EE_Error
850
-     */
851
-    public function tax_total_line_item()
852
-    {
853
-        return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
854
-    }
855
-
856
-
857
-    /**
858
-     * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
859
-     *
860
-     * @return EE_Form_Section_Proper
861
-     * @throws EE_Error
862
-     */
863
-    public function billing_info()
864
-    {
865
-        $payment_method = $this->payment_method();
866
-        if (! $payment_method) {
867
-            EE_Error::add_error(
868
-                __(
869
-                    'Could not find billing info for transaction because no gateway has been used for it yet',
870
-                    'event_espresso'
871
-                ),
872
-                __FILE__,
873
-                __FUNCTION__,
874
-                __LINE__
875
-            );
876
-            return null;
877
-        }
878
-        $primary_reg = $this->primary_registration();
879
-        if (! $primary_reg) {
880
-            EE_Error::add_error(
881
-                __(
882
-                    'Cannot get billing info for gateway %s on transaction because no primary registration exists',
883
-                    'event_espresso'
884
-                ),
885
-                __FILE__,
886
-                __FUNCTION__,
887
-                __LINE__
888
-            );
889
-            return null;
890
-        }
891
-        $attendee = $primary_reg->attendee();
892
-        if (! $attendee) {
893
-            EE_Error::add_error(
894
-                __(
895
-                    'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
896
-                    'event_espresso'
897
-                ),
898
-                __FILE__,
899
-                __FUNCTION__,
900
-                __LINE__
901
-            );
902
-            return null;
903
-        }
904
-        return $attendee->billing_info_for_payment_method($payment_method);
905
-    }
906
-
907
-
908
-    /**
909
-     * Gets PMD_ID
910
-     *
911
-     * @return int
912
-     * @throws EE_Error
913
-     */
914
-    public function payment_method_ID()
915
-    {
916
-        return $this->get('PMD_ID');
917
-    }
918
-
919
-
920
-    /**
921
-     * Sets PMD_ID
922
-     *
923
-     * @param int $PMD_ID
924
-     * @throws EE_Error
925
-     */
926
-    public function set_payment_method_ID($PMD_ID)
927
-    {
928
-        $this->set('PMD_ID', $PMD_ID);
929
-    }
930
-
931
-
932
-    /**
933
-     * Gets the last-used payment method on this transaction
934
-     * (we COULD just use the last-made payment, but some payment methods, namely
935
-     * offline ones, dont' create payments)
936
-     *
937
-     * @return EE_Payment_Method
938
-     * @throws EE_Error
939
-     */
940
-    public function payment_method()
941
-    {
942
-        $pm = $this->get_first_related('Payment_Method');
943
-        if ($pm instanceof EE_Payment_Method) {
944
-            return $pm;
945
-        }
946
-        $last_payment = $this->last_payment();
947
-        if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
948
-            return $last_payment->payment_method();
949
-        }
950
-        return null;
951
-    }
952
-
953
-
954
-    /**
955
-     * Gets the last payment made
956
-     *
957
-     * @return EE_Base_Class|EE_Payment
958
-     * @throws EE_Error
959
-     */
960
-    public function last_payment()
961
-    {
962
-        return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc')));
963
-    }
964
-
965
-
966
-    /**
967
-     * Gets all the line items which are unrelated to tickets on this transaction
968
-     *
969
-     * @return EE_Line_Item[]
970
-     * @throws EE_Error
971
-     * @throws InvalidArgumentException
972
-     * @throws InvalidDataTypeException
973
-     * @throws InvalidInterfaceException
974
-     */
975
-    public function non_ticket_line_items()
976
-    {
977
-        return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
978
-    }
979
-
980
-
981
-    /**
982
-     * possibly toggles TXN status
983
-     *
984
-     * @param  boolean $update whether to save the TXN
985
-     * @return bool whether the TXN was saved
986
-     * @throws EE_Error
987
-     * @throws RuntimeException
988
-     */
989
-    public function update_status_based_on_total_paid($update = true)
990
-    {
991
-        // set transaction status based on comparison of TXN_paid vs TXN_total
992
-        if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
993
-            $new_txn_status = EEM_Transaction::overpaid_status_code;
994
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
995
-            $new_txn_status = EEM_Transaction::complete_status_code;
996
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
997
-            $new_txn_status = EEM_Transaction::incomplete_status_code;
998
-        } else {
999
-            throw new RuntimeException(
1000
-                __('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1001
-            );
1002
-        }
1003
-        if ($new_txn_status !== $this->status_ID()) {
1004
-            $this->set_status($new_txn_status);
1005
-            if ($update) {
1006
-                return $this->save() ? true : false;
1007
-            }
1008
-        }
1009
-        return false;
1010
-    }
1011
-
1012
-
1013
-    /**
1014
-     * Updates the transaction's status and total_paid based on all the payments
1015
-     * that apply to it
1016
-     *
1017
-     * @deprecated
1018
-     * @return array|bool
1019
-     * @throws EE_Error
1020
-     * @throws InvalidArgumentException
1021
-     * @throws ReflectionException
1022
-     * @throws InvalidDataTypeException
1023
-     * @throws InvalidInterfaceException
1024
-     */
1025
-    public function update_based_on_payments()
1026
-    {
1027
-        EE_Error::doing_it_wrong(
1028
-            __CLASS__ . '::' . __FUNCTION__,
1029
-            sprintf(
1030
-                __('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1031
-                'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1032
-            ),
1033
-            '4.6.0'
1034
-        );
1035
-        /** @type EE_Transaction_Processor $transaction_processor */
1036
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1037
-        return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1038
-    }
1039
-
1040
-
1041
-    /**
1042
-     * @return string
1043
-     */
1044
-    public function old_txn_status()
1045
-    {
1046
-        return $this->_old_txn_status;
1047
-    }
1048
-
1049
-
1050
-    /**
1051
-     * @param string $old_txn_status
1052
-     */
1053
-    public function set_old_txn_status($old_txn_status)
1054
-    {
1055
-        // only set the first time
1056
-        if ($this->_old_txn_status === null) {
1057
-            $this->_old_txn_status = $old_txn_status;
1058
-        }
1059
-    }
1060
-
1061
-
1062
-    /**
1063
-     * reg_status_updated
1064
-     *
1065
-     * @return bool
1066
-     * @throws EE_Error
1067
-     */
1068
-    public function txn_status_updated()
1069
-    {
1070
-        return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1071
-    }
1072
-
1073
-
1074
-    /**
1075
-     * _reg_steps_completed
1076
-     * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1077
-     * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1078
-     * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1079
-     *
1080
-     * @param string $reg_step_slug
1081
-     * @param bool   $check_all
1082
-     * @return bool|int
1083
-     * @throws EE_Error
1084
-     */
1085
-    private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1086
-    {
1087
-        $reg_steps = $this->reg_steps();
1088
-        if (! is_array($reg_steps) || empty($reg_steps)) {
1089
-            return false;
1090
-        }
1091
-        // loop thru reg steps array)
1092
-        foreach ($reg_steps as $slug => $reg_step_completed) {
1093
-            // if NOT checking ALL steps (only checking one step)
1094
-            if (! $check_all) {
1095
-                // and this is the one
1096
-                if ($slug === $reg_step_slug) {
1097
-                    return $reg_step_completed;
1098
-                }
1099
-                // skip to next reg step in loop
1100
-                continue;
1101
-            }
1102
-            // $check_all must be true, else we would never have gotten to this point
1103
-            if ($slug === $reg_step_slug) {
1104
-                // if we reach this point, then we are testing either:
1105
-                // all_reg_steps_completed_except() or
1106
-                // all_reg_steps_completed_except_final_step(),
1107
-                // and since this is the reg step EXCEPTION being tested
1108
-                // we want to return true (yes true) if this reg step is NOT completed
1109
-                // ie: "is everything completed except the final step?"
1110
-                // "that is correct... the final step is not completed, but all others are."
1111
-                return $reg_step_completed !== true;
1112
-            }
1113
-            if ($reg_step_completed !== true) {
1114
-                // if any reg step is NOT completed, then ALL steps are not completed
1115
-                return false;
1116
-            }
1117
-        }
1118
-        return true;
1119
-    }
1120
-
1121
-
1122
-    /**
1123
-     * all_reg_steps_completed
1124
-     * returns:
1125
-     *    true if ALL reg steps have been marked as completed
1126
-     *        or false if any step is not completed
1127
-     *
1128
-     * @return bool
1129
-     * @throws EE_Error
1130
-     */
1131
-    public function all_reg_steps_completed()
1132
-    {
1133
-        return $this->_reg_steps_completed();
1134
-    }
1135
-
1136
-
1137
-    /**
1138
-     * all_reg_steps_completed_except
1139
-     * returns:
1140
-     *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1141
-     *        or false if any other step is not completed
1142
-     *        or false if ALL steps are completed including the exception you are testing !!!
1143
-     *
1144
-     * @param string $exception
1145
-     * @return bool
1146
-     * @throws EE_Error
1147
-     */
1148
-    public function all_reg_steps_completed_except($exception = '')
1149
-    {
1150
-        return $this->_reg_steps_completed($exception);
1151
-    }
1152
-
1153
-
1154
-    /**
1155
-     * all_reg_steps_completed_except
1156
-     * returns:
1157
-     *        true if ALL reg steps, except the final step, have been marked as completed
1158
-     *        or false if any step is not completed
1159
-     *    or false if ALL steps are completed including the final step !!!
1160
-     *
1161
-     * @return bool
1162
-     * @throws EE_Error
1163
-     */
1164
-    public function all_reg_steps_completed_except_final_step()
1165
-    {
1166
-        return $this->_reg_steps_completed('finalize_registration');
1167
-    }
1168
-
1169
-
1170
-    /**
1171
-     * reg_step_completed
1172
-     * returns:
1173
-     *    true if a specific reg step has been marked as completed
1174
-     *    a Unix timestamp if it has been initialized but not yet completed,
1175
-     *    or false if it has not yet been initialized
1176
-     *
1177
-     * @param string $reg_step_slug
1178
-     * @return bool|int
1179
-     * @throws EE_Error
1180
-     */
1181
-    public function reg_step_completed($reg_step_slug)
1182
-    {
1183
-        return $this->_reg_steps_completed($reg_step_slug, false);
1184
-    }
1185
-
1186
-
1187
-    /**
1188
-     * completed_final_reg_step
1189
-     * returns:
1190
-     *    true if the finalize_registration reg step has been marked as completed
1191
-     *    a Unix timestamp if it has been initialized but not yet completed,
1192
-     *    or false if it has not yet been initialized
1193
-     *
1194
-     * @return bool|int
1195
-     * @throws EE_Error
1196
-     */
1197
-    public function final_reg_step_completed()
1198
-    {
1199
-        return $this->_reg_steps_completed('finalize_registration', false);
1200
-    }
1201
-
1202
-
1203
-    /**
1204
-     * set_reg_step_initiated
1205
-     * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1206
-     *
1207
-     * @param string $reg_step_slug
1208
-     * @return boolean
1209
-     * @throws EE_Error
1210
-     */
1211
-    public function set_reg_step_initiated($reg_step_slug)
1212
-    {
1213
-        return $this->_set_reg_step_completed_status($reg_step_slug, time());
1214
-    }
1215
-
1216
-
1217
-    /**
1218
-     * set_reg_step_completed
1219
-     * given a valid TXN_reg_step, this sets the step as completed
1220
-     *
1221
-     * @param string $reg_step_slug
1222
-     * @return boolean
1223
-     * @throws EE_Error
1224
-     */
1225
-    public function set_reg_step_completed($reg_step_slug)
1226
-    {
1227
-        return $this->_set_reg_step_completed_status($reg_step_slug, true);
1228
-    }
1229
-
1230
-
1231
-    /**
1232
-     * set_reg_step_completed
1233
-     * given a valid TXN_reg_step slug, this sets the step as NOT completed
1234
-     *
1235
-     * @param string $reg_step_slug
1236
-     * @return boolean
1237
-     * @throws EE_Error
1238
-     */
1239
-    public function set_reg_step_not_completed($reg_step_slug)
1240
-    {
1241
-        return $this->_set_reg_step_completed_status($reg_step_slug, false);
1242
-    }
1243
-
1244
-
1245
-    /**
1246
-     * set_reg_step_completed
1247
-     * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1248
-     *
1249
-     * @param  string      $reg_step_slug
1250
-     * @param  boolean|int $status
1251
-     * @return boolean
1252
-     * @throws EE_Error
1253
-     */
1254
-    private function _set_reg_step_completed_status($reg_step_slug, $status)
1255
-    {
1256
-        // validate status
1257
-        $status = is_bool($status) || is_int($status) ? $status : false;
1258
-        // get reg steps array
1259
-        $txn_reg_steps = $this->reg_steps();
1260
-        // if reg step does NOT exist
1261
-        if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1262
-            return false;
1263
-        }
1264
-        // if  we're trying to complete a step that is already completed
1265
-        if ($txn_reg_steps[ $reg_step_slug ] === true) {
1266
-            return true;
1267
-        }
1268
-        // if  we're trying to complete a step that hasn't even started
1269
-        if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1270
-            return false;
1271
-        }
1272
-        // if current status value matches the incoming value (no change)
1273
-        // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1274
-        if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1275
-            // this will happen in cases where multiple AJAX requests occur during the same step
1276
-            return true;
1277
-        }
1278
-        // if we're trying to set a start time, but it has already been set...
1279
-        if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1280
-            // skip the update below, but don't return FALSE so that errors won't be displayed
1281
-            return true;
1282
-        }
1283
-        // update completed status
1284
-        $txn_reg_steps[ $reg_step_slug ] = $status;
1285
-        $this->set_reg_steps($txn_reg_steps);
1286
-        $this->save();
1287
-        return true;
1288
-    }
1289
-
1290
-
1291
-    /**
1292
-     * remove_reg_step
1293
-     * given a valid TXN_reg_step slug, this will remove (unset)
1294
-     * the reg step from the TXN reg step array
1295
-     *
1296
-     * @param string $reg_step_slug
1297
-     * @return void
1298
-     * @throws EE_Error
1299
-     */
1300
-    public function remove_reg_step($reg_step_slug)
1301
-    {
1302
-        // get reg steps array
1303
-        $txn_reg_steps = $this->reg_steps();
1304
-        unset($txn_reg_steps[ $reg_step_slug ]);
1305
-        $this->set_reg_steps($txn_reg_steps);
1306
-    }
1307
-
1308
-
1309
-    /**
1310
-     * toggle_failed_transaction_status
1311
-     * upgrades a TXNs status from failed to abandoned,
1312
-     * meaning that contact information has been captured for at least one registrant
1313
-     *
1314
-     * @param bool $save
1315
-     * @return bool
1316
-     * @throws EE_Error
1317
-     */
1318
-    public function toggle_failed_transaction_status($save = true)
1319
-    {
1320
-        // if TXN status is still set as "failed"...
1321
-        if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1322
-            $this->set_status(EEM_Transaction::abandoned_status_code);
1323
-            if ($save) {
1324
-                $this->save();
1325
-            }
1326
-            return true;
1327
-        }
1328
-        return false;
1329
-    }
1330
-
1331
-
1332
-    /**
1333
-     * toggle_abandoned_transaction_status
1334
-     * upgrades a TXNs status from failed or abandoned to incomplete
1335
-     *
1336
-     * @return bool
1337
-     * @throws EE_Error
1338
-     */
1339
-    public function toggle_abandoned_transaction_status()
1340
-    {
1341
-        // if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1342
-        $txn_status = $this->status_ID();
1343
-        if ($txn_status === EEM_Transaction::failed_status_code
1344
-            || $txn_status === EEM_Transaction::abandoned_status_code
1345
-        ) {
1346
-            // if a contact record for the primary registrant has been created
1347
-            if ($this->primary_registration() instanceof EE_Registration
1348
-                && $this->primary_registration()->attendee() instanceof EE_Attendee
1349
-            ) {
1350
-                $this->set_status(EEM_Transaction::incomplete_status_code);
1351
-            } else {
1352
-                // no contact record? yer abandoned!
1353
-                $this->set_status(EEM_Transaction::abandoned_status_code);
1354
-            }
1355
-            return true;
1356
-        }
1357
-        return false;
1358
-    }
1359
-
1360
-
1361
-    /**
1362
-     * checks if an Abandoned TXN has any related payments, and if so,
1363
-     * updates the TXN status based on the amount paid
1364
-     *
1365
-     * @throws EE_Error
1366
-     * @throws InvalidDataTypeException
1367
-     * @throws InvalidInterfaceException
1368
-     * @throws InvalidArgumentException
1369
-     * @throws RuntimeException
1370
-     */
1371
-    public function verify_abandoned_transaction_status()
1372
-    {
1373
-        if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1374
-            return;
1375
-        }
1376
-        $payments = $this->get_many_related('Payment');
1377
-        if (! empty($payments)) {
1378
-            foreach ($payments as $payment) {
1379
-                if ($payment instanceof EE_Payment) {
1380
-                    // kk this TXN should NOT be abandoned
1381
-                    $this->update_status_based_on_total_paid();
1382
-                    if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1383
-                        EE_Error::add_attention(
1384
-                            sprintf(
1385
-                                esc_html__(
1386
-                                    '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.',
1387
-                                    'event_espresso'
1388
-                                ),
1389
-                                $this->ID(),
1390
-                                $this->pretty_status()
1391
-                            )
1392
-                        );
1393
-                    }
1394
-                    // get final reg step status
1395
-                    $finalized = $this->final_reg_step_completed();
1396
-                    // if the 'finalize_registration' step has been initiated (has a timestamp)
1397
-                    // but has not yet been fully completed (TRUE)
1398
-                    if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1399
-                        $this->set_reg_step_completed('finalize_registration');
1400
-                        $this->save();
1401
-                    }
1402
-                }
1403
-            }
1404
-        }
1405
-    }
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
+	 */
39
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
40
+	{
41
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
42
+		$txn = $has_object
43
+			? $has_object
44
+			: new self($props_n_values, false, $timezone, $date_formats);
45
+		if (! $has_object) {
46
+			$txn->set_old_txn_status($txn->status_ID());
47
+		}
48
+		return $txn;
49
+	}
50
+
51
+
52
+	/**
53
+	 * @param array  $props_n_values  incoming values from the database
54
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
55
+	 *                                the website will be used.
56
+	 * @return EE_Transaction
57
+	 * @throws EE_Error
58
+	 */
59
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
60
+	{
61
+		$txn = new self($props_n_values, true, $timezone);
62
+		$txn->set_old_txn_status($txn->status_ID());
63
+		return $txn;
64
+	}
65
+
66
+
67
+	/**
68
+	 * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
69
+	 * If a lock has already been set, then we will attempt to remove it in case it has expired.
70
+	 * If that also fails, then an exception is thrown.
71
+	 *
72
+	 * @throws EE_Error
73
+	 */
74
+	public function lock()
75
+	{
76
+		// attempt to set lock, but if that fails...
77
+		if (! $this->add_extra_meta('lock', time(), true)) {
78
+			// then attempt to remove the lock in case it is expired
79
+			if ($this->_remove_expired_lock()) {
80
+				// if removal was successful, then try setting lock again
81
+				$this->lock();
82
+			} else {
83
+				// but if the lock can not be removed, then throw an exception
84
+				throw new EE_Error(
85
+					sprintf(
86
+						__(
87
+							'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.',
88
+							'event_espresso'
89
+						),
90
+						$this->ID()
91
+					)
92
+				);
93
+			}
94
+		}
95
+	}
96
+
97
+
98
+	/**
99
+	 * removes transaction lock applied in EE_Transaction::lock()
100
+	 *
101
+	 * @return int
102
+	 * @throws EE_Error
103
+	 */
104
+	public function unlock()
105
+	{
106
+		return $this->delete_extra_meta('lock');
107
+	}
108
+
109
+
110
+	/**
111
+	 * Decides whether or not now is the right time to update the transaction.
112
+	 * This is useful because we don't always know if it is safe to update the transaction
113
+	 * and its related data. why?
114
+	 * because it's possible that the transaction is being used in another
115
+	 * request and could overwrite anything we save.
116
+	 * So we want to only update the txn once we know that won't happen.
117
+	 * We also check that the lock isn't expired, and remove it if it is
118
+	 *
119
+	 * @return boolean
120
+	 * @throws EE_Error
121
+	 */
122
+	public function is_locked()
123
+	{
124
+		// if TXN is not locked, then return false immediately
125
+		if (! $this->_get_lock()) {
126
+			return false;
127
+		}
128
+		// if not, then let's try and remove the lock in case it's expired...
129
+		// _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
130
+		// and a positive number if the lock was removed (ie: number of locks deleted),
131
+		// so we need to return the opposite
132
+		return ! $this->_remove_expired_lock() ? true : false;
133
+	}
134
+
135
+
136
+	/**
137
+	 * Gets the meta field indicating that this TXN is locked
138
+	 *
139
+	 * @return int
140
+	 * @throws EE_Error
141
+	 */
142
+	protected function _get_lock()
143
+	{
144
+		return (int) $this->get_extra_meta('lock', true, 0);
145
+	}
146
+
147
+
148
+	/**
149
+	 * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
150
+	 *
151
+	 * @return int
152
+	 * @throws EE_Error
153
+	 */
154
+	protected function _remove_expired_lock()
155
+	{
156
+		$locked = $this->_get_lock();
157
+		if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
158
+			return $this->unlock();
159
+		}
160
+		return 0;
161
+	}
162
+
163
+
164
+	/**
165
+	 * Set transaction total
166
+	 *
167
+	 * @param float $total total value of transaction
168
+	 * @throws EE_Error
169
+	 */
170
+	public function set_total($total = 0.00)
171
+	{
172
+		$this->set('TXN_total', (float) $total);
173
+	}
174
+
175
+
176
+	/**
177
+	 * Set Total Amount Paid to Date
178
+	 *
179
+	 * @param float $total_paid total amount paid to date (sum of all payments)
180
+	 * @throws EE_Error
181
+	 */
182
+	public function set_paid($total_paid = 0.00)
183
+	{
184
+		$this->set('TXN_paid', (float) $total_paid);
185
+	}
186
+
187
+
188
+	/**
189
+	 * Set transaction status
190
+	 *
191
+	 * @param string $status        whether the transaction is open, declined, accepted,
192
+	 *                              or any number of custom values that can be set
193
+	 * @throws EE_Error
194
+	 */
195
+	public function set_status($status = '')
196
+	{
197
+		$this->set('STS_ID', $status);
198
+	}
199
+
200
+
201
+	/**
202
+	 * Set hash salt
203
+	 *
204
+	 * @param string $hash_salt required for some payment gateways
205
+	 * @throws EE_Error
206
+	 */
207
+	public function set_hash_salt($hash_salt = '')
208
+	{
209
+		$this->set('TXN_hash_salt', $hash_salt);
210
+	}
211
+
212
+
213
+	/**
214
+	 * Sets TXN_reg_steps array
215
+	 *
216
+	 * @param array $txn_reg_steps
217
+	 * @throws EE_Error
218
+	 */
219
+	public function set_reg_steps(array $txn_reg_steps)
220
+	{
221
+		$this->set('TXN_reg_steps', $txn_reg_steps);
222
+	}
223
+
224
+
225
+	/**
226
+	 * Gets TXN_reg_steps
227
+	 *
228
+	 * @return array
229
+	 * @throws EE_Error
230
+	 */
231
+	public function reg_steps()
232
+	{
233
+		$TXN_reg_steps = $this->get('TXN_reg_steps');
234
+		return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array();
235
+	}
236
+
237
+
238
+	/**
239
+	 * @return string of transaction's total cost, with currency symbol and decimal
240
+	 * @throws EE_Error
241
+	 */
242
+	public function pretty_total()
243
+	{
244
+		return $this->get_pretty('TXN_total');
245
+	}
246
+
247
+
248
+	/**
249
+	 * Gets the amount paid in a pretty string (formatted and with currency symbol)
250
+	 *
251
+	 * @return string
252
+	 * @throws EE_Error
253
+	 */
254
+	public function pretty_paid()
255
+	{
256
+		return $this->get_pretty('TXN_paid');
257
+	}
258
+
259
+
260
+	/**
261
+	 * calculate the amount remaining for this transaction and return;
262
+	 *
263
+	 * @return float amount remaining
264
+	 * @throws EE_Error
265
+	 */
266
+	public function remaining()
267
+	{
268
+		return $this->total() - $this->paid();
269
+	}
270
+
271
+
272
+	/**
273
+	 * get Transaction Total
274
+	 *
275
+	 * @return float
276
+	 * @throws EE_Error
277
+	 */
278
+	public function total()
279
+	{
280
+		return (float) $this->get('TXN_total');
281
+	}
282
+
283
+
284
+	/**
285
+	 * get Total Amount Paid to Date
286
+	 *
287
+	 * @return float
288
+	 * @throws EE_Error
289
+	 */
290
+	public function paid()
291
+	{
292
+		return (float) $this->get('TXN_paid');
293
+	}
294
+
295
+
296
+	/**
297
+	 * @throws EE_Error
298
+	 */
299
+	public function get_cart_session()
300
+	{
301
+		$session_data = (array) $this->get('TXN_session_data');
302
+		return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
303
+			? $session_data['cart']
304
+			: null;
305
+	}
306
+
307
+
308
+	/**
309
+	 * get Transaction session data
310
+	 *
311
+	 * @throws EE_Error
312
+	 */
313
+	public function session_data()
314
+	{
315
+		$session_data = $this->get('TXN_session_data');
316
+		if (empty($session_data)) {
317
+			$session_data = array(
318
+				'id'            => null,
319
+				'user_id'       => null,
320
+				'ip_address'    => null,
321
+				'user_agent'    => null,
322
+				'init_access'   => null,
323
+				'last_access'   => null,
324
+				'pages_visited' => array(),
325
+			);
326
+		}
327
+		return $session_data;
328
+	}
329
+
330
+
331
+	/**
332
+	 * Set session data within the TXN object
333
+	 *
334
+	 * @param EE_Session|array $session_data
335
+	 * @throws EE_Error
336
+	 */
337
+	public function set_txn_session_data($session_data)
338
+	{
339
+		if ($session_data instanceof EE_Session) {
340
+			$this->set('TXN_session_data', $session_data->get_session_data(null, true));
341
+		} else {
342
+			$this->set('TXN_session_data', $session_data);
343
+		}
344
+	}
345
+
346
+
347
+	/**
348
+	 * get Transaction hash salt
349
+	 *
350
+	 * @throws EE_Error
351
+	 */
352
+	public function hash_salt_()
353
+	{
354
+		return $this->get('TXN_hash_salt');
355
+	}
356
+
357
+
358
+	/**
359
+	 * Returns the transaction datetime as either:
360
+	 *            - unix timestamp format ($format = false, $gmt = true)
361
+	 *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
362
+	 *              has no affect with this option)), this also may include a timezone abbreviation if the
363
+	 *              set timezone in this class differs from what the timezone is on the blog.
364
+	 *            - formatted date string including the UTC (timezone) offset (default).
365
+	 *
366
+	 * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
367
+	 * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
368
+	 *                          or no UTC offset applied
369
+	 * @return string | int
370
+	 * @throws EE_Error
371
+	 */
372
+	public function datetime($format = false, $gmt = false)
373
+	{
374
+		if ($format) {
375
+			return $this->get_pretty('TXN_timestamp');
376
+		}
377
+		if ($gmt) {
378
+			return $this->get_raw('TXN_timestamp');
379
+		}
380
+		return $this->get('TXN_timestamp');
381
+	}
382
+
383
+
384
+	/**
385
+	 * Gets registrations on this transaction
386
+	 *
387
+	 * @param array   $query_params array of query parameters
388
+	 * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
389
+	 * @return EE_Base_Class[]|EE_Registration[]
390
+	 * @throws EE_Error
391
+	 */
392
+	public function registrations($query_params = array(), $get_cached = false)
393
+	{
394
+		$query_params = (empty($query_params) || ! is_array($query_params))
395
+			? array(
396
+				'order_by' => array(
397
+					'Event.EVT_name'     => 'ASC',
398
+					'Attendee.ATT_lname' => 'ASC',
399
+					'Attendee.ATT_fname' => 'ASC',
400
+				),
401
+			)
402
+			: $query_params;
403
+		$query_params = $get_cached ? array() : $query_params;
404
+		return $this->get_many_related('Registration', $query_params);
405
+	}
406
+
407
+
408
+	/**
409
+	 * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
410
+	 * function for getting attendees and how many registrations they each have for an event)
411
+	 *
412
+	 * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
413
+	 * @throws EE_Error
414
+	 */
415
+	public function attendees()
416
+	{
417
+		return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID())));
418
+	}
419
+
420
+
421
+	/**
422
+	 * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
423
+	 *
424
+	 * @param array $query_params like EEM_Base::get_all
425
+	 * @return EE_Base_Class[]|EE_Payment[]
426
+	 * @throws EE_Error
427
+	 */
428
+	public function payments($query_params = array())
429
+	{
430
+		return $this->get_many_related('Payment', $query_params);
431
+	}
432
+
433
+
434
+	/**
435
+	 * gets only approved payments for this transaction
436
+	 *
437
+	 * @return EE_Base_Class[]|EE_Payment[]
438
+	 * @throws EE_Error
439
+	 * @throws InvalidArgumentException
440
+	 * @throws ReflectionException
441
+	 * @throws InvalidDataTypeException
442
+	 * @throws InvalidInterfaceException
443
+	 */
444
+	public function approved_payments()
445
+	{
446
+		EE_Registry::instance()->load_model('Payment');
447
+		return $this->get_many_related(
448
+			'Payment',
449
+			array(
450
+				array('STS_ID' => EEM_Payment::status_id_approved),
451
+				'order_by' => array('PAY_timestamp' => 'DESC'),
452
+			)
453
+		);
454
+	}
455
+
456
+
457
+	/**
458
+	 * Gets all payments which have not been approved
459
+	 *
460
+	 * @return EE_Base_Class[]|EEI_Payment[]
461
+	 * @throws EE_Error if a model is misconfigured somehow
462
+	 */
463
+	public function pending_payments()
464
+	{
465
+		return $this->get_many_related(
466
+			'Payment',
467
+			array(
468
+				array(
469
+					'STS_ID' => EEM_Payment::status_id_pending,
470
+				),
471
+				'order_by' => array(
472
+					'PAY_timestamp' => 'DESC',
473
+				),
474
+			)
475
+		);
476
+	}
477
+
478
+
479
+	/**
480
+	 * echoes $this->pretty_status()
481
+	 *
482
+	 * @param bool $show_icons
483
+	 * @throws EE_Error
484
+	 * @throws InvalidArgumentException
485
+	 * @throws InvalidDataTypeException
486
+	 * @throws InvalidInterfaceException
487
+	 */
488
+	public function e_pretty_status($show_icons = false)
489
+	{
490
+		echo $this->pretty_status($show_icons);
491
+	}
492
+
493
+
494
+	/**
495
+	 * returns a pretty version of the status, good for displaying to users
496
+	 *
497
+	 * @param bool $show_icons
498
+	 * @return string
499
+	 * @throws EE_Error
500
+	 * @throws InvalidArgumentException
501
+	 * @throws InvalidDataTypeException
502
+	 * @throws InvalidInterfaceException
503
+	 */
504
+	public function pretty_status($show_icons = false)
505
+	{
506
+		$status = EEM_Status::instance()->localized_status(
507
+			array($this->status_ID() => __('unknown', 'event_espresso')),
508
+			false,
509
+			'sentence'
510
+		);
511
+		$icon = '';
512
+		switch ($this->status_ID()) {
513
+			case EEM_Transaction::complete_status_code:
514
+				$icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
515
+				break;
516
+			case EEM_Transaction::incomplete_status_code:
517
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
518
+					: '';
519
+				break;
520
+			case EEM_Transaction::abandoned_status_code:
521
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
522
+				break;
523
+			case EEM_Transaction::failed_status_code:
524
+				$icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
525
+				break;
526
+			case EEM_Transaction::overpaid_status_code:
527
+				$icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
528
+				break;
529
+		}
530
+		return $icon . $status[ $this->status_ID() ];
531
+	}
532
+
533
+
534
+	/**
535
+	 * get Transaction Status
536
+	 *
537
+	 * @throws EE_Error
538
+	 */
539
+	public function status_ID()
540
+	{
541
+		return $this->get('STS_ID');
542
+	}
543
+
544
+
545
+	/**
546
+	 * Returns TRUE or FALSE for whether or not this transaction cost any money
547
+	 *
548
+	 * @return boolean
549
+	 * @throws EE_Error
550
+	 */
551
+	public function is_free()
552
+	{
553
+		return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
554
+	}
555
+
556
+
557
+	/**
558
+	 * Returns whether this transaction is complete
559
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
560
+	 *
561
+	 * @return boolean
562
+	 * @throws EE_Error
563
+	 */
564
+	public function is_completed()
565
+	{
566
+		return $this->status_ID() === EEM_Transaction::complete_status_code;
567
+	}
568
+
569
+
570
+	/**
571
+	 * Returns whether this transaction is incomplete
572
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
573
+	 *
574
+	 * @return boolean
575
+	 * @throws EE_Error
576
+	 */
577
+	public function is_incomplete()
578
+	{
579
+		return $this->status_ID() === EEM_Transaction::incomplete_status_code;
580
+	}
581
+
582
+
583
+	/**
584
+	 * Returns whether this transaction is overpaid
585
+	 * Useful in templates and other logic for deciding if monies need to be refunded
586
+	 *
587
+	 * @return boolean
588
+	 * @throws EE_Error
589
+	 */
590
+	public function is_overpaid()
591
+	{
592
+		return $this->status_ID() === EEM_Transaction::overpaid_status_code;
593
+	}
594
+
595
+
596
+	/**
597
+	 * Returns whether this transaction was abandoned
598
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
599
+	 * but that contact information exists for at least one registrant
600
+	 *
601
+	 * @return boolean
602
+	 * @throws EE_Error
603
+	 */
604
+	public function is_abandoned()
605
+	{
606
+		return $this->status_ID() === EEM_Transaction::abandoned_status_code;
607
+	}
608
+
609
+
610
+	/**
611
+	 * Returns whether this transaction failed
612
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
613
+	 * and that NO contact information exists for any registrants
614
+	 *
615
+	 * @return boolean
616
+	 * @throws EE_Error
617
+	 */
618
+	public function failed()
619
+	{
620
+		return $this->status_ID() === EEM_Transaction::failed_status_code;
621
+	}
622
+
623
+
624
+	/**
625
+	 * This returns the url for the invoice of this transaction
626
+	 *
627
+	 * @param string $type 'html' or 'pdf' (default is pdf)
628
+	 * @return string
629
+	 * @throws EE_Error
630
+	 */
631
+	public function invoice_url($type = 'html')
632
+	{
633
+		$REG = $this->primary_registration();
634
+		if (! $REG instanceof EE_Registration) {
635
+			return '';
636
+		}
637
+		return $REG->invoice_url($type);
638
+	}
639
+
640
+
641
+	/**
642
+	 * Gets the primary registration only
643
+	 *
644
+	 * @return EE_Base_Class|EE_Registration
645
+	 * @throws EE_Error
646
+	 */
647
+	public function primary_registration()
648
+	{
649
+		$registrations = (array) $this->get_many_related(
650
+			'Registration',
651
+			array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT))
652
+		);
653
+		foreach ($registrations as $registration) {
654
+			// valid registration that is NOT cancelled or declined ?
655
+			if ($registration instanceof EE_Registration
656
+				&& ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
657
+			) {
658
+				return $registration;
659
+			}
660
+		}
661
+		// nothing valid found, so just return first thing from array of results
662
+		return reset($registrations);
663
+	}
664
+
665
+
666
+	/**
667
+	 * Gets the URL for viewing the receipt
668
+	 *
669
+	 * @param string $type 'pdf' or 'html' (default is 'html')
670
+	 * @return string
671
+	 * @throws EE_Error
672
+	 */
673
+	public function receipt_url($type = 'html')
674
+	{
675
+		$REG = $this->primary_registration();
676
+		if (! $REG instanceof EE_Registration) {
677
+			return '';
678
+		}
679
+		return $REG->receipt_url($type);
680
+	}
681
+
682
+
683
+	/**
684
+	 * Gets the URL of the thank you page with this registration REG_url_link added as
685
+	 * a query parameter
686
+	 *
687
+	 * @return string
688
+	 * @throws EE_Error
689
+	 */
690
+	public function payment_overview_url()
691
+	{
692
+		$primary_registration = $this->primary_registration();
693
+		return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
694
+	}
695
+
696
+
697
+	/**
698
+	 * @return string
699
+	 * @throws EE_Error
700
+	 */
701
+	public function gateway_response_on_transaction()
702
+	{
703
+		$payment = $this->get_first_related('Payment');
704
+		return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
705
+	}
706
+
707
+
708
+	/**
709
+	 * Get the status object of this object
710
+	 *
711
+	 * @return EE_Base_Class|EE_Status
712
+	 * @throws EE_Error
713
+	 */
714
+	public function status_obj()
715
+	{
716
+		return $this->get_first_related('Status');
717
+	}
718
+
719
+
720
+	/**
721
+	 * Gets all the extra meta info on this payment
722
+	 *
723
+	 * @param array $query_params like EEM_Base::get_all
724
+	 * @return EE_Base_Class[]|EE_Extra_Meta
725
+	 * @throws EE_Error
726
+	 */
727
+	public function extra_meta($query_params = array())
728
+	{
729
+		return $this->get_many_related('Extra_Meta', $query_params);
730
+	}
731
+
732
+
733
+	/**
734
+	 * Wrapper for _add_relation_to
735
+	 *
736
+	 * @param EE_Registration $registration
737
+	 * @return EE_Base_Class the relation was added to
738
+	 * @throws EE_Error
739
+	 */
740
+	public function add_registration(EE_Registration $registration)
741
+	{
742
+		return $this->_add_relation_to($registration, 'Registration');
743
+	}
744
+
745
+
746
+	/**
747
+	 * Removes the given registration from being related (even before saving this transaction).
748
+	 * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
749
+	 *
750
+	 * @param int $registration_or_id
751
+	 * @return EE_Base_Class that was removed from being related
752
+	 * @throws EE_Error
753
+	 */
754
+	public function remove_registration_with_id($registration_or_id)
755
+	{
756
+		return $this->_remove_relation_to($registration_or_id, 'Registration');
757
+	}
758
+
759
+
760
+	/**
761
+	 * Gets all the line items which are for ACTUAL items
762
+	 *
763
+	 * @return EE_Line_Item[]
764
+	 * @throws EE_Error
765
+	 */
766
+	public function items_purchased()
767
+	{
768
+		return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item)));
769
+	}
770
+
771
+
772
+	/**
773
+	 * Wrapper for _add_relation_to
774
+	 *
775
+	 * @param EE_Line_Item $line_item
776
+	 * @return EE_Base_Class the relation was added to
777
+	 * @throws EE_Error
778
+	 */
779
+	public function add_line_item(EE_Line_Item $line_item)
780
+	{
781
+		return $this->_add_relation_to($line_item, 'Line_Item');
782
+	}
783
+
784
+
785
+	/**
786
+	 * Gets ALL the line items related to this transaction (unstructured)
787
+	 *
788
+	 * @param array $query_params
789
+	 * @return EE_Base_Class[]|EE_Line_Item[]
790
+	 * @throws EE_Error
791
+	 */
792
+	public function line_items($query_params = array())
793
+	{
794
+		return $this->get_many_related('Line_Item', $query_params);
795
+	}
796
+
797
+
798
+	/**
799
+	 * Gets all the line items which are taxes on the total
800
+	 *
801
+	 * @return EE_Line_Item[]
802
+	 * @throws EE_Error
803
+	 */
804
+	public function tax_items()
805
+	{
806
+		return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax)));
807
+	}
808
+
809
+
810
+	/**
811
+	 * Gets the total line item (which is a parent of all other related line items,
812
+	 * meaning it takes them all into account on its total)
813
+	 *
814
+	 * @param bool $create_if_not_found
815
+	 * @return \EE_Line_Item
816
+	 * @throws EE_Error
817
+	 */
818
+	public function total_line_item($create_if_not_found = true)
819
+	{
820
+		$item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
821
+		if (! $item && $create_if_not_found) {
822
+			$item = EEH_Line_Item::create_total_line_item($this);
823
+		}
824
+		return $item;
825
+	}
826
+
827
+
828
+	/**
829
+	 * Returns the total amount of tax on this transaction
830
+	 * (assumes there's only one tax subtotal line item)
831
+	 *
832
+	 * @return float
833
+	 * @throws EE_Error
834
+	 */
835
+	public function tax_total()
836
+	{
837
+		$tax_line_item = $this->tax_total_line_item();
838
+		if ($tax_line_item) {
839
+			return (float) $tax_line_item->total();
840
+		}
841
+		return (float) 0;
842
+	}
843
+
844
+
845
+	/**
846
+	 * Gets the tax subtotal line item (assumes there's only one)
847
+	 *
848
+	 * @return EE_Line_Item
849
+	 * @throws EE_Error
850
+	 */
851
+	public function tax_total_line_item()
852
+	{
853
+		return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
854
+	}
855
+
856
+
857
+	/**
858
+	 * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
859
+	 *
860
+	 * @return EE_Form_Section_Proper
861
+	 * @throws EE_Error
862
+	 */
863
+	public function billing_info()
864
+	{
865
+		$payment_method = $this->payment_method();
866
+		if (! $payment_method) {
867
+			EE_Error::add_error(
868
+				__(
869
+					'Could not find billing info for transaction because no gateway has been used for it yet',
870
+					'event_espresso'
871
+				),
872
+				__FILE__,
873
+				__FUNCTION__,
874
+				__LINE__
875
+			);
876
+			return null;
877
+		}
878
+		$primary_reg = $this->primary_registration();
879
+		if (! $primary_reg) {
880
+			EE_Error::add_error(
881
+				__(
882
+					'Cannot get billing info for gateway %s on transaction because no primary registration exists',
883
+					'event_espresso'
884
+				),
885
+				__FILE__,
886
+				__FUNCTION__,
887
+				__LINE__
888
+			);
889
+			return null;
890
+		}
891
+		$attendee = $primary_reg->attendee();
892
+		if (! $attendee) {
893
+			EE_Error::add_error(
894
+				__(
895
+					'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
896
+					'event_espresso'
897
+				),
898
+				__FILE__,
899
+				__FUNCTION__,
900
+				__LINE__
901
+			);
902
+			return null;
903
+		}
904
+		return $attendee->billing_info_for_payment_method($payment_method);
905
+	}
906
+
907
+
908
+	/**
909
+	 * Gets PMD_ID
910
+	 *
911
+	 * @return int
912
+	 * @throws EE_Error
913
+	 */
914
+	public function payment_method_ID()
915
+	{
916
+		return $this->get('PMD_ID');
917
+	}
918
+
919
+
920
+	/**
921
+	 * Sets PMD_ID
922
+	 *
923
+	 * @param int $PMD_ID
924
+	 * @throws EE_Error
925
+	 */
926
+	public function set_payment_method_ID($PMD_ID)
927
+	{
928
+		$this->set('PMD_ID', $PMD_ID);
929
+	}
930
+
931
+
932
+	/**
933
+	 * Gets the last-used payment method on this transaction
934
+	 * (we COULD just use the last-made payment, but some payment methods, namely
935
+	 * offline ones, dont' create payments)
936
+	 *
937
+	 * @return EE_Payment_Method
938
+	 * @throws EE_Error
939
+	 */
940
+	public function payment_method()
941
+	{
942
+		$pm = $this->get_first_related('Payment_Method');
943
+		if ($pm instanceof EE_Payment_Method) {
944
+			return $pm;
945
+		}
946
+		$last_payment = $this->last_payment();
947
+		if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
948
+			return $last_payment->payment_method();
949
+		}
950
+		return null;
951
+	}
952
+
953
+
954
+	/**
955
+	 * Gets the last payment made
956
+	 *
957
+	 * @return EE_Base_Class|EE_Payment
958
+	 * @throws EE_Error
959
+	 */
960
+	public function last_payment()
961
+	{
962
+		return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc')));
963
+	}
964
+
965
+
966
+	/**
967
+	 * Gets all the line items which are unrelated to tickets on this transaction
968
+	 *
969
+	 * @return EE_Line_Item[]
970
+	 * @throws EE_Error
971
+	 * @throws InvalidArgumentException
972
+	 * @throws InvalidDataTypeException
973
+	 * @throws InvalidInterfaceException
974
+	 */
975
+	public function non_ticket_line_items()
976
+	{
977
+		return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
978
+	}
979
+
980
+
981
+	/**
982
+	 * possibly toggles TXN status
983
+	 *
984
+	 * @param  boolean $update whether to save the TXN
985
+	 * @return bool whether the TXN was saved
986
+	 * @throws EE_Error
987
+	 * @throws RuntimeException
988
+	 */
989
+	public function update_status_based_on_total_paid($update = true)
990
+	{
991
+		// set transaction status based on comparison of TXN_paid vs TXN_total
992
+		if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
993
+			$new_txn_status = EEM_Transaction::overpaid_status_code;
994
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
995
+			$new_txn_status = EEM_Transaction::complete_status_code;
996
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
997
+			$new_txn_status = EEM_Transaction::incomplete_status_code;
998
+		} else {
999
+			throw new RuntimeException(
1000
+				__('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1001
+			);
1002
+		}
1003
+		if ($new_txn_status !== $this->status_ID()) {
1004
+			$this->set_status($new_txn_status);
1005
+			if ($update) {
1006
+				return $this->save() ? true : false;
1007
+			}
1008
+		}
1009
+		return false;
1010
+	}
1011
+
1012
+
1013
+	/**
1014
+	 * Updates the transaction's status and total_paid based on all the payments
1015
+	 * that apply to it
1016
+	 *
1017
+	 * @deprecated
1018
+	 * @return array|bool
1019
+	 * @throws EE_Error
1020
+	 * @throws InvalidArgumentException
1021
+	 * @throws ReflectionException
1022
+	 * @throws InvalidDataTypeException
1023
+	 * @throws InvalidInterfaceException
1024
+	 */
1025
+	public function update_based_on_payments()
1026
+	{
1027
+		EE_Error::doing_it_wrong(
1028
+			__CLASS__ . '::' . __FUNCTION__,
1029
+			sprintf(
1030
+				__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1031
+				'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1032
+			),
1033
+			'4.6.0'
1034
+		);
1035
+		/** @type EE_Transaction_Processor $transaction_processor */
1036
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1037
+		return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1038
+	}
1039
+
1040
+
1041
+	/**
1042
+	 * @return string
1043
+	 */
1044
+	public function old_txn_status()
1045
+	{
1046
+		return $this->_old_txn_status;
1047
+	}
1048
+
1049
+
1050
+	/**
1051
+	 * @param string $old_txn_status
1052
+	 */
1053
+	public function set_old_txn_status($old_txn_status)
1054
+	{
1055
+		// only set the first time
1056
+		if ($this->_old_txn_status === null) {
1057
+			$this->_old_txn_status = $old_txn_status;
1058
+		}
1059
+	}
1060
+
1061
+
1062
+	/**
1063
+	 * reg_status_updated
1064
+	 *
1065
+	 * @return bool
1066
+	 * @throws EE_Error
1067
+	 */
1068
+	public function txn_status_updated()
1069
+	{
1070
+		return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1071
+	}
1072
+
1073
+
1074
+	/**
1075
+	 * _reg_steps_completed
1076
+	 * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1077
+	 * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1078
+	 * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1079
+	 *
1080
+	 * @param string $reg_step_slug
1081
+	 * @param bool   $check_all
1082
+	 * @return bool|int
1083
+	 * @throws EE_Error
1084
+	 */
1085
+	private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1086
+	{
1087
+		$reg_steps = $this->reg_steps();
1088
+		if (! is_array($reg_steps) || empty($reg_steps)) {
1089
+			return false;
1090
+		}
1091
+		// loop thru reg steps array)
1092
+		foreach ($reg_steps as $slug => $reg_step_completed) {
1093
+			// if NOT checking ALL steps (only checking one step)
1094
+			if (! $check_all) {
1095
+				// and this is the one
1096
+				if ($slug === $reg_step_slug) {
1097
+					return $reg_step_completed;
1098
+				}
1099
+				// skip to next reg step in loop
1100
+				continue;
1101
+			}
1102
+			// $check_all must be true, else we would never have gotten to this point
1103
+			if ($slug === $reg_step_slug) {
1104
+				// if we reach this point, then we are testing either:
1105
+				// all_reg_steps_completed_except() or
1106
+				// all_reg_steps_completed_except_final_step(),
1107
+				// and since this is the reg step EXCEPTION being tested
1108
+				// we want to return true (yes true) if this reg step is NOT completed
1109
+				// ie: "is everything completed except the final step?"
1110
+				// "that is correct... the final step is not completed, but all others are."
1111
+				return $reg_step_completed !== true;
1112
+			}
1113
+			if ($reg_step_completed !== true) {
1114
+				// if any reg step is NOT completed, then ALL steps are not completed
1115
+				return false;
1116
+			}
1117
+		}
1118
+		return true;
1119
+	}
1120
+
1121
+
1122
+	/**
1123
+	 * all_reg_steps_completed
1124
+	 * returns:
1125
+	 *    true if ALL reg steps have been marked as completed
1126
+	 *        or false if any step is not completed
1127
+	 *
1128
+	 * @return bool
1129
+	 * @throws EE_Error
1130
+	 */
1131
+	public function all_reg_steps_completed()
1132
+	{
1133
+		return $this->_reg_steps_completed();
1134
+	}
1135
+
1136
+
1137
+	/**
1138
+	 * all_reg_steps_completed_except
1139
+	 * returns:
1140
+	 *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1141
+	 *        or false if any other step is not completed
1142
+	 *        or false if ALL steps are completed including the exception you are testing !!!
1143
+	 *
1144
+	 * @param string $exception
1145
+	 * @return bool
1146
+	 * @throws EE_Error
1147
+	 */
1148
+	public function all_reg_steps_completed_except($exception = '')
1149
+	{
1150
+		return $this->_reg_steps_completed($exception);
1151
+	}
1152
+
1153
+
1154
+	/**
1155
+	 * all_reg_steps_completed_except
1156
+	 * returns:
1157
+	 *        true if ALL reg steps, except the final step, have been marked as completed
1158
+	 *        or false if any step is not completed
1159
+	 *    or false if ALL steps are completed including the final step !!!
1160
+	 *
1161
+	 * @return bool
1162
+	 * @throws EE_Error
1163
+	 */
1164
+	public function all_reg_steps_completed_except_final_step()
1165
+	{
1166
+		return $this->_reg_steps_completed('finalize_registration');
1167
+	}
1168
+
1169
+
1170
+	/**
1171
+	 * reg_step_completed
1172
+	 * returns:
1173
+	 *    true if a specific reg step has been marked as completed
1174
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1175
+	 *    or false if it has not yet been initialized
1176
+	 *
1177
+	 * @param string $reg_step_slug
1178
+	 * @return bool|int
1179
+	 * @throws EE_Error
1180
+	 */
1181
+	public function reg_step_completed($reg_step_slug)
1182
+	{
1183
+		return $this->_reg_steps_completed($reg_step_slug, false);
1184
+	}
1185
+
1186
+
1187
+	/**
1188
+	 * completed_final_reg_step
1189
+	 * returns:
1190
+	 *    true if the finalize_registration reg step has been marked as completed
1191
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1192
+	 *    or false if it has not yet been initialized
1193
+	 *
1194
+	 * @return bool|int
1195
+	 * @throws EE_Error
1196
+	 */
1197
+	public function final_reg_step_completed()
1198
+	{
1199
+		return $this->_reg_steps_completed('finalize_registration', false);
1200
+	}
1201
+
1202
+
1203
+	/**
1204
+	 * set_reg_step_initiated
1205
+	 * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1206
+	 *
1207
+	 * @param string $reg_step_slug
1208
+	 * @return boolean
1209
+	 * @throws EE_Error
1210
+	 */
1211
+	public function set_reg_step_initiated($reg_step_slug)
1212
+	{
1213
+		return $this->_set_reg_step_completed_status($reg_step_slug, time());
1214
+	}
1215
+
1216
+
1217
+	/**
1218
+	 * set_reg_step_completed
1219
+	 * given a valid TXN_reg_step, this sets the step as completed
1220
+	 *
1221
+	 * @param string $reg_step_slug
1222
+	 * @return boolean
1223
+	 * @throws EE_Error
1224
+	 */
1225
+	public function set_reg_step_completed($reg_step_slug)
1226
+	{
1227
+		return $this->_set_reg_step_completed_status($reg_step_slug, true);
1228
+	}
1229
+
1230
+
1231
+	/**
1232
+	 * set_reg_step_completed
1233
+	 * given a valid TXN_reg_step slug, this sets the step as NOT completed
1234
+	 *
1235
+	 * @param string $reg_step_slug
1236
+	 * @return boolean
1237
+	 * @throws EE_Error
1238
+	 */
1239
+	public function set_reg_step_not_completed($reg_step_slug)
1240
+	{
1241
+		return $this->_set_reg_step_completed_status($reg_step_slug, false);
1242
+	}
1243
+
1244
+
1245
+	/**
1246
+	 * set_reg_step_completed
1247
+	 * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1248
+	 *
1249
+	 * @param  string      $reg_step_slug
1250
+	 * @param  boolean|int $status
1251
+	 * @return boolean
1252
+	 * @throws EE_Error
1253
+	 */
1254
+	private function _set_reg_step_completed_status($reg_step_slug, $status)
1255
+	{
1256
+		// validate status
1257
+		$status = is_bool($status) || is_int($status) ? $status : false;
1258
+		// get reg steps array
1259
+		$txn_reg_steps = $this->reg_steps();
1260
+		// if reg step does NOT exist
1261
+		if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1262
+			return false;
1263
+		}
1264
+		// if  we're trying to complete a step that is already completed
1265
+		if ($txn_reg_steps[ $reg_step_slug ] === true) {
1266
+			return true;
1267
+		}
1268
+		// if  we're trying to complete a step that hasn't even started
1269
+		if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1270
+			return false;
1271
+		}
1272
+		// if current status value matches the incoming value (no change)
1273
+		// type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1274
+		if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1275
+			// this will happen in cases where multiple AJAX requests occur during the same step
1276
+			return true;
1277
+		}
1278
+		// if we're trying to set a start time, but it has already been set...
1279
+		if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1280
+			// skip the update below, but don't return FALSE so that errors won't be displayed
1281
+			return true;
1282
+		}
1283
+		// update completed status
1284
+		$txn_reg_steps[ $reg_step_slug ] = $status;
1285
+		$this->set_reg_steps($txn_reg_steps);
1286
+		$this->save();
1287
+		return true;
1288
+	}
1289
+
1290
+
1291
+	/**
1292
+	 * remove_reg_step
1293
+	 * given a valid TXN_reg_step slug, this will remove (unset)
1294
+	 * the reg step from the TXN reg step array
1295
+	 *
1296
+	 * @param string $reg_step_slug
1297
+	 * @return void
1298
+	 * @throws EE_Error
1299
+	 */
1300
+	public function remove_reg_step($reg_step_slug)
1301
+	{
1302
+		// get reg steps array
1303
+		$txn_reg_steps = $this->reg_steps();
1304
+		unset($txn_reg_steps[ $reg_step_slug ]);
1305
+		$this->set_reg_steps($txn_reg_steps);
1306
+	}
1307
+
1308
+
1309
+	/**
1310
+	 * toggle_failed_transaction_status
1311
+	 * upgrades a TXNs status from failed to abandoned,
1312
+	 * meaning that contact information has been captured for at least one registrant
1313
+	 *
1314
+	 * @param bool $save
1315
+	 * @return bool
1316
+	 * @throws EE_Error
1317
+	 */
1318
+	public function toggle_failed_transaction_status($save = true)
1319
+	{
1320
+		// if TXN status is still set as "failed"...
1321
+		if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1322
+			$this->set_status(EEM_Transaction::abandoned_status_code);
1323
+			if ($save) {
1324
+				$this->save();
1325
+			}
1326
+			return true;
1327
+		}
1328
+		return false;
1329
+	}
1330
+
1331
+
1332
+	/**
1333
+	 * toggle_abandoned_transaction_status
1334
+	 * upgrades a TXNs status from failed or abandoned to incomplete
1335
+	 *
1336
+	 * @return bool
1337
+	 * @throws EE_Error
1338
+	 */
1339
+	public function toggle_abandoned_transaction_status()
1340
+	{
1341
+		// if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1342
+		$txn_status = $this->status_ID();
1343
+		if ($txn_status === EEM_Transaction::failed_status_code
1344
+			|| $txn_status === EEM_Transaction::abandoned_status_code
1345
+		) {
1346
+			// if a contact record for the primary registrant has been created
1347
+			if ($this->primary_registration() instanceof EE_Registration
1348
+				&& $this->primary_registration()->attendee() instanceof EE_Attendee
1349
+			) {
1350
+				$this->set_status(EEM_Transaction::incomplete_status_code);
1351
+			} else {
1352
+				// no contact record? yer abandoned!
1353
+				$this->set_status(EEM_Transaction::abandoned_status_code);
1354
+			}
1355
+			return true;
1356
+		}
1357
+		return false;
1358
+	}
1359
+
1360
+
1361
+	/**
1362
+	 * checks if an Abandoned TXN has any related payments, and if so,
1363
+	 * updates the TXN status based on the amount paid
1364
+	 *
1365
+	 * @throws EE_Error
1366
+	 * @throws InvalidDataTypeException
1367
+	 * @throws InvalidInterfaceException
1368
+	 * @throws InvalidArgumentException
1369
+	 * @throws RuntimeException
1370
+	 */
1371
+	public function verify_abandoned_transaction_status()
1372
+	{
1373
+		if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1374
+			return;
1375
+		}
1376
+		$payments = $this->get_many_related('Payment');
1377
+		if (! empty($payments)) {
1378
+			foreach ($payments as $payment) {
1379
+				if ($payment instanceof EE_Payment) {
1380
+					// kk this TXN should NOT be abandoned
1381
+					$this->update_status_based_on_total_paid();
1382
+					if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1383
+						EE_Error::add_attention(
1384
+							sprintf(
1385
+								esc_html__(
1386
+									'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.',
1387
+									'event_espresso'
1388
+								),
1389
+								$this->ID(),
1390
+								$this->pretty_status()
1391
+							)
1392
+						);
1393
+					}
1394
+					// get final reg step status
1395
+					$finalized = $this->final_reg_step_completed();
1396
+					// if the 'finalize_registration' step has been initiated (has a timestamp)
1397
+					// but has not yet been fully completed (TRUE)
1398
+					if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1399
+						$this->set_reg_step_completed('finalize_registration');
1400
+						$this->save();
1401
+					}
1402
+				}
1403
+			}
1404
+		}
1405
+	}
1406 1406
 }
Please login to merge, or discard this patch.
Spacing   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -42,7 +42,7 @@  discard block
 block discarded – undo
42 42
         $txn = $has_object
43 43
             ? $has_object
44 44
             : new self($props_n_values, false, $timezone, $date_formats);
45
-        if (! $has_object) {
45
+        if ( ! $has_object) {
46 46
             $txn->set_old_txn_status($txn->status_ID());
47 47
         }
48 48
         return $txn;
@@ -74,7 +74,7 @@  discard block
 block discarded – undo
74 74
     public function lock()
75 75
     {
76 76
         // attempt to set lock, but if that fails...
77
-        if (! $this->add_extra_meta('lock', time(), true)) {
77
+        if ( ! $this->add_extra_meta('lock', time(), true)) {
78 78
             // then attempt to remove the lock in case it is expired
79 79
             if ($this->_remove_expired_lock()) {
80 80
                 // if removal was successful, then try setting lock again
@@ -122,7 +122,7 @@  discard block
 block discarded – undo
122 122
     public function is_locked()
123 123
     {
124 124
         // if TXN is not locked, then return false immediately
125
-        if (! $this->_get_lock()) {
125
+        if ( ! $this->_get_lock()) {
126 126
             return false;
127 127
         }
128 128
         // if not, then let's try and remove the lock in case it's expired...
@@ -527,7 +527,7 @@  discard block
 block discarded – undo
527 527
                 $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
528 528
                 break;
529 529
         }
530
-        return $icon . $status[ $this->status_ID() ];
530
+        return $icon.$status[$this->status_ID()];
531 531
     }
532 532
 
533 533
 
@@ -631,7 +631,7 @@  discard block
 block discarded – undo
631 631
     public function invoice_url($type = 'html')
632 632
     {
633 633
         $REG = $this->primary_registration();
634
-        if (! $REG instanceof EE_Registration) {
634
+        if ( ! $REG instanceof EE_Registration) {
635 635
             return '';
636 636
         }
637 637
         return $REG->invoice_url($type);
@@ -673,7 +673,7 @@  discard block
 block discarded – undo
673 673
     public function receipt_url($type = 'html')
674 674
     {
675 675
         $REG = $this->primary_registration();
676
-        if (! $REG instanceof EE_Registration) {
676
+        if ( ! $REG instanceof EE_Registration) {
677 677
             return '';
678 678
         }
679 679
         return $REG->receipt_url($type);
@@ -818,7 +818,7 @@  discard block
 block discarded – undo
818 818
     public function total_line_item($create_if_not_found = true)
819 819
     {
820 820
         $item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
821
-        if (! $item && $create_if_not_found) {
821
+        if ( ! $item && $create_if_not_found) {
822 822
             $item = EEH_Line_Item::create_total_line_item($this);
823 823
         }
824 824
         return $item;
@@ -863,7 +863,7 @@  discard block
 block discarded – undo
863 863
     public function billing_info()
864 864
     {
865 865
         $payment_method = $this->payment_method();
866
-        if (! $payment_method) {
866
+        if ( ! $payment_method) {
867 867
             EE_Error::add_error(
868 868
                 __(
869 869
                     'Could not find billing info for transaction because no gateway has been used for it yet',
@@ -876,7 +876,7 @@  discard block
 block discarded – undo
876 876
             return null;
877 877
         }
878 878
         $primary_reg = $this->primary_registration();
879
-        if (! $primary_reg) {
879
+        if ( ! $primary_reg) {
880 880
             EE_Error::add_error(
881 881
                 __(
882 882
                     'Cannot get billing info for gateway %s on transaction because no primary registration exists',
@@ -889,7 +889,7 @@  discard block
 block discarded – undo
889 889
             return null;
890 890
         }
891 891
         $attendee = $primary_reg->attendee();
892
-        if (! $attendee) {
892
+        if ( ! $attendee) {
893 893
             EE_Error::add_error(
894 894
                 __(
895 895
                     'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
@@ -1025,7 +1025,7 @@  discard block
 block discarded – undo
1025 1025
     public function update_based_on_payments()
1026 1026
     {
1027 1027
         EE_Error::doing_it_wrong(
1028
-            __CLASS__ . '::' . __FUNCTION__,
1028
+            __CLASS__.'::'.__FUNCTION__,
1029 1029
             sprintf(
1030 1030
                 __('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1031 1031
                 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
@@ -1085,13 +1085,13 @@  discard block
 block discarded – undo
1085 1085
     private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1086 1086
     {
1087 1087
         $reg_steps = $this->reg_steps();
1088
-        if (! is_array($reg_steps) || empty($reg_steps)) {
1088
+        if ( ! is_array($reg_steps) || empty($reg_steps)) {
1089 1089
             return false;
1090 1090
         }
1091 1091
         // loop thru reg steps array)
1092 1092
         foreach ($reg_steps as $slug => $reg_step_completed) {
1093 1093
             // if NOT checking ALL steps (only checking one step)
1094
-            if (! $check_all) {
1094
+            if ( ! $check_all) {
1095 1095
                 // and this is the one
1096 1096
                 if ($slug === $reg_step_slug) {
1097 1097
                     return $reg_step_completed;
@@ -1258,30 +1258,30 @@  discard block
 block discarded – undo
1258 1258
         // get reg steps array
1259 1259
         $txn_reg_steps = $this->reg_steps();
1260 1260
         // if reg step does NOT exist
1261
-        if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1261
+        if ( ! isset($txn_reg_steps[$reg_step_slug])) {
1262 1262
             return false;
1263 1263
         }
1264 1264
         // if  we're trying to complete a step that is already completed
1265
-        if ($txn_reg_steps[ $reg_step_slug ] === true) {
1265
+        if ($txn_reg_steps[$reg_step_slug] === true) {
1266 1266
             return true;
1267 1267
         }
1268 1268
         // if  we're trying to complete a step that hasn't even started
1269
-        if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1269
+        if ($status === true && $txn_reg_steps[$reg_step_slug] === false) {
1270 1270
             return false;
1271 1271
         }
1272 1272
         // if current status value matches the incoming value (no change)
1273 1273
         // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1274
-        if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1274
+        if ((int) $txn_reg_steps[$reg_step_slug] === (int) $status) {
1275 1275
             // this will happen in cases where multiple AJAX requests occur during the same step
1276 1276
             return true;
1277 1277
         }
1278 1278
         // if we're trying to set a start time, but it has already been set...
1279
-        if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1279
+        if (is_numeric($status) && is_numeric($txn_reg_steps[$reg_step_slug])) {
1280 1280
             // skip the update below, but don't return FALSE so that errors won't be displayed
1281 1281
             return true;
1282 1282
         }
1283 1283
         // update completed status
1284
-        $txn_reg_steps[ $reg_step_slug ] = $status;
1284
+        $txn_reg_steps[$reg_step_slug] = $status;
1285 1285
         $this->set_reg_steps($txn_reg_steps);
1286 1286
         $this->save();
1287 1287
         return true;
@@ -1301,7 +1301,7 @@  discard block
 block discarded – undo
1301 1301
     {
1302 1302
         // get reg steps array
1303 1303
         $txn_reg_steps = $this->reg_steps();
1304
-        unset($txn_reg_steps[ $reg_step_slug ]);
1304
+        unset($txn_reg_steps[$reg_step_slug]);
1305 1305
         $this->set_reg_steps($txn_reg_steps);
1306 1306
     }
1307 1307
 
@@ -1374,12 +1374,12 @@  discard block
 block discarded – undo
1374 1374
             return;
1375 1375
         }
1376 1376
         $payments = $this->get_many_related('Payment');
1377
-        if (! empty($payments)) {
1377
+        if ( ! empty($payments)) {
1378 1378
             foreach ($payments as $payment) {
1379 1379
                 if ($payment instanceof EE_Payment) {
1380 1380
                     // kk this TXN should NOT be abandoned
1381 1381
                     $this->update_status_based_on_total_paid();
1382
-                    if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1382
+                    if ( ! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1383 1383
                         EE_Error::add_attention(
1384 1384
                             sprintf(
1385 1385
                                 esc_html__(
Please login to merge, or discard this patch.
core/db_classes/EE_Datetime.class.php 2 patches
Indentation   +1272 added lines, -1272 removed lines patch added patch discarded remove patch
@@ -13,1276 +13,1276 @@
 block discarded – undo
13 13
 class EE_Datetime extends EE_Soft_Delete_Base_Class
14 14
 {
15 15
 
16
-    /**
17
-     * constant used by get_active_status, indicates datetime has no more available spaces
18
-     */
19
-    const sold_out = 'DTS';
20
-
21
-    /**
22
-     * constant used by get_active_status, indicating datetime is still active (even is not over, can be registered-for)
23
-     */
24
-    const active = 'DTA';
25
-
26
-    /**
27
-     * constant used by get_active_status, indicating the datetime cannot be used for registrations yet, but has not
28
-     * expired
29
-     */
30
-    const upcoming = 'DTU';
31
-
32
-    /**
33
-     * Datetime is postponed
34
-     */
35
-    const postponed = 'DTP';
36
-
37
-    /**
38
-     * Datetime is cancelled
39
-     */
40
-    const cancelled = 'DTC';
41
-
42
-    /**
43
-     * constant used by get_active_status, indicates datetime has expired (event is over)
44
-     */
45
-    const expired = 'DTE';
46
-
47
-    /**
48
-     * constant used in various places indicating that an event is INACTIVE (not yet ready to be published)
49
-     */
50
-    const inactive = 'DTI';
51
-
52
-
53
-    /**
54
-     * @param array  $props_n_values    incoming values
55
-     * @param string $timezone          incoming timezone (if not set the timezone set for the website will be used.)
56
-     * @param array  $date_formats      incoming date_formats in an array where the first value is the date_format
57
-     *                                  and the second value is the time format
58
-     * @return EE_Datetime
59
-     * @throws ReflectionException
60
-     * @throws InvalidArgumentException
61
-     * @throws InvalidInterfaceException
62
-     * @throws InvalidDataTypeException
63
-     * @throws EE_Error
64
-     */
65
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
66
-    {
67
-        $has_object = parent::_check_for_object(
68
-            $props_n_values,
69
-            __CLASS__,
70
-            $timezone,
71
-            $date_formats
72
-        );
73
-        return $has_object
74
-            ? $has_object
75
-            : new self($props_n_values, false, $timezone, $date_formats);
76
-    }
77
-
78
-
79
-    /**
80
-     * @param array  $props_n_values  incoming values from the database
81
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
82
-     *                                the website will be used.
83
-     * @return EE_Datetime
84
-     * @throws ReflectionException
85
-     * @throws InvalidArgumentException
86
-     * @throws InvalidInterfaceException
87
-     * @throws InvalidDataTypeException
88
-     * @throws EE_Error
89
-     */
90
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
91
-    {
92
-        return new self($props_n_values, true, $timezone);
93
-    }
94
-
95
-
96
-    /**
97
-     * @param $name
98
-     * @throws ReflectionException
99
-     * @throws InvalidArgumentException
100
-     * @throws InvalidInterfaceException
101
-     * @throws InvalidDataTypeException
102
-     * @throws EE_Error
103
-     */
104
-    public function set_name($name)
105
-    {
106
-        $this->set('DTT_name', $name);
107
-    }
108
-
109
-
110
-    /**
111
-     * @param $description
112
-     * @throws ReflectionException
113
-     * @throws InvalidArgumentException
114
-     * @throws InvalidInterfaceException
115
-     * @throws InvalidDataTypeException
116
-     * @throws EE_Error
117
-     */
118
-    public function set_description($description)
119
-    {
120
-        $this->set('DTT_description', $description);
121
-    }
122
-
123
-
124
-    /**
125
-     * Set event start date
126
-     * set the start date for an event
127
-     *
128
-     * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
129
-     * @throws ReflectionException
130
-     * @throws InvalidArgumentException
131
-     * @throws InvalidInterfaceException
132
-     * @throws InvalidDataTypeException
133
-     * @throws EE_Error
134
-     */
135
-    public function set_start_date($date)
136
-    {
137
-        $this->_set_date_for($date, 'DTT_EVT_start');
138
-    }
139
-
140
-
141
-    /**
142
-     * Set event start time
143
-     * set the start time for an event
144
-     *
145
-     * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
146
-     * @throws ReflectionException
147
-     * @throws InvalidArgumentException
148
-     * @throws InvalidInterfaceException
149
-     * @throws InvalidDataTypeException
150
-     * @throws EE_Error
151
-     */
152
-    public function set_start_time($time)
153
-    {
154
-        $this->_set_time_for($time, 'DTT_EVT_start');
155
-    }
156
-
157
-
158
-    /**
159
-     * Set event end date
160
-     * set the end date for an event
161
-     *
162
-     * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
163
-     * @throws ReflectionException
164
-     * @throws InvalidArgumentException
165
-     * @throws InvalidInterfaceException
166
-     * @throws InvalidDataTypeException
167
-     * @throws EE_Error
168
-     */
169
-    public function set_end_date($date)
170
-    {
171
-        $this->_set_date_for($date, 'DTT_EVT_end');
172
-    }
173
-
174
-
175
-    /**
176
-     * Set event end time
177
-     * set the end time for an event
178
-     *
179
-     * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
180
-     * @throws ReflectionException
181
-     * @throws InvalidArgumentException
182
-     * @throws InvalidInterfaceException
183
-     * @throws InvalidDataTypeException
184
-     * @throws EE_Error
185
-     */
186
-    public function set_end_time($time)
187
-    {
188
-        $this->_set_time_for($time, 'DTT_EVT_end');
189
-    }
190
-
191
-
192
-    /**
193
-     * Set registration limit
194
-     * set the maximum number of attendees that can be registered for this datetime slot
195
-     *
196
-     * @param int $reg_limit
197
-     * @throws ReflectionException
198
-     * @throws InvalidArgumentException
199
-     * @throws InvalidInterfaceException
200
-     * @throws InvalidDataTypeException
201
-     * @throws EE_Error
202
-     */
203
-    public function set_reg_limit($reg_limit)
204
-    {
205
-        $this->set('DTT_reg_limit', $reg_limit);
206
-    }
207
-
208
-
209
-    /**
210
-     * get the number of tickets sold for this datetime slot
211
-     *
212
-     * @return mixed int on success, FALSE on fail
213
-     * @throws ReflectionException
214
-     * @throws InvalidArgumentException
215
-     * @throws InvalidInterfaceException
216
-     * @throws InvalidDataTypeException
217
-     * @throws EE_Error
218
-     */
219
-    public function sold()
220
-    {
221
-        return $this->get_raw('DTT_sold');
222
-    }
223
-
224
-
225
-    /**
226
-     * @param int $sold
227
-     * @throws ReflectionException
228
-     * @throws InvalidArgumentException
229
-     * @throws InvalidInterfaceException
230
-     * @throws InvalidDataTypeException
231
-     * @throws EE_Error
232
-     */
233
-    public function set_sold($sold)
234
-    {
235
-        // sold can not go below zero
236
-        $sold = max(0, $sold);
237
-        $this->set('DTT_sold', $sold);
238
-    }
239
-
240
-
241
-    /**
242
-     * increments sold by amount passed by $qty
243
-     *
244
-     * @param int $qty
245
-     * @throws ReflectionException
246
-     * @throws InvalidArgumentException
247
-     * @throws InvalidInterfaceException
248
-     * @throws InvalidDataTypeException
249
-     * @throws EE_Error
250
-     */
251
-    public function increase_sold($qty = 1)
252
-    {
253
-        $sold = $this->sold() + $qty;
254
-        // remove ticket reservation
255
-        $this->decrease_reserved($qty);
256
-        $this->set_sold($sold);
257
-        do_action(
258
-            'AHEE__EE_Datetime__increase_sold',
259
-            $this,
260
-            $qty,
261
-            $sold
262
-        );
263
-    }
264
-
265
-
266
-    /**
267
-     * decrements (subtracts) sold amount passed by $qty
268
-     *
269
-     * @param int $qty
270
-     * @throws ReflectionException
271
-     * @throws InvalidArgumentException
272
-     * @throws InvalidInterfaceException
273
-     * @throws InvalidDataTypeException
274
-     * @throws EE_Error
275
-     */
276
-    public function decrease_sold($qty = 1)
277
-    {
278
-        $sold = $this->sold() - $qty;
279
-        $this->set_sold($sold);
280
-        do_action(
281
-            'AHEE__EE_Datetime__decrease_sold',
282
-            $this,
283
-            $qty,
284
-            $sold
285
-        );
286
-    }
287
-
288
-
289
-    /**
290
-     * Gets qty of reserved tickets for this datetime
291
-     *
292
-     * @return int
293
-     * @throws ReflectionException
294
-     * @throws InvalidArgumentException
295
-     * @throws InvalidInterfaceException
296
-     * @throws InvalidDataTypeException
297
-     * @throws EE_Error
298
-     */
299
-    public function reserved()
300
-    {
301
-        return $this->get_raw('DTT_reserved');
302
-    }
303
-
304
-
305
-    /**
306
-     * Sets qty of reserved tickets for this datetime
307
-     *
308
-     * @param int $reserved
309
-     * @throws ReflectionException
310
-     * @throws InvalidArgumentException
311
-     * @throws InvalidInterfaceException
312
-     * @throws InvalidDataTypeException
313
-     * @throws EE_Error
314
-     */
315
-    public function set_reserved($reserved)
316
-    {
317
-        // reserved can not go below zero
318
-        $reserved = max(0, (int) $reserved);
319
-        $this->set('DTT_reserved', $reserved);
320
-    }
321
-
322
-
323
-    /**
324
-     * increments reserved by amount passed by $qty
325
-     *
326
-     * @param int $qty
327
-     * @return void
328
-     * @throws ReflectionException
329
-     * @throws InvalidArgumentException
330
-     * @throws InvalidInterfaceException
331
-     * @throws InvalidDataTypeException
332
-     * @throws EE_Error
333
-     */
334
-    public function increase_reserved($qty = 1)
335
-    {
336
-        $reserved = $this->reserved() + absint($qty);
337
-        do_action(
338
-            'AHEE__EE_Datetime__increase_reserved',
339
-            $this,
340
-            $qty,
341
-            $reserved
342
-        );
343
-        $this->set_reserved($reserved);
344
-    }
345
-
346
-
347
-    /**
348
-     * decrements (subtracts) reserved by amount passed by $qty
349
-     *
350
-     * @param int $qty
351
-     * @return void
352
-     * @throws ReflectionException
353
-     * @throws InvalidArgumentException
354
-     * @throws InvalidInterfaceException
355
-     * @throws InvalidDataTypeException
356
-     * @throws EE_Error
357
-     */
358
-    public function decrease_reserved($qty = 1)
359
-    {
360
-        $reserved = $this->reserved() - absint($qty);
361
-        do_action(
362
-            'AHEE__EE_Datetime__decrease_reserved',
363
-            $this,
364
-            $qty,
365
-            $reserved
366
-        );
367
-        $this->set_reserved($reserved);
368
-    }
369
-
370
-
371
-    /**
372
-     * total sold and reserved tickets
373
-     *
374
-     * @return int
375
-     * @throws ReflectionException
376
-     * @throws InvalidArgumentException
377
-     * @throws InvalidInterfaceException
378
-     * @throws InvalidDataTypeException
379
-     * @throws EE_Error
380
-     */
381
-    public function sold_and_reserved()
382
-    {
383
-        return $this->sold() + $this->reserved();
384
-    }
385
-
386
-
387
-    /**
388
-     * returns the datetime name
389
-     *
390
-     * @return string
391
-     * @throws ReflectionException
392
-     * @throws InvalidArgumentException
393
-     * @throws InvalidInterfaceException
394
-     * @throws InvalidDataTypeException
395
-     * @throws EE_Error
396
-     */
397
-    public function name()
398
-    {
399
-        return $this->get('DTT_name');
400
-    }
401
-
402
-
403
-    /**
404
-     * returns the datetime description
405
-     *
406
-     * @return string
407
-     * @throws ReflectionException
408
-     * @throws InvalidArgumentException
409
-     * @throws InvalidInterfaceException
410
-     * @throws InvalidDataTypeException
411
-     * @throws EE_Error
412
-     */
413
-    public function description()
414
-    {
415
-        return $this->get('DTT_description');
416
-    }
417
-
418
-
419
-    /**
420
-     * This helper simply returns whether the event_datetime for the current datetime is a primary datetime
421
-     *
422
-     * @return boolean  TRUE if is primary, FALSE if not.
423
-     * @throws ReflectionException
424
-     * @throws InvalidArgumentException
425
-     * @throws InvalidInterfaceException
426
-     * @throws InvalidDataTypeException
427
-     * @throws EE_Error
428
-     */
429
-    public function is_primary()
430
-    {
431
-        return $this->get('DTT_is_primary');
432
-    }
433
-
434
-
435
-    /**
436
-     * This helper simply returns the order for the datetime
437
-     *
438
-     * @return int  The order of the datetime for this event.
439
-     * @throws ReflectionException
440
-     * @throws InvalidArgumentException
441
-     * @throws InvalidInterfaceException
442
-     * @throws InvalidDataTypeException
443
-     * @throws EE_Error
444
-     */
445
-    public function order()
446
-    {
447
-        return $this->get('DTT_order');
448
-    }
449
-
450
-
451
-    /**
452
-     * This helper simply returns the parent id for the datetime
453
-     *
454
-     * @return int
455
-     * @throws ReflectionException
456
-     * @throws InvalidArgumentException
457
-     * @throws InvalidInterfaceException
458
-     * @throws InvalidDataTypeException
459
-     * @throws EE_Error
460
-     */
461
-    public function parent()
462
-    {
463
-        return $this->get('DTT_parent');
464
-    }
465
-
466
-
467
-    /**
468
-     * show date and/or time
469
-     *
470
-     * @param string $date_or_time    whether to display a date or time or both
471
-     * @param string $start_or_end    whether to display start or end datetimes
472
-     * @param string $dt_frmt
473
-     * @param string $tm_frmt
474
-     * @param bool   $echo            whether we echo or return (note echoing uses "pretty" formats,
475
-     *                                otherwise we use the standard formats)
476
-     * @return string|bool  string on success, FALSE on fail
477
-     * @throws ReflectionException
478
-     * @throws InvalidArgumentException
479
-     * @throws InvalidInterfaceException
480
-     * @throws InvalidDataTypeException
481
-     * @throws EE_Error
482
-     */
483
-    private function _show_datetime(
484
-        $date_or_time = null,
485
-        $start_or_end = 'start',
486
-        $dt_frmt = '',
487
-        $tm_frmt = '',
488
-        $echo = false
489
-    ) {
490
-        $field_name = "DTT_EVT_{$start_or_end}";
491
-        $dtt = $this->_get_datetime(
492
-            $field_name,
493
-            $dt_frmt,
494
-            $tm_frmt,
495
-            $date_or_time,
496
-            $echo
497
-        );
498
-        if (! $echo) {
499
-            return $dtt;
500
-        }
501
-        return '';
502
-    }
503
-
504
-
505
-    /**
506
-     * get event start date.  Provide either the date format, or NULL to re-use the
507
-     * last-used format, or '' to use the default date format
508
-     *
509
-     * @param string $dt_frmt string representation of date format defaults to 'F j, Y'
510
-     * @return mixed            string on success, FALSE on fail
511
-     * @throws ReflectionException
512
-     * @throws InvalidArgumentException
513
-     * @throws InvalidInterfaceException
514
-     * @throws InvalidDataTypeException
515
-     * @throws EE_Error
516
-     */
517
-    public function start_date($dt_frmt = '')
518
-    {
519
-        return $this->_show_datetime('D', 'start', $dt_frmt);
520
-    }
521
-
522
-
523
-    /**
524
-     * Echoes start_date()
525
-     *
526
-     * @param string $dt_frmt
527
-     * @throws ReflectionException
528
-     * @throws InvalidArgumentException
529
-     * @throws InvalidInterfaceException
530
-     * @throws InvalidDataTypeException
531
-     * @throws EE_Error
532
-     */
533
-    public function e_start_date($dt_frmt = '')
534
-    {
535
-        $this->_show_datetime('D', 'start', $dt_frmt, null, true);
536
-    }
537
-
538
-
539
-    /**
540
-     * get end date. Provide either the date format, or NULL to re-use the
541
-     * last-used format, or '' to use the default date format
542
-     *
543
-     * @param string $dt_frmt string representation of date format defaults to 'F j, Y'
544
-     * @return mixed            string on success, FALSE on fail
545
-     * @throws ReflectionException
546
-     * @throws InvalidArgumentException
547
-     * @throws InvalidInterfaceException
548
-     * @throws InvalidDataTypeException
549
-     * @throws EE_Error
550
-     */
551
-    public function end_date($dt_frmt = '')
552
-    {
553
-        return $this->_show_datetime('D', 'end', $dt_frmt);
554
-    }
555
-
556
-
557
-    /**
558
-     * Echoes the end date. See end_date()
559
-     *
560
-     * @param string $dt_frmt
561
-     * @throws ReflectionException
562
-     * @throws InvalidArgumentException
563
-     * @throws InvalidInterfaceException
564
-     * @throws InvalidDataTypeException
565
-     * @throws EE_Error
566
-     */
567
-    public function e_end_date($dt_frmt = '')
568
-    {
569
-        $this->_show_datetime('D', 'end', $dt_frmt, null, true);
570
-    }
571
-
572
-
573
-    /**
574
-     * get date_range - meaning the start AND end date
575
-     *
576
-     * @access public
577
-     * @param string $dt_frmt     string representation of date format defaults to WP settings
578
-     * @param string $conjunction conjunction junction what's your function ?
579
-     *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
580
-     * @return mixed              string on success, FALSE on fail
581
-     * @throws ReflectionException
582
-     * @throws InvalidArgumentException
583
-     * @throws InvalidInterfaceException
584
-     * @throws InvalidDataTypeException
585
-     * @throws EE_Error
586
-     */
587
-    public function date_range($dt_frmt = '', $conjunction = ' - ')
588
-    {
589
-        $dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
590
-        $start = str_replace(
591
-            ' ',
592
-            '&nbsp;',
593
-            $this->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
594
-        );
595
-        $end = str_replace(
596
-            ' ',
597
-            '&nbsp;',
598
-            $this->get_i18n_datetime('DTT_EVT_end', $dt_frmt)
599
-        );
600
-        return $start !== $end ? $start . $conjunction . $end : $start;
601
-    }
602
-
603
-
604
-    /**
605
-     * @param string $dt_frmt
606
-     * @param string $conjunction
607
-     * @throws ReflectionException
608
-     * @throws InvalidArgumentException
609
-     * @throws InvalidInterfaceException
610
-     * @throws InvalidDataTypeException
611
-     * @throws EE_Error
612
-     */
613
-    public function e_date_range($dt_frmt = '', $conjunction = ' - ')
614
-    {
615
-        echo $this->date_range($dt_frmt, $conjunction);
616
-    }
617
-
618
-
619
-    /**
620
-     * get start time
621
-     *
622
-     * @param string $tm_format - string representation of time format defaults to 'g:i a'
623
-     * @return mixed        string on success, FALSE on fail
624
-     * @throws ReflectionException
625
-     * @throws InvalidArgumentException
626
-     * @throws InvalidInterfaceException
627
-     * @throws InvalidDataTypeException
628
-     * @throws EE_Error
629
-     */
630
-    public function start_time($tm_format = '')
631
-    {
632
-        return $this->_show_datetime('T', 'start', null, $tm_format);
633
-    }
634
-
635
-
636
-    /**
637
-     * @param string $tm_format
638
-     * @throws ReflectionException
639
-     * @throws InvalidArgumentException
640
-     * @throws InvalidInterfaceException
641
-     * @throws InvalidDataTypeException
642
-     * @throws EE_Error
643
-     */
644
-    public function e_start_time($tm_format = '')
645
-    {
646
-        $this->_show_datetime('T', 'start', null, $tm_format, true);
647
-    }
648
-
649
-
650
-    /**
651
-     * get end time
652
-     *
653
-     * @param string $tm_format string representation of time format defaults to 'g:i a'
654
-     * @return mixed                string on success, FALSE on fail
655
-     * @throws ReflectionException
656
-     * @throws InvalidArgumentException
657
-     * @throws InvalidInterfaceException
658
-     * @throws InvalidDataTypeException
659
-     * @throws EE_Error
660
-     */
661
-    public function end_time($tm_format = '')
662
-    {
663
-        return $this->_show_datetime('T', 'end', null, $tm_format);
664
-    }
665
-
666
-
667
-    /**
668
-     * @param string $tm_format
669
-     * @throws ReflectionException
670
-     * @throws InvalidArgumentException
671
-     * @throws InvalidInterfaceException
672
-     * @throws InvalidDataTypeException
673
-     * @throws EE_Error
674
-     */
675
-    public function e_end_time($tm_format = '')
676
-    {
677
-        $this->_show_datetime('T', 'end', null, $tm_format, true);
678
-    }
679
-
680
-
681
-    /**
682
-     * get time_range
683
-     *
684
-     * @access public
685
-     * @param string $tm_format   string representation of time format defaults to 'g:i a'
686
-     * @param string $conjunction conjunction junction what's your function ?
687
-     *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
688
-     * @return mixed              string on success, FALSE on fail
689
-     * @throws ReflectionException
690
-     * @throws InvalidArgumentException
691
-     * @throws InvalidInterfaceException
692
-     * @throws InvalidDataTypeException
693
-     * @throws EE_Error
694
-     */
695
-    public function time_range($tm_format = '', $conjunction = ' - ')
696
-    {
697
-        $tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
698
-        $start = str_replace(
699
-            ' ',
700
-            '&nbsp;',
701
-            $this->get_i18n_datetime('DTT_EVT_start', $tm_format)
702
-        );
703
-        $end = str_replace(
704
-            ' ',
705
-            '&nbsp;',
706
-            $this->get_i18n_datetime('DTT_EVT_end', $tm_format)
707
-        );
708
-        return $start !== $end ? $start . $conjunction . $end : $start;
709
-    }
710
-
711
-
712
-    /**
713
-     * @param string $tm_format
714
-     * @param string $conjunction
715
-     * @throws ReflectionException
716
-     * @throws InvalidArgumentException
717
-     * @throws InvalidInterfaceException
718
-     * @throws InvalidDataTypeException
719
-     * @throws EE_Error
720
-     */
721
-    public function e_time_range($tm_format = '', $conjunction = ' - ')
722
-    {
723
-        echo $this->time_range($tm_format, $conjunction);
724
-    }
725
-
726
-
727
-    /**
728
-     * This returns a range representation of the date and times.
729
-     * Output is dependent on the difference (or similarity) between DTT_EVT_start and DTT_EVT_end.
730
-     * Also, the return value is localized.
731
-     *
732
-     * @param string $dt_format
733
-     * @param string $tm_format
734
-     * @param string $conjunction used between two different dates or times.
735
-     *                            ex: Dec 1{$conjunction}}Dec 6, or 2pm{$conjunction}3pm
736
-     * @param string $separator   used between the date and time formats.
737
-     *                            ex: Dec 1, 2016{$separator}2pm
738
-     * @return string
739
-     * @throws ReflectionException
740
-     * @throws InvalidArgumentException
741
-     * @throws InvalidInterfaceException
742
-     * @throws InvalidDataTypeException
743
-     * @throws EE_Error
744
-     */
745
-    public function date_and_time_range(
746
-        $dt_format = '',
747
-        $tm_format = '',
748
-        $conjunction = ' - ',
749
-        $separator = ' '
750
-    ) {
751
-        $dt_format = ! empty($dt_format) ? $dt_format : $this->_dt_frmt;
752
-        $tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
753
-        $full_format = $dt_format . $separator . $tm_format;
754
-        // the range output depends on various conditions
755
-        switch (true) {
756
-            // start date timestamp and end date timestamp are the same.
757
-            case ($this->get_raw('DTT_EVT_start') === $this->get_raw('DTT_EVT_end')):
758
-                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format);
759
-                break;
760
-            // start and end date are the same but times are different
761
-            case ($this->start_date() === $this->end_date()):
762
-                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
763
-                          . $conjunction
764
-                          . $this->get_i18n_datetime('DTT_EVT_end', $tm_format);
765
-                break;
766
-            // all other conditions
767
-            default:
768
-                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
769
-                          . $conjunction
770
-                          . $this->get_i18n_datetime('DTT_EVT_end', $full_format);
771
-                break;
772
-        }
773
-        return $output;
774
-    }
775
-
776
-
777
-    /**
778
-     * This echos the results of date and time range.
779
-     *
780
-     * @see date_and_time_range() for more details on purpose.
781
-     * @param string $dt_format
782
-     * @param string $tm_format
783
-     * @param string $conjunction
784
-     * @return void
785
-     * @throws ReflectionException
786
-     * @throws InvalidArgumentException
787
-     * @throws InvalidInterfaceException
788
-     * @throws InvalidDataTypeException
789
-     * @throws EE_Error
790
-     */
791
-    public function e_date_and_time_range($dt_format = '', $tm_format = '', $conjunction = ' - ')
792
-    {
793
-        echo $this->date_and_time_range($dt_format, $tm_format, $conjunction);
794
-    }
795
-
796
-
797
-    /**
798
-     * get start date and start time
799
-     *
800
-     * @param    string $dt_format - string representation of date format defaults to 'F j, Y'
801
-     * @param    string $tm_format - string representation of time format defaults to 'g:i a'
802
-     * @return    mixed    string on success, FALSE on fail
803
-     * @throws ReflectionException
804
-     * @throws InvalidArgumentException
805
-     * @throws InvalidInterfaceException
806
-     * @throws InvalidDataTypeException
807
-     * @throws EE_Error
808
-     */
809
-    public function start_date_and_time($dt_format = '', $tm_format = '')
810
-    {
811
-        return $this->_show_datetime('', 'start', $dt_format, $tm_format);
812
-    }
813
-
814
-
815
-    /**
816
-     * @param string $dt_frmt
817
-     * @param string $tm_format
818
-     * @throws ReflectionException
819
-     * @throws InvalidArgumentException
820
-     * @throws InvalidInterfaceException
821
-     * @throws InvalidDataTypeException
822
-     * @throws EE_Error
823
-     */
824
-    public function e_start_date_and_time($dt_frmt = '', $tm_format = '')
825
-    {
826
-        $this->_show_datetime('', 'start', $dt_frmt, $tm_format, true);
827
-    }
828
-
829
-
830
-    /**
831
-     * Shows the length of the event (start to end time).
832
-     * Can be shown in 'seconds','minutes','hours', or 'days'.
833
-     * By default, rounds up. (So if you use 'days', and then event
834
-     * only occurs for 1 hour, it will return 1 day).
835
-     *
836
-     * @param string $units 'seconds','minutes','hours','days'
837
-     * @param bool   $round_up
838
-     * @return float|int|mixed
839
-     * @throws ReflectionException
840
-     * @throws InvalidArgumentException
841
-     * @throws InvalidInterfaceException
842
-     * @throws InvalidDataTypeException
843
-     * @throws EE_Error
844
-     */
845
-    public function length($units = 'seconds', $round_up = false)
846
-    {
847
-        $start = $this->get_raw('DTT_EVT_start');
848
-        $end = $this->get_raw('DTT_EVT_end');
849
-        $length_in_units = $end - $start;
850
-        switch ($units) {
851
-            // NOTE: We purposefully don't use "break;" in order to chain the divisions
852
-            /** @noinspection PhpMissingBreakStatementInspection */
853
-            // phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
854
-            case 'days':
855
-                $length_in_units /= 24;
856
-            /** @noinspection PhpMissingBreakStatementInspection */
857
-            case 'hours':
858
-                // fall through is intentional
859
-                $length_in_units /= 60;
860
-            /** @noinspection PhpMissingBreakStatementInspection */
861
-            case 'minutes':
862
-                // fall through is intentional
863
-                $length_in_units /= 60;
864
-            case 'seconds':
865
-            default:
866
-                $length_in_units = ceil($length_in_units);
867
-        }
868
-        // phpcs:enable
869
-        if ($round_up) {
870
-            $length_in_units = max($length_in_units, 1);
871
-        }
872
-        return $length_in_units;
873
-    }
874
-
875
-
876
-    /**
877
-     *        get end date and time
878
-     *
879
-     * @param string $dt_frmt   - string representation of date format defaults to 'F j, Y'
880
-     * @param string $tm_format - string representation of time format defaults to 'g:i a'
881
-     * @return    mixed                string on success, FALSE on fail
882
-     * @throws ReflectionException
883
-     * @throws InvalidArgumentException
884
-     * @throws InvalidInterfaceException
885
-     * @throws InvalidDataTypeException
886
-     * @throws EE_Error
887
-     */
888
-    public function end_date_and_time($dt_frmt = '', $tm_format = '')
889
-    {
890
-        return $this->_show_datetime('', 'end', $dt_frmt, $tm_format);
891
-    }
892
-
893
-
894
-    /**
895
-     * @param string $dt_frmt
896
-     * @param string $tm_format
897
-     * @throws ReflectionException
898
-     * @throws InvalidArgumentException
899
-     * @throws InvalidInterfaceException
900
-     * @throws InvalidDataTypeException
901
-     * @throws EE_Error
902
-     */
903
-    public function e_end_date_and_time($dt_frmt = '', $tm_format = '')
904
-    {
905
-        $this->_show_datetime('', 'end', $dt_frmt, $tm_format, true);
906
-    }
907
-
908
-
909
-    /**
910
-     *        get start timestamp
911
-     *
912
-     * @return        int
913
-     * @throws ReflectionException
914
-     * @throws InvalidArgumentException
915
-     * @throws InvalidInterfaceException
916
-     * @throws InvalidDataTypeException
917
-     * @throws EE_Error
918
-     */
919
-    public function start()
920
-    {
921
-        return $this->get_raw('DTT_EVT_start');
922
-    }
923
-
924
-
925
-    /**
926
-     *        get end timestamp
927
-     *
928
-     * @return        int
929
-     * @throws ReflectionException
930
-     * @throws InvalidArgumentException
931
-     * @throws InvalidInterfaceException
932
-     * @throws InvalidDataTypeException
933
-     * @throws EE_Error
934
-     */
935
-    public function end()
936
-    {
937
-        return $this->get_raw('DTT_EVT_end');
938
-    }
939
-
940
-
941
-    /**
942
-     *    get the registration limit for this datetime slot
943
-     *
944
-     * @return        mixed        int on success, FALSE on fail
945
-     * @throws ReflectionException
946
-     * @throws InvalidArgumentException
947
-     * @throws InvalidInterfaceException
948
-     * @throws InvalidDataTypeException
949
-     * @throws EE_Error
950
-     */
951
-    public function reg_limit()
952
-    {
953
-        return $this->get_raw('DTT_reg_limit');
954
-    }
955
-
956
-
957
-    /**
958
-     *    have the tickets sold for this datetime, met or exceed the registration limit ?
959
-     *
960
-     * @return        boolean
961
-     * @throws ReflectionException
962
-     * @throws InvalidArgumentException
963
-     * @throws InvalidInterfaceException
964
-     * @throws InvalidDataTypeException
965
-     * @throws EE_Error
966
-     */
967
-    public function sold_out()
968
-    {
969
-        return $this->reg_limit() > 0 && $this->sold() >= $this->reg_limit();
970
-    }
971
-
972
-
973
-    /**
974
-     * return the total number of spaces remaining at this venue.
975
-     * This only takes the venue's capacity into account, NOT the tickets available for sale
976
-     *
977
-     * @param bool $consider_tickets Whether to consider tickets remaining when determining if there are any spaces left
978
-     *                               Because if all tickets attached to this datetime have no spaces left,
979
-     *                               then this datetime IS effectively sold out.
980
-     *                               However, there are cases where we just want to know the spaces
981
-     *                               remaining for this particular datetime, hence the flag.
982
-     * @return int
983
-     * @throws ReflectionException
984
-     * @throws InvalidArgumentException
985
-     * @throws InvalidInterfaceException
986
-     * @throws InvalidDataTypeException
987
-     * @throws EE_Error
988
-     */
989
-    public function spaces_remaining($consider_tickets = false)
990
-    {
991
-        // tickets remaining available for purchase
992
-        // no need for special checks for infinite, because if DTT_reg_limit == EE_INF, then EE_INF - x = EE_INF
993
-        $dtt_remaining = $this->reg_limit() - $this->sold_and_reserved();
994
-        if (! $consider_tickets) {
995
-            return $dtt_remaining;
996
-        }
997
-        $tickets_remaining = $this->tickets_remaining();
998
-        return min($dtt_remaining, $tickets_remaining);
999
-    }
1000
-
1001
-
1002
-    /**
1003
-     * Counts the total tickets available
1004
-     * (from all the different types of tickets which are available for this datetime).
1005
-     *
1006
-     * @param array $query_params like EEM_Base::get_all's
1007
-     * @return int
1008
-     * @throws ReflectionException
1009
-     * @throws InvalidArgumentException
1010
-     * @throws InvalidInterfaceException
1011
-     * @throws InvalidDataTypeException
1012
-     * @throws EE_Error
1013
-     */
1014
-    public function tickets_remaining($query_params = array())
1015
-    {
1016
-        $sum = 0;
1017
-        $tickets = $this->tickets($query_params);
1018
-        if (! empty($tickets)) {
1019
-            foreach ($tickets as $ticket) {
1020
-                if ($ticket instanceof EE_Ticket) {
1021
-                    // get the actual amount of tickets that can be sold
1022
-                    $qty = $ticket->qty('saleable');
1023
-                    if ($qty === EE_INF) {
1024
-                        return EE_INF;
1025
-                    }
1026
-                    // no negative ticket quantities plz
1027
-                    if ($qty > 0) {
1028
-                        $sum += $qty;
1029
-                    }
1030
-                }
1031
-            }
1032
-        }
1033
-        return $sum;
1034
-    }
1035
-
1036
-
1037
-    /**
1038
-     * Gets the count of all the tickets available at this datetime (not ticket types)
1039
-     * before any were sold
1040
-     *
1041
-     * @param array $query_params like EEM_Base::get_all's
1042
-     * @return int
1043
-     * @throws ReflectionException
1044
-     * @throws InvalidArgumentException
1045
-     * @throws InvalidInterfaceException
1046
-     * @throws InvalidDataTypeException
1047
-     * @throws EE_Error
1048
-     */
1049
-    public function sum_tickets_initially_available($query_params = array())
1050
-    {
1051
-        return $this->sum_related('Ticket', $query_params, 'TKT_qty');
1052
-    }
1053
-
1054
-
1055
-    /**
1056
-     * Returns the lesser-of-the two: spaces remaining at this datetime, or
1057
-     * the total tickets remaining (a sum of the tickets remaining for each ticket type
1058
-     * that is available for this datetime).
1059
-     *
1060
-     * @return int
1061
-     * @throws ReflectionException
1062
-     * @throws InvalidArgumentException
1063
-     * @throws InvalidInterfaceException
1064
-     * @throws InvalidDataTypeException
1065
-     * @throws EE_Error
1066
-     */
1067
-    public function total_tickets_available_at_this_datetime()
1068
-    {
1069
-        return $this->spaces_remaining(true);
1070
-    }
1071
-
1072
-
1073
-    /**
1074
-     * This simply compares the internal dtt for the given string with NOW
1075
-     * and determines if the date is upcoming or not.
1076
-     *
1077
-     * @access public
1078
-     * @return boolean
1079
-     * @throws ReflectionException
1080
-     * @throws InvalidArgumentException
1081
-     * @throws InvalidInterfaceException
1082
-     * @throws InvalidDataTypeException
1083
-     * @throws EE_Error
1084
-     */
1085
-    public function is_upcoming()
1086
-    {
1087
-        return ($this->get_raw('DTT_EVT_start') > time());
1088
-    }
1089
-
1090
-
1091
-    /**
1092
-     * This simply compares the internal datetime for the given string with NOW
1093
-     * and returns if the date is active (i.e. start and end time)
1094
-     *
1095
-     * @return boolean
1096
-     * @throws ReflectionException
1097
-     * @throws InvalidArgumentException
1098
-     * @throws InvalidInterfaceException
1099
-     * @throws InvalidDataTypeException
1100
-     * @throws EE_Error
1101
-     */
1102
-    public function is_active()
1103
-    {
1104
-        return ($this->get_raw('DTT_EVT_start') < time() && $this->get_raw('DTT_EVT_end') > time());
1105
-    }
1106
-
1107
-
1108
-    /**
1109
-     * This simply compares the internal dtt for the given string with NOW
1110
-     * and determines if the date is expired or not.
1111
-     *
1112
-     * @return boolean
1113
-     * @throws ReflectionException
1114
-     * @throws InvalidArgumentException
1115
-     * @throws InvalidInterfaceException
1116
-     * @throws InvalidDataTypeException
1117
-     * @throws EE_Error
1118
-     */
1119
-    public function is_expired()
1120
-    {
1121
-        return ($this->get_raw('DTT_EVT_end') < time());
1122
-    }
1123
-
1124
-
1125
-    /**
1126
-     * This returns the active status for whether an event is active, upcoming, or expired
1127
-     *
1128
-     * @return int return value will be one of the EE_Datetime status constants.
1129
-     * @throws ReflectionException
1130
-     * @throws InvalidArgumentException
1131
-     * @throws InvalidInterfaceException
1132
-     * @throws InvalidDataTypeException
1133
-     * @throws EE_Error
1134
-     */
1135
-    public function get_active_status()
1136
-    {
1137
-        $total_tickets_for_this_dtt = $this->total_tickets_available_at_this_datetime();
1138
-        if ($total_tickets_for_this_dtt !== false && $total_tickets_for_this_dtt < 1) {
1139
-            return EE_Datetime::sold_out;
1140
-        }
1141
-        if ($this->is_expired()) {
1142
-            return EE_Datetime::expired;
1143
-        }
1144
-        if ($this->is_upcoming()) {
1145
-            return EE_Datetime::upcoming;
1146
-        }
1147
-        if ($this->is_active()) {
1148
-            return EE_Datetime::active;
1149
-        }
1150
-        return null;
1151
-    }
1152
-
1153
-
1154
-    /**
1155
-     * This returns a nice display name for the datetime that is contingent on the span between the dates and times.
1156
-     *
1157
-     * @param  boolean $use_dtt_name if TRUE then we'll use DTT->name() if its not empty.
1158
-     * @return string
1159
-     * @throws ReflectionException
1160
-     * @throws InvalidArgumentException
1161
-     * @throws InvalidInterfaceException
1162
-     * @throws InvalidDataTypeException
1163
-     * @throws EE_Error
1164
-     */
1165
-    public function get_dtt_display_name($use_dtt_name = false)
1166
-    {
1167
-        if ($use_dtt_name) {
1168
-            $dtt_name = $this->name();
1169
-            if (! empty($dtt_name)) {
1170
-                return $dtt_name;
1171
-            }
1172
-        }
1173
-        // first condition is to see if the months are different
1174
-        if (date('m', $this->get_raw('DTT_EVT_start')) !== date('m', $this->get_raw('DTT_EVT_end'))
1175
-        ) {
1176
-            $display_date = $this->start_date('M j\, Y g:i a') . ' - ' . $this->end_date('M j\, Y g:i a');
1177
-            // next condition is if its the same month but different day
1178
-        } else {
1179
-            if (date('m', $this->get_raw('DTT_EVT_start')) === date('m', $this->get_raw('DTT_EVT_end'))
1180
-                && date('d', $this->get_raw('DTT_EVT_start')) !== date('d', $this->get_raw('DTT_EVT_end'))
1181
-            ) {
1182
-                $display_date = $this->start_date('M j\, g:i a') . ' - ' . $this->end_date('M j\, g:i a Y');
1183
-            } else {
1184
-                $display_date = $this->start_date('F j\, Y')
1185
-                                . ' @ '
1186
-                                . $this->start_date('g:i a')
1187
-                                . ' - '
1188
-                                . $this->end_date('g:i a');
1189
-            }
1190
-        }
1191
-        return $display_date;
1192
-    }
1193
-
1194
-
1195
-    /**
1196
-     * Gets all the tickets for this datetime
1197
-     *
1198
-     * @param array $query_params see EEM_Base::get_all()
1199
-     * @return EE_Base_Class[]|EE_Ticket[]
1200
-     * @throws ReflectionException
1201
-     * @throws InvalidArgumentException
1202
-     * @throws InvalidInterfaceException
1203
-     * @throws InvalidDataTypeException
1204
-     * @throws EE_Error
1205
-     */
1206
-    public function tickets($query_params = array())
1207
-    {
1208
-        return $this->get_many_related('Ticket', $query_params);
1209
-    }
1210
-
1211
-
1212
-    /**
1213
-     * Gets all the ticket types currently available for purchase
1214
-     *
1215
-     * @param array $query_params like EEM_Base::get_all's
1216
-     * @return EE_Ticket[]
1217
-     * @throws ReflectionException
1218
-     * @throws InvalidArgumentException
1219
-     * @throws InvalidInterfaceException
1220
-     * @throws InvalidDataTypeException
1221
-     * @throws EE_Error
1222
-     */
1223
-    public function ticket_types_available_for_purchase($query_params = array())
1224
-    {
1225
-        // first check if datetime is valid
1226
-        if ($this->sold_out() || ! ($this->is_upcoming() || $this->is_active())) {
1227
-            return array();
1228
-        }
1229
-        if (empty($query_params)) {
1230
-            $query_params = array(
1231
-                array(
1232
-                    'TKT_start_date' => array('<=', EEM_Ticket::instance()->current_time_for_query('TKT_start_date')),
1233
-                    'TKT_end_date'   => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
1234
-                    'TKT_deleted'    => false,
1235
-                ),
1236
-            );
1237
-        }
1238
-        return $this->tickets($query_params);
1239
-    }
1240
-
1241
-
1242
-    /**
1243
-     * @return EE_Base_Class|EE_Event
1244
-     * @throws ReflectionException
1245
-     * @throws InvalidArgumentException
1246
-     * @throws InvalidInterfaceException
1247
-     * @throws InvalidDataTypeException
1248
-     * @throws EE_Error
1249
-     */
1250
-    public function event()
1251
-    {
1252
-        return $this->get_first_related('Event');
1253
-    }
1254
-
1255
-
1256
-    /**
1257
-     * Updates the DTT_sold attribute (and saves) based on the number of registrations for this datetime
1258
-     * (via the tickets). into account
1259
-     *
1260
-     * @return int
1261
-     * @throws ReflectionException
1262
-     * @throws InvalidArgumentException
1263
-     * @throws InvalidInterfaceException
1264
-     * @throws InvalidDataTypeException
1265
-     * @throws EE_Error
1266
-     */
1267
-    public function update_sold()
1268
-    {
1269
-        $count_regs_for_this_datetime = EEM_Registration::instance()->count(
1270
-            array(
1271
-                array(
1272
-                    'STS_ID'                 => EEM_Registration::status_id_approved,
1273
-                    'REG_deleted'            => 0,
1274
-                    'Ticket.Datetime.DTT_ID' => $this->ID(),
1275
-                ),
1276
-            )
1277
-        );
1278
-        $sold = $this->sold();
1279
-        if ($count_regs_for_this_datetime > $sold) {
1280
-            $this->increase_sold($count_regs_for_this_datetime - $sold);
1281
-            $this->save();
1282
-        } elseif ($count_regs_for_this_datetime < $sold) {
1283
-            $this->decrease_sold($count_regs_for_this_datetime - $sold);
1284
-            $this->save();
1285
-        }
1286
-        return $count_regs_for_this_datetime;
1287
-    }
16
+	/**
17
+	 * constant used by get_active_status, indicates datetime has no more available spaces
18
+	 */
19
+	const sold_out = 'DTS';
20
+
21
+	/**
22
+	 * constant used by get_active_status, indicating datetime is still active (even is not over, can be registered-for)
23
+	 */
24
+	const active = 'DTA';
25
+
26
+	/**
27
+	 * constant used by get_active_status, indicating the datetime cannot be used for registrations yet, but has not
28
+	 * expired
29
+	 */
30
+	const upcoming = 'DTU';
31
+
32
+	/**
33
+	 * Datetime is postponed
34
+	 */
35
+	const postponed = 'DTP';
36
+
37
+	/**
38
+	 * Datetime is cancelled
39
+	 */
40
+	const cancelled = 'DTC';
41
+
42
+	/**
43
+	 * constant used by get_active_status, indicates datetime has expired (event is over)
44
+	 */
45
+	const expired = 'DTE';
46
+
47
+	/**
48
+	 * constant used in various places indicating that an event is INACTIVE (not yet ready to be published)
49
+	 */
50
+	const inactive = 'DTI';
51
+
52
+
53
+	/**
54
+	 * @param array  $props_n_values    incoming values
55
+	 * @param string $timezone          incoming timezone (if not set the timezone set for the website will be used.)
56
+	 * @param array  $date_formats      incoming date_formats in an array where the first value is the date_format
57
+	 *                                  and the second value is the time format
58
+	 * @return EE_Datetime
59
+	 * @throws ReflectionException
60
+	 * @throws InvalidArgumentException
61
+	 * @throws InvalidInterfaceException
62
+	 * @throws InvalidDataTypeException
63
+	 * @throws EE_Error
64
+	 */
65
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
66
+	{
67
+		$has_object = parent::_check_for_object(
68
+			$props_n_values,
69
+			__CLASS__,
70
+			$timezone,
71
+			$date_formats
72
+		);
73
+		return $has_object
74
+			? $has_object
75
+			: new self($props_n_values, false, $timezone, $date_formats);
76
+	}
77
+
78
+
79
+	/**
80
+	 * @param array  $props_n_values  incoming values from the database
81
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
82
+	 *                                the website will be used.
83
+	 * @return EE_Datetime
84
+	 * @throws ReflectionException
85
+	 * @throws InvalidArgumentException
86
+	 * @throws InvalidInterfaceException
87
+	 * @throws InvalidDataTypeException
88
+	 * @throws EE_Error
89
+	 */
90
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
91
+	{
92
+		return new self($props_n_values, true, $timezone);
93
+	}
94
+
95
+
96
+	/**
97
+	 * @param $name
98
+	 * @throws ReflectionException
99
+	 * @throws InvalidArgumentException
100
+	 * @throws InvalidInterfaceException
101
+	 * @throws InvalidDataTypeException
102
+	 * @throws EE_Error
103
+	 */
104
+	public function set_name($name)
105
+	{
106
+		$this->set('DTT_name', $name);
107
+	}
108
+
109
+
110
+	/**
111
+	 * @param $description
112
+	 * @throws ReflectionException
113
+	 * @throws InvalidArgumentException
114
+	 * @throws InvalidInterfaceException
115
+	 * @throws InvalidDataTypeException
116
+	 * @throws EE_Error
117
+	 */
118
+	public function set_description($description)
119
+	{
120
+		$this->set('DTT_description', $description);
121
+	}
122
+
123
+
124
+	/**
125
+	 * Set event start date
126
+	 * set the start date for an event
127
+	 *
128
+	 * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
129
+	 * @throws ReflectionException
130
+	 * @throws InvalidArgumentException
131
+	 * @throws InvalidInterfaceException
132
+	 * @throws InvalidDataTypeException
133
+	 * @throws EE_Error
134
+	 */
135
+	public function set_start_date($date)
136
+	{
137
+		$this->_set_date_for($date, 'DTT_EVT_start');
138
+	}
139
+
140
+
141
+	/**
142
+	 * Set event start time
143
+	 * set the start time for an event
144
+	 *
145
+	 * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
146
+	 * @throws ReflectionException
147
+	 * @throws InvalidArgumentException
148
+	 * @throws InvalidInterfaceException
149
+	 * @throws InvalidDataTypeException
150
+	 * @throws EE_Error
151
+	 */
152
+	public function set_start_time($time)
153
+	{
154
+		$this->_set_time_for($time, 'DTT_EVT_start');
155
+	}
156
+
157
+
158
+	/**
159
+	 * Set event end date
160
+	 * set the end date for an event
161
+	 *
162
+	 * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
163
+	 * @throws ReflectionException
164
+	 * @throws InvalidArgumentException
165
+	 * @throws InvalidInterfaceException
166
+	 * @throws InvalidDataTypeException
167
+	 * @throws EE_Error
168
+	 */
169
+	public function set_end_date($date)
170
+	{
171
+		$this->_set_date_for($date, 'DTT_EVT_end');
172
+	}
173
+
174
+
175
+	/**
176
+	 * Set event end time
177
+	 * set the end time for an event
178
+	 *
179
+	 * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
180
+	 * @throws ReflectionException
181
+	 * @throws InvalidArgumentException
182
+	 * @throws InvalidInterfaceException
183
+	 * @throws InvalidDataTypeException
184
+	 * @throws EE_Error
185
+	 */
186
+	public function set_end_time($time)
187
+	{
188
+		$this->_set_time_for($time, 'DTT_EVT_end');
189
+	}
190
+
191
+
192
+	/**
193
+	 * Set registration limit
194
+	 * set the maximum number of attendees that can be registered for this datetime slot
195
+	 *
196
+	 * @param int $reg_limit
197
+	 * @throws ReflectionException
198
+	 * @throws InvalidArgumentException
199
+	 * @throws InvalidInterfaceException
200
+	 * @throws InvalidDataTypeException
201
+	 * @throws EE_Error
202
+	 */
203
+	public function set_reg_limit($reg_limit)
204
+	{
205
+		$this->set('DTT_reg_limit', $reg_limit);
206
+	}
207
+
208
+
209
+	/**
210
+	 * get the number of tickets sold for this datetime slot
211
+	 *
212
+	 * @return mixed int on success, FALSE on fail
213
+	 * @throws ReflectionException
214
+	 * @throws InvalidArgumentException
215
+	 * @throws InvalidInterfaceException
216
+	 * @throws InvalidDataTypeException
217
+	 * @throws EE_Error
218
+	 */
219
+	public function sold()
220
+	{
221
+		return $this->get_raw('DTT_sold');
222
+	}
223
+
224
+
225
+	/**
226
+	 * @param int $sold
227
+	 * @throws ReflectionException
228
+	 * @throws InvalidArgumentException
229
+	 * @throws InvalidInterfaceException
230
+	 * @throws InvalidDataTypeException
231
+	 * @throws EE_Error
232
+	 */
233
+	public function set_sold($sold)
234
+	{
235
+		// sold can not go below zero
236
+		$sold = max(0, $sold);
237
+		$this->set('DTT_sold', $sold);
238
+	}
239
+
240
+
241
+	/**
242
+	 * increments sold by amount passed by $qty
243
+	 *
244
+	 * @param int $qty
245
+	 * @throws ReflectionException
246
+	 * @throws InvalidArgumentException
247
+	 * @throws InvalidInterfaceException
248
+	 * @throws InvalidDataTypeException
249
+	 * @throws EE_Error
250
+	 */
251
+	public function increase_sold($qty = 1)
252
+	{
253
+		$sold = $this->sold() + $qty;
254
+		// remove ticket reservation
255
+		$this->decrease_reserved($qty);
256
+		$this->set_sold($sold);
257
+		do_action(
258
+			'AHEE__EE_Datetime__increase_sold',
259
+			$this,
260
+			$qty,
261
+			$sold
262
+		);
263
+	}
264
+
265
+
266
+	/**
267
+	 * decrements (subtracts) sold amount passed by $qty
268
+	 *
269
+	 * @param int $qty
270
+	 * @throws ReflectionException
271
+	 * @throws InvalidArgumentException
272
+	 * @throws InvalidInterfaceException
273
+	 * @throws InvalidDataTypeException
274
+	 * @throws EE_Error
275
+	 */
276
+	public function decrease_sold($qty = 1)
277
+	{
278
+		$sold = $this->sold() - $qty;
279
+		$this->set_sold($sold);
280
+		do_action(
281
+			'AHEE__EE_Datetime__decrease_sold',
282
+			$this,
283
+			$qty,
284
+			$sold
285
+		);
286
+	}
287
+
288
+
289
+	/**
290
+	 * Gets qty of reserved tickets for this datetime
291
+	 *
292
+	 * @return int
293
+	 * @throws ReflectionException
294
+	 * @throws InvalidArgumentException
295
+	 * @throws InvalidInterfaceException
296
+	 * @throws InvalidDataTypeException
297
+	 * @throws EE_Error
298
+	 */
299
+	public function reserved()
300
+	{
301
+		return $this->get_raw('DTT_reserved');
302
+	}
303
+
304
+
305
+	/**
306
+	 * Sets qty of reserved tickets for this datetime
307
+	 *
308
+	 * @param int $reserved
309
+	 * @throws ReflectionException
310
+	 * @throws InvalidArgumentException
311
+	 * @throws InvalidInterfaceException
312
+	 * @throws InvalidDataTypeException
313
+	 * @throws EE_Error
314
+	 */
315
+	public function set_reserved($reserved)
316
+	{
317
+		// reserved can not go below zero
318
+		$reserved = max(0, (int) $reserved);
319
+		$this->set('DTT_reserved', $reserved);
320
+	}
321
+
322
+
323
+	/**
324
+	 * increments reserved by amount passed by $qty
325
+	 *
326
+	 * @param int $qty
327
+	 * @return void
328
+	 * @throws ReflectionException
329
+	 * @throws InvalidArgumentException
330
+	 * @throws InvalidInterfaceException
331
+	 * @throws InvalidDataTypeException
332
+	 * @throws EE_Error
333
+	 */
334
+	public function increase_reserved($qty = 1)
335
+	{
336
+		$reserved = $this->reserved() + absint($qty);
337
+		do_action(
338
+			'AHEE__EE_Datetime__increase_reserved',
339
+			$this,
340
+			$qty,
341
+			$reserved
342
+		);
343
+		$this->set_reserved($reserved);
344
+	}
345
+
346
+
347
+	/**
348
+	 * decrements (subtracts) reserved by amount passed by $qty
349
+	 *
350
+	 * @param int $qty
351
+	 * @return void
352
+	 * @throws ReflectionException
353
+	 * @throws InvalidArgumentException
354
+	 * @throws InvalidInterfaceException
355
+	 * @throws InvalidDataTypeException
356
+	 * @throws EE_Error
357
+	 */
358
+	public function decrease_reserved($qty = 1)
359
+	{
360
+		$reserved = $this->reserved() - absint($qty);
361
+		do_action(
362
+			'AHEE__EE_Datetime__decrease_reserved',
363
+			$this,
364
+			$qty,
365
+			$reserved
366
+		);
367
+		$this->set_reserved($reserved);
368
+	}
369
+
370
+
371
+	/**
372
+	 * total sold and reserved tickets
373
+	 *
374
+	 * @return int
375
+	 * @throws ReflectionException
376
+	 * @throws InvalidArgumentException
377
+	 * @throws InvalidInterfaceException
378
+	 * @throws InvalidDataTypeException
379
+	 * @throws EE_Error
380
+	 */
381
+	public function sold_and_reserved()
382
+	{
383
+		return $this->sold() + $this->reserved();
384
+	}
385
+
386
+
387
+	/**
388
+	 * returns the datetime name
389
+	 *
390
+	 * @return string
391
+	 * @throws ReflectionException
392
+	 * @throws InvalidArgumentException
393
+	 * @throws InvalidInterfaceException
394
+	 * @throws InvalidDataTypeException
395
+	 * @throws EE_Error
396
+	 */
397
+	public function name()
398
+	{
399
+		return $this->get('DTT_name');
400
+	}
401
+
402
+
403
+	/**
404
+	 * returns the datetime description
405
+	 *
406
+	 * @return string
407
+	 * @throws ReflectionException
408
+	 * @throws InvalidArgumentException
409
+	 * @throws InvalidInterfaceException
410
+	 * @throws InvalidDataTypeException
411
+	 * @throws EE_Error
412
+	 */
413
+	public function description()
414
+	{
415
+		return $this->get('DTT_description');
416
+	}
417
+
418
+
419
+	/**
420
+	 * This helper simply returns whether the event_datetime for the current datetime is a primary datetime
421
+	 *
422
+	 * @return boolean  TRUE if is primary, FALSE if not.
423
+	 * @throws ReflectionException
424
+	 * @throws InvalidArgumentException
425
+	 * @throws InvalidInterfaceException
426
+	 * @throws InvalidDataTypeException
427
+	 * @throws EE_Error
428
+	 */
429
+	public function is_primary()
430
+	{
431
+		return $this->get('DTT_is_primary');
432
+	}
433
+
434
+
435
+	/**
436
+	 * This helper simply returns the order for the datetime
437
+	 *
438
+	 * @return int  The order of the datetime for this event.
439
+	 * @throws ReflectionException
440
+	 * @throws InvalidArgumentException
441
+	 * @throws InvalidInterfaceException
442
+	 * @throws InvalidDataTypeException
443
+	 * @throws EE_Error
444
+	 */
445
+	public function order()
446
+	{
447
+		return $this->get('DTT_order');
448
+	}
449
+
450
+
451
+	/**
452
+	 * This helper simply returns the parent id for the datetime
453
+	 *
454
+	 * @return int
455
+	 * @throws ReflectionException
456
+	 * @throws InvalidArgumentException
457
+	 * @throws InvalidInterfaceException
458
+	 * @throws InvalidDataTypeException
459
+	 * @throws EE_Error
460
+	 */
461
+	public function parent()
462
+	{
463
+		return $this->get('DTT_parent');
464
+	}
465
+
466
+
467
+	/**
468
+	 * show date and/or time
469
+	 *
470
+	 * @param string $date_or_time    whether to display a date or time or both
471
+	 * @param string $start_or_end    whether to display start or end datetimes
472
+	 * @param string $dt_frmt
473
+	 * @param string $tm_frmt
474
+	 * @param bool   $echo            whether we echo or return (note echoing uses "pretty" formats,
475
+	 *                                otherwise we use the standard formats)
476
+	 * @return string|bool  string on success, FALSE on fail
477
+	 * @throws ReflectionException
478
+	 * @throws InvalidArgumentException
479
+	 * @throws InvalidInterfaceException
480
+	 * @throws InvalidDataTypeException
481
+	 * @throws EE_Error
482
+	 */
483
+	private function _show_datetime(
484
+		$date_or_time = null,
485
+		$start_or_end = 'start',
486
+		$dt_frmt = '',
487
+		$tm_frmt = '',
488
+		$echo = false
489
+	) {
490
+		$field_name = "DTT_EVT_{$start_or_end}";
491
+		$dtt = $this->_get_datetime(
492
+			$field_name,
493
+			$dt_frmt,
494
+			$tm_frmt,
495
+			$date_or_time,
496
+			$echo
497
+		);
498
+		if (! $echo) {
499
+			return $dtt;
500
+		}
501
+		return '';
502
+	}
503
+
504
+
505
+	/**
506
+	 * get event start date.  Provide either the date format, or NULL to re-use the
507
+	 * last-used format, or '' to use the default date format
508
+	 *
509
+	 * @param string $dt_frmt string representation of date format defaults to 'F j, Y'
510
+	 * @return mixed            string on success, FALSE on fail
511
+	 * @throws ReflectionException
512
+	 * @throws InvalidArgumentException
513
+	 * @throws InvalidInterfaceException
514
+	 * @throws InvalidDataTypeException
515
+	 * @throws EE_Error
516
+	 */
517
+	public function start_date($dt_frmt = '')
518
+	{
519
+		return $this->_show_datetime('D', 'start', $dt_frmt);
520
+	}
521
+
522
+
523
+	/**
524
+	 * Echoes start_date()
525
+	 *
526
+	 * @param string $dt_frmt
527
+	 * @throws ReflectionException
528
+	 * @throws InvalidArgumentException
529
+	 * @throws InvalidInterfaceException
530
+	 * @throws InvalidDataTypeException
531
+	 * @throws EE_Error
532
+	 */
533
+	public function e_start_date($dt_frmt = '')
534
+	{
535
+		$this->_show_datetime('D', 'start', $dt_frmt, null, true);
536
+	}
537
+
538
+
539
+	/**
540
+	 * get end date. Provide either the date format, or NULL to re-use the
541
+	 * last-used format, or '' to use the default date format
542
+	 *
543
+	 * @param string $dt_frmt string representation of date format defaults to 'F j, Y'
544
+	 * @return mixed            string on success, FALSE on fail
545
+	 * @throws ReflectionException
546
+	 * @throws InvalidArgumentException
547
+	 * @throws InvalidInterfaceException
548
+	 * @throws InvalidDataTypeException
549
+	 * @throws EE_Error
550
+	 */
551
+	public function end_date($dt_frmt = '')
552
+	{
553
+		return $this->_show_datetime('D', 'end', $dt_frmt);
554
+	}
555
+
556
+
557
+	/**
558
+	 * Echoes the end date. See end_date()
559
+	 *
560
+	 * @param string $dt_frmt
561
+	 * @throws ReflectionException
562
+	 * @throws InvalidArgumentException
563
+	 * @throws InvalidInterfaceException
564
+	 * @throws InvalidDataTypeException
565
+	 * @throws EE_Error
566
+	 */
567
+	public function e_end_date($dt_frmt = '')
568
+	{
569
+		$this->_show_datetime('D', 'end', $dt_frmt, null, true);
570
+	}
571
+
572
+
573
+	/**
574
+	 * get date_range - meaning the start AND end date
575
+	 *
576
+	 * @access public
577
+	 * @param string $dt_frmt     string representation of date format defaults to WP settings
578
+	 * @param string $conjunction conjunction junction what's your function ?
579
+	 *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
580
+	 * @return mixed              string on success, FALSE on fail
581
+	 * @throws ReflectionException
582
+	 * @throws InvalidArgumentException
583
+	 * @throws InvalidInterfaceException
584
+	 * @throws InvalidDataTypeException
585
+	 * @throws EE_Error
586
+	 */
587
+	public function date_range($dt_frmt = '', $conjunction = ' - ')
588
+	{
589
+		$dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
590
+		$start = str_replace(
591
+			' ',
592
+			'&nbsp;',
593
+			$this->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
594
+		);
595
+		$end = str_replace(
596
+			' ',
597
+			'&nbsp;',
598
+			$this->get_i18n_datetime('DTT_EVT_end', $dt_frmt)
599
+		);
600
+		return $start !== $end ? $start . $conjunction . $end : $start;
601
+	}
602
+
603
+
604
+	/**
605
+	 * @param string $dt_frmt
606
+	 * @param string $conjunction
607
+	 * @throws ReflectionException
608
+	 * @throws InvalidArgumentException
609
+	 * @throws InvalidInterfaceException
610
+	 * @throws InvalidDataTypeException
611
+	 * @throws EE_Error
612
+	 */
613
+	public function e_date_range($dt_frmt = '', $conjunction = ' - ')
614
+	{
615
+		echo $this->date_range($dt_frmt, $conjunction);
616
+	}
617
+
618
+
619
+	/**
620
+	 * get start time
621
+	 *
622
+	 * @param string $tm_format - string representation of time format defaults to 'g:i a'
623
+	 * @return mixed        string on success, FALSE on fail
624
+	 * @throws ReflectionException
625
+	 * @throws InvalidArgumentException
626
+	 * @throws InvalidInterfaceException
627
+	 * @throws InvalidDataTypeException
628
+	 * @throws EE_Error
629
+	 */
630
+	public function start_time($tm_format = '')
631
+	{
632
+		return $this->_show_datetime('T', 'start', null, $tm_format);
633
+	}
634
+
635
+
636
+	/**
637
+	 * @param string $tm_format
638
+	 * @throws ReflectionException
639
+	 * @throws InvalidArgumentException
640
+	 * @throws InvalidInterfaceException
641
+	 * @throws InvalidDataTypeException
642
+	 * @throws EE_Error
643
+	 */
644
+	public function e_start_time($tm_format = '')
645
+	{
646
+		$this->_show_datetime('T', 'start', null, $tm_format, true);
647
+	}
648
+
649
+
650
+	/**
651
+	 * get end time
652
+	 *
653
+	 * @param string $tm_format string representation of time format defaults to 'g:i a'
654
+	 * @return mixed                string on success, FALSE on fail
655
+	 * @throws ReflectionException
656
+	 * @throws InvalidArgumentException
657
+	 * @throws InvalidInterfaceException
658
+	 * @throws InvalidDataTypeException
659
+	 * @throws EE_Error
660
+	 */
661
+	public function end_time($tm_format = '')
662
+	{
663
+		return $this->_show_datetime('T', 'end', null, $tm_format);
664
+	}
665
+
666
+
667
+	/**
668
+	 * @param string $tm_format
669
+	 * @throws ReflectionException
670
+	 * @throws InvalidArgumentException
671
+	 * @throws InvalidInterfaceException
672
+	 * @throws InvalidDataTypeException
673
+	 * @throws EE_Error
674
+	 */
675
+	public function e_end_time($tm_format = '')
676
+	{
677
+		$this->_show_datetime('T', 'end', null, $tm_format, true);
678
+	}
679
+
680
+
681
+	/**
682
+	 * get time_range
683
+	 *
684
+	 * @access public
685
+	 * @param string $tm_format   string representation of time format defaults to 'g:i a'
686
+	 * @param string $conjunction conjunction junction what's your function ?
687
+	 *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
688
+	 * @return mixed              string on success, FALSE on fail
689
+	 * @throws ReflectionException
690
+	 * @throws InvalidArgumentException
691
+	 * @throws InvalidInterfaceException
692
+	 * @throws InvalidDataTypeException
693
+	 * @throws EE_Error
694
+	 */
695
+	public function time_range($tm_format = '', $conjunction = ' - ')
696
+	{
697
+		$tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
698
+		$start = str_replace(
699
+			' ',
700
+			'&nbsp;',
701
+			$this->get_i18n_datetime('DTT_EVT_start', $tm_format)
702
+		);
703
+		$end = str_replace(
704
+			' ',
705
+			'&nbsp;',
706
+			$this->get_i18n_datetime('DTT_EVT_end', $tm_format)
707
+		);
708
+		return $start !== $end ? $start . $conjunction . $end : $start;
709
+	}
710
+
711
+
712
+	/**
713
+	 * @param string $tm_format
714
+	 * @param string $conjunction
715
+	 * @throws ReflectionException
716
+	 * @throws InvalidArgumentException
717
+	 * @throws InvalidInterfaceException
718
+	 * @throws InvalidDataTypeException
719
+	 * @throws EE_Error
720
+	 */
721
+	public function e_time_range($tm_format = '', $conjunction = ' - ')
722
+	{
723
+		echo $this->time_range($tm_format, $conjunction);
724
+	}
725
+
726
+
727
+	/**
728
+	 * This returns a range representation of the date and times.
729
+	 * Output is dependent on the difference (or similarity) between DTT_EVT_start and DTT_EVT_end.
730
+	 * Also, the return value is localized.
731
+	 *
732
+	 * @param string $dt_format
733
+	 * @param string $tm_format
734
+	 * @param string $conjunction used between two different dates or times.
735
+	 *                            ex: Dec 1{$conjunction}}Dec 6, or 2pm{$conjunction}3pm
736
+	 * @param string $separator   used between the date and time formats.
737
+	 *                            ex: Dec 1, 2016{$separator}2pm
738
+	 * @return string
739
+	 * @throws ReflectionException
740
+	 * @throws InvalidArgumentException
741
+	 * @throws InvalidInterfaceException
742
+	 * @throws InvalidDataTypeException
743
+	 * @throws EE_Error
744
+	 */
745
+	public function date_and_time_range(
746
+		$dt_format = '',
747
+		$tm_format = '',
748
+		$conjunction = ' - ',
749
+		$separator = ' '
750
+	) {
751
+		$dt_format = ! empty($dt_format) ? $dt_format : $this->_dt_frmt;
752
+		$tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
753
+		$full_format = $dt_format . $separator . $tm_format;
754
+		// the range output depends on various conditions
755
+		switch (true) {
756
+			// start date timestamp and end date timestamp are the same.
757
+			case ($this->get_raw('DTT_EVT_start') === $this->get_raw('DTT_EVT_end')):
758
+				$output = $this->get_i18n_datetime('DTT_EVT_start', $full_format);
759
+				break;
760
+			// start and end date are the same but times are different
761
+			case ($this->start_date() === $this->end_date()):
762
+				$output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
763
+						  . $conjunction
764
+						  . $this->get_i18n_datetime('DTT_EVT_end', $tm_format);
765
+				break;
766
+			// all other conditions
767
+			default:
768
+				$output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
769
+						  . $conjunction
770
+						  . $this->get_i18n_datetime('DTT_EVT_end', $full_format);
771
+				break;
772
+		}
773
+		return $output;
774
+	}
775
+
776
+
777
+	/**
778
+	 * This echos the results of date and time range.
779
+	 *
780
+	 * @see date_and_time_range() for more details on purpose.
781
+	 * @param string $dt_format
782
+	 * @param string $tm_format
783
+	 * @param string $conjunction
784
+	 * @return void
785
+	 * @throws ReflectionException
786
+	 * @throws InvalidArgumentException
787
+	 * @throws InvalidInterfaceException
788
+	 * @throws InvalidDataTypeException
789
+	 * @throws EE_Error
790
+	 */
791
+	public function e_date_and_time_range($dt_format = '', $tm_format = '', $conjunction = ' - ')
792
+	{
793
+		echo $this->date_and_time_range($dt_format, $tm_format, $conjunction);
794
+	}
795
+
796
+
797
+	/**
798
+	 * get start date and start time
799
+	 *
800
+	 * @param    string $dt_format - string representation of date format defaults to 'F j, Y'
801
+	 * @param    string $tm_format - string representation of time format defaults to 'g:i a'
802
+	 * @return    mixed    string on success, FALSE on fail
803
+	 * @throws ReflectionException
804
+	 * @throws InvalidArgumentException
805
+	 * @throws InvalidInterfaceException
806
+	 * @throws InvalidDataTypeException
807
+	 * @throws EE_Error
808
+	 */
809
+	public function start_date_and_time($dt_format = '', $tm_format = '')
810
+	{
811
+		return $this->_show_datetime('', 'start', $dt_format, $tm_format);
812
+	}
813
+
814
+
815
+	/**
816
+	 * @param string $dt_frmt
817
+	 * @param string $tm_format
818
+	 * @throws ReflectionException
819
+	 * @throws InvalidArgumentException
820
+	 * @throws InvalidInterfaceException
821
+	 * @throws InvalidDataTypeException
822
+	 * @throws EE_Error
823
+	 */
824
+	public function e_start_date_and_time($dt_frmt = '', $tm_format = '')
825
+	{
826
+		$this->_show_datetime('', 'start', $dt_frmt, $tm_format, true);
827
+	}
828
+
829
+
830
+	/**
831
+	 * Shows the length of the event (start to end time).
832
+	 * Can be shown in 'seconds','minutes','hours', or 'days'.
833
+	 * By default, rounds up. (So if you use 'days', and then event
834
+	 * only occurs for 1 hour, it will return 1 day).
835
+	 *
836
+	 * @param string $units 'seconds','minutes','hours','days'
837
+	 * @param bool   $round_up
838
+	 * @return float|int|mixed
839
+	 * @throws ReflectionException
840
+	 * @throws InvalidArgumentException
841
+	 * @throws InvalidInterfaceException
842
+	 * @throws InvalidDataTypeException
843
+	 * @throws EE_Error
844
+	 */
845
+	public function length($units = 'seconds', $round_up = false)
846
+	{
847
+		$start = $this->get_raw('DTT_EVT_start');
848
+		$end = $this->get_raw('DTT_EVT_end');
849
+		$length_in_units = $end - $start;
850
+		switch ($units) {
851
+			// NOTE: We purposefully don't use "break;" in order to chain the divisions
852
+			/** @noinspection PhpMissingBreakStatementInspection */
853
+			// phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
854
+			case 'days':
855
+				$length_in_units /= 24;
856
+			/** @noinspection PhpMissingBreakStatementInspection */
857
+			case 'hours':
858
+				// fall through is intentional
859
+				$length_in_units /= 60;
860
+			/** @noinspection PhpMissingBreakStatementInspection */
861
+			case 'minutes':
862
+				// fall through is intentional
863
+				$length_in_units /= 60;
864
+			case 'seconds':
865
+			default:
866
+				$length_in_units = ceil($length_in_units);
867
+		}
868
+		// phpcs:enable
869
+		if ($round_up) {
870
+			$length_in_units = max($length_in_units, 1);
871
+		}
872
+		return $length_in_units;
873
+	}
874
+
875
+
876
+	/**
877
+	 *        get end date and time
878
+	 *
879
+	 * @param string $dt_frmt   - string representation of date format defaults to 'F j, Y'
880
+	 * @param string $tm_format - string representation of time format defaults to 'g:i a'
881
+	 * @return    mixed                string on success, FALSE on fail
882
+	 * @throws ReflectionException
883
+	 * @throws InvalidArgumentException
884
+	 * @throws InvalidInterfaceException
885
+	 * @throws InvalidDataTypeException
886
+	 * @throws EE_Error
887
+	 */
888
+	public function end_date_and_time($dt_frmt = '', $tm_format = '')
889
+	{
890
+		return $this->_show_datetime('', 'end', $dt_frmt, $tm_format);
891
+	}
892
+
893
+
894
+	/**
895
+	 * @param string $dt_frmt
896
+	 * @param string $tm_format
897
+	 * @throws ReflectionException
898
+	 * @throws InvalidArgumentException
899
+	 * @throws InvalidInterfaceException
900
+	 * @throws InvalidDataTypeException
901
+	 * @throws EE_Error
902
+	 */
903
+	public function e_end_date_and_time($dt_frmt = '', $tm_format = '')
904
+	{
905
+		$this->_show_datetime('', 'end', $dt_frmt, $tm_format, true);
906
+	}
907
+
908
+
909
+	/**
910
+	 *        get start timestamp
911
+	 *
912
+	 * @return        int
913
+	 * @throws ReflectionException
914
+	 * @throws InvalidArgumentException
915
+	 * @throws InvalidInterfaceException
916
+	 * @throws InvalidDataTypeException
917
+	 * @throws EE_Error
918
+	 */
919
+	public function start()
920
+	{
921
+		return $this->get_raw('DTT_EVT_start');
922
+	}
923
+
924
+
925
+	/**
926
+	 *        get end timestamp
927
+	 *
928
+	 * @return        int
929
+	 * @throws ReflectionException
930
+	 * @throws InvalidArgumentException
931
+	 * @throws InvalidInterfaceException
932
+	 * @throws InvalidDataTypeException
933
+	 * @throws EE_Error
934
+	 */
935
+	public function end()
936
+	{
937
+		return $this->get_raw('DTT_EVT_end');
938
+	}
939
+
940
+
941
+	/**
942
+	 *    get the registration limit for this datetime slot
943
+	 *
944
+	 * @return        mixed        int on success, FALSE on fail
945
+	 * @throws ReflectionException
946
+	 * @throws InvalidArgumentException
947
+	 * @throws InvalidInterfaceException
948
+	 * @throws InvalidDataTypeException
949
+	 * @throws EE_Error
950
+	 */
951
+	public function reg_limit()
952
+	{
953
+		return $this->get_raw('DTT_reg_limit');
954
+	}
955
+
956
+
957
+	/**
958
+	 *    have the tickets sold for this datetime, met or exceed the registration limit ?
959
+	 *
960
+	 * @return        boolean
961
+	 * @throws ReflectionException
962
+	 * @throws InvalidArgumentException
963
+	 * @throws InvalidInterfaceException
964
+	 * @throws InvalidDataTypeException
965
+	 * @throws EE_Error
966
+	 */
967
+	public function sold_out()
968
+	{
969
+		return $this->reg_limit() > 0 && $this->sold() >= $this->reg_limit();
970
+	}
971
+
972
+
973
+	/**
974
+	 * return the total number of spaces remaining at this venue.
975
+	 * This only takes the venue's capacity into account, NOT the tickets available for sale
976
+	 *
977
+	 * @param bool $consider_tickets Whether to consider tickets remaining when determining if there are any spaces left
978
+	 *                               Because if all tickets attached to this datetime have no spaces left,
979
+	 *                               then this datetime IS effectively sold out.
980
+	 *                               However, there are cases where we just want to know the spaces
981
+	 *                               remaining for this particular datetime, hence the flag.
982
+	 * @return int
983
+	 * @throws ReflectionException
984
+	 * @throws InvalidArgumentException
985
+	 * @throws InvalidInterfaceException
986
+	 * @throws InvalidDataTypeException
987
+	 * @throws EE_Error
988
+	 */
989
+	public function spaces_remaining($consider_tickets = false)
990
+	{
991
+		// tickets remaining available for purchase
992
+		// no need for special checks for infinite, because if DTT_reg_limit == EE_INF, then EE_INF - x = EE_INF
993
+		$dtt_remaining = $this->reg_limit() - $this->sold_and_reserved();
994
+		if (! $consider_tickets) {
995
+			return $dtt_remaining;
996
+		}
997
+		$tickets_remaining = $this->tickets_remaining();
998
+		return min($dtt_remaining, $tickets_remaining);
999
+	}
1000
+
1001
+
1002
+	/**
1003
+	 * Counts the total tickets available
1004
+	 * (from all the different types of tickets which are available for this datetime).
1005
+	 *
1006
+	 * @param array $query_params like EEM_Base::get_all's
1007
+	 * @return int
1008
+	 * @throws ReflectionException
1009
+	 * @throws InvalidArgumentException
1010
+	 * @throws InvalidInterfaceException
1011
+	 * @throws InvalidDataTypeException
1012
+	 * @throws EE_Error
1013
+	 */
1014
+	public function tickets_remaining($query_params = array())
1015
+	{
1016
+		$sum = 0;
1017
+		$tickets = $this->tickets($query_params);
1018
+		if (! empty($tickets)) {
1019
+			foreach ($tickets as $ticket) {
1020
+				if ($ticket instanceof EE_Ticket) {
1021
+					// get the actual amount of tickets that can be sold
1022
+					$qty = $ticket->qty('saleable');
1023
+					if ($qty === EE_INF) {
1024
+						return EE_INF;
1025
+					}
1026
+					// no negative ticket quantities plz
1027
+					if ($qty > 0) {
1028
+						$sum += $qty;
1029
+					}
1030
+				}
1031
+			}
1032
+		}
1033
+		return $sum;
1034
+	}
1035
+
1036
+
1037
+	/**
1038
+	 * Gets the count of all the tickets available at this datetime (not ticket types)
1039
+	 * before any were sold
1040
+	 *
1041
+	 * @param array $query_params like EEM_Base::get_all's
1042
+	 * @return int
1043
+	 * @throws ReflectionException
1044
+	 * @throws InvalidArgumentException
1045
+	 * @throws InvalidInterfaceException
1046
+	 * @throws InvalidDataTypeException
1047
+	 * @throws EE_Error
1048
+	 */
1049
+	public function sum_tickets_initially_available($query_params = array())
1050
+	{
1051
+		return $this->sum_related('Ticket', $query_params, 'TKT_qty');
1052
+	}
1053
+
1054
+
1055
+	/**
1056
+	 * Returns the lesser-of-the two: spaces remaining at this datetime, or
1057
+	 * the total tickets remaining (a sum of the tickets remaining for each ticket type
1058
+	 * that is available for this datetime).
1059
+	 *
1060
+	 * @return int
1061
+	 * @throws ReflectionException
1062
+	 * @throws InvalidArgumentException
1063
+	 * @throws InvalidInterfaceException
1064
+	 * @throws InvalidDataTypeException
1065
+	 * @throws EE_Error
1066
+	 */
1067
+	public function total_tickets_available_at_this_datetime()
1068
+	{
1069
+		return $this->spaces_remaining(true);
1070
+	}
1071
+
1072
+
1073
+	/**
1074
+	 * This simply compares the internal dtt for the given string with NOW
1075
+	 * and determines if the date is upcoming or not.
1076
+	 *
1077
+	 * @access public
1078
+	 * @return boolean
1079
+	 * @throws ReflectionException
1080
+	 * @throws InvalidArgumentException
1081
+	 * @throws InvalidInterfaceException
1082
+	 * @throws InvalidDataTypeException
1083
+	 * @throws EE_Error
1084
+	 */
1085
+	public function is_upcoming()
1086
+	{
1087
+		return ($this->get_raw('DTT_EVT_start') > time());
1088
+	}
1089
+
1090
+
1091
+	/**
1092
+	 * This simply compares the internal datetime for the given string with NOW
1093
+	 * and returns if the date is active (i.e. start and end time)
1094
+	 *
1095
+	 * @return boolean
1096
+	 * @throws ReflectionException
1097
+	 * @throws InvalidArgumentException
1098
+	 * @throws InvalidInterfaceException
1099
+	 * @throws InvalidDataTypeException
1100
+	 * @throws EE_Error
1101
+	 */
1102
+	public function is_active()
1103
+	{
1104
+		return ($this->get_raw('DTT_EVT_start') < time() && $this->get_raw('DTT_EVT_end') > time());
1105
+	}
1106
+
1107
+
1108
+	/**
1109
+	 * This simply compares the internal dtt for the given string with NOW
1110
+	 * and determines if the date is expired or not.
1111
+	 *
1112
+	 * @return boolean
1113
+	 * @throws ReflectionException
1114
+	 * @throws InvalidArgumentException
1115
+	 * @throws InvalidInterfaceException
1116
+	 * @throws InvalidDataTypeException
1117
+	 * @throws EE_Error
1118
+	 */
1119
+	public function is_expired()
1120
+	{
1121
+		return ($this->get_raw('DTT_EVT_end') < time());
1122
+	}
1123
+
1124
+
1125
+	/**
1126
+	 * This returns the active status for whether an event is active, upcoming, or expired
1127
+	 *
1128
+	 * @return int return value will be one of the EE_Datetime status constants.
1129
+	 * @throws ReflectionException
1130
+	 * @throws InvalidArgumentException
1131
+	 * @throws InvalidInterfaceException
1132
+	 * @throws InvalidDataTypeException
1133
+	 * @throws EE_Error
1134
+	 */
1135
+	public function get_active_status()
1136
+	{
1137
+		$total_tickets_for_this_dtt = $this->total_tickets_available_at_this_datetime();
1138
+		if ($total_tickets_for_this_dtt !== false && $total_tickets_for_this_dtt < 1) {
1139
+			return EE_Datetime::sold_out;
1140
+		}
1141
+		if ($this->is_expired()) {
1142
+			return EE_Datetime::expired;
1143
+		}
1144
+		if ($this->is_upcoming()) {
1145
+			return EE_Datetime::upcoming;
1146
+		}
1147
+		if ($this->is_active()) {
1148
+			return EE_Datetime::active;
1149
+		}
1150
+		return null;
1151
+	}
1152
+
1153
+
1154
+	/**
1155
+	 * This returns a nice display name for the datetime that is contingent on the span between the dates and times.
1156
+	 *
1157
+	 * @param  boolean $use_dtt_name if TRUE then we'll use DTT->name() if its not empty.
1158
+	 * @return string
1159
+	 * @throws ReflectionException
1160
+	 * @throws InvalidArgumentException
1161
+	 * @throws InvalidInterfaceException
1162
+	 * @throws InvalidDataTypeException
1163
+	 * @throws EE_Error
1164
+	 */
1165
+	public function get_dtt_display_name($use_dtt_name = false)
1166
+	{
1167
+		if ($use_dtt_name) {
1168
+			$dtt_name = $this->name();
1169
+			if (! empty($dtt_name)) {
1170
+				return $dtt_name;
1171
+			}
1172
+		}
1173
+		// first condition is to see if the months are different
1174
+		if (date('m', $this->get_raw('DTT_EVT_start')) !== date('m', $this->get_raw('DTT_EVT_end'))
1175
+		) {
1176
+			$display_date = $this->start_date('M j\, Y g:i a') . ' - ' . $this->end_date('M j\, Y g:i a');
1177
+			// next condition is if its the same month but different day
1178
+		} else {
1179
+			if (date('m', $this->get_raw('DTT_EVT_start')) === date('m', $this->get_raw('DTT_EVT_end'))
1180
+				&& date('d', $this->get_raw('DTT_EVT_start')) !== date('d', $this->get_raw('DTT_EVT_end'))
1181
+			) {
1182
+				$display_date = $this->start_date('M j\, g:i a') . ' - ' . $this->end_date('M j\, g:i a Y');
1183
+			} else {
1184
+				$display_date = $this->start_date('F j\, Y')
1185
+								. ' @ '
1186
+								. $this->start_date('g:i a')
1187
+								. ' - '
1188
+								. $this->end_date('g:i a');
1189
+			}
1190
+		}
1191
+		return $display_date;
1192
+	}
1193
+
1194
+
1195
+	/**
1196
+	 * Gets all the tickets for this datetime
1197
+	 *
1198
+	 * @param array $query_params see EEM_Base::get_all()
1199
+	 * @return EE_Base_Class[]|EE_Ticket[]
1200
+	 * @throws ReflectionException
1201
+	 * @throws InvalidArgumentException
1202
+	 * @throws InvalidInterfaceException
1203
+	 * @throws InvalidDataTypeException
1204
+	 * @throws EE_Error
1205
+	 */
1206
+	public function tickets($query_params = array())
1207
+	{
1208
+		return $this->get_many_related('Ticket', $query_params);
1209
+	}
1210
+
1211
+
1212
+	/**
1213
+	 * Gets all the ticket types currently available for purchase
1214
+	 *
1215
+	 * @param array $query_params like EEM_Base::get_all's
1216
+	 * @return EE_Ticket[]
1217
+	 * @throws ReflectionException
1218
+	 * @throws InvalidArgumentException
1219
+	 * @throws InvalidInterfaceException
1220
+	 * @throws InvalidDataTypeException
1221
+	 * @throws EE_Error
1222
+	 */
1223
+	public function ticket_types_available_for_purchase($query_params = array())
1224
+	{
1225
+		// first check if datetime is valid
1226
+		if ($this->sold_out() || ! ($this->is_upcoming() || $this->is_active())) {
1227
+			return array();
1228
+		}
1229
+		if (empty($query_params)) {
1230
+			$query_params = array(
1231
+				array(
1232
+					'TKT_start_date' => array('<=', EEM_Ticket::instance()->current_time_for_query('TKT_start_date')),
1233
+					'TKT_end_date'   => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
1234
+					'TKT_deleted'    => false,
1235
+				),
1236
+			);
1237
+		}
1238
+		return $this->tickets($query_params);
1239
+	}
1240
+
1241
+
1242
+	/**
1243
+	 * @return EE_Base_Class|EE_Event
1244
+	 * @throws ReflectionException
1245
+	 * @throws InvalidArgumentException
1246
+	 * @throws InvalidInterfaceException
1247
+	 * @throws InvalidDataTypeException
1248
+	 * @throws EE_Error
1249
+	 */
1250
+	public function event()
1251
+	{
1252
+		return $this->get_first_related('Event');
1253
+	}
1254
+
1255
+
1256
+	/**
1257
+	 * Updates the DTT_sold attribute (and saves) based on the number of registrations for this datetime
1258
+	 * (via the tickets). into account
1259
+	 *
1260
+	 * @return int
1261
+	 * @throws ReflectionException
1262
+	 * @throws InvalidArgumentException
1263
+	 * @throws InvalidInterfaceException
1264
+	 * @throws InvalidDataTypeException
1265
+	 * @throws EE_Error
1266
+	 */
1267
+	public function update_sold()
1268
+	{
1269
+		$count_regs_for_this_datetime = EEM_Registration::instance()->count(
1270
+			array(
1271
+				array(
1272
+					'STS_ID'                 => EEM_Registration::status_id_approved,
1273
+					'REG_deleted'            => 0,
1274
+					'Ticket.Datetime.DTT_ID' => $this->ID(),
1275
+				),
1276
+			)
1277
+		);
1278
+		$sold = $this->sold();
1279
+		if ($count_regs_for_this_datetime > $sold) {
1280
+			$this->increase_sold($count_regs_for_this_datetime - $sold);
1281
+			$this->save();
1282
+		} elseif ($count_regs_for_this_datetime < $sold) {
1283
+			$this->decrease_sold($count_regs_for_this_datetime - $sold);
1284
+			$this->save();
1285
+		}
1286
+		return $count_regs_for_this_datetime;
1287
+	}
1288 1288
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -495,7 +495,7 @@  discard block
 block discarded – undo
495 495
             $date_or_time,
496 496
             $echo
497 497
         );
498
-        if (! $echo) {
498
+        if ( ! $echo) {
499 499
             return $dtt;
500 500
         }
501 501
         return '';
@@ -597,7 +597,7 @@  discard block
 block discarded – undo
597 597
             '&nbsp;',
598 598
             $this->get_i18n_datetime('DTT_EVT_end', $dt_frmt)
599 599
         );
600
-        return $start !== $end ? $start . $conjunction . $end : $start;
600
+        return $start !== $end ? $start.$conjunction.$end : $start;
601 601
     }
602 602
 
603 603
 
@@ -705,7 +705,7 @@  discard block
 block discarded – undo
705 705
             '&nbsp;',
706 706
             $this->get_i18n_datetime('DTT_EVT_end', $tm_format)
707 707
         );
708
-        return $start !== $end ? $start . $conjunction . $end : $start;
708
+        return $start !== $end ? $start.$conjunction.$end : $start;
709 709
     }
710 710
 
711 711
 
@@ -750,7 +750,7 @@  discard block
 block discarded – undo
750 750
     ) {
751 751
         $dt_format = ! empty($dt_format) ? $dt_format : $this->_dt_frmt;
752 752
         $tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
753
-        $full_format = $dt_format . $separator . $tm_format;
753
+        $full_format = $dt_format.$separator.$tm_format;
754 754
         // the range output depends on various conditions
755 755
         switch (true) {
756 756
             // start date timestamp and end date timestamp are the same.
@@ -991,7 +991,7 @@  discard block
 block discarded – undo
991 991
         // tickets remaining available for purchase
992 992
         // no need for special checks for infinite, because if DTT_reg_limit == EE_INF, then EE_INF - x = EE_INF
993 993
         $dtt_remaining = $this->reg_limit() - $this->sold_and_reserved();
994
-        if (! $consider_tickets) {
994
+        if ( ! $consider_tickets) {
995 995
             return $dtt_remaining;
996 996
         }
997 997
         $tickets_remaining = $this->tickets_remaining();
@@ -1015,7 +1015,7 @@  discard block
 block discarded – undo
1015 1015
     {
1016 1016
         $sum = 0;
1017 1017
         $tickets = $this->tickets($query_params);
1018
-        if (! empty($tickets)) {
1018
+        if ( ! empty($tickets)) {
1019 1019
             foreach ($tickets as $ticket) {
1020 1020
                 if ($ticket instanceof EE_Ticket) {
1021 1021
                     // get the actual amount of tickets that can be sold
@@ -1166,20 +1166,20 @@  discard block
 block discarded – undo
1166 1166
     {
1167 1167
         if ($use_dtt_name) {
1168 1168
             $dtt_name = $this->name();
1169
-            if (! empty($dtt_name)) {
1169
+            if ( ! empty($dtt_name)) {
1170 1170
                 return $dtt_name;
1171 1171
             }
1172 1172
         }
1173 1173
         // first condition is to see if the months are different
1174 1174
         if (date('m', $this->get_raw('DTT_EVT_start')) !== date('m', $this->get_raw('DTT_EVT_end'))
1175 1175
         ) {
1176
-            $display_date = $this->start_date('M j\, Y g:i a') . ' - ' . $this->end_date('M j\, Y g:i a');
1176
+            $display_date = $this->start_date('M j\, Y g:i a').' - '.$this->end_date('M j\, Y g:i a');
1177 1177
             // next condition is if its the same month but different day
1178 1178
         } else {
1179 1179
             if (date('m', $this->get_raw('DTT_EVT_start')) === date('m', $this->get_raw('DTT_EVT_end'))
1180 1180
                 && date('d', $this->get_raw('DTT_EVT_start')) !== date('d', $this->get_raw('DTT_EVT_end'))
1181 1181
             ) {
1182
-                $display_date = $this->start_date('M j\, g:i a') . ' - ' . $this->end_date('M j\, g:i a Y');
1182
+                $display_date = $this->start_date('M j\, g:i a').' - '.$this->end_date('M j\, g:i a Y');
1183 1183
             } else {
1184 1184
                 $display_date = $this->start_date('F j\, Y')
1185 1185
                                 . ' @ '
Please login to merge, or discard this patch.
core/db_classes/EE_Registration.class.php 2 patches
Indentation   +2067 added lines, -2067 removed lines patch added patch discarded remove patch
@@ -17,2071 +17,2071 @@
 block discarded – undo
17 17
 {
18 18
 
19 19
 
20
-    /**
21
-     * Used to reference when a registration has never been checked in.
22
-     *
23
-     * @deprecated use \EE_Checkin::status_checked_never instead
24
-     * @type int
25
-     */
26
-    const checkin_status_never = 2;
27
-
28
-    /**
29
-     * Used to reference when a registration has been checked in.
30
-     *
31
-     * @deprecated use \EE_Checkin::status_checked_in instead
32
-     * @type int
33
-     */
34
-    const checkin_status_in = 1;
35
-
36
-
37
-    /**
38
-     * Used to reference when a registration has been checked out.
39
-     *
40
-     * @deprecated use \EE_Checkin::status_checked_out instead
41
-     * @type int
42
-     */
43
-    const checkin_status_out = 0;
44
-
45
-
46
-    /**
47
-     * extra meta key for tracking reg status os trashed registrations
48
-     *
49
-     * @type string
50
-     */
51
-    const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
52
-
53
-
54
-    /**
55
-     * extra meta key for tracking if registration has reserved ticket
56
-     *
57
-     * @type string
58
-     */
59
-    const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
60
-
61
-
62
-    /**
63
-     * @param array  $props_n_values          incoming values
64
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
65
-     *                                        used.)
66
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
67
-     *                                        date_format and the second value is the time format
68
-     * @return EE_Registration
69
-     * @throws EE_Error
70
-     */
71
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
72
-    {
73
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
74
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
75
-    }
76
-
77
-
78
-    /**
79
-     * @param array  $props_n_values  incoming values from the database
80
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
-     *                                the website will be used.
82
-     * @return EE_Registration
83
-     */
84
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
85
-    {
86
-        return new self($props_n_values, true, $timezone);
87
-    }
88
-
89
-
90
-    /**
91
-     *        Set Event ID
92
-     *
93
-     * @param        int $EVT_ID Event ID
94
-     * @throws EE_Error
95
-     * @throws RuntimeException
96
-     */
97
-    public function set_event($EVT_ID = 0)
98
-    {
99
-        $this->set('EVT_ID', $EVT_ID);
100
-    }
101
-
102
-
103
-    /**
104
-     * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
105
-     * be routed to internal methods
106
-     *
107
-     * @param string $field_name
108
-     * @param mixed  $field_value
109
-     * @param bool   $use_default
110
-     * @throws EE_Error
111
-     * @throws EntityNotFoundException
112
-     * @throws InvalidArgumentException
113
-     * @throws InvalidDataTypeException
114
-     * @throws InvalidInterfaceException
115
-     * @throws ReflectionException
116
-     * @throws RuntimeException
117
-     */
118
-    public function set($field_name, $field_value, $use_default = false)
119
-    {
120
-        switch ($field_name) {
121
-            case 'REG_code':
122
-                if (! empty($field_value) && $this->reg_code() === null) {
123
-                    $this->set_reg_code($field_value, $use_default);
124
-                }
125
-                break;
126
-            case 'STS_ID':
127
-                $this->set_status($field_value, $use_default);
128
-                break;
129
-            default:
130
-                parent::set($field_name, $field_value, $use_default);
131
-        }
132
-    }
133
-
134
-
135
-    /**
136
-     * Set Status ID
137
-     * updates the registration status and ALSO...
138
-     * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
139
-     * calls release_registration_space() if the reg status changes FROM approved to any other reg status
140
-     *
141
-     * @param string                $new_STS_ID
142
-     * @param boolean               $use_default
143
-     * @param ContextInterface|null $context
144
-     * @return bool
145
-     * @throws EE_Error
146
-     * @throws EntityNotFoundException
147
-     * @throws InvalidArgumentException
148
-     * @throws ReflectionException
149
-     * @throws RuntimeException
150
-     * @throws InvalidDataTypeException
151
-     * @throws InvalidInterfaceException
152
-     */
153
-    public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
154
-    {
155
-        // get current REG_Status
156
-        $old_STS_ID = $this->status_ID();
157
-        // if status has changed
158
-        if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
159
-            && ! empty($old_STS_ID) // and that old status is actually set
160
-            && ! empty($new_STS_ID) // as well as the new status
161
-            && $this->ID() // ensure registration is in the db
162
-        ) {
163
-            // TO approved
164
-            if ($new_STS_ID === EEM_Registration::status_id_approved) {
165
-                // reserve a space by incrementing ticket and datetime sold values
166
-                $this->_reserve_registration_space();
167
-                do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
168
-                // OR FROM  approved
169
-            } elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
170
-                // release a space by decrementing ticket and datetime sold values
171
-                $this->_release_registration_space();
172
-                do_action(
173
-                    'AHEE__EE_Registration__set_status__from_approved',
174
-                    $this,
175
-                    $old_STS_ID,
176
-                    $new_STS_ID,
177
-                    $context
178
-                );
179
-            }
180
-            // update status
181
-            parent::set('STS_ID', $new_STS_ID, $use_default);
182
-            $this->_update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, $context);
183
-            if ($this->statusChangeUpdatesTransaction($context)) {
184
-                $this->updateTransactionAfterStatusChange();
185
-            }
186
-            do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
187
-            return true;
188
-        }
189
-        // even though the old value matches the new value, it's still good to
190
-        // allow the parent set method to have a say
191
-        parent::set('STS_ID', $new_STS_ID, $use_default);
192
-        return true;
193
-    }
194
-
195
-
196
-    /**
197
-     * update REGs and TXN when cancelled or declined registrations involved
198
-     *
199
-     * @param string                $new_STS_ID
200
-     * @param string                $old_STS_ID
201
-     * @param ContextInterface|null $context
202
-     * @throws EE_Error
203
-     * @throws InvalidArgumentException
204
-     * @throws InvalidDataTypeException
205
-     * @throws InvalidInterfaceException
206
-     * @throws ReflectionException
207
-     */
208
-    private function _update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
209
-    {
210
-        // these reg statuses should not be considered in any calculations involving monies owing
211
-        $closed_reg_statuses = EEM_Registration::closed_reg_statuses();
212
-        // true if registration has been cancelled or declined
213
-        $this->updateIfCanceled(
214
-            $closed_reg_statuses,
215
-            $new_STS_ID,
216
-            $old_STS_ID,
217
-            $context
218
-        );
219
-        $this->updateIfDeclined(
220
-            $closed_reg_statuses,
221
-            $new_STS_ID,
222
-            $old_STS_ID,
223
-            $context
224
-        );
225
-    }
226
-
227
-
228
-    /**
229
-     * update REGs and TXN when cancelled or declined registrations involved
230
-     *
231
-     * @param array                 $closed_reg_statuses
232
-     * @param string                $new_STS_ID
233
-     * @param string                $old_STS_ID
234
-     * @param ContextInterface|null $context
235
-     * @throws EE_Error
236
-     * @throws InvalidArgumentException
237
-     * @throws InvalidDataTypeException
238
-     * @throws InvalidInterfaceException
239
-     * @throws ReflectionException
240
-     */
241
-    private function updateIfCanceled(
242
-        array $closed_reg_statuses,
243
-        $new_STS_ID,
244
-        $old_STS_ID,
245
-        ContextInterface $context = null
246
-    ) {
247
-        // true if registration has been cancelled or declined
248
-        if (in_array($new_STS_ID, $closed_reg_statuses, true)
249
-            && ! in_array($old_STS_ID, $closed_reg_statuses, true)
250
-        ) {
251
-            /** @type EE_Registration_Processor $registration_processor */
252
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
253
-            /** @type EE_Transaction_Processor $transaction_processor */
254
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
255
-            // cancelled or declined registration
256
-            $registration_processor->update_registration_after_being_canceled_or_declined(
257
-                $this,
258
-                $closed_reg_statuses
259
-            );
260
-            $transaction_processor->update_transaction_after_canceled_or_declined_registration(
261
-                $this,
262
-                $closed_reg_statuses,
263
-                false
264
-            );
265
-            do_action(
266
-                'AHEE__EE_Registration__set_status__canceled_or_declined',
267
-                $this,
268
-                $old_STS_ID,
269
-                $new_STS_ID,
270
-                $context
271
-            );
272
-            return;
273
-        }
274
-    }
275
-
276
-
277
-    /**
278
-     * update REGs and TXN when cancelled or declined registrations involved
279
-     *
280
-     * @param array                 $closed_reg_statuses
281
-     * @param string                $new_STS_ID
282
-     * @param string                $old_STS_ID
283
-     * @param ContextInterface|null $context
284
-     * @throws EE_Error
285
-     * @throws InvalidArgumentException
286
-     * @throws InvalidDataTypeException
287
-     * @throws InvalidInterfaceException
288
-     * @throws ReflectionException
289
-     */
290
-    private function updateIfDeclined(
291
-        array $closed_reg_statuses,
292
-        $new_STS_ID,
293
-        $old_STS_ID,
294
-        ContextInterface $context = null
295
-    ) {
296
-        // true if reinstating cancelled or declined registration
297
-        if (in_array($old_STS_ID, $closed_reg_statuses, true)
298
-            && ! in_array($new_STS_ID, $closed_reg_statuses, true)
299
-        ) {
300
-            /** @type EE_Registration_Processor $registration_processor */
301
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
302
-            /** @type EE_Transaction_Processor $transaction_processor */
303
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
304
-            // reinstating cancelled or declined registration
305
-            $registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
306
-                $this,
307
-                $closed_reg_statuses
308
-            );
309
-            $transaction_processor->update_transaction_after_reinstating_canceled_registration(
310
-                $this,
311
-                $closed_reg_statuses,
312
-                false
313
-            );
314
-            do_action(
315
-                'AHEE__EE_Registration__set_status__after_reinstated',
316
-                $this,
317
-                $old_STS_ID,
318
-                $new_STS_ID,
319
-                $context
320
-            );
321
-        }
322
-    }
323
-
324
-
325
-    /**
326
-     * @param ContextInterface|null $context
327
-     * @return bool
328
-     */
329
-    private function statusChangeUpdatesTransaction(ContextInterface $context = null)
330
-    {
331
-        $contexts_that_do_not_update_transaction = (array) apply_filters(
332
-            'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
333
-            array('spco_reg_step_attendee_information_process_registrations'),
334
-            $context,
335
-            $this
336
-        );
337
-        return ! (
338
-            $context instanceof ContextInterface
339
-            && in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
340
-        );
341
-    }
342
-
343
-
344
-    /**
345
-     * @throws EE_Error
346
-     * @throws EntityNotFoundException
347
-     * @throws InvalidArgumentException
348
-     * @throws InvalidDataTypeException
349
-     * @throws InvalidInterfaceException
350
-     * @throws ReflectionException
351
-     * @throws RuntimeException
352
-     */
353
-    private function updateTransactionAfterStatusChange()
354
-    {
355
-        /** @type EE_Transaction_Payments $transaction_payments */
356
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
357
-        $transaction_payments->recalculate_transaction_total($this->transaction(), false);
358
-        $this->transaction()->update_status_based_on_total_paid(true);
359
-    }
360
-
361
-
362
-    /**
363
-     *        get Status ID
364
-     */
365
-    public function status_ID()
366
-    {
367
-        return $this->get('STS_ID');
368
-    }
369
-
370
-
371
-    /**
372
-     * Gets the ticket this registration is for
373
-     *
374
-     * @param boolean $include_archived whether to include archived tickets or not.
375
-     *
376
-     * @return EE_Ticket|EE_Base_Class
377
-     * @throws EE_Error
378
-     */
379
-    public function ticket($include_archived = true)
380
-    {
381
-        $query_params = array();
382
-        if ($include_archived) {
383
-            $query_params['default_where_conditions'] = 'none';
384
-        }
385
-        return $this->get_first_related('Ticket', $query_params);
386
-    }
387
-
388
-
389
-    /**
390
-     * Gets the event this registration is for
391
-     *
392
-     * @return EE_Event
393
-     * @throws EE_Error
394
-     * @throws EntityNotFoundException
395
-     */
396
-    public function event()
397
-    {
398
-        $event = $this->get_first_related('Event');
399
-        if (! $event instanceof \EE_Event) {
400
-            throw new EntityNotFoundException('Event ID', $this->event_ID());
401
-        }
402
-        return $event;
403
-    }
404
-
405
-
406
-    /**
407
-     * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
408
-     * with the author of the event this registration is for.
409
-     *
410
-     * @since 4.5.0
411
-     * @return int
412
-     * @throws EE_Error
413
-     * @throws EntityNotFoundException
414
-     */
415
-    public function wp_user()
416
-    {
417
-        $event = $this->event();
418
-        if ($event instanceof EE_Event) {
419
-            return $event->wp_user();
420
-        }
421
-        return 0;
422
-    }
423
-
424
-
425
-    /**
426
-     * increments this registration's related ticket sold and corresponding datetime sold values
427
-     *
428
-     * @return void
429
-     * @throws DomainException
430
-     * @throws EE_Error
431
-     * @throws EntityNotFoundException
432
-     * @throws InvalidArgumentException
433
-     * @throws InvalidDataTypeException
434
-     * @throws InvalidInterfaceException
435
-     * @throws ReflectionException
436
-     * @throws UnexpectedEntityException
437
-     */
438
-    private function _reserve_registration_space()
439
-    {
440
-        // reserved ticket and datetime counts will be decremented as sold counts are incremented
441
-        // so stop tracking that this reg has a ticket reserved
442
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
443
-        $ticket = $this->ticket();
444
-        $ticket->increase_sold();
445
-        $ticket->save();
446
-        // possibly set event status to sold out
447
-        $this->event()->perform_sold_out_status_check();
448
-    }
449
-
450
-
451
-    /**
452
-     * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
453
-     *
454
-     * @return void
455
-     * @throws DomainException
456
-     * @throws EE_Error
457
-     * @throws EntityNotFoundException
458
-     * @throws InvalidArgumentException
459
-     * @throws InvalidDataTypeException
460
-     * @throws InvalidInterfaceException
461
-     * @throws ReflectionException
462
-     * @throws UnexpectedEntityException
463
-     */
464
-    private function _release_registration_space()
465
-    {
466
-        $ticket = $this->ticket();
467
-        $ticket->decrease_sold();
468
-        $ticket->save();
469
-        // possibly change event status from sold out back to previous status
470
-        $this->event()->perform_sold_out_status_check();
471
-    }
472
-
473
-
474
-    /**
475
-     * tracks this registration's ticket reservation in extra meta
476
-     * and can increment related ticket reserved and corresponding datetime reserved values
477
-     *
478
-     * @param bool $update_ticket if true, will increment ticket and datetime reserved count
479
-     * @return void
480
-     * @throws EE_Error
481
-     * @throws InvalidArgumentException
482
-     * @throws InvalidDataTypeException
483
-     * @throws InvalidInterfaceException
484
-     * @throws ReflectionException
485
-     */
486
-    public function reserve_ticket($update_ticket = false, $source = 'unknown')
487
-    {
488
-        // only reserve ticket if space is not currently reserved
489
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
490
-            $this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
491
-            // IMPORTANT !!!
492
-            // although checking $update_ticket first would be more efficient,
493
-            // we NEED to ALWAYS call update_extra_meta(), which is why that is done first
494
-            if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true)
495
-                && $update_ticket
496
-            ) {
497
-                $ticket = $this->ticket();
498
-                $ticket->increase_reserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
499
-                $ticket->save();
500
-            }
501
-        }
502
-    }
503
-
504
-
505
-    /**
506
-     * stops tracking this registration's ticket reservation in extra meta
507
-     * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
508
-     *
509
-     * @param bool $update_ticket if true, will decrement ticket and datetime reserved count
510
-     * @return void
511
-     * @throws EE_Error
512
-     * @throws InvalidArgumentException
513
-     * @throws InvalidDataTypeException
514
-     * @throws InvalidInterfaceException
515
-     * @throws ReflectionException
516
-     */
517
-    public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
518
-    {
519
-        // only release ticket if space is currently reserved
520
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
521
-            $this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
522
-            // IMPORTANT !!!
523
-            // although checking $update_ticket first would be more efficient,
524
-            // we NEED to ALWAYS call update_extra_meta(), which is why that is done first
525
-            if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false)
526
-                && $update_ticket
527
-            ) {
528
-                $ticket = $this->ticket();
529
-                $ticket->decrease_reserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
530
-                $ticket->save();
531
-            }
532
-        }
533
-    }
534
-
535
-
536
-    /**
537
-     * Set Attendee ID
538
-     *
539
-     * @param        int $ATT_ID Attendee ID
540
-     * @throws EE_Error
541
-     * @throws RuntimeException
542
-     */
543
-    public function set_attendee_id($ATT_ID = 0)
544
-    {
545
-        $this->set('ATT_ID', $ATT_ID);
546
-    }
547
-
548
-
549
-    /**
550
-     *        Set Transaction ID
551
-     *
552
-     * @param        int $TXN_ID Transaction ID
553
-     * @throws EE_Error
554
-     * @throws RuntimeException
555
-     */
556
-    public function set_transaction_id($TXN_ID = 0)
557
-    {
558
-        $this->set('TXN_ID', $TXN_ID);
559
-    }
560
-
561
-
562
-    /**
563
-     *        Set Session
564
-     *
565
-     * @param    string $REG_session PHP Session ID
566
-     * @throws EE_Error
567
-     * @throws RuntimeException
568
-     */
569
-    public function set_session($REG_session = '')
570
-    {
571
-        $this->set('REG_session', $REG_session);
572
-    }
573
-
574
-
575
-    /**
576
-     *        Set Registration URL Link
577
-     *
578
-     * @param    string $REG_url_link Registration URL Link
579
-     * @throws EE_Error
580
-     * @throws RuntimeException
581
-     */
582
-    public function set_reg_url_link($REG_url_link = '')
583
-    {
584
-        $this->set('REG_url_link', $REG_url_link);
585
-    }
586
-
587
-
588
-    /**
589
-     *        Set Attendee Counter
590
-     *
591
-     * @param        int $REG_count Primary Attendee
592
-     * @throws EE_Error
593
-     * @throws RuntimeException
594
-     */
595
-    public function set_count($REG_count = 1)
596
-    {
597
-        $this->set('REG_count', $REG_count);
598
-    }
599
-
600
-
601
-    /**
602
-     *        Set Group Size
603
-     *
604
-     * @param        boolean $REG_group_size Group Registration
605
-     * @throws EE_Error
606
-     * @throws RuntimeException
607
-     */
608
-    public function set_group_size($REG_group_size = false)
609
-    {
610
-        $this->set('REG_group_size', $REG_group_size);
611
-    }
612
-
613
-
614
-    /**
615
-     *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
616
-     *    EEM_Registration::status_id_not_approved
617
-     *
618
-     * @return        boolean
619
-     */
620
-    public function is_not_approved()
621
-    {
622
-        return $this->status_ID() == EEM_Registration::status_id_not_approved ? true : false;
623
-    }
624
-
625
-
626
-    /**
627
-     *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
628
-     *    EEM_Registration::status_id_pending_payment
629
-     *
630
-     * @return        boolean
631
-     */
632
-    public function is_pending_payment()
633
-    {
634
-        return $this->status_ID() == EEM_Registration::status_id_pending_payment ? true : false;
635
-    }
636
-
637
-
638
-    /**
639
-     *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
640
-     *
641
-     * @return        boolean
642
-     */
643
-    public function is_approved()
644
-    {
645
-        return $this->status_ID() == EEM_Registration::status_id_approved ? true : false;
646
-    }
647
-
648
-
649
-    /**
650
-     *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
651
-     *
652
-     * @return        boolean
653
-     */
654
-    public function is_cancelled()
655
-    {
656
-        return $this->status_ID() == EEM_Registration::status_id_cancelled ? true : false;
657
-    }
658
-
659
-
660
-    /**
661
-     *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
662
-     *
663
-     * @return        boolean
664
-     */
665
-    public function is_declined()
666
-    {
667
-        return $this->status_ID() == EEM_Registration::status_id_declined ? true : false;
668
-    }
669
-
670
-
671
-    /**
672
-     *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
673
-     *    EEM_Registration::status_id_incomplete
674
-     *
675
-     * @return        boolean
676
-     */
677
-    public function is_incomplete()
678
-    {
679
-        return $this->status_ID() == EEM_Registration::status_id_incomplete ? true : false;
680
-    }
681
-
682
-
683
-    /**
684
-     *        Set Registration Date
685
-     *
686
-     * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
687
-     *                                                 Date
688
-     * @throws EE_Error
689
-     * @throws RuntimeException
690
-     */
691
-    public function set_reg_date($REG_date = false)
692
-    {
693
-        $this->set('REG_date', $REG_date);
694
-    }
695
-
696
-
697
-    /**
698
-     *    Set final price owing for this registration after all ticket/price modifications
699
-     *
700
-     * @access    public
701
-     * @param    float $REG_final_price
702
-     * @throws EE_Error
703
-     * @throws RuntimeException
704
-     */
705
-    public function set_final_price($REG_final_price = 0.00)
706
-    {
707
-        $this->set('REG_final_price', $REG_final_price);
708
-    }
709
-
710
-
711
-    /**
712
-     *    Set amount paid towards this registration's final price
713
-     *
714
-     * @access    public
715
-     * @param    float $REG_paid
716
-     * @throws EE_Error
717
-     * @throws RuntimeException
718
-     */
719
-    public function set_paid($REG_paid = 0.00)
720
-    {
721
-        $this->set('REG_paid', $REG_paid);
722
-    }
723
-
724
-
725
-    /**
726
-     *        Attendee Is Going
727
-     *
728
-     * @param        boolean $REG_att_is_going Attendee Is Going
729
-     * @throws EE_Error
730
-     * @throws RuntimeException
731
-     */
732
-    public function set_att_is_going($REG_att_is_going = false)
733
-    {
734
-        $this->set('REG_att_is_going', $REG_att_is_going);
735
-    }
736
-
737
-
738
-    /**
739
-     * Gets the related attendee
740
-     *
741
-     * @return EE_Attendee
742
-     * @throws EE_Error
743
-     */
744
-    public function attendee()
745
-    {
746
-        return $this->get_first_related('Attendee');
747
-    }
748
-
749
-
750
-    /**
751
-     *        get Event ID
752
-     */
753
-    public function event_ID()
754
-    {
755
-        return $this->get('EVT_ID');
756
-    }
757
-
758
-
759
-    /**
760
-     *        get Event ID
761
-     */
762
-    public function event_name()
763
-    {
764
-        $event = $this->event_obj();
765
-        if ($event) {
766
-            return $event->name();
767
-        } else {
768
-            return null;
769
-        }
770
-    }
771
-
772
-
773
-    /**
774
-     * Fetches the event this registration is for
775
-     *
776
-     * @return EE_Event
777
-     * @throws EE_Error
778
-     */
779
-    public function event_obj()
780
-    {
781
-        return $this->get_first_related('Event');
782
-    }
783
-
784
-
785
-    /**
786
-     *        get Attendee ID
787
-     */
788
-    public function attendee_ID()
789
-    {
790
-        return $this->get('ATT_ID');
791
-    }
792
-
793
-
794
-    /**
795
-     *        get PHP Session ID
796
-     */
797
-    public function session_ID()
798
-    {
799
-        return $this->get('REG_session');
800
-    }
801
-
802
-
803
-    /**
804
-     * Gets the string which represents the URL trigger for the receipt template in the message template system.
805
-     *
806
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
807
-     * @return string
808
-     */
809
-    public function receipt_url($messenger = 'html')
810
-    {
811
-
812
-        /**
813
-         * The below will be deprecated one version after this.  We check first if there is a custom receipt template
814
-         * already in use on old system.  If there is then we just return the standard url for it.
815
-         *
816
-         * @since 4.5.0
817
-         */
818
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
819
-        $has_custom = EEH_Template::locate_template(
820
-            $template_relative_path,
821
-            array(),
822
-            true,
823
-            true,
824
-            true
825
-        );
826
-
827
-        if ($has_custom) {
828
-            return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
829
-        }
830
-        return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
831
-    }
832
-
833
-
834
-    /**
835
-     * Gets the string which represents the URL trigger for the invoice template in the message template system.
836
-     *
837
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
838
-     * @return string
839
-     * @throws EE_Error
840
-     */
841
-    public function invoice_url($messenger = 'html')
842
-    {
843
-        /**
844
-         * The below will be deprecated one version after this.  We check first if there is a custom invoice template
845
-         * already in use on old system.  If there is then we just return the standard url for it.
846
-         *
847
-         * @since 4.5.0
848
-         */
849
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
850
-        $has_custom = EEH_Template::locate_template(
851
-            $template_relative_path,
852
-            array(),
853
-            true,
854
-            true,
855
-            true
856
-        );
857
-
858
-        if ($has_custom) {
859
-            if ($messenger == 'html') {
860
-                return $this->invoice_url('launch');
861
-            }
862
-            $route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
863
-
864
-            $query_args = array('ee' => $route, 'id' => $this->reg_url_link());
865
-            if ($messenger == 'html') {
866
-                $query_args['html'] = true;
867
-            }
868
-            return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
869
-        }
870
-        return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
871
-    }
872
-
873
-
874
-    /**
875
-     * get Registration URL Link
876
-     *
877
-     * @access public
878
-     * @return string
879
-     * @throws EE_Error
880
-     */
881
-    public function reg_url_link()
882
-    {
883
-        return (string) $this->get('REG_url_link');
884
-    }
885
-
886
-
887
-    /**
888
-     * Echoes out invoice_url()
889
-     *
890
-     * @param string $type 'download','launch', or 'html' (default is 'launch')
891
-     * @return void
892
-     * @throws EE_Error
893
-     */
894
-    public function e_invoice_url($type = 'launch')
895
-    {
896
-        echo $this->invoice_url($type);
897
-    }
898
-
899
-
900
-    /**
901
-     * Echoes out payment_overview_url
902
-     */
903
-    public function e_payment_overview_url()
904
-    {
905
-        echo $this->payment_overview_url();
906
-    }
907
-
908
-
909
-    /**
910
-     * Gets the URL for the checkout payment options reg step
911
-     * with this registration's REG_url_link added as a query parameter
912
-     *
913
-     * @param bool $clear_session Set to true when you want to clear the session on revisiting the
914
-     *                            payment overview url.
915
-     * @return string
916
-     * @throws InvalidInterfaceException
917
-     * @throws InvalidDataTypeException
918
-     * @throws EE_Error
919
-     * @throws InvalidArgumentException
920
-     */
921
-    public function payment_overview_url($clear_session = false)
922
-    {
923
-        return add_query_arg(
924
-            (array) apply_filters(
925
-                'FHEE__EE_Registration__payment_overview_url__query_args',
926
-                array(
927
-                    'e_reg_url_link' => $this->reg_url_link(),
928
-                    'step'           => 'payment_options',
929
-                    'revisit'        => true,
930
-                    'clear_session'  => (bool) $clear_session,
931
-                ),
932
-                $this
933
-            ),
934
-            EE_Registry::instance()->CFG->core->reg_page_url()
935
-        );
936
-    }
937
-
938
-
939
-    /**
940
-     * Gets the URL for the checkout attendee information reg step
941
-     * with this registration's REG_url_link added as a query parameter
942
-     *
943
-     * @return string
944
-     * @throws InvalidInterfaceException
945
-     * @throws InvalidDataTypeException
946
-     * @throws EE_Error
947
-     * @throws InvalidArgumentException
948
-     */
949
-    public function edit_attendee_information_url()
950
-    {
951
-        return add_query_arg(
952
-            (array) apply_filters(
953
-                'FHEE__EE_Registration__edit_attendee_information_url__query_args',
954
-                array(
955
-                    'e_reg_url_link' => $this->reg_url_link(),
956
-                    'step'           => 'attendee_information',
957
-                    'revisit'        => true,
958
-                ),
959
-                $this
960
-            ),
961
-            EE_Registry::instance()->CFG->core->reg_page_url()
962
-        );
963
-    }
964
-
965
-
966
-    /**
967
-     * Simply generates and returns the appropriate admin_url link to edit this registration
968
-     *
969
-     * @return string
970
-     * @throws EE_Error
971
-     */
972
-    public function get_admin_edit_url()
973
-    {
974
-        return EEH_URL::add_query_args_and_nonce(
975
-            array(
976
-                'page'    => 'espresso_registrations',
977
-                'action'  => 'view_registration',
978
-                '_REG_ID' => $this->ID(),
979
-            ),
980
-            admin_url('admin.php')
981
-        );
982
-    }
983
-
984
-
985
-    /**
986
-     *    is_primary_registrant?
987
-     */
988
-    public function is_primary_registrant()
989
-    {
990
-        return $this->get('REG_count') == 1 ? true : false;
991
-    }
992
-
993
-
994
-    /**
995
-     * This returns the primary registration object for this registration group (which may be this object).
996
-     *
997
-     * @return EE_Registration
998
-     * @throws EE_Error
999
-     */
1000
-    public function get_primary_registration()
1001
-    {
1002
-        if ($this->is_primary_registrant()) {
1003
-            return $this;
1004
-        }
1005
-
1006
-        // k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1007
-        /** @var EE_Registration $primary_registrant */
1008
-        $primary_registrant = EEM_Registration::instance()->get_one(
1009
-            array(
1010
-                array(
1011
-                    'TXN_ID'    => $this->transaction_ID(),
1012
-                    'REG_count' => 1,
1013
-                ),
1014
-            )
1015
-        );
1016
-        return $primary_registrant;
1017
-    }
1018
-
1019
-
1020
-    /**
1021
-     *        get  Attendee Number
1022
-     *
1023
-     * @access        public
1024
-     */
1025
-    public function count()
1026
-    {
1027
-        return $this->get('REG_count');
1028
-    }
1029
-
1030
-
1031
-    /**
1032
-     *        get Group Size
1033
-     */
1034
-    public function group_size()
1035
-    {
1036
-        return $this->get('REG_group_size');
1037
-    }
1038
-
1039
-
1040
-    /**
1041
-     *        get Registration Date
1042
-     */
1043
-    public function date()
1044
-    {
1045
-        return $this->get('REG_date');
1046
-    }
1047
-
1048
-
1049
-    /**
1050
-     * gets a pretty date
1051
-     *
1052
-     * @param string $date_format
1053
-     * @param string $time_format
1054
-     * @return string
1055
-     * @throws EE_Error
1056
-     */
1057
-    public function pretty_date($date_format = null, $time_format = null)
1058
-    {
1059
-        return $this->get_datetime('REG_date', $date_format, $time_format);
1060
-    }
1061
-
1062
-
1063
-    /**
1064
-     * final_price
1065
-     * the registration's share of the transaction total, so that the
1066
-     * sum of all the transaction's REG_final_prices equal the transaction's total
1067
-     *
1068
-     * @return float
1069
-     * @throws EE_Error
1070
-     */
1071
-    public function final_price()
1072
-    {
1073
-        return $this->get('REG_final_price');
1074
-    }
1075
-
1076
-
1077
-    /**
1078
-     * pretty_final_price
1079
-     *  final price as formatted string, with correct decimal places and currency symbol
1080
-     *
1081
-     * @return string
1082
-     * @throws EE_Error
1083
-     */
1084
-    public function pretty_final_price()
1085
-    {
1086
-        return $this->get_pretty('REG_final_price');
1087
-    }
1088
-
1089
-
1090
-    /**
1091
-     * get paid (yeah)
1092
-     *
1093
-     * @return float
1094
-     * @throws EE_Error
1095
-     */
1096
-    public function paid()
1097
-    {
1098
-        return $this->get('REG_paid');
1099
-    }
1100
-
1101
-
1102
-    /**
1103
-     * pretty_paid
1104
-     *
1105
-     * @return float
1106
-     * @throws EE_Error
1107
-     */
1108
-    public function pretty_paid()
1109
-    {
1110
-        return $this->get_pretty('REG_paid');
1111
-    }
1112
-
1113
-
1114
-    /**
1115
-     * owes_monies_and_can_pay
1116
-     * whether or not this registration has monies owing and it's' status allows payment
1117
-     *
1118
-     * @param array $requires_payment
1119
-     * @return bool
1120
-     * @throws EE_Error
1121
-     */
1122
-    public function owes_monies_and_can_pay($requires_payment = array())
1123
-    {
1124
-        // these reg statuses require payment (if event is not free)
1125
-        $requires_payment = ! empty($requires_payment)
1126
-            ? $requires_payment
1127
-            : EEM_Registration::reg_statuses_that_allow_payment();
1128
-        if (in_array($this->status_ID(), $requires_payment) &&
1129
-            $this->final_price() != 0 &&
1130
-            $this->final_price() != $this->paid()
1131
-        ) {
1132
-            return true;
1133
-        } else {
1134
-            return false;
1135
-        }
1136
-    }
1137
-
1138
-
1139
-    /**
1140
-     * Prints out the return value of $this->pretty_status()
1141
-     *
1142
-     * @param bool $show_icons
1143
-     * @return void
1144
-     * @throws EE_Error
1145
-     */
1146
-    public function e_pretty_status($show_icons = false)
1147
-    {
1148
-        echo $this->pretty_status($show_icons);
1149
-    }
1150
-
1151
-
1152
-    /**
1153
-     * Returns a nice version of the status for displaying to customers
1154
-     *
1155
-     * @param bool $show_icons
1156
-     * @return string
1157
-     * @throws EE_Error
1158
-     */
1159
-    public function pretty_status($show_icons = false)
1160
-    {
1161
-        $status = EEM_Status::instance()->localized_status(
1162
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1163
-            false,
1164
-            'sentence'
1165
-        );
1166
-        $icon = '';
1167
-        switch ($this->status_ID()) {
1168
-            case EEM_Registration::status_id_approved:
1169
-                $icon = $show_icons
1170
-                    ? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1171
-                    : '';
1172
-                break;
1173
-            case EEM_Registration::status_id_pending_payment:
1174
-                $icon = $show_icons
1175
-                    ? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1176
-                    : '';
1177
-                break;
1178
-            case EEM_Registration::status_id_not_approved:
1179
-                $icon = $show_icons
1180
-                    ? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1181
-                    : '';
1182
-                break;
1183
-            case EEM_Registration::status_id_cancelled:
1184
-                $icon = $show_icons
1185
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1186
-                    : '';
1187
-                break;
1188
-            case EEM_Registration::status_id_incomplete:
1189
-                $icon = $show_icons
1190
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1191
-                    : '';
1192
-                break;
1193
-            case EEM_Registration::status_id_declined:
1194
-                $icon = $show_icons
1195
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1196
-                    : '';
1197
-                break;
1198
-            case EEM_Registration::status_id_wait_list:
1199
-                $icon = $show_icons
1200
-                    ? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1201
-                    : '';
1202
-                break;
1203
-        }
1204
-        return $icon . $status[ $this->status_ID() ];
1205
-    }
1206
-
1207
-
1208
-    /**
1209
-     *        get Attendee Is Going
1210
-     */
1211
-    public function att_is_going()
1212
-    {
1213
-        return $this->get('REG_att_is_going');
1214
-    }
1215
-
1216
-
1217
-    /**
1218
-     * Gets related answers
1219
-     *
1220
-     * @param array $query_params like EEM_Base::get_all
1221
-     * @return EE_Answer[]
1222
-     * @throws EE_Error
1223
-     */
1224
-    public function answers($query_params = null)
1225
-    {
1226
-        return $this->get_many_related('Answer', $query_params);
1227
-    }
1228
-
1229
-
1230
-    /**
1231
-     * Gets the registration's answer value to the specified question
1232
-     * (either the question's ID or a question object)
1233
-     *
1234
-     * @param EE_Question|int $question
1235
-     * @param bool            $pretty_value
1236
-     * @return array|string if pretty_value= true, the result will always be a string
1237
-     * (because the answer might be an array of answer values, so passing pretty_value=true
1238
-     * will convert it into some kind of string)
1239
-     * @throws EE_Error
1240
-     */
1241
-    public function answer_value_to_question($question, $pretty_value = true)
1242
-    {
1243
-        $question_id = EEM_Question::instance()->ensure_is_ID($question);
1244
-        return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1245
-    }
1246
-
1247
-
1248
-    /**
1249
-     * question_groups
1250
-     * returns an array of EE_Question_Group objects for this registration
1251
-     *
1252
-     * @return EE_Question_Group[]
1253
-     * @throws EE_Error
1254
-     * @throws EntityNotFoundException
1255
-     */
1256
-    public function question_groups()
1257
-    {
1258
-        $question_groups = array();
1259
-        if ($this->event() instanceof EE_Event) {
1260
-            $question_groups = $this->event()->question_groups(
1261
-                array(
1262
-                    array(
1263
-                        'Event_Question_Group.EQG_primary' => $this->count() == 1 ? true : false,
1264
-                    ),
1265
-                    'order_by' => array('QSG_order' => 'ASC'),
1266
-                )
1267
-            );
1268
-        }
1269
-        return $question_groups;
1270
-    }
1271
-
1272
-
1273
-    /**
1274
-     * count_question_groups
1275
-     * returns a count of the number of EE_Question_Group objects for this registration
1276
-     *
1277
-     * @return int
1278
-     * @throws EE_Error
1279
-     * @throws EntityNotFoundException
1280
-     */
1281
-    public function count_question_groups()
1282
-    {
1283
-        $qg_count = 0;
1284
-        if ($this->event() instanceof EE_Event) {
1285
-            $qg_count = $this->event()->count_related(
1286
-                'Question_Group',
1287
-                array(
1288
-                    array(
1289
-                        'Event_Question_Group.EQG_primary' => $this->count() == 1 ? true : false,
1290
-                    ),
1291
-                )
1292
-            );
1293
-        }
1294
-        return $qg_count;
1295
-    }
1296
-
1297
-
1298
-    /**
1299
-     * Returns the registration date in the 'standard' string format
1300
-     * (function may be improved in the future to allow for different formats and timezones)
1301
-     *
1302
-     * @return string
1303
-     * @throws EE_Error
1304
-     */
1305
-    public function reg_date()
1306
-    {
1307
-        return $this->get_datetime('REG_date');
1308
-    }
1309
-
1310
-
1311
-    /**
1312
-     * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1313
-     * the ticket this registration purchased, or the datetime they have registered
1314
-     * to attend)
1315
-     *
1316
-     * @return EE_Datetime_Ticket
1317
-     * @throws EE_Error
1318
-     */
1319
-    public function datetime_ticket()
1320
-    {
1321
-        return $this->get_first_related('Datetime_Ticket');
1322
-    }
1323
-
1324
-
1325
-    /**
1326
-     * Sets the registration's datetime_ticket.
1327
-     *
1328
-     * @param EE_Datetime_Ticket $datetime_ticket
1329
-     * @return EE_Datetime_Ticket
1330
-     * @throws EE_Error
1331
-     */
1332
-    public function set_datetime_ticket($datetime_ticket)
1333
-    {
1334
-        return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1335
-    }
1336
-
1337
-    /**
1338
-     * Gets deleted
1339
-     *
1340
-     * @return bool
1341
-     * @throws EE_Error
1342
-     */
1343
-    public function deleted()
1344
-    {
1345
-        return $this->get('REG_deleted');
1346
-    }
1347
-
1348
-    /**
1349
-     * Sets deleted
1350
-     *
1351
-     * @param boolean $deleted
1352
-     * @return bool
1353
-     * @throws EE_Error
1354
-     * @throws RuntimeException
1355
-     */
1356
-    public function set_deleted($deleted)
1357
-    {
1358
-        if ($deleted) {
1359
-            $this->delete();
1360
-        } else {
1361
-            $this->restore();
1362
-        }
1363
-    }
1364
-
1365
-
1366
-    /**
1367
-     * Get the status object of this object
1368
-     *
1369
-     * @return EE_Status
1370
-     * @throws EE_Error
1371
-     */
1372
-    public function status_obj()
1373
-    {
1374
-        return $this->get_first_related('Status');
1375
-    }
1376
-
1377
-
1378
-    /**
1379
-     * Returns the number of times this registration has checked into any of the datetimes
1380
-     * its available for
1381
-     *
1382
-     * @return int
1383
-     * @throws EE_Error
1384
-     */
1385
-    public function count_checkins()
1386
-    {
1387
-        return $this->get_model()->count_related($this, 'Checkin');
1388
-    }
1389
-
1390
-
1391
-    /**
1392
-     * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1393
-     * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1394
-     *
1395
-     * @return int
1396
-     * @throws EE_Error
1397
-     */
1398
-    public function count_checkins_not_checkedout()
1399
-    {
1400
-        return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1401
-    }
1402
-
1403
-
1404
-    /**
1405
-     * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1406
-     *
1407
-     * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1408
-     * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1409
-     *                                          consider registration status as well as datetime access.
1410
-     * @return bool
1411
-     * @throws EE_Error
1412
-     */
1413
-    public function can_checkin($DTT_OR_ID, $check_approved = true)
1414
-    {
1415
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1416
-
1417
-        // first check registration status
1418
-        if (($check_approved && ! $this->is_approved()) || ! $DTT_ID) {
1419
-            return false;
1420
-        }
1421
-        // is there a datetime ticket that matches this dtt_ID?
1422
-        if (! (EEM_Datetime_Ticket::instance()->exists(
1423
-            array(
1424
-                array(
1425
-                    'TKT_ID' => $this->get('TKT_ID'),
1426
-                    'DTT_ID' => $DTT_ID,
1427
-                ),
1428
-            )
1429
-        ))
1430
-        ) {
1431
-            return false;
1432
-        }
1433
-
1434
-        // final check is against TKT_uses
1435
-        return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1436
-    }
1437
-
1438
-
1439
-    /**
1440
-     * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1441
-     * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1442
-     * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1443
-     * then return false.  Otherwise return true.
1444
-     *
1445
-     * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1446
-     * @return bool true means can checkin.  false means cannot checkin.
1447
-     * @throws EE_Error
1448
-     */
1449
-    public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1450
-    {
1451
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1452
-
1453
-        if (! $DTT_ID) {
1454
-            return false;
1455
-        }
1456
-
1457
-        $max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1458
-
1459
-        // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1460
-        // check-in or not.
1461
-        if (! $max_uses || $max_uses === EE_INF) {
1462
-            return true;
1463
-        }
1464
-
1465
-        // does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1466
-        // go ahead and toggle.
1467
-        if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1468
-            return true;
1469
-        }
1470
-
1471
-        // made it here so the last check is whether the number of checkins per unique datetime on this registration
1472
-        // disallows further check-ins.
1473
-        $count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1474
-            array(
1475
-                array(
1476
-                    'REG_ID' => $this->ID(),
1477
-                    'CHK_in' => true,
1478
-                ),
1479
-            ),
1480
-            'DTT_ID',
1481
-            true
1482
-        );
1483
-        // checkins have already reached their max number of uses
1484
-        // so registrant can NOT checkin
1485
-        if ($count_unique_dtt_checkins >= $max_uses) {
1486
-            EE_Error::add_error(
1487
-                esc_html__(
1488
-                    'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1489
-                    'event_espresso'
1490
-                ),
1491
-                __FILE__,
1492
-                __FUNCTION__,
1493
-                __LINE__
1494
-            );
1495
-            return false;
1496
-        }
1497
-        return true;
1498
-    }
1499
-
1500
-
1501
-    /**
1502
-     * toggle Check-in status for this registration
1503
-     * Check-ins are toggled in the following order:
1504
-     * never checked in -> checked in
1505
-     * checked in -> checked out
1506
-     * checked out -> checked in
1507
-     *
1508
-     * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1509
-     *                      If not included or null, then it is assumed latest datetime is being toggled.
1510
-     * @param bool $verify  If true then can_checkin() is used to verify whether the person
1511
-     *                      can be checked in or not.  Otherwise this forces change in checkin status.
1512
-     * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1513
-     * @throws EE_Error
1514
-     */
1515
-    public function toggle_checkin_status($DTT_ID = null, $verify = false)
1516
-    {
1517
-        if (empty($DTT_ID)) {
1518
-            $datetime = $this->get_latest_related_datetime();
1519
-            $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1520
-            // verify the registration can checkin for the given DTT_ID
1521
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1522
-            EE_Error::add_error(
1523
-                sprintf(
1524
-                    esc_html__(
1525
-                        'The given registration (ID:%1$d) can not be checked in to the given DTT_ID (%2$d), because the registration does not have access',
1526
-                        'event_espresso'
1527
-                    ),
1528
-                    $this->ID(),
1529
-                    $DTT_ID
1530
-                ),
1531
-                __FILE__,
1532
-                __FUNCTION__,
1533
-                __LINE__
1534
-            );
1535
-            return false;
1536
-        }
1537
-        $status_paths = array(
1538
-            EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1539
-            EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1540
-            EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1541
-        );
1542
-        // start by getting the current status so we know what status we'll be changing to.
1543
-        $cur_status = $this->check_in_status_for_datetime($DTT_ID, null);
1544
-        $status_to = $status_paths[ $cur_status ];
1545
-        // database only records true for checked IN or false for checked OUT
1546
-        // no record ( null ) means checked in NEVER, but we obviously don't save that
1547
-        $new_status = $status_to === EE_Checkin::status_checked_in ? true : false;
1548
-        // add relation - note Check-ins are always creating new rows
1549
-        // because we are keeping track of Check-ins over time.
1550
-        // Eventually we'll probably want to show a list table
1551
-        // for the individual Check-ins so that they can be managed.
1552
-        $checkin = EE_Checkin::new_instance(
1553
-            array(
1554
-                'REG_ID' => $this->ID(),
1555
-                'DTT_ID' => $DTT_ID,
1556
-                'CHK_in' => $new_status,
1557
-            )
1558
-        );
1559
-        // if the record could not be saved then return false
1560
-        if ($checkin->save() === 0) {
1561
-            if (WP_DEBUG) {
1562
-                global $wpdb;
1563
-                $error = sprintf(
1564
-                    esc_html__(
1565
-                        'Registration check in update failed because of the following database error: %1$s%2$s',
1566
-                        'event_espresso'
1567
-                    ),
1568
-                    '<br />',
1569
-                    $wpdb->last_error
1570
-                );
1571
-            } else {
1572
-                $error = esc_html__(
1573
-                    'Registration check in update failed because of an unknown database error',
1574
-                    'event_espresso'
1575
-                );
1576
-            }
1577
-            EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1578
-            return false;
1579
-        }
1580
-        return $status_to;
1581
-    }
1582
-
1583
-
1584
-    /**
1585
-     * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1586
-     * "Latest" is defined by the `DTT_EVT_start` column.
1587
-     *
1588
-     * @return EE_Datetime|null
1589
-     * @throws EE_Error
1590
-     */
1591
-    public function get_latest_related_datetime()
1592
-    {
1593
-        return EEM_Datetime::instance()->get_one(
1594
-            array(
1595
-                array(
1596
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1597
-                ),
1598
-                'order_by' => array('DTT_EVT_start' => 'DESC'),
1599
-            )
1600
-        );
1601
-    }
1602
-
1603
-
1604
-    /**
1605
-     * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1606
-     * "Earliest" is defined by the `DTT_EVT_start` column.
1607
-     *
1608
-     * @throws EE_Error
1609
-     */
1610
-    public function get_earliest_related_datetime()
1611
-    {
1612
-        return EEM_Datetime::instance()->get_one(
1613
-            array(
1614
-                array(
1615
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1616
-                ),
1617
-                'order_by' => array('DTT_EVT_start' => 'ASC'),
1618
-            )
1619
-        );
1620
-    }
1621
-
1622
-
1623
-    /**
1624
-     * This method simply returns the check-in status for this registration and the given datetime.
1625
-     * If neither the datetime nor the checkin values are provided as arguments,
1626
-     * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1627
-     *
1628
-     * @param  int       $DTT_ID  The ID of the datetime we're checking against
1629
-     *                            (if empty we'll get the primary datetime for
1630
-     *                            this registration (via event) and use it's ID);
1631
-     * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1632
-     *
1633
-     * @return int                Integer representing Check-in status.
1634
-     * @throws EE_Error
1635
-     */
1636
-    public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1637
-    {
1638
-        $checkin_query_params = array(
1639
-            'order_by' => array('CHK_timestamp' => 'DESC'),
1640
-        );
1641
-
1642
-        if ($DTT_ID > 0) {
1643
-            $checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1644
-        }
1645
-
1646
-        // get checkin object (if exists)
1647
-        $checkin = $checkin instanceof EE_Checkin
1648
-            ? $checkin
1649
-            : $this->get_first_related('Checkin', $checkin_query_params);
1650
-        if ($checkin instanceof EE_Checkin) {
1651
-            if ($checkin->get('CHK_in')) {
1652
-                return EE_Checkin::status_checked_in; // checked in
1653
-            }
1654
-            return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1655
-        }
1656
-        return EE_Checkin::status_checked_never; // never been checked in
1657
-    }
1658
-
1659
-
1660
-    /**
1661
-     * This method returns a localized message for the toggled Check-in message.
1662
-     *
1663
-     * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1664
-     *                     then it is assumed Check-in for primary datetime was toggled.
1665
-     * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1666
-     *                     message can be customized with the attendee name.
1667
-     * @return string internationalized message
1668
-     * @throws EE_Error
1669
-     */
1670
-    public function get_checkin_msg($DTT_ID, $error = false)
1671
-    {
1672
-        // let's get the attendee first so we can include the name of the attendee
1673
-        $attendee = $this->get_first_related('Attendee');
1674
-        if ($attendee instanceof EE_Attendee) {
1675
-            if ($error) {
1676
-                return sprintf(__("%s's check-in status was not changed.", "event_espresso"), $attendee->full_name());
1677
-            }
1678
-            $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1679
-            // what is the status message going to be?
1680
-            switch ($cur_status) {
1681
-                case EE_Checkin::status_checked_never:
1682
-                    return sprintf(
1683
-                        __("%s has been removed from Check-in records", "event_espresso"),
1684
-                        $attendee->full_name()
1685
-                    );
1686
-                    break;
1687
-                case EE_Checkin::status_checked_in:
1688
-                    return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1689
-                    break;
1690
-                case EE_Checkin::status_checked_out:
1691
-                    return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1692
-                    break;
1693
-            }
1694
-        }
1695
-        return esc_html__("The check-in status could not be determined.", "event_espresso");
1696
-    }
1697
-
1698
-
1699
-    /**
1700
-     * Returns the related EE_Transaction to this registration
1701
-     *
1702
-     * @return EE_Transaction
1703
-     * @throws EE_Error
1704
-     * @throws EntityNotFoundException
1705
-     */
1706
-    public function transaction()
1707
-    {
1708
-        $transaction = $this->get_first_related('Transaction');
1709
-        if (! $transaction instanceof \EE_Transaction) {
1710
-            throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1711
-        }
1712
-        return $transaction;
1713
-    }
1714
-
1715
-
1716
-    /**
1717
-     *        get Registration Code
1718
-     */
1719
-    public function reg_code()
1720
-    {
1721
-        return $this->get('REG_code');
1722
-    }
1723
-
1724
-
1725
-    /**
1726
-     *        get Transaction ID
1727
-     */
1728
-    public function transaction_ID()
1729
-    {
1730
-        return $this->get('TXN_ID');
1731
-    }
1732
-
1733
-
1734
-    /**
1735
-     * @return int
1736
-     * @throws EE_Error
1737
-     */
1738
-    public function ticket_ID()
1739
-    {
1740
-        return $this->get('TKT_ID');
1741
-    }
1742
-
1743
-
1744
-    /**
1745
-     *        Set Registration Code
1746
-     *
1747
-     * @access    public
1748
-     * @param    string  $REG_code Registration Code
1749
-     * @param    boolean $use_default
1750
-     * @throws EE_Error
1751
-     */
1752
-    public function set_reg_code($REG_code, $use_default = false)
1753
-    {
1754
-        if (empty($REG_code)) {
1755
-            EE_Error::add_error(
1756
-                esc_html__('REG_code can not be empty.', 'event_espresso'),
1757
-                __FILE__,
1758
-                __FUNCTION__,
1759
-                __LINE__
1760
-            );
1761
-            return;
1762
-        }
1763
-        if (! $this->reg_code()) {
1764
-            parent::set('REG_code', $REG_code, $use_default);
1765
-        } else {
1766
-            EE_Error::doing_it_wrong(
1767
-                __CLASS__ . '::' . __FUNCTION__,
1768
-                esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
1769
-                '4.6.0'
1770
-            );
1771
-        }
1772
-    }
1773
-
1774
-
1775
-    /**
1776
-     * Returns all other registrations in the same group as this registrant who have the same ticket option.
1777
-     * Note, if you want to just get all registrations in the same transaction (group), use:
1778
-     *    $registration->transaction()->registrations();
1779
-     *
1780
-     * @since 4.5.0
1781
-     * @return EE_Registration[] or empty array if this isn't a group registration.
1782
-     * @throws EE_Error
1783
-     */
1784
-    public function get_all_other_registrations_in_group()
1785
-    {
1786
-        if ($this->group_size() < 2) {
1787
-            return array();
1788
-        }
1789
-
1790
-        $query[0] = array(
1791
-            'TXN_ID' => $this->transaction_ID(),
1792
-            'REG_ID' => array('!=', $this->ID()),
1793
-            'TKT_ID' => $this->ticket_ID(),
1794
-        );
1795
-        /** @var EE_Registration[] $registrations */
1796
-        $registrations = $this->get_model()->get_all($query);
1797
-        return $registrations;
1798
-    }
1799
-
1800
-    /**
1801
-     * Return the link to the admin details for the object.
1802
-     *
1803
-     * @return string
1804
-     * @throws EE_Error
1805
-     */
1806
-    public function get_admin_details_link()
1807
-    {
1808
-        EE_Registry::instance()->load_helper('URL');
1809
-        return EEH_URL::add_query_args_and_nonce(
1810
-            array(
1811
-                'page'    => 'espresso_registrations',
1812
-                'action'  => 'view_registration',
1813
-                '_REG_ID' => $this->ID(),
1814
-            ),
1815
-            admin_url('admin.php')
1816
-        );
1817
-    }
1818
-
1819
-    /**
1820
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
1821
-     *
1822
-     * @return string
1823
-     * @throws EE_Error
1824
-     */
1825
-    public function get_admin_edit_link()
1826
-    {
1827
-        return $this->get_admin_details_link();
1828
-    }
1829
-
1830
-    /**
1831
-     * Returns the link to a settings page for the object.
1832
-     *
1833
-     * @return string
1834
-     * @throws EE_Error
1835
-     */
1836
-    public function get_admin_settings_link()
1837
-    {
1838
-        return $this->get_admin_details_link();
1839
-    }
1840
-
1841
-    /**
1842
-     * Returns the link to the "overview" for the object (typically the "list table" view).
1843
-     *
1844
-     * @return string
1845
-     */
1846
-    public function get_admin_overview_link()
1847
-    {
1848
-        EE_Registry::instance()->load_helper('URL');
1849
-        return EEH_URL::add_query_args_and_nonce(
1850
-            array(
1851
-                'page' => 'espresso_registrations',
1852
-            ),
1853
-            admin_url('admin.php')
1854
-        );
1855
-    }
1856
-
1857
-
1858
-    /**
1859
-     * @param array $query_params
1860
-     *
1861
-     * @return \EE_Registration[]
1862
-     * @throws EE_Error
1863
-     */
1864
-    public function payments($query_params = array())
1865
-    {
1866
-        return $this->get_many_related('Payment', $query_params);
1867
-    }
1868
-
1869
-
1870
-    /**
1871
-     * @param array $query_params
1872
-     *
1873
-     * @return \EE_Registration_Payment[]
1874
-     * @throws EE_Error
1875
-     */
1876
-    public function registration_payments($query_params = array())
1877
-    {
1878
-        return $this->get_many_related('Registration_Payment', $query_params);
1879
-    }
1880
-
1881
-
1882
-    /**
1883
-     * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
1884
-     * Note: if there are no payments on the registration there will be no payment method returned.
1885
-     *
1886
-     * @return EE_Payment_Method|null
1887
-     */
1888
-    public function payment_method()
1889
-    {
1890
-        return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
1891
-    }
1892
-
1893
-
1894
-    /**
1895
-     * @return \EE_Line_Item
1896
-     * @throws EntityNotFoundException
1897
-     * @throws EE_Error
1898
-     */
1899
-    public function ticket_line_item()
1900
-    {
1901
-        $ticket = $this->ticket();
1902
-        $transaction = $this->transaction();
1903
-        $line_item = null;
1904
-        $ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
1905
-            $transaction->total_line_item(),
1906
-            'Ticket',
1907
-            array($ticket->ID())
1908
-        );
1909
-        foreach ($ticket_line_items as $ticket_line_item) {
1910
-            if ($ticket_line_item instanceof \EE_Line_Item
1911
-                && $ticket_line_item->OBJ_type() === 'Ticket'
1912
-                && $ticket_line_item->OBJ_ID() === $ticket->ID()
1913
-            ) {
1914
-                $line_item = $ticket_line_item;
1915
-                break;
1916
-            }
1917
-        }
1918
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1919
-            throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
1920
-        }
1921
-        return $line_item;
1922
-    }
1923
-
1924
-
1925
-    /**
1926
-     * Soft Deletes this model object.
1927
-     *
1928
-     * @return boolean | int
1929
-     * @throws RuntimeException
1930
-     * @throws EE_Error
1931
-     */
1932
-    public function delete()
1933
-    {
1934
-        if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
1935
-            $this->set_status(EEM_Registration::status_id_cancelled);
1936
-        }
1937
-        return parent::delete();
1938
-    }
1939
-
1940
-
1941
-    /**
1942
-     * Restores whatever the previous status was on a registration before it was trashed (if possible)
1943
-     *
1944
-     * @throws EE_Error
1945
-     * @throws RuntimeException
1946
-     */
1947
-    public function restore()
1948
-    {
1949
-        $previous_status = $this->get_extra_meta(
1950
-            EE_Registration::PRE_TRASH_REG_STATUS_KEY,
1951
-            true,
1952
-            EEM_Registration::status_id_cancelled
1953
-        );
1954
-        if ($previous_status) {
1955
-            $this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
1956
-            $this->set_status($previous_status);
1957
-        }
1958
-        return parent::restore();
1959
-    }
1960
-
1961
-
1962
-    /**
1963
-     * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
1964
-     *
1965
-     * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
1966
-     *                                           depending on whether the reg status changes to or from "Approved"
1967
-     * @return boolean whether the Registration status was updated
1968
-     * @throws EE_Error
1969
-     * @throws RuntimeException
1970
-     */
1971
-    public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
1972
-    {
1973
-        $paid = $this->paid();
1974
-        $price = $this->final_price();
1975
-        switch (true) {
1976
-            // overpaid or paid
1977
-            case EEH_Money::compare_floats($paid, $price, '>'):
1978
-            case EEH_Money::compare_floats($paid, $price):
1979
-                $new_status = EEM_Registration::status_id_approved;
1980
-                break;
1981
-            //  underpaid
1982
-            case EEH_Money::compare_floats($paid, $price, '<'):
1983
-                $new_status = EEM_Registration::status_id_pending_payment;
1984
-                break;
1985
-            // uhhh Houston...
1986
-            default:
1987
-                throw new RuntimeException(
1988
-                    esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
1989
-                );
1990
-        }
1991
-        if ($new_status !== $this->status_ID()) {
1992
-            if ($trigger_set_status_logic) {
1993
-                return $this->set_status($new_status);
1994
-            }
1995
-            parent::set('STS_ID', $new_status);
1996
-            return true;
1997
-        }
1998
-        return false;
1999
-    }
2000
-
2001
-
2002
-    /*************************** DEPRECATED ***************************/
2003
-
2004
-
2005
-    /**
2006
-     * @deprecated
2007
-     * @since     4.7.0
2008
-     * @access    public
2009
-     */
2010
-    public function price_paid()
2011
-    {
2012
-        EE_Error::doing_it_wrong(
2013
-            'EE_Registration::price_paid()',
2014
-            esc_html__(
2015
-                'This method is deprecated, please use EE_Registration::final_price() instead.',
2016
-                'event_espresso'
2017
-            ),
2018
-            '4.7.0'
2019
-        );
2020
-        return $this->final_price();
2021
-    }
2022
-
2023
-
2024
-    /**
2025
-     * @deprecated
2026
-     * @since     4.7.0
2027
-     * @access    public
2028
-     * @param    float $REG_final_price
2029
-     * @throws EE_Error
2030
-     * @throws RuntimeException
2031
-     */
2032
-    public function set_price_paid($REG_final_price = 0.00)
2033
-    {
2034
-        EE_Error::doing_it_wrong(
2035
-            'EE_Registration::set_price_paid()',
2036
-            esc_html__(
2037
-                'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2038
-                'event_espresso'
2039
-            ),
2040
-            '4.7.0'
2041
-        );
2042
-        $this->set_final_price($REG_final_price);
2043
-    }
2044
-
2045
-
2046
-    /**
2047
-     * @deprecated
2048
-     * @since 4.7.0
2049
-     * @return string
2050
-     * @throws EE_Error
2051
-     */
2052
-    public function pretty_price_paid()
2053
-    {
2054
-        EE_Error::doing_it_wrong(
2055
-            'EE_Registration::pretty_price_paid()',
2056
-            esc_html__(
2057
-                'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2058
-                'event_espresso'
2059
-            ),
2060
-            '4.7.0'
2061
-        );
2062
-        return $this->pretty_final_price();
2063
-    }
2064
-
2065
-
2066
-    /**
2067
-     * Gets the primary datetime related to this registration via the related Event to this registration
2068
-     *
2069
-     * @deprecated 4.9.17
2070
-     * @return EE_Datetime
2071
-     * @throws EE_Error
2072
-     * @throws EntityNotFoundException
2073
-     */
2074
-    public function get_related_primary_datetime()
2075
-    {
2076
-        EE_Error::doing_it_wrong(
2077
-            __METHOD__,
2078
-            esc_html__(
2079
-                'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2080
-                'event_espresso'
2081
-            ),
2082
-            '4.9.17',
2083
-            '5.0.0'
2084
-        );
2085
-        return $this->event()->primary_datetime();
2086
-    }
20
+	/**
21
+	 * Used to reference when a registration has never been checked in.
22
+	 *
23
+	 * @deprecated use \EE_Checkin::status_checked_never instead
24
+	 * @type int
25
+	 */
26
+	const checkin_status_never = 2;
27
+
28
+	/**
29
+	 * Used to reference when a registration has been checked in.
30
+	 *
31
+	 * @deprecated use \EE_Checkin::status_checked_in instead
32
+	 * @type int
33
+	 */
34
+	const checkin_status_in = 1;
35
+
36
+
37
+	/**
38
+	 * Used to reference when a registration has been checked out.
39
+	 *
40
+	 * @deprecated use \EE_Checkin::status_checked_out instead
41
+	 * @type int
42
+	 */
43
+	const checkin_status_out = 0;
44
+
45
+
46
+	/**
47
+	 * extra meta key for tracking reg status os trashed registrations
48
+	 *
49
+	 * @type string
50
+	 */
51
+	const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
52
+
53
+
54
+	/**
55
+	 * extra meta key for tracking if registration has reserved ticket
56
+	 *
57
+	 * @type string
58
+	 */
59
+	const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
60
+
61
+
62
+	/**
63
+	 * @param array  $props_n_values          incoming values
64
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
65
+	 *                                        used.)
66
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
67
+	 *                                        date_format and the second value is the time format
68
+	 * @return EE_Registration
69
+	 * @throws EE_Error
70
+	 */
71
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
72
+	{
73
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
74
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
75
+	}
76
+
77
+
78
+	/**
79
+	 * @param array  $props_n_values  incoming values from the database
80
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
+	 *                                the website will be used.
82
+	 * @return EE_Registration
83
+	 */
84
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
85
+	{
86
+		return new self($props_n_values, true, $timezone);
87
+	}
88
+
89
+
90
+	/**
91
+	 *        Set Event ID
92
+	 *
93
+	 * @param        int $EVT_ID Event ID
94
+	 * @throws EE_Error
95
+	 * @throws RuntimeException
96
+	 */
97
+	public function set_event($EVT_ID = 0)
98
+	{
99
+		$this->set('EVT_ID', $EVT_ID);
100
+	}
101
+
102
+
103
+	/**
104
+	 * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
105
+	 * be routed to internal methods
106
+	 *
107
+	 * @param string $field_name
108
+	 * @param mixed  $field_value
109
+	 * @param bool   $use_default
110
+	 * @throws EE_Error
111
+	 * @throws EntityNotFoundException
112
+	 * @throws InvalidArgumentException
113
+	 * @throws InvalidDataTypeException
114
+	 * @throws InvalidInterfaceException
115
+	 * @throws ReflectionException
116
+	 * @throws RuntimeException
117
+	 */
118
+	public function set($field_name, $field_value, $use_default = false)
119
+	{
120
+		switch ($field_name) {
121
+			case 'REG_code':
122
+				if (! empty($field_value) && $this->reg_code() === null) {
123
+					$this->set_reg_code($field_value, $use_default);
124
+				}
125
+				break;
126
+			case 'STS_ID':
127
+				$this->set_status($field_value, $use_default);
128
+				break;
129
+			default:
130
+				parent::set($field_name, $field_value, $use_default);
131
+		}
132
+	}
133
+
134
+
135
+	/**
136
+	 * Set Status ID
137
+	 * updates the registration status and ALSO...
138
+	 * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
139
+	 * calls release_registration_space() if the reg status changes FROM approved to any other reg status
140
+	 *
141
+	 * @param string                $new_STS_ID
142
+	 * @param boolean               $use_default
143
+	 * @param ContextInterface|null $context
144
+	 * @return bool
145
+	 * @throws EE_Error
146
+	 * @throws EntityNotFoundException
147
+	 * @throws InvalidArgumentException
148
+	 * @throws ReflectionException
149
+	 * @throws RuntimeException
150
+	 * @throws InvalidDataTypeException
151
+	 * @throws InvalidInterfaceException
152
+	 */
153
+	public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
154
+	{
155
+		// get current REG_Status
156
+		$old_STS_ID = $this->status_ID();
157
+		// if status has changed
158
+		if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
159
+			&& ! empty($old_STS_ID) // and that old status is actually set
160
+			&& ! empty($new_STS_ID) // as well as the new status
161
+			&& $this->ID() // ensure registration is in the db
162
+		) {
163
+			// TO approved
164
+			if ($new_STS_ID === EEM_Registration::status_id_approved) {
165
+				// reserve a space by incrementing ticket and datetime sold values
166
+				$this->_reserve_registration_space();
167
+				do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
168
+				// OR FROM  approved
169
+			} elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
170
+				// release a space by decrementing ticket and datetime sold values
171
+				$this->_release_registration_space();
172
+				do_action(
173
+					'AHEE__EE_Registration__set_status__from_approved',
174
+					$this,
175
+					$old_STS_ID,
176
+					$new_STS_ID,
177
+					$context
178
+				);
179
+			}
180
+			// update status
181
+			parent::set('STS_ID', $new_STS_ID, $use_default);
182
+			$this->_update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, $context);
183
+			if ($this->statusChangeUpdatesTransaction($context)) {
184
+				$this->updateTransactionAfterStatusChange();
185
+			}
186
+			do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
187
+			return true;
188
+		}
189
+		// even though the old value matches the new value, it's still good to
190
+		// allow the parent set method to have a say
191
+		parent::set('STS_ID', $new_STS_ID, $use_default);
192
+		return true;
193
+	}
194
+
195
+
196
+	/**
197
+	 * update REGs and TXN when cancelled or declined registrations involved
198
+	 *
199
+	 * @param string                $new_STS_ID
200
+	 * @param string                $old_STS_ID
201
+	 * @param ContextInterface|null $context
202
+	 * @throws EE_Error
203
+	 * @throws InvalidArgumentException
204
+	 * @throws InvalidDataTypeException
205
+	 * @throws InvalidInterfaceException
206
+	 * @throws ReflectionException
207
+	 */
208
+	private function _update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
209
+	{
210
+		// these reg statuses should not be considered in any calculations involving monies owing
211
+		$closed_reg_statuses = EEM_Registration::closed_reg_statuses();
212
+		// true if registration has been cancelled or declined
213
+		$this->updateIfCanceled(
214
+			$closed_reg_statuses,
215
+			$new_STS_ID,
216
+			$old_STS_ID,
217
+			$context
218
+		);
219
+		$this->updateIfDeclined(
220
+			$closed_reg_statuses,
221
+			$new_STS_ID,
222
+			$old_STS_ID,
223
+			$context
224
+		);
225
+	}
226
+
227
+
228
+	/**
229
+	 * update REGs and TXN when cancelled or declined registrations involved
230
+	 *
231
+	 * @param array                 $closed_reg_statuses
232
+	 * @param string                $new_STS_ID
233
+	 * @param string                $old_STS_ID
234
+	 * @param ContextInterface|null $context
235
+	 * @throws EE_Error
236
+	 * @throws InvalidArgumentException
237
+	 * @throws InvalidDataTypeException
238
+	 * @throws InvalidInterfaceException
239
+	 * @throws ReflectionException
240
+	 */
241
+	private function updateIfCanceled(
242
+		array $closed_reg_statuses,
243
+		$new_STS_ID,
244
+		$old_STS_ID,
245
+		ContextInterface $context = null
246
+	) {
247
+		// true if registration has been cancelled or declined
248
+		if (in_array($new_STS_ID, $closed_reg_statuses, true)
249
+			&& ! in_array($old_STS_ID, $closed_reg_statuses, true)
250
+		) {
251
+			/** @type EE_Registration_Processor $registration_processor */
252
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
253
+			/** @type EE_Transaction_Processor $transaction_processor */
254
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
255
+			// cancelled or declined registration
256
+			$registration_processor->update_registration_after_being_canceled_or_declined(
257
+				$this,
258
+				$closed_reg_statuses
259
+			);
260
+			$transaction_processor->update_transaction_after_canceled_or_declined_registration(
261
+				$this,
262
+				$closed_reg_statuses,
263
+				false
264
+			);
265
+			do_action(
266
+				'AHEE__EE_Registration__set_status__canceled_or_declined',
267
+				$this,
268
+				$old_STS_ID,
269
+				$new_STS_ID,
270
+				$context
271
+			);
272
+			return;
273
+		}
274
+	}
275
+
276
+
277
+	/**
278
+	 * update REGs and TXN when cancelled or declined registrations involved
279
+	 *
280
+	 * @param array                 $closed_reg_statuses
281
+	 * @param string                $new_STS_ID
282
+	 * @param string                $old_STS_ID
283
+	 * @param ContextInterface|null $context
284
+	 * @throws EE_Error
285
+	 * @throws InvalidArgumentException
286
+	 * @throws InvalidDataTypeException
287
+	 * @throws InvalidInterfaceException
288
+	 * @throws ReflectionException
289
+	 */
290
+	private function updateIfDeclined(
291
+		array $closed_reg_statuses,
292
+		$new_STS_ID,
293
+		$old_STS_ID,
294
+		ContextInterface $context = null
295
+	) {
296
+		// true if reinstating cancelled or declined registration
297
+		if (in_array($old_STS_ID, $closed_reg_statuses, true)
298
+			&& ! in_array($new_STS_ID, $closed_reg_statuses, true)
299
+		) {
300
+			/** @type EE_Registration_Processor $registration_processor */
301
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
302
+			/** @type EE_Transaction_Processor $transaction_processor */
303
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
304
+			// reinstating cancelled or declined registration
305
+			$registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
306
+				$this,
307
+				$closed_reg_statuses
308
+			);
309
+			$transaction_processor->update_transaction_after_reinstating_canceled_registration(
310
+				$this,
311
+				$closed_reg_statuses,
312
+				false
313
+			);
314
+			do_action(
315
+				'AHEE__EE_Registration__set_status__after_reinstated',
316
+				$this,
317
+				$old_STS_ID,
318
+				$new_STS_ID,
319
+				$context
320
+			);
321
+		}
322
+	}
323
+
324
+
325
+	/**
326
+	 * @param ContextInterface|null $context
327
+	 * @return bool
328
+	 */
329
+	private function statusChangeUpdatesTransaction(ContextInterface $context = null)
330
+	{
331
+		$contexts_that_do_not_update_transaction = (array) apply_filters(
332
+			'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
333
+			array('spco_reg_step_attendee_information_process_registrations'),
334
+			$context,
335
+			$this
336
+		);
337
+		return ! (
338
+			$context instanceof ContextInterface
339
+			&& in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
340
+		);
341
+	}
342
+
343
+
344
+	/**
345
+	 * @throws EE_Error
346
+	 * @throws EntityNotFoundException
347
+	 * @throws InvalidArgumentException
348
+	 * @throws InvalidDataTypeException
349
+	 * @throws InvalidInterfaceException
350
+	 * @throws ReflectionException
351
+	 * @throws RuntimeException
352
+	 */
353
+	private function updateTransactionAfterStatusChange()
354
+	{
355
+		/** @type EE_Transaction_Payments $transaction_payments */
356
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
357
+		$transaction_payments->recalculate_transaction_total($this->transaction(), false);
358
+		$this->transaction()->update_status_based_on_total_paid(true);
359
+	}
360
+
361
+
362
+	/**
363
+	 *        get Status ID
364
+	 */
365
+	public function status_ID()
366
+	{
367
+		return $this->get('STS_ID');
368
+	}
369
+
370
+
371
+	/**
372
+	 * Gets the ticket this registration is for
373
+	 *
374
+	 * @param boolean $include_archived whether to include archived tickets or not.
375
+	 *
376
+	 * @return EE_Ticket|EE_Base_Class
377
+	 * @throws EE_Error
378
+	 */
379
+	public function ticket($include_archived = true)
380
+	{
381
+		$query_params = array();
382
+		if ($include_archived) {
383
+			$query_params['default_where_conditions'] = 'none';
384
+		}
385
+		return $this->get_first_related('Ticket', $query_params);
386
+	}
387
+
388
+
389
+	/**
390
+	 * Gets the event this registration is for
391
+	 *
392
+	 * @return EE_Event
393
+	 * @throws EE_Error
394
+	 * @throws EntityNotFoundException
395
+	 */
396
+	public function event()
397
+	{
398
+		$event = $this->get_first_related('Event');
399
+		if (! $event instanceof \EE_Event) {
400
+			throw new EntityNotFoundException('Event ID', $this->event_ID());
401
+		}
402
+		return $event;
403
+	}
404
+
405
+
406
+	/**
407
+	 * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
408
+	 * with the author of the event this registration is for.
409
+	 *
410
+	 * @since 4.5.0
411
+	 * @return int
412
+	 * @throws EE_Error
413
+	 * @throws EntityNotFoundException
414
+	 */
415
+	public function wp_user()
416
+	{
417
+		$event = $this->event();
418
+		if ($event instanceof EE_Event) {
419
+			return $event->wp_user();
420
+		}
421
+		return 0;
422
+	}
423
+
424
+
425
+	/**
426
+	 * increments this registration's related ticket sold and corresponding datetime sold values
427
+	 *
428
+	 * @return void
429
+	 * @throws DomainException
430
+	 * @throws EE_Error
431
+	 * @throws EntityNotFoundException
432
+	 * @throws InvalidArgumentException
433
+	 * @throws InvalidDataTypeException
434
+	 * @throws InvalidInterfaceException
435
+	 * @throws ReflectionException
436
+	 * @throws UnexpectedEntityException
437
+	 */
438
+	private function _reserve_registration_space()
439
+	{
440
+		// reserved ticket and datetime counts will be decremented as sold counts are incremented
441
+		// so stop tracking that this reg has a ticket reserved
442
+		$this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
443
+		$ticket = $this->ticket();
444
+		$ticket->increase_sold();
445
+		$ticket->save();
446
+		// possibly set event status to sold out
447
+		$this->event()->perform_sold_out_status_check();
448
+	}
449
+
450
+
451
+	/**
452
+	 * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
453
+	 *
454
+	 * @return void
455
+	 * @throws DomainException
456
+	 * @throws EE_Error
457
+	 * @throws EntityNotFoundException
458
+	 * @throws InvalidArgumentException
459
+	 * @throws InvalidDataTypeException
460
+	 * @throws InvalidInterfaceException
461
+	 * @throws ReflectionException
462
+	 * @throws UnexpectedEntityException
463
+	 */
464
+	private function _release_registration_space()
465
+	{
466
+		$ticket = $this->ticket();
467
+		$ticket->decrease_sold();
468
+		$ticket->save();
469
+		// possibly change event status from sold out back to previous status
470
+		$this->event()->perform_sold_out_status_check();
471
+	}
472
+
473
+
474
+	/**
475
+	 * tracks this registration's ticket reservation in extra meta
476
+	 * and can increment related ticket reserved and corresponding datetime reserved values
477
+	 *
478
+	 * @param bool $update_ticket if true, will increment ticket and datetime reserved count
479
+	 * @return void
480
+	 * @throws EE_Error
481
+	 * @throws InvalidArgumentException
482
+	 * @throws InvalidDataTypeException
483
+	 * @throws InvalidInterfaceException
484
+	 * @throws ReflectionException
485
+	 */
486
+	public function reserve_ticket($update_ticket = false, $source = 'unknown')
487
+	{
488
+		// only reserve ticket if space is not currently reserved
489
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
490
+			$this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
491
+			// IMPORTANT !!!
492
+			// although checking $update_ticket first would be more efficient,
493
+			// we NEED to ALWAYS call update_extra_meta(), which is why that is done first
494
+			if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true)
495
+				&& $update_ticket
496
+			) {
497
+				$ticket = $this->ticket();
498
+				$ticket->increase_reserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
499
+				$ticket->save();
500
+			}
501
+		}
502
+	}
503
+
504
+
505
+	/**
506
+	 * stops tracking this registration's ticket reservation in extra meta
507
+	 * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
508
+	 *
509
+	 * @param bool $update_ticket if true, will decrement ticket and datetime reserved count
510
+	 * @return void
511
+	 * @throws EE_Error
512
+	 * @throws InvalidArgumentException
513
+	 * @throws InvalidDataTypeException
514
+	 * @throws InvalidInterfaceException
515
+	 * @throws ReflectionException
516
+	 */
517
+	public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
518
+	{
519
+		// only release ticket if space is currently reserved
520
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
521
+			$this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
522
+			// IMPORTANT !!!
523
+			// although checking $update_ticket first would be more efficient,
524
+			// we NEED to ALWAYS call update_extra_meta(), which is why that is done first
525
+			if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false)
526
+				&& $update_ticket
527
+			) {
528
+				$ticket = $this->ticket();
529
+				$ticket->decrease_reserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
530
+				$ticket->save();
531
+			}
532
+		}
533
+	}
534
+
535
+
536
+	/**
537
+	 * Set Attendee ID
538
+	 *
539
+	 * @param        int $ATT_ID Attendee ID
540
+	 * @throws EE_Error
541
+	 * @throws RuntimeException
542
+	 */
543
+	public function set_attendee_id($ATT_ID = 0)
544
+	{
545
+		$this->set('ATT_ID', $ATT_ID);
546
+	}
547
+
548
+
549
+	/**
550
+	 *        Set Transaction ID
551
+	 *
552
+	 * @param        int $TXN_ID Transaction ID
553
+	 * @throws EE_Error
554
+	 * @throws RuntimeException
555
+	 */
556
+	public function set_transaction_id($TXN_ID = 0)
557
+	{
558
+		$this->set('TXN_ID', $TXN_ID);
559
+	}
560
+
561
+
562
+	/**
563
+	 *        Set Session
564
+	 *
565
+	 * @param    string $REG_session PHP Session ID
566
+	 * @throws EE_Error
567
+	 * @throws RuntimeException
568
+	 */
569
+	public function set_session($REG_session = '')
570
+	{
571
+		$this->set('REG_session', $REG_session);
572
+	}
573
+
574
+
575
+	/**
576
+	 *        Set Registration URL Link
577
+	 *
578
+	 * @param    string $REG_url_link Registration URL Link
579
+	 * @throws EE_Error
580
+	 * @throws RuntimeException
581
+	 */
582
+	public function set_reg_url_link($REG_url_link = '')
583
+	{
584
+		$this->set('REG_url_link', $REG_url_link);
585
+	}
586
+
587
+
588
+	/**
589
+	 *        Set Attendee Counter
590
+	 *
591
+	 * @param        int $REG_count Primary Attendee
592
+	 * @throws EE_Error
593
+	 * @throws RuntimeException
594
+	 */
595
+	public function set_count($REG_count = 1)
596
+	{
597
+		$this->set('REG_count', $REG_count);
598
+	}
599
+
600
+
601
+	/**
602
+	 *        Set Group Size
603
+	 *
604
+	 * @param        boolean $REG_group_size Group Registration
605
+	 * @throws EE_Error
606
+	 * @throws RuntimeException
607
+	 */
608
+	public function set_group_size($REG_group_size = false)
609
+	{
610
+		$this->set('REG_group_size', $REG_group_size);
611
+	}
612
+
613
+
614
+	/**
615
+	 *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
616
+	 *    EEM_Registration::status_id_not_approved
617
+	 *
618
+	 * @return        boolean
619
+	 */
620
+	public function is_not_approved()
621
+	{
622
+		return $this->status_ID() == EEM_Registration::status_id_not_approved ? true : false;
623
+	}
624
+
625
+
626
+	/**
627
+	 *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
628
+	 *    EEM_Registration::status_id_pending_payment
629
+	 *
630
+	 * @return        boolean
631
+	 */
632
+	public function is_pending_payment()
633
+	{
634
+		return $this->status_ID() == EEM_Registration::status_id_pending_payment ? true : false;
635
+	}
636
+
637
+
638
+	/**
639
+	 *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
640
+	 *
641
+	 * @return        boolean
642
+	 */
643
+	public function is_approved()
644
+	{
645
+		return $this->status_ID() == EEM_Registration::status_id_approved ? true : false;
646
+	}
647
+
648
+
649
+	/**
650
+	 *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
651
+	 *
652
+	 * @return        boolean
653
+	 */
654
+	public function is_cancelled()
655
+	{
656
+		return $this->status_ID() == EEM_Registration::status_id_cancelled ? true : false;
657
+	}
658
+
659
+
660
+	/**
661
+	 *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
662
+	 *
663
+	 * @return        boolean
664
+	 */
665
+	public function is_declined()
666
+	{
667
+		return $this->status_ID() == EEM_Registration::status_id_declined ? true : false;
668
+	}
669
+
670
+
671
+	/**
672
+	 *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
673
+	 *    EEM_Registration::status_id_incomplete
674
+	 *
675
+	 * @return        boolean
676
+	 */
677
+	public function is_incomplete()
678
+	{
679
+		return $this->status_ID() == EEM_Registration::status_id_incomplete ? true : false;
680
+	}
681
+
682
+
683
+	/**
684
+	 *        Set Registration Date
685
+	 *
686
+	 * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
687
+	 *                                                 Date
688
+	 * @throws EE_Error
689
+	 * @throws RuntimeException
690
+	 */
691
+	public function set_reg_date($REG_date = false)
692
+	{
693
+		$this->set('REG_date', $REG_date);
694
+	}
695
+
696
+
697
+	/**
698
+	 *    Set final price owing for this registration after all ticket/price modifications
699
+	 *
700
+	 * @access    public
701
+	 * @param    float $REG_final_price
702
+	 * @throws EE_Error
703
+	 * @throws RuntimeException
704
+	 */
705
+	public function set_final_price($REG_final_price = 0.00)
706
+	{
707
+		$this->set('REG_final_price', $REG_final_price);
708
+	}
709
+
710
+
711
+	/**
712
+	 *    Set amount paid towards this registration's final price
713
+	 *
714
+	 * @access    public
715
+	 * @param    float $REG_paid
716
+	 * @throws EE_Error
717
+	 * @throws RuntimeException
718
+	 */
719
+	public function set_paid($REG_paid = 0.00)
720
+	{
721
+		$this->set('REG_paid', $REG_paid);
722
+	}
723
+
724
+
725
+	/**
726
+	 *        Attendee Is Going
727
+	 *
728
+	 * @param        boolean $REG_att_is_going Attendee Is Going
729
+	 * @throws EE_Error
730
+	 * @throws RuntimeException
731
+	 */
732
+	public function set_att_is_going($REG_att_is_going = false)
733
+	{
734
+		$this->set('REG_att_is_going', $REG_att_is_going);
735
+	}
736
+
737
+
738
+	/**
739
+	 * Gets the related attendee
740
+	 *
741
+	 * @return EE_Attendee
742
+	 * @throws EE_Error
743
+	 */
744
+	public function attendee()
745
+	{
746
+		return $this->get_first_related('Attendee');
747
+	}
748
+
749
+
750
+	/**
751
+	 *        get Event ID
752
+	 */
753
+	public function event_ID()
754
+	{
755
+		return $this->get('EVT_ID');
756
+	}
757
+
758
+
759
+	/**
760
+	 *        get Event ID
761
+	 */
762
+	public function event_name()
763
+	{
764
+		$event = $this->event_obj();
765
+		if ($event) {
766
+			return $event->name();
767
+		} else {
768
+			return null;
769
+		}
770
+	}
771
+
772
+
773
+	/**
774
+	 * Fetches the event this registration is for
775
+	 *
776
+	 * @return EE_Event
777
+	 * @throws EE_Error
778
+	 */
779
+	public function event_obj()
780
+	{
781
+		return $this->get_first_related('Event');
782
+	}
783
+
784
+
785
+	/**
786
+	 *        get Attendee ID
787
+	 */
788
+	public function attendee_ID()
789
+	{
790
+		return $this->get('ATT_ID');
791
+	}
792
+
793
+
794
+	/**
795
+	 *        get PHP Session ID
796
+	 */
797
+	public function session_ID()
798
+	{
799
+		return $this->get('REG_session');
800
+	}
801
+
802
+
803
+	/**
804
+	 * Gets the string which represents the URL trigger for the receipt template in the message template system.
805
+	 *
806
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
807
+	 * @return string
808
+	 */
809
+	public function receipt_url($messenger = 'html')
810
+	{
811
+
812
+		/**
813
+		 * The below will be deprecated one version after this.  We check first if there is a custom receipt template
814
+		 * already in use on old system.  If there is then we just return the standard url for it.
815
+		 *
816
+		 * @since 4.5.0
817
+		 */
818
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
819
+		$has_custom = EEH_Template::locate_template(
820
+			$template_relative_path,
821
+			array(),
822
+			true,
823
+			true,
824
+			true
825
+		);
826
+
827
+		if ($has_custom) {
828
+			return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
829
+		}
830
+		return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
831
+	}
832
+
833
+
834
+	/**
835
+	 * Gets the string which represents the URL trigger for the invoice template in the message template system.
836
+	 *
837
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
838
+	 * @return string
839
+	 * @throws EE_Error
840
+	 */
841
+	public function invoice_url($messenger = 'html')
842
+	{
843
+		/**
844
+		 * The below will be deprecated one version after this.  We check first if there is a custom invoice template
845
+		 * already in use on old system.  If there is then we just return the standard url for it.
846
+		 *
847
+		 * @since 4.5.0
848
+		 */
849
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
850
+		$has_custom = EEH_Template::locate_template(
851
+			$template_relative_path,
852
+			array(),
853
+			true,
854
+			true,
855
+			true
856
+		);
857
+
858
+		if ($has_custom) {
859
+			if ($messenger == 'html') {
860
+				return $this->invoice_url('launch');
861
+			}
862
+			$route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
863
+
864
+			$query_args = array('ee' => $route, 'id' => $this->reg_url_link());
865
+			if ($messenger == 'html') {
866
+				$query_args['html'] = true;
867
+			}
868
+			return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
869
+		}
870
+		return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
871
+	}
872
+
873
+
874
+	/**
875
+	 * get Registration URL Link
876
+	 *
877
+	 * @access public
878
+	 * @return string
879
+	 * @throws EE_Error
880
+	 */
881
+	public function reg_url_link()
882
+	{
883
+		return (string) $this->get('REG_url_link');
884
+	}
885
+
886
+
887
+	/**
888
+	 * Echoes out invoice_url()
889
+	 *
890
+	 * @param string $type 'download','launch', or 'html' (default is 'launch')
891
+	 * @return void
892
+	 * @throws EE_Error
893
+	 */
894
+	public function e_invoice_url($type = 'launch')
895
+	{
896
+		echo $this->invoice_url($type);
897
+	}
898
+
899
+
900
+	/**
901
+	 * Echoes out payment_overview_url
902
+	 */
903
+	public function e_payment_overview_url()
904
+	{
905
+		echo $this->payment_overview_url();
906
+	}
907
+
908
+
909
+	/**
910
+	 * Gets the URL for the checkout payment options reg step
911
+	 * with this registration's REG_url_link added as a query parameter
912
+	 *
913
+	 * @param bool $clear_session Set to true when you want to clear the session on revisiting the
914
+	 *                            payment overview url.
915
+	 * @return string
916
+	 * @throws InvalidInterfaceException
917
+	 * @throws InvalidDataTypeException
918
+	 * @throws EE_Error
919
+	 * @throws InvalidArgumentException
920
+	 */
921
+	public function payment_overview_url($clear_session = false)
922
+	{
923
+		return add_query_arg(
924
+			(array) apply_filters(
925
+				'FHEE__EE_Registration__payment_overview_url__query_args',
926
+				array(
927
+					'e_reg_url_link' => $this->reg_url_link(),
928
+					'step'           => 'payment_options',
929
+					'revisit'        => true,
930
+					'clear_session'  => (bool) $clear_session,
931
+				),
932
+				$this
933
+			),
934
+			EE_Registry::instance()->CFG->core->reg_page_url()
935
+		);
936
+	}
937
+
938
+
939
+	/**
940
+	 * Gets the URL for the checkout attendee information reg step
941
+	 * with this registration's REG_url_link added as a query parameter
942
+	 *
943
+	 * @return string
944
+	 * @throws InvalidInterfaceException
945
+	 * @throws InvalidDataTypeException
946
+	 * @throws EE_Error
947
+	 * @throws InvalidArgumentException
948
+	 */
949
+	public function edit_attendee_information_url()
950
+	{
951
+		return add_query_arg(
952
+			(array) apply_filters(
953
+				'FHEE__EE_Registration__edit_attendee_information_url__query_args',
954
+				array(
955
+					'e_reg_url_link' => $this->reg_url_link(),
956
+					'step'           => 'attendee_information',
957
+					'revisit'        => true,
958
+				),
959
+				$this
960
+			),
961
+			EE_Registry::instance()->CFG->core->reg_page_url()
962
+		);
963
+	}
964
+
965
+
966
+	/**
967
+	 * Simply generates and returns the appropriate admin_url link to edit this registration
968
+	 *
969
+	 * @return string
970
+	 * @throws EE_Error
971
+	 */
972
+	public function get_admin_edit_url()
973
+	{
974
+		return EEH_URL::add_query_args_and_nonce(
975
+			array(
976
+				'page'    => 'espresso_registrations',
977
+				'action'  => 'view_registration',
978
+				'_REG_ID' => $this->ID(),
979
+			),
980
+			admin_url('admin.php')
981
+		);
982
+	}
983
+
984
+
985
+	/**
986
+	 *    is_primary_registrant?
987
+	 */
988
+	public function is_primary_registrant()
989
+	{
990
+		return $this->get('REG_count') == 1 ? true : false;
991
+	}
992
+
993
+
994
+	/**
995
+	 * This returns the primary registration object for this registration group (which may be this object).
996
+	 *
997
+	 * @return EE_Registration
998
+	 * @throws EE_Error
999
+	 */
1000
+	public function get_primary_registration()
1001
+	{
1002
+		if ($this->is_primary_registrant()) {
1003
+			return $this;
1004
+		}
1005
+
1006
+		// k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1007
+		/** @var EE_Registration $primary_registrant */
1008
+		$primary_registrant = EEM_Registration::instance()->get_one(
1009
+			array(
1010
+				array(
1011
+					'TXN_ID'    => $this->transaction_ID(),
1012
+					'REG_count' => 1,
1013
+				),
1014
+			)
1015
+		);
1016
+		return $primary_registrant;
1017
+	}
1018
+
1019
+
1020
+	/**
1021
+	 *        get  Attendee Number
1022
+	 *
1023
+	 * @access        public
1024
+	 */
1025
+	public function count()
1026
+	{
1027
+		return $this->get('REG_count');
1028
+	}
1029
+
1030
+
1031
+	/**
1032
+	 *        get Group Size
1033
+	 */
1034
+	public function group_size()
1035
+	{
1036
+		return $this->get('REG_group_size');
1037
+	}
1038
+
1039
+
1040
+	/**
1041
+	 *        get Registration Date
1042
+	 */
1043
+	public function date()
1044
+	{
1045
+		return $this->get('REG_date');
1046
+	}
1047
+
1048
+
1049
+	/**
1050
+	 * gets a pretty date
1051
+	 *
1052
+	 * @param string $date_format
1053
+	 * @param string $time_format
1054
+	 * @return string
1055
+	 * @throws EE_Error
1056
+	 */
1057
+	public function pretty_date($date_format = null, $time_format = null)
1058
+	{
1059
+		return $this->get_datetime('REG_date', $date_format, $time_format);
1060
+	}
1061
+
1062
+
1063
+	/**
1064
+	 * final_price
1065
+	 * the registration's share of the transaction total, so that the
1066
+	 * sum of all the transaction's REG_final_prices equal the transaction's total
1067
+	 *
1068
+	 * @return float
1069
+	 * @throws EE_Error
1070
+	 */
1071
+	public function final_price()
1072
+	{
1073
+		return $this->get('REG_final_price');
1074
+	}
1075
+
1076
+
1077
+	/**
1078
+	 * pretty_final_price
1079
+	 *  final price as formatted string, with correct decimal places and currency symbol
1080
+	 *
1081
+	 * @return string
1082
+	 * @throws EE_Error
1083
+	 */
1084
+	public function pretty_final_price()
1085
+	{
1086
+		return $this->get_pretty('REG_final_price');
1087
+	}
1088
+
1089
+
1090
+	/**
1091
+	 * get paid (yeah)
1092
+	 *
1093
+	 * @return float
1094
+	 * @throws EE_Error
1095
+	 */
1096
+	public function paid()
1097
+	{
1098
+		return $this->get('REG_paid');
1099
+	}
1100
+
1101
+
1102
+	/**
1103
+	 * pretty_paid
1104
+	 *
1105
+	 * @return float
1106
+	 * @throws EE_Error
1107
+	 */
1108
+	public function pretty_paid()
1109
+	{
1110
+		return $this->get_pretty('REG_paid');
1111
+	}
1112
+
1113
+
1114
+	/**
1115
+	 * owes_monies_and_can_pay
1116
+	 * whether or not this registration has monies owing and it's' status allows payment
1117
+	 *
1118
+	 * @param array $requires_payment
1119
+	 * @return bool
1120
+	 * @throws EE_Error
1121
+	 */
1122
+	public function owes_monies_and_can_pay($requires_payment = array())
1123
+	{
1124
+		// these reg statuses require payment (if event is not free)
1125
+		$requires_payment = ! empty($requires_payment)
1126
+			? $requires_payment
1127
+			: EEM_Registration::reg_statuses_that_allow_payment();
1128
+		if (in_array($this->status_ID(), $requires_payment) &&
1129
+			$this->final_price() != 0 &&
1130
+			$this->final_price() != $this->paid()
1131
+		) {
1132
+			return true;
1133
+		} else {
1134
+			return false;
1135
+		}
1136
+	}
1137
+
1138
+
1139
+	/**
1140
+	 * Prints out the return value of $this->pretty_status()
1141
+	 *
1142
+	 * @param bool $show_icons
1143
+	 * @return void
1144
+	 * @throws EE_Error
1145
+	 */
1146
+	public function e_pretty_status($show_icons = false)
1147
+	{
1148
+		echo $this->pretty_status($show_icons);
1149
+	}
1150
+
1151
+
1152
+	/**
1153
+	 * Returns a nice version of the status for displaying to customers
1154
+	 *
1155
+	 * @param bool $show_icons
1156
+	 * @return string
1157
+	 * @throws EE_Error
1158
+	 */
1159
+	public function pretty_status($show_icons = false)
1160
+	{
1161
+		$status = EEM_Status::instance()->localized_status(
1162
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1163
+			false,
1164
+			'sentence'
1165
+		);
1166
+		$icon = '';
1167
+		switch ($this->status_ID()) {
1168
+			case EEM_Registration::status_id_approved:
1169
+				$icon = $show_icons
1170
+					? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1171
+					: '';
1172
+				break;
1173
+			case EEM_Registration::status_id_pending_payment:
1174
+				$icon = $show_icons
1175
+					? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1176
+					: '';
1177
+				break;
1178
+			case EEM_Registration::status_id_not_approved:
1179
+				$icon = $show_icons
1180
+					? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1181
+					: '';
1182
+				break;
1183
+			case EEM_Registration::status_id_cancelled:
1184
+				$icon = $show_icons
1185
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1186
+					: '';
1187
+				break;
1188
+			case EEM_Registration::status_id_incomplete:
1189
+				$icon = $show_icons
1190
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1191
+					: '';
1192
+				break;
1193
+			case EEM_Registration::status_id_declined:
1194
+				$icon = $show_icons
1195
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1196
+					: '';
1197
+				break;
1198
+			case EEM_Registration::status_id_wait_list:
1199
+				$icon = $show_icons
1200
+					? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1201
+					: '';
1202
+				break;
1203
+		}
1204
+		return $icon . $status[ $this->status_ID() ];
1205
+	}
1206
+
1207
+
1208
+	/**
1209
+	 *        get Attendee Is Going
1210
+	 */
1211
+	public function att_is_going()
1212
+	{
1213
+		return $this->get('REG_att_is_going');
1214
+	}
1215
+
1216
+
1217
+	/**
1218
+	 * Gets related answers
1219
+	 *
1220
+	 * @param array $query_params like EEM_Base::get_all
1221
+	 * @return EE_Answer[]
1222
+	 * @throws EE_Error
1223
+	 */
1224
+	public function answers($query_params = null)
1225
+	{
1226
+		return $this->get_many_related('Answer', $query_params);
1227
+	}
1228
+
1229
+
1230
+	/**
1231
+	 * Gets the registration's answer value to the specified question
1232
+	 * (either the question's ID or a question object)
1233
+	 *
1234
+	 * @param EE_Question|int $question
1235
+	 * @param bool            $pretty_value
1236
+	 * @return array|string if pretty_value= true, the result will always be a string
1237
+	 * (because the answer might be an array of answer values, so passing pretty_value=true
1238
+	 * will convert it into some kind of string)
1239
+	 * @throws EE_Error
1240
+	 */
1241
+	public function answer_value_to_question($question, $pretty_value = true)
1242
+	{
1243
+		$question_id = EEM_Question::instance()->ensure_is_ID($question);
1244
+		return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1245
+	}
1246
+
1247
+
1248
+	/**
1249
+	 * question_groups
1250
+	 * returns an array of EE_Question_Group objects for this registration
1251
+	 *
1252
+	 * @return EE_Question_Group[]
1253
+	 * @throws EE_Error
1254
+	 * @throws EntityNotFoundException
1255
+	 */
1256
+	public function question_groups()
1257
+	{
1258
+		$question_groups = array();
1259
+		if ($this->event() instanceof EE_Event) {
1260
+			$question_groups = $this->event()->question_groups(
1261
+				array(
1262
+					array(
1263
+						'Event_Question_Group.EQG_primary' => $this->count() == 1 ? true : false,
1264
+					),
1265
+					'order_by' => array('QSG_order' => 'ASC'),
1266
+				)
1267
+			);
1268
+		}
1269
+		return $question_groups;
1270
+	}
1271
+
1272
+
1273
+	/**
1274
+	 * count_question_groups
1275
+	 * returns a count of the number of EE_Question_Group objects for this registration
1276
+	 *
1277
+	 * @return int
1278
+	 * @throws EE_Error
1279
+	 * @throws EntityNotFoundException
1280
+	 */
1281
+	public function count_question_groups()
1282
+	{
1283
+		$qg_count = 0;
1284
+		if ($this->event() instanceof EE_Event) {
1285
+			$qg_count = $this->event()->count_related(
1286
+				'Question_Group',
1287
+				array(
1288
+					array(
1289
+						'Event_Question_Group.EQG_primary' => $this->count() == 1 ? true : false,
1290
+					),
1291
+				)
1292
+			);
1293
+		}
1294
+		return $qg_count;
1295
+	}
1296
+
1297
+
1298
+	/**
1299
+	 * Returns the registration date in the 'standard' string format
1300
+	 * (function may be improved in the future to allow for different formats and timezones)
1301
+	 *
1302
+	 * @return string
1303
+	 * @throws EE_Error
1304
+	 */
1305
+	public function reg_date()
1306
+	{
1307
+		return $this->get_datetime('REG_date');
1308
+	}
1309
+
1310
+
1311
+	/**
1312
+	 * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1313
+	 * the ticket this registration purchased, or the datetime they have registered
1314
+	 * to attend)
1315
+	 *
1316
+	 * @return EE_Datetime_Ticket
1317
+	 * @throws EE_Error
1318
+	 */
1319
+	public function datetime_ticket()
1320
+	{
1321
+		return $this->get_first_related('Datetime_Ticket');
1322
+	}
1323
+
1324
+
1325
+	/**
1326
+	 * Sets the registration's datetime_ticket.
1327
+	 *
1328
+	 * @param EE_Datetime_Ticket $datetime_ticket
1329
+	 * @return EE_Datetime_Ticket
1330
+	 * @throws EE_Error
1331
+	 */
1332
+	public function set_datetime_ticket($datetime_ticket)
1333
+	{
1334
+		return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1335
+	}
1336
+
1337
+	/**
1338
+	 * Gets deleted
1339
+	 *
1340
+	 * @return bool
1341
+	 * @throws EE_Error
1342
+	 */
1343
+	public function deleted()
1344
+	{
1345
+		return $this->get('REG_deleted');
1346
+	}
1347
+
1348
+	/**
1349
+	 * Sets deleted
1350
+	 *
1351
+	 * @param boolean $deleted
1352
+	 * @return bool
1353
+	 * @throws EE_Error
1354
+	 * @throws RuntimeException
1355
+	 */
1356
+	public function set_deleted($deleted)
1357
+	{
1358
+		if ($deleted) {
1359
+			$this->delete();
1360
+		} else {
1361
+			$this->restore();
1362
+		}
1363
+	}
1364
+
1365
+
1366
+	/**
1367
+	 * Get the status object of this object
1368
+	 *
1369
+	 * @return EE_Status
1370
+	 * @throws EE_Error
1371
+	 */
1372
+	public function status_obj()
1373
+	{
1374
+		return $this->get_first_related('Status');
1375
+	}
1376
+
1377
+
1378
+	/**
1379
+	 * Returns the number of times this registration has checked into any of the datetimes
1380
+	 * its available for
1381
+	 *
1382
+	 * @return int
1383
+	 * @throws EE_Error
1384
+	 */
1385
+	public function count_checkins()
1386
+	{
1387
+		return $this->get_model()->count_related($this, 'Checkin');
1388
+	}
1389
+
1390
+
1391
+	/**
1392
+	 * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1393
+	 * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1394
+	 *
1395
+	 * @return int
1396
+	 * @throws EE_Error
1397
+	 */
1398
+	public function count_checkins_not_checkedout()
1399
+	{
1400
+		return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1401
+	}
1402
+
1403
+
1404
+	/**
1405
+	 * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1406
+	 *
1407
+	 * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1408
+	 * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1409
+	 *                                          consider registration status as well as datetime access.
1410
+	 * @return bool
1411
+	 * @throws EE_Error
1412
+	 */
1413
+	public function can_checkin($DTT_OR_ID, $check_approved = true)
1414
+	{
1415
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1416
+
1417
+		// first check registration status
1418
+		if (($check_approved && ! $this->is_approved()) || ! $DTT_ID) {
1419
+			return false;
1420
+		}
1421
+		// is there a datetime ticket that matches this dtt_ID?
1422
+		if (! (EEM_Datetime_Ticket::instance()->exists(
1423
+			array(
1424
+				array(
1425
+					'TKT_ID' => $this->get('TKT_ID'),
1426
+					'DTT_ID' => $DTT_ID,
1427
+				),
1428
+			)
1429
+		))
1430
+		) {
1431
+			return false;
1432
+		}
1433
+
1434
+		// final check is against TKT_uses
1435
+		return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1436
+	}
1437
+
1438
+
1439
+	/**
1440
+	 * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1441
+	 * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1442
+	 * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1443
+	 * then return false.  Otherwise return true.
1444
+	 *
1445
+	 * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1446
+	 * @return bool true means can checkin.  false means cannot checkin.
1447
+	 * @throws EE_Error
1448
+	 */
1449
+	public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1450
+	{
1451
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1452
+
1453
+		if (! $DTT_ID) {
1454
+			return false;
1455
+		}
1456
+
1457
+		$max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1458
+
1459
+		// if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1460
+		// check-in or not.
1461
+		if (! $max_uses || $max_uses === EE_INF) {
1462
+			return true;
1463
+		}
1464
+
1465
+		// does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1466
+		// go ahead and toggle.
1467
+		if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1468
+			return true;
1469
+		}
1470
+
1471
+		// made it here so the last check is whether the number of checkins per unique datetime on this registration
1472
+		// disallows further check-ins.
1473
+		$count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1474
+			array(
1475
+				array(
1476
+					'REG_ID' => $this->ID(),
1477
+					'CHK_in' => true,
1478
+				),
1479
+			),
1480
+			'DTT_ID',
1481
+			true
1482
+		);
1483
+		// checkins have already reached their max number of uses
1484
+		// so registrant can NOT checkin
1485
+		if ($count_unique_dtt_checkins >= $max_uses) {
1486
+			EE_Error::add_error(
1487
+				esc_html__(
1488
+					'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1489
+					'event_espresso'
1490
+				),
1491
+				__FILE__,
1492
+				__FUNCTION__,
1493
+				__LINE__
1494
+			);
1495
+			return false;
1496
+		}
1497
+		return true;
1498
+	}
1499
+
1500
+
1501
+	/**
1502
+	 * toggle Check-in status for this registration
1503
+	 * Check-ins are toggled in the following order:
1504
+	 * never checked in -> checked in
1505
+	 * checked in -> checked out
1506
+	 * checked out -> checked in
1507
+	 *
1508
+	 * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1509
+	 *                      If not included or null, then it is assumed latest datetime is being toggled.
1510
+	 * @param bool $verify  If true then can_checkin() is used to verify whether the person
1511
+	 *                      can be checked in or not.  Otherwise this forces change in checkin status.
1512
+	 * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1513
+	 * @throws EE_Error
1514
+	 */
1515
+	public function toggle_checkin_status($DTT_ID = null, $verify = false)
1516
+	{
1517
+		if (empty($DTT_ID)) {
1518
+			$datetime = $this->get_latest_related_datetime();
1519
+			$DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1520
+			// verify the registration can checkin for the given DTT_ID
1521
+		} elseif (! $this->can_checkin($DTT_ID, $verify)) {
1522
+			EE_Error::add_error(
1523
+				sprintf(
1524
+					esc_html__(
1525
+						'The given registration (ID:%1$d) can not be checked in to the given DTT_ID (%2$d), because the registration does not have access',
1526
+						'event_espresso'
1527
+					),
1528
+					$this->ID(),
1529
+					$DTT_ID
1530
+				),
1531
+				__FILE__,
1532
+				__FUNCTION__,
1533
+				__LINE__
1534
+			);
1535
+			return false;
1536
+		}
1537
+		$status_paths = array(
1538
+			EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1539
+			EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1540
+			EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1541
+		);
1542
+		// start by getting the current status so we know what status we'll be changing to.
1543
+		$cur_status = $this->check_in_status_for_datetime($DTT_ID, null);
1544
+		$status_to = $status_paths[ $cur_status ];
1545
+		// database only records true for checked IN or false for checked OUT
1546
+		// no record ( null ) means checked in NEVER, but we obviously don't save that
1547
+		$new_status = $status_to === EE_Checkin::status_checked_in ? true : false;
1548
+		// add relation - note Check-ins are always creating new rows
1549
+		// because we are keeping track of Check-ins over time.
1550
+		// Eventually we'll probably want to show a list table
1551
+		// for the individual Check-ins so that they can be managed.
1552
+		$checkin = EE_Checkin::new_instance(
1553
+			array(
1554
+				'REG_ID' => $this->ID(),
1555
+				'DTT_ID' => $DTT_ID,
1556
+				'CHK_in' => $new_status,
1557
+			)
1558
+		);
1559
+		// if the record could not be saved then return false
1560
+		if ($checkin->save() === 0) {
1561
+			if (WP_DEBUG) {
1562
+				global $wpdb;
1563
+				$error = sprintf(
1564
+					esc_html__(
1565
+						'Registration check in update failed because of the following database error: %1$s%2$s',
1566
+						'event_espresso'
1567
+					),
1568
+					'<br />',
1569
+					$wpdb->last_error
1570
+				);
1571
+			} else {
1572
+				$error = esc_html__(
1573
+					'Registration check in update failed because of an unknown database error',
1574
+					'event_espresso'
1575
+				);
1576
+			}
1577
+			EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1578
+			return false;
1579
+		}
1580
+		return $status_to;
1581
+	}
1582
+
1583
+
1584
+	/**
1585
+	 * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1586
+	 * "Latest" is defined by the `DTT_EVT_start` column.
1587
+	 *
1588
+	 * @return EE_Datetime|null
1589
+	 * @throws EE_Error
1590
+	 */
1591
+	public function get_latest_related_datetime()
1592
+	{
1593
+		return EEM_Datetime::instance()->get_one(
1594
+			array(
1595
+				array(
1596
+					'Ticket.Registration.REG_ID' => $this->ID(),
1597
+				),
1598
+				'order_by' => array('DTT_EVT_start' => 'DESC'),
1599
+			)
1600
+		);
1601
+	}
1602
+
1603
+
1604
+	/**
1605
+	 * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1606
+	 * "Earliest" is defined by the `DTT_EVT_start` column.
1607
+	 *
1608
+	 * @throws EE_Error
1609
+	 */
1610
+	public function get_earliest_related_datetime()
1611
+	{
1612
+		return EEM_Datetime::instance()->get_one(
1613
+			array(
1614
+				array(
1615
+					'Ticket.Registration.REG_ID' => $this->ID(),
1616
+				),
1617
+				'order_by' => array('DTT_EVT_start' => 'ASC'),
1618
+			)
1619
+		);
1620
+	}
1621
+
1622
+
1623
+	/**
1624
+	 * This method simply returns the check-in status for this registration and the given datetime.
1625
+	 * If neither the datetime nor the checkin values are provided as arguments,
1626
+	 * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1627
+	 *
1628
+	 * @param  int       $DTT_ID  The ID of the datetime we're checking against
1629
+	 *                            (if empty we'll get the primary datetime for
1630
+	 *                            this registration (via event) and use it's ID);
1631
+	 * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1632
+	 *
1633
+	 * @return int                Integer representing Check-in status.
1634
+	 * @throws EE_Error
1635
+	 */
1636
+	public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1637
+	{
1638
+		$checkin_query_params = array(
1639
+			'order_by' => array('CHK_timestamp' => 'DESC'),
1640
+		);
1641
+
1642
+		if ($DTT_ID > 0) {
1643
+			$checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1644
+		}
1645
+
1646
+		// get checkin object (if exists)
1647
+		$checkin = $checkin instanceof EE_Checkin
1648
+			? $checkin
1649
+			: $this->get_first_related('Checkin', $checkin_query_params);
1650
+		if ($checkin instanceof EE_Checkin) {
1651
+			if ($checkin->get('CHK_in')) {
1652
+				return EE_Checkin::status_checked_in; // checked in
1653
+			}
1654
+			return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1655
+		}
1656
+		return EE_Checkin::status_checked_never; // never been checked in
1657
+	}
1658
+
1659
+
1660
+	/**
1661
+	 * This method returns a localized message for the toggled Check-in message.
1662
+	 *
1663
+	 * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1664
+	 *                     then it is assumed Check-in for primary datetime was toggled.
1665
+	 * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1666
+	 *                     message can be customized with the attendee name.
1667
+	 * @return string internationalized message
1668
+	 * @throws EE_Error
1669
+	 */
1670
+	public function get_checkin_msg($DTT_ID, $error = false)
1671
+	{
1672
+		// let's get the attendee first so we can include the name of the attendee
1673
+		$attendee = $this->get_first_related('Attendee');
1674
+		if ($attendee instanceof EE_Attendee) {
1675
+			if ($error) {
1676
+				return sprintf(__("%s's check-in status was not changed.", "event_espresso"), $attendee->full_name());
1677
+			}
1678
+			$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1679
+			// what is the status message going to be?
1680
+			switch ($cur_status) {
1681
+				case EE_Checkin::status_checked_never:
1682
+					return sprintf(
1683
+						__("%s has been removed from Check-in records", "event_espresso"),
1684
+						$attendee->full_name()
1685
+					);
1686
+					break;
1687
+				case EE_Checkin::status_checked_in:
1688
+					return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1689
+					break;
1690
+				case EE_Checkin::status_checked_out:
1691
+					return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1692
+					break;
1693
+			}
1694
+		}
1695
+		return esc_html__("The check-in status could not be determined.", "event_espresso");
1696
+	}
1697
+
1698
+
1699
+	/**
1700
+	 * Returns the related EE_Transaction to this registration
1701
+	 *
1702
+	 * @return EE_Transaction
1703
+	 * @throws EE_Error
1704
+	 * @throws EntityNotFoundException
1705
+	 */
1706
+	public function transaction()
1707
+	{
1708
+		$transaction = $this->get_first_related('Transaction');
1709
+		if (! $transaction instanceof \EE_Transaction) {
1710
+			throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1711
+		}
1712
+		return $transaction;
1713
+	}
1714
+
1715
+
1716
+	/**
1717
+	 *        get Registration Code
1718
+	 */
1719
+	public function reg_code()
1720
+	{
1721
+		return $this->get('REG_code');
1722
+	}
1723
+
1724
+
1725
+	/**
1726
+	 *        get Transaction ID
1727
+	 */
1728
+	public function transaction_ID()
1729
+	{
1730
+		return $this->get('TXN_ID');
1731
+	}
1732
+
1733
+
1734
+	/**
1735
+	 * @return int
1736
+	 * @throws EE_Error
1737
+	 */
1738
+	public function ticket_ID()
1739
+	{
1740
+		return $this->get('TKT_ID');
1741
+	}
1742
+
1743
+
1744
+	/**
1745
+	 *        Set Registration Code
1746
+	 *
1747
+	 * @access    public
1748
+	 * @param    string  $REG_code Registration Code
1749
+	 * @param    boolean $use_default
1750
+	 * @throws EE_Error
1751
+	 */
1752
+	public function set_reg_code($REG_code, $use_default = false)
1753
+	{
1754
+		if (empty($REG_code)) {
1755
+			EE_Error::add_error(
1756
+				esc_html__('REG_code can not be empty.', 'event_espresso'),
1757
+				__FILE__,
1758
+				__FUNCTION__,
1759
+				__LINE__
1760
+			);
1761
+			return;
1762
+		}
1763
+		if (! $this->reg_code()) {
1764
+			parent::set('REG_code', $REG_code, $use_default);
1765
+		} else {
1766
+			EE_Error::doing_it_wrong(
1767
+				__CLASS__ . '::' . __FUNCTION__,
1768
+				esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
1769
+				'4.6.0'
1770
+			);
1771
+		}
1772
+	}
1773
+
1774
+
1775
+	/**
1776
+	 * Returns all other registrations in the same group as this registrant who have the same ticket option.
1777
+	 * Note, if you want to just get all registrations in the same transaction (group), use:
1778
+	 *    $registration->transaction()->registrations();
1779
+	 *
1780
+	 * @since 4.5.0
1781
+	 * @return EE_Registration[] or empty array if this isn't a group registration.
1782
+	 * @throws EE_Error
1783
+	 */
1784
+	public function get_all_other_registrations_in_group()
1785
+	{
1786
+		if ($this->group_size() < 2) {
1787
+			return array();
1788
+		}
1789
+
1790
+		$query[0] = array(
1791
+			'TXN_ID' => $this->transaction_ID(),
1792
+			'REG_ID' => array('!=', $this->ID()),
1793
+			'TKT_ID' => $this->ticket_ID(),
1794
+		);
1795
+		/** @var EE_Registration[] $registrations */
1796
+		$registrations = $this->get_model()->get_all($query);
1797
+		return $registrations;
1798
+	}
1799
+
1800
+	/**
1801
+	 * Return the link to the admin details for the object.
1802
+	 *
1803
+	 * @return string
1804
+	 * @throws EE_Error
1805
+	 */
1806
+	public function get_admin_details_link()
1807
+	{
1808
+		EE_Registry::instance()->load_helper('URL');
1809
+		return EEH_URL::add_query_args_and_nonce(
1810
+			array(
1811
+				'page'    => 'espresso_registrations',
1812
+				'action'  => 'view_registration',
1813
+				'_REG_ID' => $this->ID(),
1814
+			),
1815
+			admin_url('admin.php')
1816
+		);
1817
+	}
1818
+
1819
+	/**
1820
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
1821
+	 *
1822
+	 * @return string
1823
+	 * @throws EE_Error
1824
+	 */
1825
+	public function get_admin_edit_link()
1826
+	{
1827
+		return $this->get_admin_details_link();
1828
+	}
1829
+
1830
+	/**
1831
+	 * Returns the link to a settings page for the object.
1832
+	 *
1833
+	 * @return string
1834
+	 * @throws EE_Error
1835
+	 */
1836
+	public function get_admin_settings_link()
1837
+	{
1838
+		return $this->get_admin_details_link();
1839
+	}
1840
+
1841
+	/**
1842
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
1843
+	 *
1844
+	 * @return string
1845
+	 */
1846
+	public function get_admin_overview_link()
1847
+	{
1848
+		EE_Registry::instance()->load_helper('URL');
1849
+		return EEH_URL::add_query_args_and_nonce(
1850
+			array(
1851
+				'page' => 'espresso_registrations',
1852
+			),
1853
+			admin_url('admin.php')
1854
+		);
1855
+	}
1856
+
1857
+
1858
+	/**
1859
+	 * @param array $query_params
1860
+	 *
1861
+	 * @return \EE_Registration[]
1862
+	 * @throws EE_Error
1863
+	 */
1864
+	public function payments($query_params = array())
1865
+	{
1866
+		return $this->get_many_related('Payment', $query_params);
1867
+	}
1868
+
1869
+
1870
+	/**
1871
+	 * @param array $query_params
1872
+	 *
1873
+	 * @return \EE_Registration_Payment[]
1874
+	 * @throws EE_Error
1875
+	 */
1876
+	public function registration_payments($query_params = array())
1877
+	{
1878
+		return $this->get_many_related('Registration_Payment', $query_params);
1879
+	}
1880
+
1881
+
1882
+	/**
1883
+	 * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
1884
+	 * Note: if there are no payments on the registration there will be no payment method returned.
1885
+	 *
1886
+	 * @return EE_Payment_Method|null
1887
+	 */
1888
+	public function payment_method()
1889
+	{
1890
+		return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
1891
+	}
1892
+
1893
+
1894
+	/**
1895
+	 * @return \EE_Line_Item
1896
+	 * @throws EntityNotFoundException
1897
+	 * @throws EE_Error
1898
+	 */
1899
+	public function ticket_line_item()
1900
+	{
1901
+		$ticket = $this->ticket();
1902
+		$transaction = $this->transaction();
1903
+		$line_item = null;
1904
+		$ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
1905
+			$transaction->total_line_item(),
1906
+			'Ticket',
1907
+			array($ticket->ID())
1908
+		);
1909
+		foreach ($ticket_line_items as $ticket_line_item) {
1910
+			if ($ticket_line_item instanceof \EE_Line_Item
1911
+				&& $ticket_line_item->OBJ_type() === 'Ticket'
1912
+				&& $ticket_line_item->OBJ_ID() === $ticket->ID()
1913
+			) {
1914
+				$line_item = $ticket_line_item;
1915
+				break;
1916
+			}
1917
+		}
1918
+		if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1919
+			throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
1920
+		}
1921
+		return $line_item;
1922
+	}
1923
+
1924
+
1925
+	/**
1926
+	 * Soft Deletes this model object.
1927
+	 *
1928
+	 * @return boolean | int
1929
+	 * @throws RuntimeException
1930
+	 * @throws EE_Error
1931
+	 */
1932
+	public function delete()
1933
+	{
1934
+		if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
1935
+			$this->set_status(EEM_Registration::status_id_cancelled);
1936
+		}
1937
+		return parent::delete();
1938
+	}
1939
+
1940
+
1941
+	/**
1942
+	 * Restores whatever the previous status was on a registration before it was trashed (if possible)
1943
+	 *
1944
+	 * @throws EE_Error
1945
+	 * @throws RuntimeException
1946
+	 */
1947
+	public function restore()
1948
+	{
1949
+		$previous_status = $this->get_extra_meta(
1950
+			EE_Registration::PRE_TRASH_REG_STATUS_KEY,
1951
+			true,
1952
+			EEM_Registration::status_id_cancelled
1953
+		);
1954
+		if ($previous_status) {
1955
+			$this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
1956
+			$this->set_status($previous_status);
1957
+		}
1958
+		return parent::restore();
1959
+	}
1960
+
1961
+
1962
+	/**
1963
+	 * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
1964
+	 *
1965
+	 * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
1966
+	 *                                           depending on whether the reg status changes to or from "Approved"
1967
+	 * @return boolean whether the Registration status was updated
1968
+	 * @throws EE_Error
1969
+	 * @throws RuntimeException
1970
+	 */
1971
+	public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
1972
+	{
1973
+		$paid = $this->paid();
1974
+		$price = $this->final_price();
1975
+		switch (true) {
1976
+			// overpaid or paid
1977
+			case EEH_Money::compare_floats($paid, $price, '>'):
1978
+			case EEH_Money::compare_floats($paid, $price):
1979
+				$new_status = EEM_Registration::status_id_approved;
1980
+				break;
1981
+			//  underpaid
1982
+			case EEH_Money::compare_floats($paid, $price, '<'):
1983
+				$new_status = EEM_Registration::status_id_pending_payment;
1984
+				break;
1985
+			// uhhh Houston...
1986
+			default:
1987
+				throw new RuntimeException(
1988
+					esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
1989
+				);
1990
+		}
1991
+		if ($new_status !== $this->status_ID()) {
1992
+			if ($trigger_set_status_logic) {
1993
+				return $this->set_status($new_status);
1994
+			}
1995
+			parent::set('STS_ID', $new_status);
1996
+			return true;
1997
+		}
1998
+		return false;
1999
+	}
2000
+
2001
+
2002
+	/*************************** DEPRECATED ***************************/
2003
+
2004
+
2005
+	/**
2006
+	 * @deprecated
2007
+	 * @since     4.7.0
2008
+	 * @access    public
2009
+	 */
2010
+	public function price_paid()
2011
+	{
2012
+		EE_Error::doing_it_wrong(
2013
+			'EE_Registration::price_paid()',
2014
+			esc_html__(
2015
+				'This method is deprecated, please use EE_Registration::final_price() instead.',
2016
+				'event_espresso'
2017
+			),
2018
+			'4.7.0'
2019
+		);
2020
+		return $this->final_price();
2021
+	}
2022
+
2023
+
2024
+	/**
2025
+	 * @deprecated
2026
+	 * @since     4.7.0
2027
+	 * @access    public
2028
+	 * @param    float $REG_final_price
2029
+	 * @throws EE_Error
2030
+	 * @throws RuntimeException
2031
+	 */
2032
+	public function set_price_paid($REG_final_price = 0.00)
2033
+	{
2034
+		EE_Error::doing_it_wrong(
2035
+			'EE_Registration::set_price_paid()',
2036
+			esc_html__(
2037
+				'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2038
+				'event_espresso'
2039
+			),
2040
+			'4.7.0'
2041
+		);
2042
+		$this->set_final_price($REG_final_price);
2043
+	}
2044
+
2045
+
2046
+	/**
2047
+	 * @deprecated
2048
+	 * @since 4.7.0
2049
+	 * @return string
2050
+	 * @throws EE_Error
2051
+	 */
2052
+	public function pretty_price_paid()
2053
+	{
2054
+		EE_Error::doing_it_wrong(
2055
+			'EE_Registration::pretty_price_paid()',
2056
+			esc_html__(
2057
+				'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2058
+				'event_espresso'
2059
+			),
2060
+			'4.7.0'
2061
+		);
2062
+		return $this->pretty_final_price();
2063
+	}
2064
+
2065
+
2066
+	/**
2067
+	 * Gets the primary datetime related to this registration via the related Event to this registration
2068
+	 *
2069
+	 * @deprecated 4.9.17
2070
+	 * @return EE_Datetime
2071
+	 * @throws EE_Error
2072
+	 * @throws EntityNotFoundException
2073
+	 */
2074
+	public function get_related_primary_datetime()
2075
+	{
2076
+		EE_Error::doing_it_wrong(
2077
+			__METHOD__,
2078
+			esc_html__(
2079
+				'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2080
+				'event_espresso'
2081
+			),
2082
+			'4.9.17',
2083
+			'5.0.0'
2084
+		);
2085
+		return $this->event()->primary_datetime();
2086
+	}
2087 2087
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
     {
120 120
         switch ($field_name) {
121 121
             case 'REG_code':
122
-                if (! empty($field_value) && $this->reg_code() === null) {
122
+                if ( ! empty($field_value) && $this->reg_code() === null) {
123 123
                     $this->set_reg_code($field_value, $use_default);
124 124
                 }
125 125
                 break;
@@ -396,7 +396,7 @@  discard block
 block discarded – undo
396 396
     public function event()
397 397
     {
398 398
         $event = $this->get_first_related('Event');
399
-        if (! $event instanceof \EE_Event) {
399
+        if ( ! $event instanceof \EE_Event) {
400 400
             throw new EntityNotFoundException('Event ID', $this->event_ID());
401 401
         }
402 402
         return $event;
@@ -439,7 +439,7 @@  discard block
 block discarded – undo
439 439
     {
440 440
         // reserved ticket and datetime counts will be decremented as sold counts are incremented
441 441
         // so stop tracking that this reg has a ticket reserved
442
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
442
+        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:".__LINE__.')');
443 443
         $ticket = $this->ticket();
444 444
         $ticket->increase_sold();
445 445
         $ticket->save();
@@ -495,7 +495,7 @@  discard block
 block discarded – undo
495 495
                 && $update_ticket
496 496
             ) {
497 497
                 $ticket = $this->ticket();
498
-                $ticket->increase_reserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
498
+                $ticket->increase_reserved(1, "REG: {$this->ID()} (ln:".__LINE__.')');
499 499
                 $ticket->save();
500 500
             }
501 501
         }
@@ -526,7 +526,7 @@  discard block
 block discarded – undo
526 526
                 && $update_ticket
527 527
             ) {
528 528
                 $ticket = $this->ticket();
529
-                $ticket->decrease_reserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
529
+                $ticket->decrease_reserved(1, true, "REG: {$this->ID()} (ln:".__LINE__.')');
530 530
                 $ticket->save();
531 531
             }
532 532
         }
@@ -1201,7 +1201,7 @@  discard block
 block discarded – undo
1201 1201
                     : '';
1202 1202
                 break;
1203 1203
         }
1204
-        return $icon . $status[ $this->status_ID() ];
1204
+        return $icon.$status[$this->status_ID()];
1205 1205
     }
1206 1206
 
1207 1207
 
@@ -1419,7 +1419,7 @@  discard block
 block discarded – undo
1419 1419
             return false;
1420 1420
         }
1421 1421
         // is there a datetime ticket that matches this dtt_ID?
1422
-        if (! (EEM_Datetime_Ticket::instance()->exists(
1422
+        if ( ! (EEM_Datetime_Ticket::instance()->exists(
1423 1423
             array(
1424 1424
                 array(
1425 1425
                     'TKT_ID' => $this->get('TKT_ID'),
@@ -1450,7 +1450,7 @@  discard block
 block discarded – undo
1450 1450
     {
1451 1451
         $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1452 1452
 
1453
-        if (! $DTT_ID) {
1453
+        if ( ! $DTT_ID) {
1454 1454
             return false;
1455 1455
         }
1456 1456
 
@@ -1458,7 +1458,7 @@  discard block
 block discarded – undo
1458 1458
 
1459 1459
         // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1460 1460
         // check-in or not.
1461
-        if (! $max_uses || $max_uses === EE_INF) {
1461
+        if ( ! $max_uses || $max_uses === EE_INF) {
1462 1462
             return true;
1463 1463
         }
1464 1464
 
@@ -1518,7 +1518,7 @@  discard block
 block discarded – undo
1518 1518
             $datetime = $this->get_latest_related_datetime();
1519 1519
             $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1520 1520
             // verify the registration can checkin for the given DTT_ID
1521
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1521
+        } elseif ( ! $this->can_checkin($DTT_ID, $verify)) {
1522 1522
             EE_Error::add_error(
1523 1523
                 sprintf(
1524 1524
                     esc_html__(
@@ -1541,7 +1541,7 @@  discard block
 block discarded – undo
1541 1541
         );
1542 1542
         // start by getting the current status so we know what status we'll be changing to.
1543 1543
         $cur_status = $this->check_in_status_for_datetime($DTT_ID, null);
1544
-        $status_to = $status_paths[ $cur_status ];
1544
+        $status_to = $status_paths[$cur_status];
1545 1545
         // database only records true for checked IN or false for checked OUT
1546 1546
         // no record ( null ) means checked in NEVER, but we obviously don't save that
1547 1547
         $new_status = $status_to === EE_Checkin::status_checked_in ? true : false;
@@ -1706,7 +1706,7 @@  discard block
 block discarded – undo
1706 1706
     public function transaction()
1707 1707
     {
1708 1708
         $transaction = $this->get_first_related('Transaction');
1709
-        if (! $transaction instanceof \EE_Transaction) {
1709
+        if ( ! $transaction instanceof \EE_Transaction) {
1710 1710
             throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1711 1711
         }
1712 1712
         return $transaction;
@@ -1760,11 +1760,11 @@  discard block
 block discarded – undo
1760 1760
             );
1761 1761
             return;
1762 1762
         }
1763
-        if (! $this->reg_code()) {
1763
+        if ( ! $this->reg_code()) {
1764 1764
             parent::set('REG_code', $REG_code, $use_default);
1765 1765
         } else {
1766 1766
             EE_Error::doing_it_wrong(
1767
-                __CLASS__ . '::' . __FUNCTION__,
1767
+                __CLASS__.'::'.__FUNCTION__,
1768 1768
                 esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
1769 1769
                 '4.6.0'
1770 1770
             );
@@ -1915,7 +1915,7 @@  discard block
 block discarded – undo
1915 1915
                 break;
1916 1916
             }
1917 1917
         }
1918
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1918
+        if ( ! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1919 1919
             throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
1920 1920
         }
1921 1921
         return $line_item;
Please login to merge, or discard this patch.
core/db_classes/EE_Checkin.class.php 1 patch
Indentation   +82 added lines, -82 removed lines patch added patch discarded remove patch
@@ -11,86 +11,86 @@
 block discarded – undo
11 11
 {
12 12
 
13 13
 
14
-    /**
15
-     * Used to reference when a registration has been checked out.
16
-     *
17
-     * @type int
18
-     */
19
-    const status_checked_out = 0;
20
-
21
-    /**
22
-     * Used to reference when a registration has been checked in.
23
-     *
24
-     * @type int
25
-     */
26
-    const status_checked_in = 1;
27
-
28
-    /**
29
-     * Used to reference when a registration has never been checked in.
30
-     *
31
-     * @type int
32
-     */
33
-    const status_checked_never = 2;
34
-
35
-
36
-    /**
37
-     *
38
-     * @param array  $props_n_values    incoming values
39
-     * @param string $timezone          incoming timezone (if not set the timezone set for the website will be used.)
40
-     * @param array  $date_formats      incoming date_formats in an array
41
-     *                                  where the first value is the date_format
42
-     *                                  and the second value is the time format
43
-     * @return EE_Checkin
44
-     * @throws EE_Error
45
-     */
46
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
47
-    {
48
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
49
-        return $has_object
50
-            ? $has_object
51
-            : new self($props_n_values, false, $timezone, $date_formats);
52
-    }
53
-
54
-
55
-    /**
56
-     * @param array  $props_n_values  incoming values from the database
57
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
58
-     *                                the website will be used.
59
-     * @return EE_Checkin
60
-     * @throws EE_Error
61
-     */
62
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
63
-    {
64
-        return new self($props_n_values, true, $timezone);
65
-    }
66
-
67
-
68
-    public function ID()
69
-    {
70
-        return $this->get('CHK_ID');
71
-    }
72
-
73
-
74
-    public function registration_id()
75
-    {
76
-        return $this->get('REG_ID');
77
-    }
78
-
79
-
80
-    public function datetime_id()
81
-    {
82
-        return $this->get('DTT_ID');
83
-    }
84
-
85
-
86
-    public function status()
87
-    {
88
-        return $this->get('CHK_in');
89
-    }
90
-
91
-
92
-    public function timestamp()
93
-    {
94
-        return $this->get('CHK_timestamp');
95
-    }
14
+	/**
15
+	 * Used to reference when a registration has been checked out.
16
+	 *
17
+	 * @type int
18
+	 */
19
+	const status_checked_out = 0;
20
+
21
+	/**
22
+	 * Used to reference when a registration has been checked in.
23
+	 *
24
+	 * @type int
25
+	 */
26
+	const status_checked_in = 1;
27
+
28
+	/**
29
+	 * Used to reference when a registration has never been checked in.
30
+	 *
31
+	 * @type int
32
+	 */
33
+	const status_checked_never = 2;
34
+
35
+
36
+	/**
37
+	 *
38
+	 * @param array  $props_n_values    incoming values
39
+	 * @param string $timezone          incoming timezone (if not set the timezone set for the website will be used.)
40
+	 * @param array  $date_formats      incoming date_formats in an array
41
+	 *                                  where the first value is the date_format
42
+	 *                                  and the second value is the time format
43
+	 * @return EE_Checkin
44
+	 * @throws EE_Error
45
+	 */
46
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
47
+	{
48
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
49
+		return $has_object
50
+			? $has_object
51
+			: new self($props_n_values, false, $timezone, $date_formats);
52
+	}
53
+
54
+
55
+	/**
56
+	 * @param array  $props_n_values  incoming values from the database
57
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
58
+	 *                                the website will be used.
59
+	 * @return EE_Checkin
60
+	 * @throws EE_Error
61
+	 */
62
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
63
+	{
64
+		return new self($props_n_values, true, $timezone);
65
+	}
66
+
67
+
68
+	public function ID()
69
+	{
70
+		return $this->get('CHK_ID');
71
+	}
72
+
73
+
74
+	public function registration_id()
75
+	{
76
+		return $this->get('REG_ID');
77
+	}
78
+
79
+
80
+	public function datetime_id()
81
+	{
82
+		return $this->get('DTT_ID');
83
+	}
84
+
85
+
86
+	public function status()
87
+	{
88
+		return $this->get('CHK_in');
89
+	}
90
+
91
+
92
+	public function timestamp()
93
+	{
94
+		return $this->get('CHK_timestamp');
95
+	}
96 96
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Payment_Method.class.php 2 patches
Indentation   +568 added lines, -568 removed lines patch added patch discarded remove patch
@@ -11,578 +11,578 @@
 block discarded – undo
11 11
 class EE_Payment_Method extends EE_Base_Class
12 12
 {
13 13
 
14
-    /**
15
-     * Payment Method type object, which has all the info about this type of payment method,
16
-     * including functions for processing payments, to get settings forms, etc.
17
-     *
18
-     * @var EE_PMT_Base
19
-     */
20
-    protected $_type_obj;
21
-
22
-
23
-    /**
24
-     * @param array $props_n_values
25
-     * @return EE_Payment_Method
26
-     * @throws \EE_Error
27
-     */
28
-    public static function new_instance($props_n_values = array())
29
-    {
30
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__);
31
-        return $has_object ? $has_object : new self($props_n_values, false);
32
-    }
33
-
34
-
35
-    /**
36
-     * @param array $props_n_values
37
-     * @return EE_Payment_Method
38
-     * @throws \EE_Error
39
-     */
40
-    public static function new_instance_from_db($props_n_values = array())
41
-    {
42
-        return new self($props_n_values, true);
43
-    }
44
-
45
-
46
-
47
-    /**
48
-     * Checks if there is a payment method class of the given 'PMD_type', and if so returns the classname.
49
-     * Otherwise returns a normal EE_Payment_Method
50
-     *
51
-     * @param array $props_n_values where 'PMD_type' is a gateway name like 'Paypal_Standard','Invoice',etc (basically
52
-     *                              the classname minus 'EEPM_')
53
-     * @return string
54
-     */
55
-    // private static function _payment_method_type($props_n_values)
56
-    // {
57
-    //     EE_Registry::instance()->load_lib('Payment_Method_Manager');
58
-    //     $type_string = isset($props_n_values['PMD_type']) ? $props_n_values['PMD_type'] : null;
59
-    //     if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($type_string)) {
60
-    //         return 'EEPM_' . $type_string;
61
-    //     } else {
62
-    //         return __CLASS__;
63
-    //     }
64
-    // }
65
-
66
-
67
-    /**
68
-     * Gets whether this payment method can be used anywhere at all (ie frontend cart, admin, etc)
69
-     *
70
-     * @return boolean
71
-     */
72
-    public function active()
73
-    {
74
-        return array_intersect(array_keys(EEM_Payment_Method::instance()->scopes()), $this->scope());
75
-    }
76
-
77
-
78
-    /**
79
-     * Sets this PM as active by making it usable within the CART scope. Offline gateways
80
-     * are also usable from the admin-scope as well. DOES NOT SAVE it
81
-     *
82
-     * @throws \EE_Error
83
-     */
84
-    public function set_active()
85
-    {
86
-        $default_scopes = array(EEM_Payment_Method::scope_cart);
87
-        if ($this->type_obj() &&
88
-            $this->type_obj()->payment_occurs() === EE_PMT_Base::offline) {
89
-            $default_scopes[] = EEM_Payment_Method::scope_admin;
90
-        }
91
-        $this->set_scope($default_scopes);
92
-    }
93
-
94
-
95
-    /**
96
-     * Makes this payment method apply to NO scopes at all. DOES NOT SAVE it.
97
-     */
98
-    public function deactivate()
99
-    {
100
-        $this->set_scope(array());
101
-    }
102
-
103
-
104
-    /**
105
-     * Gets button_url
106
-     *
107
-     * @return string
108
-     */
109
-    public function button_url()
110
-    {
111
-        return $this->get('PMD_button_url');
112
-    }
113
-
114
-
115
-    /**
116
-     * Sets button_url
117
-     *
118
-     * @param string $button_url
119
-     */
120
-    public function set_button_url($button_url)
121
-    {
122
-        $this->set('PMD_button_url', $button_url);
123
-    }
124
-
125
-
126
-    /**
127
-     * Gets debug_mode
128
-     *
129
-     * @return boolean
130
-     */
131
-    public function debug_mode()
132
-    {
133
-        return $this->get('PMD_debug_mode');
134
-    }
135
-
136
-
137
-    /**
138
-     * Sets debug_mode
139
-     *
140
-     * @param boolean $debug_mode
141
-     */
142
-    public function set_debug_mode($debug_mode)
143
-    {
144
-        $this->set('PMD_debug_mode', $debug_mode);
145
-    }
146
-
147
-
148
-    /**
149
-     * Gets description
150
-     *
151
-     * @return string
152
-     */
153
-    public function description()
154
-    {
155
-        return $this->get('PMD_desc');
156
-    }
157
-
158
-
159
-    /**
160
-     * Sets description
161
-     *
162
-     * @param string $description
163
-     */
164
-    public function set_description($description)
165
-    {
166
-        $this->set('PMD_desc', $description);
167
-    }
168
-
169
-
170
-    /**
171
-     * Gets name
172
-     *
173
-     * @return string
174
-     */
175
-    public function name()
176
-    {
177
-        return $this->get('PMD_name');
178
-    }
179
-
180
-
181
-    /**
182
-     * Sets name
183
-     *
184
-     * @param string $name
185
-     */
186
-    public function set_name($name)
187
-    {
188
-        $this->set('PMD_name', $name);
189
-    }
190
-
191
-
192
-    /**
193
-     * Gets open_by_default
194
-     *
195
-     * @return boolean
196
-     */
197
-    public function open_by_default()
198
-    {
199
-        return $this->get('PMD_open_by_default');
200
-    }
201
-
202
-
203
-    /**
204
-     * Sets open_by_default
205
-     *
206
-     * @param boolean $open_by_default
207
-     */
208
-    public function set_open_by_default($open_by_default)
209
-    {
210
-        $this->set('PMD_open_by_default', $open_by_default);
211
-    }
212
-
213
-
214
-    /**
215
-     * Gets order
216
-     *
217
-     * @return int
218
-     */
219
-    public function order()
220
-    {
221
-        return $this->get('PMD_order');
222
-    }
223
-
224
-
225
-    /**
226
-     * Sets order
227
-     *
228
-     * @param int $order
229
-     */
230
-    public function set_order($order)
231
-    {
232
-        $this->set('PMD_order', $order);
233
-    }
234
-
235
-
236
-    /**
237
-     * Gets slug
238
-     *
239
-     * @return string
240
-     */
241
-    public function slug()
242
-    {
243
-        return $this->get('PMD_slug');
244
-    }
245
-
246
-
247
-    /**
248
-     * Sets slug
249
-     *
250
-     * @param string $slug
251
-     */
252
-    public function set_slug($slug)
253
-    {
254
-        $this->set('PMD_slug', $slug);
255
-    }
256
-
257
-
258
-    /**
259
-     * Gets type
260
-     *
261
-     * @return string
262
-     */
263
-    public function type()
264
-    {
265
-        return $this->get('PMD_type');
266
-    }
267
-
268
-
269
-    /**
270
-     * Sets type
271
-     *
272
-     * @param string $type
273
-     */
274
-    public function set_type($type)
275
-    {
276
-        $this->set('PMD_type', $type);
277
-    }
278
-
279
-
280
-    /**
281
-     * Gets wp_user
282
-     *
283
-     * @return int
284
-     */
285
-    public function wp_user()
286
-    {
287
-        return $this->get('PMD_wp_user');
288
-    }
289
-
290
-
291
-    /**
292
-     * Sets wp_user
293
-     *
294
-     * @param int $wp_user_id
295
-     */
296
-    public function set_wp_user($wp_user_id)
297
-    {
298
-        $this->set('PMD_wp_user', $wp_user_id);
299
-    }
300
-
301
-    /**
302
-     * Overrides parent so when PMD_type is changed we refresh the _type_obj
303
-     *
304
-     * @param string $field_name
305
-     * @param mixed $field_value
306
-     * @param boolean $use_default
307
-     */
308
-    public function set($field_name, $field_value, $use_default = false)
309
-    {
310
-        if ($field_name === 'PMD_type') {
311
-            // the type has probably changed, so forget about its old type object
312
-            $this->_type_obj = null;
313
-        }
314
-        parent::set($field_name, $field_value, $use_default);
315
-    }
316
-
317
-
318
-    /**
319
-     * Gets admin_name
320
-     *
321
-     * @return string
322
-     */
323
-    public function admin_name()
324
-    {
325
-        return $this->get('PMD_admin_name');
326
-    }
327
-
328
-
329
-    /**
330
-     * Sets admin_name
331
-     *
332
-     * @param string $admin_name
333
-     */
334
-    public function set_admin_name($admin_name)
335
-    {
336
-        $this->set('PMD_admin_name', $admin_name);
337
-    }
338
-
339
-
340
-    /**
341
-     * Gets admin_desc
342
-     *
343
-     * @return string
344
-     */
345
-    public function admin_desc()
346
-    {
347
-        return $this->get('PMD_admin_desc');
348
-    }
349
-
350
-
351
-    /**
352
-     * Sets admin_desc
353
-     *
354
-     * @param string $admin_desc
355
-     */
356
-    public function set_admin_desc($admin_desc)
357
-    {
358
-        $this->set('PMD_admin_desc', $admin_desc);
359
-    }
360
-
361
-
362
-    /**
363
-     * Gets scope
364
-     *
365
-     * @return array
366
-     */
367
-    public function scope()
368
-    {
369
-        return $this->get('PMD_scope');
370
-    }
371
-
372
-
373
-    /**
374
-     * Sets scope
375
-     *
376
-     * @param array $scope
377
-     */
378
-    public function set_scope($scope)
379
-    {
380
-        $this->set('PMD_scope', $scope);
381
-    }
382
-
383
-
384
-    /**
385
-     * Gets the payment method type for this payment method instance
386
-     *
387
-     * @return EE_PMT_Base
388
-     * @throws EE_Error
389
-     */
390
-    public function type_obj()
391
-    {
392
-        if (! $this->_type_obj) {
393
-            EE_Registry::instance()->load_lib('Payment_Method_Manager');
394
-            if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($this->type())) {
395
-                $class_name = EE_Payment_Method_Manager::instance()->payment_method_class_from_type($this->type());
396
-                if (! class_exists($class_name)) {
397
-                    throw new EE_Error(
398
-                        sprintf(
399
-                            __(
400
-                                'An attempt to use the "%1$s" payment method failed, so it was deactivated.%2$sWas the "%1$s" Plugin recently deactivated? It can be reactivated on the %3$sPlugins Admin Page%4$s',
401
-                                'event_espresso'
402
-                            ),
403
-                            $class_name,
404
-                            '<br />',
405
-                            '<a href="' . admin_url('plugins.php') . '">',
406
-                            '</a>'
407
-                        )
408
-                    );
409
-                }
410
-                $r = new ReflectionClass($class_name);
411
-                $this->_type_obj = $r->newInstanceArgs(array($this));
412
-            } else {
413
-                throw new EE_Error(
414
-                    sprintf(
415
-                        __(
416
-                            'A payment method of type "%1$s" does not exist. Only ones existing are: %2$s',
417
-                            'event_espresso'
418
-                        ),
419
-                        $this->type(),
420
-                        implode(',', EE_Payment_Method_Manager::instance()->payment_method_type_names())
421
-                    )
422
-                );
423
-            }
424
-        }
425
-        return $this->_type_obj;
426
-    }
427
-
428
-
429
-    /**
430
-     * Returns a simple array of key-value pairs combining the payment method's fields (without the 'PMD_' prefix)
431
-     * and the extra meta. Mostly used for passing off ot gateways.     *
432
-     *
433
-     * @return array
434
-     */
435
-    public function settings_array()
436
-    {
437
-        $fields = $this->model_field_array();
438
-        $extra_meta = $this->all_extra_meta_array();
439
-        // remove the model's prefix from the fields
440
-        $combined_settings_array = array();
441
-        foreach ($fields as $key => $value) {
442
-            if (strpos($key, 'PMD_') === 0) {
443
-                $key_sans_model_prefix = str_replace('PMD_', '', $key);
444
-                $combined_settings_array [ $key_sans_model_prefix ] = $value;
445
-            }
446
-        }
447
-        $combined_settings_array = array_merge($extra_meta, $combined_settings_array);
448
-        return $combined_settings_array;
449
-    }
450
-
451
-
452
-    /**
453
-     * Gets the HTML for displaying the payment method on a page.
454
-     *
455
-     * @param string $url
456
-     * @param string $css_class
457
-     * @return string of HTML for displaying the button
458
-     * @throws \EE_Error
459
-     */
460
-    public function button_html($url = '', $css_class = '')
461
-    {
462
-        $payment_occurs = $this->type_obj()->payment_occurs();
463
-        return '
14
+	/**
15
+	 * Payment Method type object, which has all the info about this type of payment method,
16
+	 * including functions for processing payments, to get settings forms, etc.
17
+	 *
18
+	 * @var EE_PMT_Base
19
+	 */
20
+	protected $_type_obj;
21
+
22
+
23
+	/**
24
+	 * @param array $props_n_values
25
+	 * @return EE_Payment_Method
26
+	 * @throws \EE_Error
27
+	 */
28
+	public static function new_instance($props_n_values = array())
29
+	{
30
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__);
31
+		return $has_object ? $has_object : new self($props_n_values, false);
32
+	}
33
+
34
+
35
+	/**
36
+	 * @param array $props_n_values
37
+	 * @return EE_Payment_Method
38
+	 * @throws \EE_Error
39
+	 */
40
+	public static function new_instance_from_db($props_n_values = array())
41
+	{
42
+		return new self($props_n_values, true);
43
+	}
44
+
45
+
46
+
47
+	/**
48
+	 * Checks if there is a payment method class of the given 'PMD_type', and if so returns the classname.
49
+	 * Otherwise returns a normal EE_Payment_Method
50
+	 *
51
+	 * @param array $props_n_values where 'PMD_type' is a gateway name like 'Paypal_Standard','Invoice',etc (basically
52
+	 *                              the classname minus 'EEPM_')
53
+	 * @return string
54
+	 */
55
+	// private static function _payment_method_type($props_n_values)
56
+	// {
57
+	//     EE_Registry::instance()->load_lib('Payment_Method_Manager');
58
+	//     $type_string = isset($props_n_values['PMD_type']) ? $props_n_values['PMD_type'] : null;
59
+	//     if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($type_string)) {
60
+	//         return 'EEPM_' . $type_string;
61
+	//     } else {
62
+	//         return __CLASS__;
63
+	//     }
64
+	// }
65
+
66
+
67
+	/**
68
+	 * Gets whether this payment method can be used anywhere at all (ie frontend cart, admin, etc)
69
+	 *
70
+	 * @return boolean
71
+	 */
72
+	public function active()
73
+	{
74
+		return array_intersect(array_keys(EEM_Payment_Method::instance()->scopes()), $this->scope());
75
+	}
76
+
77
+
78
+	/**
79
+	 * Sets this PM as active by making it usable within the CART scope. Offline gateways
80
+	 * are also usable from the admin-scope as well. DOES NOT SAVE it
81
+	 *
82
+	 * @throws \EE_Error
83
+	 */
84
+	public function set_active()
85
+	{
86
+		$default_scopes = array(EEM_Payment_Method::scope_cart);
87
+		if ($this->type_obj() &&
88
+			$this->type_obj()->payment_occurs() === EE_PMT_Base::offline) {
89
+			$default_scopes[] = EEM_Payment_Method::scope_admin;
90
+		}
91
+		$this->set_scope($default_scopes);
92
+	}
93
+
94
+
95
+	/**
96
+	 * Makes this payment method apply to NO scopes at all. DOES NOT SAVE it.
97
+	 */
98
+	public function deactivate()
99
+	{
100
+		$this->set_scope(array());
101
+	}
102
+
103
+
104
+	/**
105
+	 * Gets button_url
106
+	 *
107
+	 * @return string
108
+	 */
109
+	public function button_url()
110
+	{
111
+		return $this->get('PMD_button_url');
112
+	}
113
+
114
+
115
+	/**
116
+	 * Sets button_url
117
+	 *
118
+	 * @param string $button_url
119
+	 */
120
+	public function set_button_url($button_url)
121
+	{
122
+		$this->set('PMD_button_url', $button_url);
123
+	}
124
+
125
+
126
+	/**
127
+	 * Gets debug_mode
128
+	 *
129
+	 * @return boolean
130
+	 */
131
+	public function debug_mode()
132
+	{
133
+		return $this->get('PMD_debug_mode');
134
+	}
135
+
136
+
137
+	/**
138
+	 * Sets debug_mode
139
+	 *
140
+	 * @param boolean $debug_mode
141
+	 */
142
+	public function set_debug_mode($debug_mode)
143
+	{
144
+		$this->set('PMD_debug_mode', $debug_mode);
145
+	}
146
+
147
+
148
+	/**
149
+	 * Gets description
150
+	 *
151
+	 * @return string
152
+	 */
153
+	public function description()
154
+	{
155
+		return $this->get('PMD_desc');
156
+	}
157
+
158
+
159
+	/**
160
+	 * Sets description
161
+	 *
162
+	 * @param string $description
163
+	 */
164
+	public function set_description($description)
165
+	{
166
+		$this->set('PMD_desc', $description);
167
+	}
168
+
169
+
170
+	/**
171
+	 * Gets name
172
+	 *
173
+	 * @return string
174
+	 */
175
+	public function name()
176
+	{
177
+		return $this->get('PMD_name');
178
+	}
179
+
180
+
181
+	/**
182
+	 * Sets name
183
+	 *
184
+	 * @param string $name
185
+	 */
186
+	public function set_name($name)
187
+	{
188
+		$this->set('PMD_name', $name);
189
+	}
190
+
191
+
192
+	/**
193
+	 * Gets open_by_default
194
+	 *
195
+	 * @return boolean
196
+	 */
197
+	public function open_by_default()
198
+	{
199
+		return $this->get('PMD_open_by_default');
200
+	}
201
+
202
+
203
+	/**
204
+	 * Sets open_by_default
205
+	 *
206
+	 * @param boolean $open_by_default
207
+	 */
208
+	public function set_open_by_default($open_by_default)
209
+	{
210
+		$this->set('PMD_open_by_default', $open_by_default);
211
+	}
212
+
213
+
214
+	/**
215
+	 * Gets order
216
+	 *
217
+	 * @return int
218
+	 */
219
+	public function order()
220
+	{
221
+		return $this->get('PMD_order');
222
+	}
223
+
224
+
225
+	/**
226
+	 * Sets order
227
+	 *
228
+	 * @param int $order
229
+	 */
230
+	public function set_order($order)
231
+	{
232
+		$this->set('PMD_order', $order);
233
+	}
234
+
235
+
236
+	/**
237
+	 * Gets slug
238
+	 *
239
+	 * @return string
240
+	 */
241
+	public function slug()
242
+	{
243
+		return $this->get('PMD_slug');
244
+	}
245
+
246
+
247
+	/**
248
+	 * Sets slug
249
+	 *
250
+	 * @param string $slug
251
+	 */
252
+	public function set_slug($slug)
253
+	{
254
+		$this->set('PMD_slug', $slug);
255
+	}
256
+
257
+
258
+	/**
259
+	 * Gets type
260
+	 *
261
+	 * @return string
262
+	 */
263
+	public function type()
264
+	{
265
+		return $this->get('PMD_type');
266
+	}
267
+
268
+
269
+	/**
270
+	 * Sets type
271
+	 *
272
+	 * @param string $type
273
+	 */
274
+	public function set_type($type)
275
+	{
276
+		$this->set('PMD_type', $type);
277
+	}
278
+
279
+
280
+	/**
281
+	 * Gets wp_user
282
+	 *
283
+	 * @return int
284
+	 */
285
+	public function wp_user()
286
+	{
287
+		return $this->get('PMD_wp_user');
288
+	}
289
+
290
+
291
+	/**
292
+	 * Sets wp_user
293
+	 *
294
+	 * @param int $wp_user_id
295
+	 */
296
+	public function set_wp_user($wp_user_id)
297
+	{
298
+		$this->set('PMD_wp_user', $wp_user_id);
299
+	}
300
+
301
+	/**
302
+	 * Overrides parent so when PMD_type is changed we refresh the _type_obj
303
+	 *
304
+	 * @param string $field_name
305
+	 * @param mixed $field_value
306
+	 * @param boolean $use_default
307
+	 */
308
+	public function set($field_name, $field_value, $use_default = false)
309
+	{
310
+		if ($field_name === 'PMD_type') {
311
+			// the type has probably changed, so forget about its old type object
312
+			$this->_type_obj = null;
313
+		}
314
+		parent::set($field_name, $field_value, $use_default);
315
+	}
316
+
317
+
318
+	/**
319
+	 * Gets admin_name
320
+	 *
321
+	 * @return string
322
+	 */
323
+	public function admin_name()
324
+	{
325
+		return $this->get('PMD_admin_name');
326
+	}
327
+
328
+
329
+	/**
330
+	 * Sets admin_name
331
+	 *
332
+	 * @param string $admin_name
333
+	 */
334
+	public function set_admin_name($admin_name)
335
+	{
336
+		$this->set('PMD_admin_name', $admin_name);
337
+	}
338
+
339
+
340
+	/**
341
+	 * Gets admin_desc
342
+	 *
343
+	 * @return string
344
+	 */
345
+	public function admin_desc()
346
+	{
347
+		return $this->get('PMD_admin_desc');
348
+	}
349
+
350
+
351
+	/**
352
+	 * Sets admin_desc
353
+	 *
354
+	 * @param string $admin_desc
355
+	 */
356
+	public function set_admin_desc($admin_desc)
357
+	{
358
+		$this->set('PMD_admin_desc', $admin_desc);
359
+	}
360
+
361
+
362
+	/**
363
+	 * Gets scope
364
+	 *
365
+	 * @return array
366
+	 */
367
+	public function scope()
368
+	{
369
+		return $this->get('PMD_scope');
370
+	}
371
+
372
+
373
+	/**
374
+	 * Sets scope
375
+	 *
376
+	 * @param array $scope
377
+	 */
378
+	public function set_scope($scope)
379
+	{
380
+		$this->set('PMD_scope', $scope);
381
+	}
382
+
383
+
384
+	/**
385
+	 * Gets the payment method type for this payment method instance
386
+	 *
387
+	 * @return EE_PMT_Base
388
+	 * @throws EE_Error
389
+	 */
390
+	public function type_obj()
391
+	{
392
+		if (! $this->_type_obj) {
393
+			EE_Registry::instance()->load_lib('Payment_Method_Manager');
394
+			if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($this->type())) {
395
+				$class_name = EE_Payment_Method_Manager::instance()->payment_method_class_from_type($this->type());
396
+				if (! class_exists($class_name)) {
397
+					throw new EE_Error(
398
+						sprintf(
399
+							__(
400
+								'An attempt to use the "%1$s" payment method failed, so it was deactivated.%2$sWas the "%1$s" Plugin recently deactivated? It can be reactivated on the %3$sPlugins Admin Page%4$s',
401
+								'event_espresso'
402
+							),
403
+							$class_name,
404
+							'<br />',
405
+							'<a href="' . admin_url('plugins.php') . '">',
406
+							'</a>'
407
+						)
408
+					);
409
+				}
410
+				$r = new ReflectionClass($class_name);
411
+				$this->_type_obj = $r->newInstanceArgs(array($this));
412
+			} else {
413
+				throw new EE_Error(
414
+					sprintf(
415
+						__(
416
+							'A payment method of type "%1$s" does not exist. Only ones existing are: %2$s',
417
+							'event_espresso'
418
+						),
419
+						$this->type(),
420
+						implode(',', EE_Payment_Method_Manager::instance()->payment_method_type_names())
421
+					)
422
+				);
423
+			}
424
+		}
425
+		return $this->_type_obj;
426
+	}
427
+
428
+
429
+	/**
430
+	 * Returns a simple array of key-value pairs combining the payment method's fields (without the 'PMD_' prefix)
431
+	 * and the extra meta. Mostly used for passing off ot gateways.     *
432
+	 *
433
+	 * @return array
434
+	 */
435
+	public function settings_array()
436
+	{
437
+		$fields = $this->model_field_array();
438
+		$extra_meta = $this->all_extra_meta_array();
439
+		// remove the model's prefix from the fields
440
+		$combined_settings_array = array();
441
+		foreach ($fields as $key => $value) {
442
+			if (strpos($key, 'PMD_') === 0) {
443
+				$key_sans_model_prefix = str_replace('PMD_', '', $key);
444
+				$combined_settings_array [ $key_sans_model_prefix ] = $value;
445
+			}
446
+		}
447
+		$combined_settings_array = array_merge($extra_meta, $combined_settings_array);
448
+		return $combined_settings_array;
449
+	}
450
+
451
+
452
+	/**
453
+	 * Gets the HTML for displaying the payment method on a page.
454
+	 *
455
+	 * @param string $url
456
+	 * @param string $css_class
457
+	 * @return string of HTML for displaying the button
458
+	 * @throws \EE_Error
459
+	 */
460
+	public function button_html($url = '', $css_class = '')
461
+	{
462
+		$payment_occurs = $this->type_obj()->payment_occurs();
463
+		return '
464 464
 		 <div id="'
465
-               . $this->slug()
466
-               . '-payment-option-dv" class="'
467
-               . $payment_occurs . '-payment-gateway reg-page-payment-option-dv' . $css_class . '">
465
+			   . $this->slug()
466
+			   . '-payment-option-dv" class="'
467
+			   . $payment_occurs . '-payment-gateway reg-page-payment-option-dv' . $css_class . '">
468 468
 			<a id="payment-gateway-button-' . $this->slug()
469
-               . '" class="reg-page-payment-option-lnk" rel="'
470
-               . $this->slug() . '" href="' . $url . '" >
469
+			   . '" class="reg-page-payment-option-lnk" rel="'
470
+			   . $this->slug() . '" href="' . $url . '" >
471 471
 				<img src="' . $this->button_url() . '" alt="' . sprintf(
472
-                   esc_attr__('Pay using %s', 'event_espresso'),
473
-                   $this->get_pretty('PMD_name', 'form_input')
474
-               ) . '" />
472
+				   esc_attr__('Pay using %s', 'event_espresso'),
473
+				   $this->get_pretty('PMD_name', 'form_input')
474
+			   ) . '" />
475 475
 			</a>
476 476
 		</div>
477 477
 ';
478
-    }
479
-
480
-
481
-    /**
482
-     * Gets all the currencies which are an option for this payment method
483
-     * (as defined by the gateway and the currently active currencies)
484
-     *
485
-     * @return EE_Currency[]
486
-     * @throws \EE_Error
487
-     */
488
-    public function get_all_usable_currencies()
489
-    {
490
-        return EEM_Currency::instance()->get_all_currencies_usable_by($this->type_obj());
491
-    }
492
-
493
-
494
-    /**
495
-     * Reports whether or not this payment method can be used for this payment method
496
-     *
497
-     * @param string $currency_code currency ID (code)
498
-     * @return boolean
499
-     * @throws \EE_Error
500
-     */
501
-    public function usable_for_currency($currency_code)
502
-    {
503
-        foreach ($this->get_all_usable_currencies() as $currency_obj) {
504
-            if ($currency_obj->ID() === $currency_code) {
505
-                return true;
506
-            }
507
-        }
508
-        return false;
509
-    }
510
-
511
-
512
-    /**
513
-     * Returns TRUE if this payment method's gateway is an instance of EE_Onsite_Gateway
514
-     *
515
-     * @return bool
516
-     * @throws \EE_Error
517
-     */
518
-    public function is_on_site()
519
-    {
520
-        return $this->type_obj()->payment_occurs() === EE_PMT_Base::onsite;
521
-    }
522
-
523
-
524
-    /**
525
-     * Returns TRUE if this payment method's gateway is an instance of EE_Offsite_Gateway
526
-     *
527
-     * @return bool
528
-     * @throws \EE_Error
529
-     */
530
-    public function is_off_site()
531
-    {
532
-        return $this->type_obj()->payment_occurs() === EE_PMT_Base::offsite;
533
-    }
534
-
535
-
536
-    /**
537
-     * Returns TRUE if this payment method does not utilize a gateway
538
-     *
539
-     * @return bool
540
-     * @throws \EE_Error
541
-     */
542
-    public function is_off_line()
543
-    {
544
-        return $this->type_obj()->payment_occurs() === EE_PMT_Base::offline;
545
-    }
546
-
547
-    /**
548
-     * Overrides default __sleep so the object type is NOT cached.
549
-     * This way we can rely on the normal EE_Payment_Method::type_obj() logic
550
-     * to load the required classes, and don't need them at the time of unserialization
551
-     *
552
-     * @return array
553
-     */
554
-    public function __sleep()
555
-    {
556
-        $properties = get_object_vars($this);
557
-        unset($properties['_type_obj']);
558
-        return array_keys($properties);
559
-    }
560
-
561
-
562
-    /**
563
-     * Overrides parent to add some logging for when payment methods get deactivated
564
-     *
565
-     * @param array $set_cols_n_values
566
-     * @return int @see EE_Base_Class::save()
567
-     * @throws \EE_Error
568
-     */
569
-    public function save($set_cols_n_values = array())
570
-    {
571
-        $results = parent::save($set_cols_n_values);
572
-        if ($this->get_original('PMD_scope') !== $this->get('PMD_scope')) {
573
-            EE_Log::instance()->log(
574
-                __FILE__,
575
-                __FUNCTION__,
576
-                sprintf(
577
-                    __('Set new scope on payment method %1$s to %2$s from %3$s on URL %4$s', 'event_espresso'),
578
-                    $this->name(),
579
-                    serialize($this->get_original('PMD_scope')),
580
-                    serialize($this->get('PMD_scope')),
581
-                    EE_Registry::instance()->REQ->get_current_page_permalink()
582
-                ),
583
-                'payment_method_change'
584
-            );
585
-        }
586
-        return $results;
587
-    }
478
+	}
479
+
480
+
481
+	/**
482
+	 * Gets all the currencies which are an option for this payment method
483
+	 * (as defined by the gateway and the currently active currencies)
484
+	 *
485
+	 * @return EE_Currency[]
486
+	 * @throws \EE_Error
487
+	 */
488
+	public function get_all_usable_currencies()
489
+	{
490
+		return EEM_Currency::instance()->get_all_currencies_usable_by($this->type_obj());
491
+	}
492
+
493
+
494
+	/**
495
+	 * Reports whether or not this payment method can be used for this payment method
496
+	 *
497
+	 * @param string $currency_code currency ID (code)
498
+	 * @return boolean
499
+	 * @throws \EE_Error
500
+	 */
501
+	public function usable_for_currency($currency_code)
502
+	{
503
+		foreach ($this->get_all_usable_currencies() as $currency_obj) {
504
+			if ($currency_obj->ID() === $currency_code) {
505
+				return true;
506
+			}
507
+		}
508
+		return false;
509
+	}
510
+
511
+
512
+	/**
513
+	 * Returns TRUE if this payment method's gateway is an instance of EE_Onsite_Gateway
514
+	 *
515
+	 * @return bool
516
+	 * @throws \EE_Error
517
+	 */
518
+	public function is_on_site()
519
+	{
520
+		return $this->type_obj()->payment_occurs() === EE_PMT_Base::onsite;
521
+	}
522
+
523
+
524
+	/**
525
+	 * Returns TRUE if this payment method's gateway is an instance of EE_Offsite_Gateway
526
+	 *
527
+	 * @return bool
528
+	 * @throws \EE_Error
529
+	 */
530
+	public function is_off_site()
531
+	{
532
+		return $this->type_obj()->payment_occurs() === EE_PMT_Base::offsite;
533
+	}
534
+
535
+
536
+	/**
537
+	 * Returns TRUE if this payment method does not utilize a gateway
538
+	 *
539
+	 * @return bool
540
+	 * @throws \EE_Error
541
+	 */
542
+	public function is_off_line()
543
+	{
544
+		return $this->type_obj()->payment_occurs() === EE_PMT_Base::offline;
545
+	}
546
+
547
+	/**
548
+	 * Overrides default __sleep so the object type is NOT cached.
549
+	 * This way we can rely on the normal EE_Payment_Method::type_obj() logic
550
+	 * to load the required classes, and don't need them at the time of unserialization
551
+	 *
552
+	 * @return array
553
+	 */
554
+	public function __sleep()
555
+	{
556
+		$properties = get_object_vars($this);
557
+		unset($properties['_type_obj']);
558
+		return array_keys($properties);
559
+	}
560
+
561
+
562
+	/**
563
+	 * Overrides parent to add some logging for when payment methods get deactivated
564
+	 *
565
+	 * @param array $set_cols_n_values
566
+	 * @return int @see EE_Base_Class::save()
567
+	 * @throws \EE_Error
568
+	 */
569
+	public function save($set_cols_n_values = array())
570
+	{
571
+		$results = parent::save($set_cols_n_values);
572
+		if ($this->get_original('PMD_scope') !== $this->get('PMD_scope')) {
573
+			EE_Log::instance()->log(
574
+				__FILE__,
575
+				__FUNCTION__,
576
+				sprintf(
577
+					__('Set new scope on payment method %1$s to %2$s from %3$s on URL %4$s', 'event_espresso'),
578
+					$this->name(),
579
+					serialize($this->get_original('PMD_scope')),
580
+					serialize($this->get('PMD_scope')),
581
+					EE_Registry::instance()->REQ->get_current_page_permalink()
582
+				),
583
+				'payment_method_change'
584
+			);
585
+		}
586
+		return $results;
587
+	}
588 588
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -389,11 +389,11 @@  discard block
 block discarded – undo
389 389
      */
390 390
     public function type_obj()
391 391
     {
392
-        if (! $this->_type_obj) {
392
+        if ( ! $this->_type_obj) {
393 393
             EE_Registry::instance()->load_lib('Payment_Method_Manager');
394 394
             if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($this->type())) {
395 395
                 $class_name = EE_Payment_Method_Manager::instance()->payment_method_class_from_type($this->type());
396
-                if (! class_exists($class_name)) {
396
+                if ( ! class_exists($class_name)) {
397 397
                     throw new EE_Error(
398 398
                         sprintf(
399 399
                             __(
@@ -402,7 +402,7 @@  discard block
 block discarded – undo
402 402
                             ),
403 403
                             $class_name,
404 404
                             '<br />',
405
-                            '<a href="' . admin_url('plugins.php') . '">',
405
+                            '<a href="'.admin_url('plugins.php').'">',
406 406
                             '</a>'
407 407
                         )
408 408
                     );
@@ -441,7 +441,7 @@  discard block
 block discarded – undo
441 441
         foreach ($fields as $key => $value) {
442 442
             if (strpos($key, 'PMD_') === 0) {
443 443
                 $key_sans_model_prefix = str_replace('PMD_', '', $key);
444
-                $combined_settings_array [ $key_sans_model_prefix ] = $value;
444
+                $combined_settings_array [$key_sans_model_prefix] = $value;
445 445
             }
446 446
         }
447 447
         $combined_settings_array = array_merge($extra_meta, $combined_settings_array);
@@ -464,14 +464,14 @@  discard block
 block discarded – undo
464 464
 		 <div id="'
465 465
                . $this->slug()
466 466
                . '-payment-option-dv" class="'
467
-               . $payment_occurs . '-payment-gateway reg-page-payment-option-dv' . $css_class . '">
467
+               . $payment_occurs.'-payment-gateway reg-page-payment-option-dv'.$css_class.'">
468 468
 			<a id="payment-gateway-button-' . $this->slug()
469 469
                . '" class="reg-page-payment-option-lnk" rel="'
470
-               . $this->slug() . '" href="' . $url . '" >
471
-				<img src="' . $this->button_url() . '" alt="' . sprintf(
470
+               . $this->slug().'" href="'.$url.'" >
471
+				<img src="' . $this->button_url().'" alt="'.sprintf(
472 472
                    esc_attr__('Pay using %s', 'event_espresso'),
473 473
                    $this->get_pretty('PMD_name', 'form_input')
474
-               ) . '" />
474
+               ).'" />
475 475
 			</a>
476 476
 		</div>
477 477
 ';
Please login to merge, or discard this patch.
core/db_classes/EE_Event_Venue.class.php 1 patch
Indentation   +17 added lines, -17 removed lines patch added patch discarded remove patch
@@ -6,23 +6,23 @@
 block discarded – undo
6 6
 class EE_Event_Venue extends EE_Base_Class
7 7
 {
8 8
 
9
-    /**
10
-     * @param array $props_n_values
11
-     * @return EE_Event_Venue|mixed
12
-     */
13
-    public static function new_instance($props_n_values = array())
14
-    {
15
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__);
16
-        return $has_object ? $has_object : new self($props_n_values);
17
-    }
9
+	/**
10
+	 * @param array $props_n_values
11
+	 * @return EE_Event_Venue|mixed
12
+	 */
13
+	public static function new_instance($props_n_values = array())
14
+	{
15
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__);
16
+		return $has_object ? $has_object : new self($props_n_values);
17
+	}
18 18
 
19 19
 
20
-    /**
21
-     * @param array $props_n_values
22
-     * @return EE_Event_Venue
23
-     */
24
-    public static function new_instance_from_db($props_n_values = array())
25
-    {
26
-        return new self($props_n_values, true);
27
-    }
20
+	/**
21
+	 * @param array $props_n_values
22
+	 * @return EE_Event_Venue
23
+	 */
24
+	public static function new_instance_from_db($props_n_values = array())
25
+	{
26
+		return new self($props_n_values, true);
27
+	}
28 28
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Soft_Delete_Base_Class.class.php 1 patch
Indentation   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -12,53 +12,53 @@
 block discarded – undo
12 12
 {
13 13
 
14 14
 
15
-    /**
16
-     * Overrides parent _delete() so that we do soft deletes.
17
-     *
18
-     * @return bool|int
19
-     */
20
-    protected function _delete()
21
-    {
22
-        return $this->delete_or_restore();
23
-    }
15
+	/**
16
+	 * Overrides parent _delete() so that we do soft deletes.
17
+	 *
18
+	 * @return bool|int
19
+	 */
20
+	protected function _delete()
21
+	{
22
+		return $this->delete_or_restore();
23
+	}
24 24
 
25 25
 
26
-    /**
27
-     * Deletes or restores this object.
28
-     *
29
-     * @param bool $delete true=>delete, false=>restore
30
-     * @return bool|int
31
-     */
32
-    public function delete_or_restore($delete = true)
33
-    {
34
-        /**
35
-         * Called just before trashing (soft delete) or restoring a trashed item.
36
-         *
37
-         * @param EE_Base_Class $model_object about to be trashed or restored
38
-         * @param bool          $delete       true the item is being trashed, false the item is being restored.
39
-         */
40
-        do_action('AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__before', $this, $delete);
41
-        $model = $this->get_model();
42
-        $result = $model->delete_or_restore_by_ID($delete, $this->ID());
43
-        /**
44
-         * Called just after trashing (soft delete) or restoring a trashed item.
45
-         *
46
-         * @param EE_Base_Class $model_object that was just trashed or restored.
47
-         * @param bool          $delete       true the item is being trashed, false the item is being restored.
48
-         * @param bool|int      $result
49
-         */
50
-        do_action('AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__after', $this, $delete, $result);
51
-        return $result;
52
-    }
26
+	/**
27
+	 * Deletes or restores this object.
28
+	 *
29
+	 * @param bool $delete true=>delete, false=>restore
30
+	 * @return bool|int
31
+	 */
32
+	public function delete_or_restore($delete = true)
33
+	{
34
+		/**
35
+		 * Called just before trashing (soft delete) or restoring a trashed item.
36
+		 *
37
+		 * @param EE_Base_Class $model_object about to be trashed or restored
38
+		 * @param bool          $delete       true the item is being trashed, false the item is being restored.
39
+		 */
40
+		do_action('AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__before', $this, $delete);
41
+		$model = $this->get_model();
42
+		$result = $model->delete_or_restore_by_ID($delete, $this->ID());
43
+		/**
44
+		 * Called just after trashing (soft delete) or restoring a trashed item.
45
+		 *
46
+		 * @param EE_Base_Class $model_object that was just trashed or restored.
47
+		 * @param bool          $delete       true the item is being trashed, false the item is being restored.
48
+		 * @param bool|int      $result
49
+		 */
50
+		do_action('AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__after', $this, $delete, $result);
51
+		return $result;
52
+	}
53 53
 
54 54
 
55
-    /**
56
-     * Performs a restoration (un-deletes) this object
57
-     *
58
-     * @return bool|int
59
-     */
60
-    public function restore()
61
-    {
62
-        return $this->delete_or_restore(false);
63
-    }
55
+	/**
56
+	 * Performs a restoration (un-deletes) this object
57
+	 *
58
+	 * @return bool|int
59
+	 */
60
+	public function restore()
61
+	{
62
+		return $this->delete_or_restore(false);
63
+	}
64 64
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Event_Question_Group.class.php 1 patch
Indentation   +17 added lines, -17 removed lines patch added patch discarded remove patch
@@ -6,23 +6,23 @@
 block discarded – undo
6 6
 class EE_Event_Question_Group extends EE_Base_Class
7 7
 {
8 8
 
9
-    /**
10
-     * @param array $props_n_values
11
-     * @return EE_Event_Question_Group|mixed
12
-     */
13
-    public static function new_instance($props_n_values = array())
14
-    {
15
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__);
16
-        return $has_object ? $has_object : new self($props_n_values);
17
-    }
9
+	/**
10
+	 * @param array $props_n_values
11
+	 * @return EE_Event_Question_Group|mixed
12
+	 */
13
+	public static function new_instance($props_n_values = array())
14
+	{
15
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__);
16
+		return $has_object ? $has_object : new self($props_n_values);
17
+	}
18 18
 
19 19
 
20
-    /**
21
-     * @param array $props_n_values
22
-     * @return EE_Event_Question_Group
23
-     */
24
-    public static function new_instance_from_db($props_n_values = array())
25
-    {
26
-        return new self($props_n_values, true);
27
-    }
20
+	/**
21
+	 * @param array $props_n_values
22
+	 * @return EE_Event_Question_Group
23
+	 */
24
+	public static function new_instance_from_db($props_n_values = array())
25
+	{
26
+		return new self($props_n_values, true);
27
+	}
28 28
 }
Please login to merge, or discard this patch.