Completed
Branch 973/fix-visible-recaptcha (0580c7)
by
unknown
03:03 queued 30s
created
core/domain/services/admin/ajax/EventEditorHeartbeat.php 2 patches
Indentation   +43 added lines, -43 removed lines patch added patch discarded remove patch
@@ -16,52 +16,52 @@
 block discarded – undo
16 16
 class EventEditorHeartbeat
17 17
 {
18 18
 
19
-    /**
20
-     * @var Domain $domain
21
-     */
22
-    protected $domain;
19
+	/**
20
+	 * @var Domain $domain
21
+	 */
22
+	protected $domain;
23 23
 
24
-    /**
25
-     * @var EE_Environment_Config $environment
26
-     */
27
-    protected $environment;
24
+	/**
25
+	 * @var EE_Environment_Config $environment
26
+	 */
27
+	protected $environment;
28 28
 
29 29
 
30
-    /**
31
-     * EventEditorHeartbeat constructor.
32
-     *
33
-     * @param Domain                $domain
34
-     * @param EE_Environment_Config $environment
35
-     */
36
-    public function __construct(Domain $domain, EE_Environment_Config $environment)
37
-    {
38
-        $this->domain = $domain;
39
-        $this->environment = $environment;
40
-        if ($this->domain->isCaffeinated()) {
41
-            add_filter('heartbeat_received', array($this, 'heartbeatResponse'), 10, 2);
42
-        }
43
-    }
30
+	/**
31
+	 * EventEditorHeartbeat constructor.
32
+	 *
33
+	 * @param Domain                $domain
34
+	 * @param EE_Environment_Config $environment
35
+	 */
36
+	public function __construct(Domain $domain, EE_Environment_Config $environment)
37
+	{
38
+		$this->domain = $domain;
39
+		$this->environment = $environment;
40
+		if ($this->domain->isCaffeinated()) {
41
+			add_filter('heartbeat_received', array($this, 'heartbeatResponse'), 10, 2);
42
+		}
43
+	}
44 44
 
45 45
 
46
-    /**
47
-     * This will be used to listen for any heartbeat data packages coming via the WordPress heartbeat API and handle
48
-     * accordingly.
49
-     *
50
-     * @param array $response The existing heartbeat response array.
51
-     * @param array $data     The incoming data package.
52
-     * @return array  possibly appended response.
53
-     */
54
-    public function heartbeatResponse($response, $data)
55
-    {
56
-        /**
57
-         * check whether count of tickets is approaching the potential
58
-         * limits for the server.
59
-         */
60
-        if (! empty($data['input_count'])) {
61
-            $response['max_input_vars_check'] = $this->environment->max_input_vars_limit_check(
62
-                $data['input_count']
63
-            );
64
-        }
65
-        return $response;
66
-    }
46
+	/**
47
+	 * This will be used to listen for any heartbeat data packages coming via the WordPress heartbeat API and handle
48
+	 * accordingly.
49
+	 *
50
+	 * @param array $response The existing heartbeat response array.
51
+	 * @param array $data     The incoming data package.
52
+	 * @return array  possibly appended response.
53
+	 */
54
+	public function heartbeatResponse($response, $data)
55
+	{
56
+		/**
57
+		 * check whether count of tickets is approaching the potential
58
+		 * limits for the server.
59
+		 */
60
+		if (! empty($data['input_count'])) {
61
+			$response['max_input_vars_check'] = $this->environment->max_input_vars_limit_check(
62
+				$data['input_count']
63
+			);
64
+		}
65
+		return $response;
66
+	}
67 67
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -57,7 +57,7 @@
 block discarded – undo
57 57
          * check whether count of tickets is approaching the potential
58 58
          * limits for the server.
59 59
          */
60
-        if (! empty($data['input_count'])) {
60
+        if ( ! empty($data['input_count'])) {
61 61
             $response['max_input_vars_check'] = $this->environment->max_input_vars_limit_check(
62 62
                 $data['input_count']
63 63
             );
Please login to merge, or discard this patch.
payment_methods/Paypal_Express/forms/SettingsForm.php 1 patch
Indentation   +49 added lines, -49 removed lines patch added patch discarded remove patch
@@ -19,53 +19,53 @@
 block discarded – undo
19 19
  */
20 20
 class SettingsForm extends PayPalSettingsForm
21 21
 {
22
-    /**
23
-     * SettingsForm constructor.
24
-     *
25
-     * @param array $options_array
26
-     * @param string $help_tab_link
27
-     * @throws InvalidDataTypeException
28
-     * @throws InvalidInterfaceException
29
-     * @throws InvalidArgumentException
30
-     */
31
-    public function __construct(array $options_array = array(), $help_tab_link = '')
32
-    {
33
-        $options_array = array_replace_recursive(
34
-            array(
35
-                'extra_meta_inputs' => array(
36
-                    'request_shipping_addr' => new EE_Yes_No_Input(
37
-                        array(
38
-                            'html_label_text' => sprintf(
39
-                                esc_html__('Request Shipping Address %s', 'event_espresso'),
40
-                                $help_tab_link
41
-                            ),
42
-                            'html_help_text'  => esc_html__(
43
-                            // @codingStandardsIgnoreStart
44
-                                'If set to "Yes", then a shipping address will be requested on the PayPal checkout page.',
45
-                                // @codingStandardsIgnoreEnd
46
-                                'event_espresso'
47
-                            ),
48
-                            'required'        => true,
49
-                            'default'         => false,
50
-                        )
51
-                    ),
52
-                    'image_url' => new EE_Admin_File_Uploader_Input(
53
-                        array(
54
-                            'html_label_text' => sprintf(
55
-                                esc_html__('Image URL %s', 'event_espresso'),
56
-                                $help_tab_link
57
-                            ),
58
-                            'html_help_text'  => esc_html__(
59
-                                'Used for your business/personal logo on the PayPal page',
60
-                                'event_espresso'
61
-                            ),
62
-                            'required'        => false,
63
-                        )
64
-                    ),
65
-                )
66
-            ),
67
-            $options_array
68
-        );
69
-        parent::__construct($options_array, $help_tab_link);
70
-    }
22
+	/**
23
+	 * SettingsForm constructor.
24
+	 *
25
+	 * @param array $options_array
26
+	 * @param string $help_tab_link
27
+	 * @throws InvalidDataTypeException
28
+	 * @throws InvalidInterfaceException
29
+	 * @throws InvalidArgumentException
30
+	 */
31
+	public function __construct(array $options_array = array(), $help_tab_link = '')
32
+	{
33
+		$options_array = array_replace_recursive(
34
+			array(
35
+				'extra_meta_inputs' => array(
36
+					'request_shipping_addr' => new EE_Yes_No_Input(
37
+						array(
38
+							'html_label_text' => sprintf(
39
+								esc_html__('Request Shipping Address %s', 'event_espresso'),
40
+								$help_tab_link
41
+							),
42
+							'html_help_text'  => esc_html__(
43
+							// @codingStandardsIgnoreStart
44
+								'If set to "Yes", then a shipping address will be requested on the PayPal checkout page.',
45
+								// @codingStandardsIgnoreEnd
46
+								'event_espresso'
47
+							),
48
+							'required'        => true,
49
+							'default'         => false,
50
+						)
51
+					),
52
+					'image_url' => new EE_Admin_File_Uploader_Input(
53
+						array(
54
+							'html_label_text' => sprintf(
55
+								esc_html__('Image URL %s', 'event_espresso'),
56
+								$help_tab_link
57
+							),
58
+							'html_help_text'  => esc_html__(
59
+								'Used for your business/personal logo on the PayPal page',
60
+								'event_espresso'
61
+							),
62
+							'required'        => false,
63
+						)
64
+					),
65
+				)
66
+			),
67
+			$options_array
68
+		);
69
+		parent::__construct($options_array, $help_tab_link);
70
+	}
71 71
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Event_Question_Group.model.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -32,10 +32,10 @@
 block discarded – undo
32 32
         );
33 33
         // this model is generally available for reading
34 34
         $path_to_event = 'Event';
35
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
36
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
37
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
38
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event, EEM_Base::caps_edit);
35
+        $this->_cap_restriction_generators[EEM_Base::caps_read] = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
36
+        $this->_cap_restriction_generators[EEM_Base::caps_read_admin] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
37
+        $this->_cap_restriction_generators[EEM_Base::caps_edit] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
38
+        $this->_cap_restriction_generators[EEM_Base::caps_delete] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event, EEM_Base::caps_edit);
39 39
         parent::__construct($timezone);
40 40
     }
41 41
 
Please login to merge, or discard this patch.
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -8,72 +8,72 @@
 block discarded – undo
8 8
  */
9 9
 class EEM_Event_Question_Group extends EEM_Base
10 10
 {
11
-    /**
12
-     * Name of the field indicating an event should use the question group for the primary attendee
13
-     */
14
-    const PRIMARY = 'EQG_primary';
11
+	/**
12
+	 * Name of the field indicating an event should use the question group for the primary attendee
13
+	 */
14
+	const PRIMARY = 'EQG_primary';
15 15
 
16
-    /**
17
-     * Name of hte field indicating an event should use the question group for additional attendees
18
-     */
19
-    const ADDITIONAL = 'EQG_additional';
16
+	/**
17
+	 * Name of hte field indicating an event should use the question group for additional attendees
18
+	 */
19
+	const ADDITIONAL = 'EQG_additional';
20 20
 
21
-    // private instance of the Event_Question_Group object
22
-    protected static $_instance = null;
21
+	// private instance of the Event_Question_Group object
22
+	protected static $_instance = null;
23 23
 
24
-    protected function __construct($timezone = null)
25
-    {
26
-        $this->singular_item = esc_html__('Event to Question Group Link', 'event_espresso');
27
-        $this->plural_item = esc_html__('Event to Question Group Links', 'event_espresso');
28
-        $this->_tables = array(
29
-            'Event_Question_Group' => new EE_Primary_Table('esp_event_question_group', 'EQG_ID')
30
-        );
31
-        $this->_fields = array(
32
-            'Event_Question_Group' => array(
33
-                'EQG_ID' => new EE_Primary_Key_Int_Field('EQG_ID', esc_html__('Event to Question Group Link ID', 'event_espresso')),
34
-                'EVT_ID' => new EE_Foreign_Key_Int_Field('EVT_ID', esc_html__('Event ID', 'event_espresso'), false, 0, 'Event'),
35
-                'QSG_ID' => new EE_Foreign_Key_Int_Field('QSG_ID', esc_html__('Question Group Id', 'event_espresso'), false, 0, 'Question_Group'),
36
-                'EQG_primary' => new EE_Boolean_Field('EQG_primary', esc_html__('Flag indicating question is only for primary attendees', 'event_espresso'), false, false),
37
-                'EQG_additional' => new EE_Boolean_Field('EQG_additional', esc_html__('Flag indicating question is only for additional attendees', 'event_espresso'), false, false)
38
-            )
39
-        );
40
-        $this->_model_relations = array(
41
-            'Event' => new EE_Belongs_To_Relation(),
42
-            'Question_Group' => new EE_Belongs_To_Relation()
43
-        );
44
-        // this model is generally available for reading
45
-        $path_to_event = 'Event';
46
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
47
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
48
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
49
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event, EEM_Base::caps_edit);
50
-        parent::__construct($timezone);
51
-    }
24
+	protected function __construct($timezone = null)
25
+	{
26
+		$this->singular_item = esc_html__('Event to Question Group Link', 'event_espresso');
27
+		$this->plural_item = esc_html__('Event to Question Group Links', 'event_espresso');
28
+		$this->_tables = array(
29
+			'Event_Question_Group' => new EE_Primary_Table('esp_event_question_group', 'EQG_ID')
30
+		);
31
+		$this->_fields = array(
32
+			'Event_Question_Group' => array(
33
+				'EQG_ID' => new EE_Primary_Key_Int_Field('EQG_ID', esc_html__('Event to Question Group Link ID', 'event_espresso')),
34
+				'EVT_ID' => new EE_Foreign_Key_Int_Field('EVT_ID', esc_html__('Event ID', 'event_espresso'), false, 0, 'Event'),
35
+				'QSG_ID' => new EE_Foreign_Key_Int_Field('QSG_ID', esc_html__('Question Group Id', 'event_espresso'), false, 0, 'Question_Group'),
36
+				'EQG_primary' => new EE_Boolean_Field('EQG_primary', esc_html__('Flag indicating question is only for primary attendees', 'event_espresso'), false, false),
37
+				'EQG_additional' => new EE_Boolean_Field('EQG_additional', esc_html__('Flag indicating question is only for additional attendees', 'event_espresso'), false, false)
38
+			)
39
+		);
40
+		$this->_model_relations = array(
41
+			'Event' => new EE_Belongs_To_Relation(),
42
+			'Question_Group' => new EE_Belongs_To_Relation()
43
+		);
44
+		// this model is generally available for reading
45
+		$path_to_event = 'Event';
46
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
47
+		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
48
+		$this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
49
+		$this->_cap_restriction_generators[ EEM_Base::caps_delete ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event, EEM_Base::caps_edit);
50
+		parent::__construct($timezone);
51
+	}
52 52
 
53
-    /**
54
-     * Decides whether to use the 'EQG_primary' or newer 'EQG_additional' for use in queries, based on whether
55
-     * this is concerning primary attendees or additional attendees.
56
-     * If 1, true, or "primary" is passed in, returns EQG_primary. If 0, false, or "additional" is passed in, returns
57
-     * EQG_additional.
58
-     * @since 4.10.0.p
59
-     * @param string|boolean|int $context
60
-     * @return string
61
-     */
62
-    public function fieldNameForContext($context)
63
-    {
64
-        // Basically do a strict switch statement.
65
-        switch (true) {
66
-            case $context === 'additional':
67
-            case $context === false:
68
-            case $context === 0:
69
-                $field_name = EEM_Event_Question_Group::ADDITIONAL;
70
-                break;
71
-            case $context === 'primary':
72
-            case $context === true:
73
-            case $context === 1:
74
-            default:
75
-                $field_name = EEM_Event_Question_Group::PRIMARY;
76
-        }
77
-        return apply_filters('FHEE__EEM_Event_Question_Group__fieldNameForContext', $field_name, $context);
78
-    }
53
+	/**
54
+	 * Decides whether to use the 'EQG_primary' or newer 'EQG_additional' for use in queries, based on whether
55
+	 * this is concerning primary attendees or additional attendees.
56
+	 * If 1, true, or "primary" is passed in, returns EQG_primary. If 0, false, or "additional" is passed in, returns
57
+	 * EQG_additional.
58
+	 * @since 4.10.0.p
59
+	 * @param string|boolean|int $context
60
+	 * @return string
61
+	 */
62
+	public function fieldNameForContext($context)
63
+	{
64
+		// Basically do a strict switch statement.
65
+		switch (true) {
66
+			case $context === 'additional':
67
+			case $context === false:
68
+			case $context === 0:
69
+				$field_name = EEM_Event_Question_Group::ADDITIONAL;
70
+				break;
71
+			case $context === 'primary':
72
+			case $context === true:
73
+			case $context === 1:
74
+			default:
75
+				$field_name = EEM_Event_Question_Group::PRIMARY;
76
+		}
77
+		return apply_filters('FHEE__EEM_Event_Question_Group__fieldNameForContext', $field_name, $context);
78
+	}
79 79
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Event.model.php 2 patches
Spacing   +17 added lines, -17 removed lines patch added patch discarded remove patch
@@ -278,7 +278,7 @@  discard block
 block discarded – undo
278 278
             'WP_User'                => new EE_Belongs_To_Relation(),
279 279
         );
280 280
         // this model is generally available for reading
281
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
281
+        $this->_cap_restriction_generators[EEM_Base::caps_read] = new EE_Restriction_Generator_Public();
282 282
         $this->model_chain_to_password = '';
283 283
         parent::__construct($timezone);
284 284
     }
@@ -371,7 +371,7 @@  discard block
 block discarded – undo
371 371
      */
372 372
     public function get_all_event_question_groups($EVT_ID = 0)
373 373
     {
374
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
374
+        if ( ! isset($EVT_ID) || ! absint($EVT_ID)) {
375 375
             EE_Error::add_error(
376 376
                 esc_html__(
377 377
                     'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
@@ -405,7 +405,7 @@  discard block
 block discarded – undo
405 405
      */
406 406
     public function get_event_question_groups($EVT_ID = 0, $for_primary_attendee = true)
407 407
     {
408
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
408
+        if ( ! isset($EVT_ID) || ! absint($EVT_ID)) {
409 409
             EE_Error::add_error(
410 410
                 esc_html__(
411 411
                     // @codingStandardsIgnoreStart
@@ -448,7 +448,7 @@  discard block
 block discarded – undo
448 448
      */
449 449
     public function get_question_groups_for_event($EVT_ID = 0, EE_Registration $registration)
450 450
     {
451
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
451
+        if ( ! isset($EVT_ID) || ! absint($EVT_ID)) {
452 452
             EE_Error::add_error(
453 453
                 esc_html__(
454 454
                     'An error occurred. No Question Groups could be retrieved because an Event ID was not received.',
@@ -861,11 +861,11 @@  discard block
 block discarded – undo
861 861
         $questions = array();
862 862
         // get all question groups for event
863 863
         $qgs = $this->get_question_groups_for_event($EVT_ID, $registration);
864
-        if (! empty($qgs)) {
864
+        if ( ! empty($qgs)) {
865 865
             foreach ($qgs as $qg) {
866 866
                 $qsts = $qg->questions();
867
-                $questions[ $qg->ID() ] = $qg->model_field_array();
868
-                $questions[ $qg->ID() ]['QSG_questions'] = array();
867
+                $questions[$qg->ID()] = $qg->model_field_array();
868
+                $questions[$qg->ID()]['QSG_questions'] = array();
869 869
                 foreach ($qsts as $qst) {
870 870
                     if ($qst->is_system_question()) {
871 871
                         continue;
@@ -879,26 +879,26 @@  discard block
 block discarded – undo
879 879
                     $answer = $answer instanceof EE_Answer ? $answer : EEM_Answer::instance()->create_default_object();
880 880
                     $qst_name = $qstn_id = $qst->ID();
881 881
                     $ans_id = $answer->ID();
882
-                    $qst_name = ! empty($ans_id) ? '[' . $qst_name . '][' . $ans_id . ']' : '[' . $qst_name . ']';
882
+                    $qst_name = ! empty($ans_id) ? '['.$qst_name.']['.$ans_id.']' : '['.$qst_name.']';
883 883
                     $input_name = '';
884 884
                     $input_id = sanitize_key($qst->display_text());
885 885
                     $input_class = '';
886
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ] = $qst->model_field_array();
887
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_name'] = 'qstn'
886
+                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()] = $qst->model_field_array();
887
+                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_name'] = 'qstn'
888 888
                                                                                            . $input_name
889 889
                                                                                            . $qst_name;
890
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_id'] = $input_id . '-' . $qstn_id;
891
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_class'] = $input_class;
892
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'] = array();
893
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['qst_obj'] = $qst;
894
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['ans_obj'] = $answer;
890
+                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_id'] = $input_id.'-'.$qstn_id;
891
+                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_input_class'] = $input_class;
892
+                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_options'] = array();
893
+                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['qst_obj'] = $qst;
894
+                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['ans_obj'] = $answer;
895 895
                     // leave responses as-is, don't convert stuff into html entities please!
896
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['htmlentities'] = false;
896
+                    $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['htmlentities'] = false;
897 897
                     if ($qst->type() == 'RADIO_BTN' || $qst->type() == 'CHECKBOX' || $qst->type() == 'DROPDOWN') {
898 898
                         $QSOs = $qst->options(true, $answer->value());
899 899
                         if (is_array($QSOs)) {
900 900
                             foreach ($QSOs as $QSO_ID => $QSO) {
901
-                                $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'][ $QSO_ID ] = $QSO->model_field_array();
901
+                                $questions[$qg->ID()]['QSG_questions'][$qst->ID()]['QST_options'][$QSO_ID] = $QSO->model_field_array();
902 902
                             }
903 903
                         }
904 904
                     }
Please login to merge, or discard this patch.
Indentation   +951 added lines, -951 removed lines patch added patch discarded remove patch
@@ -15,955 +15,955 @@
 block discarded – undo
15 15
 class EEM_Event extends EEM_CPT_Base
16 16
 {
17 17
 
18
-    /**
19
-     * constant used by status(), indicating that no more tickets can be purchased for any of the datetimes for the
20
-     * event
21
-     */
22
-    const sold_out = 'sold_out';
23
-
24
-    /**
25
-     * constant used by status(), indicating that upcoming event dates have been postponed (may be pushed to a later
26
-     * date)
27
-     */
28
-    const postponed = 'postponed';
29
-
30
-    /**
31
-     * constant used by status(), indicating that the event will no longer occur
32
-     */
33
-    const cancelled = 'cancelled';
34
-
35
-
36
-    /**
37
-     * @var string
38
-     */
39
-    protected static $_default_reg_status;
40
-
41
-
42
-    /**
43
-     * This is the default for the additional limit field.
44
-     * @var int
45
-     */
46
-    protected static $_default_additional_limit = 10;
47
-
48
-
49
-    /**
50
-     * private instance of the Event object
51
-     *
52
-     * @var EEM_Event
53
-     */
54
-    protected static $_instance;
55
-
56
-
57
-
58
-
59
-    /**
60
-     * Adds a relationship to Term_Taxonomy for each CPT_Base
61
-     *
62
-     * @param string $timezone
63
-     * @throws \EE_Error
64
-     */
65
-    protected function __construct($timezone = null)
66
-    {
67
-        EE_Registry::instance()->load_model('Registration');
68
-        $this->singular_item = esc_html__('Event', 'event_espresso');
69
-        $this->plural_item = esc_html__('Events', 'event_espresso');
70
-        // to remove Cancelled events from the frontend, copy the following filter to your functions.php file
71
-        // add_filter( 'AFEE__EEM_Event__construct___custom_stati__cancelled__Public', '__return_false' );
72
-        // to remove Postponed events from the frontend, copy the following filter to your functions.php file
73
-        // add_filter( 'AFEE__EEM_Event__construct___custom_stati__postponed__Public', '__return_false' );
74
-        // to remove Sold Out events from the frontend, copy the following filter to your functions.php file
75
-        //  add_filter( 'AFEE__EEM_Event__construct___custom_stati__sold_out__Public', '__return_false' );
76
-        $this->_custom_stati = apply_filters(
77
-            'AFEE__EEM_Event__construct___custom_stati',
78
-            array(
79
-                EEM_Event::cancelled => array(
80
-                    'label'  => esc_html__('Cancelled', 'event_espresso'),
81
-                    'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__cancelled__Public', true),
82
-                ),
83
-                EEM_Event::postponed => array(
84
-                    'label'  => esc_html__('Postponed', 'event_espresso'),
85
-                    'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__postponed__Public', true),
86
-                ),
87
-                EEM_Event::sold_out  => array(
88
-                    'label'  => esc_html__('Sold Out', 'event_espresso'),
89
-                    'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__sold_out__Public', true),
90
-                ),
91
-            )
92
-        );
93
-        self::$_default_reg_status = empty(self::$_default_reg_status) ? EEM_Registration::status_id_pending_payment
94
-            : self::$_default_reg_status;
95
-        $this->_tables = array(
96
-            'Event_CPT'  => new EE_Primary_Table('posts', 'ID'),
97
-            'Event_Meta' => new EE_Secondary_Table('esp_event_meta', 'EVTM_ID', 'EVT_ID'),
98
-        );
99
-        $this->_fields = array(
100
-            'Event_CPT'  => array(
101
-                'EVT_ID'         => new EE_Primary_Key_Int_Field(
102
-                    'ID',
103
-                    esc_html__('Post ID for Event', 'event_espresso')
104
-                ),
105
-                'EVT_name'       => new EE_Plain_Text_Field(
106
-                    'post_title',
107
-                    esc_html__('Event Name', 'event_espresso'),
108
-                    false,
109
-                    ''
110
-                ),
111
-                'EVT_desc'       => new EE_Post_Content_Field(
112
-                    'post_content',
113
-                    esc_html__('Event Description', 'event_espresso'),
114
-                    false,
115
-                    ''
116
-                ),
117
-                'EVT_slug'       => new EE_Slug_Field(
118
-                    'post_name',
119
-                    esc_html__('Event Slug', 'event_espresso'),
120
-                    false,
121
-                    ''
122
-                ),
123
-                'EVT_created'    => new EE_Datetime_Field(
124
-                    'post_date',
125
-                    esc_html__('Date/Time Event Created', 'event_espresso'),
126
-                    false,
127
-                    EE_Datetime_Field::now
128
-                ),
129
-                'EVT_short_desc' => new EE_Simple_HTML_Field(
130
-                    'post_excerpt',
131
-                    esc_html__('Event Short Description', 'event_espresso'),
132
-                    false,
133
-                    ''
134
-                ),
135
-                'EVT_modified'   => new EE_Datetime_Field(
136
-                    'post_modified',
137
-                    esc_html__('Date/Time Event Modified', 'event_espresso'),
138
-                    false,
139
-                    EE_Datetime_Field::now
140
-                ),
141
-                'EVT_wp_user'    => new EE_WP_User_Field(
142
-                    'post_author',
143
-                    esc_html__('Event Creator ID', 'event_espresso'),
144
-                    false
145
-                ),
146
-                'parent'         => new EE_Integer_Field(
147
-                    'post_parent',
148
-                    esc_html__('Event Parent ID', 'event_espresso'),
149
-                    false,
150
-                    0
151
-                ),
152
-                'EVT_order'      => new EE_Integer_Field(
153
-                    'menu_order',
154
-                    esc_html__('Event Menu Order', 'event_espresso'),
155
-                    false,
156
-                    1
157
-                ),
158
-                'post_type'      => new EE_WP_Post_Type_Field('espresso_events'),
159
-                // EE_Plain_Text_Field( 'post_type', esc_html__( 'Event Post Type', 'event_espresso' ), FALSE, 'espresso_events' ),
160
-                'status'         => new EE_WP_Post_Status_Field(
161
-                    'post_status',
162
-                    esc_html__('Event Status', 'event_espresso'),
163
-                    false,
164
-                    'draft',
165
-                    $this->_custom_stati
166
-                ),
167
-                'password' => new EE_Password_Field(
168
-                    'post_password',
169
-                    esc_html__('Password', 'event_espresso'),
170
-                    false,
171
-                    '',
172
-                    array(
173
-                        'EVT_desc',
174
-                        'EVT_short_desc',
175
-                        'EVT_display_desc',
176
-                        'EVT_display_ticket_selector',
177
-                        'EVT_visible_on',
178
-                        'EVT_additional_limit',
179
-                        'EVT_default_registration_status',
180
-                        'EVT_member_only',
181
-                        'EVT_phone',
182
-                        'EVT_allow_overflow',
183
-                        'EVT_timezone_string',
184
-                        'EVT_external_URL',
185
-                        'EVT_donations'
186
-                    )
187
-                )
188
-            ),
189
-            'Event_Meta' => array(
190
-                'EVTM_ID'                         => new EE_DB_Only_Float_Field(
191
-                    'EVTM_ID',
192
-                    esc_html__('Event Meta Row ID', 'event_espresso'),
193
-                    false
194
-                ),
195
-                'EVT_ID_fk'                       => new EE_DB_Only_Int_Field(
196
-                    'EVT_ID',
197
-                    esc_html__('Foreign key to Event ID from Event Meta table', 'event_espresso'),
198
-                    false
199
-                ),
200
-                'EVT_display_desc'                => new EE_Boolean_Field(
201
-                    'EVT_display_desc',
202
-                    esc_html__('Display Description Flag', 'event_espresso'),
203
-                    false,
204
-                    true
205
-                ),
206
-                'EVT_display_ticket_selector'     => new EE_Boolean_Field(
207
-                    'EVT_display_ticket_selector',
208
-                    esc_html__('Display Ticket Selector Flag', 'event_espresso'),
209
-                    false,
210
-                    true
211
-                ),
212
-                'EVT_visible_on'                  => new EE_Datetime_Field(
213
-                    'EVT_visible_on',
214
-                    esc_html__('Event Visible Date', 'event_espresso'),
215
-                    true,
216
-                    EE_Datetime_Field::now
217
-                ),
218
-                'EVT_additional_limit'            => new EE_Integer_Field(
219
-                    'EVT_additional_limit',
220
-                    esc_html__('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
221
-                    true,
222
-                    self::$_default_additional_limit
223
-                ),
224
-                'EVT_default_registration_status' => new EE_Enum_Text_Field(
225
-                    'EVT_default_registration_status',
226
-                    esc_html__('Default Registration Status on this Event', 'event_espresso'),
227
-                    false,
228
-                    EEM_Event::$_default_reg_status,
229
-                    EEM_Registration::reg_status_array()
230
-                ),
231
-                'EVT_member_only'                 => new EE_Boolean_Field(
232
-                    'EVT_member_only',
233
-                    esc_html__('Member-Only Event Flag', 'event_espresso'),
234
-                    false,
235
-                    false
236
-                ),
237
-                'EVT_phone'                       => new EE_Plain_Text_Field(
238
-                    'EVT_phone',
239
-                    esc_html__('Event Phone Number', 'event_espresso'),
240
-                    false,
241
-                    ''
242
-                ),
243
-                'EVT_allow_overflow'              => new EE_Boolean_Field(
244
-                    'EVT_allow_overflow',
245
-                    esc_html__('Allow Overflow on Event', 'event_espresso'),
246
-                    false,
247
-                    false
248
-                ),
249
-                'EVT_timezone_string'             => new EE_Plain_Text_Field(
250
-                    'EVT_timezone_string',
251
-                    esc_html__('Timezone (name) for Event times', 'event_espresso'),
252
-                    false,
253
-                    ''
254
-                ),
255
-                'EVT_external_URL'                => new EE_Plain_Text_Field(
256
-                    'EVT_external_URL',
257
-                    esc_html__('URL of Event Page if hosted elsewhere', 'event_espresso'),
258
-                    true
259
-                ),
260
-                'EVT_donations'                   => new EE_Boolean_Field(
261
-                    'EVT_donations',
262
-                    esc_html__('Accept Donations?', 'event_espresso'),
263
-                    false,
264
-                    false
265
-                ),
266
-            ),
267
-        );
268
-        $this->_model_relations = array(
269
-            'Registration'           => new EE_Has_Many_Relation(),
270
-            'Datetime'               => new EE_Has_Many_Relation(),
271
-            'Question_Group'         => new EE_HABTM_Relation('Event_Question_Group'),
272
-            'Event_Question_Group'   => new EE_Has_Many_Relation(),
273
-            'Venue'                  => new EE_HABTM_Relation('Event_Venue'),
274
-            'Term_Relationship'      => new EE_Has_Many_Relation(),
275
-            'Term_Taxonomy'          => new EE_HABTM_Relation('Term_Relationship'),
276
-            'Message_Template_Group' => new EE_HABTM_Relation('Event_Message_Template'),
277
-            'Attendee'               => new EE_HABTM_Relation('Registration'),
278
-            'WP_User'                => new EE_Belongs_To_Relation(),
279
-        );
280
-        // this model is generally available for reading
281
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
282
-        $this->model_chain_to_password = '';
283
-        parent::__construct($timezone);
284
-    }
285
-
286
-
287
-
288
-    /**
289
-     * @param string $default_reg_status
290
-     */
291
-    public static function set_default_reg_status($default_reg_status)
292
-    {
293
-        self::$_default_reg_status = $default_reg_status;
294
-        // if EEM_Event has already been instantiated,
295
-        // then we need to reset the `EVT_default_reg_status` field to use the new default.
296
-        if (self::$_instance instanceof EEM_Event) {
297
-            $default_reg_status = new EE_Enum_Text_Field(
298
-                'EVT_default_registration_status',
299
-                esc_html__('Default Registration Status on this Event', 'event_espresso'),
300
-                false,
301
-                $default_reg_status,
302
-                EEM_Registration::reg_status_array()
303
-            );
304
-            $default_reg_status->_construct_finalize(
305
-                'Event_Meta',
306
-                'EVT_default_registration_status',
307
-                'EEM_Event'
308
-            );
309
-            self::$_instance->_fields['Event_Meta']['EVT_default_registration_status'] = $default_reg_status;
310
-        }
311
-    }
312
-
313
-
314
-    /**
315
-     * Used to override the default for the additional limit field.
316
-     * @param $additional_limit
317
-     */
318
-    public static function set_default_additional_limit($additional_limit)
319
-    {
320
-        self::$_default_additional_limit = (int) $additional_limit;
321
-        if (self::$_instance instanceof EEM_Event) {
322
-            self::$_instance->_fields['Event_Meta']['EVT_additional_limit'] = new EE_Integer_Field(
323
-                'EVT_additional_limit',
324
-                esc_html__('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
325
-                true,
326
-                self::$_default_additional_limit
327
-            );
328
-            self::$_instance->_fields['Event_Meta']['EVT_additional_limit']->_construct_finalize(
329
-                'Event_Meta',
330
-                'EVT_additional_limit',
331
-                'EEM_Event'
332
-            );
333
-        }
334
-    }
335
-
336
-
337
-    /**
338
-     * Return what is currently set as the default additional limit for the event.
339
-     * @return int
340
-     */
341
-    public static function get_default_additional_limit()
342
-    {
343
-        return apply_filters('FHEE__EEM_Event__get_default_additional_limit', self::$_default_additional_limit);
344
-    }
345
-
346
-
347
-    /**
348
-     * get_question_groups
349
-     *
350
-     * @return array
351
-     * @throws \EE_Error
352
-     */
353
-    public function get_all_question_groups()
354
-    {
355
-        return EE_Registry::instance()->load_model('Question_Group')->get_all(
356
-            array(
357
-                array('QSG_deleted' => false),
358
-                'order_by' => array('QSG_order' => 'ASC'),
359
-            )
360
-        );
361
-    }
362
-
363
-
364
-
365
-    /**
366
-     * get_question_groups
367
-     *
368
-     * @param int $EVT_ID
369
-     * @return array|bool
370
-     * @throws \EE_Error
371
-     */
372
-    public function get_all_event_question_groups($EVT_ID = 0)
373
-    {
374
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
375
-            EE_Error::add_error(
376
-                esc_html__(
377
-                    'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
378
-                    'event_espresso'
379
-                ),
380
-                __FILE__,
381
-                __FUNCTION__,
382
-                __LINE__
383
-            );
384
-            return false;
385
-        }
386
-        return EE_Registry::instance()->load_model('Event_Question_Group')->get_all(
387
-            array(
388
-                array('EVT_ID' => $EVT_ID),
389
-            )
390
-        );
391
-    }
392
-
393
-
394
-    /**
395
-     * get_question_groups
396
-     *
397
-     * @param int $EVT_ID
398
-     * @param boolean $for_primary_attendee
399
-     * @return array|bool
400
-     * @throws EE_Error
401
-     * @throws InvalidArgumentException
402
-     * @throws ReflectionException
403
-     * @throws InvalidDataTypeException
404
-     * @throws InvalidInterfaceException
405
-     */
406
-    public function get_event_question_groups($EVT_ID = 0, $for_primary_attendee = true)
407
-    {
408
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
409
-            EE_Error::add_error(
410
-                esc_html__(
411
-                    // @codingStandardsIgnoreStart
412
-                    'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
413
-                    // @codingStandardsIgnoreEnd
414
-                    'event_espresso'
415
-                ),
416
-                __FILE__,
417
-                __FUNCTION__,
418
-                __LINE__
419
-            );
420
-            return false;
421
-        }
422
-        $query_params = [
423
-            [
424
-                'EVT_ID' => $EVT_ID,
425
-                EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary_attendee) => true
426
-            ]
427
-        ];
428
-        if ($for_primary_attendee) {
429
-            $query_params[0]['EQG_primary'] = true;
430
-        } else {
431
-            $query_params[0]['EQG_additional'] = true;
432
-        }
433
-        return EE_Registry::instance()->load_model('Event_Question_Group')->get_all($query_params);
434
-    }
435
-
436
-
437
-    /**
438
-     * get_question_groups
439
-     *
440
-     * @param int $EVT_ID
441
-     * @param EE_Registration $registration
442
-     * @return array|bool
443
-     * @throws EE_Error
444
-     * @throws InvalidArgumentException
445
-     * @throws InvalidDataTypeException
446
-     * @throws InvalidInterfaceException
447
-     * @throws ReflectionException
448
-     */
449
-    public function get_question_groups_for_event($EVT_ID = 0, EE_Registration $registration)
450
-    {
451
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
452
-            EE_Error::add_error(
453
-                esc_html__(
454
-                    'An error occurred. No Question Groups could be retrieved because an Event ID was not received.',
455
-                    'event_espresso'
456
-                ),
457
-                __FILE__,
458
-                __FUNCTION__,
459
-                __LINE__
460
-            );
461
-            return false;
462
-        }
463
-        return EE_Registry::instance()->load_model('Question_Group')->get_all(
464
-            [
465
-                [
466
-                    'Event_Question_Group.EVT_ID'      => $EVT_ID,
467
-                    'Event_Question_Group.'
468
-                        . EEM_Event_Question_Group::instance()->fieldNameForContext(
469
-                            $registration->is_primary_registrant()
470
-                        ) => true
471
-                ],
472
-                'order_by' => ['QSG_order' => 'ASC'],
473
-            ]
474
-        );
475
-    }
476
-
477
-
478
-
479
-    /**
480
-     * get_question_target_db_column
481
-     *
482
-     * @param string $QSG_IDs csv list of $QSG IDs
483
-     * @return array|bool
484
-     * @throws \EE_Error
485
-     */
486
-    public function get_questions_in_groups($QSG_IDs = '')
487
-    {
488
-        if (empty($QSG_IDs)) {
489
-            EE_Error::add_error(
490
-                esc_html__('An error occurred. No Question Group IDs were received.', 'event_espresso'),
491
-                __FILE__,
492
-                __FUNCTION__,
493
-                __LINE__
494
-            );
495
-            return false;
496
-        }
497
-        return EE_Registry::instance()->load_model('Question')->get_all(
498
-            array(
499
-                array(
500
-                    'Question_Group.QSG_ID' => array('IN', $QSG_IDs),
501
-                    'QST_deleted'           => false,
502
-                    'QST_admin_only'        => is_admin(),
503
-                ),
504
-                'order_by' => 'QST_order',
505
-            )
506
-        );
507
-    }
508
-
509
-
510
-
511
-    /**
512
-     * get_options_for_question
513
-     *
514
-     * @param string $QST_IDs csv list of $QST IDs
515
-     * @return array|bool
516
-     * @throws \EE_Error
517
-     */
518
-    public function get_options_for_question($QST_IDs)
519
-    {
520
-        if (empty($QST_IDs)) {
521
-            EE_Error::add_error(
522
-                esc_html__('An error occurred. No Question IDs were received.', 'event_espresso'),
523
-                __FILE__,
524
-                __FUNCTION__,
525
-                __LINE__
526
-            );
527
-            return false;
528
-        }
529
-        return EE_Registry::instance()->load_model('Question_Option')->get_all(
530
-            array(
531
-                array(
532
-                    'Question.QST_ID' => array('IN', $QST_IDs),
533
-                    'QSO_deleted'     => false,
534
-                ),
535
-                'order_by' => 'QSO_ID',
536
-            )
537
-        );
538
-    }
539
-
540
-
541
-
542
-
543
-
544
-
545
-
546
-    /**
547
-     * Gets all events that are published
548
-     * and have event start time earlier than now and an event end time later than now
549
-     *
550
-     * @param  array $query_params An array of query params to further filter on
551
-     *                             (note that status and DTT_EVT_start and DTT_EVT_end will be overridden)
552
-     * @param bool   $count        whether to return the count or not (default FALSE)
553
-     * @return EE_Event[]|int
554
-     * @throws \EE_Error
555
-     */
556
-    public function get_active_events($query_params, $count = false)
557
-    {
558
-        if (array_key_exists(0, $query_params)) {
559
-            $where_params = $query_params[0];
560
-            unset($query_params[0]);
561
-        } else {
562
-            $where_params = array();
563
-        }
564
-        // if we have count make sure we don't include group by
565
-        if ($count && isset($query_params['group_by'])) {
566
-            unset($query_params['group_by']);
567
-        }
568
-        // let's add specific query_params for active_events
569
-        // keep in mind this will override any sent status in the query AND any date queries.
570
-        $where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
571
-        // if already have where params for DTT_EVT_start or DTT_EVT_end then append these conditions
572
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
573
-            $where_params['Datetime.DTT_EVT_start******'] = array(
574
-                '<',
575
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
576
-            );
577
-        } else {
578
-            $where_params['Datetime.DTT_EVT_start'] = array(
579
-                '<',
580
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
581
-            );
582
-        }
583
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
584
-            $where_params['Datetime.DTT_EVT_end*****'] = array(
585
-                '>',
586
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
587
-            );
588
-        } else {
589
-            $where_params['Datetime.DTT_EVT_end'] = array(
590
-                '>',
591
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
592
-            );
593
-        }
594
-        $query_params[0] = $where_params;
595
-        // don't use $query_params with count()
596
-        // because we don't want to include additional query clauses like "GROUP BY"
597
-        return $count
598
-            ? $this->count(array($where_params), 'EVT_ID', true)
599
-            : $this->get_all($query_params);
600
-    }
601
-
602
-
603
-
604
-    /**
605
-     * get all events that are published and have an event start time later than now
606
-     *
607
-     * @param  array $query_params An array of query params to further filter on
608
-     *                             (Note that status and DTT_EVT_start will be overridden)
609
-     * @param bool   $count        whether to return the count or not (default FALSE)
610
-     * @return EE_Event[]|int
611
-     * @throws \EE_Error
612
-     */
613
-    public function get_upcoming_events($query_params, $count = false)
614
-    {
615
-        if (array_key_exists(0, $query_params)) {
616
-            $where_params = $query_params[0];
617
-            unset($query_params[0]);
618
-        } else {
619
-            $where_params = array();
620
-        }
621
-        // if we have count make sure we don't include group by
622
-        if ($count && isset($query_params['group_by'])) {
623
-            unset($query_params['group_by']);
624
-        }
625
-        // let's add specific query_params for active_events
626
-        // keep in mind this will override any sent status in the query AND any date queries.
627
-        // we need to pull events with a status of publish and sold_out
628
-        $event_status = array('publish', EEM_Event::sold_out);
629
-        // check if the user can read private events and if so add the 'private status to the were params'
630
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_upcoming_events')) {
631
-            $event_status[] = 'private';
632
-        }
633
-        $where_params['status'] = array('IN', $event_status);
634
-        // if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
635
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
636
-            $where_params['Datetime.DTT_EVT_start*****'] = array(
637
-                '>',
638
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
639
-            );
640
-        } else {
641
-            $where_params['Datetime.DTT_EVT_start'] = array(
642
-                '>',
643
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
644
-            );
645
-        }
646
-        $query_params[0] = $where_params;
647
-        // don't use $query_params with count()
648
-        // because we don't want to include additional query clauses like "GROUP BY"
649
-        return $count
650
-            ? $this->count(array($where_params), 'EVT_ID', true)
651
-            : $this->get_all($query_params);
652
-    }
653
-
654
-
655
-
656
-    /**
657
-     * Gets all events that are published
658
-     * and have an event end time later than now
659
-     *
660
-     * @param  array $query_params An array of query params to further filter on
661
-     *                             (note that status and DTT_EVT_end will be overridden)
662
-     * @param bool   $count        whether to return the count or not (default FALSE)
663
-     * @return EE_Event[]|int
664
-     * @throws \EE_Error
665
-     */
666
-    public function get_active_and_upcoming_events($query_params, $count = false)
667
-    {
668
-        if (array_key_exists(0, $query_params)) {
669
-            $where_params = $query_params[0];
670
-            unset($query_params[0]);
671
-        } else {
672
-            $where_params = array();
673
-        }
674
-        // if we have count make sure we don't include group by
675
-        if ($count && isset($query_params['group_by'])) {
676
-            unset($query_params['group_by']);
677
-        }
678
-        // let's add specific query_params for active_events
679
-        // keep in mind this will override any sent status in the query AND any date queries.
680
-        $where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
681
-        // add where params for DTT_EVT_end
682
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
683
-            $where_params['Datetime.DTT_EVT_end*****'] = array(
684
-                '>',
685
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
686
-            );
687
-        } else {
688
-            $where_params['Datetime.DTT_EVT_end'] = array(
689
-                '>',
690
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
691
-            );
692
-        }
693
-        $query_params[0] = $where_params;
694
-        // don't use $query_params with count()
695
-        // because we don't want to include additional query clauses like "GROUP BY"
696
-        return $count
697
-            ? $this->count(array($where_params), 'EVT_ID', true)
698
-            : $this->get_all($query_params);
699
-    }
700
-
701
-
702
-
703
-    /**
704
-     * This only returns events that are expired.
705
-     * They may still be published but all their datetimes have expired.
706
-     *
707
-     * @param  array $query_params An array of query params to further filter on
708
-     *                             (note that status and DTT_EVT_end will be overridden)
709
-     * @param bool   $count        whether to return the count or not (default FALSE)
710
-     * @return EE_Event[]|int
711
-     * @throws \EE_Error
712
-     */
713
-    public function get_expired_events($query_params, $count = false)
714
-    {
715
-        $where_params = isset($query_params[0]) ? $query_params[0] : array();
716
-        // if we have count make sure we don't include group by
717
-        if ($count && isset($query_params['group_by'])) {
718
-            unset($query_params['group_by']);
719
-        }
720
-        // let's add specific query_params for active_events
721
-        // keep in mind this will override any sent status in the query AND any date queries.
722
-        if (isset($where_params['status'])) {
723
-            unset($where_params['status']);
724
-        }
725
-        $exclude_query = $query_params;
726
-        if (isset($exclude_query[0])) {
727
-            unset($exclude_query[0]);
728
-        }
729
-        $exclude_query[0] = array(
730
-            'Datetime.DTT_EVT_end' => array(
731
-                '>',
732
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
733
-            ),
734
-        );
735
-        // first get all events that have datetimes where its not expired.
736
-        $event_ids = $this->_get_all_wpdb_results($exclude_query, OBJECT_K, 'Event_CPT.ID');
737
-        $event_ids = array_keys($event_ids);
738
-        // if we have any additional query_params, let's add them to the 'AND' condition
739
-        $and_condition = array(
740
-            'Datetime.DTT_EVT_end' => array('<', EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end')),
741
-            'EVT_ID'               => array('NOT IN', $event_ids),
742
-        );
743
-        if (isset($where_params['OR'])) {
744
-            $and_condition['OR'] = $where_params['OR'];
745
-            unset($where_params['OR']);
746
-        }
747
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
748
-            $and_condition['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
749
-            unset($where_params['Datetime.DTT_EVT_end']);
750
-        }
751
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
752
-            $and_condition['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
753
-            unset($where_params['Datetime.DTT_EVT_start']);
754
-        }
755
-        // merge remaining $where params with the and conditions.
756
-        $where_params['AND'] = array_merge($and_condition, $where_params);
757
-        $query_params[0] = $where_params;
758
-        // don't use $query_params with count()
759
-        // because we don't want to include additional query clauses like "GROUP BY"
760
-        return $count
761
-            ? $this->count(array($where_params), 'EVT_ID', true)
762
-            : $this->get_all($query_params);
763
-    }
764
-
765
-
766
-
767
-    /**
768
-     * This basically just returns the events that do not have the publish status.
769
-     *
770
-     * @param  array   $query_params An array of query params to further filter on
771
-     *                               (note that status will be overwritten)
772
-     * @param  boolean $count        whether to return the count or not (default FALSE)
773
-     * @return EE_Event[]|int
774
-     * @throws \EE_Error
775
-     */
776
-    public function get_inactive_events($query_params, $count = false)
777
-    {
778
-        $where_params = isset($query_params[0]) ? $query_params[0] : array();
779
-        // let's add in specific query_params for inactive events.
780
-        if (isset($where_params['status'])) {
781
-            unset($where_params['status']);
782
-        }
783
-        // if we have count make sure we don't include group by
784
-        if ($count && isset($query_params['group_by'])) {
785
-            unset($query_params['group_by']);
786
-        }
787
-        // if we have any additional query_params, let's add them to the 'AND' condition
788
-        $where_params['AND']['status'] = array('!=', 'publish');
789
-        if (isset($where_params['OR'])) {
790
-            $where_params['AND']['OR'] = $where_params['OR'];
791
-            unset($where_params['OR']);
792
-        }
793
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
794
-            $where_params['AND']['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
795
-            unset($where_params['Datetime.DTT_EVT_end']);
796
-        }
797
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
798
-            $where_params['AND']['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
799
-            unset($where_params['Datetime.DTT_EVT_start']);
800
-        }
801
-        $query_params[0] = $where_params;
802
-        // don't use $query_params with count()
803
-        // because we don't want to include additional query clauses like "GROUP BY"
804
-        return $count
805
-            ? $this->count(array($where_params), 'EVT_ID', true)
806
-            : $this->get_all($query_params);
807
-    }
808
-
809
-
810
-
811
-    /**
812
-     * This is just injecting into the parent add_relationship_to so we do special handling on price relationships
813
-     * because we don't want to override any existing global default prices but instead insert NEW prices that get
814
-     * attached to the event. See parent for param descriptions
815
-     *
816
-     * @param        $id_or_obj
817
-     * @param        $other_model_id_or_obj
818
-     * @param string $relationName
819
-     * @param array  $where_query
820
-     * @return EE_Base_Class
821
-     * @throws EE_Error
822
-     */
823
-    public function add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query = array())
824
-    {
825
-        if ($relationName === 'Price') {
826
-            // let's get the PRC object for the given ID to make sure that we aren't dealing with a default
827
-            $prc_chk = $this->get_related_model_obj($relationName)->ensure_is_obj($other_model_id_or_obj);
828
-            // if EVT_ID = 0, then this is a default
829
-            if ((int) $prc_chk->get('EVT_ID') === 0) {
830
-                // let's set the prc_id as 0 so we force an insert on the add_relation_to carried out by relation
831
-                $prc_chk->set('PRC_ID', 0);
832
-            }
833
-            // run parent
834
-            return parent::add_relationship_to($id_or_obj, $prc_chk, $relationName, $where_query);
835
-        }
836
-        // otherwise carry on as normal
837
-        return parent::add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query);
838
-    }
839
-
840
-
841
-
842
-    /******************** DEPRECATED METHODS ********************/
843
-
844
-
845
-
846
-    /**
847
-     * _get_question_target_db_column
848
-     *
849
-     * @deprecated as of 4.8.32.rc.001. Instead consider using
850
-     *             EE_Registration_Custom_Questions_Form located in
851
-     *             admin_pages/registrations/form_sections/EE_Registration_Custom_Questions_Form.form.php
852
-     * @access     public
853
-     * @param    EE_Registration $registration (so existing answers for registration are included)
854
-     * @param    int             $EVT_ID       so all question groups are included for event (not just answers from
855
-     *                                         registration).
856
-     * @throws EE_Error
857
-     * @return    array
858
-     */
859
-    public function assemble_array_of_groups_questions_and_options(EE_Registration $registration, $EVT_ID = 0)
860
-    {
861
-        if (empty($EVT_ID)) {
862
-            throw new EE_Error(esc_html__(
863
-                'An error occurred. No EVT_ID is included.  Needed to know which question groups to retrieve.',
864
-                'event_espresso'
865
-            ));
866
-        }
867
-        $questions = array();
868
-        // get all question groups for event
869
-        $qgs = $this->get_question_groups_for_event($EVT_ID, $registration);
870
-        if (! empty($qgs)) {
871
-            foreach ($qgs as $qg) {
872
-                $qsts = $qg->questions();
873
-                $questions[ $qg->ID() ] = $qg->model_field_array();
874
-                $questions[ $qg->ID() ]['QSG_questions'] = array();
875
-                foreach ($qsts as $qst) {
876
-                    if ($qst->is_system_question()) {
877
-                        continue;
878
-                    }
879
-                    $answer = EEM_Answer::instance()->get_one(array(
880
-                        array(
881
-                            'QST_ID' => $qst->ID(),
882
-                            'REG_ID' => $registration->ID(),
883
-                        ),
884
-                    ));
885
-                    $answer = $answer instanceof EE_Answer ? $answer : EEM_Answer::instance()->create_default_object();
886
-                    $qst_name = $qstn_id = $qst->ID();
887
-                    $ans_id = $answer->ID();
888
-                    $qst_name = ! empty($ans_id) ? '[' . $qst_name . '][' . $ans_id . ']' : '[' . $qst_name . ']';
889
-                    $input_name = '';
890
-                    $input_id = sanitize_key($qst->display_text());
891
-                    $input_class = '';
892
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ] = $qst->model_field_array();
893
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_name'] = 'qstn'
894
-                                                                                           . $input_name
895
-                                                                                           . $qst_name;
896
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_id'] = $input_id . '-' . $qstn_id;
897
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_class'] = $input_class;
898
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'] = array();
899
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['qst_obj'] = $qst;
900
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['ans_obj'] = $answer;
901
-                    // leave responses as-is, don't convert stuff into html entities please!
902
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['htmlentities'] = false;
903
-                    if ($qst->type() == 'RADIO_BTN' || $qst->type() == 'CHECKBOX' || $qst->type() == 'DROPDOWN') {
904
-                        $QSOs = $qst->options(true, $answer->value());
905
-                        if (is_array($QSOs)) {
906
-                            foreach ($QSOs as $QSO_ID => $QSO) {
907
-                                $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'][ $QSO_ID ] = $QSO->model_field_array();
908
-                            }
909
-                        }
910
-                    }
911
-                }
912
-            }
913
-        }
914
-        return $questions;
915
-    }
916
-
917
-
918
-    /**
919
-     * @param mixed $cols_n_values either an array of where each key is the name of a field, and the value is its value
920
-     *                             or an stdClass where each property is the name of a column,
921
-     * @return EE_Base_Class
922
-     * @throws \EE_Error
923
-     */
924
-    public function instantiate_class_from_array_or_object($cols_n_values)
925
-    {
926
-        $classInstance = parent::instantiate_class_from_array_or_object($cols_n_values);
927
-        if ($classInstance instanceof EE_Event) {
928
-            // events have their timezone defined in the DB, so use it immediately
929
-            $this->set_timezone($classInstance->get_timezone());
930
-        }
931
-        return $classInstance;
932
-    }
933
-
934
-
935
-    /**
936
-     * Deletes the model objects that meet the query params. Note: this method is overridden
937
-     * in EEM_Soft_Delete_Base so that soft-deleted model objects are instead only flagged
938
-     * as archived, not actually deleted
939
-     *
940
-     * @param array   $query_params   @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
941
-     * @param boolean $allow_blocking if TRUE, matched objects will only be deleted if there is no related model info
942
-     *                                that blocks it (ie, there' sno other data that depends on this data); if false,
943
-     *                                deletes regardless of other objects which may depend on it. Its generally
944
-     *                                advisable to always leave this as TRUE, otherwise you could easily corrupt your
945
-     *                                DB
946
-     * @return int                    number of rows deleted
947
-     * @throws EE_Error
948
-     */
949
-    public function delete_permanently($query_params, $allow_blocking = true)
950
-    {
951
-        $deleted = parent::delete_permanently($query_params, $allow_blocking);
952
-        if ($deleted) {
953
-            // get list of events with no prices
954
-            $espresso_no_ticket_prices = get_option('ee_no_ticket_prices', []);
955
-            $where = isset($query_params[0]) ? $query_params[0] : [];
956
-            $where_event = isset($where['EVT_ID']) ? $where['EVT_ID'] : ['', ''];
957
-            $where_event_ids = isset($where_event[1]) ? $where_event[1] : '';
958
-            $event_ids = is_string($where_event_ids)
959
-                ? explode(',', $where_event_ids)
960
-                : (array) $where_event_ids;
961
-            array_walk($event_ids, 'trim');
962
-            $event_ids = array_filter($event_ids);
963
-            // remove events from list of events with no prices
964
-            $espresso_no_ticket_prices = array_diff($espresso_no_ticket_prices, $event_ids);
965
-            update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
966
-        }
967
-        return $deleted;
968
-    }
18
+	/**
19
+	 * constant used by status(), indicating that no more tickets can be purchased for any of the datetimes for the
20
+	 * event
21
+	 */
22
+	const sold_out = 'sold_out';
23
+
24
+	/**
25
+	 * constant used by status(), indicating that upcoming event dates have been postponed (may be pushed to a later
26
+	 * date)
27
+	 */
28
+	const postponed = 'postponed';
29
+
30
+	/**
31
+	 * constant used by status(), indicating that the event will no longer occur
32
+	 */
33
+	const cancelled = 'cancelled';
34
+
35
+
36
+	/**
37
+	 * @var string
38
+	 */
39
+	protected static $_default_reg_status;
40
+
41
+
42
+	/**
43
+	 * This is the default for the additional limit field.
44
+	 * @var int
45
+	 */
46
+	protected static $_default_additional_limit = 10;
47
+
48
+
49
+	/**
50
+	 * private instance of the Event object
51
+	 *
52
+	 * @var EEM_Event
53
+	 */
54
+	protected static $_instance;
55
+
56
+
57
+
58
+
59
+	/**
60
+	 * Adds a relationship to Term_Taxonomy for each CPT_Base
61
+	 *
62
+	 * @param string $timezone
63
+	 * @throws \EE_Error
64
+	 */
65
+	protected function __construct($timezone = null)
66
+	{
67
+		EE_Registry::instance()->load_model('Registration');
68
+		$this->singular_item = esc_html__('Event', 'event_espresso');
69
+		$this->plural_item = esc_html__('Events', 'event_espresso');
70
+		// to remove Cancelled events from the frontend, copy the following filter to your functions.php file
71
+		// add_filter( 'AFEE__EEM_Event__construct___custom_stati__cancelled__Public', '__return_false' );
72
+		// to remove Postponed events from the frontend, copy the following filter to your functions.php file
73
+		// add_filter( 'AFEE__EEM_Event__construct___custom_stati__postponed__Public', '__return_false' );
74
+		// to remove Sold Out events from the frontend, copy the following filter to your functions.php file
75
+		//  add_filter( 'AFEE__EEM_Event__construct___custom_stati__sold_out__Public', '__return_false' );
76
+		$this->_custom_stati = apply_filters(
77
+			'AFEE__EEM_Event__construct___custom_stati',
78
+			array(
79
+				EEM_Event::cancelled => array(
80
+					'label'  => esc_html__('Cancelled', 'event_espresso'),
81
+					'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__cancelled__Public', true),
82
+				),
83
+				EEM_Event::postponed => array(
84
+					'label'  => esc_html__('Postponed', 'event_espresso'),
85
+					'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__postponed__Public', true),
86
+				),
87
+				EEM_Event::sold_out  => array(
88
+					'label'  => esc_html__('Sold Out', 'event_espresso'),
89
+					'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__sold_out__Public', true),
90
+				),
91
+			)
92
+		);
93
+		self::$_default_reg_status = empty(self::$_default_reg_status) ? EEM_Registration::status_id_pending_payment
94
+			: self::$_default_reg_status;
95
+		$this->_tables = array(
96
+			'Event_CPT'  => new EE_Primary_Table('posts', 'ID'),
97
+			'Event_Meta' => new EE_Secondary_Table('esp_event_meta', 'EVTM_ID', 'EVT_ID'),
98
+		);
99
+		$this->_fields = array(
100
+			'Event_CPT'  => array(
101
+				'EVT_ID'         => new EE_Primary_Key_Int_Field(
102
+					'ID',
103
+					esc_html__('Post ID for Event', 'event_espresso')
104
+				),
105
+				'EVT_name'       => new EE_Plain_Text_Field(
106
+					'post_title',
107
+					esc_html__('Event Name', 'event_espresso'),
108
+					false,
109
+					''
110
+				),
111
+				'EVT_desc'       => new EE_Post_Content_Field(
112
+					'post_content',
113
+					esc_html__('Event Description', 'event_espresso'),
114
+					false,
115
+					''
116
+				),
117
+				'EVT_slug'       => new EE_Slug_Field(
118
+					'post_name',
119
+					esc_html__('Event Slug', 'event_espresso'),
120
+					false,
121
+					''
122
+				),
123
+				'EVT_created'    => new EE_Datetime_Field(
124
+					'post_date',
125
+					esc_html__('Date/Time Event Created', 'event_espresso'),
126
+					false,
127
+					EE_Datetime_Field::now
128
+				),
129
+				'EVT_short_desc' => new EE_Simple_HTML_Field(
130
+					'post_excerpt',
131
+					esc_html__('Event Short Description', 'event_espresso'),
132
+					false,
133
+					''
134
+				),
135
+				'EVT_modified'   => new EE_Datetime_Field(
136
+					'post_modified',
137
+					esc_html__('Date/Time Event Modified', 'event_espresso'),
138
+					false,
139
+					EE_Datetime_Field::now
140
+				),
141
+				'EVT_wp_user'    => new EE_WP_User_Field(
142
+					'post_author',
143
+					esc_html__('Event Creator ID', 'event_espresso'),
144
+					false
145
+				),
146
+				'parent'         => new EE_Integer_Field(
147
+					'post_parent',
148
+					esc_html__('Event Parent ID', 'event_espresso'),
149
+					false,
150
+					0
151
+				),
152
+				'EVT_order'      => new EE_Integer_Field(
153
+					'menu_order',
154
+					esc_html__('Event Menu Order', 'event_espresso'),
155
+					false,
156
+					1
157
+				),
158
+				'post_type'      => new EE_WP_Post_Type_Field('espresso_events'),
159
+				// EE_Plain_Text_Field( 'post_type', esc_html__( 'Event Post Type', 'event_espresso' ), FALSE, 'espresso_events' ),
160
+				'status'         => new EE_WP_Post_Status_Field(
161
+					'post_status',
162
+					esc_html__('Event Status', 'event_espresso'),
163
+					false,
164
+					'draft',
165
+					$this->_custom_stati
166
+				),
167
+				'password' => new EE_Password_Field(
168
+					'post_password',
169
+					esc_html__('Password', 'event_espresso'),
170
+					false,
171
+					'',
172
+					array(
173
+						'EVT_desc',
174
+						'EVT_short_desc',
175
+						'EVT_display_desc',
176
+						'EVT_display_ticket_selector',
177
+						'EVT_visible_on',
178
+						'EVT_additional_limit',
179
+						'EVT_default_registration_status',
180
+						'EVT_member_only',
181
+						'EVT_phone',
182
+						'EVT_allow_overflow',
183
+						'EVT_timezone_string',
184
+						'EVT_external_URL',
185
+						'EVT_donations'
186
+					)
187
+				)
188
+			),
189
+			'Event_Meta' => array(
190
+				'EVTM_ID'                         => new EE_DB_Only_Float_Field(
191
+					'EVTM_ID',
192
+					esc_html__('Event Meta Row ID', 'event_espresso'),
193
+					false
194
+				),
195
+				'EVT_ID_fk'                       => new EE_DB_Only_Int_Field(
196
+					'EVT_ID',
197
+					esc_html__('Foreign key to Event ID from Event Meta table', 'event_espresso'),
198
+					false
199
+				),
200
+				'EVT_display_desc'                => new EE_Boolean_Field(
201
+					'EVT_display_desc',
202
+					esc_html__('Display Description Flag', 'event_espresso'),
203
+					false,
204
+					true
205
+				),
206
+				'EVT_display_ticket_selector'     => new EE_Boolean_Field(
207
+					'EVT_display_ticket_selector',
208
+					esc_html__('Display Ticket Selector Flag', 'event_espresso'),
209
+					false,
210
+					true
211
+				),
212
+				'EVT_visible_on'                  => new EE_Datetime_Field(
213
+					'EVT_visible_on',
214
+					esc_html__('Event Visible Date', 'event_espresso'),
215
+					true,
216
+					EE_Datetime_Field::now
217
+				),
218
+				'EVT_additional_limit'            => new EE_Integer_Field(
219
+					'EVT_additional_limit',
220
+					esc_html__('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
221
+					true,
222
+					self::$_default_additional_limit
223
+				),
224
+				'EVT_default_registration_status' => new EE_Enum_Text_Field(
225
+					'EVT_default_registration_status',
226
+					esc_html__('Default Registration Status on this Event', 'event_espresso'),
227
+					false,
228
+					EEM_Event::$_default_reg_status,
229
+					EEM_Registration::reg_status_array()
230
+				),
231
+				'EVT_member_only'                 => new EE_Boolean_Field(
232
+					'EVT_member_only',
233
+					esc_html__('Member-Only Event Flag', 'event_espresso'),
234
+					false,
235
+					false
236
+				),
237
+				'EVT_phone'                       => new EE_Plain_Text_Field(
238
+					'EVT_phone',
239
+					esc_html__('Event Phone Number', 'event_espresso'),
240
+					false,
241
+					''
242
+				),
243
+				'EVT_allow_overflow'              => new EE_Boolean_Field(
244
+					'EVT_allow_overflow',
245
+					esc_html__('Allow Overflow on Event', 'event_espresso'),
246
+					false,
247
+					false
248
+				),
249
+				'EVT_timezone_string'             => new EE_Plain_Text_Field(
250
+					'EVT_timezone_string',
251
+					esc_html__('Timezone (name) for Event times', 'event_espresso'),
252
+					false,
253
+					''
254
+				),
255
+				'EVT_external_URL'                => new EE_Plain_Text_Field(
256
+					'EVT_external_URL',
257
+					esc_html__('URL of Event Page if hosted elsewhere', 'event_espresso'),
258
+					true
259
+				),
260
+				'EVT_donations'                   => new EE_Boolean_Field(
261
+					'EVT_donations',
262
+					esc_html__('Accept Donations?', 'event_espresso'),
263
+					false,
264
+					false
265
+				),
266
+			),
267
+		);
268
+		$this->_model_relations = array(
269
+			'Registration'           => new EE_Has_Many_Relation(),
270
+			'Datetime'               => new EE_Has_Many_Relation(),
271
+			'Question_Group'         => new EE_HABTM_Relation('Event_Question_Group'),
272
+			'Event_Question_Group'   => new EE_Has_Many_Relation(),
273
+			'Venue'                  => new EE_HABTM_Relation('Event_Venue'),
274
+			'Term_Relationship'      => new EE_Has_Many_Relation(),
275
+			'Term_Taxonomy'          => new EE_HABTM_Relation('Term_Relationship'),
276
+			'Message_Template_Group' => new EE_HABTM_Relation('Event_Message_Template'),
277
+			'Attendee'               => new EE_HABTM_Relation('Registration'),
278
+			'WP_User'                => new EE_Belongs_To_Relation(),
279
+		);
280
+		// this model is generally available for reading
281
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
282
+		$this->model_chain_to_password = '';
283
+		parent::__construct($timezone);
284
+	}
285
+
286
+
287
+
288
+	/**
289
+	 * @param string $default_reg_status
290
+	 */
291
+	public static function set_default_reg_status($default_reg_status)
292
+	{
293
+		self::$_default_reg_status = $default_reg_status;
294
+		// if EEM_Event has already been instantiated,
295
+		// then we need to reset the `EVT_default_reg_status` field to use the new default.
296
+		if (self::$_instance instanceof EEM_Event) {
297
+			$default_reg_status = new EE_Enum_Text_Field(
298
+				'EVT_default_registration_status',
299
+				esc_html__('Default Registration Status on this Event', 'event_espresso'),
300
+				false,
301
+				$default_reg_status,
302
+				EEM_Registration::reg_status_array()
303
+			);
304
+			$default_reg_status->_construct_finalize(
305
+				'Event_Meta',
306
+				'EVT_default_registration_status',
307
+				'EEM_Event'
308
+			);
309
+			self::$_instance->_fields['Event_Meta']['EVT_default_registration_status'] = $default_reg_status;
310
+		}
311
+	}
312
+
313
+
314
+	/**
315
+	 * Used to override the default for the additional limit field.
316
+	 * @param $additional_limit
317
+	 */
318
+	public static function set_default_additional_limit($additional_limit)
319
+	{
320
+		self::$_default_additional_limit = (int) $additional_limit;
321
+		if (self::$_instance instanceof EEM_Event) {
322
+			self::$_instance->_fields['Event_Meta']['EVT_additional_limit'] = new EE_Integer_Field(
323
+				'EVT_additional_limit',
324
+				esc_html__('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
325
+				true,
326
+				self::$_default_additional_limit
327
+			);
328
+			self::$_instance->_fields['Event_Meta']['EVT_additional_limit']->_construct_finalize(
329
+				'Event_Meta',
330
+				'EVT_additional_limit',
331
+				'EEM_Event'
332
+			);
333
+		}
334
+	}
335
+
336
+
337
+	/**
338
+	 * Return what is currently set as the default additional limit for the event.
339
+	 * @return int
340
+	 */
341
+	public static function get_default_additional_limit()
342
+	{
343
+		return apply_filters('FHEE__EEM_Event__get_default_additional_limit', self::$_default_additional_limit);
344
+	}
345
+
346
+
347
+	/**
348
+	 * get_question_groups
349
+	 *
350
+	 * @return array
351
+	 * @throws \EE_Error
352
+	 */
353
+	public function get_all_question_groups()
354
+	{
355
+		return EE_Registry::instance()->load_model('Question_Group')->get_all(
356
+			array(
357
+				array('QSG_deleted' => false),
358
+				'order_by' => array('QSG_order' => 'ASC'),
359
+			)
360
+		);
361
+	}
362
+
363
+
364
+
365
+	/**
366
+	 * get_question_groups
367
+	 *
368
+	 * @param int $EVT_ID
369
+	 * @return array|bool
370
+	 * @throws \EE_Error
371
+	 */
372
+	public function get_all_event_question_groups($EVT_ID = 0)
373
+	{
374
+		if (! isset($EVT_ID) || ! absint($EVT_ID)) {
375
+			EE_Error::add_error(
376
+				esc_html__(
377
+					'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
378
+					'event_espresso'
379
+				),
380
+				__FILE__,
381
+				__FUNCTION__,
382
+				__LINE__
383
+			);
384
+			return false;
385
+		}
386
+		return EE_Registry::instance()->load_model('Event_Question_Group')->get_all(
387
+			array(
388
+				array('EVT_ID' => $EVT_ID),
389
+			)
390
+		);
391
+	}
392
+
393
+
394
+	/**
395
+	 * get_question_groups
396
+	 *
397
+	 * @param int $EVT_ID
398
+	 * @param boolean $for_primary_attendee
399
+	 * @return array|bool
400
+	 * @throws EE_Error
401
+	 * @throws InvalidArgumentException
402
+	 * @throws ReflectionException
403
+	 * @throws InvalidDataTypeException
404
+	 * @throws InvalidInterfaceException
405
+	 */
406
+	public function get_event_question_groups($EVT_ID = 0, $for_primary_attendee = true)
407
+	{
408
+		if (! isset($EVT_ID) || ! absint($EVT_ID)) {
409
+			EE_Error::add_error(
410
+				esc_html__(
411
+					// @codingStandardsIgnoreStart
412
+					'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
413
+					// @codingStandardsIgnoreEnd
414
+					'event_espresso'
415
+				),
416
+				__FILE__,
417
+				__FUNCTION__,
418
+				__LINE__
419
+			);
420
+			return false;
421
+		}
422
+		$query_params = [
423
+			[
424
+				'EVT_ID' => $EVT_ID,
425
+				EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary_attendee) => true
426
+			]
427
+		];
428
+		if ($for_primary_attendee) {
429
+			$query_params[0]['EQG_primary'] = true;
430
+		} else {
431
+			$query_params[0]['EQG_additional'] = true;
432
+		}
433
+		return EE_Registry::instance()->load_model('Event_Question_Group')->get_all($query_params);
434
+	}
435
+
436
+
437
+	/**
438
+	 * get_question_groups
439
+	 *
440
+	 * @param int $EVT_ID
441
+	 * @param EE_Registration $registration
442
+	 * @return array|bool
443
+	 * @throws EE_Error
444
+	 * @throws InvalidArgumentException
445
+	 * @throws InvalidDataTypeException
446
+	 * @throws InvalidInterfaceException
447
+	 * @throws ReflectionException
448
+	 */
449
+	public function get_question_groups_for_event($EVT_ID = 0, EE_Registration $registration)
450
+	{
451
+		if (! isset($EVT_ID) || ! absint($EVT_ID)) {
452
+			EE_Error::add_error(
453
+				esc_html__(
454
+					'An error occurred. No Question Groups could be retrieved because an Event ID was not received.',
455
+					'event_espresso'
456
+				),
457
+				__FILE__,
458
+				__FUNCTION__,
459
+				__LINE__
460
+			);
461
+			return false;
462
+		}
463
+		return EE_Registry::instance()->load_model('Question_Group')->get_all(
464
+			[
465
+				[
466
+					'Event_Question_Group.EVT_ID'      => $EVT_ID,
467
+					'Event_Question_Group.'
468
+						. EEM_Event_Question_Group::instance()->fieldNameForContext(
469
+							$registration->is_primary_registrant()
470
+						) => true
471
+				],
472
+				'order_by' => ['QSG_order' => 'ASC'],
473
+			]
474
+		);
475
+	}
476
+
477
+
478
+
479
+	/**
480
+	 * get_question_target_db_column
481
+	 *
482
+	 * @param string $QSG_IDs csv list of $QSG IDs
483
+	 * @return array|bool
484
+	 * @throws \EE_Error
485
+	 */
486
+	public function get_questions_in_groups($QSG_IDs = '')
487
+	{
488
+		if (empty($QSG_IDs)) {
489
+			EE_Error::add_error(
490
+				esc_html__('An error occurred. No Question Group IDs were received.', 'event_espresso'),
491
+				__FILE__,
492
+				__FUNCTION__,
493
+				__LINE__
494
+			);
495
+			return false;
496
+		}
497
+		return EE_Registry::instance()->load_model('Question')->get_all(
498
+			array(
499
+				array(
500
+					'Question_Group.QSG_ID' => array('IN', $QSG_IDs),
501
+					'QST_deleted'           => false,
502
+					'QST_admin_only'        => is_admin(),
503
+				),
504
+				'order_by' => 'QST_order',
505
+			)
506
+		);
507
+	}
508
+
509
+
510
+
511
+	/**
512
+	 * get_options_for_question
513
+	 *
514
+	 * @param string $QST_IDs csv list of $QST IDs
515
+	 * @return array|bool
516
+	 * @throws \EE_Error
517
+	 */
518
+	public function get_options_for_question($QST_IDs)
519
+	{
520
+		if (empty($QST_IDs)) {
521
+			EE_Error::add_error(
522
+				esc_html__('An error occurred. No Question IDs were received.', 'event_espresso'),
523
+				__FILE__,
524
+				__FUNCTION__,
525
+				__LINE__
526
+			);
527
+			return false;
528
+		}
529
+		return EE_Registry::instance()->load_model('Question_Option')->get_all(
530
+			array(
531
+				array(
532
+					'Question.QST_ID' => array('IN', $QST_IDs),
533
+					'QSO_deleted'     => false,
534
+				),
535
+				'order_by' => 'QSO_ID',
536
+			)
537
+		);
538
+	}
539
+
540
+
541
+
542
+
543
+
544
+
545
+
546
+	/**
547
+	 * Gets all events that are published
548
+	 * and have event start time earlier than now and an event end time later than now
549
+	 *
550
+	 * @param  array $query_params An array of query params to further filter on
551
+	 *                             (note that status and DTT_EVT_start and DTT_EVT_end will be overridden)
552
+	 * @param bool   $count        whether to return the count or not (default FALSE)
553
+	 * @return EE_Event[]|int
554
+	 * @throws \EE_Error
555
+	 */
556
+	public function get_active_events($query_params, $count = false)
557
+	{
558
+		if (array_key_exists(0, $query_params)) {
559
+			$where_params = $query_params[0];
560
+			unset($query_params[0]);
561
+		} else {
562
+			$where_params = array();
563
+		}
564
+		// if we have count make sure we don't include group by
565
+		if ($count && isset($query_params['group_by'])) {
566
+			unset($query_params['group_by']);
567
+		}
568
+		// let's add specific query_params for active_events
569
+		// keep in mind this will override any sent status in the query AND any date queries.
570
+		$where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
571
+		// if already have where params for DTT_EVT_start or DTT_EVT_end then append these conditions
572
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
573
+			$where_params['Datetime.DTT_EVT_start******'] = array(
574
+				'<',
575
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
576
+			);
577
+		} else {
578
+			$where_params['Datetime.DTT_EVT_start'] = array(
579
+				'<',
580
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
581
+			);
582
+		}
583
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
584
+			$where_params['Datetime.DTT_EVT_end*****'] = array(
585
+				'>',
586
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
587
+			);
588
+		} else {
589
+			$where_params['Datetime.DTT_EVT_end'] = array(
590
+				'>',
591
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
592
+			);
593
+		}
594
+		$query_params[0] = $where_params;
595
+		// don't use $query_params with count()
596
+		// because we don't want to include additional query clauses like "GROUP BY"
597
+		return $count
598
+			? $this->count(array($where_params), 'EVT_ID', true)
599
+			: $this->get_all($query_params);
600
+	}
601
+
602
+
603
+
604
+	/**
605
+	 * get all events that are published and have an event start time later than now
606
+	 *
607
+	 * @param  array $query_params An array of query params to further filter on
608
+	 *                             (Note that status and DTT_EVT_start will be overridden)
609
+	 * @param bool   $count        whether to return the count or not (default FALSE)
610
+	 * @return EE_Event[]|int
611
+	 * @throws \EE_Error
612
+	 */
613
+	public function get_upcoming_events($query_params, $count = false)
614
+	{
615
+		if (array_key_exists(0, $query_params)) {
616
+			$where_params = $query_params[0];
617
+			unset($query_params[0]);
618
+		} else {
619
+			$where_params = array();
620
+		}
621
+		// if we have count make sure we don't include group by
622
+		if ($count && isset($query_params['group_by'])) {
623
+			unset($query_params['group_by']);
624
+		}
625
+		// let's add specific query_params for active_events
626
+		// keep in mind this will override any sent status in the query AND any date queries.
627
+		// we need to pull events with a status of publish and sold_out
628
+		$event_status = array('publish', EEM_Event::sold_out);
629
+		// check if the user can read private events and if so add the 'private status to the were params'
630
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_upcoming_events')) {
631
+			$event_status[] = 'private';
632
+		}
633
+		$where_params['status'] = array('IN', $event_status);
634
+		// if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
635
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
636
+			$where_params['Datetime.DTT_EVT_start*****'] = array(
637
+				'>',
638
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
639
+			);
640
+		} else {
641
+			$where_params['Datetime.DTT_EVT_start'] = array(
642
+				'>',
643
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
644
+			);
645
+		}
646
+		$query_params[0] = $where_params;
647
+		// don't use $query_params with count()
648
+		// because we don't want to include additional query clauses like "GROUP BY"
649
+		return $count
650
+			? $this->count(array($where_params), 'EVT_ID', true)
651
+			: $this->get_all($query_params);
652
+	}
653
+
654
+
655
+
656
+	/**
657
+	 * Gets all events that are published
658
+	 * and have an event end time later than now
659
+	 *
660
+	 * @param  array $query_params An array of query params to further filter on
661
+	 *                             (note that status and DTT_EVT_end will be overridden)
662
+	 * @param bool   $count        whether to return the count or not (default FALSE)
663
+	 * @return EE_Event[]|int
664
+	 * @throws \EE_Error
665
+	 */
666
+	public function get_active_and_upcoming_events($query_params, $count = false)
667
+	{
668
+		if (array_key_exists(0, $query_params)) {
669
+			$where_params = $query_params[0];
670
+			unset($query_params[0]);
671
+		} else {
672
+			$where_params = array();
673
+		}
674
+		// if we have count make sure we don't include group by
675
+		if ($count && isset($query_params['group_by'])) {
676
+			unset($query_params['group_by']);
677
+		}
678
+		// let's add specific query_params for active_events
679
+		// keep in mind this will override any sent status in the query AND any date queries.
680
+		$where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
681
+		// add where params for DTT_EVT_end
682
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
683
+			$where_params['Datetime.DTT_EVT_end*****'] = array(
684
+				'>',
685
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
686
+			);
687
+		} else {
688
+			$where_params['Datetime.DTT_EVT_end'] = array(
689
+				'>',
690
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
691
+			);
692
+		}
693
+		$query_params[0] = $where_params;
694
+		// don't use $query_params with count()
695
+		// because we don't want to include additional query clauses like "GROUP BY"
696
+		return $count
697
+			? $this->count(array($where_params), 'EVT_ID', true)
698
+			: $this->get_all($query_params);
699
+	}
700
+
701
+
702
+
703
+	/**
704
+	 * This only returns events that are expired.
705
+	 * They may still be published but all their datetimes have expired.
706
+	 *
707
+	 * @param  array $query_params An array of query params to further filter on
708
+	 *                             (note that status and DTT_EVT_end will be overridden)
709
+	 * @param bool   $count        whether to return the count or not (default FALSE)
710
+	 * @return EE_Event[]|int
711
+	 * @throws \EE_Error
712
+	 */
713
+	public function get_expired_events($query_params, $count = false)
714
+	{
715
+		$where_params = isset($query_params[0]) ? $query_params[0] : array();
716
+		// if we have count make sure we don't include group by
717
+		if ($count && isset($query_params['group_by'])) {
718
+			unset($query_params['group_by']);
719
+		}
720
+		// let's add specific query_params for active_events
721
+		// keep in mind this will override any sent status in the query AND any date queries.
722
+		if (isset($where_params['status'])) {
723
+			unset($where_params['status']);
724
+		}
725
+		$exclude_query = $query_params;
726
+		if (isset($exclude_query[0])) {
727
+			unset($exclude_query[0]);
728
+		}
729
+		$exclude_query[0] = array(
730
+			'Datetime.DTT_EVT_end' => array(
731
+				'>',
732
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
733
+			),
734
+		);
735
+		// first get all events that have datetimes where its not expired.
736
+		$event_ids = $this->_get_all_wpdb_results($exclude_query, OBJECT_K, 'Event_CPT.ID');
737
+		$event_ids = array_keys($event_ids);
738
+		// if we have any additional query_params, let's add them to the 'AND' condition
739
+		$and_condition = array(
740
+			'Datetime.DTT_EVT_end' => array('<', EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end')),
741
+			'EVT_ID'               => array('NOT IN', $event_ids),
742
+		);
743
+		if (isset($where_params['OR'])) {
744
+			$and_condition['OR'] = $where_params['OR'];
745
+			unset($where_params['OR']);
746
+		}
747
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
748
+			$and_condition['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
749
+			unset($where_params['Datetime.DTT_EVT_end']);
750
+		}
751
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
752
+			$and_condition['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
753
+			unset($where_params['Datetime.DTT_EVT_start']);
754
+		}
755
+		// merge remaining $where params with the and conditions.
756
+		$where_params['AND'] = array_merge($and_condition, $where_params);
757
+		$query_params[0] = $where_params;
758
+		// don't use $query_params with count()
759
+		// because we don't want to include additional query clauses like "GROUP BY"
760
+		return $count
761
+			? $this->count(array($where_params), 'EVT_ID', true)
762
+			: $this->get_all($query_params);
763
+	}
764
+
765
+
766
+
767
+	/**
768
+	 * This basically just returns the events that do not have the publish status.
769
+	 *
770
+	 * @param  array   $query_params An array of query params to further filter on
771
+	 *                               (note that status will be overwritten)
772
+	 * @param  boolean $count        whether to return the count or not (default FALSE)
773
+	 * @return EE_Event[]|int
774
+	 * @throws \EE_Error
775
+	 */
776
+	public function get_inactive_events($query_params, $count = false)
777
+	{
778
+		$where_params = isset($query_params[0]) ? $query_params[0] : array();
779
+		// let's add in specific query_params for inactive events.
780
+		if (isset($where_params['status'])) {
781
+			unset($where_params['status']);
782
+		}
783
+		// if we have count make sure we don't include group by
784
+		if ($count && isset($query_params['group_by'])) {
785
+			unset($query_params['group_by']);
786
+		}
787
+		// if we have any additional query_params, let's add them to the 'AND' condition
788
+		$where_params['AND']['status'] = array('!=', 'publish');
789
+		if (isset($where_params['OR'])) {
790
+			$where_params['AND']['OR'] = $where_params['OR'];
791
+			unset($where_params['OR']);
792
+		}
793
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
794
+			$where_params['AND']['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
795
+			unset($where_params['Datetime.DTT_EVT_end']);
796
+		}
797
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
798
+			$where_params['AND']['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
799
+			unset($where_params['Datetime.DTT_EVT_start']);
800
+		}
801
+		$query_params[0] = $where_params;
802
+		// don't use $query_params with count()
803
+		// because we don't want to include additional query clauses like "GROUP BY"
804
+		return $count
805
+			? $this->count(array($where_params), 'EVT_ID', true)
806
+			: $this->get_all($query_params);
807
+	}
808
+
809
+
810
+
811
+	/**
812
+	 * This is just injecting into the parent add_relationship_to so we do special handling on price relationships
813
+	 * because we don't want to override any existing global default prices but instead insert NEW prices that get
814
+	 * attached to the event. See parent for param descriptions
815
+	 *
816
+	 * @param        $id_or_obj
817
+	 * @param        $other_model_id_or_obj
818
+	 * @param string $relationName
819
+	 * @param array  $where_query
820
+	 * @return EE_Base_Class
821
+	 * @throws EE_Error
822
+	 */
823
+	public function add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query = array())
824
+	{
825
+		if ($relationName === 'Price') {
826
+			// let's get the PRC object for the given ID to make sure that we aren't dealing with a default
827
+			$prc_chk = $this->get_related_model_obj($relationName)->ensure_is_obj($other_model_id_or_obj);
828
+			// if EVT_ID = 0, then this is a default
829
+			if ((int) $prc_chk->get('EVT_ID') === 0) {
830
+				// let's set the prc_id as 0 so we force an insert on the add_relation_to carried out by relation
831
+				$prc_chk->set('PRC_ID', 0);
832
+			}
833
+			// run parent
834
+			return parent::add_relationship_to($id_or_obj, $prc_chk, $relationName, $where_query);
835
+		}
836
+		// otherwise carry on as normal
837
+		return parent::add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query);
838
+	}
839
+
840
+
841
+
842
+	/******************** DEPRECATED METHODS ********************/
843
+
844
+
845
+
846
+	/**
847
+	 * _get_question_target_db_column
848
+	 *
849
+	 * @deprecated as of 4.8.32.rc.001. Instead consider using
850
+	 *             EE_Registration_Custom_Questions_Form located in
851
+	 *             admin_pages/registrations/form_sections/EE_Registration_Custom_Questions_Form.form.php
852
+	 * @access     public
853
+	 * @param    EE_Registration $registration (so existing answers for registration are included)
854
+	 * @param    int             $EVT_ID       so all question groups are included for event (not just answers from
855
+	 *                                         registration).
856
+	 * @throws EE_Error
857
+	 * @return    array
858
+	 */
859
+	public function assemble_array_of_groups_questions_and_options(EE_Registration $registration, $EVT_ID = 0)
860
+	{
861
+		if (empty($EVT_ID)) {
862
+			throw new EE_Error(esc_html__(
863
+				'An error occurred. No EVT_ID is included.  Needed to know which question groups to retrieve.',
864
+				'event_espresso'
865
+			));
866
+		}
867
+		$questions = array();
868
+		// get all question groups for event
869
+		$qgs = $this->get_question_groups_for_event($EVT_ID, $registration);
870
+		if (! empty($qgs)) {
871
+			foreach ($qgs as $qg) {
872
+				$qsts = $qg->questions();
873
+				$questions[ $qg->ID() ] = $qg->model_field_array();
874
+				$questions[ $qg->ID() ]['QSG_questions'] = array();
875
+				foreach ($qsts as $qst) {
876
+					if ($qst->is_system_question()) {
877
+						continue;
878
+					}
879
+					$answer = EEM_Answer::instance()->get_one(array(
880
+						array(
881
+							'QST_ID' => $qst->ID(),
882
+							'REG_ID' => $registration->ID(),
883
+						),
884
+					));
885
+					$answer = $answer instanceof EE_Answer ? $answer : EEM_Answer::instance()->create_default_object();
886
+					$qst_name = $qstn_id = $qst->ID();
887
+					$ans_id = $answer->ID();
888
+					$qst_name = ! empty($ans_id) ? '[' . $qst_name . '][' . $ans_id . ']' : '[' . $qst_name . ']';
889
+					$input_name = '';
890
+					$input_id = sanitize_key($qst->display_text());
891
+					$input_class = '';
892
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ] = $qst->model_field_array();
893
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_name'] = 'qstn'
894
+																						   . $input_name
895
+																						   . $qst_name;
896
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_id'] = $input_id . '-' . $qstn_id;
897
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_class'] = $input_class;
898
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'] = array();
899
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['qst_obj'] = $qst;
900
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['ans_obj'] = $answer;
901
+					// leave responses as-is, don't convert stuff into html entities please!
902
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['htmlentities'] = false;
903
+					if ($qst->type() == 'RADIO_BTN' || $qst->type() == 'CHECKBOX' || $qst->type() == 'DROPDOWN') {
904
+						$QSOs = $qst->options(true, $answer->value());
905
+						if (is_array($QSOs)) {
906
+							foreach ($QSOs as $QSO_ID => $QSO) {
907
+								$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'][ $QSO_ID ] = $QSO->model_field_array();
908
+							}
909
+						}
910
+					}
911
+				}
912
+			}
913
+		}
914
+		return $questions;
915
+	}
916
+
917
+
918
+	/**
919
+	 * @param mixed $cols_n_values either an array of where each key is the name of a field, and the value is its value
920
+	 *                             or an stdClass where each property is the name of a column,
921
+	 * @return EE_Base_Class
922
+	 * @throws \EE_Error
923
+	 */
924
+	public function instantiate_class_from_array_or_object($cols_n_values)
925
+	{
926
+		$classInstance = parent::instantiate_class_from_array_or_object($cols_n_values);
927
+		if ($classInstance instanceof EE_Event) {
928
+			// events have their timezone defined in the DB, so use it immediately
929
+			$this->set_timezone($classInstance->get_timezone());
930
+		}
931
+		return $classInstance;
932
+	}
933
+
934
+
935
+	/**
936
+	 * Deletes the model objects that meet the query params. Note: this method is overridden
937
+	 * in EEM_Soft_Delete_Base so that soft-deleted model objects are instead only flagged
938
+	 * as archived, not actually deleted
939
+	 *
940
+	 * @param array   $query_params   @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
941
+	 * @param boolean $allow_blocking if TRUE, matched objects will only be deleted if there is no related model info
942
+	 *                                that blocks it (ie, there' sno other data that depends on this data); if false,
943
+	 *                                deletes regardless of other objects which may depend on it. Its generally
944
+	 *                                advisable to always leave this as TRUE, otherwise you could easily corrupt your
945
+	 *                                DB
946
+	 * @return int                    number of rows deleted
947
+	 * @throws EE_Error
948
+	 */
949
+	public function delete_permanently($query_params, $allow_blocking = true)
950
+	{
951
+		$deleted = parent::delete_permanently($query_params, $allow_blocking);
952
+		if ($deleted) {
953
+			// get list of events with no prices
954
+			$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', []);
955
+			$where = isset($query_params[0]) ? $query_params[0] : [];
956
+			$where_event = isset($where['EVT_ID']) ? $where['EVT_ID'] : ['', ''];
957
+			$where_event_ids = isset($where_event[1]) ? $where_event[1] : '';
958
+			$event_ids = is_string($where_event_ids)
959
+				? explode(',', $where_event_ids)
960
+				: (array) $where_event_ids;
961
+			array_walk($event_ids, 'trim');
962
+			$event_ids = array_filter($event_ids);
963
+			// remove events from list of events with no prices
964
+			$espresso_no_ticket_prices = array_diff($espresso_no_ticket_prices, $event_ids);
965
+			update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
966
+		}
967
+		return $deleted;
968
+	}
969 969
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Line_Item.model.php 2 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -324,8 +324,8 @@  discard block
 block discarded – undo
324 324
         );
325 325
         $query = $wpdb->prepare(
326 326
             'DELETE li
327
-				FROM ' . $this->table() . ' li
328
-				LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON li.TXN_ID = t.TXN_ID
327
+				FROM ' . $this->table().' li
328
+				LEFT JOIN ' . EEM_Transaction::instance()->table().' t ON li.TXN_ID = t.TXN_ID
329 329
 				WHERE t.TXN_ID IS NULL AND li.LIN_timestamp < %s',
330 330
             // use GMT time because that's what TXN_timestamps are in
331 331
             date('Y-m-d H:i:s', time() - $time_to_leave_alone)
@@ -598,7 +598,7 @@  discard block
 block discarded – undo
598 598
      */
599 599
     public function getTicketLineItemsForExpiredCarts($timestamp = 0)
600 600
     {
601
-        if (! absint($timestamp)) {
601
+        if ( ! absint($timestamp)) {
602 602
             /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
603 603
             $session_lifespan = LoaderFactory::getLoader()->getShared(
604 604
                 'EventEspresso\core\domain\values\session\SessionLifespan'
Please login to merge, or discard this patch.
Indentation   +595 added lines, -595 removed lines patch added patch discarded remove patch
@@ -28,602 +28,602 @@
 block discarded – undo
28 28
 class EEM_Line_Item extends EEM_Base
29 29
 {
30 30
 
31
-    /**
32
-     * Tax sub-total is just the total of all the taxes, which should be children
33
-     * of this line item. There should only ever be one tax sub-total, and it should
34
-     * be a direct child of. Its quantity and LIN_unit_price = 1.
35
-     */
36
-    const type_tax_sub_total = 'tax-sub-total';
37
-
38
-    /**
39
-     * Tax line items indicate a tax applied to all the taxable line items.
40
-     * Should not have any children line items. Its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal
41
-     * (eg 10% tax = 10, not 0.1). Its LIN_total = LIN_unit_price * pre-tax-total. Quantity = 1.
42
-     */
43
-    const type_tax = 'tax';
44
-
45
-    /**
46
-     * Indicating individual items purchased, or discounts or surcharges.
47
-     * The sum of all the regular line items  plus the tax items should equal the grand total.
48
-     * Possible children are sub-line-items and cancellations.
49
-     * For flat items, LIN_unit_price * LIN_quantity = LIN_total. Its LIN_total is the sum of all the children
50
-     * LIN_totals. Its LIN_percent = 0.
51
-     * For percent items, its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal (eg 10% = 10, not 0.1).
52
-     * Its LIN_total is LIN_percent / 100 * sum of lower-priority sibling line items. Quantity = 1.
53
-     */
54
-    const type_line_item = 'line-item';
55
-
56
-    /**
57
-     * Line item indicating all the factors that make a single line item.
58
-     * Sub-line items should have NO children line items.
59
-     * For flat sub-items, their quantity should match their parent item, their LIN_unit_price should be this sub-item's
60
-     * contribution towards the price of ONE of their parent items, and its LIN_total should be
61
-     *  = LIN_quantity * LIN_unit_price. Its LIN_percent = 0.
62
-     * For percent sub-items, the quantity should be 1, LIN_unit_price should be 0, and its LIN_total should
63
-     * = LIN_percent / 100 * sum of lower-priority sibling line items..
64
-     */
65
-    const type_sub_line_item = 'sub-item';
66
-
67
-    /**
68
-     * Line item indicating a sub-total (eg total for an event, or pre-tax subtotal).
69
-     * Direct children should be event subtotals.
70
-     * Should have quantity of 1, and a LIN_total and LIN_unit_price of the sum of all its sub-items' LIN_totals.
71
-     */
72
-    const type_sub_total = 'sub-total';
73
-
74
-    /**
75
-     * Line item for the grand total of an order.
76
-     * Its direct children should be tax subtotals and (pre-tax) subtotals,
77
-     * and possibly a regular line item indicating a transaction-wide discount/surcharge.
78
-     * Should have a quantity of 1, a LIN_total and LIN_unit_price of the entire order's amount.
79
-     */
80
-    const type_total = 'total';
81
-
82
-    /**
83
-     * When a line item is cancelled, a sub-line-item of type 'cancellation'
84
-     * should be created, indicating the quantity that were cancelled
85
-     * (because a line item could have a quantity of 1, and its cancellation item
86
-     * could be for 3, indicating that originally 4 were purchased, but 3 have been
87
-     * cancelled, and only one remains).
88
-     * When items are refunded, a cancellation line item should be made, which points
89
-     * to teh payment model object which actually refunded the payment.
90
-     * Cancellations should NOT have any children line items; the should NOT affect
91
-     * any calculations, and are only meant as a record that cancellations have occurred.
92
-     * Their LIN_percent should be 0.
93
-     */
94
-    const type_cancellation = 'cancellation';
95
-
96
-    // various line item object types
97
-    const OBJ_TYPE_EVENT = 'Event';
98
-
99
-    const OBJ_TYPE_PRICE = 'Price';
100
-
101
-    const OBJ_TYPE_PROMOTION = 'Promotion';
102
-
103
-    const OBJ_TYPE_TICKET = 'Ticket';
104
-
105
-    const OBJ_TYPE_TRANSACTION = 'Transaction';
106
-
107
-    /**
108
-     * @var EEM_Line_Item $_instance
109
-     */
110
-    protected static $_instance;
111
-
112
-
113
-    /**
114
-     * private constructor to prevent direct creation
115
-     *
116
-     * @Constructor
117
-     * @param string $timezone string representing the timezone we want to set for returned Date Time Strings
118
-     *                         (and any incoming timezone data that gets saved).
119
-     *                         Note this just sends the timezone info to the date time model field objects.
120
-     *                         Default is NULL
121
-     *                         (and will be assumed using the set timezone in the 'timezone_string' wp option)
122
-     * @throws EE_Error
123
-     * @throws InvalidArgumentException
124
-     */
125
-    protected function __construct($timezone)
126
-    {
127
-        $this->singular_item = esc_html__('Line Item', 'event_espresso');
128
-        $this->plural_item = esc_html__('Line Items', 'event_espresso');
129
-
130
-        $this->_tables = array(
131
-            'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID'),
132
-        );
133
-        $line_items_can_be_for = apply_filters(
134
-            'FHEE__EEM_Line_Item__line_items_can_be_for',
135
-            array('Ticket', 'Price', 'Event')
136
-        );
137
-        $this->_fields = array(
138
-            'Line_Item' => array(
139
-                'LIN_ID'         => new EE_Primary_Key_Int_Field(
140
-                    'LIN_ID',
141
-                    esc_html__('ID', 'event_espresso')
142
-                ),
143
-                'LIN_code'       => new EE_Slug_Field(
144
-                    'LIN_code',
145
-                    esc_html__('Code for index into Cart', 'event_espresso'),
146
-                    true
147
-                ),
148
-                'TXN_ID'         => new EE_Foreign_Key_Int_Field(
149
-                    'TXN_ID',
150
-                    esc_html__('Transaction ID', 'event_espresso'),
151
-                    true,
152
-                    null,
153
-                    'Transaction'
154
-                ),
155
-                'LIN_name'       => new EE_Full_HTML_Field(
156
-                    'LIN_name',
157
-                    esc_html__('Line Item Name', 'event_espresso'),
158
-                    false,
159
-                    ''
160
-                ),
161
-                'LIN_desc'       => new EE_Full_HTML_Field(
162
-                    'LIN_desc',
163
-                    esc_html__('Line Item Description', 'event_espresso'),
164
-                    true
165
-                ),
166
-                'LIN_unit_price' => new EE_Money_Field(
167
-                    'LIN_unit_price',
168
-                    esc_html__('Unit Price', 'event_espresso'),
169
-                    false,
170
-                    0
171
-                ),
172
-                'LIN_percent'    => new EE_Float_Field(
173
-                    'LIN_percent',
174
-                    esc_html__('Percent', 'event_espresso'),
175
-                    false,
176
-                    0
177
-                ),
178
-                'LIN_is_taxable' => new EE_Boolean_Field(
179
-                    'LIN_is_taxable',
180
-                    esc_html__('Taxable', 'event_espresso'),
181
-                    false,
182
-                    false
183
-                ),
184
-                'LIN_order'      => new EE_Integer_Field(
185
-                    'LIN_order',
186
-                    esc_html__('Order of Application towards total of parent', 'event_espresso'),
187
-                    false,
188
-                    1
189
-                ),
190
-                'LIN_total'      => new EE_Money_Field(
191
-                    'LIN_total',
192
-                    esc_html__('Total (unit price x quantity)', 'event_espresso'),
193
-                    false,
194
-                    0
195
-                ),
196
-                'LIN_quantity'   => new EE_Integer_Field(
197
-                    'LIN_quantity',
198
-                    esc_html__('Quantity', 'event_espresso'),
199
-                    true,
200
-                    1
201
-                ),
202
-                'LIN_parent'     => new EE_Integer_Field(
203
-                    'LIN_parent',
204
-                    esc_html__("Parent ID (this item goes towards that Line Item's total)", 'event_espresso'),
205
-                    true,
206
-                    null
207
-                ),
208
-                'LIN_type'       => new EE_Enum_Text_Field(
209
-                    'LIN_type',
210
-                    esc_html__('Type', 'event_espresso'),
211
-                    false,
212
-                    'line-item',
213
-                    array(
214
-                        self::type_line_item     => esc_html__('Line Item', 'event_espresso'),
215
-                        self::type_sub_line_item => esc_html__('Sub-Item', 'event_espresso'),
216
-                        self::type_sub_total     => esc_html__('Subtotal', 'event_espresso'),
217
-                        self::type_tax_sub_total => esc_html__('Tax Subtotal', 'event_espresso'),
218
-                        self::type_tax           => esc_html__('Tax', 'event_espresso'),
219
-                        self::type_total         => esc_html__('Total', 'event_espresso'),
220
-                        self::type_cancellation  => esc_html__('Cancellation', 'event_espresso'),
221
-                    )
222
-                ),
223
-                'OBJ_ID'         => new EE_Foreign_Key_Int_Field(
224
-                    'OBJ_ID',
225
-                    esc_html__('ID of Item purchased.', 'event_espresso'),
226
-                    true,
227
-                    null,
228
-                    $line_items_can_be_for
229
-                ),
230
-                'OBJ_type'       => new EE_Any_Foreign_Model_Name_Field(
231
-                    'OBJ_type',
232
-                    esc_html__('Model Name this Line Item is for', 'event_espresso'),
233
-                    true,
234
-                    null,
235
-                    $line_items_can_be_for
236
-                ),
237
-                'LIN_timestamp'  => new EE_Datetime_Field(
238
-                    'LIN_timestamp',
239
-                    esc_html__('When the line item was created', 'event_espresso'),
240
-                    false,
241
-                    EE_Datetime_Field::now,
242
-                    $timezone
243
-                ),
244
-            ),
245
-        );
246
-        $this->_model_relations = array(
247
-            'Transaction' => new EE_Belongs_To_Relation(),
248
-            'Ticket'      => new EE_Belongs_To_Any_Relation(),
249
-            'Price'       => new EE_Belongs_To_Any_Relation(),
250
-            'Event'       => new EE_Belongs_To_Any_Relation(),
251
-        );
252
-        $this->_model_chain_to_wp_user = 'Transaction.Registration.Event';
253
-        $this->_caps_slug = 'transactions';
254
-        parent::__construct($timezone);
255
-    }
256
-
257
-
258
-    /**
259
-     * Gets all the line items for this transaction of the given type
260
-     *
261
-     * @param string             $line_item_type like one of EEM_Line_Item::type_*
262
-     * @param EE_Transaction|int $transaction
263
-     * @return EE_Base_Class[]|EE_Line_Item[]
264
-     * @throws EE_Error
265
-     * @throws InvalidArgumentException
266
-     * @throws InvalidDataTypeException
267
-     * @throws InvalidInterfaceException
268
-     */
269
-    public function get_all_of_type_for_transaction($line_item_type, $transaction)
270
-    {
271
-        $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction);
272
-        return $this->get_all(array(
273
-            array(
274
-                'LIN_type' => $line_item_type,
275
-                'TXN_ID'   => $transaction,
276
-            ),
277
-        ));
278
-    }
279
-
280
-
281
-    /**
282
-     * Gets all line items unrelated to tickets that are normal line items
283
-     * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category)
284
-     *
285
-     * @param EE_Transaction|int $transaction
286
-     * @return EE_Base_Class[]|EE_Line_Item[]
287
-     * @throws EE_Error
288
-     * @throws InvalidArgumentException
289
-     * @throws InvalidDataTypeException
290
-     * @throws InvalidInterfaceException
291
-     */
292
-    public function get_all_non_ticket_line_items_for_transaction($transaction)
293
-    {
294
-        $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction);
295
-        return $this->get_all(array(
296
-            array(
297
-                'LIN_type' => self::type_line_item,
298
-                'TXN_ID'   => $transaction,
299
-                'OR'       => array(
300
-                    'OBJ_type*notticket' => array('!=', EEM_Line_Item::OBJ_TYPE_TICKET),
301
-                    'OBJ_type*null'      => array('IS_NULL'),
302
-                ),
303
-            ),
304
-        ));
305
-    }
306
-
307
-
308
-    /**
309
-     * Deletes line items with no transaction who have passed the transaction cutoff time.
310
-     * This needs to be very efficient
311
-     * because if there are spam bots afoot there will be LOTS of line items. Also MySQL doesn't allow a limit when
312
-     * deleting and joining tables like this.
313
-     *
314
-     * @return int count of how many deleted
315
-     * @throws EE_Error
316
-     * @throws InvalidArgumentException
317
-     * @throws InvalidDataTypeException
318
-     * @throws InvalidInterfaceException
319
-     */
320
-    public function delete_line_items_with_no_transaction()
321
-    {
322
-        /** @type WPDB $wpdb */
323
-        global $wpdb;
324
-        $time_to_leave_alone = apply_filters(
325
-            'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone',
326
-            WEEK_IN_SECONDS
327
-        );
328
-        $query = $wpdb->prepare(
329
-            'DELETE li
31
+	/**
32
+	 * Tax sub-total is just the total of all the taxes, which should be children
33
+	 * of this line item. There should only ever be one tax sub-total, and it should
34
+	 * be a direct child of. Its quantity and LIN_unit_price = 1.
35
+	 */
36
+	const type_tax_sub_total = 'tax-sub-total';
37
+
38
+	/**
39
+	 * Tax line items indicate a tax applied to all the taxable line items.
40
+	 * Should not have any children line items. Its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal
41
+	 * (eg 10% tax = 10, not 0.1). Its LIN_total = LIN_unit_price * pre-tax-total. Quantity = 1.
42
+	 */
43
+	const type_tax = 'tax';
44
+
45
+	/**
46
+	 * Indicating individual items purchased, or discounts or surcharges.
47
+	 * The sum of all the regular line items  plus the tax items should equal the grand total.
48
+	 * Possible children are sub-line-items and cancellations.
49
+	 * For flat items, LIN_unit_price * LIN_quantity = LIN_total. Its LIN_total is the sum of all the children
50
+	 * LIN_totals. Its LIN_percent = 0.
51
+	 * For percent items, its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal (eg 10% = 10, not 0.1).
52
+	 * Its LIN_total is LIN_percent / 100 * sum of lower-priority sibling line items. Quantity = 1.
53
+	 */
54
+	const type_line_item = 'line-item';
55
+
56
+	/**
57
+	 * Line item indicating all the factors that make a single line item.
58
+	 * Sub-line items should have NO children line items.
59
+	 * For flat sub-items, their quantity should match their parent item, their LIN_unit_price should be this sub-item's
60
+	 * contribution towards the price of ONE of their parent items, and its LIN_total should be
61
+	 *  = LIN_quantity * LIN_unit_price. Its LIN_percent = 0.
62
+	 * For percent sub-items, the quantity should be 1, LIN_unit_price should be 0, and its LIN_total should
63
+	 * = LIN_percent / 100 * sum of lower-priority sibling line items..
64
+	 */
65
+	const type_sub_line_item = 'sub-item';
66
+
67
+	/**
68
+	 * Line item indicating a sub-total (eg total for an event, or pre-tax subtotal).
69
+	 * Direct children should be event subtotals.
70
+	 * Should have quantity of 1, and a LIN_total and LIN_unit_price of the sum of all its sub-items' LIN_totals.
71
+	 */
72
+	const type_sub_total = 'sub-total';
73
+
74
+	/**
75
+	 * Line item for the grand total of an order.
76
+	 * Its direct children should be tax subtotals and (pre-tax) subtotals,
77
+	 * and possibly a regular line item indicating a transaction-wide discount/surcharge.
78
+	 * Should have a quantity of 1, a LIN_total and LIN_unit_price of the entire order's amount.
79
+	 */
80
+	const type_total = 'total';
81
+
82
+	/**
83
+	 * When a line item is cancelled, a sub-line-item of type 'cancellation'
84
+	 * should be created, indicating the quantity that were cancelled
85
+	 * (because a line item could have a quantity of 1, and its cancellation item
86
+	 * could be for 3, indicating that originally 4 were purchased, but 3 have been
87
+	 * cancelled, and only one remains).
88
+	 * When items are refunded, a cancellation line item should be made, which points
89
+	 * to teh payment model object which actually refunded the payment.
90
+	 * Cancellations should NOT have any children line items; the should NOT affect
91
+	 * any calculations, and are only meant as a record that cancellations have occurred.
92
+	 * Their LIN_percent should be 0.
93
+	 */
94
+	const type_cancellation = 'cancellation';
95
+
96
+	// various line item object types
97
+	const OBJ_TYPE_EVENT = 'Event';
98
+
99
+	const OBJ_TYPE_PRICE = 'Price';
100
+
101
+	const OBJ_TYPE_PROMOTION = 'Promotion';
102
+
103
+	const OBJ_TYPE_TICKET = 'Ticket';
104
+
105
+	const OBJ_TYPE_TRANSACTION = 'Transaction';
106
+
107
+	/**
108
+	 * @var EEM_Line_Item $_instance
109
+	 */
110
+	protected static $_instance;
111
+
112
+
113
+	/**
114
+	 * private constructor to prevent direct creation
115
+	 *
116
+	 * @Constructor
117
+	 * @param string $timezone string representing the timezone we want to set for returned Date Time Strings
118
+	 *                         (and any incoming timezone data that gets saved).
119
+	 *                         Note this just sends the timezone info to the date time model field objects.
120
+	 *                         Default is NULL
121
+	 *                         (and will be assumed using the set timezone in the 'timezone_string' wp option)
122
+	 * @throws EE_Error
123
+	 * @throws InvalidArgumentException
124
+	 */
125
+	protected function __construct($timezone)
126
+	{
127
+		$this->singular_item = esc_html__('Line Item', 'event_espresso');
128
+		$this->plural_item = esc_html__('Line Items', 'event_espresso');
129
+
130
+		$this->_tables = array(
131
+			'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID'),
132
+		);
133
+		$line_items_can_be_for = apply_filters(
134
+			'FHEE__EEM_Line_Item__line_items_can_be_for',
135
+			array('Ticket', 'Price', 'Event')
136
+		);
137
+		$this->_fields = array(
138
+			'Line_Item' => array(
139
+				'LIN_ID'         => new EE_Primary_Key_Int_Field(
140
+					'LIN_ID',
141
+					esc_html__('ID', 'event_espresso')
142
+				),
143
+				'LIN_code'       => new EE_Slug_Field(
144
+					'LIN_code',
145
+					esc_html__('Code for index into Cart', 'event_espresso'),
146
+					true
147
+				),
148
+				'TXN_ID'         => new EE_Foreign_Key_Int_Field(
149
+					'TXN_ID',
150
+					esc_html__('Transaction ID', 'event_espresso'),
151
+					true,
152
+					null,
153
+					'Transaction'
154
+				),
155
+				'LIN_name'       => new EE_Full_HTML_Field(
156
+					'LIN_name',
157
+					esc_html__('Line Item Name', 'event_espresso'),
158
+					false,
159
+					''
160
+				),
161
+				'LIN_desc'       => new EE_Full_HTML_Field(
162
+					'LIN_desc',
163
+					esc_html__('Line Item Description', 'event_espresso'),
164
+					true
165
+				),
166
+				'LIN_unit_price' => new EE_Money_Field(
167
+					'LIN_unit_price',
168
+					esc_html__('Unit Price', 'event_espresso'),
169
+					false,
170
+					0
171
+				),
172
+				'LIN_percent'    => new EE_Float_Field(
173
+					'LIN_percent',
174
+					esc_html__('Percent', 'event_espresso'),
175
+					false,
176
+					0
177
+				),
178
+				'LIN_is_taxable' => new EE_Boolean_Field(
179
+					'LIN_is_taxable',
180
+					esc_html__('Taxable', 'event_espresso'),
181
+					false,
182
+					false
183
+				),
184
+				'LIN_order'      => new EE_Integer_Field(
185
+					'LIN_order',
186
+					esc_html__('Order of Application towards total of parent', 'event_espresso'),
187
+					false,
188
+					1
189
+				),
190
+				'LIN_total'      => new EE_Money_Field(
191
+					'LIN_total',
192
+					esc_html__('Total (unit price x quantity)', 'event_espresso'),
193
+					false,
194
+					0
195
+				),
196
+				'LIN_quantity'   => new EE_Integer_Field(
197
+					'LIN_quantity',
198
+					esc_html__('Quantity', 'event_espresso'),
199
+					true,
200
+					1
201
+				),
202
+				'LIN_parent'     => new EE_Integer_Field(
203
+					'LIN_parent',
204
+					esc_html__("Parent ID (this item goes towards that Line Item's total)", 'event_espresso'),
205
+					true,
206
+					null
207
+				),
208
+				'LIN_type'       => new EE_Enum_Text_Field(
209
+					'LIN_type',
210
+					esc_html__('Type', 'event_espresso'),
211
+					false,
212
+					'line-item',
213
+					array(
214
+						self::type_line_item     => esc_html__('Line Item', 'event_espresso'),
215
+						self::type_sub_line_item => esc_html__('Sub-Item', 'event_espresso'),
216
+						self::type_sub_total     => esc_html__('Subtotal', 'event_espresso'),
217
+						self::type_tax_sub_total => esc_html__('Tax Subtotal', 'event_espresso'),
218
+						self::type_tax           => esc_html__('Tax', 'event_espresso'),
219
+						self::type_total         => esc_html__('Total', 'event_espresso'),
220
+						self::type_cancellation  => esc_html__('Cancellation', 'event_espresso'),
221
+					)
222
+				),
223
+				'OBJ_ID'         => new EE_Foreign_Key_Int_Field(
224
+					'OBJ_ID',
225
+					esc_html__('ID of Item purchased.', 'event_espresso'),
226
+					true,
227
+					null,
228
+					$line_items_can_be_for
229
+				),
230
+				'OBJ_type'       => new EE_Any_Foreign_Model_Name_Field(
231
+					'OBJ_type',
232
+					esc_html__('Model Name this Line Item is for', 'event_espresso'),
233
+					true,
234
+					null,
235
+					$line_items_can_be_for
236
+				),
237
+				'LIN_timestamp'  => new EE_Datetime_Field(
238
+					'LIN_timestamp',
239
+					esc_html__('When the line item was created', 'event_espresso'),
240
+					false,
241
+					EE_Datetime_Field::now,
242
+					$timezone
243
+				),
244
+			),
245
+		);
246
+		$this->_model_relations = array(
247
+			'Transaction' => new EE_Belongs_To_Relation(),
248
+			'Ticket'      => new EE_Belongs_To_Any_Relation(),
249
+			'Price'       => new EE_Belongs_To_Any_Relation(),
250
+			'Event'       => new EE_Belongs_To_Any_Relation(),
251
+		);
252
+		$this->_model_chain_to_wp_user = 'Transaction.Registration.Event';
253
+		$this->_caps_slug = 'transactions';
254
+		parent::__construct($timezone);
255
+	}
256
+
257
+
258
+	/**
259
+	 * Gets all the line items for this transaction of the given type
260
+	 *
261
+	 * @param string             $line_item_type like one of EEM_Line_Item::type_*
262
+	 * @param EE_Transaction|int $transaction
263
+	 * @return EE_Base_Class[]|EE_Line_Item[]
264
+	 * @throws EE_Error
265
+	 * @throws InvalidArgumentException
266
+	 * @throws InvalidDataTypeException
267
+	 * @throws InvalidInterfaceException
268
+	 */
269
+	public function get_all_of_type_for_transaction($line_item_type, $transaction)
270
+	{
271
+		$transaction = EEM_Transaction::instance()->ensure_is_ID($transaction);
272
+		return $this->get_all(array(
273
+			array(
274
+				'LIN_type' => $line_item_type,
275
+				'TXN_ID'   => $transaction,
276
+			),
277
+		));
278
+	}
279
+
280
+
281
+	/**
282
+	 * Gets all line items unrelated to tickets that are normal line items
283
+	 * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category)
284
+	 *
285
+	 * @param EE_Transaction|int $transaction
286
+	 * @return EE_Base_Class[]|EE_Line_Item[]
287
+	 * @throws EE_Error
288
+	 * @throws InvalidArgumentException
289
+	 * @throws InvalidDataTypeException
290
+	 * @throws InvalidInterfaceException
291
+	 */
292
+	public function get_all_non_ticket_line_items_for_transaction($transaction)
293
+	{
294
+		$transaction = EEM_Transaction::instance()->ensure_is_ID($transaction);
295
+		return $this->get_all(array(
296
+			array(
297
+				'LIN_type' => self::type_line_item,
298
+				'TXN_ID'   => $transaction,
299
+				'OR'       => array(
300
+					'OBJ_type*notticket' => array('!=', EEM_Line_Item::OBJ_TYPE_TICKET),
301
+					'OBJ_type*null'      => array('IS_NULL'),
302
+				),
303
+			),
304
+		));
305
+	}
306
+
307
+
308
+	/**
309
+	 * Deletes line items with no transaction who have passed the transaction cutoff time.
310
+	 * This needs to be very efficient
311
+	 * because if there are spam bots afoot there will be LOTS of line items. Also MySQL doesn't allow a limit when
312
+	 * deleting and joining tables like this.
313
+	 *
314
+	 * @return int count of how many deleted
315
+	 * @throws EE_Error
316
+	 * @throws InvalidArgumentException
317
+	 * @throws InvalidDataTypeException
318
+	 * @throws InvalidInterfaceException
319
+	 */
320
+	public function delete_line_items_with_no_transaction()
321
+	{
322
+		/** @type WPDB $wpdb */
323
+		global $wpdb;
324
+		$time_to_leave_alone = apply_filters(
325
+			'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone',
326
+			WEEK_IN_SECONDS
327
+		);
328
+		$query = $wpdb->prepare(
329
+			'DELETE li
330 330
 				FROM ' . $this->table() . ' li
331 331
 				LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON li.TXN_ID = t.TXN_ID
332 332
 				WHERE t.TXN_ID IS NULL AND li.LIN_timestamp < %s',
333
-            // use GMT time because that's what TXN_timestamps are in
334
-            date('Y-m-d H:i:s', time() - $time_to_leave_alone)
335
-        );
336
-        return $wpdb->query($query);
337
-    }
338
-
339
-
340
-    /**
341
-     * get_line_item_for_transaction_object
342
-     * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket
343
-     *
344
-     * @param int           $TXN_ID
345
-     * @param EE_Base_Class $object
346
-     * @return EE_Base_Class[]|EE_Line_Item[]
347
-     * @throws EE_Error
348
-     * @throws InvalidArgumentException
349
-     * @throws InvalidDataTypeException
350
-     * @throws InvalidInterfaceException
351
-     * @throws ReflectionException
352
-     */
353
-    public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object)
354
-    {
355
-        return $this->get_all(array(
356
-            array(
357
-                'TXN_ID'   => $TXN_ID,
358
-                'OBJ_type' => str_replace('EE_', '', get_class($object)),
359
-                'OBJ_ID'   => $object->ID(),
360
-            ),
361
-        ));
362
-    }
363
-
364
-
365
-    /**
366
-     * get_object_line_items_for_transaction
367
-     * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs
368
-     *
369
-     * @param int    $TXN_ID
370
-     * @param string $OBJ_type
371
-     * @param array  $OBJ_IDs
372
-     * @return EE_Base_Class[]|EE_Line_Item[]
373
-     * @throws EE_Error
374
-     */
375
-    public function get_object_line_items_for_transaction(
376
-        $TXN_ID,
377
-        $OBJ_type = EEM_Line_Item::OBJ_TYPE_EVENT,
378
-        $OBJ_IDs = array()
379
-    ) {
380
-        $query_params = array(
381
-            'OBJ_type' => $OBJ_type,
382
-            // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query
383
-            'OBJ_ID'   => is_array($OBJ_IDs) && ! isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs,
384
-        );
385
-        if ($TXN_ID) {
386
-            $query_params['TXN_ID'] = $TXN_ID;
387
-        }
388
-        return $this->get_all(array($query_params));
389
-    }
390
-
391
-
392
-    /**
393
-     * get_all_ticket_line_items_for_transaction
394
-     *
395
-     * @param EE_Transaction $transaction
396
-     * @return EE_Base_Class[]|EE_Line_Item[]
397
-     * @throws EE_Error
398
-     * @throws InvalidArgumentException
399
-     * @throws InvalidDataTypeException
400
-     * @throws InvalidInterfaceException
401
-     * @throws ReflectionException
402
-     */
403
-    public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction)
404
-    {
405
-        return $this->get_all(array(
406
-            array(
407
-                'TXN_ID'   => $transaction->ID(),
408
-                'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET,
409
-            ),
410
-        ));
411
-    }
412
-
413
-
414
-    /**
415
-     * get_ticket_line_item_for_transaction
416
-     *
417
-     * @param int $TXN_ID
418
-     * @param int $TKT_ID
419
-     * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL
420
-     * @throws EE_Error
421
-     * @throws InvalidArgumentException
422
-     * @throws InvalidDataTypeException
423
-     * @throws InvalidInterfaceException
424
-     */
425
-    public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID)
426
-    {
427
-        return $this->get_one(array(
428
-            array(
429
-                'TXN_ID'   => EEM_Transaction::instance()->ensure_is_ID($TXN_ID),
430
-                'OBJ_ID'   => $TKT_ID,
431
-                'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET,
432
-            ),
433
-        ));
434
-    }
435
-
436
-
437
-    /**
438
-     * get_existing_promotion_line_item
439
-     * searches the cart for existing line items for the specified promotion
440
-     *
441
-     * @since 1.0.0
442
-     * @param EE_Line_Item $parent_line_item
443
-     * @param EE_Promotion $promotion
444
-     * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL
445
-     * @throws EE_Error
446
-     * @throws InvalidArgumentException
447
-     * @throws InvalidDataTypeException
448
-     * @throws InvalidInterfaceException
449
-     * @throws ReflectionException
450
-     */
451
-    public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion)
452
-    {
453
-        return $this->get_one(array(
454
-            array(
455
-                'TXN_ID'     => $parent_line_item->TXN_ID(),
456
-                'LIN_parent' => $parent_line_item->ID(),
457
-                'OBJ_type'   => EEM_Line_Item::OBJ_TYPE_PROMOTION,
458
-                'OBJ_ID'     => $promotion->ID(),
459
-            ),
460
-        ));
461
-    }
462
-
463
-
464
-    /**
465
-     * get_all_promotion_line_items
466
-     * searches the cart for any and all existing promotion line items
467
-     *
468
-     * @since   1.0.0
469
-     * @param EE_Line_Item $parent_line_item
470
-     * @return EE_Base_Class[]|EE_Line_Item[]
471
-     * @throws EE_Error
472
-     * @throws InvalidArgumentException
473
-     * @throws InvalidDataTypeException
474
-     * @throws InvalidInterfaceException
475
-     * @throws ReflectionException
476
-     */
477
-    public function get_all_promotion_line_items(EE_Line_Item $parent_line_item)
478
-    {
479
-        return $this->get_all(array(
480
-            array(
481
-                'TXN_ID'     => $parent_line_item->TXN_ID(),
482
-                'LIN_parent' => $parent_line_item->ID(),
483
-                'OBJ_type'   => EEM_Line_Item::OBJ_TYPE_PROMOTION,
484
-            ),
485
-        ));
486
-    }
487
-
488
-
489
-    /**
490
-     * Gets the registration's corresponding line item.
491
-     * Note: basically does NOT support having multiple line items for a single ticket,
492
-     * which would happen if some of the registrations had a price modifier while others didn't.
493
-     * In order to support that, we'd probably need a LIN_ID on registrations or something.
494
-     *
495
-     * @param EE_Registration $registration
496
-     * @return EE_Base_Class|EE_Line_ITem|EE_Soft_Delete_Base_Class|NULL
497
-     * @throws EE_Error
498
-     */
499
-    public function get_line_item_for_registration(EE_Registration $registration)
500
-    {
501
-        return $this->get_one($this->line_item_for_registration_query_params($registration));
502
-    }
503
-
504
-
505
-    /**
506
-     * Gets the query params used to retrieve a specific line item for the given registration
507
-     *
508
-     * @param EE_Registration $registration
509
-     * @param array           $original_query_params any extra query params you'd like to be merged with
510
-     * @return array @see
511
-     *      https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
512
-     * @throws EE_Error
513
-     */
514
-    public function line_item_for_registration_query_params(
515
-        EE_Registration $registration,
516
-        $original_query_params = array()
517
-    ) {
518
-        return array_replace_recursive($original_query_params, array(
519
-            array(
520
-                'OBJ_ID'   => $registration->ticket_ID(),
521
-                'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET,
522
-                'TXN_ID'   => $registration->transaction_ID(),
523
-            ),
524
-        ));
525
-    }
526
-
527
-
528
-    /**
529
-     * @return EE_Base_Class[]|EE_Line_Item[]
530
-     * @throws InvalidInterfaceException
531
-     * @throws InvalidDataTypeException
532
-     * @throws EE_Error
533
-     * @throws InvalidArgumentException
534
-     */
535
-    public function get_total_line_items_with_no_transaction()
536
-    {
537
-        return $this->get_total_line_items_for_carts();
538
-    }
539
-
540
-
541
-    /**
542
-     * @return EE_Base_Class[]|EE_Line_Item[]
543
-     * @throws InvalidInterfaceException
544
-     * @throws InvalidDataTypeException
545
-     * @throws EE_Error
546
-     * @throws InvalidArgumentException
547
-     */
548
-    public function get_total_line_items_for_active_carts()
549
-    {
550
-        return $this->get_total_line_items_for_carts(false);
551
-    }
552
-
553
-
554
-    /**
555
-     * @return EE_Base_Class[]|EE_Line_Item[]
556
-     * @throws InvalidInterfaceException
557
-     * @throws InvalidDataTypeException
558
-     * @throws EE_Error
559
-     * @throws InvalidArgumentException
560
-     */
561
-    public function get_total_line_items_for_expired_carts()
562
-    {
563
-        return $this->get_total_line_items_for_carts(true);
564
-    }
565
-
566
-
567
-    /**
568
-     * Returns an array of grand total line items where the TXN_ID is 0.
569
-     * If $expired is set to true, then only line items for expired sessions will be returned.
570
-     * If $expired is set to false, then only line items for active sessions will be returned.
571
-     *
572
-     * @param null $expired
573
-     * @return EE_Base_Class[]|EE_Line_Item[]
574
-     * @throws EE_Error
575
-     * @throws InvalidArgumentException
576
-     * @throws InvalidDataTypeException
577
-     * @throws InvalidInterfaceException
578
-     */
579
-    private function get_total_line_items_for_carts($expired = null)
580
-    {
581
-        $where_params = array(
582
-            'TXN_ID'   => 0,
583
-            'LIN_type' => 'total',
584
-        );
585
-        if ($expired !== null) {
586
-            /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
587
-            $session_lifespan = LoaderFactory::getLoader()->getShared(
588
-                'EventEspresso\core\domain\values\session\SessionLifespan'
589
-            );
590
-            $where_params['LIN_timestamp'] = array(
591
-                $expired ? '<=' : '>',
592
-                $session_lifespan->expiration(),
593
-            );
594
-        }
595
-        return $this->get_all(array($where_params));
596
-    }
597
-
598
-
599
-    /**
600
-     * Returns an array of ticket total line items where the TXN_ID is 0
601
-     * AND the timestamp is older than the session lifespan.
602
-     *
603
-     * @param int $timestamp
604
-     * @return EE_Base_Class[]|EE_Line_Item[]
605
-     * @throws EE_Error
606
-     * @throws InvalidArgumentException
607
-     * @throws InvalidDataTypeException
608
-     * @throws InvalidInterfaceException
609
-     */
610
-    public function getTicketLineItemsForExpiredCarts($timestamp = 0)
611
-    {
612
-        if (! absint($timestamp)) {
613
-            /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
614
-            $session_lifespan = LoaderFactory::getLoader()->getShared(
615
-                'EventEspresso\core\domain\values\session\SessionLifespan'
616
-            );
617
-            $timestamp = $session_lifespan->expiration();
618
-        }
619
-        return $this->get_all(
620
-            array(
621
-                array(
622
-                    'TXN_ID'        => 0,
623
-                    'OBJ_type'      => EEM_Line_Item::OBJ_TYPE_TICKET,
624
-                    'LIN_timestamp' => array('<=', $timestamp),
625
-                ),
626
-            )
627
-        );
628
-    }
333
+			// use GMT time because that's what TXN_timestamps are in
334
+			date('Y-m-d H:i:s', time() - $time_to_leave_alone)
335
+		);
336
+		return $wpdb->query($query);
337
+	}
338
+
339
+
340
+	/**
341
+	 * get_line_item_for_transaction_object
342
+	 * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket
343
+	 *
344
+	 * @param int           $TXN_ID
345
+	 * @param EE_Base_Class $object
346
+	 * @return EE_Base_Class[]|EE_Line_Item[]
347
+	 * @throws EE_Error
348
+	 * @throws InvalidArgumentException
349
+	 * @throws InvalidDataTypeException
350
+	 * @throws InvalidInterfaceException
351
+	 * @throws ReflectionException
352
+	 */
353
+	public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object)
354
+	{
355
+		return $this->get_all(array(
356
+			array(
357
+				'TXN_ID'   => $TXN_ID,
358
+				'OBJ_type' => str_replace('EE_', '', get_class($object)),
359
+				'OBJ_ID'   => $object->ID(),
360
+			),
361
+		));
362
+	}
363
+
364
+
365
+	/**
366
+	 * get_object_line_items_for_transaction
367
+	 * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs
368
+	 *
369
+	 * @param int    $TXN_ID
370
+	 * @param string $OBJ_type
371
+	 * @param array  $OBJ_IDs
372
+	 * @return EE_Base_Class[]|EE_Line_Item[]
373
+	 * @throws EE_Error
374
+	 */
375
+	public function get_object_line_items_for_transaction(
376
+		$TXN_ID,
377
+		$OBJ_type = EEM_Line_Item::OBJ_TYPE_EVENT,
378
+		$OBJ_IDs = array()
379
+	) {
380
+		$query_params = array(
381
+			'OBJ_type' => $OBJ_type,
382
+			// if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query
383
+			'OBJ_ID'   => is_array($OBJ_IDs) && ! isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs,
384
+		);
385
+		if ($TXN_ID) {
386
+			$query_params['TXN_ID'] = $TXN_ID;
387
+		}
388
+		return $this->get_all(array($query_params));
389
+	}
390
+
391
+
392
+	/**
393
+	 * get_all_ticket_line_items_for_transaction
394
+	 *
395
+	 * @param EE_Transaction $transaction
396
+	 * @return EE_Base_Class[]|EE_Line_Item[]
397
+	 * @throws EE_Error
398
+	 * @throws InvalidArgumentException
399
+	 * @throws InvalidDataTypeException
400
+	 * @throws InvalidInterfaceException
401
+	 * @throws ReflectionException
402
+	 */
403
+	public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction)
404
+	{
405
+		return $this->get_all(array(
406
+			array(
407
+				'TXN_ID'   => $transaction->ID(),
408
+				'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET,
409
+			),
410
+		));
411
+	}
412
+
413
+
414
+	/**
415
+	 * get_ticket_line_item_for_transaction
416
+	 *
417
+	 * @param int $TXN_ID
418
+	 * @param int $TKT_ID
419
+	 * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL
420
+	 * @throws EE_Error
421
+	 * @throws InvalidArgumentException
422
+	 * @throws InvalidDataTypeException
423
+	 * @throws InvalidInterfaceException
424
+	 */
425
+	public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID)
426
+	{
427
+		return $this->get_one(array(
428
+			array(
429
+				'TXN_ID'   => EEM_Transaction::instance()->ensure_is_ID($TXN_ID),
430
+				'OBJ_ID'   => $TKT_ID,
431
+				'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET,
432
+			),
433
+		));
434
+	}
435
+
436
+
437
+	/**
438
+	 * get_existing_promotion_line_item
439
+	 * searches the cart for existing line items for the specified promotion
440
+	 *
441
+	 * @since 1.0.0
442
+	 * @param EE_Line_Item $parent_line_item
443
+	 * @param EE_Promotion $promotion
444
+	 * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL
445
+	 * @throws EE_Error
446
+	 * @throws InvalidArgumentException
447
+	 * @throws InvalidDataTypeException
448
+	 * @throws InvalidInterfaceException
449
+	 * @throws ReflectionException
450
+	 */
451
+	public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion)
452
+	{
453
+		return $this->get_one(array(
454
+			array(
455
+				'TXN_ID'     => $parent_line_item->TXN_ID(),
456
+				'LIN_parent' => $parent_line_item->ID(),
457
+				'OBJ_type'   => EEM_Line_Item::OBJ_TYPE_PROMOTION,
458
+				'OBJ_ID'     => $promotion->ID(),
459
+			),
460
+		));
461
+	}
462
+
463
+
464
+	/**
465
+	 * get_all_promotion_line_items
466
+	 * searches the cart for any and all existing promotion line items
467
+	 *
468
+	 * @since   1.0.0
469
+	 * @param EE_Line_Item $parent_line_item
470
+	 * @return EE_Base_Class[]|EE_Line_Item[]
471
+	 * @throws EE_Error
472
+	 * @throws InvalidArgumentException
473
+	 * @throws InvalidDataTypeException
474
+	 * @throws InvalidInterfaceException
475
+	 * @throws ReflectionException
476
+	 */
477
+	public function get_all_promotion_line_items(EE_Line_Item $parent_line_item)
478
+	{
479
+		return $this->get_all(array(
480
+			array(
481
+				'TXN_ID'     => $parent_line_item->TXN_ID(),
482
+				'LIN_parent' => $parent_line_item->ID(),
483
+				'OBJ_type'   => EEM_Line_Item::OBJ_TYPE_PROMOTION,
484
+			),
485
+		));
486
+	}
487
+
488
+
489
+	/**
490
+	 * Gets the registration's corresponding line item.
491
+	 * Note: basically does NOT support having multiple line items for a single ticket,
492
+	 * which would happen if some of the registrations had a price modifier while others didn't.
493
+	 * In order to support that, we'd probably need a LIN_ID on registrations or something.
494
+	 *
495
+	 * @param EE_Registration $registration
496
+	 * @return EE_Base_Class|EE_Line_ITem|EE_Soft_Delete_Base_Class|NULL
497
+	 * @throws EE_Error
498
+	 */
499
+	public function get_line_item_for_registration(EE_Registration $registration)
500
+	{
501
+		return $this->get_one($this->line_item_for_registration_query_params($registration));
502
+	}
503
+
504
+
505
+	/**
506
+	 * Gets the query params used to retrieve a specific line item for the given registration
507
+	 *
508
+	 * @param EE_Registration $registration
509
+	 * @param array           $original_query_params any extra query params you'd like to be merged with
510
+	 * @return array @see
511
+	 *      https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
512
+	 * @throws EE_Error
513
+	 */
514
+	public function line_item_for_registration_query_params(
515
+		EE_Registration $registration,
516
+		$original_query_params = array()
517
+	) {
518
+		return array_replace_recursive($original_query_params, array(
519
+			array(
520
+				'OBJ_ID'   => $registration->ticket_ID(),
521
+				'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET,
522
+				'TXN_ID'   => $registration->transaction_ID(),
523
+			),
524
+		));
525
+	}
526
+
527
+
528
+	/**
529
+	 * @return EE_Base_Class[]|EE_Line_Item[]
530
+	 * @throws InvalidInterfaceException
531
+	 * @throws InvalidDataTypeException
532
+	 * @throws EE_Error
533
+	 * @throws InvalidArgumentException
534
+	 */
535
+	public function get_total_line_items_with_no_transaction()
536
+	{
537
+		return $this->get_total_line_items_for_carts();
538
+	}
539
+
540
+
541
+	/**
542
+	 * @return EE_Base_Class[]|EE_Line_Item[]
543
+	 * @throws InvalidInterfaceException
544
+	 * @throws InvalidDataTypeException
545
+	 * @throws EE_Error
546
+	 * @throws InvalidArgumentException
547
+	 */
548
+	public function get_total_line_items_for_active_carts()
549
+	{
550
+		return $this->get_total_line_items_for_carts(false);
551
+	}
552
+
553
+
554
+	/**
555
+	 * @return EE_Base_Class[]|EE_Line_Item[]
556
+	 * @throws InvalidInterfaceException
557
+	 * @throws InvalidDataTypeException
558
+	 * @throws EE_Error
559
+	 * @throws InvalidArgumentException
560
+	 */
561
+	public function get_total_line_items_for_expired_carts()
562
+	{
563
+		return $this->get_total_line_items_for_carts(true);
564
+	}
565
+
566
+
567
+	/**
568
+	 * Returns an array of grand total line items where the TXN_ID is 0.
569
+	 * If $expired is set to true, then only line items for expired sessions will be returned.
570
+	 * If $expired is set to false, then only line items for active sessions will be returned.
571
+	 *
572
+	 * @param null $expired
573
+	 * @return EE_Base_Class[]|EE_Line_Item[]
574
+	 * @throws EE_Error
575
+	 * @throws InvalidArgumentException
576
+	 * @throws InvalidDataTypeException
577
+	 * @throws InvalidInterfaceException
578
+	 */
579
+	private function get_total_line_items_for_carts($expired = null)
580
+	{
581
+		$where_params = array(
582
+			'TXN_ID'   => 0,
583
+			'LIN_type' => 'total',
584
+		);
585
+		if ($expired !== null) {
586
+			/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
587
+			$session_lifespan = LoaderFactory::getLoader()->getShared(
588
+				'EventEspresso\core\domain\values\session\SessionLifespan'
589
+			);
590
+			$where_params['LIN_timestamp'] = array(
591
+				$expired ? '<=' : '>',
592
+				$session_lifespan->expiration(),
593
+			);
594
+		}
595
+		return $this->get_all(array($where_params));
596
+	}
597
+
598
+
599
+	/**
600
+	 * Returns an array of ticket total line items where the TXN_ID is 0
601
+	 * AND the timestamp is older than the session lifespan.
602
+	 *
603
+	 * @param int $timestamp
604
+	 * @return EE_Base_Class[]|EE_Line_Item[]
605
+	 * @throws EE_Error
606
+	 * @throws InvalidArgumentException
607
+	 * @throws InvalidDataTypeException
608
+	 * @throws InvalidInterfaceException
609
+	 */
610
+	public function getTicketLineItemsForExpiredCarts($timestamp = 0)
611
+	{
612
+		if (! absint($timestamp)) {
613
+			/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
614
+			$session_lifespan = LoaderFactory::getLoader()->getShared(
615
+				'EventEspresso\core\domain\values\session\SessionLifespan'
616
+			);
617
+			$timestamp = $session_lifespan->expiration();
618
+		}
619
+		return $this->get_all(
620
+			array(
621
+				array(
622
+					'TXN_ID'        => 0,
623
+					'OBJ_type'      => EEM_Line_Item::OBJ_TYPE_TICKET,
624
+					'LIN_timestamp' => array('<=', $timestamp),
625
+				),
626
+			)
627
+		);
628
+	}
629 629
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Transaction.class.php 2 patches
Spacing   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -53,7 +53,7 @@  discard block
 block discarded – undo
53 53
         $txn = $has_object
54 54
             ? $has_object
55 55
             : new self($props_n_values, false, $timezone, $date_formats);
56
-        if (! $has_object) {
56
+        if ( ! $has_object) {
57 57
             $txn->set_old_txn_status($txn->status_ID());
58 58
         }
59 59
         return $txn;
@@ -93,7 +93,7 @@  discard block
 block discarded – undo
93 93
     public function lock()
94 94
     {
95 95
         // attempt to set lock, but if that fails...
96
-        if (! $this->add_extra_meta('lock', time(), true)) {
96
+        if ( ! $this->add_extra_meta('lock', time(), true)) {
97 97
             // then attempt to remove the lock in case it is expired
98 98
             if ($this->_remove_expired_lock()) {
99 99
                 // if removal was successful, then try setting lock again
@@ -149,7 +149,7 @@  discard block
 block discarded – undo
149 149
     public function is_locked()
150 150
     {
151 151
         // if TXN is not locked, then return false immediately
152
-        if (! $this->_get_lock()) {
152
+        if ( ! $this->_get_lock()) {
153 153
             return false;
154 154
         }
155 155
         // if not, then let's try and remove the lock in case it's expired...
@@ -647,7 +647,7 @@  discard block
 block discarded – undo
647 647
                 $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
648 648
                 break;
649 649
         }
650
-        return $icon . $status[ $this->status_ID() ];
650
+        return $icon.$status[$this->status_ID()];
651 651
     }
652 652
 
653 653
 
@@ -785,7 +785,7 @@  discard block
 block discarded – undo
785 785
     public function invoice_url($type = 'html')
786 786
     {
787 787
         $REG = $this->primary_registration();
788
-        if (! $REG instanceof EE_Registration) {
788
+        if ( ! $REG instanceof EE_Registration) {
789 789
             return '';
790 790
         }
791 791
         return $REG->invoice_url($type);
@@ -836,7 +836,7 @@  discard block
 block discarded – undo
836 836
     public function receipt_url($type = 'html')
837 837
     {
838 838
         $REG = $this->primary_registration();
839
-        if (! $REG instanceof EE_Registration) {
839
+        if ( ! $REG instanceof EE_Registration) {
840 840
             return '';
841 841
         }
842 842
         return $REG->receipt_url($type);
@@ -1025,7 +1025,7 @@  discard block
 block discarded – undo
1025 1025
     public function total_line_item($create_if_not_found = true)
1026 1026
     {
1027 1027
         $item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
1028
-        if (! $item && $create_if_not_found) {
1028
+        if ( ! $item && $create_if_not_found) {
1029 1029
             $item = EEH_Line_Item::create_total_line_item($this);
1030 1030
         }
1031 1031
         return $item;
@@ -1082,7 +1082,7 @@  discard block
 block discarded – undo
1082 1082
     public function billing_info()
1083 1083
     {
1084 1084
         $payment_method = $this->payment_method();
1085
-        if (! $payment_method) {
1085
+        if ( ! $payment_method) {
1086 1086
             EE_Error::add_error(
1087 1087
                 esc_html__(
1088 1088
                     'Could not find billing info for transaction because no gateway has been used for it yet',
@@ -1095,7 +1095,7 @@  discard block
 block discarded – undo
1095 1095
             return null;
1096 1096
         }
1097 1097
         $primary_reg = $this->primary_registration();
1098
-        if (! $primary_reg) {
1098
+        if ( ! $primary_reg) {
1099 1099
             EE_Error::add_error(
1100 1100
                 esc_html__(
1101 1101
                     'Cannot get billing info for gateway %s on transaction because no primary registration exists',
@@ -1108,7 +1108,7 @@  discard block
 block discarded – undo
1108 1108
             return null;
1109 1109
         }
1110 1110
         $attendee = $primary_reg->attendee();
1111
-        if (! $attendee) {
1111
+        if ( ! $attendee) {
1112 1112
             EE_Error::add_error(
1113 1113
                 esc_html__(
1114 1114
                     'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
@@ -1265,7 +1265,7 @@  discard block
 block discarded – undo
1265 1265
     public function update_based_on_payments()
1266 1266
     {
1267 1267
         EE_Error::doing_it_wrong(
1268
-            __CLASS__ . '::' . __FUNCTION__,
1268
+            __CLASS__.'::'.__FUNCTION__,
1269 1269
             sprintf(
1270 1270
                 esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1271 1271
                 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
@@ -1333,13 +1333,13 @@  discard block
 block discarded – undo
1333 1333
     private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1334 1334
     {
1335 1335
         $reg_steps = $this->reg_steps();
1336
-        if (! is_array($reg_steps) || empty($reg_steps)) {
1336
+        if ( ! is_array($reg_steps) || empty($reg_steps)) {
1337 1337
             return false;
1338 1338
         }
1339 1339
         // loop thru reg steps array)
1340 1340
         foreach ($reg_steps as $slug => $reg_step_completed) {
1341 1341
             // if NOT checking ALL steps (only checking one step)
1342
-            if (! $check_all) {
1342
+            if ( ! $check_all) {
1343 1343
                 // and this is the one
1344 1344
                 if ($slug === $reg_step_slug) {
1345 1345
                     return $reg_step_completed;
@@ -1542,30 +1542,30 @@  discard block
 block discarded – undo
1542 1542
         // get reg steps array
1543 1543
         $txn_reg_steps = $this->reg_steps();
1544 1544
         // if reg step does NOT exist
1545
-        if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1545
+        if ( ! isset($txn_reg_steps[$reg_step_slug])) {
1546 1546
             return false;
1547 1547
         }
1548 1548
         // if  we're trying to complete a step that is already completed
1549
-        if ($txn_reg_steps[ $reg_step_slug ] === true) {
1549
+        if ($txn_reg_steps[$reg_step_slug] === true) {
1550 1550
             return true;
1551 1551
         }
1552 1552
         // if  we're trying to complete a step that hasn't even started
1553
-        if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1553
+        if ($status === true && $txn_reg_steps[$reg_step_slug] === false) {
1554 1554
             return false;
1555 1555
         }
1556 1556
         // if current status value matches the incoming value (no change)
1557 1557
         // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1558
-        if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1558
+        if ((int) $txn_reg_steps[$reg_step_slug] === (int) $status) {
1559 1559
             // this will happen in cases where multiple AJAX requests occur during the same step
1560 1560
             return true;
1561 1561
         }
1562 1562
         // if we're trying to set a start time, but it has already been set...
1563
-        if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1563
+        if (is_numeric($status) && is_numeric($txn_reg_steps[$reg_step_slug])) {
1564 1564
             // skip the update below, but don't return FALSE so that errors won't be displayed
1565 1565
             return true;
1566 1566
         }
1567 1567
         // update completed status
1568
-        $txn_reg_steps[ $reg_step_slug ] = $status;
1568
+        $txn_reg_steps[$reg_step_slug] = $status;
1569 1569
         $this->set_reg_steps($txn_reg_steps);
1570 1570
         $this->save();
1571 1571
         return true;
@@ -1589,7 +1589,7 @@  discard block
 block discarded – undo
1589 1589
     {
1590 1590
         // get reg steps array
1591 1591
         $txn_reg_steps = $this->reg_steps();
1592
-        unset($txn_reg_steps[ $reg_step_slug ]);
1592
+        unset($txn_reg_steps[$reg_step_slug]);
1593 1593
         $this->set_reg_steps($txn_reg_steps);
1594 1594
     }
1595 1595
 
@@ -1671,12 +1671,12 @@  discard block
 block discarded – undo
1671 1671
             return;
1672 1672
         }
1673 1673
         $payments = $this->get_many_related('Payment');
1674
-        if (! empty($payments)) {
1674
+        if ( ! empty($payments)) {
1675 1675
             foreach ($payments as $payment) {
1676 1676
                 if ($payment instanceof EE_Payment) {
1677 1677
                     // kk this TXN should NOT be abandoned
1678 1678
                     $this->update_status_based_on_total_paid();
1679
-                    if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1679
+                    if ( ! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1680 1680
                         EE_Error::add_attention(
1681 1681
                             sprintf(
1682 1682
                                 esc_html__(
Please login to merge, or discard this patch.
Indentation   +1701 added lines, -1701 removed lines patch added patch discarded remove patch
@@ -14,1705 +14,1705 @@
 block discarded – undo
14 14
 class EE_Transaction extends EE_Base_Class implements EEI_Transaction
15 15
 {
16 16
 
17
-    /**
18
-     * The length of time in seconds that a lock is applied before being considered expired.
19
-     * It is not long because a transaction should only be locked for the duration of the request that locked it
20
-     */
21
-    const LOCK_EXPIRATION = 2;
22
-
23
-    /**
24
-     * txn status upon initial construction.
25
-     *
26
-     * @var string
27
-     */
28
-    protected $_old_txn_status;
29
-
30
-
31
-    /**
32
-     * @param array  $props_n_values          incoming values
33
-     * @param string $timezone                incoming timezone
34
-     *                                        (if not set the timezone set for the website will be used.)
35
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
36
-     *                                        date_format and the second value is the time format
37
-     * @return EE_Transaction
38
-     * @throws EE_Error
39
-     * @throws InvalidArgumentException
40
-     * @throws InvalidDataTypeException
41
-     * @throws InvalidInterfaceException
42
-     * @throws ReflectionException
43
-     */
44
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
45
-    {
46
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
47
-        $txn = $has_object
48
-            ? $has_object
49
-            : new self($props_n_values, false, $timezone, $date_formats);
50
-        if (! $has_object) {
51
-            $txn->set_old_txn_status($txn->status_ID());
52
-        }
53
-        return $txn;
54
-    }
55
-
56
-
57
-    /**
58
-     * @param array  $props_n_values  incoming values from the database
59
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
60
-     *                                the website will be used.
61
-     * @return EE_Transaction
62
-     * @throws EE_Error
63
-     * @throws InvalidArgumentException
64
-     * @throws InvalidDataTypeException
65
-     * @throws InvalidInterfaceException
66
-     * @throws ReflectionException
67
-     */
68
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
69
-    {
70
-        $txn = new self($props_n_values, true, $timezone);
71
-        $txn->set_old_txn_status($txn->status_ID());
72
-        return $txn;
73
-    }
74
-
75
-
76
-    /**
77
-     * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
78
-     * If a lock has already been set, then we will attempt to remove it in case it has expired.
79
-     * If that also fails, then an exception is thrown.
80
-     *
81
-     * @throws EE_Error
82
-     * @throws InvalidArgumentException
83
-     * @throws InvalidDataTypeException
84
-     * @throws InvalidInterfaceException
85
-     * @throws ReflectionException
86
-     */
87
-    public function lock()
88
-    {
89
-        // attempt to set lock, but if that fails...
90
-        if (! $this->add_extra_meta('lock', time(), true)) {
91
-            // then attempt to remove the lock in case it is expired
92
-            if ($this->_remove_expired_lock()) {
93
-                // if removal was successful, then try setting lock again
94
-                $this->lock();
95
-            } else {
96
-                // but if the lock can not be removed, then throw an exception
97
-                throw new EE_Error(
98
-                    sprintf(
99
-                        esc_html__(
100
-                            '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.',
101
-                            'event_espresso'
102
-                        ),
103
-                        $this->ID()
104
-                    )
105
-                );
106
-            }
107
-        }
108
-    }
109
-
110
-
111
-    /**
112
-     * removes transaction lock applied in EE_Transaction::lock()
113
-     *
114
-     * @return int
115
-     * @throws EE_Error
116
-     * @throws InvalidArgumentException
117
-     * @throws InvalidDataTypeException
118
-     * @throws InvalidInterfaceException
119
-     * @throws ReflectionException
120
-     */
121
-    public function unlock()
122
-    {
123
-        return $this->delete_extra_meta('lock');
124
-    }
125
-
126
-
127
-    /**
128
-     * Decides whether or not now is the right time to update the transaction.
129
-     * This is useful because we don't always know if it is safe to update the transaction
130
-     * and its related data. why?
131
-     * because it's possible that the transaction is being used in another
132
-     * request and could overwrite anything we save.
133
-     * So we want to only update the txn once we know that won't happen.
134
-     * We also check that the lock isn't expired, and remove it if it is
135
-     *
136
-     * @return boolean
137
-     * @throws EE_Error
138
-     * @throws InvalidArgumentException
139
-     * @throws InvalidDataTypeException
140
-     * @throws InvalidInterfaceException
141
-     * @throws ReflectionException
142
-     */
143
-    public function is_locked()
144
-    {
145
-        // if TXN is not locked, then return false immediately
146
-        if (! $this->_get_lock()) {
147
-            return false;
148
-        }
149
-        // if not, then let's try and remove the lock in case it's expired...
150
-        // _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
151
-        // and a positive number if the lock was removed (ie: number of locks deleted),
152
-        // so we need to return the opposite
153
-        return ! $this->_remove_expired_lock() ? true : false;
154
-    }
155
-
156
-
157
-    /**
158
-     * Gets the meta field indicating that this TXN is locked
159
-     *
160
-     * @return int
161
-     * @throws EE_Error
162
-     * @throws InvalidArgumentException
163
-     * @throws InvalidDataTypeException
164
-     * @throws InvalidInterfaceException
165
-     * @throws ReflectionException
166
-     */
167
-    protected function _get_lock()
168
-    {
169
-        return (int) $this->get_extra_meta('lock', true, 0);
170
-    }
171
-
172
-
173
-    /**
174
-     * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
175
-     *
176
-     * @return int
177
-     * @throws EE_Error
178
-     * @throws InvalidArgumentException
179
-     * @throws InvalidDataTypeException
180
-     * @throws InvalidInterfaceException
181
-     * @throws ReflectionException
182
-     */
183
-    protected function _remove_expired_lock()
184
-    {
185
-        $locked = $this->_get_lock();
186
-        if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
187
-            return $this->unlock();
188
-        }
189
-        return 0;
190
-    }
191
-
192
-
193
-    /**
194
-     * Set transaction total
195
-     *
196
-     * @param float $total total value of transaction
197
-     * @throws EE_Error
198
-     * @throws InvalidArgumentException
199
-     * @throws InvalidDataTypeException
200
-     * @throws InvalidInterfaceException
201
-     * @throws ReflectionException
202
-     */
203
-    public function set_total($total = 0.00)
204
-    {
205
-        $this->set('TXN_total', (float) $total);
206
-    }
207
-
208
-
209
-    /**
210
-     * Set Total Amount Paid to Date
211
-     *
212
-     * @param float $total_paid total amount paid to date (sum of all payments)
213
-     * @throws EE_Error
214
-     * @throws InvalidArgumentException
215
-     * @throws InvalidDataTypeException
216
-     * @throws InvalidInterfaceException
217
-     * @throws ReflectionException
218
-     */
219
-    public function set_paid($total_paid = 0.00)
220
-    {
221
-        $this->set('TXN_paid', (float) $total_paid);
222
-    }
223
-
224
-
225
-    /**
226
-     * Set transaction status
227
-     *
228
-     * @param string $status        whether the transaction is open, declined, accepted,
229
-     *                              or any number of custom values that can be set
230
-     * @throws EE_Error
231
-     * @throws InvalidArgumentException
232
-     * @throws InvalidDataTypeException
233
-     * @throws InvalidInterfaceException
234
-     * @throws ReflectionException
235
-     */
236
-    public function set_status($status = '')
237
-    {
238
-        $this->set('STS_ID', $status);
239
-    }
240
-
241
-
242
-    /**
243
-     * Set hash salt
244
-     *
245
-     * @param string $hash_salt required for some payment gateways
246
-     * @throws EE_Error
247
-     * @throws InvalidArgumentException
248
-     * @throws InvalidDataTypeException
249
-     * @throws InvalidInterfaceException
250
-     * @throws ReflectionException
251
-     */
252
-    public function set_hash_salt($hash_salt = '')
253
-    {
254
-        $this->set('TXN_hash_salt', $hash_salt);
255
-    }
256
-
257
-
258
-    /**
259
-     * Sets TXN_reg_steps array
260
-     *
261
-     * @param array $txn_reg_steps
262
-     * @throws EE_Error
263
-     * @throws InvalidArgumentException
264
-     * @throws InvalidDataTypeException
265
-     * @throws InvalidInterfaceException
266
-     * @throws ReflectionException
267
-     */
268
-    public function set_reg_steps(array $txn_reg_steps)
269
-    {
270
-        $this->set('TXN_reg_steps', $txn_reg_steps);
271
-    }
272
-
273
-
274
-    /**
275
-     * Gets TXN_reg_steps
276
-     *
277
-     * @return array
278
-     * @throws EE_Error
279
-     * @throws InvalidArgumentException
280
-     * @throws InvalidDataTypeException
281
-     * @throws InvalidInterfaceException
282
-     * @throws ReflectionException
283
-     */
284
-    public function reg_steps()
285
-    {
286
-        $TXN_reg_steps = $this->get('TXN_reg_steps');
287
-        return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array();
288
-    }
289
-
290
-
291
-    /**
292
-     * @return string of transaction's total cost, with currency symbol and decimal
293
-     * @throws EE_Error
294
-     * @throws InvalidArgumentException
295
-     * @throws InvalidDataTypeException
296
-     * @throws InvalidInterfaceException
297
-     * @throws ReflectionException
298
-     */
299
-    public function pretty_total()
300
-    {
301
-        return $this->get_pretty('TXN_total');
302
-    }
303
-
304
-
305
-    /**
306
-     * Gets the amount paid in a pretty string (formatted and with currency symbol)
307
-     *
308
-     * @return string
309
-     * @throws EE_Error
310
-     * @throws InvalidArgumentException
311
-     * @throws InvalidDataTypeException
312
-     * @throws InvalidInterfaceException
313
-     * @throws ReflectionException
314
-     */
315
-    public function pretty_paid()
316
-    {
317
-        return $this->get_pretty('TXN_paid');
318
-    }
319
-
320
-
321
-    /**
322
-     * calculate the amount remaining for this transaction and return;
323
-     *
324
-     * @return float amount remaining
325
-     * @throws EE_Error
326
-     * @throws InvalidArgumentException
327
-     * @throws InvalidDataTypeException
328
-     * @throws InvalidInterfaceException
329
-     * @throws ReflectionException
330
-     */
331
-    public function remaining()
332
-    {
333
-        return $this->total() - $this->paid();
334
-    }
335
-
336
-
337
-    /**
338
-     * get Transaction Total
339
-     *
340
-     * @return float
341
-     * @throws EE_Error
342
-     * @throws InvalidArgumentException
343
-     * @throws InvalidDataTypeException
344
-     * @throws InvalidInterfaceException
345
-     * @throws ReflectionException
346
-     */
347
-    public function total()
348
-    {
349
-        return (float) $this->get('TXN_total');
350
-    }
351
-
352
-
353
-    /**
354
-     * get Total Amount Paid to Date
355
-     *
356
-     * @return float
357
-     * @throws EE_Error
358
-     * @throws InvalidArgumentException
359
-     * @throws InvalidDataTypeException
360
-     * @throws InvalidInterfaceException
361
-     * @throws ReflectionException
362
-     */
363
-    public function paid()
364
-    {
365
-        return (float) $this->get('TXN_paid');
366
-    }
367
-
368
-
369
-    /**
370
-     * @return mixed|null
371
-     * @throws EE_Error
372
-     * @throws InvalidArgumentException
373
-     * @throws InvalidDataTypeException
374
-     * @throws InvalidInterfaceException
375
-     * @throws ReflectionException
376
-     */
377
-    public function get_cart_session()
378
-    {
379
-        $session_data = (array) $this->get('TXN_session_data');
380
-        return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
381
-            ? $session_data['cart']
382
-            : null;
383
-    }
384
-
385
-
386
-    /**
387
-     * get Transaction session data
388
-     *
389
-     * @return array|mixed
390
-     * @throws EE_Error
391
-     * @throws InvalidArgumentException
392
-     * @throws InvalidDataTypeException
393
-     * @throws InvalidInterfaceException
394
-     * @throws ReflectionException
395
-     */
396
-    public function session_data()
397
-    {
398
-        $session_data = $this->get('TXN_session_data');
399
-        if (empty($session_data)) {
400
-            $session_data = array(
401
-                'id'            => null,
402
-                'user_id'       => null,
403
-                'ip_address'    => null,
404
-                'user_agent'    => null,
405
-                'init_access'   => null,
406
-                'last_access'   => null,
407
-                'pages_visited' => array(),
408
-            );
409
-        }
410
-        return $session_data;
411
-    }
412
-
413
-
414
-    /**
415
-     * Set session data within the TXN object
416
-     *
417
-     * @param EE_Session|array $session_data
418
-     * @throws EE_Error
419
-     * @throws InvalidArgumentException
420
-     * @throws InvalidDataTypeException
421
-     * @throws InvalidInterfaceException
422
-     * @throws ReflectionException
423
-     */
424
-    public function set_txn_session_data($session_data)
425
-    {
426
-        if ($session_data instanceof EE_Session) {
427
-            $this->set('TXN_session_data', $session_data->get_session_data(null, true));
428
-        } else {
429
-            $this->set('TXN_session_data', $session_data);
430
-        }
431
-    }
432
-
433
-
434
-    /**
435
-     * get Transaction hash salt
436
-     *
437
-     * @return mixed
438
-     * @throws EE_Error
439
-     * @throws InvalidArgumentException
440
-     * @throws InvalidDataTypeException
441
-     * @throws InvalidInterfaceException
442
-     * @throws ReflectionException
443
-     */
444
-    public function hash_salt_()
445
-    {
446
-        return $this->get('TXN_hash_salt');
447
-    }
448
-
449
-
450
-    /**
451
-     * Returns the transaction datetime as either:
452
-     *            - unix timestamp format ($format = false, $gmt = true)
453
-     *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
454
-     *              has no affect with this option)), this also may include a timezone abbreviation if the
455
-     *              set timezone in this class differs from what the timezone is on the blog.
456
-     *            - formatted date string including the UTC (timezone) offset (default).
457
-     *
458
-     * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
459
-     * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
460
-     *                          or no UTC offset applied
461
-     * @return string | int
462
-     * @throws EE_Error
463
-     * @throws InvalidArgumentException
464
-     * @throws InvalidDataTypeException
465
-     * @throws InvalidInterfaceException
466
-     * @throws ReflectionException
467
-     */
468
-    public function datetime($format = false, $gmt = false)
469
-    {
470
-        if ($format) {
471
-            return $this->get_pretty('TXN_timestamp');
472
-        }
473
-        if ($gmt) {
474
-            return $this->get_raw('TXN_timestamp');
475
-        }
476
-        return $this->get('TXN_timestamp');
477
-    }
478
-
479
-
480
-    /**
481
-     * Gets registrations on this transaction
482
-     *
483
-     * @param array   $query_params array of query parameters
484
-     * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
485
-     * @return EE_Base_Class[]|EE_Registration[]
486
-     * @throws EE_Error
487
-     * @throws InvalidArgumentException
488
-     * @throws InvalidDataTypeException
489
-     * @throws InvalidInterfaceException
490
-     * @throws ReflectionException
491
-     */
492
-    public function registrations($query_params = array(), $get_cached = false)
493
-    {
494
-        $query_params = (empty($query_params) || ! is_array($query_params))
495
-            ? array(
496
-                'order_by' => array(
497
-                    'Event.EVT_name'     => 'ASC',
498
-                    'Attendee.ATT_lname' => 'ASC',
499
-                    'Attendee.ATT_fname' => 'ASC',
500
-                ),
501
-            )
502
-            : $query_params;
503
-        $query_params = $get_cached ? array() : $query_params;
504
-        return $this->get_many_related('Registration', $query_params);
505
-    }
506
-
507
-
508
-    /**
509
-     * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
510
-     * function for getting attendees and how many registrations they each have for an event)
511
-     *
512
-     * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
513
-     * @throws EE_Error
514
-     * @throws InvalidArgumentException
515
-     * @throws InvalidDataTypeException
516
-     * @throws InvalidInterfaceException
517
-     * @throws ReflectionException
518
-     */
519
-    public function attendees()
520
-    {
521
-        return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID())));
522
-    }
523
-
524
-
525
-    /**
526
-     * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
527
-     *
528
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
529
-     * @return EE_Base_Class[]|EE_Payment[]
530
-     * @throws EE_Error
531
-     * @throws InvalidArgumentException
532
-     * @throws InvalidDataTypeException
533
-     * @throws InvalidInterfaceException
534
-     * @throws ReflectionException
535
-     */
536
-    public function payments($query_params = array())
537
-    {
538
-        return $this->get_many_related('Payment', $query_params);
539
-    }
540
-
541
-
542
-    /**
543
-     * gets only approved payments for this transaction
544
-     *
545
-     * @return EE_Base_Class[]|EE_Payment[]
546
-     * @throws EE_Error
547
-     * @throws InvalidArgumentException
548
-     * @throws ReflectionException
549
-     * @throws InvalidDataTypeException
550
-     * @throws InvalidInterfaceException
551
-     */
552
-    public function approved_payments()
553
-    {
554
-        EE_Registry::instance()->load_model('Payment');
555
-        return $this->get_many_related(
556
-            'Payment',
557
-            array(
558
-                array('STS_ID' => EEM_Payment::status_id_approved),
559
-                'order_by' => array('PAY_timestamp' => 'DESC'),
560
-            )
561
-        );
562
-    }
563
-
564
-
565
-    /**
566
-     * Gets all payments which have not been approved
567
-     *
568
-     * @return EE_Base_Class[]|EEI_Payment[]
569
-     * @throws EE_Error if a model is misconfigured somehow
570
-     * @throws InvalidArgumentException
571
-     * @throws InvalidDataTypeException
572
-     * @throws InvalidInterfaceException
573
-     * @throws ReflectionException
574
-     */
575
-    public function pending_payments()
576
-    {
577
-        return $this->get_many_related(
578
-            'Payment',
579
-            array(
580
-                array(
581
-                    'STS_ID' => EEM_Payment::status_id_pending,
582
-                ),
583
-                'order_by' => array(
584
-                    'PAY_timestamp' => 'DESC',
585
-                ),
586
-            )
587
-        );
588
-    }
589
-
590
-
591
-    /**
592
-     * echoes $this->pretty_status()
593
-     *
594
-     * @param bool $show_icons
595
-     * @throws EE_Error
596
-     * @throws InvalidArgumentException
597
-     * @throws InvalidDataTypeException
598
-     * @throws InvalidInterfaceException
599
-     * @throws ReflectionException
600
-     */
601
-    public function e_pretty_status($show_icons = false)
602
-    {
603
-        echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
604
-    }
605
-
606
-
607
-    /**
608
-     * returns a pretty version of the status, good for displaying to users
609
-     *
610
-     * @param bool $show_icons
611
-     * @return string
612
-     * @throws EE_Error
613
-     * @throws InvalidArgumentException
614
-     * @throws InvalidDataTypeException
615
-     * @throws InvalidInterfaceException
616
-     * @throws ReflectionException
617
-     */
618
-    public function pretty_status($show_icons = false)
619
-    {
620
-        $status = EEM_Status::instance()->localized_status(
621
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
622
-            false,
623
-            'sentence'
624
-        );
625
-        $icon = '';
626
-        switch ($this->status_ID()) {
627
-            case EEM_Transaction::complete_status_code:
628
-                $icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
629
-                break;
630
-            case EEM_Transaction::incomplete_status_code:
631
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
632
-                    : '';
633
-                break;
634
-            case EEM_Transaction::abandoned_status_code:
635
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
636
-                break;
637
-            case EEM_Transaction::failed_status_code:
638
-                $icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
639
-                break;
640
-            case EEM_Transaction::overpaid_status_code:
641
-                $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
642
-                break;
643
-        }
644
-        return $icon . $status[ $this->status_ID() ];
645
-    }
646
-
647
-
648
-    /**
649
-     * get Transaction Status
650
-     *
651
-     * @return mixed
652
-     * @throws EE_Error
653
-     * @throws InvalidArgumentException
654
-     * @throws InvalidDataTypeException
655
-     * @throws InvalidInterfaceException
656
-     * @throws ReflectionException
657
-     */
658
-    public function status_ID()
659
-    {
660
-        return $this->get('STS_ID');
661
-    }
662
-
663
-
664
-    /**
665
-     * Returns TRUE or FALSE for whether or not this transaction cost any money
666
-     *
667
-     * @return boolean
668
-     * @throws EE_Error
669
-     * @throws InvalidArgumentException
670
-     * @throws InvalidDataTypeException
671
-     * @throws InvalidInterfaceException
672
-     * @throws ReflectionException
673
-     */
674
-    public function is_free()
675
-    {
676
-        return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
677
-    }
678
-
679
-
680
-    /**
681
-     * Returns whether this transaction is complete
682
-     * Useful in templates and other logic for deciding if we should ask for another payment...
683
-     *
684
-     * @return boolean
685
-     * @throws EE_Error
686
-     * @throws InvalidArgumentException
687
-     * @throws InvalidDataTypeException
688
-     * @throws InvalidInterfaceException
689
-     * @throws ReflectionException
690
-     */
691
-    public function is_completed()
692
-    {
693
-        return $this->status_ID() === EEM_Transaction::complete_status_code;
694
-    }
695
-
696
-
697
-    /**
698
-     * Returns whether this transaction is incomplete
699
-     * Useful in templates and other logic for deciding if we should ask for another payment...
700
-     *
701
-     * @return boolean
702
-     * @throws EE_Error
703
-     * @throws InvalidArgumentException
704
-     * @throws InvalidDataTypeException
705
-     * @throws InvalidInterfaceException
706
-     * @throws ReflectionException
707
-     */
708
-    public function is_incomplete()
709
-    {
710
-        return $this->status_ID() === EEM_Transaction::incomplete_status_code;
711
-    }
712
-
713
-
714
-    /**
715
-     * Returns whether this transaction is overpaid
716
-     * Useful in templates and other logic for deciding if monies need to be refunded
717
-     *
718
-     * @return boolean
719
-     * @throws EE_Error
720
-     * @throws InvalidArgumentException
721
-     * @throws InvalidDataTypeException
722
-     * @throws InvalidInterfaceException
723
-     * @throws ReflectionException
724
-     */
725
-    public function is_overpaid()
726
-    {
727
-        return $this->status_ID() === EEM_Transaction::overpaid_status_code;
728
-    }
729
-
730
-
731
-    /**
732
-     * Returns whether this transaction was abandoned
733
-     * meaning that the transaction/registration process was somehow interrupted and never completed
734
-     * but that contact information exists for at least one registrant
735
-     *
736
-     * @return boolean
737
-     * @throws EE_Error
738
-     * @throws InvalidArgumentException
739
-     * @throws InvalidDataTypeException
740
-     * @throws InvalidInterfaceException
741
-     * @throws ReflectionException
742
-     */
743
-    public function is_abandoned()
744
-    {
745
-        return $this->status_ID() === EEM_Transaction::abandoned_status_code;
746
-    }
747
-
748
-
749
-    /**
750
-     * Returns whether this transaction failed
751
-     * meaning that the transaction/registration process was somehow interrupted and never completed
752
-     * and that NO contact information exists for any registrants
753
-     *
754
-     * @return boolean
755
-     * @throws EE_Error
756
-     * @throws InvalidArgumentException
757
-     * @throws InvalidDataTypeException
758
-     * @throws InvalidInterfaceException
759
-     * @throws ReflectionException
760
-     */
761
-    public function failed()
762
-    {
763
-        return $this->status_ID() === EEM_Transaction::failed_status_code;
764
-    }
765
-
766
-
767
-    /**
768
-     * This returns the url for the invoice of this transaction
769
-     *
770
-     * @param string $type 'html' or 'pdf' (default is pdf)
771
-     * @return string
772
-     * @throws EE_Error
773
-     * @throws InvalidArgumentException
774
-     * @throws InvalidDataTypeException
775
-     * @throws InvalidInterfaceException
776
-     * @throws ReflectionException
777
-     */
778
-    public function invoice_url($type = 'html')
779
-    {
780
-        $REG = $this->primary_registration();
781
-        if (! $REG instanceof EE_Registration) {
782
-            return '';
783
-        }
784
-        return $REG->invoice_url($type);
785
-    }
786
-
787
-
788
-    /**
789
-     * Gets the primary registration only
790
-     *
791
-     * @return EE_Base_Class|EE_Registration
792
-     * @throws EE_Error
793
-     * @throws InvalidArgumentException
794
-     * @throws InvalidDataTypeException
795
-     * @throws InvalidInterfaceException
796
-     * @throws ReflectionException
797
-     */
798
-    public function primary_registration()
799
-    {
800
-        $registrations = (array) $this->get_many_related(
801
-            'Registration',
802
-            array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT))
803
-        );
804
-        foreach ($registrations as $registration) {
805
-            // valid registration that is NOT cancelled or declined ?
806
-            if (
807
-                $registration instanceof EE_Registration
808
-                && ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
809
-            ) {
810
-                return $registration;
811
-            }
812
-        }
813
-        // nothing valid found, so just return first thing from array of results
814
-        return reset($registrations);
815
-    }
816
-
817
-
818
-    /**
819
-     * Gets the URL for viewing the receipt
820
-     *
821
-     * @param string $type 'pdf' or 'html' (default is 'html')
822
-     * @return string
823
-     * @throws EE_Error
824
-     * @throws InvalidArgumentException
825
-     * @throws InvalidDataTypeException
826
-     * @throws InvalidInterfaceException
827
-     * @throws ReflectionException
828
-     */
829
-    public function receipt_url($type = 'html')
830
-    {
831
-        $REG = $this->primary_registration();
832
-        if (! $REG instanceof EE_Registration) {
833
-            return '';
834
-        }
835
-        return $REG->receipt_url($type);
836
-    }
837
-
838
-
839
-    /**
840
-     * Gets the URL of the thank you page with this registration REG_url_link added as
841
-     * a query parameter
842
-     *
843
-     * @return string
844
-     * @throws EE_Error
845
-     * @throws InvalidArgumentException
846
-     * @throws InvalidDataTypeException
847
-     * @throws InvalidInterfaceException
848
-     * @throws ReflectionException
849
-     */
850
-    public function payment_overview_url()
851
-    {
852
-        $primary_registration = $this->primary_registration();
853
-        return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
854
-    }
855
-
856
-
857
-    /**
858
-     * @return string
859
-     * @throws EE_Error
860
-     * @throws InvalidArgumentException
861
-     * @throws InvalidDataTypeException
862
-     * @throws InvalidInterfaceException
863
-     * @throws ReflectionException
864
-     */
865
-    public function gateway_response_on_transaction()
866
-    {
867
-        $payment = $this->get_first_related('Payment');
868
-        return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
869
-    }
870
-
871
-
872
-    /**
873
-     * Get the status object of this object
874
-     *
875
-     * @return EE_Base_Class|EE_Status
876
-     * @throws EE_Error
877
-     * @throws InvalidArgumentException
878
-     * @throws InvalidDataTypeException
879
-     * @throws InvalidInterfaceException
880
-     * @throws ReflectionException
881
-     */
882
-    public function status_obj()
883
-    {
884
-        return $this->get_first_related('Status');
885
-    }
886
-
887
-
888
-    /**
889
-     * Gets all the extra meta info on this payment
890
-     *
891
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
892
-     * @return EE_Base_Class[]|EE_Extra_Meta
893
-     * @throws EE_Error
894
-     * @throws InvalidArgumentException
895
-     * @throws InvalidDataTypeException
896
-     * @throws InvalidInterfaceException
897
-     * @throws ReflectionException
898
-     */
899
-    public function extra_meta($query_params = array())
900
-    {
901
-        return $this->get_many_related('Extra_Meta', $query_params);
902
-    }
903
-
904
-
905
-    /**
906
-     * Wrapper for _add_relation_to
907
-     *
908
-     * @param EE_Registration $registration
909
-     * @return EE_Base_Class the relation was added to
910
-     * @throws EE_Error
911
-     * @throws InvalidArgumentException
912
-     * @throws InvalidDataTypeException
913
-     * @throws InvalidInterfaceException
914
-     * @throws ReflectionException
915
-     */
916
-    public function add_registration(EE_Registration $registration)
917
-    {
918
-        return $this->_add_relation_to($registration, 'Registration');
919
-    }
920
-
921
-
922
-    /**
923
-     * Removes the given registration from being related (even before saving this transaction).
924
-     * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
925
-     *
926
-     * @param int $registration_or_id
927
-     * @return EE_Base_Class that was removed from being related
928
-     * @throws EE_Error
929
-     * @throws InvalidArgumentException
930
-     * @throws InvalidDataTypeException
931
-     * @throws InvalidInterfaceException
932
-     * @throws ReflectionException
933
-     */
934
-    public function remove_registration_with_id($registration_or_id)
935
-    {
936
-        return $this->_remove_relation_to($registration_or_id, 'Registration');
937
-    }
938
-
939
-
940
-    /**
941
-     * Gets all the line items which are for ACTUAL items
942
-     *
943
-     * @return EE_Line_Item[]
944
-     * @throws EE_Error
945
-     * @throws InvalidArgumentException
946
-     * @throws InvalidDataTypeException
947
-     * @throws InvalidInterfaceException
948
-     * @throws ReflectionException
949
-     */
950
-    public function items_purchased()
951
-    {
952
-        return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item)));
953
-    }
954
-
955
-
956
-    /**
957
-     * Wrapper for _add_relation_to
958
-     *
959
-     * @param EE_Line_Item $line_item
960
-     * @return EE_Base_Class the relation was added to
961
-     * @throws EE_Error
962
-     * @throws InvalidArgumentException
963
-     * @throws InvalidDataTypeException
964
-     * @throws InvalidInterfaceException
965
-     * @throws ReflectionException
966
-     */
967
-    public function add_line_item(EE_Line_Item $line_item)
968
-    {
969
-        return $this->_add_relation_to($line_item, 'Line_Item');
970
-    }
971
-
972
-
973
-    /**
974
-     * Gets ALL the line items related to this transaction (unstructured)
975
-     *
976
-     * @param array $query_params
977
-     * @return EE_Base_Class[]|EE_Line_Item[]
978
-     * @throws EE_Error
979
-     * @throws InvalidArgumentException
980
-     * @throws InvalidDataTypeException
981
-     * @throws InvalidInterfaceException
982
-     * @throws ReflectionException
983
-     */
984
-    public function line_items($query_params = array())
985
-    {
986
-        return $this->get_many_related('Line_Item', $query_params);
987
-    }
988
-
989
-
990
-    /**
991
-     * Gets all the line items which are taxes on the total
992
-     *
993
-     * @return EE_Line_Item[]
994
-     * @throws EE_Error
995
-     * @throws InvalidArgumentException
996
-     * @throws InvalidDataTypeException
997
-     * @throws InvalidInterfaceException
998
-     * @throws ReflectionException
999
-     */
1000
-    public function tax_items()
1001
-    {
1002
-        return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax)));
1003
-    }
1004
-
1005
-
1006
-    /**
1007
-     * Gets the total line item (which is a parent of all other related line items,
1008
-     * meaning it takes them all into account on its total)
1009
-     *
1010
-     * @param bool $create_if_not_found
1011
-     * @return \EE_Line_Item
1012
-     * @throws EE_Error
1013
-     * @throws InvalidArgumentException
1014
-     * @throws InvalidDataTypeException
1015
-     * @throws InvalidInterfaceException
1016
-     * @throws ReflectionException
1017
-     */
1018
-    public function total_line_item($create_if_not_found = true)
1019
-    {
1020
-        $item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
1021
-        if (! $item && $create_if_not_found) {
1022
-            $item = EEH_Line_Item::create_total_line_item($this);
1023
-        }
1024
-        return $item;
1025
-    }
1026
-
1027
-
1028
-    /**
1029
-     * Returns the total amount of tax on this transaction
1030
-     * (assumes there's only one tax subtotal line item)
1031
-     *
1032
-     * @return float
1033
-     * @throws EE_Error
1034
-     * @throws InvalidArgumentException
1035
-     * @throws InvalidDataTypeException
1036
-     * @throws InvalidInterfaceException
1037
-     * @throws ReflectionException
1038
-     */
1039
-    public function tax_total()
1040
-    {
1041
-        $tax_line_item = $this->tax_total_line_item();
1042
-        if ($tax_line_item) {
1043
-            return (float) $tax_line_item->total();
1044
-        }
1045
-        return (float) 0;
1046
-    }
1047
-
1048
-
1049
-    /**
1050
-     * Gets the tax subtotal line item (assumes there's only one)
1051
-     *
1052
-     * @return EE_Line_Item
1053
-     * @throws EE_Error
1054
-     * @throws InvalidArgumentException
1055
-     * @throws InvalidDataTypeException
1056
-     * @throws InvalidInterfaceException
1057
-     * @throws ReflectionException
1058
-     */
1059
-    public function tax_total_line_item()
1060
-    {
1061
-        return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
1062
-    }
1063
-
1064
-
1065
-    /**
1066
-     * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
1067
-     *
1068
-     * @return EE_Form_Section_Proper
1069
-     * @throws EE_Error
1070
-     * @throws InvalidArgumentException
1071
-     * @throws InvalidDataTypeException
1072
-     * @throws InvalidInterfaceException
1073
-     * @throws ReflectionException
1074
-     */
1075
-    public function billing_info()
1076
-    {
1077
-        $payment_method = $this->payment_method();
1078
-        if (! $payment_method) {
1079
-            EE_Error::add_error(
1080
-                esc_html__(
1081
-                    'Could not find billing info for transaction because no gateway has been used for it yet',
1082
-                    'event_espresso'
1083
-                ),
1084
-                __FILE__,
1085
-                __FUNCTION__,
1086
-                __LINE__
1087
-            );
1088
-            return null;
1089
-        }
1090
-        $primary_reg = $this->primary_registration();
1091
-        if (! $primary_reg) {
1092
-            EE_Error::add_error(
1093
-                esc_html__(
1094
-                    'Cannot get billing info for gateway %s on transaction because no primary registration exists',
1095
-                    'event_espresso'
1096
-                ),
1097
-                __FILE__,
1098
-                __FUNCTION__,
1099
-                __LINE__
1100
-            );
1101
-            return null;
1102
-        }
1103
-        $attendee = $primary_reg->attendee();
1104
-        if (! $attendee) {
1105
-            EE_Error::add_error(
1106
-                esc_html__(
1107
-                    'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
1108
-                    'event_espresso'
1109
-                ),
1110
-                __FILE__,
1111
-                __FUNCTION__,
1112
-                __LINE__
1113
-            );
1114
-            return null;
1115
-        }
1116
-        return $attendee->billing_info_for_payment_method($payment_method);
1117
-    }
1118
-
1119
-
1120
-    /**
1121
-     * Gets PMD_ID
1122
-     *
1123
-     * @return int
1124
-     * @throws EE_Error
1125
-     * @throws InvalidArgumentException
1126
-     * @throws InvalidDataTypeException
1127
-     * @throws InvalidInterfaceException
1128
-     * @throws ReflectionException
1129
-     */
1130
-    public function payment_method_ID()
1131
-    {
1132
-        return $this->get('PMD_ID');
1133
-    }
1134
-
1135
-
1136
-    /**
1137
-     * Sets PMD_ID
1138
-     *
1139
-     * @param int $PMD_ID
1140
-     * @throws EE_Error
1141
-     * @throws InvalidArgumentException
1142
-     * @throws InvalidDataTypeException
1143
-     * @throws InvalidInterfaceException
1144
-     * @throws ReflectionException
1145
-     */
1146
-    public function set_payment_method_ID($PMD_ID)
1147
-    {
1148
-        $this->set('PMD_ID', $PMD_ID);
1149
-    }
1150
-
1151
-
1152
-    /**
1153
-     * Gets the last-used payment method on this transaction
1154
-     * (we COULD just use the last-made payment, but some payment methods, namely
1155
-     * offline ones, dont' create payments)
1156
-     *
1157
-     * @return EE_Payment_Method
1158
-     * @throws EE_Error
1159
-     * @throws InvalidArgumentException
1160
-     * @throws InvalidDataTypeException
1161
-     * @throws InvalidInterfaceException
1162
-     * @throws ReflectionException
1163
-     */
1164
-    public function payment_method()
1165
-    {
1166
-        $pm = $this->get_first_related('Payment_Method');
1167
-        if ($pm instanceof EE_Payment_Method) {
1168
-            return $pm;
1169
-        }
1170
-        $last_payment = $this->last_payment();
1171
-        if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
1172
-            return $last_payment->payment_method();
1173
-        }
1174
-        return null;
1175
-    }
1176
-
1177
-
1178
-    /**
1179
-     * Gets the last payment made
1180
-     *
1181
-     * @return EE_Base_Class|EE_Payment
1182
-     * @throws EE_Error
1183
-     * @throws InvalidArgumentException
1184
-     * @throws InvalidDataTypeException
1185
-     * @throws InvalidInterfaceException
1186
-     * @throws ReflectionException
1187
-     */
1188
-    public function last_payment()
1189
-    {
1190
-        return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc')));
1191
-    }
1192
-
1193
-
1194
-    /**
1195
-     * Gets all the line items which are unrelated to tickets on this transaction
1196
-     *
1197
-     * @return EE_Line_Item[]
1198
-     * @throws EE_Error
1199
-     * @throws InvalidArgumentException
1200
-     * @throws InvalidDataTypeException
1201
-     * @throws InvalidInterfaceException
1202
-     * @throws ReflectionException
1203
-     */
1204
-    public function non_ticket_line_items()
1205
-    {
1206
-        return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
1207
-    }
1208
-
1209
-
1210
-    /**
1211
-     * possibly toggles TXN status
1212
-     *
1213
-     * @param  boolean $update whether to save the TXN
1214
-     * @return bool whether the TXN was saved
1215
-     * @throws EE_Error
1216
-     * @throws InvalidArgumentException
1217
-     * @throws InvalidDataTypeException
1218
-     * @throws InvalidInterfaceException
1219
-     * @throws ReflectionException
1220
-     * @throws RuntimeException
1221
-     */
1222
-    public function update_status_based_on_total_paid($update = true)
1223
-    {
1224
-        // set transaction status based on comparison of TXN_paid vs TXN_total
1225
-        if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
1226
-            $new_txn_status = EEM_Transaction::overpaid_status_code;
1227
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
1228
-            $new_txn_status = EEM_Transaction::complete_status_code;
1229
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
1230
-            $new_txn_status = EEM_Transaction::incomplete_status_code;
1231
-        } else {
1232
-            throw new RuntimeException(
1233
-                esc_html__('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1234
-            );
1235
-        }
1236
-        if ($new_txn_status !== $this->status_ID()) {
1237
-            $this->set_status($new_txn_status);
1238
-            if ($update) {
1239
-                return $this->save() ? true : false;
1240
-            }
1241
-        }
1242
-        return false;
1243
-    }
1244
-
1245
-
1246
-    /**
1247
-     * Updates the transaction's status and total_paid based on all the payments
1248
-     * that apply to it
1249
-     *
1250
-     * @deprecated
1251
-     * @return array|bool
1252
-     * @throws EE_Error
1253
-     * @throws InvalidArgumentException
1254
-     * @throws ReflectionException
1255
-     * @throws InvalidDataTypeException
1256
-     * @throws InvalidInterfaceException
1257
-     */
1258
-    public function update_based_on_payments()
1259
-    {
1260
-        EE_Error::doing_it_wrong(
1261
-            __CLASS__ . '::' . __FUNCTION__,
1262
-            sprintf(
1263
-                esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1264
-                'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1265
-            ),
1266
-            '4.6.0'
1267
-        );
1268
-        /** @type EE_Transaction_Processor $transaction_processor */
1269
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1270
-        return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1271
-    }
1272
-
1273
-
1274
-    /**
1275
-     * @return string
1276
-     */
1277
-    public function old_txn_status()
1278
-    {
1279
-        return $this->_old_txn_status;
1280
-    }
1281
-
1282
-
1283
-    /**
1284
-     * @param string $old_txn_status
1285
-     */
1286
-    public function set_old_txn_status($old_txn_status)
1287
-    {
1288
-        // only set the first time
1289
-        if ($this->_old_txn_status === null) {
1290
-            $this->_old_txn_status = $old_txn_status;
1291
-        }
1292
-    }
1293
-
1294
-
1295
-    /**
1296
-     * reg_status_updated
1297
-     *
1298
-     * @return bool
1299
-     * @throws EE_Error
1300
-     * @throws InvalidArgumentException
1301
-     * @throws InvalidDataTypeException
1302
-     * @throws InvalidInterfaceException
1303
-     * @throws ReflectionException
1304
-     */
1305
-    public function txn_status_updated()
1306
-    {
1307
-        return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1308
-    }
1309
-
1310
-
1311
-    /**
1312
-     * _reg_steps_completed
1313
-     * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1314
-     * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1315
-     * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1316
-     *
1317
-     * @param string $reg_step_slug
1318
-     * @param bool   $check_all
1319
-     * @return bool|int
1320
-     * @throws EE_Error
1321
-     * @throws InvalidArgumentException
1322
-     * @throws InvalidDataTypeException
1323
-     * @throws InvalidInterfaceException
1324
-     * @throws ReflectionException
1325
-     */
1326
-    private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1327
-    {
1328
-        $reg_steps = $this->reg_steps();
1329
-        if (! is_array($reg_steps) || empty($reg_steps)) {
1330
-            return false;
1331
-        }
1332
-        // loop thru reg steps array)
1333
-        foreach ($reg_steps as $slug => $reg_step_completed) {
1334
-            // if NOT checking ALL steps (only checking one step)
1335
-            if (! $check_all) {
1336
-                // and this is the one
1337
-                if ($slug === $reg_step_slug) {
1338
-                    return $reg_step_completed;
1339
-                }
1340
-                // skip to next reg step in loop
1341
-                continue;
1342
-            }
1343
-            // $check_all must be true, else we would never have gotten to this point
1344
-            if ($slug === $reg_step_slug) {
1345
-                // if we reach this point, then we are testing either:
1346
-                // all_reg_steps_completed_except() or
1347
-                // all_reg_steps_completed_except_final_step(),
1348
-                // and since this is the reg step EXCEPTION being tested
1349
-                // we want to return true (yes true) if this reg step is NOT completed
1350
-                // ie: "is everything completed except the final step?"
1351
-                // "that is correct... the final step is not completed, but all others are."
1352
-                return $reg_step_completed !== true;
1353
-            }
1354
-            if ($reg_step_completed !== true) {
1355
-                // if any reg step is NOT completed, then ALL steps are not completed
1356
-                return false;
1357
-            }
1358
-        }
1359
-        return true;
1360
-    }
1361
-
1362
-
1363
-    /**
1364
-     * all_reg_steps_completed
1365
-     * returns:
1366
-     *    true if ALL reg steps have been marked as completed
1367
-     *        or false if any step is not completed
1368
-     *
1369
-     * @return bool
1370
-     * @throws EE_Error
1371
-     * @throws InvalidArgumentException
1372
-     * @throws InvalidDataTypeException
1373
-     * @throws InvalidInterfaceException
1374
-     * @throws ReflectionException
1375
-     */
1376
-    public function all_reg_steps_completed()
1377
-    {
1378
-        return $this->_reg_steps_completed();
1379
-    }
1380
-
1381
-
1382
-    /**
1383
-     * all_reg_steps_completed_except
1384
-     * returns:
1385
-     *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1386
-     *        or false if any other step is not completed
1387
-     *        or false if ALL steps are completed including the exception you are testing !!!
1388
-     *
1389
-     * @param string $exception
1390
-     * @return bool
1391
-     * @throws EE_Error
1392
-     * @throws InvalidArgumentException
1393
-     * @throws InvalidDataTypeException
1394
-     * @throws InvalidInterfaceException
1395
-     * @throws ReflectionException
1396
-     */
1397
-    public function all_reg_steps_completed_except($exception = '')
1398
-    {
1399
-        return $this->_reg_steps_completed($exception);
1400
-    }
1401
-
1402
-
1403
-    /**
1404
-     * all_reg_steps_completed_except
1405
-     * returns:
1406
-     *        true if ALL reg steps, except the final step, have been marked as completed
1407
-     *        or false if any step is not completed
1408
-     *    or false if ALL steps are completed including the final step !!!
1409
-     *
1410
-     * @return bool
1411
-     * @throws EE_Error
1412
-     * @throws InvalidArgumentException
1413
-     * @throws InvalidDataTypeException
1414
-     * @throws InvalidInterfaceException
1415
-     * @throws ReflectionException
1416
-     */
1417
-    public function all_reg_steps_completed_except_final_step()
1418
-    {
1419
-        return $this->_reg_steps_completed('finalize_registration');
1420
-    }
1421
-
1422
-
1423
-    /**
1424
-     * reg_step_completed
1425
-     * returns:
1426
-     *    true if a specific reg step has been marked as completed
1427
-     *    a Unix timestamp if it has been initialized but not yet completed,
1428
-     *    or false if it has not yet been initialized
1429
-     *
1430
-     * @param string $reg_step_slug
1431
-     * @return bool|int
1432
-     * @throws EE_Error
1433
-     * @throws InvalidArgumentException
1434
-     * @throws InvalidDataTypeException
1435
-     * @throws InvalidInterfaceException
1436
-     * @throws ReflectionException
1437
-     */
1438
-    public function reg_step_completed($reg_step_slug)
1439
-    {
1440
-        return $this->_reg_steps_completed($reg_step_slug, false);
1441
-    }
1442
-
1443
-
1444
-    /**
1445
-     * completed_final_reg_step
1446
-     * returns:
1447
-     *    true if the finalize_registration reg step has been marked as completed
1448
-     *    a Unix timestamp if it has been initialized but not yet completed,
1449
-     *    or false if it has not yet been initialized
1450
-     *
1451
-     * @return bool|int
1452
-     * @throws EE_Error
1453
-     * @throws InvalidArgumentException
1454
-     * @throws InvalidDataTypeException
1455
-     * @throws InvalidInterfaceException
1456
-     * @throws ReflectionException
1457
-     */
1458
-    public function final_reg_step_completed()
1459
-    {
1460
-        return $this->_reg_steps_completed('finalize_registration', false);
1461
-    }
1462
-
1463
-
1464
-    /**
1465
-     * set_reg_step_initiated
1466
-     * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1467
-     *
1468
-     * @param string $reg_step_slug
1469
-     * @return boolean
1470
-     * @throws EE_Error
1471
-     * @throws InvalidArgumentException
1472
-     * @throws InvalidDataTypeException
1473
-     * @throws InvalidInterfaceException
1474
-     * @throws ReflectionException
1475
-     */
1476
-    public function set_reg_step_initiated($reg_step_slug)
1477
-    {
1478
-        return $this->_set_reg_step_completed_status($reg_step_slug, time());
1479
-    }
1480
-
1481
-
1482
-    /**
1483
-     * set_reg_step_completed
1484
-     * given a valid TXN_reg_step, this sets the step as completed
1485
-     *
1486
-     * @param string $reg_step_slug
1487
-     * @return boolean
1488
-     * @throws EE_Error
1489
-     * @throws InvalidArgumentException
1490
-     * @throws InvalidDataTypeException
1491
-     * @throws InvalidInterfaceException
1492
-     * @throws ReflectionException
1493
-     */
1494
-    public function set_reg_step_completed($reg_step_slug)
1495
-    {
1496
-        return $this->_set_reg_step_completed_status($reg_step_slug, true);
1497
-    }
1498
-
1499
-
1500
-    /**
1501
-     * set_reg_step_completed
1502
-     * given a valid TXN_reg_step slug, this sets the step as NOT completed
1503
-     *
1504
-     * @param string $reg_step_slug
1505
-     * @return boolean
1506
-     * @throws EE_Error
1507
-     * @throws InvalidArgumentException
1508
-     * @throws InvalidDataTypeException
1509
-     * @throws InvalidInterfaceException
1510
-     * @throws ReflectionException
1511
-     */
1512
-    public function set_reg_step_not_completed($reg_step_slug)
1513
-    {
1514
-        return $this->_set_reg_step_completed_status($reg_step_slug, false);
1515
-    }
1516
-
1517
-
1518
-    /**
1519
-     * set_reg_step_completed
1520
-     * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1521
-     *
1522
-     * @param  string      $reg_step_slug
1523
-     * @param  boolean|int $status
1524
-     * @return boolean
1525
-     * @throws EE_Error
1526
-     * @throws InvalidArgumentException
1527
-     * @throws InvalidDataTypeException
1528
-     * @throws InvalidInterfaceException
1529
-     * @throws ReflectionException
1530
-     */
1531
-    private function _set_reg_step_completed_status($reg_step_slug, $status)
1532
-    {
1533
-        // validate status
1534
-        $status = is_bool($status) || is_int($status) ? $status : false;
1535
-        // get reg steps array
1536
-        $txn_reg_steps = $this->reg_steps();
1537
-        // if reg step does NOT exist
1538
-        if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1539
-            return false;
1540
-        }
1541
-        // if  we're trying to complete a step that is already completed
1542
-        if ($txn_reg_steps[ $reg_step_slug ] === true) {
1543
-            return true;
1544
-        }
1545
-        // if  we're trying to complete a step that hasn't even started
1546
-        if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1547
-            return false;
1548
-        }
1549
-        // if current status value matches the incoming value (no change)
1550
-        // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1551
-        if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1552
-            // this will happen in cases where multiple AJAX requests occur during the same step
1553
-            return true;
1554
-        }
1555
-        // if we're trying to set a start time, but it has already been set...
1556
-        if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1557
-            // skip the update below, but don't return FALSE so that errors won't be displayed
1558
-            return true;
1559
-        }
1560
-        // update completed status
1561
-        $txn_reg_steps[ $reg_step_slug ] = $status;
1562
-        $this->set_reg_steps($txn_reg_steps);
1563
-        $this->save();
1564
-        return true;
1565
-    }
1566
-
1567
-
1568
-    /**
1569
-     * remove_reg_step
1570
-     * given a valid TXN_reg_step slug, this will remove (unset)
1571
-     * the reg step from the TXN reg step array
1572
-     *
1573
-     * @param string $reg_step_slug
1574
-     * @return void
1575
-     * @throws EE_Error
1576
-     * @throws InvalidArgumentException
1577
-     * @throws InvalidDataTypeException
1578
-     * @throws InvalidInterfaceException
1579
-     * @throws ReflectionException
1580
-     */
1581
-    public function remove_reg_step($reg_step_slug)
1582
-    {
1583
-        // get reg steps array
1584
-        $txn_reg_steps = $this->reg_steps();
1585
-        unset($txn_reg_steps[ $reg_step_slug ]);
1586
-        $this->set_reg_steps($txn_reg_steps);
1587
-    }
1588
-
1589
-
1590
-    /**
1591
-     * toggle_failed_transaction_status
1592
-     * upgrades a TXNs status from failed to abandoned,
1593
-     * meaning that contact information has been captured for at least one registrant
1594
-     *
1595
-     * @param bool $save
1596
-     * @return bool
1597
-     * @throws EE_Error
1598
-     * @throws InvalidArgumentException
1599
-     * @throws InvalidDataTypeException
1600
-     * @throws InvalidInterfaceException
1601
-     * @throws ReflectionException
1602
-     */
1603
-    public function toggle_failed_transaction_status($save = true)
1604
-    {
1605
-        // if TXN status is still set as "failed"...
1606
-        if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1607
-            $this->set_status(EEM_Transaction::abandoned_status_code);
1608
-            if ($save) {
1609
-                $this->save();
1610
-            }
1611
-            return true;
1612
-        }
1613
-        return false;
1614
-    }
1615
-
1616
-
1617
-    /**
1618
-     * toggle_abandoned_transaction_status
1619
-     * upgrades a TXNs status from failed or abandoned to incomplete
1620
-     *
1621
-     * @return bool
1622
-     * @throws EE_Error
1623
-     * @throws InvalidArgumentException
1624
-     * @throws InvalidDataTypeException
1625
-     * @throws InvalidInterfaceException
1626
-     * @throws ReflectionException
1627
-     */
1628
-    public function toggle_abandoned_transaction_status()
1629
-    {
1630
-        // if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1631
-        $txn_status = $this->status_ID();
1632
-        if (
1633
-            $txn_status === EEM_Transaction::failed_status_code
1634
-            || $txn_status === EEM_Transaction::abandoned_status_code
1635
-        ) {
1636
-            // if a contact record for the primary registrant has been created
1637
-            if (
1638
-                $this->primary_registration() instanceof EE_Registration
1639
-                && $this->primary_registration()->attendee() instanceof EE_Attendee
1640
-            ) {
1641
-                $this->set_status(EEM_Transaction::incomplete_status_code);
1642
-            } else {
1643
-                // no contact record? yer abandoned!
1644
-                $this->set_status(EEM_Transaction::abandoned_status_code);
1645
-            }
1646
-            return true;
1647
-        }
1648
-        return false;
1649
-    }
1650
-
1651
-
1652
-    /**
1653
-     * checks if an Abandoned TXN has any related payments, and if so,
1654
-     * updates the TXN status based on the amount paid
1655
-     *
1656
-     * @throws EE_Error
1657
-     * @throws InvalidDataTypeException
1658
-     * @throws InvalidInterfaceException
1659
-     * @throws InvalidArgumentException
1660
-     * @throws RuntimeException
1661
-     * @throws ReflectionException
1662
-     */
1663
-    public function verify_abandoned_transaction_status()
1664
-    {
1665
-        if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1666
-            return;
1667
-        }
1668
-        $payments = $this->get_many_related('Payment');
1669
-        if (! empty($payments)) {
1670
-            foreach ($payments as $payment) {
1671
-                if ($payment instanceof EE_Payment) {
1672
-                    // kk this TXN should NOT be abandoned
1673
-                    $this->update_status_based_on_total_paid();
1674
-                    if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1675
-                        EE_Error::add_attention(
1676
-                            sprintf(
1677
-                                esc_html__(
1678
-                                    '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.',
1679
-                                    'event_espresso'
1680
-                                ),
1681
-                                $this->ID(),
1682
-                                $this->pretty_status()
1683
-                            )
1684
-                        );
1685
-                    }
1686
-                    // get final reg step status
1687
-                    $finalized = $this->final_reg_step_completed();
1688
-                    // if the 'finalize_registration' step has been initiated (has a timestamp)
1689
-                    // but has not yet been fully completed (TRUE)
1690
-                    if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1691
-                        $this->set_reg_step_completed('finalize_registration');
1692
-                        $this->save();
1693
-                    }
1694
-                }
1695
-            }
1696
-        }
1697
-    }
1698
-
1699
-
1700
-    /**
1701
-     * @since 4.10.4.p
1702
-     * @throws EE_Error
1703
-     * @throws InvalidArgumentException
1704
-     * @throws InvalidDataTypeException
1705
-     * @throws InvalidInterfaceException
1706
-     * @throws ReflectionException
1707
-     * @throws RuntimeException
1708
-     */
1709
-    public function recalculateLineItems()
1710
-    {
1711
-        $total_line_item = $this->total_line_item(false);
1712
-        if ($total_line_item instanceof EE_Line_Item) {
1713
-            EEH_Line_Item::resetIsTaxableForTickets($total_line_item);
1714
-            return EEH_Line_Item::apply_taxes($total_line_item, true);
1715
-        }
1716
-        return false;
1717
-    }
17
+	/**
18
+	 * The length of time in seconds that a lock is applied before being considered expired.
19
+	 * It is not long because a transaction should only be locked for the duration of the request that locked it
20
+	 */
21
+	const LOCK_EXPIRATION = 2;
22
+
23
+	/**
24
+	 * txn status upon initial construction.
25
+	 *
26
+	 * @var string
27
+	 */
28
+	protected $_old_txn_status;
29
+
30
+
31
+	/**
32
+	 * @param array  $props_n_values          incoming values
33
+	 * @param string $timezone                incoming timezone
34
+	 *                                        (if not set the timezone set for the website will be used.)
35
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
36
+	 *                                        date_format and the second value is the time format
37
+	 * @return EE_Transaction
38
+	 * @throws EE_Error
39
+	 * @throws InvalidArgumentException
40
+	 * @throws InvalidDataTypeException
41
+	 * @throws InvalidInterfaceException
42
+	 * @throws ReflectionException
43
+	 */
44
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
45
+	{
46
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
47
+		$txn = $has_object
48
+			? $has_object
49
+			: new self($props_n_values, false, $timezone, $date_formats);
50
+		if (! $has_object) {
51
+			$txn->set_old_txn_status($txn->status_ID());
52
+		}
53
+		return $txn;
54
+	}
55
+
56
+
57
+	/**
58
+	 * @param array  $props_n_values  incoming values from the database
59
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
60
+	 *                                the website will be used.
61
+	 * @return EE_Transaction
62
+	 * @throws EE_Error
63
+	 * @throws InvalidArgumentException
64
+	 * @throws InvalidDataTypeException
65
+	 * @throws InvalidInterfaceException
66
+	 * @throws ReflectionException
67
+	 */
68
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
69
+	{
70
+		$txn = new self($props_n_values, true, $timezone);
71
+		$txn->set_old_txn_status($txn->status_ID());
72
+		return $txn;
73
+	}
74
+
75
+
76
+	/**
77
+	 * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
78
+	 * If a lock has already been set, then we will attempt to remove it in case it has expired.
79
+	 * If that also fails, then an exception is thrown.
80
+	 *
81
+	 * @throws EE_Error
82
+	 * @throws InvalidArgumentException
83
+	 * @throws InvalidDataTypeException
84
+	 * @throws InvalidInterfaceException
85
+	 * @throws ReflectionException
86
+	 */
87
+	public function lock()
88
+	{
89
+		// attempt to set lock, but if that fails...
90
+		if (! $this->add_extra_meta('lock', time(), true)) {
91
+			// then attempt to remove the lock in case it is expired
92
+			if ($this->_remove_expired_lock()) {
93
+				// if removal was successful, then try setting lock again
94
+				$this->lock();
95
+			} else {
96
+				// but if the lock can not be removed, then throw an exception
97
+				throw new EE_Error(
98
+					sprintf(
99
+						esc_html__(
100
+							'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.',
101
+							'event_espresso'
102
+						),
103
+						$this->ID()
104
+					)
105
+				);
106
+			}
107
+		}
108
+	}
109
+
110
+
111
+	/**
112
+	 * removes transaction lock applied in EE_Transaction::lock()
113
+	 *
114
+	 * @return int
115
+	 * @throws EE_Error
116
+	 * @throws InvalidArgumentException
117
+	 * @throws InvalidDataTypeException
118
+	 * @throws InvalidInterfaceException
119
+	 * @throws ReflectionException
120
+	 */
121
+	public function unlock()
122
+	{
123
+		return $this->delete_extra_meta('lock');
124
+	}
125
+
126
+
127
+	/**
128
+	 * Decides whether or not now is the right time to update the transaction.
129
+	 * This is useful because we don't always know if it is safe to update the transaction
130
+	 * and its related data. why?
131
+	 * because it's possible that the transaction is being used in another
132
+	 * request and could overwrite anything we save.
133
+	 * So we want to only update the txn once we know that won't happen.
134
+	 * We also check that the lock isn't expired, and remove it if it is
135
+	 *
136
+	 * @return boolean
137
+	 * @throws EE_Error
138
+	 * @throws InvalidArgumentException
139
+	 * @throws InvalidDataTypeException
140
+	 * @throws InvalidInterfaceException
141
+	 * @throws ReflectionException
142
+	 */
143
+	public function is_locked()
144
+	{
145
+		// if TXN is not locked, then return false immediately
146
+		if (! $this->_get_lock()) {
147
+			return false;
148
+		}
149
+		// if not, then let's try and remove the lock in case it's expired...
150
+		// _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
151
+		// and a positive number if the lock was removed (ie: number of locks deleted),
152
+		// so we need to return the opposite
153
+		return ! $this->_remove_expired_lock() ? true : false;
154
+	}
155
+
156
+
157
+	/**
158
+	 * Gets the meta field indicating that this TXN is locked
159
+	 *
160
+	 * @return int
161
+	 * @throws EE_Error
162
+	 * @throws InvalidArgumentException
163
+	 * @throws InvalidDataTypeException
164
+	 * @throws InvalidInterfaceException
165
+	 * @throws ReflectionException
166
+	 */
167
+	protected function _get_lock()
168
+	{
169
+		return (int) $this->get_extra_meta('lock', true, 0);
170
+	}
171
+
172
+
173
+	/**
174
+	 * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
175
+	 *
176
+	 * @return int
177
+	 * @throws EE_Error
178
+	 * @throws InvalidArgumentException
179
+	 * @throws InvalidDataTypeException
180
+	 * @throws InvalidInterfaceException
181
+	 * @throws ReflectionException
182
+	 */
183
+	protected function _remove_expired_lock()
184
+	{
185
+		$locked = $this->_get_lock();
186
+		if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
187
+			return $this->unlock();
188
+		}
189
+		return 0;
190
+	}
191
+
192
+
193
+	/**
194
+	 * Set transaction total
195
+	 *
196
+	 * @param float $total total value of transaction
197
+	 * @throws EE_Error
198
+	 * @throws InvalidArgumentException
199
+	 * @throws InvalidDataTypeException
200
+	 * @throws InvalidInterfaceException
201
+	 * @throws ReflectionException
202
+	 */
203
+	public function set_total($total = 0.00)
204
+	{
205
+		$this->set('TXN_total', (float) $total);
206
+	}
207
+
208
+
209
+	/**
210
+	 * Set Total Amount Paid to Date
211
+	 *
212
+	 * @param float $total_paid total amount paid to date (sum of all payments)
213
+	 * @throws EE_Error
214
+	 * @throws InvalidArgumentException
215
+	 * @throws InvalidDataTypeException
216
+	 * @throws InvalidInterfaceException
217
+	 * @throws ReflectionException
218
+	 */
219
+	public function set_paid($total_paid = 0.00)
220
+	{
221
+		$this->set('TXN_paid', (float) $total_paid);
222
+	}
223
+
224
+
225
+	/**
226
+	 * Set transaction status
227
+	 *
228
+	 * @param string $status        whether the transaction is open, declined, accepted,
229
+	 *                              or any number of custom values that can be set
230
+	 * @throws EE_Error
231
+	 * @throws InvalidArgumentException
232
+	 * @throws InvalidDataTypeException
233
+	 * @throws InvalidInterfaceException
234
+	 * @throws ReflectionException
235
+	 */
236
+	public function set_status($status = '')
237
+	{
238
+		$this->set('STS_ID', $status);
239
+	}
240
+
241
+
242
+	/**
243
+	 * Set hash salt
244
+	 *
245
+	 * @param string $hash_salt required for some payment gateways
246
+	 * @throws EE_Error
247
+	 * @throws InvalidArgumentException
248
+	 * @throws InvalidDataTypeException
249
+	 * @throws InvalidInterfaceException
250
+	 * @throws ReflectionException
251
+	 */
252
+	public function set_hash_salt($hash_salt = '')
253
+	{
254
+		$this->set('TXN_hash_salt', $hash_salt);
255
+	}
256
+
257
+
258
+	/**
259
+	 * Sets TXN_reg_steps array
260
+	 *
261
+	 * @param array $txn_reg_steps
262
+	 * @throws EE_Error
263
+	 * @throws InvalidArgumentException
264
+	 * @throws InvalidDataTypeException
265
+	 * @throws InvalidInterfaceException
266
+	 * @throws ReflectionException
267
+	 */
268
+	public function set_reg_steps(array $txn_reg_steps)
269
+	{
270
+		$this->set('TXN_reg_steps', $txn_reg_steps);
271
+	}
272
+
273
+
274
+	/**
275
+	 * Gets TXN_reg_steps
276
+	 *
277
+	 * @return array
278
+	 * @throws EE_Error
279
+	 * @throws InvalidArgumentException
280
+	 * @throws InvalidDataTypeException
281
+	 * @throws InvalidInterfaceException
282
+	 * @throws ReflectionException
283
+	 */
284
+	public function reg_steps()
285
+	{
286
+		$TXN_reg_steps = $this->get('TXN_reg_steps');
287
+		return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array();
288
+	}
289
+
290
+
291
+	/**
292
+	 * @return string of transaction's total cost, with currency symbol and decimal
293
+	 * @throws EE_Error
294
+	 * @throws InvalidArgumentException
295
+	 * @throws InvalidDataTypeException
296
+	 * @throws InvalidInterfaceException
297
+	 * @throws ReflectionException
298
+	 */
299
+	public function pretty_total()
300
+	{
301
+		return $this->get_pretty('TXN_total');
302
+	}
303
+
304
+
305
+	/**
306
+	 * Gets the amount paid in a pretty string (formatted and with currency symbol)
307
+	 *
308
+	 * @return string
309
+	 * @throws EE_Error
310
+	 * @throws InvalidArgumentException
311
+	 * @throws InvalidDataTypeException
312
+	 * @throws InvalidInterfaceException
313
+	 * @throws ReflectionException
314
+	 */
315
+	public function pretty_paid()
316
+	{
317
+		return $this->get_pretty('TXN_paid');
318
+	}
319
+
320
+
321
+	/**
322
+	 * calculate the amount remaining for this transaction and return;
323
+	 *
324
+	 * @return float amount remaining
325
+	 * @throws EE_Error
326
+	 * @throws InvalidArgumentException
327
+	 * @throws InvalidDataTypeException
328
+	 * @throws InvalidInterfaceException
329
+	 * @throws ReflectionException
330
+	 */
331
+	public function remaining()
332
+	{
333
+		return $this->total() - $this->paid();
334
+	}
335
+
336
+
337
+	/**
338
+	 * get Transaction Total
339
+	 *
340
+	 * @return float
341
+	 * @throws EE_Error
342
+	 * @throws InvalidArgumentException
343
+	 * @throws InvalidDataTypeException
344
+	 * @throws InvalidInterfaceException
345
+	 * @throws ReflectionException
346
+	 */
347
+	public function total()
348
+	{
349
+		return (float) $this->get('TXN_total');
350
+	}
351
+
352
+
353
+	/**
354
+	 * get Total Amount Paid to Date
355
+	 *
356
+	 * @return float
357
+	 * @throws EE_Error
358
+	 * @throws InvalidArgumentException
359
+	 * @throws InvalidDataTypeException
360
+	 * @throws InvalidInterfaceException
361
+	 * @throws ReflectionException
362
+	 */
363
+	public function paid()
364
+	{
365
+		return (float) $this->get('TXN_paid');
366
+	}
367
+
368
+
369
+	/**
370
+	 * @return mixed|null
371
+	 * @throws EE_Error
372
+	 * @throws InvalidArgumentException
373
+	 * @throws InvalidDataTypeException
374
+	 * @throws InvalidInterfaceException
375
+	 * @throws ReflectionException
376
+	 */
377
+	public function get_cart_session()
378
+	{
379
+		$session_data = (array) $this->get('TXN_session_data');
380
+		return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
381
+			? $session_data['cart']
382
+			: null;
383
+	}
384
+
385
+
386
+	/**
387
+	 * get Transaction session data
388
+	 *
389
+	 * @return array|mixed
390
+	 * @throws EE_Error
391
+	 * @throws InvalidArgumentException
392
+	 * @throws InvalidDataTypeException
393
+	 * @throws InvalidInterfaceException
394
+	 * @throws ReflectionException
395
+	 */
396
+	public function session_data()
397
+	{
398
+		$session_data = $this->get('TXN_session_data');
399
+		if (empty($session_data)) {
400
+			$session_data = array(
401
+				'id'            => null,
402
+				'user_id'       => null,
403
+				'ip_address'    => null,
404
+				'user_agent'    => null,
405
+				'init_access'   => null,
406
+				'last_access'   => null,
407
+				'pages_visited' => array(),
408
+			);
409
+		}
410
+		return $session_data;
411
+	}
412
+
413
+
414
+	/**
415
+	 * Set session data within the TXN object
416
+	 *
417
+	 * @param EE_Session|array $session_data
418
+	 * @throws EE_Error
419
+	 * @throws InvalidArgumentException
420
+	 * @throws InvalidDataTypeException
421
+	 * @throws InvalidInterfaceException
422
+	 * @throws ReflectionException
423
+	 */
424
+	public function set_txn_session_data($session_data)
425
+	{
426
+		if ($session_data instanceof EE_Session) {
427
+			$this->set('TXN_session_data', $session_data->get_session_data(null, true));
428
+		} else {
429
+			$this->set('TXN_session_data', $session_data);
430
+		}
431
+	}
432
+
433
+
434
+	/**
435
+	 * get Transaction hash salt
436
+	 *
437
+	 * @return mixed
438
+	 * @throws EE_Error
439
+	 * @throws InvalidArgumentException
440
+	 * @throws InvalidDataTypeException
441
+	 * @throws InvalidInterfaceException
442
+	 * @throws ReflectionException
443
+	 */
444
+	public function hash_salt_()
445
+	{
446
+		return $this->get('TXN_hash_salt');
447
+	}
448
+
449
+
450
+	/**
451
+	 * Returns the transaction datetime as either:
452
+	 *            - unix timestamp format ($format = false, $gmt = true)
453
+	 *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
454
+	 *              has no affect with this option)), this also may include a timezone abbreviation if the
455
+	 *              set timezone in this class differs from what the timezone is on the blog.
456
+	 *            - formatted date string including the UTC (timezone) offset (default).
457
+	 *
458
+	 * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
459
+	 * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
460
+	 *                          or no UTC offset applied
461
+	 * @return string | int
462
+	 * @throws EE_Error
463
+	 * @throws InvalidArgumentException
464
+	 * @throws InvalidDataTypeException
465
+	 * @throws InvalidInterfaceException
466
+	 * @throws ReflectionException
467
+	 */
468
+	public function datetime($format = false, $gmt = false)
469
+	{
470
+		if ($format) {
471
+			return $this->get_pretty('TXN_timestamp');
472
+		}
473
+		if ($gmt) {
474
+			return $this->get_raw('TXN_timestamp');
475
+		}
476
+		return $this->get('TXN_timestamp');
477
+	}
478
+
479
+
480
+	/**
481
+	 * Gets registrations on this transaction
482
+	 *
483
+	 * @param array   $query_params array of query parameters
484
+	 * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
485
+	 * @return EE_Base_Class[]|EE_Registration[]
486
+	 * @throws EE_Error
487
+	 * @throws InvalidArgumentException
488
+	 * @throws InvalidDataTypeException
489
+	 * @throws InvalidInterfaceException
490
+	 * @throws ReflectionException
491
+	 */
492
+	public function registrations($query_params = array(), $get_cached = false)
493
+	{
494
+		$query_params = (empty($query_params) || ! is_array($query_params))
495
+			? array(
496
+				'order_by' => array(
497
+					'Event.EVT_name'     => 'ASC',
498
+					'Attendee.ATT_lname' => 'ASC',
499
+					'Attendee.ATT_fname' => 'ASC',
500
+				),
501
+			)
502
+			: $query_params;
503
+		$query_params = $get_cached ? array() : $query_params;
504
+		return $this->get_many_related('Registration', $query_params);
505
+	}
506
+
507
+
508
+	/**
509
+	 * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
510
+	 * function for getting attendees and how many registrations they each have for an event)
511
+	 *
512
+	 * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
513
+	 * @throws EE_Error
514
+	 * @throws InvalidArgumentException
515
+	 * @throws InvalidDataTypeException
516
+	 * @throws InvalidInterfaceException
517
+	 * @throws ReflectionException
518
+	 */
519
+	public function attendees()
520
+	{
521
+		return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID())));
522
+	}
523
+
524
+
525
+	/**
526
+	 * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
527
+	 *
528
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
529
+	 * @return EE_Base_Class[]|EE_Payment[]
530
+	 * @throws EE_Error
531
+	 * @throws InvalidArgumentException
532
+	 * @throws InvalidDataTypeException
533
+	 * @throws InvalidInterfaceException
534
+	 * @throws ReflectionException
535
+	 */
536
+	public function payments($query_params = array())
537
+	{
538
+		return $this->get_many_related('Payment', $query_params);
539
+	}
540
+
541
+
542
+	/**
543
+	 * gets only approved payments for this transaction
544
+	 *
545
+	 * @return EE_Base_Class[]|EE_Payment[]
546
+	 * @throws EE_Error
547
+	 * @throws InvalidArgumentException
548
+	 * @throws ReflectionException
549
+	 * @throws InvalidDataTypeException
550
+	 * @throws InvalidInterfaceException
551
+	 */
552
+	public function approved_payments()
553
+	{
554
+		EE_Registry::instance()->load_model('Payment');
555
+		return $this->get_many_related(
556
+			'Payment',
557
+			array(
558
+				array('STS_ID' => EEM_Payment::status_id_approved),
559
+				'order_by' => array('PAY_timestamp' => 'DESC'),
560
+			)
561
+		);
562
+	}
563
+
564
+
565
+	/**
566
+	 * Gets all payments which have not been approved
567
+	 *
568
+	 * @return EE_Base_Class[]|EEI_Payment[]
569
+	 * @throws EE_Error if a model is misconfigured somehow
570
+	 * @throws InvalidArgumentException
571
+	 * @throws InvalidDataTypeException
572
+	 * @throws InvalidInterfaceException
573
+	 * @throws ReflectionException
574
+	 */
575
+	public function pending_payments()
576
+	{
577
+		return $this->get_many_related(
578
+			'Payment',
579
+			array(
580
+				array(
581
+					'STS_ID' => EEM_Payment::status_id_pending,
582
+				),
583
+				'order_by' => array(
584
+					'PAY_timestamp' => 'DESC',
585
+				),
586
+			)
587
+		);
588
+	}
589
+
590
+
591
+	/**
592
+	 * echoes $this->pretty_status()
593
+	 *
594
+	 * @param bool $show_icons
595
+	 * @throws EE_Error
596
+	 * @throws InvalidArgumentException
597
+	 * @throws InvalidDataTypeException
598
+	 * @throws InvalidInterfaceException
599
+	 * @throws ReflectionException
600
+	 */
601
+	public function e_pretty_status($show_icons = false)
602
+	{
603
+		echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
604
+	}
605
+
606
+
607
+	/**
608
+	 * returns a pretty version of the status, good for displaying to users
609
+	 *
610
+	 * @param bool $show_icons
611
+	 * @return string
612
+	 * @throws EE_Error
613
+	 * @throws InvalidArgumentException
614
+	 * @throws InvalidDataTypeException
615
+	 * @throws InvalidInterfaceException
616
+	 * @throws ReflectionException
617
+	 */
618
+	public function pretty_status($show_icons = false)
619
+	{
620
+		$status = EEM_Status::instance()->localized_status(
621
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
622
+			false,
623
+			'sentence'
624
+		);
625
+		$icon = '';
626
+		switch ($this->status_ID()) {
627
+			case EEM_Transaction::complete_status_code:
628
+				$icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
629
+				break;
630
+			case EEM_Transaction::incomplete_status_code:
631
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
632
+					: '';
633
+				break;
634
+			case EEM_Transaction::abandoned_status_code:
635
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
636
+				break;
637
+			case EEM_Transaction::failed_status_code:
638
+				$icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
639
+				break;
640
+			case EEM_Transaction::overpaid_status_code:
641
+				$icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
642
+				break;
643
+		}
644
+		return $icon . $status[ $this->status_ID() ];
645
+	}
646
+
647
+
648
+	/**
649
+	 * get Transaction Status
650
+	 *
651
+	 * @return mixed
652
+	 * @throws EE_Error
653
+	 * @throws InvalidArgumentException
654
+	 * @throws InvalidDataTypeException
655
+	 * @throws InvalidInterfaceException
656
+	 * @throws ReflectionException
657
+	 */
658
+	public function status_ID()
659
+	{
660
+		return $this->get('STS_ID');
661
+	}
662
+
663
+
664
+	/**
665
+	 * Returns TRUE or FALSE for whether or not this transaction cost any money
666
+	 *
667
+	 * @return boolean
668
+	 * @throws EE_Error
669
+	 * @throws InvalidArgumentException
670
+	 * @throws InvalidDataTypeException
671
+	 * @throws InvalidInterfaceException
672
+	 * @throws ReflectionException
673
+	 */
674
+	public function is_free()
675
+	{
676
+		return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
677
+	}
678
+
679
+
680
+	/**
681
+	 * Returns whether this transaction is complete
682
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
683
+	 *
684
+	 * @return boolean
685
+	 * @throws EE_Error
686
+	 * @throws InvalidArgumentException
687
+	 * @throws InvalidDataTypeException
688
+	 * @throws InvalidInterfaceException
689
+	 * @throws ReflectionException
690
+	 */
691
+	public function is_completed()
692
+	{
693
+		return $this->status_ID() === EEM_Transaction::complete_status_code;
694
+	}
695
+
696
+
697
+	/**
698
+	 * Returns whether this transaction is incomplete
699
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
700
+	 *
701
+	 * @return boolean
702
+	 * @throws EE_Error
703
+	 * @throws InvalidArgumentException
704
+	 * @throws InvalidDataTypeException
705
+	 * @throws InvalidInterfaceException
706
+	 * @throws ReflectionException
707
+	 */
708
+	public function is_incomplete()
709
+	{
710
+		return $this->status_ID() === EEM_Transaction::incomplete_status_code;
711
+	}
712
+
713
+
714
+	/**
715
+	 * Returns whether this transaction is overpaid
716
+	 * Useful in templates and other logic for deciding if monies need to be refunded
717
+	 *
718
+	 * @return boolean
719
+	 * @throws EE_Error
720
+	 * @throws InvalidArgumentException
721
+	 * @throws InvalidDataTypeException
722
+	 * @throws InvalidInterfaceException
723
+	 * @throws ReflectionException
724
+	 */
725
+	public function is_overpaid()
726
+	{
727
+		return $this->status_ID() === EEM_Transaction::overpaid_status_code;
728
+	}
729
+
730
+
731
+	/**
732
+	 * Returns whether this transaction was abandoned
733
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
734
+	 * but that contact information exists for at least one registrant
735
+	 *
736
+	 * @return boolean
737
+	 * @throws EE_Error
738
+	 * @throws InvalidArgumentException
739
+	 * @throws InvalidDataTypeException
740
+	 * @throws InvalidInterfaceException
741
+	 * @throws ReflectionException
742
+	 */
743
+	public function is_abandoned()
744
+	{
745
+		return $this->status_ID() === EEM_Transaction::abandoned_status_code;
746
+	}
747
+
748
+
749
+	/**
750
+	 * Returns whether this transaction failed
751
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
752
+	 * and that NO contact information exists for any registrants
753
+	 *
754
+	 * @return boolean
755
+	 * @throws EE_Error
756
+	 * @throws InvalidArgumentException
757
+	 * @throws InvalidDataTypeException
758
+	 * @throws InvalidInterfaceException
759
+	 * @throws ReflectionException
760
+	 */
761
+	public function failed()
762
+	{
763
+		return $this->status_ID() === EEM_Transaction::failed_status_code;
764
+	}
765
+
766
+
767
+	/**
768
+	 * This returns the url for the invoice of this transaction
769
+	 *
770
+	 * @param string $type 'html' or 'pdf' (default is pdf)
771
+	 * @return string
772
+	 * @throws EE_Error
773
+	 * @throws InvalidArgumentException
774
+	 * @throws InvalidDataTypeException
775
+	 * @throws InvalidInterfaceException
776
+	 * @throws ReflectionException
777
+	 */
778
+	public function invoice_url($type = 'html')
779
+	{
780
+		$REG = $this->primary_registration();
781
+		if (! $REG instanceof EE_Registration) {
782
+			return '';
783
+		}
784
+		return $REG->invoice_url($type);
785
+	}
786
+
787
+
788
+	/**
789
+	 * Gets the primary registration only
790
+	 *
791
+	 * @return EE_Base_Class|EE_Registration
792
+	 * @throws EE_Error
793
+	 * @throws InvalidArgumentException
794
+	 * @throws InvalidDataTypeException
795
+	 * @throws InvalidInterfaceException
796
+	 * @throws ReflectionException
797
+	 */
798
+	public function primary_registration()
799
+	{
800
+		$registrations = (array) $this->get_many_related(
801
+			'Registration',
802
+			array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT))
803
+		);
804
+		foreach ($registrations as $registration) {
805
+			// valid registration that is NOT cancelled or declined ?
806
+			if (
807
+				$registration instanceof EE_Registration
808
+				&& ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
809
+			) {
810
+				return $registration;
811
+			}
812
+		}
813
+		// nothing valid found, so just return first thing from array of results
814
+		return reset($registrations);
815
+	}
816
+
817
+
818
+	/**
819
+	 * Gets the URL for viewing the receipt
820
+	 *
821
+	 * @param string $type 'pdf' or 'html' (default is 'html')
822
+	 * @return string
823
+	 * @throws EE_Error
824
+	 * @throws InvalidArgumentException
825
+	 * @throws InvalidDataTypeException
826
+	 * @throws InvalidInterfaceException
827
+	 * @throws ReflectionException
828
+	 */
829
+	public function receipt_url($type = 'html')
830
+	{
831
+		$REG = $this->primary_registration();
832
+		if (! $REG instanceof EE_Registration) {
833
+			return '';
834
+		}
835
+		return $REG->receipt_url($type);
836
+	}
837
+
838
+
839
+	/**
840
+	 * Gets the URL of the thank you page with this registration REG_url_link added as
841
+	 * a query parameter
842
+	 *
843
+	 * @return string
844
+	 * @throws EE_Error
845
+	 * @throws InvalidArgumentException
846
+	 * @throws InvalidDataTypeException
847
+	 * @throws InvalidInterfaceException
848
+	 * @throws ReflectionException
849
+	 */
850
+	public function payment_overview_url()
851
+	{
852
+		$primary_registration = $this->primary_registration();
853
+		return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
854
+	}
855
+
856
+
857
+	/**
858
+	 * @return string
859
+	 * @throws EE_Error
860
+	 * @throws InvalidArgumentException
861
+	 * @throws InvalidDataTypeException
862
+	 * @throws InvalidInterfaceException
863
+	 * @throws ReflectionException
864
+	 */
865
+	public function gateway_response_on_transaction()
866
+	{
867
+		$payment = $this->get_first_related('Payment');
868
+		return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
869
+	}
870
+
871
+
872
+	/**
873
+	 * Get the status object of this object
874
+	 *
875
+	 * @return EE_Base_Class|EE_Status
876
+	 * @throws EE_Error
877
+	 * @throws InvalidArgumentException
878
+	 * @throws InvalidDataTypeException
879
+	 * @throws InvalidInterfaceException
880
+	 * @throws ReflectionException
881
+	 */
882
+	public function status_obj()
883
+	{
884
+		return $this->get_first_related('Status');
885
+	}
886
+
887
+
888
+	/**
889
+	 * Gets all the extra meta info on this payment
890
+	 *
891
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
892
+	 * @return EE_Base_Class[]|EE_Extra_Meta
893
+	 * @throws EE_Error
894
+	 * @throws InvalidArgumentException
895
+	 * @throws InvalidDataTypeException
896
+	 * @throws InvalidInterfaceException
897
+	 * @throws ReflectionException
898
+	 */
899
+	public function extra_meta($query_params = array())
900
+	{
901
+		return $this->get_many_related('Extra_Meta', $query_params);
902
+	}
903
+
904
+
905
+	/**
906
+	 * Wrapper for _add_relation_to
907
+	 *
908
+	 * @param EE_Registration $registration
909
+	 * @return EE_Base_Class the relation was added to
910
+	 * @throws EE_Error
911
+	 * @throws InvalidArgumentException
912
+	 * @throws InvalidDataTypeException
913
+	 * @throws InvalidInterfaceException
914
+	 * @throws ReflectionException
915
+	 */
916
+	public function add_registration(EE_Registration $registration)
917
+	{
918
+		return $this->_add_relation_to($registration, 'Registration');
919
+	}
920
+
921
+
922
+	/**
923
+	 * Removes the given registration from being related (even before saving this transaction).
924
+	 * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
925
+	 *
926
+	 * @param int $registration_or_id
927
+	 * @return EE_Base_Class that was removed from being related
928
+	 * @throws EE_Error
929
+	 * @throws InvalidArgumentException
930
+	 * @throws InvalidDataTypeException
931
+	 * @throws InvalidInterfaceException
932
+	 * @throws ReflectionException
933
+	 */
934
+	public function remove_registration_with_id($registration_or_id)
935
+	{
936
+		return $this->_remove_relation_to($registration_or_id, 'Registration');
937
+	}
938
+
939
+
940
+	/**
941
+	 * Gets all the line items which are for ACTUAL items
942
+	 *
943
+	 * @return EE_Line_Item[]
944
+	 * @throws EE_Error
945
+	 * @throws InvalidArgumentException
946
+	 * @throws InvalidDataTypeException
947
+	 * @throws InvalidInterfaceException
948
+	 * @throws ReflectionException
949
+	 */
950
+	public function items_purchased()
951
+	{
952
+		return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item)));
953
+	}
954
+
955
+
956
+	/**
957
+	 * Wrapper for _add_relation_to
958
+	 *
959
+	 * @param EE_Line_Item $line_item
960
+	 * @return EE_Base_Class the relation was added to
961
+	 * @throws EE_Error
962
+	 * @throws InvalidArgumentException
963
+	 * @throws InvalidDataTypeException
964
+	 * @throws InvalidInterfaceException
965
+	 * @throws ReflectionException
966
+	 */
967
+	public function add_line_item(EE_Line_Item $line_item)
968
+	{
969
+		return $this->_add_relation_to($line_item, 'Line_Item');
970
+	}
971
+
972
+
973
+	/**
974
+	 * Gets ALL the line items related to this transaction (unstructured)
975
+	 *
976
+	 * @param array $query_params
977
+	 * @return EE_Base_Class[]|EE_Line_Item[]
978
+	 * @throws EE_Error
979
+	 * @throws InvalidArgumentException
980
+	 * @throws InvalidDataTypeException
981
+	 * @throws InvalidInterfaceException
982
+	 * @throws ReflectionException
983
+	 */
984
+	public function line_items($query_params = array())
985
+	{
986
+		return $this->get_many_related('Line_Item', $query_params);
987
+	}
988
+
989
+
990
+	/**
991
+	 * Gets all the line items which are taxes on the total
992
+	 *
993
+	 * @return EE_Line_Item[]
994
+	 * @throws EE_Error
995
+	 * @throws InvalidArgumentException
996
+	 * @throws InvalidDataTypeException
997
+	 * @throws InvalidInterfaceException
998
+	 * @throws ReflectionException
999
+	 */
1000
+	public function tax_items()
1001
+	{
1002
+		return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax)));
1003
+	}
1004
+
1005
+
1006
+	/**
1007
+	 * Gets the total line item (which is a parent of all other related line items,
1008
+	 * meaning it takes them all into account on its total)
1009
+	 *
1010
+	 * @param bool $create_if_not_found
1011
+	 * @return \EE_Line_Item
1012
+	 * @throws EE_Error
1013
+	 * @throws InvalidArgumentException
1014
+	 * @throws InvalidDataTypeException
1015
+	 * @throws InvalidInterfaceException
1016
+	 * @throws ReflectionException
1017
+	 */
1018
+	public function total_line_item($create_if_not_found = true)
1019
+	{
1020
+		$item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
1021
+		if (! $item && $create_if_not_found) {
1022
+			$item = EEH_Line_Item::create_total_line_item($this);
1023
+		}
1024
+		return $item;
1025
+	}
1026
+
1027
+
1028
+	/**
1029
+	 * Returns the total amount of tax on this transaction
1030
+	 * (assumes there's only one tax subtotal line item)
1031
+	 *
1032
+	 * @return float
1033
+	 * @throws EE_Error
1034
+	 * @throws InvalidArgumentException
1035
+	 * @throws InvalidDataTypeException
1036
+	 * @throws InvalidInterfaceException
1037
+	 * @throws ReflectionException
1038
+	 */
1039
+	public function tax_total()
1040
+	{
1041
+		$tax_line_item = $this->tax_total_line_item();
1042
+		if ($tax_line_item) {
1043
+			return (float) $tax_line_item->total();
1044
+		}
1045
+		return (float) 0;
1046
+	}
1047
+
1048
+
1049
+	/**
1050
+	 * Gets the tax subtotal line item (assumes there's only one)
1051
+	 *
1052
+	 * @return EE_Line_Item
1053
+	 * @throws EE_Error
1054
+	 * @throws InvalidArgumentException
1055
+	 * @throws InvalidDataTypeException
1056
+	 * @throws InvalidInterfaceException
1057
+	 * @throws ReflectionException
1058
+	 */
1059
+	public function tax_total_line_item()
1060
+	{
1061
+		return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
1062
+	}
1063
+
1064
+
1065
+	/**
1066
+	 * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
1067
+	 *
1068
+	 * @return EE_Form_Section_Proper
1069
+	 * @throws EE_Error
1070
+	 * @throws InvalidArgumentException
1071
+	 * @throws InvalidDataTypeException
1072
+	 * @throws InvalidInterfaceException
1073
+	 * @throws ReflectionException
1074
+	 */
1075
+	public function billing_info()
1076
+	{
1077
+		$payment_method = $this->payment_method();
1078
+		if (! $payment_method) {
1079
+			EE_Error::add_error(
1080
+				esc_html__(
1081
+					'Could not find billing info for transaction because no gateway has been used for it yet',
1082
+					'event_espresso'
1083
+				),
1084
+				__FILE__,
1085
+				__FUNCTION__,
1086
+				__LINE__
1087
+			);
1088
+			return null;
1089
+		}
1090
+		$primary_reg = $this->primary_registration();
1091
+		if (! $primary_reg) {
1092
+			EE_Error::add_error(
1093
+				esc_html__(
1094
+					'Cannot get billing info for gateway %s on transaction because no primary registration exists',
1095
+					'event_espresso'
1096
+				),
1097
+				__FILE__,
1098
+				__FUNCTION__,
1099
+				__LINE__
1100
+			);
1101
+			return null;
1102
+		}
1103
+		$attendee = $primary_reg->attendee();
1104
+		if (! $attendee) {
1105
+			EE_Error::add_error(
1106
+				esc_html__(
1107
+					'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
1108
+					'event_espresso'
1109
+				),
1110
+				__FILE__,
1111
+				__FUNCTION__,
1112
+				__LINE__
1113
+			);
1114
+			return null;
1115
+		}
1116
+		return $attendee->billing_info_for_payment_method($payment_method);
1117
+	}
1118
+
1119
+
1120
+	/**
1121
+	 * Gets PMD_ID
1122
+	 *
1123
+	 * @return int
1124
+	 * @throws EE_Error
1125
+	 * @throws InvalidArgumentException
1126
+	 * @throws InvalidDataTypeException
1127
+	 * @throws InvalidInterfaceException
1128
+	 * @throws ReflectionException
1129
+	 */
1130
+	public function payment_method_ID()
1131
+	{
1132
+		return $this->get('PMD_ID');
1133
+	}
1134
+
1135
+
1136
+	/**
1137
+	 * Sets PMD_ID
1138
+	 *
1139
+	 * @param int $PMD_ID
1140
+	 * @throws EE_Error
1141
+	 * @throws InvalidArgumentException
1142
+	 * @throws InvalidDataTypeException
1143
+	 * @throws InvalidInterfaceException
1144
+	 * @throws ReflectionException
1145
+	 */
1146
+	public function set_payment_method_ID($PMD_ID)
1147
+	{
1148
+		$this->set('PMD_ID', $PMD_ID);
1149
+	}
1150
+
1151
+
1152
+	/**
1153
+	 * Gets the last-used payment method on this transaction
1154
+	 * (we COULD just use the last-made payment, but some payment methods, namely
1155
+	 * offline ones, dont' create payments)
1156
+	 *
1157
+	 * @return EE_Payment_Method
1158
+	 * @throws EE_Error
1159
+	 * @throws InvalidArgumentException
1160
+	 * @throws InvalidDataTypeException
1161
+	 * @throws InvalidInterfaceException
1162
+	 * @throws ReflectionException
1163
+	 */
1164
+	public function payment_method()
1165
+	{
1166
+		$pm = $this->get_first_related('Payment_Method');
1167
+		if ($pm instanceof EE_Payment_Method) {
1168
+			return $pm;
1169
+		}
1170
+		$last_payment = $this->last_payment();
1171
+		if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
1172
+			return $last_payment->payment_method();
1173
+		}
1174
+		return null;
1175
+	}
1176
+
1177
+
1178
+	/**
1179
+	 * Gets the last payment made
1180
+	 *
1181
+	 * @return EE_Base_Class|EE_Payment
1182
+	 * @throws EE_Error
1183
+	 * @throws InvalidArgumentException
1184
+	 * @throws InvalidDataTypeException
1185
+	 * @throws InvalidInterfaceException
1186
+	 * @throws ReflectionException
1187
+	 */
1188
+	public function last_payment()
1189
+	{
1190
+		return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc')));
1191
+	}
1192
+
1193
+
1194
+	/**
1195
+	 * Gets all the line items which are unrelated to tickets on this transaction
1196
+	 *
1197
+	 * @return EE_Line_Item[]
1198
+	 * @throws EE_Error
1199
+	 * @throws InvalidArgumentException
1200
+	 * @throws InvalidDataTypeException
1201
+	 * @throws InvalidInterfaceException
1202
+	 * @throws ReflectionException
1203
+	 */
1204
+	public function non_ticket_line_items()
1205
+	{
1206
+		return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
1207
+	}
1208
+
1209
+
1210
+	/**
1211
+	 * possibly toggles TXN status
1212
+	 *
1213
+	 * @param  boolean $update whether to save the TXN
1214
+	 * @return bool whether the TXN was saved
1215
+	 * @throws EE_Error
1216
+	 * @throws InvalidArgumentException
1217
+	 * @throws InvalidDataTypeException
1218
+	 * @throws InvalidInterfaceException
1219
+	 * @throws ReflectionException
1220
+	 * @throws RuntimeException
1221
+	 */
1222
+	public function update_status_based_on_total_paid($update = true)
1223
+	{
1224
+		// set transaction status based on comparison of TXN_paid vs TXN_total
1225
+		if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
1226
+			$new_txn_status = EEM_Transaction::overpaid_status_code;
1227
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
1228
+			$new_txn_status = EEM_Transaction::complete_status_code;
1229
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
1230
+			$new_txn_status = EEM_Transaction::incomplete_status_code;
1231
+		} else {
1232
+			throw new RuntimeException(
1233
+				esc_html__('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1234
+			);
1235
+		}
1236
+		if ($new_txn_status !== $this->status_ID()) {
1237
+			$this->set_status($new_txn_status);
1238
+			if ($update) {
1239
+				return $this->save() ? true : false;
1240
+			}
1241
+		}
1242
+		return false;
1243
+	}
1244
+
1245
+
1246
+	/**
1247
+	 * Updates the transaction's status and total_paid based on all the payments
1248
+	 * that apply to it
1249
+	 *
1250
+	 * @deprecated
1251
+	 * @return array|bool
1252
+	 * @throws EE_Error
1253
+	 * @throws InvalidArgumentException
1254
+	 * @throws ReflectionException
1255
+	 * @throws InvalidDataTypeException
1256
+	 * @throws InvalidInterfaceException
1257
+	 */
1258
+	public function update_based_on_payments()
1259
+	{
1260
+		EE_Error::doing_it_wrong(
1261
+			__CLASS__ . '::' . __FUNCTION__,
1262
+			sprintf(
1263
+				esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1264
+				'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1265
+			),
1266
+			'4.6.0'
1267
+		);
1268
+		/** @type EE_Transaction_Processor $transaction_processor */
1269
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1270
+		return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1271
+	}
1272
+
1273
+
1274
+	/**
1275
+	 * @return string
1276
+	 */
1277
+	public function old_txn_status()
1278
+	{
1279
+		return $this->_old_txn_status;
1280
+	}
1281
+
1282
+
1283
+	/**
1284
+	 * @param string $old_txn_status
1285
+	 */
1286
+	public function set_old_txn_status($old_txn_status)
1287
+	{
1288
+		// only set the first time
1289
+		if ($this->_old_txn_status === null) {
1290
+			$this->_old_txn_status = $old_txn_status;
1291
+		}
1292
+	}
1293
+
1294
+
1295
+	/**
1296
+	 * reg_status_updated
1297
+	 *
1298
+	 * @return bool
1299
+	 * @throws EE_Error
1300
+	 * @throws InvalidArgumentException
1301
+	 * @throws InvalidDataTypeException
1302
+	 * @throws InvalidInterfaceException
1303
+	 * @throws ReflectionException
1304
+	 */
1305
+	public function txn_status_updated()
1306
+	{
1307
+		return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1308
+	}
1309
+
1310
+
1311
+	/**
1312
+	 * _reg_steps_completed
1313
+	 * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1314
+	 * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1315
+	 * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1316
+	 *
1317
+	 * @param string $reg_step_slug
1318
+	 * @param bool   $check_all
1319
+	 * @return bool|int
1320
+	 * @throws EE_Error
1321
+	 * @throws InvalidArgumentException
1322
+	 * @throws InvalidDataTypeException
1323
+	 * @throws InvalidInterfaceException
1324
+	 * @throws ReflectionException
1325
+	 */
1326
+	private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1327
+	{
1328
+		$reg_steps = $this->reg_steps();
1329
+		if (! is_array($reg_steps) || empty($reg_steps)) {
1330
+			return false;
1331
+		}
1332
+		// loop thru reg steps array)
1333
+		foreach ($reg_steps as $slug => $reg_step_completed) {
1334
+			// if NOT checking ALL steps (only checking one step)
1335
+			if (! $check_all) {
1336
+				// and this is the one
1337
+				if ($slug === $reg_step_slug) {
1338
+					return $reg_step_completed;
1339
+				}
1340
+				// skip to next reg step in loop
1341
+				continue;
1342
+			}
1343
+			// $check_all must be true, else we would never have gotten to this point
1344
+			if ($slug === $reg_step_slug) {
1345
+				// if we reach this point, then we are testing either:
1346
+				// all_reg_steps_completed_except() or
1347
+				// all_reg_steps_completed_except_final_step(),
1348
+				// and since this is the reg step EXCEPTION being tested
1349
+				// we want to return true (yes true) if this reg step is NOT completed
1350
+				// ie: "is everything completed except the final step?"
1351
+				// "that is correct... the final step is not completed, but all others are."
1352
+				return $reg_step_completed !== true;
1353
+			}
1354
+			if ($reg_step_completed !== true) {
1355
+				// if any reg step is NOT completed, then ALL steps are not completed
1356
+				return false;
1357
+			}
1358
+		}
1359
+		return true;
1360
+	}
1361
+
1362
+
1363
+	/**
1364
+	 * all_reg_steps_completed
1365
+	 * returns:
1366
+	 *    true if ALL reg steps have been marked as completed
1367
+	 *        or false if any step is not completed
1368
+	 *
1369
+	 * @return bool
1370
+	 * @throws EE_Error
1371
+	 * @throws InvalidArgumentException
1372
+	 * @throws InvalidDataTypeException
1373
+	 * @throws InvalidInterfaceException
1374
+	 * @throws ReflectionException
1375
+	 */
1376
+	public function all_reg_steps_completed()
1377
+	{
1378
+		return $this->_reg_steps_completed();
1379
+	}
1380
+
1381
+
1382
+	/**
1383
+	 * all_reg_steps_completed_except
1384
+	 * returns:
1385
+	 *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1386
+	 *        or false if any other step is not completed
1387
+	 *        or false if ALL steps are completed including the exception you are testing !!!
1388
+	 *
1389
+	 * @param string $exception
1390
+	 * @return bool
1391
+	 * @throws EE_Error
1392
+	 * @throws InvalidArgumentException
1393
+	 * @throws InvalidDataTypeException
1394
+	 * @throws InvalidInterfaceException
1395
+	 * @throws ReflectionException
1396
+	 */
1397
+	public function all_reg_steps_completed_except($exception = '')
1398
+	{
1399
+		return $this->_reg_steps_completed($exception);
1400
+	}
1401
+
1402
+
1403
+	/**
1404
+	 * all_reg_steps_completed_except
1405
+	 * returns:
1406
+	 *        true if ALL reg steps, except the final step, have been marked as completed
1407
+	 *        or false if any step is not completed
1408
+	 *    or false if ALL steps are completed including the final step !!!
1409
+	 *
1410
+	 * @return bool
1411
+	 * @throws EE_Error
1412
+	 * @throws InvalidArgumentException
1413
+	 * @throws InvalidDataTypeException
1414
+	 * @throws InvalidInterfaceException
1415
+	 * @throws ReflectionException
1416
+	 */
1417
+	public function all_reg_steps_completed_except_final_step()
1418
+	{
1419
+		return $this->_reg_steps_completed('finalize_registration');
1420
+	}
1421
+
1422
+
1423
+	/**
1424
+	 * reg_step_completed
1425
+	 * returns:
1426
+	 *    true if a specific reg step has been marked as completed
1427
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1428
+	 *    or false if it has not yet been initialized
1429
+	 *
1430
+	 * @param string $reg_step_slug
1431
+	 * @return bool|int
1432
+	 * @throws EE_Error
1433
+	 * @throws InvalidArgumentException
1434
+	 * @throws InvalidDataTypeException
1435
+	 * @throws InvalidInterfaceException
1436
+	 * @throws ReflectionException
1437
+	 */
1438
+	public function reg_step_completed($reg_step_slug)
1439
+	{
1440
+		return $this->_reg_steps_completed($reg_step_slug, false);
1441
+	}
1442
+
1443
+
1444
+	/**
1445
+	 * completed_final_reg_step
1446
+	 * returns:
1447
+	 *    true if the finalize_registration reg step has been marked as completed
1448
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1449
+	 *    or false if it has not yet been initialized
1450
+	 *
1451
+	 * @return bool|int
1452
+	 * @throws EE_Error
1453
+	 * @throws InvalidArgumentException
1454
+	 * @throws InvalidDataTypeException
1455
+	 * @throws InvalidInterfaceException
1456
+	 * @throws ReflectionException
1457
+	 */
1458
+	public function final_reg_step_completed()
1459
+	{
1460
+		return $this->_reg_steps_completed('finalize_registration', false);
1461
+	}
1462
+
1463
+
1464
+	/**
1465
+	 * set_reg_step_initiated
1466
+	 * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1467
+	 *
1468
+	 * @param string $reg_step_slug
1469
+	 * @return boolean
1470
+	 * @throws EE_Error
1471
+	 * @throws InvalidArgumentException
1472
+	 * @throws InvalidDataTypeException
1473
+	 * @throws InvalidInterfaceException
1474
+	 * @throws ReflectionException
1475
+	 */
1476
+	public function set_reg_step_initiated($reg_step_slug)
1477
+	{
1478
+		return $this->_set_reg_step_completed_status($reg_step_slug, time());
1479
+	}
1480
+
1481
+
1482
+	/**
1483
+	 * set_reg_step_completed
1484
+	 * given a valid TXN_reg_step, this sets the step as completed
1485
+	 *
1486
+	 * @param string $reg_step_slug
1487
+	 * @return boolean
1488
+	 * @throws EE_Error
1489
+	 * @throws InvalidArgumentException
1490
+	 * @throws InvalidDataTypeException
1491
+	 * @throws InvalidInterfaceException
1492
+	 * @throws ReflectionException
1493
+	 */
1494
+	public function set_reg_step_completed($reg_step_slug)
1495
+	{
1496
+		return $this->_set_reg_step_completed_status($reg_step_slug, true);
1497
+	}
1498
+
1499
+
1500
+	/**
1501
+	 * set_reg_step_completed
1502
+	 * given a valid TXN_reg_step slug, this sets the step as NOT completed
1503
+	 *
1504
+	 * @param string $reg_step_slug
1505
+	 * @return boolean
1506
+	 * @throws EE_Error
1507
+	 * @throws InvalidArgumentException
1508
+	 * @throws InvalidDataTypeException
1509
+	 * @throws InvalidInterfaceException
1510
+	 * @throws ReflectionException
1511
+	 */
1512
+	public function set_reg_step_not_completed($reg_step_slug)
1513
+	{
1514
+		return $this->_set_reg_step_completed_status($reg_step_slug, false);
1515
+	}
1516
+
1517
+
1518
+	/**
1519
+	 * set_reg_step_completed
1520
+	 * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1521
+	 *
1522
+	 * @param  string      $reg_step_slug
1523
+	 * @param  boolean|int $status
1524
+	 * @return boolean
1525
+	 * @throws EE_Error
1526
+	 * @throws InvalidArgumentException
1527
+	 * @throws InvalidDataTypeException
1528
+	 * @throws InvalidInterfaceException
1529
+	 * @throws ReflectionException
1530
+	 */
1531
+	private function _set_reg_step_completed_status($reg_step_slug, $status)
1532
+	{
1533
+		// validate status
1534
+		$status = is_bool($status) || is_int($status) ? $status : false;
1535
+		// get reg steps array
1536
+		$txn_reg_steps = $this->reg_steps();
1537
+		// if reg step does NOT exist
1538
+		if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1539
+			return false;
1540
+		}
1541
+		// if  we're trying to complete a step that is already completed
1542
+		if ($txn_reg_steps[ $reg_step_slug ] === true) {
1543
+			return true;
1544
+		}
1545
+		// if  we're trying to complete a step that hasn't even started
1546
+		if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1547
+			return false;
1548
+		}
1549
+		// if current status value matches the incoming value (no change)
1550
+		// type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1551
+		if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1552
+			// this will happen in cases where multiple AJAX requests occur during the same step
1553
+			return true;
1554
+		}
1555
+		// if we're trying to set a start time, but it has already been set...
1556
+		if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1557
+			// skip the update below, but don't return FALSE so that errors won't be displayed
1558
+			return true;
1559
+		}
1560
+		// update completed status
1561
+		$txn_reg_steps[ $reg_step_slug ] = $status;
1562
+		$this->set_reg_steps($txn_reg_steps);
1563
+		$this->save();
1564
+		return true;
1565
+	}
1566
+
1567
+
1568
+	/**
1569
+	 * remove_reg_step
1570
+	 * given a valid TXN_reg_step slug, this will remove (unset)
1571
+	 * the reg step from the TXN reg step array
1572
+	 *
1573
+	 * @param string $reg_step_slug
1574
+	 * @return void
1575
+	 * @throws EE_Error
1576
+	 * @throws InvalidArgumentException
1577
+	 * @throws InvalidDataTypeException
1578
+	 * @throws InvalidInterfaceException
1579
+	 * @throws ReflectionException
1580
+	 */
1581
+	public function remove_reg_step($reg_step_slug)
1582
+	{
1583
+		// get reg steps array
1584
+		$txn_reg_steps = $this->reg_steps();
1585
+		unset($txn_reg_steps[ $reg_step_slug ]);
1586
+		$this->set_reg_steps($txn_reg_steps);
1587
+	}
1588
+
1589
+
1590
+	/**
1591
+	 * toggle_failed_transaction_status
1592
+	 * upgrades a TXNs status from failed to abandoned,
1593
+	 * meaning that contact information has been captured for at least one registrant
1594
+	 *
1595
+	 * @param bool $save
1596
+	 * @return bool
1597
+	 * @throws EE_Error
1598
+	 * @throws InvalidArgumentException
1599
+	 * @throws InvalidDataTypeException
1600
+	 * @throws InvalidInterfaceException
1601
+	 * @throws ReflectionException
1602
+	 */
1603
+	public function toggle_failed_transaction_status($save = true)
1604
+	{
1605
+		// if TXN status is still set as "failed"...
1606
+		if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1607
+			$this->set_status(EEM_Transaction::abandoned_status_code);
1608
+			if ($save) {
1609
+				$this->save();
1610
+			}
1611
+			return true;
1612
+		}
1613
+		return false;
1614
+	}
1615
+
1616
+
1617
+	/**
1618
+	 * toggle_abandoned_transaction_status
1619
+	 * upgrades a TXNs status from failed or abandoned to incomplete
1620
+	 *
1621
+	 * @return bool
1622
+	 * @throws EE_Error
1623
+	 * @throws InvalidArgumentException
1624
+	 * @throws InvalidDataTypeException
1625
+	 * @throws InvalidInterfaceException
1626
+	 * @throws ReflectionException
1627
+	 */
1628
+	public function toggle_abandoned_transaction_status()
1629
+	{
1630
+		// if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1631
+		$txn_status = $this->status_ID();
1632
+		if (
1633
+			$txn_status === EEM_Transaction::failed_status_code
1634
+			|| $txn_status === EEM_Transaction::abandoned_status_code
1635
+		) {
1636
+			// if a contact record for the primary registrant has been created
1637
+			if (
1638
+				$this->primary_registration() instanceof EE_Registration
1639
+				&& $this->primary_registration()->attendee() instanceof EE_Attendee
1640
+			) {
1641
+				$this->set_status(EEM_Transaction::incomplete_status_code);
1642
+			} else {
1643
+				// no contact record? yer abandoned!
1644
+				$this->set_status(EEM_Transaction::abandoned_status_code);
1645
+			}
1646
+			return true;
1647
+		}
1648
+		return false;
1649
+	}
1650
+
1651
+
1652
+	/**
1653
+	 * checks if an Abandoned TXN has any related payments, and if so,
1654
+	 * updates the TXN status based on the amount paid
1655
+	 *
1656
+	 * @throws EE_Error
1657
+	 * @throws InvalidDataTypeException
1658
+	 * @throws InvalidInterfaceException
1659
+	 * @throws InvalidArgumentException
1660
+	 * @throws RuntimeException
1661
+	 * @throws ReflectionException
1662
+	 */
1663
+	public function verify_abandoned_transaction_status()
1664
+	{
1665
+		if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1666
+			return;
1667
+		}
1668
+		$payments = $this->get_many_related('Payment');
1669
+		if (! empty($payments)) {
1670
+			foreach ($payments as $payment) {
1671
+				if ($payment instanceof EE_Payment) {
1672
+					// kk this TXN should NOT be abandoned
1673
+					$this->update_status_based_on_total_paid();
1674
+					if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1675
+						EE_Error::add_attention(
1676
+							sprintf(
1677
+								esc_html__(
1678
+									'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.',
1679
+									'event_espresso'
1680
+								),
1681
+								$this->ID(),
1682
+								$this->pretty_status()
1683
+							)
1684
+						);
1685
+					}
1686
+					// get final reg step status
1687
+					$finalized = $this->final_reg_step_completed();
1688
+					// if the 'finalize_registration' step has been initiated (has a timestamp)
1689
+					// but has not yet been fully completed (TRUE)
1690
+					if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1691
+						$this->set_reg_step_completed('finalize_registration');
1692
+						$this->save();
1693
+					}
1694
+				}
1695
+			}
1696
+		}
1697
+	}
1698
+
1699
+
1700
+	/**
1701
+	 * @since 4.10.4.p
1702
+	 * @throws EE_Error
1703
+	 * @throws InvalidArgumentException
1704
+	 * @throws InvalidDataTypeException
1705
+	 * @throws InvalidInterfaceException
1706
+	 * @throws ReflectionException
1707
+	 * @throws RuntimeException
1708
+	 */
1709
+	public function recalculateLineItems()
1710
+	{
1711
+		$total_line_item = $this->total_line_item(false);
1712
+		if ($total_line_item instanceof EE_Line_Item) {
1713
+			EEH_Line_Item::resetIsTaxableForTickets($total_line_item);
1714
+			return EEH_Line_Item::apply_taxes($total_line_item, true);
1715
+		}
1716
+		return false;
1717
+	}
1718 1718
 }
Please login to merge, or discard this patch.
core/libraries/form_sections/inputs/EE_Admin_File_Uploader_Input.input.php 1 patch
Indentation   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -14,27 +14,27 @@
 block discarded – undo
14 14
 class EE_Admin_File_Uploader_Input extends EE_Form_Input_Base
15 15
 {
16 16
 
17
-    /**
18
-     * @param array $input_settings
19
-     * @throws InvalidArgumentException
20
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
21
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
22
-     */
23
-    public function __construct($input_settings = array())
24
-    {
25
-        $this->_set_display_strategy(new EE_Admin_File_Uploader_Display_Strategy());
26
-        $this->_set_normalization_strategy(new EE_Text_Normalization());
27
-        $this->_add_validation_strategy(
28
-            LoaderFactory::getLoader()->getNew(
29
-                'EE_URL_Validation_Strategy',
30
-                array(
31
-                    isset($input_settings['validation_error_message'])
32
-                        ? $input_settings['validation_error_message']
33
-                        : null,
34
-                    false
35
-                )
36
-            )
37
-        );
38
-        parent::__construct($input_settings);
39
-    }
17
+	/**
18
+	 * @param array $input_settings
19
+	 * @throws InvalidArgumentException
20
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
21
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
22
+	 */
23
+	public function __construct($input_settings = array())
24
+	{
25
+		$this->_set_display_strategy(new EE_Admin_File_Uploader_Display_Strategy());
26
+		$this->_set_normalization_strategy(new EE_Text_Normalization());
27
+		$this->_add_validation_strategy(
28
+			LoaderFactory::getLoader()->getNew(
29
+				'EE_URL_Validation_Strategy',
30
+				array(
31
+					isset($input_settings['validation_error_message'])
32
+						? $input_settings['validation_error_message']
33
+						: null,
34
+					false
35
+				)
36
+			)
37
+		);
38
+		parent::__construct($input_settings);
39
+	}
40 40
 }
Please login to merge, or discard this patch.
admin_pages/events/Event_Categories_Admin_List_Table.class.php 2 patches
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -82,9 +82,9 @@  discard block
 block discarded – undo
82 82
     public function column_id($item)
83 83
     {
84 84
         $content = $item->get('term_id');
85
-        $content .= '  <span class="show-on-mobile-view-only">' . $item->get_first_related('Term')->get(
85
+        $content .= '  <span class="show-on-mobile-view-only">'.$item->get_first_related('Term')->get(
86 86
             'name'
87
-        ) . '</span>';
87
+        ).'</span>';
88 88
         return $content;
89 89
     }
90 90
 
@@ -105,16 +105,16 @@  discard block
 block discarded – undo
105 105
         $delete_link = EE_Admin_Page::add_query_args_and_nonce($delete_query_args, EVENTS_ADMIN_URL);
106 106
 
107 107
         $actions = array(
108
-            'edit' => '<a href="' . $edit_link . '" aria-label="' . esc_attr__(
108
+            'edit' => '<a href="'.$edit_link.'" aria-label="'.esc_attr__(
109 109
                 'Edit Category',
110 110
                 'event_espresso'
111
-            ) . '">' . esc_html__('Edit', 'event_espresso') . '</a>',
111
+            ).'">'.esc_html__('Edit', 'event_espresso').'</a>',
112 112
         );
113 113
 
114
-        $actions['delete'] = '<a href="' . $delete_link . '" aria-label="' . esc_attr__(
114
+        $actions['delete'] = '<a href="'.$delete_link.'" aria-label="'.esc_attr__(
115 115
             'Delete Category',
116 116
             'event_espresso'
117
-        ) . '">' . esc_html__('Delete', 'event_espresso') . '</a>';
117
+        ).'">'.esc_html__('Delete', 'event_espresso').'</a>';
118 118
 
119 119
         $actions['view'] = sprintf(
120 120
             '<a href="%s" aria-label="%s">%s</a>',
@@ -129,9 +129,9 @@  discard block
 block discarded – undo
129 129
             esc_html__('View', 'event_espresso')
130 130
         );
131 131
 
132
-        $content = '<strong><a class="row-title" href="' . $edit_link . '">' . $item->get_first_related('Term')->get(
132
+        $content = '<strong><a class="row-title" href="'.$edit_link.'">'.$item->get_first_related('Term')->get(
133 133
             'name'
134
-        ) . '</a></strong>';
134
+        ).'</a></strong>';
135 135
         $content .= $this->row_actions($actions);
136 136
         return $content;
137 137
     }
@@ -139,7 +139,7 @@  discard block
 block discarded – undo
139 139
 
140 140
     public function column_shortcode($item)
141 141
     {
142
-        $content = '[ESPRESSO_EVENTS category_slug=' . $item->get_first_related('Term')->get('slug') . ']';
142
+        $content = '[ESPRESSO_EVENTS category_slug='.$item->get_first_related('Term')->get('slug').']';
143 143
         return $content;
144 144
     }
145 145
 
@@ -151,7 +151,7 @@  discard block
 block discarded – undo
151 151
             'EVT_CAT' => $item->get_first_related('Term')->ID(),
152 152
         );
153 153
         $e_link = EE_Admin_Page::add_query_args_and_nonce($e_args, EVENTS_ADMIN_URL);
154
-        $content = '<a href="' . $e_link . '">' . $item->get('term_count') . '</a>';
154
+        $content = '<a href="'.$e_link.'">'.$item->get('term_count').'</a>';
155 155
         return $content;
156 156
     }
157 157
 }
Please login to merge, or discard this patch.
Indentation   +138 added lines, -138 removed lines patch added patch discarded remove patch
@@ -16,142 +16,142 @@
 block discarded – undo
16 16
 class Event_Categories_Admin_List_Table extends EE_Admin_List_Table
17 17
 {
18 18
 
19
-    public function __construct($admin_page)
20
-    {
21
-        parent::__construct($admin_page);
22
-    }
23
-
24
-
25
-    protected function _setup_data()
26
-    {
27
-        $this->_data = $this->_admin_page->get_categories($this->_per_page, $this->_current_page);
28
-        $this->_all_data_count = EEM_Term_Taxonomy::instance()->count(
29
-            array(array('taxonomy' => 'espresso_event_categories'))
30
-        );
31
-    }
32
-
33
-
34
-    protected function _set_properties()
35
-    {
36
-        $this->_wp_list_args = array(
37
-            'singular' => esc_html__('event category', 'event_espresso'),
38
-            'plural'   => esc_html__('event categories', 'event_espresso'),
39
-            'ajax'     => true, // for now,
40
-            'screen'   => $this->_admin_page->get_current_screen()->id,
41
-        );
42
-
43
-        $this->_columns = array(
44
-            'cb'        => '<input type="checkbox" />',
45
-            'id'        => esc_html__('ID', 'event_espresso'),
46
-            'name'      => esc_html__('Name', 'event_espresso'),
47
-            'shortcode' => esc_html__('Shortcode', 'event_espresso'),
48
-            'count'     => esc_html__('Events', 'event_espresso'),
49
-        );
50
-
51
-        $this->_sortable_columns = array(
52
-            'id'    => array('Term.term_id' => true),
53
-            'name'  => array('Term.slug' => false),
54
-            'count' => array('term_count' => false),
55
-        );
56
-
57
-        $this->_primary_column = 'id';
58
-
59
-        $this->_hidden_columns = array();
60
-    }
61
-
62
-
63
-    // not needed
64
-    protected function _get_table_filters()
65
-    {
66
-        return array();
67
-    }
68
-
69
-
70
-    protected function _add_view_counts()
71
-    {
72
-        $this->_views['all']['count'] = $this->_all_data_count;
73
-    }
74
-
75
-
76
-    public function column_cb($item)
77
-    {
78
-        return sprintf('<input type="checkbox" name="EVT_CAT_ID[]" value="%s" />', $item->get('term_id'));
79
-    }
80
-
81
-
82
-    public function column_id($item)
83
-    {
84
-        $content = $item->get('term_id');
85
-        $content .= '  <span class="show-on-mobile-view-only">' . $item->get_first_related('Term')->get(
86
-            'name'
87
-        ) . '</span>';
88
-        return $content;
89
-    }
90
-
91
-
92
-    public function column_name($item)
93
-    {
94
-        $edit_query_args = array(
95
-            'action'     => 'edit_category',
96
-            'EVT_CAT_ID' => $item->get('term_id'),
97
-        );
98
-
99
-        $delete_query_args = array(
100
-            'action'     => 'delete_category',
101
-            'EVT_CAT_ID' => $item->get('term_id'),
102
-        );
103
-
104
-        $edit_link = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
105
-        $delete_link = EE_Admin_Page::add_query_args_and_nonce($delete_query_args, EVENTS_ADMIN_URL);
106
-
107
-        $actions = array(
108
-            'edit' => '<a href="' . $edit_link . '" aria-label="' . esc_attr__(
109
-                'Edit Category',
110
-                'event_espresso'
111
-            ) . '">' . esc_html__('Edit', 'event_espresso') . '</a>',
112
-        );
113
-
114
-        $actions['delete'] = '<a href="' . $delete_link . '" aria-label="' . esc_attr__(
115
-            'Delete Category',
116
-            'event_espresso'
117
-        ) . '">' . esc_html__('Delete', 'event_espresso') . '</a>';
118
-
119
-        $actions['view'] = sprintf(
120
-            '<a href="%s" aria-label="%s">%s</a>',
121
-            get_term_link($item->get('term_id')),
122
-            esc_attr(
123
-                sprintf(
124
-                    /* translators: %s: event category name */
125
-                    esc_html__('View &#8220;%s&#8221; archive', 'event_espresso'),
126
-                    $item->get_first_related('Term')->get('name')
127
-                )
128
-            ),
129
-            esc_html__('View', 'event_espresso')
130
-        );
131
-
132
-        $content = '<strong><a class="row-title" href="' . $edit_link . '">' . $item->get_first_related('Term')->get(
133
-            'name'
134
-        ) . '</a></strong>';
135
-        $content .= $this->row_actions($actions);
136
-        return $content;
137
-    }
138
-
139
-
140
-    public function column_shortcode($item)
141
-    {
142
-        $content = '[ESPRESSO_EVENTS category_slug=' . $item->get_first_related('Term')->get('slug') . ']';
143
-        return $content;
144
-    }
145
-
146
-
147
-    public function column_count($item)
148
-    {
149
-        $e_args = array(
150
-            'action'  => 'default',
151
-            'EVT_CAT' => $item->get_first_related('Term')->ID(),
152
-        );
153
-        $e_link = EE_Admin_Page::add_query_args_and_nonce($e_args, EVENTS_ADMIN_URL);
154
-        $content = '<a href="' . $e_link . '">' . $item->get('term_count') . '</a>';
155
-        return $content;
156
-    }
19
+	public function __construct($admin_page)
20
+	{
21
+		parent::__construct($admin_page);
22
+	}
23
+
24
+
25
+	protected function _setup_data()
26
+	{
27
+		$this->_data = $this->_admin_page->get_categories($this->_per_page, $this->_current_page);
28
+		$this->_all_data_count = EEM_Term_Taxonomy::instance()->count(
29
+			array(array('taxonomy' => 'espresso_event_categories'))
30
+		);
31
+	}
32
+
33
+
34
+	protected function _set_properties()
35
+	{
36
+		$this->_wp_list_args = array(
37
+			'singular' => esc_html__('event category', 'event_espresso'),
38
+			'plural'   => esc_html__('event categories', 'event_espresso'),
39
+			'ajax'     => true, // for now,
40
+			'screen'   => $this->_admin_page->get_current_screen()->id,
41
+		);
42
+
43
+		$this->_columns = array(
44
+			'cb'        => '<input type="checkbox" />',
45
+			'id'        => esc_html__('ID', 'event_espresso'),
46
+			'name'      => esc_html__('Name', 'event_espresso'),
47
+			'shortcode' => esc_html__('Shortcode', 'event_espresso'),
48
+			'count'     => esc_html__('Events', 'event_espresso'),
49
+		);
50
+
51
+		$this->_sortable_columns = array(
52
+			'id'    => array('Term.term_id' => true),
53
+			'name'  => array('Term.slug' => false),
54
+			'count' => array('term_count' => false),
55
+		);
56
+
57
+		$this->_primary_column = 'id';
58
+
59
+		$this->_hidden_columns = array();
60
+	}
61
+
62
+
63
+	// not needed
64
+	protected function _get_table_filters()
65
+	{
66
+		return array();
67
+	}
68
+
69
+
70
+	protected function _add_view_counts()
71
+	{
72
+		$this->_views['all']['count'] = $this->_all_data_count;
73
+	}
74
+
75
+
76
+	public function column_cb($item)
77
+	{
78
+		return sprintf('<input type="checkbox" name="EVT_CAT_ID[]" value="%s" />', $item->get('term_id'));
79
+	}
80
+
81
+
82
+	public function column_id($item)
83
+	{
84
+		$content = $item->get('term_id');
85
+		$content .= '  <span class="show-on-mobile-view-only">' . $item->get_first_related('Term')->get(
86
+			'name'
87
+		) . '</span>';
88
+		return $content;
89
+	}
90
+
91
+
92
+	public function column_name($item)
93
+	{
94
+		$edit_query_args = array(
95
+			'action'     => 'edit_category',
96
+			'EVT_CAT_ID' => $item->get('term_id'),
97
+		);
98
+
99
+		$delete_query_args = array(
100
+			'action'     => 'delete_category',
101
+			'EVT_CAT_ID' => $item->get('term_id'),
102
+		);
103
+
104
+		$edit_link = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
105
+		$delete_link = EE_Admin_Page::add_query_args_and_nonce($delete_query_args, EVENTS_ADMIN_URL);
106
+
107
+		$actions = array(
108
+			'edit' => '<a href="' . $edit_link . '" aria-label="' . esc_attr__(
109
+				'Edit Category',
110
+				'event_espresso'
111
+			) . '">' . esc_html__('Edit', 'event_espresso') . '</a>',
112
+		);
113
+
114
+		$actions['delete'] = '<a href="' . $delete_link . '" aria-label="' . esc_attr__(
115
+			'Delete Category',
116
+			'event_espresso'
117
+		) . '">' . esc_html__('Delete', 'event_espresso') . '</a>';
118
+
119
+		$actions['view'] = sprintf(
120
+			'<a href="%s" aria-label="%s">%s</a>',
121
+			get_term_link($item->get('term_id')),
122
+			esc_attr(
123
+				sprintf(
124
+					/* translators: %s: event category name */
125
+					esc_html__('View &#8220;%s&#8221; archive', 'event_espresso'),
126
+					$item->get_first_related('Term')->get('name')
127
+				)
128
+			),
129
+			esc_html__('View', 'event_espresso')
130
+		);
131
+
132
+		$content = '<strong><a class="row-title" href="' . $edit_link . '">' . $item->get_first_related('Term')->get(
133
+			'name'
134
+		) . '</a></strong>';
135
+		$content .= $this->row_actions($actions);
136
+		return $content;
137
+	}
138
+
139
+
140
+	public function column_shortcode($item)
141
+	{
142
+		$content = '[ESPRESSO_EVENTS category_slug=' . $item->get_first_related('Term')->get('slug') . ']';
143
+		return $content;
144
+	}
145
+
146
+
147
+	public function column_count($item)
148
+	{
149
+		$e_args = array(
150
+			'action'  => 'default',
151
+			'EVT_CAT' => $item->get_first_related('Term')->ID(),
152
+		);
153
+		$e_link = EE_Admin_Page::add_query_args_and_nonce($e_args, EVENTS_ADMIN_URL);
154
+		$content = '<a href="' . $e_link . '">' . $item->get('term_count') . '</a>';
155
+		return $content;
156
+	}
157 157
 }
Please login to merge, or discard this patch.
support/templates/support_admin_details_additional_information.template.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -1,8 +1,8 @@
 block discarded – undo
1 1
 <div class="padding">
2 2
     <p><?php
3
-        printf(
4
-            esc_html__('Check out the %1$sroadmap for Event Espresso%2$s.', 'event_espresso'),
5
-            '<a href="https://trello.com/b/zg9DCIpe/event-espresso-public-roadmap" target="_blank" rel="noopener noreferrer">',
6
-            '</a>'
7
-        ); ?></p>
3
+		printf(
4
+			esc_html__('Check out the %1$sroadmap for Event Espresso%2$s.', 'event_espresso'),
5
+			'<a href="https://trello.com/b/zg9DCIpe/event-espresso-public-roadmap" target="_blank" rel="noopener noreferrer">',
6
+			'</a>'
7
+		); ?></p>
8 8
 </div>
9 9
\ No newline at end of file
Please login to merge, or discard this patch.