Passed
Push — master ( 55fff1...2692d4 )
by Brian
16:18
created
includes/data-stores/class-getpaid-item-data-store.php 1 patch
Indentation   +210 added lines, -210 removed lines patch added patch discarded remove patch
@@ -4,7 +4,7 @@  discard block
 block discarded – undo
4 4
  *
5 5
  */
6 6
 if ( ! defined( 'ABSPATH' ) ) {
7
-	exit;
7
+    exit;
8 8
 }
9 9
 
10 10
 /**
@@ -14,228 +14,228 @@  discard block
 block discarded – undo
14 14
  */
15 15
 class GetPaid_Item_Data_Store extends GetPaid_Data_Store_WP {
16 16
 
17
-	/**
18
-	 * Data stored in meta keys, but not considered "meta" for an item.
19
-	 *
20
-	 * @since 1.0.19
21
-	 * @var array
22
-	 */
23
-	protected $internal_meta_keys = array(
24
-		'_wpinv_price',
25
-		'_wpinv_vat_rule',
26
-		'_wpinv_vat_class',
27
-		'_wpinv_type',
28
-		'_wpinv_custom_id',
29
-		'_wpinv_custom_name',
30
-		'_wpinv_custom_singular_name',
31
-		'_wpinv_editable',
32
-		'_wpinv_dynamic_pricing',
33
-		'_minimum_price',
34
-		'_wpinv_is_recurring',
35
-		'_wpinv_recurring_period',
36
-		'_wpinv_recurring_interval',
37
-		'_wpinv_recurring_limit',
38
-		'_wpinv_free_trial',
39
-		'_wpinv_trial_period',
40
-		'_wpinv_trial_interval',
41
-	);
42
-
43
-	/**
44
-	 * A map of meta keys to data props.
45
-	 *
46
-	 * @since 1.0.19
47
-	 *
48
-	 * @var array
49
-	 */
50
-	protected $meta_key_to_props = array(
51
-		'_wpinv_price'                => 'price',
52
-		'_wpinv_vat_rule'             => 'vat_rule',
53
-		'_wpinv_vat_class'            => 'vat_class',
54
-		'_wpinv_type'                 => 'type',
55
-		'_wpinv_custom_id'            => 'custom_id',
56
-		'_wpinv_custom_name'          => 'custom_name',
57
-		'_wpinv_custom_singular_name' => 'custom_singular_name',
58
-		'_wpinv_editable'             => 'is_editable',
59
-		'_wpinv_dynamic_pricing'      => 'is_dynamic_pricing',
60
-		'_minimum_price'              => 'minimum_price',
61
-		'_wpinv_custom_name'          => 'custom_name',
62
-		'_wpinv_is_recurring'         => 'is_recurring',
63
-		'_wpinv_recurring_period'     => 'recurring_period',
64
-		'_wpinv_recurring_interval'   => 'recurring_interval',
65
-		'_wpinv_recurring_limit'      => 'recurring_limit',
66
-		'_wpinv_free_trial'           => 'is_free_trial',
67
-		'_wpinv_trial_period'         => 'trial_period',
68
-		'_wpinv_trial_interval'       => 'trial_interval',
69
-		'_wpinv_version'              => 'version',
70
-	);
71
-
72
-	/*
17
+    /**
18
+     * Data stored in meta keys, but not considered "meta" for an item.
19
+     *
20
+     * @since 1.0.19
21
+     * @var array
22
+     */
23
+    protected $internal_meta_keys = array(
24
+        '_wpinv_price',
25
+        '_wpinv_vat_rule',
26
+        '_wpinv_vat_class',
27
+        '_wpinv_type',
28
+        '_wpinv_custom_id',
29
+        '_wpinv_custom_name',
30
+        '_wpinv_custom_singular_name',
31
+        '_wpinv_editable',
32
+        '_wpinv_dynamic_pricing',
33
+        '_minimum_price',
34
+        '_wpinv_is_recurring',
35
+        '_wpinv_recurring_period',
36
+        '_wpinv_recurring_interval',
37
+        '_wpinv_recurring_limit',
38
+        '_wpinv_free_trial',
39
+        '_wpinv_trial_period',
40
+        '_wpinv_trial_interval',
41
+    );
42
+
43
+    /**
44
+     * A map of meta keys to data props.
45
+     *
46
+     * @since 1.0.19
47
+     *
48
+     * @var array
49
+     */
50
+    protected $meta_key_to_props = array(
51
+        '_wpinv_price'                => 'price',
52
+        '_wpinv_vat_rule'             => 'vat_rule',
53
+        '_wpinv_vat_class'            => 'vat_class',
54
+        '_wpinv_type'                 => 'type',
55
+        '_wpinv_custom_id'            => 'custom_id',
56
+        '_wpinv_custom_name'          => 'custom_name',
57
+        '_wpinv_custom_singular_name' => 'custom_singular_name',
58
+        '_wpinv_editable'             => 'is_editable',
59
+        '_wpinv_dynamic_pricing'      => 'is_dynamic_pricing',
60
+        '_minimum_price'              => 'minimum_price',
61
+        '_wpinv_custom_name'          => 'custom_name',
62
+        '_wpinv_is_recurring'         => 'is_recurring',
63
+        '_wpinv_recurring_period'     => 'recurring_period',
64
+        '_wpinv_recurring_interval'   => 'recurring_interval',
65
+        '_wpinv_recurring_limit'      => 'recurring_limit',
66
+        '_wpinv_free_trial'           => 'is_free_trial',
67
+        '_wpinv_trial_period'         => 'trial_period',
68
+        '_wpinv_trial_interval'       => 'trial_interval',
69
+        '_wpinv_version'              => 'version',
70
+    );
71
+
72
+    /*
73 73
 	|--------------------------------------------------------------------------
74 74
 	| CRUD Methods
75 75
 	|--------------------------------------------------------------------------
76 76
 	*/
77 77
 
78
-	/**
79
-	 * Method to create a new item in the database.
80
-	 *
81
-	 * @param WPInv_Item $item Item object.
82
-	 */
83
-	public function create( &$item ) {
84
-		$item->set_version( WPINV_VERSION );
85
-		$item->set_date_created( current_time( 'mysql' ) );
86
-
87
-		// Create a new post.
88
-		$id = wp_insert_post(
89
-			apply_filters(
90
-				'getpaid_new_item_data',
91
-				array(
92
-					'post_date'    => $item->get_date_created( 'edit' ),
93
-					'post_type'    => 'wpi_item',
94
-					'post_status'  => $this->get_post_status( $item ),
95
-					'ping_status'  => 'closed',
96
-					'post_author'  => $item->get_author( 'edit' ),
97
-					'post_title'   => $item->get_name( 'edit' ),
98
-					'post_parent'  => $item->get_parent_id(),
99
-					'post_excerpt' => $item->get_description( 'edit' ),
100
-				)
101
-			),
102
-			true
103
-		);
104
-
105
-		if ( $id && ! is_wp_error( $id ) ) {
106
-			$item->set_id( $id );
107
-			$this->update_post_meta( $item );
108
-			$item->save_meta_data();
109
-			$item->apply_changes();
110
-			$this->clear_caches( $item );
111
-			do_action( 'getpaid_new_item', $item );
112
-			return true;
113
-		}
114
-
115
-		if ( is_wp_error( $id ) ) {
116
-			$item->last_error = $id->get_error_message();
117
-		}
118
-
119
-		return false;
120
-	}
121
-
122
-	/**
123
-	 * Method to read an item from the database.
124
-	 *
125
-	 * @param WPInv_Item $item Item object.
126
-	 *
127
-	 */
128
-	public function read( &$item ) {
129
-
130
-		$item->set_defaults();
131
-		$item_object = get_post( $item->get_id() );
132
-
133
-		if ( ! $item->get_id() || ! $item_object || $item_object->post_type != 'wpi_item' ) {
134
-			$item->last_error = __( 'Invalid item.', 'invoicing' );
135
-			$item->set_id( 0 );
136
-			return false;
137
-		}
138
-
139
-		$item->set_props(
140
-			array(
141
-				'parent_id'     => $item_object->post_parent,
142
-				'date_created'  => 0 < $item_object->post_date ? $item_object->post_date : null,
143
-				'date_modified' => 0 < $item_object->post_modified ? $item_object->post_modified : null,
144
-				'status'        => $item_object->post_status,
145
-				'name'          => $item_object->post_title,
146
-				'description'   => $item_object->post_excerpt,
147
-				'author'        => $item_object->post_author,
148
-			)
149
-		);
150
-
151
-		$this->read_object_data( $item, $item_object );
152
-		$item->read_meta_data();
153
-		$item->set_object_read( true );
154
-		do_action( 'getpaid_read_item', $item );
155
-
156
-	}
157
-
158
-	/**
159
-	 * Method to update an item in the database.
160
-	 *
161
-	 * @param WPInv_Item $item Item object.
162
-	 */
163
-	public function update( &$item ) {
164
-		$item->save_meta_data();
165
-		$item->set_version( WPINV_VERSION );
166
-
167
-		if ( null === $item->get_date_created( 'edit' ) ) {
168
-			$item->set_date_created( current_time( 'mysql' ) );
169
-		}
170
-
171
-		// Grab the current status so we can compare.
172
-		$previous_status = get_post_status( $item->get_id() );
173
-
174
-		$changes = $item->get_changes();
175
-
176
-		// Only update the post when the post data changes.
177
-		if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'parent_id', 'description', 'name', 'author' ), array_keys( $changes ) ) ) {
178
-			$post_data = array(
179
-				'post_date'     => $item->get_date_created( 'edit' ),
180
-				'post_status'   => $item->get_status( 'edit' ),
181
-				'post_parent'   => $item->get_parent_id( 'edit' ),
182
-				'post_excerpt'  => $item->get_description( 'edit' ),
183
-				'post_modified' => $item->get_date_modified( 'edit' ),
184
-				'post_title'    => $item->get_name( 'edit' ),
185
-				'post_author'   => $item->get_author( 'edit' ),
186
-			);
187
-
188
-			/**
189
-			 * When updating this object, to prevent infinite loops, use $wpdb
190
-			 * to update data, since wp_update_post spawns more calls to the
191
-			 * save_post action.
192
-			 *
193
-			 * This ensures hooks are fired by either WP itself (admin screen save),
194
-			 * or an update purely from CRUD.
195
-			 */
196
-			if ( doing_action( 'save_post' ) ) {
197
-				$GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $item->get_id() ) );
198
-				clean_post_cache( $item->get_id() );
199
-			} else {
200
-				wp_update_post( array_merge( array( 'ID' => $item->get_id() ), $post_data ) );
201
-			}
202
-			$item->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
203
-		}
204
-		$this->update_post_meta( $item );
205
-		$item->apply_changes();
206
-		$this->clear_caches( $item );
207
-
208
-		// Fire a hook depending on the status - this should be considered a creation if it was previously draft status.
209
-		$new_status = $item->get_status( 'edit' );
210
-
211
-		if ( $new_status !== $previous_status && in_array( $previous_status, array( 'new', 'auto-draft', 'draft' ), true ) ) {
212
-			do_action( 'getpaid_new_item', $item );
213
-		} else {
214
-			do_action( 'getpaid_update_item', $item );
215
-		}
216
-
217
-	}
218
-
219
-	/*
78
+    /**
79
+     * Method to create a new item in the database.
80
+     *
81
+     * @param WPInv_Item $item Item object.
82
+     */
83
+    public function create( &$item ) {
84
+        $item->set_version( WPINV_VERSION );
85
+        $item->set_date_created( current_time( 'mysql' ) );
86
+
87
+        // Create a new post.
88
+        $id = wp_insert_post(
89
+            apply_filters(
90
+                'getpaid_new_item_data',
91
+                array(
92
+                    'post_date'    => $item->get_date_created( 'edit' ),
93
+                    'post_type'    => 'wpi_item',
94
+                    'post_status'  => $this->get_post_status( $item ),
95
+                    'ping_status'  => 'closed',
96
+                    'post_author'  => $item->get_author( 'edit' ),
97
+                    'post_title'   => $item->get_name( 'edit' ),
98
+                    'post_parent'  => $item->get_parent_id(),
99
+                    'post_excerpt' => $item->get_description( 'edit' ),
100
+                )
101
+            ),
102
+            true
103
+        );
104
+
105
+        if ( $id && ! is_wp_error( $id ) ) {
106
+            $item->set_id( $id );
107
+            $this->update_post_meta( $item );
108
+            $item->save_meta_data();
109
+            $item->apply_changes();
110
+            $this->clear_caches( $item );
111
+            do_action( 'getpaid_new_item', $item );
112
+            return true;
113
+        }
114
+
115
+        if ( is_wp_error( $id ) ) {
116
+            $item->last_error = $id->get_error_message();
117
+        }
118
+
119
+        return false;
120
+    }
121
+
122
+    /**
123
+     * Method to read an item from the database.
124
+     *
125
+     * @param WPInv_Item $item Item object.
126
+     *
127
+     */
128
+    public function read( &$item ) {
129
+
130
+        $item->set_defaults();
131
+        $item_object = get_post( $item->get_id() );
132
+
133
+        if ( ! $item->get_id() || ! $item_object || $item_object->post_type != 'wpi_item' ) {
134
+            $item->last_error = __( 'Invalid item.', 'invoicing' );
135
+            $item->set_id( 0 );
136
+            return false;
137
+        }
138
+
139
+        $item->set_props(
140
+            array(
141
+                'parent_id'     => $item_object->post_parent,
142
+                'date_created'  => 0 < $item_object->post_date ? $item_object->post_date : null,
143
+                'date_modified' => 0 < $item_object->post_modified ? $item_object->post_modified : null,
144
+                'status'        => $item_object->post_status,
145
+                'name'          => $item_object->post_title,
146
+                'description'   => $item_object->post_excerpt,
147
+                'author'        => $item_object->post_author,
148
+            )
149
+        );
150
+
151
+        $this->read_object_data( $item, $item_object );
152
+        $item->read_meta_data();
153
+        $item->set_object_read( true );
154
+        do_action( 'getpaid_read_item', $item );
155
+
156
+    }
157
+
158
+    /**
159
+     * Method to update an item in the database.
160
+     *
161
+     * @param WPInv_Item $item Item object.
162
+     */
163
+    public function update( &$item ) {
164
+        $item->save_meta_data();
165
+        $item->set_version( WPINV_VERSION );
166
+
167
+        if ( null === $item->get_date_created( 'edit' ) ) {
168
+            $item->set_date_created( current_time( 'mysql' ) );
169
+        }
170
+
171
+        // Grab the current status so we can compare.
172
+        $previous_status = get_post_status( $item->get_id() );
173
+
174
+        $changes = $item->get_changes();
175
+
176
+        // Only update the post when the post data changes.
177
+        if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'parent_id', 'description', 'name', 'author' ), array_keys( $changes ) ) ) {
178
+            $post_data = array(
179
+                'post_date'     => $item->get_date_created( 'edit' ),
180
+                'post_status'   => $item->get_status( 'edit' ),
181
+                'post_parent'   => $item->get_parent_id( 'edit' ),
182
+                'post_excerpt'  => $item->get_description( 'edit' ),
183
+                'post_modified' => $item->get_date_modified( 'edit' ),
184
+                'post_title'    => $item->get_name( 'edit' ),
185
+                'post_author'   => $item->get_author( 'edit' ),
186
+            );
187
+
188
+            /**
189
+             * When updating this object, to prevent infinite loops, use $wpdb
190
+             * to update data, since wp_update_post spawns more calls to the
191
+             * save_post action.
192
+             *
193
+             * This ensures hooks are fired by either WP itself (admin screen save),
194
+             * or an update purely from CRUD.
195
+             */
196
+            if ( doing_action( 'save_post' ) ) {
197
+                $GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $item->get_id() ) );
198
+                clean_post_cache( $item->get_id() );
199
+            } else {
200
+                wp_update_post( array_merge( array( 'ID' => $item->get_id() ), $post_data ) );
201
+            }
202
+            $item->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
203
+        }
204
+        $this->update_post_meta( $item );
205
+        $item->apply_changes();
206
+        $this->clear_caches( $item );
207
+
208
+        // Fire a hook depending on the status - this should be considered a creation if it was previously draft status.
209
+        $new_status = $item->get_status( 'edit' );
210
+
211
+        if ( $new_status !== $previous_status && in_array( $previous_status, array( 'new', 'auto-draft', 'draft' ), true ) ) {
212
+            do_action( 'getpaid_new_item', $item );
213
+        } else {
214
+            do_action( 'getpaid_update_item', $item );
215
+        }
216
+
217
+    }
218
+
219
+    /*
220 220
 	|--------------------------------------------------------------------------
221 221
 	| Additional Methods
222 222
 	|--------------------------------------------------------------------------
223 223
 	*/
224 224
 
225
-	/**
226
-	 * Helper method that updates all the post meta for an item based on it's settings in the WPInv_Item class.
227
-	 *
228
-	 * @param WPInv_Item $item WPInv_Item object.
229
-	 * @since 1.0.19
230
-	 */
231
-	protected function update_post_meta( &$item ) {
225
+    /**
226
+     * Helper method that updates all the post meta for an item based on it's settings in the WPInv_Item class.
227
+     *
228
+     * @param WPInv_Item $item WPInv_Item object.
229
+     * @since 1.0.19
230
+     */
231
+    protected function update_post_meta( &$item ) {
232 232
 
233
-		// Ensure that we have a custom id.
233
+        // Ensure that we have a custom id.
234 234
         if ( ! $item->get_custom_id() ) {
235 235
             $item->set_custom_id( $item->get_id() );
236
-		}
236
+        }
237 237
 
238
-		parent::update_post_meta( $item );
239
-	}
238
+        parent::update_post_meta( $item );
239
+    }
240 240
 
241 241
 }
Please login to merge, or discard this patch.
includes/payments/class-getpaid-payment-form-submission.php 1 patch
Indentation   +878 added lines, -878 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 if ( ! defined( 'ABSPATH' ) ) {
3
-	exit;
3
+    exit;
4 4
 }
5 5
 
6 6
 /**
@@ -10,199 +10,199 @@  discard block
 block discarded – undo
10 10
 class GetPaid_Payment_Form_Submission {
11 11
 
12 12
     /**
13
-	 * Submission ID
14
-	 *
15
-	 * @var string
16
-	 */
17
-	public $id = null;
18
-
19
-	/**
20
-	 * The raw submission data.
21
-	 *
22
-	 * @var array
23
-	 */
24
-	protected $data = null;
25
-
26
-	/**
27
-	 * Submission totals
28
-	 *
29
-	 * @var array
30
-	 */
31
-	protected $totals = array(
32
-
33
-		'subtotal' => array(
34
-			'initial'   => 0,
35
-			'recurring' => 0,
36
-		),
37
-
38
-		'discount' => array(
39
-			'initial'   => 0,
40
-			'recurring' => 0,
41
-		),
42
-
43
-		'fees'     => array(
44
-			'initial'   => 0,
45
-			'recurring' => 0,
46
-		),
47
-
48
-		'taxes'    => array(
49
-			'initial'   => 0,
50
-			'recurring' => 0,
51
-		),
52
-
53
-		'shipping' => array(
54
-			'initial'   => 0,
55
-			'recurring' => 0,
56
-		),
57
-
58
-	);
59
-
60
-	/**
61
-	 * Sets the associated payment form.
62
-	 *
63
-	 * @var GetPaid_Payment_Form
64
-	 */
13
+     * Submission ID
14
+     *
15
+     * @var string
16
+     */
17
+    public $id = null;
18
+
19
+    /**
20
+     * The raw submission data.
21
+     *
22
+     * @var array
23
+     */
24
+    protected $data = null;
25
+
26
+    /**
27
+     * Submission totals
28
+     *
29
+     * @var array
30
+     */
31
+    protected $totals = array(
32
+
33
+        'subtotal' => array(
34
+            'initial'   => 0,
35
+            'recurring' => 0,
36
+        ),
37
+
38
+        'discount' => array(
39
+            'initial'   => 0,
40
+            'recurring' => 0,
41
+        ),
42
+
43
+        'fees'     => array(
44
+            'initial'   => 0,
45
+            'recurring' => 0,
46
+        ),
47
+
48
+        'taxes'    => array(
49
+            'initial'   => 0,
50
+            'recurring' => 0,
51
+        ),
52
+
53
+        'shipping' => array(
54
+            'initial'   => 0,
55
+            'recurring' => 0,
56
+        ),
57
+
58
+    );
59
+
60
+    /**
61
+     * Sets the associated payment form.
62
+     *
63
+     * @var GetPaid_Payment_Form
64
+     */
65 65
     protected $payment_form = null;
66 66
 
67 67
     /**
68
-	 * The country for the submission.
69
-	 *
70
-	 * @var string
71
-	 */
72
-	public $country = null;
73
-
74
-    /**
75
-	 * The state for the submission.
76
-	 *
77
-	 * @since 1.0.19
78
-	 * @var string
79
-	 */
80
-	public $state = null;
81
-
82
-	/**
83
-	 * The invoice associated with the submission.
84
-	 *
85
-	 * @var WPInv_Invoice
86
-	 */
87
-	protected $invoice = null;
88
-
89
-	/**
90
-	 * The recurring item for the submission.
91
-	 *
92
-	 * @var int
93
-	 */
94
-	public $has_recurring = 0;
95
-
96
-	/**
97
-	 * An array of fees for the submission.
98
-	 *
99
-	 * @var array
100
-	 */
101
-	protected $fees = array();
102
-
103
-	/**
104
-	 * An array of discounts for the submission.
105
-	 *
106
-	 * @var array
107
-	 */
108
-	protected $discounts = array();
109
-
110
-	/**
111
-	 * An array of taxes for the submission.
112
-	 *
113
-	 * @var array
114
-	 */
115
-	protected $taxes = array();
116
-
117
-	/**
118
-	 * An array of items for the submission.
119
-	 *
120
-	 * @var GetPaid_Form_Item[]
121
-	 */
122
-	protected $items = array();
123
-
124
-	/**
125
-	 * The last error.
126
-	 *
127
-	 * @var string
128
-	 */
129
-	public $last_error = null;
130
-
131
-	/**
132
-	 * The last error code.
133
-	 *
134
-	 * @var string
135
-	 */
136
-	public $last_error_code = null;
137
-
138
-    /**
139
-	 * Class constructor.
140
-	 *
141
-	 */
142
-	public function __construct() {
143
-
144
-		// Set the state and country to the default state and country.
145
-		$this->country = wpinv_default_billing_country();
146
-		$this->state   = wpinv_get_default_state();
147
-
148
-		// Do we have an actual submission?
149
-		if ( isset( $_POST['getpaid_payment_form_submission'] ) ) {
150
-			$this->load_data( wp_kses_post_deep( wp_unslash( $_POST ) ) );
151
-		}
152
-
153
-	}
154
-
155
-	/**
156
-	 * Loads submission data.
157
-	 *
158
-	 * @param array $data
159
-	 */
160
-	public function load_data( $data ) {
161
-
162
-		// Allow plugins to filter the data.
163
-		$data       = apply_filters( 'getpaid_submission_data', $data, $this );
164
-
165
-		// Cache it...
166
-		$this->data = $data;
167
-
168
-		// Then generate a unique id from the data.
169
-		$this->id   = md5( wp_json_encode( $data ) );
170
-
171
-		// Finally, process the submission.
172
-		try {
173
-
174
-			// Each process is passed an instance of the class (with reference)
175
-			// and should throw an Exception whenever it encounters one.
176
-			$processors = apply_filters(
177
-				'getpaid_payment_form_submission_processors',
178
-				array(
179
-					array( $this, 'process_payment_form' ),
180
-					array( $this, 'process_invoice' ),
181
-					array( $this, 'process_fees' ),
182
-					array( $this, 'process_items' ),
183
-					array( $this, 'process_discount' ),
184
-					array( $this, 'process_taxes' ),
185
-				),
186
-				$this
187
-			);
188
-
189
-			foreach ( $processors as $processor ) {
190
-				call_user_func_array( $processor, array( &$this ) );
191
-			}
192
-		} catch ( GetPaid_Payment_Exception $e ) {
193
-			$this->last_error      = $e->getMessage();
194
-			$this->last_error_code = $e->getErrorCode();
195
-		} catch ( Exception $e ) {
196
-			$this->last_error      = $e->getMessage();
197
-			$this->last_error_code = $e->getCode();
198
-		}
199
-
200
-		// Fired when we are done processing a submission.
201
-		do_action_ref_array( 'getpaid_process_submission', array( &$this ) );
202
-
203
-	}
204
-
205
-	/*
68
+     * The country for the submission.
69
+     *
70
+     * @var string
71
+     */
72
+    public $country = null;
73
+
74
+    /**
75
+     * The state for the submission.
76
+     *
77
+     * @since 1.0.19
78
+     * @var string
79
+     */
80
+    public $state = null;
81
+
82
+    /**
83
+     * The invoice associated with the submission.
84
+     *
85
+     * @var WPInv_Invoice
86
+     */
87
+    protected $invoice = null;
88
+
89
+    /**
90
+     * The recurring item for the submission.
91
+     *
92
+     * @var int
93
+     */
94
+    public $has_recurring = 0;
95
+
96
+    /**
97
+     * An array of fees for the submission.
98
+     *
99
+     * @var array
100
+     */
101
+    protected $fees = array();
102
+
103
+    /**
104
+     * An array of discounts for the submission.
105
+     *
106
+     * @var array
107
+     */
108
+    protected $discounts = array();
109
+
110
+    /**
111
+     * An array of taxes for the submission.
112
+     *
113
+     * @var array
114
+     */
115
+    protected $taxes = array();
116
+
117
+    /**
118
+     * An array of items for the submission.
119
+     *
120
+     * @var GetPaid_Form_Item[]
121
+     */
122
+    protected $items = array();
123
+
124
+    /**
125
+     * The last error.
126
+     *
127
+     * @var string
128
+     */
129
+    public $last_error = null;
130
+
131
+    /**
132
+     * The last error code.
133
+     *
134
+     * @var string
135
+     */
136
+    public $last_error_code = null;
137
+
138
+    /**
139
+     * Class constructor.
140
+     *
141
+     */
142
+    public function __construct() {
143
+
144
+        // Set the state and country to the default state and country.
145
+        $this->country = wpinv_default_billing_country();
146
+        $this->state   = wpinv_get_default_state();
147
+
148
+        // Do we have an actual submission?
149
+        if ( isset( $_POST['getpaid_payment_form_submission'] ) ) {
150
+            $this->load_data( wp_kses_post_deep( wp_unslash( $_POST ) ) );
151
+        }
152
+
153
+    }
154
+
155
+    /**
156
+     * Loads submission data.
157
+     *
158
+     * @param array $data
159
+     */
160
+    public function load_data( $data ) {
161
+
162
+        // Allow plugins to filter the data.
163
+        $data       = apply_filters( 'getpaid_submission_data', $data, $this );
164
+
165
+        // Cache it...
166
+        $this->data = $data;
167
+
168
+        // Then generate a unique id from the data.
169
+        $this->id   = md5( wp_json_encode( $data ) );
170
+
171
+        // Finally, process the submission.
172
+        try {
173
+
174
+            // Each process is passed an instance of the class (with reference)
175
+            // and should throw an Exception whenever it encounters one.
176
+            $processors = apply_filters(
177
+                'getpaid_payment_form_submission_processors',
178
+                array(
179
+                    array( $this, 'process_payment_form' ),
180
+                    array( $this, 'process_invoice' ),
181
+                    array( $this, 'process_fees' ),
182
+                    array( $this, 'process_items' ),
183
+                    array( $this, 'process_discount' ),
184
+                    array( $this, 'process_taxes' ),
185
+                ),
186
+                $this
187
+            );
188
+
189
+            foreach ( $processors as $processor ) {
190
+                call_user_func_array( $processor, array( &$this ) );
191
+            }
192
+        } catch ( GetPaid_Payment_Exception $e ) {
193
+            $this->last_error      = $e->getMessage();
194
+            $this->last_error_code = $e->getErrorCode();
195
+        } catch ( Exception $e ) {
196
+            $this->last_error      = $e->getMessage();
197
+            $this->last_error_code = $e->getCode();
198
+        }
199
+
200
+        // Fired when we are done processing a submission.
201
+        do_action_ref_array( 'getpaid_process_submission', array( &$this ) );
202
+
203
+    }
204
+
205
+    /*
206 206
 	|--------------------------------------------------------------------------
207 207
 	| Payment Forms.
208 208
 	|--------------------------------------------------------------------------
@@ -211,39 +211,39 @@  discard block
 block discarded – undo
211 211
 	| submission has an active payment form etc.
212 212
     */
213 213
 
214
-	/**
215
-	 * Prepares the submission's payment form.
216
-	 *
217
-	 * @since 1.0.19
218
-	 */
219
-	public function process_payment_form() {
214
+    /**
215
+     * Prepares the submission's payment form.
216
+     *
217
+     * @since 1.0.19
218
+     */
219
+    public function process_payment_form() {
220 220
 
221
-		// Every submission needs an active payment form.
222
-		if ( empty( $this->data['form_id'] ) ) {
223
-			throw new Exception( __( 'Missing payment form', 'invoicing' ) );
224
-		}
221
+        // Every submission needs an active payment form.
222
+        if ( empty( $this->data['form_id'] ) ) {
223
+            throw new Exception( __( 'Missing payment form', 'invoicing' ) );
224
+        }
225 225
 
226
-		// Fetch the payment form.
227
-		$this->payment_form = new GetPaid_Payment_Form( $this->data['form_id'] );
226
+        // Fetch the payment form.
227
+        $this->payment_form = new GetPaid_Payment_Form( $this->data['form_id'] );
228 228
 
229
-		if ( ! $this->payment_form->is_active() ) {
230
-			throw new Exception( __( 'Payment form not active', 'invoicing' ) );
231
-		}
229
+        if ( ! $this->payment_form->is_active() ) {
230
+            throw new Exception( __( 'Payment form not active', 'invoicing' ) );
231
+        }
232 232
 
233
-		do_action_ref_array( 'getpaid_submissions_process_payment_form', array( &$this ) );
234
-	}
233
+        do_action_ref_array( 'getpaid_submissions_process_payment_form', array( &$this ) );
234
+    }
235 235
 
236 236
     /**
237
-	 * Returns the payment form.
238
-	 *
239
-	 * @since 1.0.19
240
-	 * @return GetPaid_Payment_Form
241
-	 */
242
-	public function get_payment_form() {
243
-		return $this->payment_form;
244
-	}
237
+     * Returns the payment form.
238
+     *
239
+     * @since 1.0.19
240
+     * @return GetPaid_Payment_Form
241
+     */
242
+    public function get_payment_form() {
243
+        return $this->payment_form;
244
+    }
245 245
 
246
-	/*
246
+    /*
247 247
 	|--------------------------------------------------------------------------
248 248
 	| Invoices.
249 249
 	|--------------------------------------------------------------------------
@@ -252,95 +252,95 @@  discard block
 block discarded – undo
252 252
 	| might be for an existing invoice.
253 253
 	*/
254 254
 
255
-	/**
256
-	 * Prepares the submission's invoice.
257
-	 *
258
-	 * @since 1.0.19
259
-	 */
260
-	public function process_invoice() {
261
-
262
-		// Abort if there is no invoice.
263
-		if ( empty( $this->data['invoice_id'] ) ) {
264
-
265
-			// Check if we are resuming a payment.
266
-			if ( empty( $this->data['maybe_use_invoice'] ) ) {
267
-				return;
268
-			}
269
-
270
-			$invoice = wpinv_get_invoice( $this->data['maybe_use_invoice'] );
271
-			if ( empty( $invoice ) || ! $invoice->has_status( 'draft, auto-draft, wpi-pending' ) ) {
272
-				return;
273
-			}
274
-		}
275
-
276
-		// If the submission is for an existing invoice, ensure that it exists
277
-		// and that it is not paid for.
278
-		if ( empty( $invoice ) ) {
279
-			$invoice = wpinv_get_invoice( $this->data['invoice_id'] );
280
-		}
255
+    /**
256
+     * Prepares the submission's invoice.
257
+     *
258
+     * @since 1.0.19
259
+     */
260
+    public function process_invoice() {
261
+
262
+        // Abort if there is no invoice.
263
+        if ( empty( $this->data['invoice_id'] ) ) {
264
+
265
+            // Check if we are resuming a payment.
266
+            if ( empty( $this->data['maybe_use_invoice'] ) ) {
267
+                return;
268
+            }
269
+
270
+            $invoice = wpinv_get_invoice( $this->data['maybe_use_invoice'] );
271
+            if ( empty( $invoice ) || ! $invoice->has_status( 'draft, auto-draft, wpi-pending' ) ) {
272
+                return;
273
+            }
274
+        }
275
+
276
+        // If the submission is for an existing invoice, ensure that it exists
277
+        // and that it is not paid for.
278
+        if ( empty( $invoice ) ) {
279
+            $invoice = wpinv_get_invoice( $this->data['invoice_id'] );
280
+        }
281 281
 
282 282
         if ( empty( $invoice ) ) {
283
-			throw new Exception( __( 'Invalid invoice', 'invoicing' ) );
284
-		}
285
-
286
-		if ( $invoice->is_paid() ) {
287
-			throw new Exception( __( 'This invoice is already paid for.', 'invoicing' ) );
288
-		}
289
-
290
-		$this->payment_form->invoice = $invoice;
291
-		if ( ! $this->payment_form->is_default() ) {
292
-
293
-			$items    = array();
294
-			$item_ids = array();
295
-
296
-			foreach ( $invoice->get_items() as $item ) {
297
-				if ( ! in_array( $item->get_id(), $item_ids ) ) {
298
-					$item_ids[] = $item->get_id();
299
-					$items[]    = $item;
300
-				}
301
-			}
302
-
303
-			foreach ( $this->payment_form->get_items() as $item ) {
304
-				if ( ! in_array( $item->get_id(), $item_ids ) ) {
305
-					$item_ids[] = $item->get_id();
306
-					$items[]    = $item;
307
-				}
308
-			}
309
-
310
-			$this->payment_form->set_items( $items );
311
-
312
-		} else {
313
-			$this->payment_form->set_items( $invoice->get_items() );
314
-		}
315
-
316
-		$this->country = $invoice->get_country();
317
-		$this->state   = $invoice->get_state();
318
-		$this->invoice = $invoice;
319
-
320
-		do_action_ref_array( 'getpaid_submissions_process_invoice', array( &$this ) );
321
-	}
322
-
323
-	/**
324
-	 * Returns the associated invoice.
325
-	 *
326
-	 * @since 1.0.19
327
-	 * @return WPInv_Invoice
328
-	 */
329
-	public function get_invoice() {
330
-		return $this->invoice;
331
-	}
332
-
333
-	/**
334
-	 * Checks whether there is an invoice associated with this submission.
335
-	 *
336
-	 * @since 1.0.19
337
-	 * @return bool
338
-	 */
339
-	public function has_invoice() {
340
-		return ! empty( $this->invoice );
341
-	}
342
-
343
-	/*
283
+            throw new Exception( __( 'Invalid invoice', 'invoicing' ) );
284
+        }
285
+
286
+        if ( $invoice->is_paid() ) {
287
+            throw new Exception( __( 'This invoice is already paid for.', 'invoicing' ) );
288
+        }
289
+
290
+        $this->payment_form->invoice = $invoice;
291
+        if ( ! $this->payment_form->is_default() ) {
292
+
293
+            $items    = array();
294
+            $item_ids = array();
295
+
296
+            foreach ( $invoice->get_items() as $item ) {
297
+                if ( ! in_array( $item->get_id(), $item_ids ) ) {
298
+                    $item_ids[] = $item->get_id();
299
+                    $items[]    = $item;
300
+                }
301
+            }
302
+
303
+            foreach ( $this->payment_form->get_items() as $item ) {
304
+                if ( ! in_array( $item->get_id(), $item_ids ) ) {
305
+                    $item_ids[] = $item->get_id();
306
+                    $items[]    = $item;
307
+                }
308
+            }
309
+
310
+            $this->payment_form->set_items( $items );
311
+
312
+        } else {
313
+            $this->payment_form->set_items( $invoice->get_items() );
314
+        }
315
+
316
+        $this->country = $invoice->get_country();
317
+        $this->state   = $invoice->get_state();
318
+        $this->invoice = $invoice;
319
+
320
+        do_action_ref_array( 'getpaid_submissions_process_invoice', array( &$this ) );
321
+    }
322
+
323
+    /**
324
+     * Returns the associated invoice.
325
+     *
326
+     * @since 1.0.19
327
+     * @return WPInv_Invoice
328
+     */
329
+    public function get_invoice() {
330
+        return $this->invoice;
331
+    }
332
+
333
+    /**
334
+     * Checks whether there is an invoice associated with this submission.
335
+     *
336
+     * @since 1.0.19
337
+     * @return bool
338
+     */
339
+    public function has_invoice() {
340
+        return ! empty( $this->invoice );
341
+    }
342
+
343
+    /*
344 344
 	|--------------------------------------------------------------------------
345 345
 	| Items.
346 346
 	|--------------------------------------------------------------------------
@@ -349,129 +349,129 @@  discard block
 block discarded – undo
349 349
 	| recurring item. But can have an unlimited number of non-recurring items.
350 350
 	*/
351 351
 
352
-	/**
353
-	 * Prepares the submission's items.
354
-	 *
355
-	 * @since 1.0.19
356
-	 */
357
-	public function process_items() {
358
-
359
-		$processor = new GetPaid_Payment_Form_Submission_Items( $this );
360
-
361
-		foreach ( $processor->items as $item ) {
362
-			$this->add_item( $item );
363
-		}
364
-
365
-		do_action_ref_array( 'getpaid_submissions_process_items', array( &$this ) );
366
-	}
367
-
368
-	/**
369
-	 * Adds an item to the submission.
370
-	 *
371
-	 * @since 1.0.19
372
-	 * @param GetPaid_Form_Item $item
373
-	 */
374
-	public function add_item( $item ) {
375
-
376
-		// Make sure that it is available for purchase.
377
-		if ( ! $item->can_purchase() || isset( $this->items[ $item->get_id() ] ) ) {
378
-			return;
379
-		}
380
-
381
-		// Each submission can only contain one recurring item.
382
-		if ( $item->is_recurring() ) {
383
-			$this->has_recurring = $item->get_id();
384
-		}
385
-
386
-		// Update the items and totals.
387
-		$this->items[ $item->get_id() ]         = $item;
388
-		$this->totals['subtotal']['initial']   += $item->get_sub_total();
389
-		$this->totals['subtotal']['recurring'] += $item->get_recurring_sub_total();
390
-
391
-	}
392
-
393
-	/**
394
-	 * Removes a specific item.
395
-	 *
396
-	 * You should not call this method after the discounts and taxes
397
-	 * have been calculated.
398
-	 *
399
-	 * @since 1.0.19
400
-	 */
401
-	public function remove_item( $item_id ) {
402
-
403
-		if ( isset( $this->items[ $item_id ] ) ) {
404
-			$this->totals['subtotal']['initial']   -= $this->items[ $item_id ]->get_sub_total();
405
-			$this->totals['subtotal']['recurring'] -= $this->items[ $item_id ]->get_recurring_sub_total();
406
-
407
-			if ( $this->items[ $item_id ]->is_recurring() ) {
408
-				$this->has_recurring = 0;
409
-			}
410
-
411
-			unset( $this->items[ $item_id ] );
412
-		}
413
-
414
-	}
415
-
416
-	/**
417
-	 * Returns the subtotal.
418
-	 *
419
-	 * @since 1.0.19
420
-	 */
421
-	public function get_subtotal() {
422
-
423
-		if ( wpinv_prices_include_tax() ) {
424
-			return $this->totals['subtotal']['initial'] - $this->totals['taxes']['initial'];
425
-		}
426
-
427
-		return $this->totals['subtotal']['initial'];
428
-	}
429
-
430
-	/**
431
-	 * Returns the recurring subtotal.
432
-	 *
433
-	 * @since 1.0.19
434
-	 */
435
-	public function get_recurring_subtotal() {
436
-
437
-		if ( wpinv_prices_include_tax() ) {
438
-			return $this->totals['subtotal']['recurring'] - $this->totals['taxes']['recurring'];
439
-		}
440
-
441
-		return $this->totals['subtotal']['recurring'];
442
-	}
443
-
444
-	/**
445
-	 * Returns all items.
446
-	 *
447
-	 * @since 1.0.19
448
-	 * @return GetPaid_Form_Item[]
449
-	 */
450
-	public function get_items() {
451
-		return $this->items;
452
-	}
453
-
454
-	/**
455
-	 * Checks if there's a single subscription group in the submission.
456
-	 *
457
-	 * @since 2.3.0
458
-	 * @return bool
459
-	 */
460
-	public function has_subscription_group() {
461
-		return $this->has_recurring && getpaid_should_group_subscriptions( $this ) && 1 == count( getpaid_get_subscription_groups( $this ) );
462
-	}
463
-
464
-	/**
465
-	 * Checks if there are multipe subscription groups in the submission.
466
-	 *
467
-	 * @since 2.3.0
468
-	 * @return bool
469
-	 */
470
-	public function has_multiple_subscription_groups() {
471
-		return $this->has_recurring && 1 < count( getpaid_get_subscription_groups( $this ) );
472
-	}
473
-
474
-	/*
352
+    /**
353
+     * Prepares the submission's items.
354
+     *
355
+     * @since 1.0.19
356
+     */
357
+    public function process_items() {
358
+
359
+        $processor = new GetPaid_Payment_Form_Submission_Items( $this );
360
+
361
+        foreach ( $processor->items as $item ) {
362
+            $this->add_item( $item );
363
+        }
364
+
365
+        do_action_ref_array( 'getpaid_submissions_process_items', array( &$this ) );
366
+    }
367
+
368
+    /**
369
+     * Adds an item to the submission.
370
+     *
371
+     * @since 1.0.19
372
+     * @param GetPaid_Form_Item $item
373
+     */
374
+    public function add_item( $item ) {
375
+
376
+        // Make sure that it is available for purchase.
377
+        if ( ! $item->can_purchase() || isset( $this->items[ $item->get_id() ] ) ) {
378
+            return;
379
+        }
380
+
381
+        // Each submission can only contain one recurring item.
382
+        if ( $item->is_recurring() ) {
383
+            $this->has_recurring = $item->get_id();
384
+        }
385
+
386
+        // Update the items and totals.
387
+        $this->items[ $item->get_id() ]         = $item;
388
+        $this->totals['subtotal']['initial']   += $item->get_sub_total();
389
+        $this->totals['subtotal']['recurring'] += $item->get_recurring_sub_total();
390
+
391
+    }
392
+
393
+    /**
394
+     * Removes a specific item.
395
+     *
396
+     * You should not call this method after the discounts and taxes
397
+     * have been calculated.
398
+     *
399
+     * @since 1.0.19
400
+     */
401
+    public function remove_item( $item_id ) {
402
+
403
+        if ( isset( $this->items[ $item_id ] ) ) {
404
+            $this->totals['subtotal']['initial']   -= $this->items[ $item_id ]->get_sub_total();
405
+            $this->totals['subtotal']['recurring'] -= $this->items[ $item_id ]->get_recurring_sub_total();
406
+
407
+            if ( $this->items[ $item_id ]->is_recurring() ) {
408
+                $this->has_recurring = 0;
409
+            }
410
+
411
+            unset( $this->items[ $item_id ] );
412
+        }
413
+
414
+    }
415
+
416
+    /**
417
+     * Returns the subtotal.
418
+     *
419
+     * @since 1.0.19
420
+     */
421
+    public function get_subtotal() {
422
+
423
+        if ( wpinv_prices_include_tax() ) {
424
+            return $this->totals['subtotal']['initial'] - $this->totals['taxes']['initial'];
425
+        }
426
+
427
+        return $this->totals['subtotal']['initial'];
428
+    }
429
+
430
+    /**
431
+     * Returns the recurring subtotal.
432
+     *
433
+     * @since 1.0.19
434
+     */
435
+    public function get_recurring_subtotal() {
436
+
437
+        if ( wpinv_prices_include_tax() ) {
438
+            return $this->totals['subtotal']['recurring'] - $this->totals['taxes']['recurring'];
439
+        }
440
+
441
+        return $this->totals['subtotal']['recurring'];
442
+    }
443
+
444
+    /**
445
+     * Returns all items.
446
+     *
447
+     * @since 1.0.19
448
+     * @return GetPaid_Form_Item[]
449
+     */
450
+    public function get_items() {
451
+        return $this->items;
452
+    }
453
+
454
+    /**
455
+     * Checks if there's a single subscription group in the submission.
456
+     *
457
+     * @since 2.3.0
458
+     * @return bool
459
+     */
460
+    public function has_subscription_group() {
461
+        return $this->has_recurring && getpaid_should_group_subscriptions( $this ) && 1 == count( getpaid_get_subscription_groups( $this ) );
462
+    }
463
+
464
+    /**
465
+     * Checks if there are multipe subscription groups in the submission.
466
+     *
467
+     * @since 2.3.0
468
+     * @return bool
469
+     */
470
+    public function has_multiple_subscription_groups() {
471
+        return $this->has_recurring && 1 < count( getpaid_get_subscription_groups( $this ) );
472
+    }
473
+
474
+    /*
475 475
 	|--------------------------------------------------------------------------
476 476
 	| Taxes
477 477
 	|--------------------------------------------------------------------------
@@ -480,128 +480,128 @@  discard block
 block discarded – undo
480 480
 	| or only one-time.
481 481
     */
482 482
 
483
-	/**
484
-	 * Prepares the submission's taxes.
485
-	 *
486
-	 * @since 1.0.19
487
-	 */
488
-	public function process_taxes() {
489
-
490
-		// Abort if we're not using taxes.
491
-		if ( ! $this->use_taxes() ) {
492
-			return;
493
-		}
494
-
495
-		// If a custom country && state has been passed in, use it to calculate taxes.
496
-		$country = $this->get_field( 'wpinv_country', 'billing' );
497
-		if ( ! empty( $country ) ) {
498
-			$this->country = $country;
499
-		}
500
-
501
-		$state = $this->get_field( 'wpinv_state', 'billing' );
502
-		if ( ! empty( $state ) ) {
503
-			$this->state = $state;
504
-		}
505
-
506
-		// Confirm if the provided country and the ip country are similar.
507
-		$address_confirmed = $this->get_field( 'confirm-address' );
508
-		if ( isset( $_POST['billing']['country'] ) && wpinv_should_validate_vat_number() && getpaid_get_ip_country() != $this->country && empty( $address_confirmed ) ) {
509
-			throw new Exception( __( 'The country of your current location must be the same as the country of your billing location or you must confirm the billing address is your home country.', 'invoicing' ) );
510
-		}
511
-
512
-		// Abort if the country is not taxable.
513
-		if ( ! wpinv_is_country_taxable( $this->country ) ) {
514
-			return;
515
-		}
516
-
517
-		$processor = new GetPaid_Payment_Form_Submission_Taxes( $this );
518
-
519
-		foreach ( $processor->taxes as $tax ) {
520
-			$this->add_tax( $tax );
521
-		}
522
-
523
-		do_action_ref_array( 'getpaid_submissions_process_taxes', array( &$this ) );
524
-	}
525
-
526
-	/**
527
-	 * Adds a tax to the submission.
528
-	 *
529
-	 * @param array $tax An array of tax details. name, initial_tax, and recurring_tax are required.
530
-	 * @since 1.0.19
531
-	 */
532
-	public function add_tax( $tax ) {
533
-
534
-		if ( wpinv_round_tax_per_tax_rate() ) {
535
-			$tax['initial_tax']   = wpinv_round_amount( $tax['initial_tax'] );
536
-			$tax['recurring_tax'] = wpinv_round_amount( $tax['recurring_tax'] );
537
-		}
538
-
539
-		$this->taxes[ $tax['name'] ]         = $tax;
540
-		$this->totals['taxes']['initial']   += wpinv_sanitize_amount( $tax['initial_tax'] );
541
-		$this->totals['taxes']['recurring'] += wpinv_sanitize_amount( $tax['recurring_tax'] );
542
-
543
-	}
544
-
545
-	/**
546
-	 * Removes a specific tax.
547
-	 *
548
-	 * @since 1.0.19
549
-	 */
550
-	public function remove_tax( $tax_name ) {
551
-
552
-		if ( isset( $this->taxes[ $tax_name ] ) ) {
553
-			$this->totals['taxes']['initial']   -= $this->taxes[ $tax_name ]['initial_tax'];
554
-			$this->totals['taxes']['recurring'] -= $this->taxes[ $tax_name ]['recurring_tax'];
555
-			unset( $this->taxes[ $tax_name ] );
556
-		}
557
-
558
-	}
559
-
560
-	/**
561
-	 * Whether or not we'll use taxes for the submission.
562
-	 *
563
-	 * @since 1.0.19
564
-	 */
565
-	public function use_taxes() {
566
-
567
-		$use_taxes = wpinv_use_taxes();
568
-
569
-		if ( $this->has_invoice() && ! $this->invoice->is_taxable() ) {
570
-			$use_taxes = false;
571
-		}
572
-
573
-		return apply_filters( 'getpaid_submission_use_taxes', $use_taxes, $this );
574
-
575
-	}
576
-
577
-	/**
578
-	 * Returns the tax.
579
-	 *
580
-	 * @since 1.0.19
581
-	 */
582
-	public function get_tax() {
583
-		return $this->totals['taxes']['initial'];
584
-	}
585
-
586
-	/**
587
-	 * Returns the recurring tax.
588
-	 *
589
-	 * @since 1.0.19
590
-	 */
591
-	public function get_recurring_tax() {
592
-		return $this->totals['taxes']['recurring'];
593
-	}
594
-
595
-	/**
596
-	 * Returns all taxes.
597
-	 *
598
-	 * @since 1.0.19
599
-	 */
600
-	public function get_taxes() {
601
-		return $this->taxes;
602
-	}
603
-
604
-	/*
483
+    /**
484
+     * Prepares the submission's taxes.
485
+     *
486
+     * @since 1.0.19
487
+     */
488
+    public function process_taxes() {
489
+
490
+        // Abort if we're not using taxes.
491
+        if ( ! $this->use_taxes() ) {
492
+            return;
493
+        }
494
+
495
+        // If a custom country && state has been passed in, use it to calculate taxes.
496
+        $country = $this->get_field( 'wpinv_country', 'billing' );
497
+        if ( ! empty( $country ) ) {
498
+            $this->country = $country;
499
+        }
500
+
501
+        $state = $this->get_field( 'wpinv_state', 'billing' );
502
+        if ( ! empty( $state ) ) {
503
+            $this->state = $state;
504
+        }
505
+
506
+        // Confirm if the provided country and the ip country are similar.
507
+        $address_confirmed = $this->get_field( 'confirm-address' );
508
+        if ( isset( $_POST['billing']['country'] ) && wpinv_should_validate_vat_number() && getpaid_get_ip_country() != $this->country && empty( $address_confirmed ) ) {
509
+            throw new Exception( __( 'The country of your current location must be the same as the country of your billing location or you must confirm the billing address is your home country.', 'invoicing' ) );
510
+        }
511
+
512
+        // Abort if the country is not taxable.
513
+        if ( ! wpinv_is_country_taxable( $this->country ) ) {
514
+            return;
515
+        }
516
+
517
+        $processor = new GetPaid_Payment_Form_Submission_Taxes( $this );
518
+
519
+        foreach ( $processor->taxes as $tax ) {
520
+            $this->add_tax( $tax );
521
+        }
522
+
523
+        do_action_ref_array( 'getpaid_submissions_process_taxes', array( &$this ) );
524
+    }
525
+
526
+    /**
527
+     * Adds a tax to the submission.
528
+     *
529
+     * @param array $tax An array of tax details. name, initial_tax, and recurring_tax are required.
530
+     * @since 1.0.19
531
+     */
532
+    public function add_tax( $tax ) {
533
+
534
+        if ( wpinv_round_tax_per_tax_rate() ) {
535
+            $tax['initial_tax']   = wpinv_round_amount( $tax['initial_tax'] );
536
+            $tax['recurring_tax'] = wpinv_round_amount( $tax['recurring_tax'] );
537
+        }
538
+
539
+        $this->taxes[ $tax['name'] ]         = $tax;
540
+        $this->totals['taxes']['initial']   += wpinv_sanitize_amount( $tax['initial_tax'] );
541
+        $this->totals['taxes']['recurring'] += wpinv_sanitize_amount( $tax['recurring_tax'] );
542
+
543
+    }
544
+
545
+    /**
546
+     * Removes a specific tax.
547
+     *
548
+     * @since 1.0.19
549
+     */
550
+    public function remove_tax( $tax_name ) {
551
+
552
+        if ( isset( $this->taxes[ $tax_name ] ) ) {
553
+            $this->totals['taxes']['initial']   -= $this->taxes[ $tax_name ]['initial_tax'];
554
+            $this->totals['taxes']['recurring'] -= $this->taxes[ $tax_name ]['recurring_tax'];
555
+            unset( $this->taxes[ $tax_name ] );
556
+        }
557
+
558
+    }
559
+
560
+    /**
561
+     * Whether or not we'll use taxes for the submission.
562
+     *
563
+     * @since 1.0.19
564
+     */
565
+    public function use_taxes() {
566
+
567
+        $use_taxes = wpinv_use_taxes();
568
+
569
+        if ( $this->has_invoice() && ! $this->invoice->is_taxable() ) {
570
+            $use_taxes = false;
571
+        }
572
+
573
+        return apply_filters( 'getpaid_submission_use_taxes', $use_taxes, $this );
574
+
575
+    }
576
+
577
+    /**
578
+     * Returns the tax.
579
+     *
580
+     * @since 1.0.19
581
+     */
582
+    public function get_tax() {
583
+        return $this->totals['taxes']['initial'];
584
+    }
585
+
586
+    /**
587
+     * Returns the recurring tax.
588
+     *
589
+     * @since 1.0.19
590
+     */
591
+    public function get_recurring_tax() {
592
+        return $this->totals['taxes']['recurring'];
593
+    }
594
+
595
+    /**
596
+     * Returns all taxes.
597
+     *
598
+     * @since 1.0.19
599
+     */
600
+    public function get_taxes() {
601
+        return $this->taxes;
602
+    }
603
+
604
+    /*
605 605
 	|--------------------------------------------------------------------------
606 606
 	| Discounts
607 607
 	|--------------------------------------------------------------------------
@@ -610,99 +610,99 @@  discard block
 block discarded – undo
610 610
 	| or only one-time. They also do not have to come from a discount code.
611 611
     */
612 612
 
613
-	/**
614
-	 * Prepares the submission's discount.
615
-	 *
616
-	 * @since 1.0.19
617
-	 */
618
-	public function process_discount() {
619
-
620
-		$initial_total    = $this->get_subtotal() + $this->get_fee() + $this->get_tax();
621
-		$recurring_total  = $this->get_recurring_subtotal() + $this->get_recurring_fee() + $this->get_recurring_tax();
622
-		$processor        = new GetPaid_Payment_Form_Submission_Discount( $this, $initial_total, $recurring_total );
623
-
624
-		foreach ( $processor->discounts as $discount ) {
625
-			$this->add_discount( $discount );
626
-		}
627
-
628
-		do_action_ref_array( 'getpaid_submissions_process_discounts', array( &$this ) );
629
-	}
630
-
631
-	/**
632
-	 * Adds a discount to the submission.
633
-	 *
634
-	 * @param array $discount An array of discount details. name, initial_discount, and recurring_discount are required. Include discount_code if the discount is from a discount code.
635
-	 * @since 1.0.19
636
-	 */
637
-	public function add_discount( $discount ) {
638
-		$this->discounts[ $discount['name'] ]   = $discount;
639
-		$this->totals['discount']['initial']   += wpinv_sanitize_amount( $discount['initial_discount'] );
640
-		$this->totals['discount']['recurring'] += wpinv_sanitize_amount( $discount['recurring_discount'] );
641
-	}
642
-
643
-	/**
644
-	 * Removes a discount from the submission.
645
-	 *
646
-	 * @since 1.0.19
647
-	 */
648
-	public function remove_discount( $name ) {
649
-
650
-		if ( isset( $this->discounts[ $name ] ) ) {
651
-			$this->totals['discount']['initial']   -= $this->discounts[ $name ]['initial_discount'];
652
-			$this->totals['discount']['recurring'] -= $this->discounts[ $name ]['recurring_discount'];
653
-			unset( $this->discounts[ $name ] );
654
-		}
655
-
656
-	}
657
-
658
-	/**
659
-	 * Checks whether there is a discount code associated with this submission.
660
-	 *
661
-	 * @since 1.0.19
662
-	 * @return bool
663
-	 */
664
-	public function has_discount_code() {
665
-		return ! empty( $this->discounts['discount_code'] );
666
-	}
667
-
668
-	/**
669
-	 * Returns the discount code.
670
-	 *
671
-	 * @since 1.0.19
672
-	 * @return string
673
-	 */
674
-	public function get_discount_code() {
675
-		return $this->has_discount_code() ? $this->discounts['discount_code']['discount_code'] : '';
676
-	}
677
-
678
-	/**
679
-	 * Returns the discount.
680
-	 *
681
-	 * @since 1.0.19
682
-	 */
683
-	public function get_discount() {
684
-		return $this->totals['discount']['initial'];
685
-	}
686
-
687
-	/**
688
-	 * Returns the recurring discount.
689
-	 *
690
-	 * @since 1.0.19
691
-	 */
692
-	public function get_recurring_discount() {
693
-		return $this->totals['discount']['recurring'];
694
-	}
695
-
696
-	/**
697
-	 * Returns all discounts.
698
-	 *
699
-	 * @since 1.0.19
700
-	 */
701
-	public function get_discounts() {
702
-		return $this->discounts;
703
-	}
704
-
705
-	/*
613
+    /**
614
+     * Prepares the submission's discount.
615
+     *
616
+     * @since 1.0.19
617
+     */
618
+    public function process_discount() {
619
+
620
+        $initial_total    = $this->get_subtotal() + $this->get_fee() + $this->get_tax();
621
+        $recurring_total  = $this->get_recurring_subtotal() + $this->get_recurring_fee() + $this->get_recurring_tax();
622
+        $processor        = new GetPaid_Payment_Form_Submission_Discount( $this, $initial_total, $recurring_total );
623
+
624
+        foreach ( $processor->discounts as $discount ) {
625
+            $this->add_discount( $discount );
626
+        }
627
+
628
+        do_action_ref_array( 'getpaid_submissions_process_discounts', array( &$this ) );
629
+    }
630
+
631
+    /**
632
+     * Adds a discount to the submission.
633
+     *
634
+     * @param array $discount An array of discount details. name, initial_discount, and recurring_discount are required. Include discount_code if the discount is from a discount code.
635
+     * @since 1.0.19
636
+     */
637
+    public function add_discount( $discount ) {
638
+        $this->discounts[ $discount['name'] ]   = $discount;
639
+        $this->totals['discount']['initial']   += wpinv_sanitize_amount( $discount['initial_discount'] );
640
+        $this->totals['discount']['recurring'] += wpinv_sanitize_amount( $discount['recurring_discount'] );
641
+    }
642
+
643
+    /**
644
+     * Removes a discount from the submission.
645
+     *
646
+     * @since 1.0.19
647
+     */
648
+    public function remove_discount( $name ) {
649
+
650
+        if ( isset( $this->discounts[ $name ] ) ) {
651
+            $this->totals['discount']['initial']   -= $this->discounts[ $name ]['initial_discount'];
652
+            $this->totals['discount']['recurring'] -= $this->discounts[ $name ]['recurring_discount'];
653
+            unset( $this->discounts[ $name ] );
654
+        }
655
+
656
+    }
657
+
658
+    /**
659
+     * Checks whether there is a discount code associated with this submission.
660
+     *
661
+     * @since 1.0.19
662
+     * @return bool
663
+     */
664
+    public function has_discount_code() {
665
+        return ! empty( $this->discounts['discount_code'] );
666
+    }
667
+
668
+    /**
669
+     * Returns the discount code.
670
+     *
671
+     * @since 1.0.19
672
+     * @return string
673
+     */
674
+    public function get_discount_code() {
675
+        return $this->has_discount_code() ? $this->discounts['discount_code']['discount_code'] : '';
676
+    }
677
+
678
+    /**
679
+     * Returns the discount.
680
+     *
681
+     * @since 1.0.19
682
+     */
683
+    public function get_discount() {
684
+        return $this->totals['discount']['initial'];
685
+    }
686
+
687
+    /**
688
+     * Returns the recurring discount.
689
+     *
690
+     * @since 1.0.19
691
+     */
692
+    public function get_recurring_discount() {
693
+        return $this->totals['discount']['recurring'];
694
+    }
695
+
696
+    /**
697
+     * Returns all discounts.
698
+     *
699
+     * @since 1.0.19
700
+     */
701
+    public function get_discounts() {
702
+        return $this->discounts;
703
+    }
704
+
705
+    /*
706 706
 	|--------------------------------------------------------------------------
707 707
 	| Fees
708 708
 	|--------------------------------------------------------------------------
@@ -712,100 +712,100 @@  discard block
 block discarded – undo
712 712
 	| fees.
713 713
     */
714 714
 
715
-	/**
716
-	 * Prepares the submission's fees.
717
-	 *
718
-	 * @since 1.0.19
719
-	 */
720
-	public function process_fees() {
721
-
722
-		$fees_processor = new GetPaid_Payment_Form_Submission_Fees( $this );
723
-
724
-		foreach ( $fees_processor->fees as $fee ) {
725
-			$this->add_fee( $fee );
726
-		}
727
-
728
-		do_action_ref_array( 'getpaid_submissions_process_fees', array( &$this ) );
729
-	}
730
-
731
-	/**
732
-	 * Adds a fee to the submission.
733
-	 *
734
-	 * @param array $fee An array of fee details. name, initial_fee, and recurring_fee are required.
735
-	 * @since 1.0.19
736
-	 */
737
-	public function add_fee( $fee ) {
738
-
739
-		if ( $fee['name'] == 'shipping' ) {
740
-			$this->totals['shipping']['initial']   += wpinv_sanitize_amount( $fee['initial_fee'] );
741
-			$this->totals['shipping']['recurring'] += wpinv_sanitize_amount( $fee['recurring_fee'] );
742
-			return;
743
-		}
744
-
745
-		$this->fees[ $fee['name'] ]         = $fee;
746
-		$this->totals['fees']['initial']   += wpinv_sanitize_amount( $fee['initial_fee'] );
747
-		$this->totals['fees']['recurring'] += wpinv_sanitize_amount( $fee['recurring_fee'] );
748
-
749
-	}
750
-
751
-	/**
752
-	 * Removes a fee from the submission.
753
-	 *
754
-	 * @since 1.0.19
755
-	 */
756
-	public function remove_fee( $name ) {
757
-
758
-		if ( isset( $this->fees[ $name ] ) ) {
759
-			$this->totals['fees']['initial']   -= $this->fees[ $name ]['initial_fee'];
760
-			$this->totals['fees']['recurring'] -= $this->fees[ $name ]['recurring_fee'];
761
-			unset( $this->fees[ $name ] );
762
-		}
763
-
764
-		if ( 'shipping' == $name ) {
765
-			$this->totals['shipping']['initial']   = 0;
766
-			$this->totals['shipping']['recurring'] = 0;
767
-		}
768
-
769
-	}
770
-
771
-	/**
772
-	 * Returns the fees.
773
-	 *
774
-	 * @since 1.0.19
775
-	 */
776
-	public function get_fee() {
777
-		return $this->totals['fees']['initial'];
778
-	}
779
-
780
-	/**
781
-	 * Returns the recurring fees.
782
-	 *
783
-	 * @since 1.0.19
784
-	 */
785
-	public function get_recurring_fee() {
786
-		return $this->totals['fees']['recurring'];
787
-	}
788
-
789
-	/**
790
-	 * Returns all fees.
791
-	 *
792
-	 * @since 1.0.19
793
-	 */
794
-	public function get_fees() {
795
-		return $this->fees;
796
-	}
797
-
798
-	/**
799
-	 * Checks if there are any fees for the form.
800
-	 *
801
-	 * @return bool
802
-	 * @since 1.0.19
803
-	 */
804
-	public function has_fees() {
805
-		return count( $this->fees ) !== 0;
806
-	}
807
-
808
-	/*
715
+    /**
716
+     * Prepares the submission's fees.
717
+     *
718
+     * @since 1.0.19
719
+     */
720
+    public function process_fees() {
721
+
722
+        $fees_processor = new GetPaid_Payment_Form_Submission_Fees( $this );
723
+
724
+        foreach ( $fees_processor->fees as $fee ) {
725
+            $this->add_fee( $fee );
726
+        }
727
+
728
+        do_action_ref_array( 'getpaid_submissions_process_fees', array( &$this ) );
729
+    }
730
+
731
+    /**
732
+     * Adds a fee to the submission.
733
+     *
734
+     * @param array $fee An array of fee details. name, initial_fee, and recurring_fee are required.
735
+     * @since 1.0.19
736
+     */
737
+    public function add_fee( $fee ) {
738
+
739
+        if ( $fee['name'] == 'shipping' ) {
740
+            $this->totals['shipping']['initial']   += wpinv_sanitize_amount( $fee['initial_fee'] );
741
+            $this->totals['shipping']['recurring'] += wpinv_sanitize_amount( $fee['recurring_fee'] );
742
+            return;
743
+        }
744
+
745
+        $this->fees[ $fee['name'] ]         = $fee;
746
+        $this->totals['fees']['initial']   += wpinv_sanitize_amount( $fee['initial_fee'] );
747
+        $this->totals['fees']['recurring'] += wpinv_sanitize_amount( $fee['recurring_fee'] );
748
+
749
+    }
750
+
751
+    /**
752
+     * Removes a fee from the submission.
753
+     *
754
+     * @since 1.0.19
755
+     */
756
+    public function remove_fee( $name ) {
757
+
758
+        if ( isset( $this->fees[ $name ] ) ) {
759
+            $this->totals['fees']['initial']   -= $this->fees[ $name ]['initial_fee'];
760
+            $this->totals['fees']['recurring'] -= $this->fees[ $name ]['recurring_fee'];
761
+            unset( $this->fees[ $name ] );
762
+        }
763
+
764
+        if ( 'shipping' == $name ) {
765
+            $this->totals['shipping']['initial']   = 0;
766
+            $this->totals['shipping']['recurring'] = 0;
767
+        }
768
+
769
+    }
770
+
771
+    /**
772
+     * Returns the fees.
773
+     *
774
+     * @since 1.0.19
775
+     */
776
+    public function get_fee() {
777
+        return $this->totals['fees']['initial'];
778
+    }
779
+
780
+    /**
781
+     * Returns the recurring fees.
782
+     *
783
+     * @since 1.0.19
784
+     */
785
+    public function get_recurring_fee() {
786
+        return $this->totals['fees']['recurring'];
787
+    }
788
+
789
+    /**
790
+     * Returns all fees.
791
+     *
792
+     * @since 1.0.19
793
+     */
794
+    public function get_fees() {
795
+        return $this->fees;
796
+    }
797
+
798
+    /**
799
+     * Checks if there are any fees for the form.
800
+     *
801
+     * @return bool
802
+     * @since 1.0.19
803
+     */
804
+    public function has_fees() {
805
+        return count( $this->fees ) !== 0;
806
+    }
807
+
808
+    /*
809 809
 	|--------------------------------------------------------------------------
810 810
 	| MISC
811 811
 	|--------------------------------------------------------------------------
@@ -813,147 +813,147 @@  discard block
 block discarded – undo
813 813
 	| Extra submission functions.
814 814
     */
815 815
 
816
-	/**
817
-	 * Returns the shipping amount.
818
-	 *
819
-	 * @since 1.0.19
820
-	 */
821
-	public function get_shipping() {
822
-		return $this->totals['shipping']['initial'];
823
-	}
824
-
825
-	/**
826
-	 * Returns the recurring shipping.
827
-	 *
828
-	 * @since 1.0.19
829
-	 */
830
-	public function get_recurring_shipping() {
831
-		return $this->totals['shipping']['recurring'];
832
-	}
833
-
834
-	/**
835
-	 * Checks if there are any shipping fees for the form.
836
-	 *
837
-	 * @return bool
838
-	 * @since 1.0.19
839
-	 */
840
-	public function has_shipping() {
841
-		return apply_filters( 'getpaid_payment_form_has_shipping', false, $this );
842
-	}
843
-
844
-	/**
845
-	 * Checks if this is the initial fetch.
846
-	 *
847
-	 * @return bool
848
-	 * @since 1.0.19
849
-	 */
850
-	public function is_initial_fetch() {
851
-		return isset( $this->data['initial_state'] ) && empty( $this->data['initial_state'] );
852
-	}
853
-
854
-	/**
855
-	 * Returns the total amount to collect for this submission.
856
-	 *
857
-	 * @since 1.0.19
858
-	 */
859
-	public function get_total() {
860
-		$total = $this->get_subtotal() + $this->get_fee() + $this->get_tax() + $this->get_shipping() - $this->get_discount();
861
-		return max( $total, 0 );
862
-	}
863
-
864
-	/**
865
-	 * Returns the recurring total amount to collect for this submission.
866
-	 *
867
-	 * @since 1.0.19
868
-	 */
869
-	public function get_recurring_total() {
870
-		$total = $this->get_recurring_subtotal() + $this->get_recurring_fee() + $this->get_recurring_tax() + $this->get_recurring_shipping() - $this->get_recurring_discount();
871
-		return max( $total, 0 );
872
-	}
873
-
874
-	/**
875
-	 * Whether payment details should be collected for this submission.
876
-	 *
877
-	 * @since 1.0.19
878
-	 */
879
-	public function should_collect_payment_details() {
880
-		$initial   = $this->get_total();
881
-		$recurring = $this->get_recurring_total();
882
-
883
-		if ( $this->has_recurring == 0 ) {
884
-			$recurring = 0;
885
-		}
886
-
887
-		$collect = $initial > 0 || $recurring > 0;
888
-		return apply_filters( 'getpaid_submission_should_collect_payment_details', $collect, $this );
889
-	}
890
-
891
-	/**
892
-	 * Returns the billing email of the user.
893
-	 *
894
-	 * @since 1.0.19
895
-	 */
896
-	public function get_billing_email() {
897
-		return apply_filters( 'getpaid_get_submission_billing_email', $this->get_field( 'billing_email' ), $this );
898
-	}
899
-
900
-	/**
901
-	 * Checks if the submitter has a billing email.
902
-	 *
903
-	 * @since 1.0.19
904
-	 */
905
-	public function has_billing_email() {
906
-		$billing_email = $this->get_billing_email();
907
-		return ! empty( $billing_email ) && is_email( $billing_email );
908
-	}
909
-
910
-	/**
911
-	 * Returns the appropriate currency for the submission.
912
-	 *
913
-	 * @since 1.0.19
914
-	 * @return string
915
-	 */
916
-	public function get_currency() {
917
-		return $this->has_invoice() ? $this->invoice->get_currency() : wpinv_get_currency();
918
-    }
919
-
920
-    /**
921
-	 * Returns the raw submission data.
922
-	 *
923
-	 * @since 1.0.19
924
-	 * @return array
925
-	 */
926
-	public function get_data() {
927
-		return $this->data;
928
-	}
929
-
930
-	/**
931
-	 * Returns a field from the submission data
932
-	 *
933
-	 * @param string $field
934
-	 * @since 1.0.19
935
-	 * @return mixed|null
936
-	 */
937
-	public function get_field( $field, $sub_array_key = null ) {
938
-		return getpaid_get_array_field( $this->data, $field, $sub_array_key );
939
-	}
940
-
941
-	/**
942
-	 * Checks if a required field is set.
943
-	 *
944
-	 * @since 1.0.19
945
-	 */
946
-	public function is_required_field_set( $field ) {
947
-		return empty( $field['required'] ) || ! empty( $this->data[ $field['id'] ] );
948
-	}
949
-
950
-	/**
951
-	 * Formats an amount
952
-	 *
953
-	 * @since 1.0.19
954
-	 */
955
-	public function format_amount( $amount ) {
956
-		return wpinv_price( $amount, $this->get_currency() );
957
-	}
816
+    /**
817
+     * Returns the shipping amount.
818
+     *
819
+     * @since 1.0.19
820
+     */
821
+    public function get_shipping() {
822
+        return $this->totals['shipping']['initial'];
823
+    }
824
+
825
+    /**
826
+     * Returns the recurring shipping.
827
+     *
828
+     * @since 1.0.19
829
+     */
830
+    public function get_recurring_shipping() {
831
+        return $this->totals['shipping']['recurring'];
832
+    }
833
+
834
+    /**
835
+     * Checks if there are any shipping fees for the form.
836
+     *
837
+     * @return bool
838
+     * @since 1.0.19
839
+     */
840
+    public function has_shipping() {
841
+        return apply_filters( 'getpaid_payment_form_has_shipping', false, $this );
842
+    }
843
+
844
+    /**
845
+     * Checks if this is the initial fetch.
846
+     *
847
+     * @return bool
848
+     * @since 1.0.19
849
+     */
850
+    public function is_initial_fetch() {
851
+        return isset( $this->data['initial_state'] ) && empty( $this->data['initial_state'] );
852
+    }
853
+
854
+    /**
855
+     * Returns the total amount to collect for this submission.
856
+     *
857
+     * @since 1.0.19
858
+     */
859
+    public function get_total() {
860
+        $total = $this->get_subtotal() + $this->get_fee() + $this->get_tax() + $this->get_shipping() - $this->get_discount();
861
+        return max( $total, 0 );
862
+    }
863
+
864
+    /**
865
+     * Returns the recurring total amount to collect for this submission.
866
+     *
867
+     * @since 1.0.19
868
+     */
869
+    public function get_recurring_total() {
870
+        $total = $this->get_recurring_subtotal() + $this->get_recurring_fee() + $this->get_recurring_tax() + $this->get_recurring_shipping() - $this->get_recurring_discount();
871
+        return max( $total, 0 );
872
+    }
873
+
874
+    /**
875
+     * Whether payment details should be collected for this submission.
876
+     *
877
+     * @since 1.0.19
878
+     */
879
+    public function should_collect_payment_details() {
880
+        $initial   = $this->get_total();
881
+        $recurring = $this->get_recurring_total();
882
+
883
+        if ( $this->has_recurring == 0 ) {
884
+            $recurring = 0;
885
+        }
886
+
887
+        $collect = $initial > 0 || $recurring > 0;
888
+        return apply_filters( 'getpaid_submission_should_collect_payment_details', $collect, $this );
889
+    }
890
+
891
+    /**
892
+     * Returns the billing email of the user.
893
+     *
894
+     * @since 1.0.19
895
+     */
896
+    public function get_billing_email() {
897
+        return apply_filters( 'getpaid_get_submission_billing_email', $this->get_field( 'billing_email' ), $this );
898
+    }
899
+
900
+    /**
901
+     * Checks if the submitter has a billing email.
902
+     *
903
+     * @since 1.0.19
904
+     */
905
+    public function has_billing_email() {
906
+        $billing_email = $this->get_billing_email();
907
+        return ! empty( $billing_email ) && is_email( $billing_email );
908
+    }
909
+
910
+    /**
911
+     * Returns the appropriate currency for the submission.
912
+     *
913
+     * @since 1.0.19
914
+     * @return string
915
+     */
916
+    public function get_currency() {
917
+        return $this->has_invoice() ? $this->invoice->get_currency() : wpinv_get_currency();
918
+    }
919
+
920
+    /**
921
+     * Returns the raw submission data.
922
+     *
923
+     * @since 1.0.19
924
+     * @return array
925
+     */
926
+    public function get_data() {
927
+        return $this->data;
928
+    }
929
+
930
+    /**
931
+     * Returns a field from the submission data
932
+     *
933
+     * @param string $field
934
+     * @since 1.0.19
935
+     * @return mixed|null
936
+     */
937
+    public function get_field( $field, $sub_array_key = null ) {
938
+        return getpaid_get_array_field( $this->data, $field, $sub_array_key );
939
+    }
940
+
941
+    /**
942
+     * Checks if a required field is set.
943
+     *
944
+     * @since 1.0.19
945
+     */
946
+    public function is_required_field_set( $field ) {
947
+        return empty( $field['required'] ) || ! empty( $this->data[ $field['id'] ] );
948
+    }
949
+
950
+    /**
951
+     * Formats an amount
952
+     *
953
+     * @since 1.0.19
954
+     */
955
+    public function format_amount( $amount ) {
956
+        return wpinv_price( $amount, $this->get_currency() );
957
+    }
958 958
 
959 959
 }
Please login to merge, or discard this patch.
templates/invoice/line-totals.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -52,27 +52,27 @@
 block discarded – undo
52 52
 
53 53
                                 // Total Fee.
54 54
                                 if ( 'fee' === $key ) {
55
-								wpinv_the_price( $invoice->get_total_fees(), $invoice->get_currency() );
55
+                                wpinv_the_price( $invoice->get_total_fees(), $invoice->get_currency() );
56 56
                                 }
57 57
 
58 58
                                 // Total discount.
59 59
                                 if ( 'discount' === $key ) {
60
-								wpinv_the_price( $invoice->get_total_discount(), $invoice->get_currency() );
60
+                                wpinv_the_price( $invoice->get_total_discount(), $invoice->get_currency() );
61 61
                                 }
62 62
 
63 63
                                 // Shipping.
64 64
                                 if ( 'shipping' === $key ) {
65
-								wpinv_the_price( $invoice->get_shipping(), $invoice->get_currency() );
65
+                                wpinv_the_price( $invoice->get_shipping(), $invoice->get_currency() );
66 66
                                 }
67 67
 
68 68
                                 // Sub total.
69 69
                                 if ( 'subtotal' === $key ) {
70
-								wpinv_the_price( $invoice->get_subtotal(), $invoice->get_currency() );
70
+                                wpinv_the_price( $invoice->get_subtotal(), $invoice->get_currency() );
71 71
                                 }
72 72
 
73 73
                                 // Total.
74 74
                                 if ( 'total' === $key ) {
75
-								wpinv_the_price( $invoice->get_total(), $invoice->get_currency() );
75
+                                wpinv_the_price( $invoice->get_total(), $invoice->get_currency() );
76 76
                                 }
77 77
 
78 78
                                 // Fires when printing a cart total.
Please login to merge, or discard this patch.
includes/api/class-getpaid-rest-report-sales-controller.php 1 patch
Indentation   +679 added lines, -679 removed lines patch added patch discarded remove patch
@@ -18,688 +18,688 @@
 block discarded – undo
18 18
  */
19 19
 class GetPaid_REST_Report_Sales_Controller extends GetPaid_REST_Date_Based_Controller {
20 20
 
21
-	/**
22
-	 * Route base.
23
-	 *
24
-	 * @var string
25
-	 */
26
-	protected $rest_base = 'reports/sales';
27
-
28
-	/**
29
-	 * The report data.
30
-	 *
31
-	 * @var stdClass
32
-	 */
33
-	public $report_data;
34
-
35
-	/**
36
-	 * The report range.
37
-	 *
38
-	 * @var array
39
-	 */
40
-	public $report_range;
41
-
42
-	/**
43
-	 * Registers the routes for the objects of the controller.
44
-	 *
45
-	 * @since 2.0.0
46
-	 *
47
-	 * @see register_rest_route()
48
-	 */
49
-	public function register_namespace_routes( $namespace ) {
50
-
51
-		// Get sales report.
52
-		register_rest_route(
53
-			$namespace,
54
-			$this->rest_base,
55
-			array(
56
-				array(
57
-					'methods'             => WP_REST_Server::READABLE,
58
-					'callback'            => array( $this, 'get_items' ),
59
-					'permission_callback' => array( $this, 'get_items_permissions_check' ),
60
-					'args'                => $this->get_collection_params(),
61
-				),
62
-				'schema' => array( $this, 'get_public_item_schema' ),
63
-			)
64
-		);
65
-
66
-	}
67
-
68
-	/**
69
-	 * Makes sure the current user has access to READ the report APIs.
70
-	 *
71
-	 * @since  2.0.0
72
-	 * @param WP_REST_Request $request Full data about the request.
73
-	 * @return WP_Error|boolean
74
-	 */
75
-	public function get_items_permissions_check( $request ) {
76
-
77
-		if ( ! wpinv_current_user_can_manage_invoicing() ) {
78
-			return new WP_Error( 'rest_cannot_view', __( 'Sorry, you cannot list resources.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
79
-		}
80
-
81
-		return true;
82
-	}
83
-
84
-	/**
85
-	 * Get sales reports.
86
-	 *
87
-	 * @param WP_REST_Request $request
88
-	 * @return array|WP_Error
89
-	 */
90
-	public function get_items( $request ) {
91
-		$data   = array();
92
-		$item   = $this->prepare_item_for_response( null, $request );
93
-		$data[] = $this->prepare_response_for_collection( $item );
94
-
95
-		return rest_ensure_response( $data );
96
-	}
97
-
98
-	/**
99
-	 * Prepare a report sales object for serialization.
100
-	 *
101
-	 * @param null $_
102
-	 * @param WP_REST_Request $request Request object.
103
-	 * @return WP_REST_Response $response Response data.
104
-	 */
105
-	public function prepare_item_for_response( $_, $request ) {
106
-
107
-		// Set report range.
108
-		$this->report_range = $this->get_date_range( $request );
109
-
110
-		$report_data     = $this->get_report_data();
111
-		$period_totals   = array();
112
-
113
-		// Setup period totals by ensuring each period in the interval has data.
114
-		$start_date      = strtotime( $this->report_range['after'] );
115
-
116
-		if ( 'month' === $this->groupby ) {
117
-			$start_date      = strtotime( gmdate( 'Y-m-01', $start_date ) );
118
-		}
119
-
120
-		for ( $i = 0; $i < $this->interval; $i++ ) {
121
-
122
-			switch ( $this->groupby ) {
123
-				case 'day':
124
-					$time = gmdate( 'Y-m-d', strtotime( "+{$i} DAY", $start_date ) );
125
-					break;
126
-				default:
127
-					$time = gmdate( 'Y-m', strtotime( "+{$i} MONTH", $start_date ) );
128
-					break;
129
-			}
130
-
131
-			// Set the defaults for each period.
132
-			$period_totals[ $time ] = array(
133
-				'invoices'          => 0,
134
-				'items'             => 0,
135
-				'refunded_items'    => 0,
136
-				'refunded_tax'      => wpinv_round_amount( 0.00 ),
137
-				'subtotal'          => wpinv_round_amount( 0.00 ),
138
-				'refunded_subtotal' => wpinv_round_amount( 0.00 ),
139
-				'refunded_fees'     => wpinv_round_amount( 0.00 ),
140
-				'discount'          => wpinv_round_amount( 0.00 ),
141
-			);
142
-
143
-			foreach ( array_keys( wpinv_get_report_graphs() ) as $key ) {
144
-				if ( ! isset( $period_totals[ $time ][ $key ] ) ) {
145
-					$period_totals[ $time ][ $key ] = wpinv_round_amount( 0.00 );
146
-				}
147
-			}
148
-		}
149
-
150
-		// add total sales, total invoice count, total tax for each period
151
-		$date_format = ( 'day' === $this->groupby ) ? 'Y-m-d' : 'Y-m';
152
-		foreach ( $report_data->invoices as $invoice ) {
153
-			$time = gmdate( $date_format, strtotime( $invoice->post_date ) );
154
-
155
-			if ( ! isset( $period_totals[ $time ] ) ) {
156
-				continue;
157
-			}
158
-
159
-			$period_totals[ $time ]['sales']    = wpinv_round_amount( $invoice->total_sales );
160
-			$period_totals[ $time ]['tax']      = wpinv_round_amount( $invoice->total_tax );
161
-			$period_totals[ $time ]['subtotal'] = wpinv_round_amount( $invoice->subtotal );
162
-			$period_totals[ $time ]['fees']     = wpinv_round_amount( $invoice->total_fees );
163
-
164
-		}
165
-
166
-		foreach ( $report_data->refunds as $invoice ) {
167
-			$time = gmdate( $date_format, strtotime( $invoice->post_date ) );
168
-
169
-			if ( ! isset( $period_totals[ $time ] ) ) {
170
-				continue;
171
-			}
172
-
173
-			$period_totals[ $time ]['refunds']           = wpinv_round_amount( $invoice->total_sales );
174
-			$period_totals[ $time ]['refunded_tax']      = wpinv_round_amount( $invoice->total_tax );
175
-			$period_totals[ $time ]['refunded_subtotal'] = wpinv_round_amount( $invoice->subtotal );
176
-			$period_totals[ $time ]['refunded_fees']     = wpinv_round_amount( $invoice->total_fees );
177
-
178
-		}
179
-
180
-		foreach ( $report_data->invoice_counts as $invoice ) {
181
-			$time = gmdate( $date_format, strtotime( $invoice->post_date ) );
182
-
183
-			if ( isset( $period_totals[ $time ] ) ) {
184
-				$period_totals[ $time ]['invoices']   = (int) $invoice->count;
185
-			}
186
-		}
187
-
188
-		// Add total invoice items for each period.
189
-		foreach ( $report_data->invoice_items as $invoice_item ) {
190
-			$time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $invoice_item->post_date ) ) : gmdate( 'Y-m', strtotime( $invoice_item->post_date ) );
191
-
192
-			if ( isset( $period_totals[ $time ] ) ) {
193
-				$period_totals[ $time ]['items'] = (int) $invoice_item->invoice_item_count;
194
-			}
195
-		}
196
-
197
-		// Add total discount for each period.
198
-		foreach ( $report_data->coupons as $discount ) {
199
-			$time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $discount->post_date ) ) : gmdate( 'Y-m', strtotime( $discount->post_date ) );
200
-
201
-			if ( isset( $period_totals[ $time ] ) ) {
202
-				$period_totals[ $time ]['discount'] = wpinv_round_amount( $discount->discount_amount );
203
-			}
204
-		}
205
-
206
-		// Extra fields.
207
-		foreach ( array_keys( wpinv_get_report_graphs() ) as $key ) {
208
-
209
-			// Abort unprepared.
210
-			if ( ! isset( $report_data->$key ) ) {
211
-				continue;
212
-			}
213
-
214
-			// Abort defaults.
215
-			if ( in_array( $key, array( 'sales', 'refunds', 'tax', 'fees', 'discount', 'invoices', 'items' ) ) ) {
216
-				continue;
217
-			}
218
-
219
-			// Set values.
220
-			foreach ( $report_data->$key as $item ) {
221
-				$time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $item->date ) ) : gmdate( 'Y-m', strtotime( $item->date ) );
222
-
223
-				if ( isset( $period_totals[ $time ] ) ) {
224
-					$period_totals[ $time ][ $key ] = wpinv_round_amount( $item->val );
225
-				}
226
-			}
227
-
228
-			unset( $report_data->$key );
229
-		}
230
-
231
-		$report_data->totals            = $period_totals;
232
-		$report_data->grouped_by        = $this->groupby;
233
-		$report_data->interval          = max( $this->interval, 1 );
234
-		$report_data->currency          = wpinv_get_currency();
235
-		$report_data->currency_symbol   = wpinv_currency_symbol();
236
-		$report_data->currency_position = wpinv_currency_position();
237
-		$report_data->decimal_places    = wpinv_decimals();
238
-		$report_data->thousands_sep     = wpinv_thousands_separator();
239
-		$report_data->decimals_sep      = wpinv_decimal_separator();
240
-		$report_data->start_date        = gmdate( 'Y-m-d', strtotime( $this->report_range['after'] ) );
241
-		$report_data->end_date          = gmdate( 'Y-m-d', strtotime( $this->report_range['before'] ) );
242
-		$report_data->start_date_locale = getpaid_format_date( gmdate( 'Y-m-d', strtotime( $this->report_range['after'] ) ) );
243
-		$report_data->end_date_locale   = getpaid_format_date( gmdate( 'Y-m-d', strtotime( $this->report_range['before'] ) ) );
244
-		$report_data->decimals_sep      = wpinv_decimal_separator();
245
-
246
-		$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
247
-		$data    = $report_data;
248
-		unset( $data->invoice_counts, $data->invoices, $data->coupons, $data->refunds, $data->invoice_items );
249
-		$data    = $this->add_additional_fields_to_object( (array) $data, $request );
250
-		$data    = $this->filter_response_by_context( $data, $context );
251
-
252
-		// Wrap the data in a response object.
253
-		$response = rest_ensure_response( $data );
254
-		$response->add_links(
21
+    /**
22
+     * Route base.
23
+     *
24
+     * @var string
25
+     */
26
+    protected $rest_base = 'reports/sales';
27
+
28
+    /**
29
+     * The report data.
30
+     *
31
+     * @var stdClass
32
+     */
33
+    public $report_data;
34
+
35
+    /**
36
+     * The report range.
37
+     *
38
+     * @var array
39
+     */
40
+    public $report_range;
41
+
42
+    /**
43
+     * Registers the routes for the objects of the controller.
44
+     *
45
+     * @since 2.0.0
46
+     *
47
+     * @see register_rest_route()
48
+     */
49
+    public function register_namespace_routes( $namespace ) {
50
+
51
+        // Get sales report.
52
+        register_rest_route(
53
+            $namespace,
54
+            $this->rest_base,
255 55
             array(
256
-				'about' => array(
257
-					'href' => rest_url( sprintf( '%s/reports', $this->namespace ) ),
258
-				),
56
+                array(
57
+                    'methods'             => WP_REST_Server::READABLE,
58
+                    'callback'            => array( $this, 'get_items' ),
59
+                    'permission_callback' => array( $this, 'get_items_permissions_check' ),
60
+                    'args'                => $this->get_collection_params(),
61
+                ),
62
+                'schema' => array( $this, 'get_public_item_schema' ),
259 63
             )
260 64
         );
261 65
 
262
-		return apply_filters( 'getpaid_rest_prepare_report_sales', $response, $report_data, $request );
263
-	}
264
-
265
-	/**
266
-	 * Get report data.
267
-	 *
268
-	 * @return stdClass
269
-	 */
270
-	public function get_report_data() {
271
-		if ( empty( $this->report_data ) ) {
272
-			$this->query_report_data();
273
-		}
274
-		return $this->report_data;
275
-	}
276
-
277
-	/**
278
-	 * Get all data needed for this report and store in the class.
279
-	 */
280
-	protected function query_report_data() {
281
-
282
-		// Prepare reports.
283
-		$this->report_data = (object) array(
284
-			'invoice_counts' => $this->query_invoice_counts(), //count, post_date
285
-			'coupons'        => $this->query_coupon_counts(), // discount_amount, post_date
286
-			'invoice_items'  => $this->query_item_counts(), // invoice_item_count, post_date
287
-			'refunded_items' => $this->count_refunded_items(), // invoice_item_count, post_date
288
-			'invoices'       => $this->query_invoice_totals(), // total_sales, total_tax, total_discount, total_fees, subtotal, post_date
289
-			'refunds'        => $this->query_refunded_totals(), // total_sales, total_tax, total_discount, total_fees, subtotal, post_date
290
-			'previous_range' => $this->previous_range,
291
-		);
292
-
293
-		// Calculated totals.
294
-		$this->report_data->total_tax          = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_tax' ) ) );
295
-		$this->report_data->total_sales        = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_sales' ) ) );
296
-		$this->report_data->total_discount     = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_discount' ) ) );
297
-		$this->report_data->total_fees         = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_fees' ) ) );
298
-		$this->report_data->subtotal           = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'subtotal' ) ) );
299
-		$this->report_data->net_sales          = wpinv_round_amount( $this->report_data->total_sales - max( 0, $this->report_data->total_tax ) );
300
-		$this->report_data->total_refunded_tax = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_tax' ) ) );
301
-		$this->report_data->total_refunds      = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_sales' ) ) );
302
-		$this->report_data->refunded_discount  = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_discount' ) ) );
303
-		$this->report_data->refunded_fees      = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_fees' ) ) );
304
-		$this->report_data->refunded_subtotal  = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'subtotal' ) ) );
305
-		$this->report_data->net_refunds        = wpinv_round_amount( $this->report_data->total_refunds + max( 0, $this->report_data->total_refunded_tax ) );
306
-
307
-		// Calculate average based on net.
308
-		$this->report_data->average_sales       = wpinv_round_amount( $this->report_data->net_sales / max( $this->interval, 1 ), 2 );
309
-		$this->report_data->average_total_sales = wpinv_round_amount( $this->report_data->total_sales / max( $this->interval, 1 ), 2 );
310
-
311
-		// Total invoices in this period, even if refunded.
312
-		$this->report_data->total_invoices = absint( array_sum( wp_list_pluck( $this->report_data->invoice_counts, 'count' ) ) );
313
-
314
-		// Items invoiced in this period, even if refunded.
315
-		$this->report_data->total_items = absint( array_sum( wp_list_pluck( $this->report_data->invoice_items, 'invoice_item_count' ) ) );
316
-
317
-		// 3rd party filtering of report data
318
-		$this->report_data = apply_filters( 'getpaid_rest_api_filter_report_data', $this->report_data, $this );
319
-	}
320
-
321
-	/**
322
-	 * Prepares invoice counts.
323
-	 *
324
-	 * @return array.
325
-	 */
326
-	protected function query_invoice_counts() {
327
-
328
-		return (array) GetPaid_Reports_Helper::get_invoice_report_data(
329
-			array(
330
-				'data'           => array(
331
-					'ID'        => array(
332
-						'type'     => 'post_data',
333
-						'function' => 'COUNT',
334
-						'name'     => 'count',
335
-						'distinct' => true,
336
-					),
337
-					'post_date' => array(
338
-						'type'     => 'post_data',
339
-						'function' => 'MIN',
340
-						'name'     => 'post_date',
341
-					),
342
-				),
343
-				'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
344
-				'order_by'       => 'post_date ASC',
345
-				'query_type'     => 'get_results',
346
-				'filter_range'   => $this->report_range,
347
-				'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
348
-			)
349
-		);
350
-
351
-	}
352
-
353
-	/**
354
-	 * Prepares coupon counts.
355
-	 *
356
-	 * @return array.
357
-	 */
358
-	protected function query_coupon_counts() {
359
-
360
-		return (array) GetPaid_Reports_Helper::get_invoice_report_data(
361
-			array(
362
-				'data'           => array(
363
-					'discount'  => array(
364
-						'type'     => 'invoice_data',
365
-						'function' => 'SUM',
366
-						'name'     => 'discount_amount',
367
-					),
368
-					'post_date' => array(
369
-						'type'     => 'post_data',
370
-						'function' => 'MIN',
371
-						'name'     => 'post_date',
372
-					),
373
-				),
374
-				'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
375
-				'order_by'       => 'post_date ASC',
376
-				'query_type'     => 'get_results',
377
-				'filter_range'   => $this->report_range,
378
-				'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
379
-			)
380
-		);
381
-
382
-	}
383
-
384
-	/**
385
-	 * Prepares item counts.
386
-	 *
387
-	 * @return array.
388
-	 */
389
-	protected function query_item_counts() {
390
-
391
-		return (array) GetPaid_Reports_Helper::get_invoice_report_data(
392
-			array(
393
-				'data'           => array(
394
-					'quantity'  => array(
395
-						'type'     => 'invoice_item',
396
-						'function' => 'SUM',
397
-						'name'     => 'invoice_item_count',
398
-					),
399
-					'post_date' => array(
400
-						'type'     => 'post_data',
401
-						'function' => 'MIN',
402
-						'name'     => 'post_date',
403
-					),
404
-				),
405
-				'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
406
-				'order_by'       => 'post_date ASC',
407
-				'query_type'     => 'get_results',
408
-				'filter_range'   => $this->report_range,
409
-				'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
410
-			)
411
-		);
412
-
413
-	}
414
-
415
-	/**
416
-	 * Prepares refunded item counts.
417
-	 *
418
-	 * @return array.
419
-	 */
420
-	protected function count_refunded_items() {
421
-
422
-		return (int) GetPaid_Reports_Helper::get_invoice_report_data(
423
-			array(
424
-				'data'           => array(
425
-					'quantity' => array(
426
-						'type'     => 'invoice_item',
427
-						'function' => 'SUM',
428
-						'name'     => 'invoice_item_count',
429
-					),
430
-				),
431
-				'query_type'     => 'get_var',
432
-				'filter_range'   => $this->report_range,
433
-				'invoice_status' => array( 'wpi-refunded' ),
434
-			)
435
-		);
436
-
437
-	}
438
-
439
-	/**
440
-	 * Prepares daily invoice totals.
441
-	 *
442
-	 * @return array.
443
-	 */
444
-	protected function query_invoice_totals() {
445
-
446
-		return (array) GetPaid_Reports_Helper::get_invoice_report_data(
447
-			array(
448
-				'data'           => array(
449
-					'total'      => array(
450
-						'type'     => 'invoice_data',
451
-						'function' => 'SUM',
452
-						'name'     => 'total_sales',
453
-					),
454
-					'tax'        => array(
455
-						'type'     => 'invoice_data',
456
-						'function' => 'SUM',
457
-						'name'     => 'total_tax',
458
-					),
459
-					'discount'   => array(
460
-						'type'     => 'invoice_data',
461
-						'function' => 'SUM',
462
-						'name'     => 'total_discount',
463
-					),
464
-					'fees_total' => array(
465
-						'type'     => 'invoice_data',
466
-						'function' => 'SUM',
467
-						'name'     => 'total_fees',
468
-					),
469
-					'subtotal'   => array(
470
-						'type'     => 'invoice_data',
471
-						'function' => 'SUM',
472
-						'name'     => 'subtotal',
473
-					),
474
-					'post_date'  => array(
475
-						'type'     => 'post_data',
476
-						'function' => '',
477
-						'name'     => 'post_date',
478
-					),
479
-				),
480
-				'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
481
-				'order_by'       => 'post_date ASC',
482
-				'query_type'     => 'get_results',
483
-				'filter_range'   => $this->report_range,
484
-				'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-renewal' ),
485
-			)
486
-		);
487
-
488
-	}
489
-
490
-	/**
491
-	 * Prepares daily invoice totals.
492
-	 *
493
-	 * @return array.
494
-	 */
495
-	protected function query_refunded_totals() {
496
-
497
-		return (array) GetPaid_Reports_Helper::get_invoice_report_data(
498
-			array(
499
-				'data'           => array(
500
-					'total'      => array(
501
-						'type'     => 'invoice_data',
502
-						'function' => 'SUM',
503
-						'name'     => 'total_sales',
504
-					),
505
-					'tax'        => array(
506
-						'type'     => 'invoice_data',
507
-						'function' => 'SUM',
508
-						'name'     => 'total_tax',
509
-					),
510
-					'discount'   => array(
511
-						'type'     => 'invoice_data',
512
-						'function' => 'SUM',
513
-						'name'     => 'total_discount',
514
-					),
515
-					'fees_total' => array(
516
-						'type'     => 'invoice_data',
517
-						'function' => 'SUM',
518
-						'name'     => 'total_fees',
519
-					),
520
-					'subtotal'   => array(
521
-						'type'     => 'invoice_data',
522
-						'function' => 'SUM',
523
-						'name'     => 'subtotal',
524
-					),
525
-					'post_date'  => array(
526
-						'type'     => 'post_data',
527
-						'function' => '',
528
-						'name'     => 'post_date',
529
-					),
530
-				),
531
-				'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
532
-				'order_by'       => 'post_date ASC',
533
-				'query_type'     => 'get_results',
534
-				'filter_range'   => $this->report_range,
535
-				'invoice_status' => array( 'wpi-refunded' ),
536
-			)
537
-		);
538
-
539
-	}
540
-
541
-	/**
542
-	 * Get the Report's schema, conforming to JSON Schema.
543
-	 *
544
-	 * @return array
545
-	 */
546
-	public function get_item_schema() {
547
-
548
-		$schema = array(
549
-			'$schema'    => 'http://json-schema.org/draft-04/schema#',
550
-			'title'      => 'sales_report',
551
-			'type'       => 'object',
552
-			'properties' => array(
553
-				'total_sales'         => array(
554
-					'description' => __( 'Gross sales in the period.', 'invoicing' ),
555
-					'type'        => 'string',
556
-					'context'     => array( 'view' ),
557
-					'readonly'    => true,
558
-				),
559
-				'net_sales'           => array(
560
-					'description' => __( 'Net sales in the period.', 'invoicing' ),
561
-					'type'        => 'string',
562
-					'context'     => array( 'view' ),
563
-					'readonly'    => true,
564
-				),
565
-				'average_sales'       => array(
566
-					'description' => __( 'Average net daily sales.', 'invoicing' ),
567
-					'type'        => 'string',
568
-					'context'     => array( 'view' ),
569
-					'readonly'    => true,
570
-				),
571
-				'average_total_sales' => array(
572
-					'description' => __( 'Average gross daily sales.', 'invoicing' ),
573
-					'type'        => 'string',
574
-					'context'     => array( 'view' ),
575
-					'readonly'    => true,
576
-				),
577
-				'total_invoices'      => array(
578
-					'description' => __( 'Number of paid invoices.', 'invoicing' ),
579
-					'type'        => 'integer',
580
-					'context'     => array( 'view' ),
581
-					'readonly'    => true,
582
-				),
583
-				'total_items'         => array(
584
-					'description' => __( 'Number of items purchased.', 'invoicing' ),
585
-					'type'        => 'integer',
586
-					'context'     => array( 'view' ),
587
-					'readonly'    => true,
588
-				),
589
-				'refunded_items'      => array(
590
-					'description' => __( 'Number of items refunded.', 'invoicing' ),
591
-					'type'        => 'integer',
592
-					'context'     => array( 'view' ),
593
-					'readonly'    => true,
594
-				),
595
-				'total_tax'           => array(
596
-					'description' => __( 'Total charged for taxes.', 'invoicing' ),
597
-					'type'        => 'string',
598
-					'context'     => array( 'view' ),
599
-					'readonly'    => true,
600
-				),
601
-				'total_refunded_tax'  => array(
602
-					'description' => __( 'Total refunded for taxes.', 'invoicing' ),
603
-					'type'        => 'string',
604
-					'context'     => array( 'view' ),
605
-					'readonly'    => true,
606
-				),
607
-				'total_fees'          => array(
608
-					'description' => __( 'Total fees charged.', 'invoicing' ),
609
-					'type'        => 'string',
610
-					'context'     => array( 'view' ),
611
-					'readonly'    => true,
612
-				),
613
-				'total_refunds'       => array(
614
-					'description' => __( 'Total of refunded invoices.', 'invoicing' ),
615
-					'type'        => 'integer',
616
-					'context'     => array( 'view' ),
617
-					'readonly'    => true,
618
-				),
619
-				'net_refunds'         => array(
620
-					'description' => __( 'Net of refunded invoices.', 'invoicing' ),
621
-					'type'        => 'integer',
622
-					'context'     => array( 'view' ),
623
-					'readonly'    => true,
624
-				),
625
-				'total_discount'      => array(
626
-					'description' => __( 'Total of discounts used.', 'invoicing' ),
627
-					'type'        => 'integer',
628
-					'context'     => array( 'view' ),
629
-					'readonly'    => true,
630
-				),
631
-				'totals'              => array(
632
-					'description' => __( 'Totals.', 'invoicing' ),
633
-					'type'        => 'array',
634
-					'items'       => array(
635
-						'type' => 'array',
636
-					),
637
-					'context'     => array( 'view' ),
638
-					'readonly'    => true,
639
-				),
640
-				'interval'            => array(
641
-					'description' => __( 'Number of months/days in the report period.', 'invoicing' ),
642
-					'type'        => 'integer',
643
-					'context'     => array( 'view' ),
644
-					'readonly'    => true,
645
-				),
646
-				'previous_range'      => array(
647
-					'description' => __( 'The previous report period.', 'invoicing' ),
648
-					'type'        => 'array',
649
-					'items'       => array(
650
-						'type' => 'string',
651
-					),
652
-					'context'     => array( 'view' ),
653
-					'readonly'    => true,
654
-				),
655
-				'grouped_by'          => array(
656
-					'description' => __( 'The period used to group the totals.', 'invoicing' ),
657
-					'type'        => 'string',
658
-					'context'     => array( 'view' ),
659
-					'enum'        => array( 'day', 'month' ),
660
-					'readonly'    => true,
661
-				),
662
-				'currency'            => array(
663
-					'description' => __( 'The default store currency.', 'invoicing' ),
664
-					'type'        => 'string',
665
-					'context'     => array( 'view' ),
666
-					'readonly'    => true,
667
-				),
668
-				'currency_symbol'     => array(
669
-					'description' => __( 'The default store currency symbol.', 'invoicing' ),
670
-					'type'        => 'string',
671
-					'context'     => array( 'view' ),
672
-					'readonly'    => true,
673
-				),
674
-				'currency_position'   => array(
675
-					'description' => __( 'The default store currency position.', 'invoicing' ),
676
-					'type'        => 'string',
677
-					'context'     => array( 'view' ),
678
-					'readonly'    => true,
679
-				),
680
-				'decimal_places'      => array(
681
-					'description' => __( 'The default store decimal places.', 'invoicing' ),
682
-					'type'        => 'string',
683
-					'context'     => array( 'view' ),
684
-					'readonly'    => true,
685
-				),
686
-				'thousands_sep'       => array(
687
-					'description' => __( 'The default store thousands separator.', 'invoicing' ),
688
-					'type'        => 'string',
689
-					'context'     => array( 'view' ),
690
-					'readonly'    => true,
691
-				),
692
-				'decimals_sep'        => array(
693
-					'description' => __( 'The default store decimals separator.', 'invoicing' ),
694
-					'type'        => 'string',
695
-					'context'     => array( 'view' ),
696
-					'readonly'    => true,
697
-				),
698
-			),
699
-		);
700
-
701
-		return $this->add_additional_fields_schema( $schema );
702
-
703
-	}
66
+    }
67
+
68
+    /**
69
+     * Makes sure the current user has access to READ the report APIs.
70
+     *
71
+     * @since  2.0.0
72
+     * @param WP_REST_Request $request Full data about the request.
73
+     * @return WP_Error|boolean
74
+     */
75
+    public function get_items_permissions_check( $request ) {
76
+
77
+        if ( ! wpinv_current_user_can_manage_invoicing() ) {
78
+            return new WP_Error( 'rest_cannot_view', __( 'Sorry, you cannot list resources.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
79
+        }
80
+
81
+        return true;
82
+    }
83
+
84
+    /**
85
+     * Get sales reports.
86
+     *
87
+     * @param WP_REST_Request $request
88
+     * @return array|WP_Error
89
+     */
90
+    public function get_items( $request ) {
91
+        $data   = array();
92
+        $item   = $this->prepare_item_for_response( null, $request );
93
+        $data[] = $this->prepare_response_for_collection( $item );
94
+
95
+        return rest_ensure_response( $data );
96
+    }
97
+
98
+    /**
99
+     * Prepare a report sales object for serialization.
100
+     *
101
+     * @param null $_
102
+     * @param WP_REST_Request $request Request object.
103
+     * @return WP_REST_Response $response Response data.
104
+     */
105
+    public function prepare_item_for_response( $_, $request ) {
106
+
107
+        // Set report range.
108
+        $this->report_range = $this->get_date_range( $request );
109
+
110
+        $report_data     = $this->get_report_data();
111
+        $period_totals   = array();
112
+
113
+        // Setup period totals by ensuring each period in the interval has data.
114
+        $start_date      = strtotime( $this->report_range['after'] );
115
+
116
+        if ( 'month' === $this->groupby ) {
117
+            $start_date      = strtotime( gmdate( 'Y-m-01', $start_date ) );
118
+        }
119
+
120
+        for ( $i = 0; $i < $this->interval; $i++ ) {
121
+
122
+            switch ( $this->groupby ) {
123
+                case 'day':
124
+                    $time = gmdate( 'Y-m-d', strtotime( "+{$i} DAY", $start_date ) );
125
+                    break;
126
+                default:
127
+                    $time = gmdate( 'Y-m', strtotime( "+{$i} MONTH", $start_date ) );
128
+                    break;
129
+            }
130
+
131
+            // Set the defaults for each period.
132
+            $period_totals[ $time ] = array(
133
+                'invoices'          => 0,
134
+                'items'             => 0,
135
+                'refunded_items'    => 0,
136
+                'refunded_tax'      => wpinv_round_amount( 0.00 ),
137
+                'subtotal'          => wpinv_round_amount( 0.00 ),
138
+                'refunded_subtotal' => wpinv_round_amount( 0.00 ),
139
+                'refunded_fees'     => wpinv_round_amount( 0.00 ),
140
+                'discount'          => wpinv_round_amount( 0.00 ),
141
+            );
142
+
143
+            foreach ( array_keys( wpinv_get_report_graphs() ) as $key ) {
144
+                if ( ! isset( $period_totals[ $time ][ $key ] ) ) {
145
+                    $period_totals[ $time ][ $key ] = wpinv_round_amount( 0.00 );
146
+                }
147
+            }
148
+        }
149
+
150
+        // add total sales, total invoice count, total tax for each period
151
+        $date_format = ( 'day' === $this->groupby ) ? 'Y-m-d' : 'Y-m';
152
+        foreach ( $report_data->invoices as $invoice ) {
153
+            $time = gmdate( $date_format, strtotime( $invoice->post_date ) );
154
+
155
+            if ( ! isset( $period_totals[ $time ] ) ) {
156
+                continue;
157
+            }
158
+
159
+            $period_totals[ $time ]['sales']    = wpinv_round_amount( $invoice->total_sales );
160
+            $period_totals[ $time ]['tax']      = wpinv_round_amount( $invoice->total_tax );
161
+            $period_totals[ $time ]['subtotal'] = wpinv_round_amount( $invoice->subtotal );
162
+            $period_totals[ $time ]['fees']     = wpinv_round_amount( $invoice->total_fees );
163
+
164
+        }
165
+
166
+        foreach ( $report_data->refunds as $invoice ) {
167
+            $time = gmdate( $date_format, strtotime( $invoice->post_date ) );
168
+
169
+            if ( ! isset( $period_totals[ $time ] ) ) {
170
+                continue;
171
+            }
172
+
173
+            $period_totals[ $time ]['refunds']           = wpinv_round_amount( $invoice->total_sales );
174
+            $period_totals[ $time ]['refunded_tax']      = wpinv_round_amount( $invoice->total_tax );
175
+            $period_totals[ $time ]['refunded_subtotal'] = wpinv_round_amount( $invoice->subtotal );
176
+            $period_totals[ $time ]['refunded_fees']     = wpinv_round_amount( $invoice->total_fees );
177
+
178
+        }
179
+
180
+        foreach ( $report_data->invoice_counts as $invoice ) {
181
+            $time = gmdate( $date_format, strtotime( $invoice->post_date ) );
182
+
183
+            if ( isset( $period_totals[ $time ] ) ) {
184
+                $period_totals[ $time ]['invoices']   = (int) $invoice->count;
185
+            }
186
+        }
187
+
188
+        // Add total invoice items for each period.
189
+        foreach ( $report_data->invoice_items as $invoice_item ) {
190
+            $time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $invoice_item->post_date ) ) : gmdate( 'Y-m', strtotime( $invoice_item->post_date ) );
191
+
192
+            if ( isset( $period_totals[ $time ] ) ) {
193
+                $period_totals[ $time ]['items'] = (int) $invoice_item->invoice_item_count;
194
+            }
195
+        }
196
+
197
+        // Add total discount for each period.
198
+        foreach ( $report_data->coupons as $discount ) {
199
+            $time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $discount->post_date ) ) : gmdate( 'Y-m', strtotime( $discount->post_date ) );
200
+
201
+            if ( isset( $period_totals[ $time ] ) ) {
202
+                $period_totals[ $time ]['discount'] = wpinv_round_amount( $discount->discount_amount );
203
+            }
204
+        }
205
+
206
+        // Extra fields.
207
+        foreach ( array_keys( wpinv_get_report_graphs() ) as $key ) {
208
+
209
+            // Abort unprepared.
210
+            if ( ! isset( $report_data->$key ) ) {
211
+                continue;
212
+            }
213
+
214
+            // Abort defaults.
215
+            if ( in_array( $key, array( 'sales', 'refunds', 'tax', 'fees', 'discount', 'invoices', 'items' ) ) ) {
216
+                continue;
217
+            }
218
+
219
+            // Set values.
220
+            foreach ( $report_data->$key as $item ) {
221
+                $time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $item->date ) ) : gmdate( 'Y-m', strtotime( $item->date ) );
222
+
223
+                if ( isset( $period_totals[ $time ] ) ) {
224
+                    $period_totals[ $time ][ $key ] = wpinv_round_amount( $item->val );
225
+                }
226
+            }
227
+
228
+            unset( $report_data->$key );
229
+        }
230
+
231
+        $report_data->totals            = $period_totals;
232
+        $report_data->grouped_by        = $this->groupby;
233
+        $report_data->interval          = max( $this->interval, 1 );
234
+        $report_data->currency          = wpinv_get_currency();
235
+        $report_data->currency_symbol   = wpinv_currency_symbol();
236
+        $report_data->currency_position = wpinv_currency_position();
237
+        $report_data->decimal_places    = wpinv_decimals();
238
+        $report_data->thousands_sep     = wpinv_thousands_separator();
239
+        $report_data->decimals_sep      = wpinv_decimal_separator();
240
+        $report_data->start_date        = gmdate( 'Y-m-d', strtotime( $this->report_range['after'] ) );
241
+        $report_data->end_date          = gmdate( 'Y-m-d', strtotime( $this->report_range['before'] ) );
242
+        $report_data->start_date_locale = getpaid_format_date( gmdate( 'Y-m-d', strtotime( $this->report_range['after'] ) ) );
243
+        $report_data->end_date_locale   = getpaid_format_date( gmdate( 'Y-m-d', strtotime( $this->report_range['before'] ) ) );
244
+        $report_data->decimals_sep      = wpinv_decimal_separator();
245
+
246
+        $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
247
+        $data    = $report_data;
248
+        unset( $data->invoice_counts, $data->invoices, $data->coupons, $data->refunds, $data->invoice_items );
249
+        $data    = $this->add_additional_fields_to_object( (array) $data, $request );
250
+        $data    = $this->filter_response_by_context( $data, $context );
251
+
252
+        // Wrap the data in a response object.
253
+        $response = rest_ensure_response( $data );
254
+        $response->add_links(
255
+            array(
256
+                'about' => array(
257
+                    'href' => rest_url( sprintf( '%s/reports', $this->namespace ) ),
258
+                ),
259
+            )
260
+        );
261
+
262
+        return apply_filters( 'getpaid_rest_prepare_report_sales', $response, $report_data, $request );
263
+    }
264
+
265
+    /**
266
+     * Get report data.
267
+     *
268
+     * @return stdClass
269
+     */
270
+    public function get_report_data() {
271
+        if ( empty( $this->report_data ) ) {
272
+            $this->query_report_data();
273
+        }
274
+        return $this->report_data;
275
+    }
276
+
277
+    /**
278
+     * Get all data needed for this report and store in the class.
279
+     */
280
+    protected function query_report_data() {
281
+
282
+        // Prepare reports.
283
+        $this->report_data = (object) array(
284
+            'invoice_counts' => $this->query_invoice_counts(), //count, post_date
285
+            'coupons'        => $this->query_coupon_counts(), // discount_amount, post_date
286
+            'invoice_items'  => $this->query_item_counts(), // invoice_item_count, post_date
287
+            'refunded_items' => $this->count_refunded_items(), // invoice_item_count, post_date
288
+            'invoices'       => $this->query_invoice_totals(), // total_sales, total_tax, total_discount, total_fees, subtotal, post_date
289
+            'refunds'        => $this->query_refunded_totals(), // total_sales, total_tax, total_discount, total_fees, subtotal, post_date
290
+            'previous_range' => $this->previous_range,
291
+        );
292
+
293
+        // Calculated totals.
294
+        $this->report_data->total_tax          = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_tax' ) ) );
295
+        $this->report_data->total_sales        = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_sales' ) ) );
296
+        $this->report_data->total_discount     = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_discount' ) ) );
297
+        $this->report_data->total_fees         = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_fees' ) ) );
298
+        $this->report_data->subtotal           = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'subtotal' ) ) );
299
+        $this->report_data->net_sales          = wpinv_round_amount( $this->report_data->total_sales - max( 0, $this->report_data->total_tax ) );
300
+        $this->report_data->total_refunded_tax = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_tax' ) ) );
301
+        $this->report_data->total_refunds      = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_sales' ) ) );
302
+        $this->report_data->refunded_discount  = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_discount' ) ) );
303
+        $this->report_data->refunded_fees      = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_fees' ) ) );
304
+        $this->report_data->refunded_subtotal  = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'subtotal' ) ) );
305
+        $this->report_data->net_refunds        = wpinv_round_amount( $this->report_data->total_refunds + max( 0, $this->report_data->total_refunded_tax ) );
306
+
307
+        // Calculate average based on net.
308
+        $this->report_data->average_sales       = wpinv_round_amount( $this->report_data->net_sales / max( $this->interval, 1 ), 2 );
309
+        $this->report_data->average_total_sales = wpinv_round_amount( $this->report_data->total_sales / max( $this->interval, 1 ), 2 );
310
+
311
+        // Total invoices in this period, even if refunded.
312
+        $this->report_data->total_invoices = absint( array_sum( wp_list_pluck( $this->report_data->invoice_counts, 'count' ) ) );
313
+
314
+        // Items invoiced in this period, even if refunded.
315
+        $this->report_data->total_items = absint( array_sum( wp_list_pluck( $this->report_data->invoice_items, 'invoice_item_count' ) ) );
316
+
317
+        // 3rd party filtering of report data
318
+        $this->report_data = apply_filters( 'getpaid_rest_api_filter_report_data', $this->report_data, $this );
319
+    }
320
+
321
+    /**
322
+     * Prepares invoice counts.
323
+     *
324
+     * @return array.
325
+     */
326
+    protected function query_invoice_counts() {
327
+
328
+        return (array) GetPaid_Reports_Helper::get_invoice_report_data(
329
+            array(
330
+                'data'           => array(
331
+                    'ID'        => array(
332
+                        'type'     => 'post_data',
333
+                        'function' => 'COUNT',
334
+                        'name'     => 'count',
335
+                        'distinct' => true,
336
+                    ),
337
+                    'post_date' => array(
338
+                        'type'     => 'post_data',
339
+                        'function' => 'MIN',
340
+                        'name'     => 'post_date',
341
+                    ),
342
+                ),
343
+                'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
344
+                'order_by'       => 'post_date ASC',
345
+                'query_type'     => 'get_results',
346
+                'filter_range'   => $this->report_range,
347
+                'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
348
+            )
349
+        );
350
+
351
+    }
352
+
353
+    /**
354
+     * Prepares coupon counts.
355
+     *
356
+     * @return array.
357
+     */
358
+    protected function query_coupon_counts() {
359
+
360
+        return (array) GetPaid_Reports_Helper::get_invoice_report_data(
361
+            array(
362
+                'data'           => array(
363
+                    'discount'  => array(
364
+                        'type'     => 'invoice_data',
365
+                        'function' => 'SUM',
366
+                        'name'     => 'discount_amount',
367
+                    ),
368
+                    'post_date' => array(
369
+                        'type'     => 'post_data',
370
+                        'function' => 'MIN',
371
+                        'name'     => 'post_date',
372
+                    ),
373
+                ),
374
+                'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
375
+                'order_by'       => 'post_date ASC',
376
+                'query_type'     => 'get_results',
377
+                'filter_range'   => $this->report_range,
378
+                'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
379
+            )
380
+        );
381
+
382
+    }
383
+
384
+    /**
385
+     * Prepares item counts.
386
+     *
387
+     * @return array.
388
+     */
389
+    protected function query_item_counts() {
390
+
391
+        return (array) GetPaid_Reports_Helper::get_invoice_report_data(
392
+            array(
393
+                'data'           => array(
394
+                    'quantity'  => array(
395
+                        'type'     => 'invoice_item',
396
+                        'function' => 'SUM',
397
+                        'name'     => 'invoice_item_count',
398
+                    ),
399
+                    'post_date' => array(
400
+                        'type'     => 'post_data',
401
+                        'function' => 'MIN',
402
+                        'name'     => 'post_date',
403
+                    ),
404
+                ),
405
+                'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
406
+                'order_by'       => 'post_date ASC',
407
+                'query_type'     => 'get_results',
408
+                'filter_range'   => $this->report_range,
409
+                'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
410
+            )
411
+        );
412
+
413
+    }
414
+
415
+    /**
416
+     * Prepares refunded item counts.
417
+     *
418
+     * @return array.
419
+     */
420
+    protected function count_refunded_items() {
421
+
422
+        return (int) GetPaid_Reports_Helper::get_invoice_report_data(
423
+            array(
424
+                'data'           => array(
425
+                    'quantity' => array(
426
+                        'type'     => 'invoice_item',
427
+                        'function' => 'SUM',
428
+                        'name'     => 'invoice_item_count',
429
+                    ),
430
+                ),
431
+                'query_type'     => 'get_var',
432
+                'filter_range'   => $this->report_range,
433
+                'invoice_status' => array( 'wpi-refunded' ),
434
+            )
435
+        );
436
+
437
+    }
438
+
439
+    /**
440
+     * Prepares daily invoice totals.
441
+     *
442
+     * @return array.
443
+     */
444
+    protected function query_invoice_totals() {
445
+
446
+        return (array) GetPaid_Reports_Helper::get_invoice_report_data(
447
+            array(
448
+                'data'           => array(
449
+                    'total'      => array(
450
+                        'type'     => 'invoice_data',
451
+                        'function' => 'SUM',
452
+                        'name'     => 'total_sales',
453
+                    ),
454
+                    'tax'        => array(
455
+                        'type'     => 'invoice_data',
456
+                        'function' => 'SUM',
457
+                        'name'     => 'total_tax',
458
+                    ),
459
+                    'discount'   => array(
460
+                        'type'     => 'invoice_data',
461
+                        'function' => 'SUM',
462
+                        'name'     => 'total_discount',
463
+                    ),
464
+                    'fees_total' => array(
465
+                        'type'     => 'invoice_data',
466
+                        'function' => 'SUM',
467
+                        'name'     => 'total_fees',
468
+                    ),
469
+                    'subtotal'   => array(
470
+                        'type'     => 'invoice_data',
471
+                        'function' => 'SUM',
472
+                        'name'     => 'subtotal',
473
+                    ),
474
+                    'post_date'  => array(
475
+                        'type'     => 'post_data',
476
+                        'function' => '',
477
+                        'name'     => 'post_date',
478
+                    ),
479
+                ),
480
+                'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
481
+                'order_by'       => 'post_date ASC',
482
+                'query_type'     => 'get_results',
483
+                'filter_range'   => $this->report_range,
484
+                'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-renewal' ),
485
+            )
486
+        );
487
+
488
+    }
489
+
490
+    /**
491
+     * Prepares daily invoice totals.
492
+     *
493
+     * @return array.
494
+     */
495
+    protected function query_refunded_totals() {
496
+
497
+        return (array) GetPaid_Reports_Helper::get_invoice_report_data(
498
+            array(
499
+                'data'           => array(
500
+                    'total'      => array(
501
+                        'type'     => 'invoice_data',
502
+                        'function' => 'SUM',
503
+                        'name'     => 'total_sales',
504
+                    ),
505
+                    'tax'        => array(
506
+                        'type'     => 'invoice_data',
507
+                        'function' => 'SUM',
508
+                        'name'     => 'total_tax',
509
+                    ),
510
+                    'discount'   => array(
511
+                        'type'     => 'invoice_data',
512
+                        'function' => 'SUM',
513
+                        'name'     => 'total_discount',
514
+                    ),
515
+                    'fees_total' => array(
516
+                        'type'     => 'invoice_data',
517
+                        'function' => 'SUM',
518
+                        'name'     => 'total_fees',
519
+                    ),
520
+                    'subtotal'   => array(
521
+                        'type'     => 'invoice_data',
522
+                        'function' => 'SUM',
523
+                        'name'     => 'subtotal',
524
+                    ),
525
+                    'post_date'  => array(
526
+                        'type'     => 'post_data',
527
+                        'function' => '',
528
+                        'name'     => 'post_date',
529
+                    ),
530
+                ),
531
+                'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
532
+                'order_by'       => 'post_date ASC',
533
+                'query_type'     => 'get_results',
534
+                'filter_range'   => $this->report_range,
535
+                'invoice_status' => array( 'wpi-refunded' ),
536
+            )
537
+        );
538
+
539
+    }
540
+
541
+    /**
542
+     * Get the Report's schema, conforming to JSON Schema.
543
+     *
544
+     * @return array
545
+     */
546
+    public function get_item_schema() {
547
+
548
+        $schema = array(
549
+            '$schema'    => 'http://json-schema.org/draft-04/schema#',
550
+            'title'      => 'sales_report',
551
+            'type'       => 'object',
552
+            'properties' => array(
553
+                'total_sales'         => array(
554
+                    'description' => __( 'Gross sales in the period.', 'invoicing' ),
555
+                    'type'        => 'string',
556
+                    'context'     => array( 'view' ),
557
+                    'readonly'    => true,
558
+                ),
559
+                'net_sales'           => array(
560
+                    'description' => __( 'Net sales in the period.', 'invoicing' ),
561
+                    'type'        => 'string',
562
+                    'context'     => array( 'view' ),
563
+                    'readonly'    => true,
564
+                ),
565
+                'average_sales'       => array(
566
+                    'description' => __( 'Average net daily sales.', 'invoicing' ),
567
+                    'type'        => 'string',
568
+                    'context'     => array( 'view' ),
569
+                    'readonly'    => true,
570
+                ),
571
+                'average_total_sales' => array(
572
+                    'description' => __( 'Average gross daily sales.', 'invoicing' ),
573
+                    'type'        => 'string',
574
+                    'context'     => array( 'view' ),
575
+                    'readonly'    => true,
576
+                ),
577
+                'total_invoices'      => array(
578
+                    'description' => __( 'Number of paid invoices.', 'invoicing' ),
579
+                    'type'        => 'integer',
580
+                    'context'     => array( 'view' ),
581
+                    'readonly'    => true,
582
+                ),
583
+                'total_items'         => array(
584
+                    'description' => __( 'Number of items purchased.', 'invoicing' ),
585
+                    'type'        => 'integer',
586
+                    'context'     => array( 'view' ),
587
+                    'readonly'    => true,
588
+                ),
589
+                'refunded_items'      => array(
590
+                    'description' => __( 'Number of items refunded.', 'invoicing' ),
591
+                    'type'        => 'integer',
592
+                    'context'     => array( 'view' ),
593
+                    'readonly'    => true,
594
+                ),
595
+                'total_tax'           => array(
596
+                    'description' => __( 'Total charged for taxes.', 'invoicing' ),
597
+                    'type'        => 'string',
598
+                    'context'     => array( 'view' ),
599
+                    'readonly'    => true,
600
+                ),
601
+                'total_refunded_tax'  => array(
602
+                    'description' => __( 'Total refunded for taxes.', 'invoicing' ),
603
+                    'type'        => 'string',
604
+                    'context'     => array( 'view' ),
605
+                    'readonly'    => true,
606
+                ),
607
+                'total_fees'          => array(
608
+                    'description' => __( 'Total fees charged.', 'invoicing' ),
609
+                    'type'        => 'string',
610
+                    'context'     => array( 'view' ),
611
+                    'readonly'    => true,
612
+                ),
613
+                'total_refunds'       => array(
614
+                    'description' => __( 'Total of refunded invoices.', 'invoicing' ),
615
+                    'type'        => 'integer',
616
+                    'context'     => array( 'view' ),
617
+                    'readonly'    => true,
618
+                ),
619
+                'net_refunds'         => array(
620
+                    'description' => __( 'Net of refunded invoices.', 'invoicing' ),
621
+                    'type'        => 'integer',
622
+                    'context'     => array( 'view' ),
623
+                    'readonly'    => true,
624
+                ),
625
+                'total_discount'      => array(
626
+                    'description' => __( 'Total of discounts used.', 'invoicing' ),
627
+                    'type'        => 'integer',
628
+                    'context'     => array( 'view' ),
629
+                    'readonly'    => true,
630
+                ),
631
+                'totals'              => array(
632
+                    'description' => __( 'Totals.', 'invoicing' ),
633
+                    'type'        => 'array',
634
+                    'items'       => array(
635
+                        'type' => 'array',
636
+                    ),
637
+                    'context'     => array( 'view' ),
638
+                    'readonly'    => true,
639
+                ),
640
+                'interval'            => array(
641
+                    'description' => __( 'Number of months/days in the report period.', 'invoicing' ),
642
+                    'type'        => 'integer',
643
+                    'context'     => array( 'view' ),
644
+                    'readonly'    => true,
645
+                ),
646
+                'previous_range'      => array(
647
+                    'description' => __( 'The previous report period.', 'invoicing' ),
648
+                    'type'        => 'array',
649
+                    'items'       => array(
650
+                        'type' => 'string',
651
+                    ),
652
+                    'context'     => array( 'view' ),
653
+                    'readonly'    => true,
654
+                ),
655
+                'grouped_by'          => array(
656
+                    'description' => __( 'The period used to group the totals.', 'invoicing' ),
657
+                    'type'        => 'string',
658
+                    'context'     => array( 'view' ),
659
+                    'enum'        => array( 'day', 'month' ),
660
+                    'readonly'    => true,
661
+                ),
662
+                'currency'            => array(
663
+                    'description' => __( 'The default store currency.', 'invoicing' ),
664
+                    'type'        => 'string',
665
+                    'context'     => array( 'view' ),
666
+                    'readonly'    => true,
667
+                ),
668
+                'currency_symbol'     => array(
669
+                    'description' => __( 'The default store currency symbol.', 'invoicing' ),
670
+                    'type'        => 'string',
671
+                    'context'     => array( 'view' ),
672
+                    'readonly'    => true,
673
+                ),
674
+                'currency_position'   => array(
675
+                    'description' => __( 'The default store currency position.', 'invoicing' ),
676
+                    'type'        => 'string',
677
+                    'context'     => array( 'view' ),
678
+                    'readonly'    => true,
679
+                ),
680
+                'decimal_places'      => array(
681
+                    'description' => __( 'The default store decimal places.', 'invoicing' ),
682
+                    'type'        => 'string',
683
+                    'context'     => array( 'view' ),
684
+                    'readonly'    => true,
685
+                ),
686
+                'thousands_sep'       => array(
687
+                    'description' => __( 'The default store thousands separator.', 'invoicing' ),
688
+                    'type'        => 'string',
689
+                    'context'     => array( 'view' ),
690
+                    'readonly'    => true,
691
+                ),
692
+                'decimals_sep'        => array(
693
+                    'description' => __( 'The default store decimals separator.', 'invoicing' ),
694
+                    'type'        => 'string',
695
+                    'context'     => array( 'view' ),
696
+                    'readonly'    => true,
697
+                ),
698
+            ),
699
+        );
700
+
701
+        return $this->add_additional_fields_schema( $schema );
702
+
703
+    }
704 704
 
705 705
 }
Please login to merge, or discard this patch.
includes/api/class-getpaid-rest-date-based-controller.php 1 patch
Indentation   +492 added lines, -492 removed lines patch added patch discarded remove patch
@@ -16,496 +16,496 @@
 block discarded – undo
16 16
  */
17 17
 class GetPaid_REST_Date_Based_Controller extends GetPaid_REST_Controller {
18 18
 
19
-	/**
20
-	 * Group response items by day or month.
21
-	 *
22
-	 * @var string
23
-	 */
24
-	public $groupby = 'day';
25
-
26
-	/**
27
-	 * Returns an array with arguments to request the previous report.
28
-	 *
29
-	 * @var array
30
-	 */
31
-	public $previous_range = array();
32
-
33
-	/**
34
-	 * The period interval.
35
-	 *
36
-	 * @var int
37
-	 */
38
-	public $interval;
39
-
40
-	/**
41
-	 * Retrieves the before and after dates.
42
-	 *
43
-	 * @param WP_REST_Request $request Request object.
44
-	 * @return array The appropriate date range.
45
-	 */
46
-	public function get_date_range( $request ) {
47
-
48
-		// Check if the period is x_days.
49
-		if ( preg_match( '/^(\d+)_days$/', $request['period'], $matches ) ) {
50
-			$date_range = $this->get_x_days_date_range( absint( $matches[1] ) );
51
-		} elseif ( is_callable( array( $this, 'get_' . $request['period'] . '_date_range' ) ) ) {
52
-			$date_range = call_user_func( array( $this, 'get_' . $request['period'] . '_date_range' ), $request );
53
-		} else {
54
-			$request['period'] = '7_days';
55
-			$date_range        = $this->get_x_days_date_range();
56
-		}
57
-
58
-		// 3 months max for day view.
59
-		$before = strtotime( $date_range['before'] );
60
-		$after  = strtotime( $date_range['after'] );
61
-		if ( floor( ( $before - $after ) / MONTH_IN_SECONDS ) > 2 ) {
62
-			$this->groupby = 'month';
63
-		}
64
-
65
-		$this->prepare_interval( $date_range );
66
-
67
-		return $date_range;
68
-
69
-	}
70
-
71
-	/**
72
-	 * Groups by month or days.
73
-	 *
74
-	 * @param array $range Date range.
75
-	 * @return array The appropriate date range.
76
-	 */
77
-	public function prepare_interval( $range ) {
78
-
79
-		$before = strtotime( $range['before'] );
80
-		$after  = strtotime( $range['after'] );
81
-		if ( 'day' === $this->groupby ) {
82
-			$difference     = max( DAY_IN_SECONDS, ( DAY_IN_SECONDS + $before - $after ) ); // Prevent division by 0;
83
-			$this->interval = absint( ceil( max( 1, $difference / DAY_IN_SECONDS ) ) );
84
-			return;
85
-		}
86
-
87
-		$this->interval = 0;
88
-		$min_date       = strtotime( gmdate( 'Y-m-01', $after ) );
89
-
90
-		while ( $min_date <= $before ) {
91
-			$this->interval ++;
92
-			$min_date = strtotime( '+1 MONTH', $min_date );
93
-		}
94
-
95
-		$this->interval = max( 1, $this->interval );
96
-
97
-	}
98
-
99
-	/**
100
-	 * Retrieves a custom date range.
101
-	 *
102
-	 * @param WP_REST_Request $request Request object.
103
-	 * @return array The appropriate date range.
104
-	 */
105
-	public function get_custom_date_range( $request ) {
106
-
107
-		$after  = max( strtotime( '-20 years' ), strtotime( sanitize_text_field( $request['after'] ) ) );
108
-		$before = gmdate( 'Y-m-d' );
109
-
110
-		if ( ! empty( $request['before'] ) ) {
111
-			$before  = min( $before, strtotime( sanitize_text_field( $request['before'] ) ) );
112
-		}
113
-
114
-		// Set the previous date range.
115
-		$difference           = $before - $after;
116
-		$this->previous_range = array(
117
-			'period' => 'custom',
118
-			'before' => gmdate( 'Y-m-d', $before - $difference - DAY_IN_SECONDS ),
119
-			'after'  => gmdate( 'Y-m-d', $after - $difference - DAY_IN_SECONDS ),
120
-		);
121
-
122
-		// Generate the report.
123
-		return array(
124
-			'before' => gmdate( 'Y-m-d', $before ),
125
-			'after'  => gmdate( 'Y-m-d', $after ),
126
-		);
127
-
128
-	}
129
-
130
-	/**
131
-	 * Retrieves todays date range.
132
-	 *
133
-	 * @return array The appropriate date range.
134
-	 */
135
-	public function get_today_date_range() {
136
-
137
-		// Set the previous date range.
138
-		$this->previous_range = array(
139
-			'period' => 'yesterday',
140
-		);
141
-
142
-		// Generate the report.
143
-		return array(
144
-			'before' => gmdate( 'Y-m-d' ),
145
-			'after'  => gmdate( 'Y-m-d' ),
146
-		);
147
-
148
-	}
149
-
150
-	/**
151
-	 * Retrieves yesterdays date range.
152
-	 *
153
-	 * @return array The appropriate date range.
154
-	 */
155
-	public function get_yesterday_date_range() {
156
-
157
-		// Set the previous date range.
158
-		$this->previous_range = array(
159
-			'period' => 'custom',
160
-			'before' => gmdate( 'Y-m-d', strtotime( '-2 days' ) ),
161
-			'after'  => gmdate( 'Y-m-d', strtotime( '-2 days' ) ),
162
-		);
163
-
164
-		// Generate the report.
165
-		return array(
166
-			'before' => gmdate( 'Y-m-d', strtotime( '-1 day' ) ),
167
-			'after'  => gmdate( 'Y-m-d', strtotime( '-1 day' ) ),
168
-		);
169
-
170
-	}
171
-
172
-	/**
173
-	 * Retrieves this week's date range.
174
-	 *
175
-	 * @return array The appropriate date range.
176
-	 */
177
-	public function get_week_date_range() {
178
-
179
-		// Set the previous date range.
180
-		$this->previous_range = array(
181
-			'period' => 'last_week',
182
-		);
183
-
184
-		// Generate the report.
185
-		$week_starts = absint( get_option( 'start_of_week' ) );
186
-		return array(
187
-			'before' => gmdate( 'Y-m-d' ),
188
-			'after'  => gmdate( 'Y-m-d', strtotime( 'next Sunday -' . ( 7 - $week_starts ) . ' days' ) ),
189
-		);
190
-	}
191
-
192
-	/**
193
-	 * Retrieves last week's date range.
194
-	 *
195
-	 * @return array The appropriate date range.
196
-	 */
197
-	public function get_last_week_date_range() {
198
-
199
-		$week_starts = absint( get_option( 'start_of_week' ) );
200
-		$week_starts = strtotime( 'last Sunday -' . ( 7 - $week_starts ) . ' days' );
201
-		$date_range  = array(
202
-			'before' => gmdate( 'Y-m-d', $week_starts + 6 * DAY_IN_SECONDS ),
203
-			'after'  => gmdate( 'Y-m-d', $week_starts ),
204
-		);
205
-
206
-		// Set the previous date range.
207
-		$week_starts          = $week_starts - 7 * DAY_IN_SECONDS;
208
-		$this->previous_range = array(
209
-			'period' => 'custom',
210
-			'before' => gmdate( 'Y-m-d', $week_starts + 6 * DAY_IN_SECONDS ),
211
-			'after'  => gmdate( 'Y-m-d', $week_starts ),
212
-		);
213
-
214
-		// Generate the report.
215
-		return $date_range;
216
-	}
217
-
218
-	/**
219
-	 * Retrieves last x days date range.
220
-	 *
221
-	 * @return array The appropriate date range.
222
-	 */
223
-	public function get_x_days_date_range( $days = 7 ) {
224
-
225
-		$days--;
226
-
227
-		$date_range  = array(
228
-			'before' => gmdate( 'Y-m-d' ),
229
-			'after'  => gmdate( 'Y-m-d', strtotime( "-$days days" ) ),
230
-		);
231
-
232
-		$days++;
233
-
234
-		// Set the previous date range.
235
-		$this->previous_range = array(
236
-			'period' => 'custom',
237
-			'before' => gmdate( 'Y-m-d', strtotime( $date_range['before'] ) - $days * DAY_IN_SECONDS ),
238
-			'after'  => gmdate( 'Y-m-d', strtotime( $date_range['after'] ) - $days * DAY_IN_SECONDS ),
239
-		);
240
-
241
-		// Generate the report.
242
-		return $date_range;
243
-	}
244
-
245
-	/**
246
-	 * Retrieves this month date range.
247
-	 *
248
-	 * @return array The appropriate date range.
249
-	 */
250
-	public function get_month_date_range() {
251
-
252
-		// Set the previous date range.
253
-		$this->previous_range = array(
254
-			'period' => 'last_month',
255
-		);
256
-
257
-		// Generate the report.
258
-		return array(
259
-			'after'  => gmdate( 'Y-m-01' ),
260
-			'before' => gmdate( 'Y-m-t' ),
261
-		);
262
-
263
-	}
264
-
265
-	/**
266
-	 * Retrieves last month's date range.
267
-	 *
268
-	 * @return array The appropriate date range.
269
-	 */
270
-	public function get_last_month_date_range() {
271
-
272
-		// Set the previous date range.
273
-		$this->previous_range = array(
274
-			'period' => 'custom',
275
-			'after'  => gmdate( 'Y-m-01', strtotime( '-2 months' ) ),
276
-			'before' => gmdate( 'Y-m-t', strtotime( '-2 months' ) ),
277
-		);
278
-
279
-		// Generate the report.
280
-		return array(
281
-			'after'  => gmdate( 'Y-m-01', strtotime( 'last month' ) ),
282
-			'before' => gmdate( 'Y-m-t', strtotime( 'last month' ) ),
283
-		);
284
-
285
-	}
286
-
287
-	/**
288
-	 * Retrieves this quarter date range.
289
-	 *
290
-	 * @return array The available quarters.
291
-	 */
292
-	public function get_quarters() {
293
-
294
-		$year      = (int) gmdate( 'Y' );
295
-		$last_year = (int) $year - 1;
296
-		return array(
297
-
298
-			// Third quarter of previous year: July 1st to September 30th
299
-			array(
300
-				'before' => "{$last_year}-09-30",
301
-				'after'  => "{$last_year}-07-01",
302
-			),
303
-
304
-			// Last quarter of previous year: October 1st to December 31st
305
-			array(
306
-				'before' => "{$last_year}-12-31",
307
-        		'after'  => "{$last_year}-10-01",
308
-			),
309
-
310
-			// First quarter: January 1st to March 31st
311
-			array(
312
-				'before' => "{$year}-03-31",
313
-				'after'  => "{$year}-01-01",
314
-			),
315
-
316
-			// Second quarter: April 1st to June 30th
317
-			array(
318
-				'before' => "{$year}-06-30",
319
-				'after'  => "{$year}-04-01",
320
-			),
321
-
322
-			// Third quarter: July 1st to September 30th
323
-			array(
324
-				'before' => "{$year}-09-30",
325
-				'after'  => "{$year}-07-01",
326
-			),
327
-
328
-			// Fourth quarter: October 1st to December 31st
329
-			array(
330
-				'before' => "{$year}-12-31",
331
-				'after'  => "{$year}-10-01",
332
-			),
333
-		);
334
-	}
335
-
336
-	/**
337
-	 * Retrieves the current quater.
338
-	 *
339
-	 * @return int The current quarter.
340
-	 */
341
-	public function get_quarter() {
342
-
343
-		$month    = (int) gmdate( 'n' );
344
-		$quarters = array( 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4 );
345
-		return $quarters[ $month - 1 ];
346
-
347
-	}
348
-
349
-	/**
350
-	 * Retrieves this quarter date range.
351
-	 *
352
-	 * @return array The appropriate date range.
353
-	 */
354
-	public function get_quarter_date_range() {
355
-
356
-		// Set the previous date range.
357
-		$this->previous_range = array(
358
-			'period' => 'last_quarter',
359
-		);
360
-
361
-		// Generate the report.
362
-		$quarter  = $this->get_quarter();
363
-		$quarters = $this->get_quarters();
364
-		return $quarters[ $quarter + 1 ];
365
-
366
-	}
367
-
368
-	/**
369
-	 * Retrieves last quarter's date range.
370
-	 *
371
-	 * @return array The appropriate date range.
372
-	 */
373
-	public function get_last_quarter_date_range() {
374
-
375
-		$quarters = $this->get_quarters();
376
-		$quarter  = $this->get_quarter();
377
-
378
-		// Set the previous date range.
379
-		$this->previous_range = array_merge(
380
-			$quarters[ $quarter - 1 ],
381
-			array( 'period' => 'custom' )
382
-		);
383
-
384
-		// Generate the report.
385
-		return $quarters[ $quarter ];
386
-
387
-	}
388
-
389
-	/**
390
-	 * Retrieves this year date range.
391
-	 *
392
-	 * @return array The appropriate date range.
393
-	 */
394
-	public function get_year_date_range() {
395
-
396
-		// Set the previous date range.
397
-		$this->previous_range = array(
398
-			'period' => 'last_year',
399
-		);
400
-
401
-		// Generate the report.
402
-		return array(
403
-			'after'  => gmdate( 'Y-01-01' ),
404
-			'before' => gmdate( 'Y-12-31' ),
405
-		);
406
-
407
-	}
408
-
409
-	/**
410
-	 * Retrieves last year date range.
411
-	 *
412
-	 * @return array The appropriate date range.
413
-	 */
414
-	public function get_last_year_date_range() {
415
-
416
-		// Set the previous date range.
417
-		$this->previous_range = array(
418
-			'period' => 'custom',
419
-			'after'  => gmdate( 'Y-01-01', strtotime( '-2 years' ) ),
420
-			'before' => gmdate( 'Y-12-31', strtotime( '-2 years' ) ),
421
-		);
422
-
423
-		// Generate the report.
424
-		return array(
425
-			'after'  => gmdate( 'Y-01-01', strtotime( 'last year' ) ),
426
-			'before' => gmdate( 'Y-12-31', strtotime( 'last year' ) ),
427
-		);
428
-
429
-	}
430
-
431
-	/**
432
-	 * Prepare a the request date for SQL usage.
433
-	 *
434
-	 * @param WP_REST_Request $request Request object.
435
-	 * @param string $date_field The date field.
436
-	 * @return string The appropriate SQL.
437
-	 */
438
-	public function get_date_range_sql( $request, $date_field ) {
439
-		global $wpdb;
440
-
441
-		$sql = '1=1';
442
-		$range = $this->get_date_range( $request );
443
-
444
-		if ( ! empty( $range['after'] ) ) {
445
-			$sql .= ' AND ' . $wpdb->prepare(
446
-				"$date_field >= %s",
447
-				$range['after']
448
-			);
449
-		}
450
-
451
-		if ( ! empty( $range['before'] ) ) {
452
-			$sql .= ' AND ' . $wpdb->prepare(
453
-				"$date_field <= %s",
454
-				$range['before']
455
-			);
456
-		}
457
-
458
-		return $sql;
459
-
460
-	}
461
-
462
-	/**
463
-	 * Prepares a group by query.
464
-	 *
465
-	 * @param string $date_field The date field.
466
-	 * @return string The appropriate SQL.
467
-	 */
468
-	public function get_group_by_sql( $date_field ) {
469
-
470
-		if ( 'day' === $this->groupby ) {
471
-			return "YEAR($date_field), MONTH($date_field), DAY($date_field)";
472
-		}
473
-
474
-		return "YEAR($date_field), MONTH($date_field)";
475
-	}
476
-
477
-	/**
478
-	 * Get the query params for collections.
479
-	 *
480
-	 * @return array
481
-	 */
482
-	public function get_collection_params() {
483
-		return array(
484
-			'context' => $this->get_context_param( array( 'default' => 'view' ) ),
485
-			'period'  => array(
486
-				'description'       => __( 'Limit to results of a specific period.', 'invoicing' ),
487
-				'type'              => 'string',
488
-				'enum'              => array( 'custom', 'today', 'yesterday', 'week', 'last_week', '7_days', '30_days', '60_days', '90_days', '180_days', 'month', 'last_month', 'quarter', 'last_quarter', 'year', 'last_year', 'quarter', 'last_quarter' ),
489
-				'validate_callback' => 'rest_validate_request_arg',
490
-				'sanitize_callback' => 'sanitize_text_field',
491
-				'default'           => '7_days',
492
-			),
493
-			'after'   => array(
494
-				/* translators: %s: date format */
495
-				'description'       => sprintf( __( 'Limit to results after a specific date, the date needs to be in the %s format.', 'invoicing' ), 'YYYY-MM-DD' ),
496
-				'type'              => 'string',
497
-				'validate_callback' => 'rest_validate_request_arg',
498
-				'sanitize_callback' => 'sanitize_text_field',
499
-				'default'           => gmdate( 'Y-m-d', strtotime( '-7 days' ) ),
500
-			),
501
-			'before'  => array(
502
-				/* translators: %s: date format */
503
-				'description'       => sprintf( __( 'Limit to results before a specific date, the date needs to be in the %s format.', 'invoicing' ), 'YYYY-MM-DD' ),
504
-				'type'              => 'string',
505
-				'validate_callback' => 'rest_validate_request_arg',
506
-				'sanitize_callback' => 'sanitize_text_field',
507
-				'default'           => gmdate( 'Y-m-d' ),
508
-			),
509
-		);
510
-	}
19
+    /**
20
+     * Group response items by day or month.
21
+     *
22
+     * @var string
23
+     */
24
+    public $groupby = 'day';
25
+
26
+    /**
27
+     * Returns an array with arguments to request the previous report.
28
+     *
29
+     * @var array
30
+     */
31
+    public $previous_range = array();
32
+
33
+    /**
34
+     * The period interval.
35
+     *
36
+     * @var int
37
+     */
38
+    public $interval;
39
+
40
+    /**
41
+     * Retrieves the before and after dates.
42
+     *
43
+     * @param WP_REST_Request $request Request object.
44
+     * @return array The appropriate date range.
45
+     */
46
+    public function get_date_range( $request ) {
47
+
48
+        // Check if the period is x_days.
49
+        if ( preg_match( '/^(\d+)_days$/', $request['period'], $matches ) ) {
50
+            $date_range = $this->get_x_days_date_range( absint( $matches[1] ) );
51
+        } elseif ( is_callable( array( $this, 'get_' . $request['period'] . '_date_range' ) ) ) {
52
+            $date_range = call_user_func( array( $this, 'get_' . $request['period'] . '_date_range' ), $request );
53
+        } else {
54
+            $request['period'] = '7_days';
55
+            $date_range        = $this->get_x_days_date_range();
56
+        }
57
+
58
+        // 3 months max for day view.
59
+        $before = strtotime( $date_range['before'] );
60
+        $after  = strtotime( $date_range['after'] );
61
+        if ( floor( ( $before - $after ) / MONTH_IN_SECONDS ) > 2 ) {
62
+            $this->groupby = 'month';
63
+        }
64
+
65
+        $this->prepare_interval( $date_range );
66
+
67
+        return $date_range;
68
+
69
+    }
70
+
71
+    /**
72
+     * Groups by month or days.
73
+     *
74
+     * @param array $range Date range.
75
+     * @return array The appropriate date range.
76
+     */
77
+    public function prepare_interval( $range ) {
78
+
79
+        $before = strtotime( $range['before'] );
80
+        $after  = strtotime( $range['after'] );
81
+        if ( 'day' === $this->groupby ) {
82
+            $difference     = max( DAY_IN_SECONDS, ( DAY_IN_SECONDS + $before - $after ) ); // Prevent division by 0;
83
+            $this->interval = absint( ceil( max( 1, $difference / DAY_IN_SECONDS ) ) );
84
+            return;
85
+        }
86
+
87
+        $this->interval = 0;
88
+        $min_date       = strtotime( gmdate( 'Y-m-01', $after ) );
89
+
90
+        while ( $min_date <= $before ) {
91
+            $this->interval ++;
92
+            $min_date = strtotime( '+1 MONTH', $min_date );
93
+        }
94
+
95
+        $this->interval = max( 1, $this->interval );
96
+
97
+    }
98
+
99
+    /**
100
+     * Retrieves a custom date range.
101
+     *
102
+     * @param WP_REST_Request $request Request object.
103
+     * @return array The appropriate date range.
104
+     */
105
+    public function get_custom_date_range( $request ) {
106
+
107
+        $after  = max( strtotime( '-20 years' ), strtotime( sanitize_text_field( $request['after'] ) ) );
108
+        $before = gmdate( 'Y-m-d' );
109
+
110
+        if ( ! empty( $request['before'] ) ) {
111
+            $before  = min( $before, strtotime( sanitize_text_field( $request['before'] ) ) );
112
+        }
113
+
114
+        // Set the previous date range.
115
+        $difference           = $before - $after;
116
+        $this->previous_range = array(
117
+            'period' => 'custom',
118
+            'before' => gmdate( 'Y-m-d', $before - $difference - DAY_IN_SECONDS ),
119
+            'after'  => gmdate( 'Y-m-d', $after - $difference - DAY_IN_SECONDS ),
120
+        );
121
+
122
+        // Generate the report.
123
+        return array(
124
+            'before' => gmdate( 'Y-m-d', $before ),
125
+            'after'  => gmdate( 'Y-m-d', $after ),
126
+        );
127
+
128
+    }
129
+
130
+    /**
131
+     * Retrieves todays date range.
132
+     *
133
+     * @return array The appropriate date range.
134
+     */
135
+    public function get_today_date_range() {
136
+
137
+        // Set the previous date range.
138
+        $this->previous_range = array(
139
+            'period' => 'yesterday',
140
+        );
141
+
142
+        // Generate the report.
143
+        return array(
144
+            'before' => gmdate( 'Y-m-d' ),
145
+            'after'  => gmdate( 'Y-m-d' ),
146
+        );
147
+
148
+    }
149
+
150
+    /**
151
+     * Retrieves yesterdays date range.
152
+     *
153
+     * @return array The appropriate date range.
154
+     */
155
+    public function get_yesterday_date_range() {
156
+
157
+        // Set the previous date range.
158
+        $this->previous_range = array(
159
+            'period' => 'custom',
160
+            'before' => gmdate( 'Y-m-d', strtotime( '-2 days' ) ),
161
+            'after'  => gmdate( 'Y-m-d', strtotime( '-2 days' ) ),
162
+        );
163
+
164
+        // Generate the report.
165
+        return array(
166
+            'before' => gmdate( 'Y-m-d', strtotime( '-1 day' ) ),
167
+            'after'  => gmdate( 'Y-m-d', strtotime( '-1 day' ) ),
168
+        );
169
+
170
+    }
171
+
172
+    /**
173
+     * Retrieves this week's date range.
174
+     *
175
+     * @return array The appropriate date range.
176
+     */
177
+    public function get_week_date_range() {
178
+
179
+        // Set the previous date range.
180
+        $this->previous_range = array(
181
+            'period' => 'last_week',
182
+        );
183
+
184
+        // Generate the report.
185
+        $week_starts = absint( get_option( 'start_of_week' ) );
186
+        return array(
187
+            'before' => gmdate( 'Y-m-d' ),
188
+            'after'  => gmdate( 'Y-m-d', strtotime( 'next Sunday -' . ( 7 - $week_starts ) . ' days' ) ),
189
+        );
190
+    }
191
+
192
+    /**
193
+     * Retrieves last week's date range.
194
+     *
195
+     * @return array The appropriate date range.
196
+     */
197
+    public function get_last_week_date_range() {
198
+
199
+        $week_starts = absint( get_option( 'start_of_week' ) );
200
+        $week_starts = strtotime( 'last Sunday -' . ( 7 - $week_starts ) . ' days' );
201
+        $date_range  = array(
202
+            'before' => gmdate( 'Y-m-d', $week_starts + 6 * DAY_IN_SECONDS ),
203
+            'after'  => gmdate( 'Y-m-d', $week_starts ),
204
+        );
205
+
206
+        // Set the previous date range.
207
+        $week_starts          = $week_starts - 7 * DAY_IN_SECONDS;
208
+        $this->previous_range = array(
209
+            'period' => 'custom',
210
+            'before' => gmdate( 'Y-m-d', $week_starts + 6 * DAY_IN_SECONDS ),
211
+            'after'  => gmdate( 'Y-m-d', $week_starts ),
212
+        );
213
+
214
+        // Generate the report.
215
+        return $date_range;
216
+    }
217
+
218
+    /**
219
+     * Retrieves last x days date range.
220
+     *
221
+     * @return array The appropriate date range.
222
+     */
223
+    public function get_x_days_date_range( $days = 7 ) {
224
+
225
+        $days--;
226
+
227
+        $date_range  = array(
228
+            'before' => gmdate( 'Y-m-d' ),
229
+            'after'  => gmdate( 'Y-m-d', strtotime( "-$days days" ) ),
230
+        );
231
+
232
+        $days++;
233
+
234
+        // Set the previous date range.
235
+        $this->previous_range = array(
236
+            'period' => 'custom',
237
+            'before' => gmdate( 'Y-m-d', strtotime( $date_range['before'] ) - $days * DAY_IN_SECONDS ),
238
+            'after'  => gmdate( 'Y-m-d', strtotime( $date_range['after'] ) - $days * DAY_IN_SECONDS ),
239
+        );
240
+
241
+        // Generate the report.
242
+        return $date_range;
243
+    }
244
+
245
+    /**
246
+     * Retrieves this month date range.
247
+     *
248
+     * @return array The appropriate date range.
249
+     */
250
+    public function get_month_date_range() {
251
+
252
+        // Set the previous date range.
253
+        $this->previous_range = array(
254
+            'period' => 'last_month',
255
+        );
256
+
257
+        // Generate the report.
258
+        return array(
259
+            'after'  => gmdate( 'Y-m-01' ),
260
+            'before' => gmdate( 'Y-m-t' ),
261
+        );
262
+
263
+    }
264
+
265
+    /**
266
+     * Retrieves last month's date range.
267
+     *
268
+     * @return array The appropriate date range.
269
+     */
270
+    public function get_last_month_date_range() {
271
+
272
+        // Set the previous date range.
273
+        $this->previous_range = array(
274
+            'period' => 'custom',
275
+            'after'  => gmdate( 'Y-m-01', strtotime( '-2 months' ) ),
276
+            'before' => gmdate( 'Y-m-t', strtotime( '-2 months' ) ),
277
+        );
278
+
279
+        // Generate the report.
280
+        return array(
281
+            'after'  => gmdate( 'Y-m-01', strtotime( 'last month' ) ),
282
+            'before' => gmdate( 'Y-m-t', strtotime( 'last month' ) ),
283
+        );
284
+
285
+    }
286
+
287
+    /**
288
+     * Retrieves this quarter date range.
289
+     *
290
+     * @return array The available quarters.
291
+     */
292
+    public function get_quarters() {
293
+
294
+        $year      = (int) gmdate( 'Y' );
295
+        $last_year = (int) $year - 1;
296
+        return array(
297
+
298
+            // Third quarter of previous year: July 1st to September 30th
299
+            array(
300
+                'before' => "{$last_year}-09-30",
301
+                'after'  => "{$last_year}-07-01",
302
+            ),
303
+
304
+            // Last quarter of previous year: October 1st to December 31st
305
+            array(
306
+                'before' => "{$last_year}-12-31",
307
+                'after'  => "{$last_year}-10-01",
308
+            ),
309
+
310
+            // First quarter: January 1st to March 31st
311
+            array(
312
+                'before' => "{$year}-03-31",
313
+                'after'  => "{$year}-01-01",
314
+            ),
315
+
316
+            // Second quarter: April 1st to June 30th
317
+            array(
318
+                'before' => "{$year}-06-30",
319
+                'after'  => "{$year}-04-01",
320
+            ),
321
+
322
+            // Third quarter: July 1st to September 30th
323
+            array(
324
+                'before' => "{$year}-09-30",
325
+                'after'  => "{$year}-07-01",
326
+            ),
327
+
328
+            // Fourth quarter: October 1st to December 31st
329
+            array(
330
+                'before' => "{$year}-12-31",
331
+                'after'  => "{$year}-10-01",
332
+            ),
333
+        );
334
+    }
335
+
336
+    /**
337
+     * Retrieves the current quater.
338
+     *
339
+     * @return int The current quarter.
340
+     */
341
+    public function get_quarter() {
342
+
343
+        $month    = (int) gmdate( 'n' );
344
+        $quarters = array( 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4 );
345
+        return $quarters[ $month - 1 ];
346
+
347
+    }
348
+
349
+    /**
350
+     * Retrieves this quarter date range.
351
+     *
352
+     * @return array The appropriate date range.
353
+     */
354
+    public function get_quarter_date_range() {
355
+
356
+        // Set the previous date range.
357
+        $this->previous_range = array(
358
+            'period' => 'last_quarter',
359
+        );
360
+
361
+        // Generate the report.
362
+        $quarter  = $this->get_quarter();
363
+        $quarters = $this->get_quarters();
364
+        return $quarters[ $quarter + 1 ];
365
+
366
+    }
367
+
368
+    /**
369
+     * Retrieves last quarter's date range.
370
+     *
371
+     * @return array The appropriate date range.
372
+     */
373
+    public function get_last_quarter_date_range() {
374
+
375
+        $quarters = $this->get_quarters();
376
+        $quarter  = $this->get_quarter();
377
+
378
+        // Set the previous date range.
379
+        $this->previous_range = array_merge(
380
+            $quarters[ $quarter - 1 ],
381
+            array( 'period' => 'custom' )
382
+        );
383
+
384
+        // Generate the report.
385
+        return $quarters[ $quarter ];
386
+
387
+    }
388
+
389
+    /**
390
+     * Retrieves this year date range.
391
+     *
392
+     * @return array The appropriate date range.
393
+     */
394
+    public function get_year_date_range() {
395
+
396
+        // Set the previous date range.
397
+        $this->previous_range = array(
398
+            'period' => 'last_year',
399
+        );
400
+
401
+        // Generate the report.
402
+        return array(
403
+            'after'  => gmdate( 'Y-01-01' ),
404
+            'before' => gmdate( 'Y-12-31' ),
405
+        );
406
+
407
+    }
408
+
409
+    /**
410
+     * Retrieves last year date range.
411
+     *
412
+     * @return array The appropriate date range.
413
+     */
414
+    public function get_last_year_date_range() {
415
+
416
+        // Set the previous date range.
417
+        $this->previous_range = array(
418
+            'period' => 'custom',
419
+            'after'  => gmdate( 'Y-01-01', strtotime( '-2 years' ) ),
420
+            'before' => gmdate( 'Y-12-31', strtotime( '-2 years' ) ),
421
+        );
422
+
423
+        // Generate the report.
424
+        return array(
425
+            'after'  => gmdate( 'Y-01-01', strtotime( 'last year' ) ),
426
+            'before' => gmdate( 'Y-12-31', strtotime( 'last year' ) ),
427
+        );
428
+
429
+    }
430
+
431
+    /**
432
+     * Prepare a the request date for SQL usage.
433
+     *
434
+     * @param WP_REST_Request $request Request object.
435
+     * @param string $date_field The date field.
436
+     * @return string The appropriate SQL.
437
+     */
438
+    public function get_date_range_sql( $request, $date_field ) {
439
+        global $wpdb;
440
+
441
+        $sql = '1=1';
442
+        $range = $this->get_date_range( $request );
443
+
444
+        if ( ! empty( $range['after'] ) ) {
445
+            $sql .= ' AND ' . $wpdb->prepare(
446
+                "$date_field >= %s",
447
+                $range['after']
448
+            );
449
+        }
450
+
451
+        if ( ! empty( $range['before'] ) ) {
452
+            $sql .= ' AND ' . $wpdb->prepare(
453
+                "$date_field <= %s",
454
+                $range['before']
455
+            );
456
+        }
457
+
458
+        return $sql;
459
+
460
+    }
461
+
462
+    /**
463
+     * Prepares a group by query.
464
+     *
465
+     * @param string $date_field The date field.
466
+     * @return string The appropriate SQL.
467
+     */
468
+    public function get_group_by_sql( $date_field ) {
469
+
470
+        if ( 'day' === $this->groupby ) {
471
+            return "YEAR($date_field), MONTH($date_field), DAY($date_field)";
472
+        }
473
+
474
+        return "YEAR($date_field), MONTH($date_field)";
475
+    }
476
+
477
+    /**
478
+     * Get the query params for collections.
479
+     *
480
+     * @return array
481
+     */
482
+    public function get_collection_params() {
483
+        return array(
484
+            'context' => $this->get_context_param( array( 'default' => 'view' ) ),
485
+            'period'  => array(
486
+                'description'       => __( 'Limit to results of a specific period.', 'invoicing' ),
487
+                'type'              => 'string',
488
+                'enum'              => array( 'custom', 'today', 'yesterday', 'week', 'last_week', '7_days', '30_days', '60_days', '90_days', '180_days', 'month', 'last_month', 'quarter', 'last_quarter', 'year', 'last_year', 'quarter', 'last_quarter' ),
489
+                'validate_callback' => 'rest_validate_request_arg',
490
+                'sanitize_callback' => 'sanitize_text_field',
491
+                'default'           => '7_days',
492
+            ),
493
+            'after'   => array(
494
+                /* translators: %s: date format */
495
+                'description'       => sprintf( __( 'Limit to results after a specific date, the date needs to be in the %s format.', 'invoicing' ), 'YYYY-MM-DD' ),
496
+                'type'              => 'string',
497
+                'validate_callback' => 'rest_validate_request_arg',
498
+                'sanitize_callback' => 'sanitize_text_field',
499
+                'default'           => gmdate( 'Y-m-d', strtotime( '-7 days' ) ),
500
+            ),
501
+            'before'  => array(
502
+                /* translators: %s: date format */
503
+                'description'       => sprintf( __( 'Limit to results before a specific date, the date needs to be in the %s format.', 'invoicing' ), 'YYYY-MM-DD' ),
504
+                'type'              => 'string',
505
+                'validate_callback' => 'rest_validate_request_arg',
506
+                'sanitize_callback' => 'sanitize_text_field',
507
+                'default'           => gmdate( 'Y-m-d' ),
508
+            ),
509
+        );
510
+    }
511 511
 }
Please login to merge, or discard this patch.
includes/reports/class-getpaid-reports-helper.php 1 patch
Indentation   +276 added lines, -276 removed lines patch added patch discarded remove patch
@@ -12,294 +12,294 @@
 block discarded – undo
12 12
  */
13 13
 class GetPaid_Reports_Helper {
14 14
 
15
-	/**
16
-	 * Get report totals such as invoice totals and discount amounts.
17
-	 *
18
-	 * Data example:
19
-	 *
20
-	 * 'subtotal' => array(
21
-	 *     'type'     => 'invoice_data',
22
-	 *     'function' => 'SUM',
23
-	 *     'name'     => 'subtotal'
24
-	 * )
25
-	 *
26
-	 * @param  array $args
27
-	 * @return mixed depending on query_type
28
-	 */
29
-	public static function get_invoice_report_data( $args = array() ) {
30
-		global $wpdb;
31
-
32
-		$default_args = array(
33
-			'data'                  => array(), // The data to retrieve.
34
-			'where'                 => array(), // An array of where queries.
35
-			'query_type'            => 'get_row', // wpdb query to run.
36
-			'group_by'              => '', // What to group results by.
37
-			'order_by'              => '', // What to order by.
38
-			'limit'                 => '', // Results limit.
39
-			'filter_range'          => array(), // An array of before and after dates to limit results by.
40
-			'invoice_types'         => array( 'wpi_invoice' ), // An array of post types to retrieve.
41
-			'invoice_status'        => array( 'publish', 'wpi-processing', 'wpi-onhold' ),
42
-			'parent_invoice_status' => false, // Optionally filter by parent invoice status.
43
-		);
44
-
45
-		$args         = apply_filters( 'getpaid_reports_get_invoice_report_data_args', $args );
46
-		$args         = wp_parse_args( $args, $default_args );
47
-
48
-		extract( $args );
49
-
50
-		if ( empty( $data ) ) {
51
-			return '';
52
-		}
53
-
54
-		$query           = array();
55
-		$query['select'] = 'SELECT ' . implode( ',', self::prepare_invoice_data( $data ) );
56
-		$query['from']   = "FROM {$wpdb->posts} AS posts";
57
-		$query['join']   = implode( ' ', self::prepare_invoice_joins( $data + $where, ! empty( $parent_invoice_status ) ) );
58
-
59
-		$query['where']  = "
15
+    /**
16
+     * Get report totals such as invoice totals and discount amounts.
17
+     *
18
+     * Data example:
19
+     *
20
+     * 'subtotal' => array(
21
+     *     'type'     => 'invoice_data',
22
+     *     'function' => 'SUM',
23
+     *     'name'     => 'subtotal'
24
+     * )
25
+     *
26
+     * @param  array $args
27
+     * @return mixed depending on query_type
28
+     */
29
+    public static function get_invoice_report_data( $args = array() ) {
30
+        global $wpdb;
31
+
32
+        $default_args = array(
33
+            'data'                  => array(), // The data to retrieve.
34
+            'where'                 => array(), // An array of where queries.
35
+            'query_type'            => 'get_row', // wpdb query to run.
36
+            'group_by'              => '', // What to group results by.
37
+            'order_by'              => '', // What to order by.
38
+            'limit'                 => '', // Results limit.
39
+            'filter_range'          => array(), // An array of before and after dates to limit results by.
40
+            'invoice_types'         => array( 'wpi_invoice' ), // An array of post types to retrieve.
41
+            'invoice_status'        => array( 'publish', 'wpi-processing', 'wpi-onhold' ),
42
+            'parent_invoice_status' => false, // Optionally filter by parent invoice status.
43
+        );
44
+
45
+        $args         = apply_filters( 'getpaid_reports_get_invoice_report_data_args', $args );
46
+        $args         = wp_parse_args( $args, $default_args );
47
+
48
+        extract( $args );
49
+
50
+        if ( empty( $data ) ) {
51
+            return '';
52
+        }
53
+
54
+        $query           = array();
55
+        $query['select'] = 'SELECT ' . implode( ',', self::prepare_invoice_data( $data ) );
56
+        $query['from']   = "FROM {$wpdb->posts} AS posts";
57
+        $query['join']   = implode( ' ', self::prepare_invoice_joins( $data + $where, ! empty( $parent_invoice_status ) ) );
58
+
59
+        $query['where']  = "
60 60
 			WHERE 	posts.post_type 	IN ( '" . implode( "','", $invoice_types ) . "' )
61 61
 			";
62 62
 
63
-		if ( ! empty( $invoice_status ) ) {
64
-			$query['where'] .= "
63
+        if ( ! empty( $invoice_status ) ) {
64
+            $query['where'] .= "
65 65
 				AND 	posts.post_status 	IN ( '" . implode( "','", $invoice_status ) . "' )
66 66
 			";
67
-		}
68
-
69
-		if ( ! empty( $parent_invoice_status ) ) {
70
-			if ( ! empty( $invoice_status ) ) {
71
-				$query['where'] .= " AND ( parent.post_status IN ( '" . implode( "','", $parent_invoice_status ) . "' ) OR parent.ID IS NULL ) ";
72
-			} else {
73
-				$query['where'] .= " AND parent.post_status IN ( '" . implode( "','", $parent_invoice_status ) . "' ) ";
74
-			}
75
-		}
76
-
77
-		if ( ! empty( $filter_range['before'] ) ) {
78
-			$query['where'] .= "
67
+        }
68
+
69
+        if ( ! empty( $parent_invoice_status ) ) {
70
+            if ( ! empty( $invoice_status ) ) {
71
+                $query['where'] .= " AND ( parent.post_status IN ( '" . implode( "','", $parent_invoice_status ) . "' ) OR parent.ID IS NULL ) ";
72
+            } else {
73
+                $query['where'] .= " AND parent.post_status IN ( '" . implode( "','", $parent_invoice_status ) . "' ) ";
74
+            }
75
+        }
76
+
77
+        if ( ! empty( $filter_range['before'] ) ) {
78
+            $query['where'] .= "
79 79
 				AND 	posts.post_date <= '" . gmdate( 'Y-m-d 23:59:59', strtotime( $filter_range['before'] ) ) . "'
80 80
 			";
81
-		}
81
+        }
82 82
 
83
-		if ( ! empty( $filter_range['after'] ) ) {
84
-			$query['where'] .= "
83
+        if ( ! empty( $filter_range['after'] ) ) {
84
+            $query['where'] .= "
85 85
 				AND 	posts.post_date >= '" . gmdate( 'Y-m-d 00:00:00', strtotime( $filter_range['after'] ) ) . "'
86 86
 			";
87
-		}
87
+        }
88 88
 
89
-		if ( ! empty( $where ) ) {
89
+        if ( ! empty( $where ) ) {
90 90
 
91
-			foreach ( $where as $value ) {
91
+            foreach ( $where as $value ) {
92 92
 
93
-				if ( strtolower( $value['operator'] ) === 'in' || strtolower( $value['operator'] ) === 'not in' ) {
94
-
95
-					if ( is_array( $value['value'] ) ) {
96
-						$value['value'] = implode( "','", $value['value'] );
97
-					}
98
-
99
-					if ( ! empty( $value['value'] ) ) {
100
-						$where_value = "{$value['operator']} ('{$value['value']}')";
101
-					}
102
-				} else {
103
-					$where_value = "{$value['operator']} '{$value['value']}'";
104
-				}
105
-
106
-				if ( ! empty( $where_value ) ) {
107
-					$query['where'] .= " AND {$value['key']} {$where_value}";
108
-				}
109
-			}
110
-		}
111
-
112
-		if ( $group_by ) {
113
-			$query['group_by'] = "GROUP BY {$group_by}";
114
-		}
115
-
116
-		if ( $order_by ) {
117
-			$query['order_by'] = "ORDER BY {$order_by}";
118
-		}
119
-
120
-		if ( $limit ) {
121
-			$query['limit'] = "LIMIT {$limit}";
122
-		}
123
-
124
-		$query = apply_filters( 'getpaid_reports_get_invoice_report_query', $query, $data );
125
-		$query = implode( ' ', $query );
126
-
127
-		return self::execute( $query_type, $query );
128
-
129
-	}
130
-
131
-	/**
132
-	 * Prepares the data to select.
133
-	 *
134
-	 *
135
-	 * @param  array $data
136
-	 * @return array
137
-	 */
138
-	public static function prepare_invoice_data( $data ) {
139
-
140
-		$prepared = array();
141
-
142
-		foreach ( $data as $raw_key => $value ) {
143
-			$key      = sanitize_key( $raw_key );
144
-			$distinct = '';
145
-
146
-			if ( isset( $value['distinct'] ) ) {
147
-				$distinct = 'DISTINCT';
148
-			}
149
-
150
-			$get_key = self::get_invoice_table_key( $key, $value['type'] );
151
-
152
-			if ( false === $get_key ) {
153
-				// Skip to the next foreach iteration else the query will be invalid.
154
-				continue;
155
-			}
156
-
157
-			if ( ! empty( $value['function'] ) ) {
158
-				$get = "{$value['function']}({$distinct} {$get_key})";
159
-			} else {
160
-				$get = "{$distinct} {$get_key}";
161
-			}
162
-
163
-			$prepared[] = "{$get} as {$value['name']}";
164
-		}
165
-
166
-		return $prepared;
167
-
168
-	}
169
-
170
-	/**
171
-	 * Prepares the joins to use.
172
-	 *
173
-	 *
174
-	 * @param  array $data
175
-	 * @param  bool $with_parent
176
-	 * @return array
177
-	 */
178
-	public static function prepare_invoice_joins( $data, $with_parent ) {
179
-		global $wpdb;
180
-
181
-		$prepared = array();
182
-
183
-		foreach ( $data as $raw_key => $value ) {
184
-			$join_type = isset( $value['join_type'] ) ? $value['join_type'] : 'INNER';
185
-			$type      = isset( $value['type'] ) ? $value['type'] : false;
186
-			$key       = sanitize_key( $raw_key );
187
-
188
-			switch ( $type ) {
189
-				case 'meta':
190
-					$prepared[ "meta_{$key}" ] = "{$join_type} JOIN {$wpdb->postmeta} AS meta_{$key} ON ( posts.ID = meta_{$key}.post_id AND meta_{$key}.meta_key = '{$raw_key}' )";
191
-					break;
192
-				case 'parent_meta':
193
-					$prepared[ "parent_meta_{$key}" ] = "{$join_type} JOIN {$wpdb->postmeta} AS parent_meta_{$key} ON (posts.post_parent = parent_meta_{$key}.post_id) AND (parent_meta_{$key}.meta_key = '{$raw_key}')";
194
-					break;
195
-				case 'invoice_data':
196
-					$prepared['invoices'] = "{$join_type} JOIN {$wpdb->prefix}getpaid_invoices AS invoices ON posts.ID = invoices.post_id";
197
-					break;
198
-				case 'invoice_item':
199
-					$prepared['invoice_items'] = "{$join_type} JOIN {$wpdb->prefix}getpaid_invoice_items AS invoice_items ON posts.ID = invoice_items.post_id";
200
-					break;
201
-			}
202
-		}
203
-
204
-		if ( $with_parent ) {
205
-			$prepared['parent'] = "LEFT JOIN {$wpdb->posts} AS parent ON posts.post_parent = parent.ID";
206
-		}
207
-
208
-		return $prepared;
209
-
210
-	}
211
-
212
-	/**
213
-	 * Retrieves the appropriate table key to use.
214
-	 *
215
-	 *
216
-	 * @param  string $key
217
-	 * @param  string $table
218
-	 * @return string|false
219
-	 */
220
-	public static function get_invoice_table_key( $key, $table ) {
221
-
222
-		$keys = array(
223
-			'meta'         => "meta_{$key}.meta_value",
224
-			'parent_meta'  => "parent_meta_{$key}.meta_value",
225
-			'post_data'    => "posts.{$key}",
226
-			'invoice_data' => "invoices.{$key}",
227
-			'invoice_item' => "invoice_items.{$key}",
228
-		);
229
-
230
-		return isset( $keys[ $table ] ) ? $keys[ $table ] : false;
231
-
232
-	}
233
-
234
-	/**
235
-	 * Executes a query and caches the result for a minute.
236
-	 *
237
-	 *
238
-	 * @param  string $query_type
239
-	 * @param  string $query
240
-	 * @return mixed depending on query_type
241
-	 */
242
-	public static function execute( $query_type, $query ) {
243
-		global $wpdb;
244
-
245
-		$query_hash = md5( $query_type . $query );
246
-		$result     = self::get_cached_query( $query_hash );
247
-		if ( $result === false ) {
248
-			self::enable_big_selects();
249
-
250
-			$result = $wpdb->$query_type( $query );
251
-			self::set_cached_query( $query_hash, $result );
252
-		}
253
-
254
-		return $result;
255
-
256
-	}
257
-
258
-	/**
259
-	 * Enables big mysql selects for reports, just once for this session.
260
-	 */
261
-	protected static function enable_big_selects() {
262
-		static $big_selects = false;
263
-
264
-		global $wpdb;
265
-
266
-		if ( ! $big_selects ) {
267
-			$wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' );
268
-			$big_selects = true;
269
-		}
270
-	}
271
-
272
-	/**
273
-	 * Get the cached query result or null if it's not in the cache.
274
-	 *
275
-	 * @param string $query_hash The query hash.
276
-	 *
277
-	 * @return mixed|false The cache contents on success, false on failure to retrieve contents.
278
-	 */
279
-	protected static function get_cached_query( $query_hash ) {
280
-
281
-		return wp_cache_get(
282
-			$query_hash,
283
-			strtolower( __CLASS__ )
284
-		);
285
-
286
-	}
287
-
288
-	/**
289
-	 * Set the cached query result.
290
-	 *
291
-	 * @param string $query_hash The query hash.
292
-	 * @param mixed  $data The data to cache.
293
-	 */
294
-	protected static function set_cached_query( $query_hash, $data ) {
295
-
296
-		wp_cache_set(
297
-			$query_hash,
298
-			$data,
299
-			strtolower( __CLASS__ ),
300
-			MINUTE_IN_SECONDS
301
-		);
302
-
303
-	}
93
+                if ( strtolower( $value['operator'] ) === 'in' || strtolower( $value['operator'] ) === 'not in' ) {
94
+
95
+                    if ( is_array( $value['value'] ) ) {
96
+                        $value['value'] = implode( "','", $value['value'] );
97
+                    }
98
+
99
+                    if ( ! empty( $value['value'] ) ) {
100
+                        $where_value = "{$value['operator']} ('{$value['value']}')";
101
+                    }
102
+                } else {
103
+                    $where_value = "{$value['operator']} '{$value['value']}'";
104
+                }
105
+
106
+                if ( ! empty( $where_value ) ) {
107
+                    $query['where'] .= " AND {$value['key']} {$where_value}";
108
+                }
109
+            }
110
+        }
111
+
112
+        if ( $group_by ) {
113
+            $query['group_by'] = "GROUP BY {$group_by}";
114
+        }
115
+
116
+        if ( $order_by ) {
117
+            $query['order_by'] = "ORDER BY {$order_by}";
118
+        }
119
+
120
+        if ( $limit ) {
121
+            $query['limit'] = "LIMIT {$limit}";
122
+        }
123
+
124
+        $query = apply_filters( 'getpaid_reports_get_invoice_report_query', $query, $data );
125
+        $query = implode( ' ', $query );
126
+
127
+        return self::execute( $query_type, $query );
128
+
129
+    }
130
+
131
+    /**
132
+     * Prepares the data to select.
133
+     *
134
+     *
135
+     * @param  array $data
136
+     * @return array
137
+     */
138
+    public static function prepare_invoice_data( $data ) {
139
+
140
+        $prepared = array();
141
+
142
+        foreach ( $data as $raw_key => $value ) {
143
+            $key      = sanitize_key( $raw_key );
144
+            $distinct = '';
145
+
146
+            if ( isset( $value['distinct'] ) ) {
147
+                $distinct = 'DISTINCT';
148
+            }
149
+
150
+            $get_key = self::get_invoice_table_key( $key, $value['type'] );
151
+
152
+            if ( false === $get_key ) {
153
+                // Skip to the next foreach iteration else the query will be invalid.
154
+                continue;
155
+            }
156
+
157
+            if ( ! empty( $value['function'] ) ) {
158
+                $get = "{$value['function']}({$distinct} {$get_key})";
159
+            } else {
160
+                $get = "{$distinct} {$get_key}";
161
+            }
162
+
163
+            $prepared[] = "{$get} as {$value['name']}";
164
+        }
165
+
166
+        return $prepared;
167
+
168
+    }
169
+
170
+    /**
171
+     * Prepares the joins to use.
172
+     *
173
+     *
174
+     * @param  array $data
175
+     * @param  bool $with_parent
176
+     * @return array
177
+     */
178
+    public static function prepare_invoice_joins( $data, $with_parent ) {
179
+        global $wpdb;
180
+
181
+        $prepared = array();
182
+
183
+        foreach ( $data as $raw_key => $value ) {
184
+            $join_type = isset( $value['join_type'] ) ? $value['join_type'] : 'INNER';
185
+            $type      = isset( $value['type'] ) ? $value['type'] : false;
186
+            $key       = sanitize_key( $raw_key );
187
+
188
+            switch ( $type ) {
189
+                case 'meta':
190
+                    $prepared[ "meta_{$key}" ] = "{$join_type} JOIN {$wpdb->postmeta} AS meta_{$key} ON ( posts.ID = meta_{$key}.post_id AND meta_{$key}.meta_key = '{$raw_key}' )";
191
+                    break;
192
+                case 'parent_meta':
193
+                    $prepared[ "parent_meta_{$key}" ] = "{$join_type} JOIN {$wpdb->postmeta} AS parent_meta_{$key} ON (posts.post_parent = parent_meta_{$key}.post_id) AND (parent_meta_{$key}.meta_key = '{$raw_key}')";
194
+                    break;
195
+                case 'invoice_data':
196
+                    $prepared['invoices'] = "{$join_type} JOIN {$wpdb->prefix}getpaid_invoices AS invoices ON posts.ID = invoices.post_id";
197
+                    break;
198
+                case 'invoice_item':
199
+                    $prepared['invoice_items'] = "{$join_type} JOIN {$wpdb->prefix}getpaid_invoice_items AS invoice_items ON posts.ID = invoice_items.post_id";
200
+                    break;
201
+            }
202
+        }
203
+
204
+        if ( $with_parent ) {
205
+            $prepared['parent'] = "LEFT JOIN {$wpdb->posts} AS parent ON posts.post_parent = parent.ID";
206
+        }
207
+
208
+        return $prepared;
209
+
210
+    }
211
+
212
+    /**
213
+     * Retrieves the appropriate table key to use.
214
+     *
215
+     *
216
+     * @param  string $key
217
+     * @param  string $table
218
+     * @return string|false
219
+     */
220
+    public static function get_invoice_table_key( $key, $table ) {
221
+
222
+        $keys = array(
223
+            'meta'         => "meta_{$key}.meta_value",
224
+            'parent_meta'  => "parent_meta_{$key}.meta_value",
225
+            'post_data'    => "posts.{$key}",
226
+            'invoice_data' => "invoices.{$key}",
227
+            'invoice_item' => "invoice_items.{$key}",
228
+        );
229
+
230
+        return isset( $keys[ $table ] ) ? $keys[ $table ] : false;
231
+
232
+    }
233
+
234
+    /**
235
+     * Executes a query and caches the result for a minute.
236
+     *
237
+     *
238
+     * @param  string $query_type
239
+     * @param  string $query
240
+     * @return mixed depending on query_type
241
+     */
242
+    public static function execute( $query_type, $query ) {
243
+        global $wpdb;
244
+
245
+        $query_hash = md5( $query_type . $query );
246
+        $result     = self::get_cached_query( $query_hash );
247
+        if ( $result === false ) {
248
+            self::enable_big_selects();
249
+
250
+            $result = $wpdb->$query_type( $query );
251
+            self::set_cached_query( $query_hash, $result );
252
+        }
253
+
254
+        return $result;
255
+
256
+    }
257
+
258
+    /**
259
+     * Enables big mysql selects for reports, just once for this session.
260
+     */
261
+    protected static function enable_big_selects() {
262
+        static $big_selects = false;
263
+
264
+        global $wpdb;
265
+
266
+        if ( ! $big_selects ) {
267
+            $wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' );
268
+            $big_selects = true;
269
+        }
270
+    }
271
+
272
+    /**
273
+     * Get the cached query result or null if it's not in the cache.
274
+     *
275
+     * @param string $query_hash The query hash.
276
+     *
277
+     * @return mixed|false The cache contents on success, false on failure to retrieve contents.
278
+     */
279
+    protected static function get_cached_query( $query_hash ) {
280
+
281
+        return wp_cache_get(
282
+            $query_hash,
283
+            strtolower( __CLASS__ )
284
+        );
285
+
286
+    }
287
+
288
+    /**
289
+     * Set the cached query result.
290
+     *
291
+     * @param string $query_hash The query hash.
292
+     * @param mixed  $data The data to cache.
293
+     */
294
+    protected static function set_cached_query( $query_hash, $data ) {
295
+
296
+        wp_cache_set(
297
+            $query_hash,
298
+            $data,
299
+            strtolower( __CLASS__ ),
300
+            MINUTE_IN_SECONDS
301
+        );
302
+
303
+    }
304 304
 
305 305
 }
Please login to merge, or discard this patch.
includes/subscription-functions.php 1 patch
Indentation   +323 added lines, -323 removed lines patch added patch discarded remove patch
@@ -50,7 +50,7 @@  discard block
 block discarded – undo
50 50
  */
51 51
 function getpaid_get_invoice_subscription_group( $invoice_id, $subscription_id ) {
52 52
     $subscription_groups = getpaid_get_invoice_subscription_groups( $invoice_id );
53
-	$matching_group      = wp_list_filter( $subscription_groups, compact( 'subscription_id' ) );
53
+    $matching_group      = wp_list_filter( $subscription_groups, compact( 'subscription_id' ) );
54 54
     return reset( $matching_group );
55 55
 }
56 56
 
@@ -63,11 +63,11 @@  discard block
 block discarded – undo
63 63
  */
64 64
 function getpaid_get_subscription( $subscription ) {
65 65
 
66
-	if ( ! is_a( $subscription, 'WPInv_Subscription' ) ) {
67
-		$subscription = new WPInv_Subscription( $subscription );
68
-	}
66
+    if ( ! is_a( $subscription, 'WPInv_Subscription' ) ) {
67
+        $subscription = new WPInv_Subscription( $subscription );
68
+    }
69 69
 
70
-	return $subscription->exists() ? $subscription : false;
70
+    return $subscription->exists() ? $subscription : false;
71 71
 }
72 72
 
73 73
 /**
@@ -81,28 +81,28 @@  discard block
 block discarded – undo
81 81
  */
82 82
 function getpaid_get_subscriptions( $args = array(), $return = 'results' ) {
83 83
 
84
-	// Do not retrieve all fields if we just want the count.
85
-	if ( 'count' == $return ) {
86
-		$args['fields'] = 'id';
87
-		$args['number'] = 1;
88
-	}
84
+    // Do not retrieve all fields if we just want the count.
85
+    if ( 'count' == $return ) {
86
+        $args['fields'] = 'id';
87
+        $args['number'] = 1;
88
+    }
89 89
 
90
-	// Do not count all matches if we just want the results.
91
-	if ( 'results' == $return ) {
92
-		$args['count_total'] = false;
93
-	}
90
+    // Do not count all matches if we just want the results.
91
+    if ( 'results' == $return ) {
92
+        $args['count_total'] = false;
93
+    }
94 94
 
95
-	$query = new GetPaid_Subscriptions_Query( $args );
95
+    $query = new GetPaid_Subscriptions_Query( $args );
96 96
 
97
-	if ( 'results' == $return ) {
98
-		return $query->get_results();
99
-	}
97
+    if ( 'results' == $return ) {
98
+        return $query->get_results();
99
+    }
100 100
 
101
-	if ( 'count' == $return ) {
102
-		return $query->get_total();
103
-	}
101
+    if ( 'count' == $return ) {
102
+        return $query->get_total();
103
+    }
104 104
 
105
-	return $query;
105
+    return $query;
106 106
 }
107 107
 
108 108
 /**
@@ -112,18 +112,18 @@  discard block
 block discarded – undo
112 112
  */
113 113
 function getpaid_get_subscription_statuses() {
114 114
 
115
-	return apply_filters(
116
-		'getpaid_get_subscription_statuses',
117
-		array(
118
-			'pending'   => __( 'Pending', 'invoicing' ),
119
-			'trialling' => __( 'Trialing', 'invoicing' ),
120
-			'active'    => __( 'Active', 'invoicing' ),
121
-			'failing'   => __( 'Failing', 'invoicing' ),
122
-			'expired'   => __( 'Expired', 'invoicing' ),
123
-			'completed' => __( 'Complete', 'invoicing' ),
124
-			'cancelled' => __( 'Cancelled', 'invoicing' ),
125
-		)
126
-	);
115
+    return apply_filters(
116
+        'getpaid_get_subscription_statuses',
117
+        array(
118
+            'pending'   => __( 'Pending', 'invoicing' ),
119
+            'trialling' => __( 'Trialing', 'invoicing' ),
120
+            'active'    => __( 'Active', 'invoicing' ),
121
+            'failing'   => __( 'Failing', 'invoicing' ),
122
+            'expired'   => __( 'Expired', 'invoicing' ),
123
+            'completed' => __( 'Complete', 'invoicing' ),
124
+            'cancelled' => __( 'Cancelled', 'invoicing' ),
125
+        )
126
+    );
127 127
 
128 128
 }
129 129
 
@@ -133,8 +133,8 @@  discard block
 block discarded – undo
133 133
  * @return string
134 134
  */
135 135
 function getpaid_get_subscription_status_label( $status ) {
136
-	$statuses = getpaid_get_subscription_statuses();
137
-	return isset( $statuses[ $status ] ) ? $statuses[ $status ] : ucfirst( sanitize_text_field( $status ) );
136
+    $statuses = getpaid_get_subscription_statuses();
137
+    return isset( $statuses[ $status ] ) ? $statuses[ $status ] : ucfirst( sanitize_text_field( $status ) );
138 138
 }
139 139
 
140 140
 /**
@@ -144,18 +144,18 @@  discard block
 block discarded – undo
144 144
  */
145 145
 function getpaid_get_subscription_status_classes() {
146 146
 
147
-	return apply_filters(
148
-		'getpaid_get_subscription_status_classes',
149
-		array(
150
-			'pending'   => 'bg-dark',
151
-			'trialling' => 'bg-info',
152
-			'active'    => 'bg-success',
153
-			'failing'   => 'bg-warning text-dark',
154
-			'expired'   => 'bg-danger',
155
-			'completed' => 'bg-primary',
156
-			'cancelled' => 'bg-secondary',
157
-		)
158
-	);
147
+    return apply_filters(
148
+        'getpaid_get_subscription_status_classes',
149
+        array(
150
+            'pending'   => 'bg-dark',
151
+            'trialling' => 'bg-info',
152
+            'active'    => 'bg-success',
153
+            'failing'   => 'bg-warning text-dark',
154
+            'expired'   => 'bg-danger',
155
+            'completed' => 'bg-primary',
156
+            'cancelled' => 'bg-secondary',
157
+        )
158
+    );
159 159
 
160 160
 }
161 161
 
@@ -166,15 +166,15 @@  discard block
 block discarded – undo
166 166
  */
167 167
 function getpaid_get_subscription_status_counts( $args = array() ) {
168 168
 
169
-	$statuses = array_keys( getpaid_get_subscription_statuses() );
170
-	$counts   = array();
169
+    $statuses = array_keys( getpaid_get_subscription_statuses() );
170
+    $counts   = array();
171 171
 
172
-	foreach ( $statuses as $status ) {
173
-		$_args             = wp_parse_args( "status=$status", $args );
174
-		$counts[ $status ] = getpaid_get_subscriptions( $_args, 'count' );
175
-	}
172
+    foreach ( $statuses as $status ) {
173
+        $_args             = wp_parse_args( "status=$status", $args );
174
+        $counts[ $status ] = getpaid_get_subscriptions( $_args, 'count' );
175
+    }
176 176
 
177
-	return $counts;
177
+    return $counts;
178 178
 
179 179
 }
180 180
 
@@ -185,32 +185,32 @@  discard block
 block discarded – undo
185 185
  */
186 186
 function getpaid_get_subscription_periods() {
187 187
 
188
-	return apply_filters(
189
-		'getpaid_get_subscription_periods',
190
-		array(
188
+    return apply_filters(
189
+        'getpaid_get_subscription_periods',
190
+        array(
191 191
 
192
-			'day'   => array(
193
-				'singular' => __( '%s day', 'invoicing' ),
194
-				'plural'   => __( '%d days', 'invoicing' ),
195
-			),
192
+            'day'   => array(
193
+                'singular' => __( '%s day', 'invoicing' ),
194
+                'plural'   => __( '%d days', 'invoicing' ),
195
+            ),
196 196
 
197
-			'week'  => array(
198
-				'singular' => __( '%s week', 'invoicing' ),
199
-				'plural'   => __( '%d weeks', 'invoicing' ),
200
-			),
197
+            'week'  => array(
198
+                'singular' => __( '%s week', 'invoicing' ),
199
+                'plural'   => __( '%d weeks', 'invoicing' ),
200
+            ),
201 201
 
202
-			'month' => array(
203
-				'singular' => __( '%s month', 'invoicing' ),
204
-				'plural'   => __( '%d months', 'invoicing' ),
205
-			),
202
+            'month' => array(
203
+                'singular' => __( '%s month', 'invoicing' ),
204
+                'plural'   => __( '%d months', 'invoicing' ),
205
+            ),
206 206
 
207
-			'year'  => array(
208
-				'singular' => __( '%s year', 'invoicing' ),
209
-				'plural'   => __( '%d years', 'invoicing' ),
210
-			),
207
+            'year'  => array(
208
+                'singular' => __( '%s year', 'invoicing' ),
209
+                'plural'   => __( '%d years', 'invoicing' ),
210
+            ),
211 211
 
212
-		)
213
-	);
212
+        )
213
+    );
214 214
 
215 215
 }
216 216
 
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
  * @return int
222 222
  */
223 223
 function getpaid_get_subscription_trial_period_interval( $trial_period ) {
224
-	return (int) preg_replace( '/[^0-9]/', '', $trial_period );
224
+    return (int) preg_replace( '/[^0-9]/', '', $trial_period );
225 225
 }
226 226
 
227 227
 /**
@@ -231,7 +231,7 @@  discard block
 block discarded – undo
231 231
  * @return string
232 232
  */
233 233
 function getpaid_get_subscription_trial_period_period( $trial_period ) {
234
-	return preg_replace( '/[^a-z]/', '', strtolower( $trial_period ) );
234
+    return preg_replace( '/[^a-z]/', '', strtolower( $trial_period ) );
235 235
 }
236 236
 
237 237
 /**
@@ -242,8 +242,8 @@  discard block
 block discarded – undo
242 242
  * @return string
243 243
  */
244 244
 function getpaid_get_subscription_period_label( $period, $interval = 1, $singular_prefix = '1' ) {
245
-	$label = (int) $interval > 1 ? getpaid_get_plural_subscription_period_label( $period, $interval ) : getpaid_get_singular_subscription_period_label( $period, $singular_prefix );
246
-	return strtolower( sanitize_text_field( $label ) );
245
+    $label = (int) $interval > 1 ? getpaid_get_plural_subscription_period_label( $period, $interval ) : getpaid_get_singular_subscription_period_label( $period, $singular_prefix );
246
+    return strtolower( sanitize_text_field( $label ) );
247 247
 }
248 248
 
249 249
 /**
@@ -254,22 +254,22 @@  discard block
 block discarded – undo
254 254
  */
255 255
 function getpaid_get_singular_subscription_period_label( $period, $singular_prefix = '1' ) {
256 256
 
257
-	$periods = getpaid_get_subscription_periods();
258
-	$period  = strtolower( $period );
257
+    $periods = getpaid_get_subscription_periods();
258
+    $period  = strtolower( $period );
259 259
 
260
-	if ( isset( $periods[ $period ] ) ) {
261
-		return sprintf( $periods[ $period ]['singular'], $singular_prefix );
262
-	}
260
+    if ( isset( $periods[ $period ] ) ) {
261
+        return sprintf( $periods[ $period ]['singular'], $singular_prefix );
262
+    }
263 263
 
264
-	// Backwards compatibility.
265
-	foreach ( $periods as $key => $data ) {
266
-		if ( strpos( $key, $period ) === 0 ) {
267
-			return sprintf( $data['singular'], $singular_prefix );
268
-		}
269
-	}
264
+    // Backwards compatibility.
265
+    foreach ( $periods as $key => $data ) {
266
+        if ( strpos( $key, $period ) === 0 ) {
267
+            return sprintf( $data['singular'], $singular_prefix );
268
+        }
269
+    }
270 270
 
271
-	// Invalid string.
272
-	return '';
271
+    // Invalid string.
272
+    return '';
273 273
 }
274 274
 
275 275
 /**
@@ -281,22 +281,22 @@  discard block
 block discarded – undo
281 281
  */
282 282
 function getpaid_get_plural_subscription_period_label( $period, $interval ) {
283 283
 
284
-	$periods = getpaid_get_subscription_periods();
285
-	$period  = strtolower( $period );
284
+    $periods = getpaid_get_subscription_periods();
285
+    $period  = strtolower( $period );
286 286
 
287
-	if ( isset( $periods[ $period ] ) ) {
288
-		return sprintf( $periods[ $period ]['plural'], $interval );
289
-	}
287
+    if ( isset( $periods[ $period ] ) ) {
288
+        return sprintf( $periods[ $period ]['plural'], $interval );
289
+    }
290 290
 
291
-	// Backwards compatibility.
292
-	foreach ( $periods as $key => $data ) {
293
-		if ( strpos( $key, $period ) === 0 ) {
294
-			return sprintf( $data['plural'], $interval );
295
-		}
296
-	}
291
+    // Backwards compatibility.
292
+    foreach ( $periods as $key => $data ) {
293
+        if ( strpos( $key, $period ) === 0 ) {
294
+            return sprintf( $data['plural'], $interval );
295
+        }
296
+    }
297 297
 
298
-	// Invalid string.
299
-	return '';
298
+    // Invalid string.
299
+    return '';
300 300
 }
301 301
 
302 302
 /**
@@ -307,92 +307,92 @@  discard block
 block discarded – undo
307 307
  */
308 308
 function getpaid_get_formatted_subscription_amount( $subscription ) {
309 309
 
310
-	$initial    = wpinv_price( $subscription->get_initial_amount(), $subscription->get_parent_payment()->get_currency() );
311
-	$recurring  = wpinv_price( $subscription->get_recurring_amount(), $subscription->get_parent_payment()->get_currency() );
312
-	$period     = getpaid_get_subscription_period_label( $subscription->get_period(), $subscription->get_frequency(), '' );
313
-	$bill_times = $subscription->get_bill_times();
314
-	$bill_times_less = $bill_times - 1;
315
-
316
-	if ( ! empty( $bill_times ) ) {
317
-		$bill_times = $subscription->get_frequency() * $bill_times;
318
-		$bill_times_less = getpaid_get_subscription_period_label( $subscription->get_frequency(), $bill_times - $subscription->get_frequency() );
319
-		$bill_times = getpaid_get_subscription_period_label( $subscription->get_period(), $bill_times );
320
-	}
321
-
322
-	// Trial periods.
323
-	if ( $subscription->has_trial_period() ) {
324
-
325
-		$trial_period   = getpaid_get_subscription_trial_period_period( $subscription->get_trial_period() );
326
-		$trial_interval = getpaid_get_subscription_trial_period_interval( $subscription->get_trial_period() );
327
-
328
-		if ( empty( $bill_times ) ) {
329
-
330
-			return sprintf(
331
-				// translators: $1: is the initial amount, $2: is the trial period, $3: is the recurring amount, $4: is the recurring period
332
-				_x( '%1$s trial for %2$s then %3$s / %4$s', 'Subscription amount. (e.g.: $10 trial for 1 month then $120 / year)', 'invoicing' ),
333
-				$initial,
334
-				getpaid_get_subscription_period_label( $trial_period, $trial_interval ),
335
-				$recurring,
336
-				$period
337
-			);
338
-
339
-		}
340
-
341
-		return sprintf(
342
-			// translators: $1: is the initial amount, $2: is the trial period, $3: is the recurring amount, $4: is the recurring period, $5: is the bill times
343
-			_x( '%1$s trial for %2$s then %3$s / %4$s for %5$s', 'Subscription amount. (e.g.: $10 trial for 1 month then $120 / year for 4 years)', 'invoicing' ),
344
-			$initial,
345
-			getpaid_get_subscription_period_label( $trial_period, $trial_interval ),
346
-			$recurring,
347
-			$period,
348
-			$bill_times
349
-		);
350
-
351
-	}
352
-
353
-	if ( $initial != $recurring ) {
354
-
355
-		if ( empty( $bill_times ) ) {
356
-
357
-			return sprintf(
358
-				// translators: $1: is the initial amount, $2: is the recurring amount, $3: is the recurring period
359
-				_x( 'Initial payment of %1$s which renews at %2$s / %3$s', 'Subscription amount. (e.g.:Initial payment of $100 which renews at $120 / year)', 'invoicing' ),
360
-				$initial,
361
-				$recurring,
362
-				$period
363
-			);
364
-
365
-		}
366
-
367
-		return sprintf(
368
-			// translators: $1: is the initial amount, $2: is the recurring amount, $3: is the recurring period, $4: is the bill times
369
-			_x( 'Initial payment of %1$s which renews at %2$s / %3$s for %4$s', 'Subscription amount. (e.g.:Initial payment of $100 which renews at $120 / year for 5 years)', 'invoicing' ),
370
-			$initial,
371
-			$recurring,
372
-			$period,
373
-			$bill_times_less
374
-		);
375
-
376
-	}
377
-
378
-	if ( empty( $bill_times ) ) {
379
-
380
-		return sprintf(
381
-			// translators: $1: is the recurring amount, $2: is the recurring period
382
-			_x( '%1$s / %2$s', 'Subscription amount. (e.g.: $120 / year)', 'invoicing' ),
383
-			$initial,
384
-			$period
385
-		);
386
-
387
-	}
388
-
389
-	return sprintf(
390
-		// translators: $1: is the bill times, $2: is the recurring amount, $3: is the recurring period
391
-		_x( '%2$s / %3$s for %1$s', 'Subscription amount. (e.g.: $120 / year for 5 years)', 'invoicing' ),
392
-		$bill_times,
393
-		$initial,
394
-		$period
395
-	);
310
+    $initial    = wpinv_price( $subscription->get_initial_amount(), $subscription->get_parent_payment()->get_currency() );
311
+    $recurring  = wpinv_price( $subscription->get_recurring_amount(), $subscription->get_parent_payment()->get_currency() );
312
+    $period     = getpaid_get_subscription_period_label( $subscription->get_period(), $subscription->get_frequency(), '' );
313
+    $bill_times = $subscription->get_bill_times();
314
+    $bill_times_less = $bill_times - 1;
315
+
316
+    if ( ! empty( $bill_times ) ) {
317
+        $bill_times = $subscription->get_frequency() * $bill_times;
318
+        $bill_times_less = getpaid_get_subscription_period_label( $subscription->get_frequency(), $bill_times - $subscription->get_frequency() );
319
+        $bill_times = getpaid_get_subscription_period_label( $subscription->get_period(), $bill_times );
320
+    }
321
+
322
+    // Trial periods.
323
+    if ( $subscription->has_trial_period() ) {
324
+
325
+        $trial_period   = getpaid_get_subscription_trial_period_period( $subscription->get_trial_period() );
326
+        $trial_interval = getpaid_get_subscription_trial_period_interval( $subscription->get_trial_period() );
327
+
328
+        if ( empty( $bill_times ) ) {
329
+
330
+            return sprintf(
331
+                // translators: $1: is the initial amount, $2: is the trial period, $3: is the recurring amount, $4: is the recurring period
332
+                _x( '%1$s trial for %2$s then %3$s / %4$s', 'Subscription amount. (e.g.: $10 trial for 1 month then $120 / year)', 'invoicing' ),
333
+                $initial,
334
+                getpaid_get_subscription_period_label( $trial_period, $trial_interval ),
335
+                $recurring,
336
+                $period
337
+            );
338
+
339
+        }
340
+
341
+        return sprintf(
342
+            // translators: $1: is the initial amount, $2: is the trial period, $3: is the recurring amount, $4: is the recurring period, $5: is the bill times
343
+            _x( '%1$s trial for %2$s then %3$s / %4$s for %5$s', 'Subscription amount. (e.g.: $10 trial for 1 month then $120 / year for 4 years)', 'invoicing' ),
344
+            $initial,
345
+            getpaid_get_subscription_period_label( $trial_period, $trial_interval ),
346
+            $recurring,
347
+            $period,
348
+            $bill_times
349
+        );
350
+
351
+    }
352
+
353
+    if ( $initial != $recurring ) {
354
+
355
+        if ( empty( $bill_times ) ) {
356
+
357
+            return sprintf(
358
+                // translators: $1: is the initial amount, $2: is the recurring amount, $3: is the recurring period
359
+                _x( 'Initial payment of %1$s which renews at %2$s / %3$s', 'Subscription amount. (e.g.:Initial payment of $100 which renews at $120 / year)', 'invoicing' ),
360
+                $initial,
361
+                $recurring,
362
+                $period
363
+            );
364
+
365
+        }
366
+
367
+        return sprintf(
368
+            // translators: $1: is the initial amount, $2: is the recurring amount, $3: is the recurring period, $4: is the bill times
369
+            _x( 'Initial payment of %1$s which renews at %2$s / %3$s for %4$s', 'Subscription amount. (e.g.:Initial payment of $100 which renews at $120 / year for 5 years)', 'invoicing' ),
370
+            $initial,
371
+            $recurring,
372
+            $period,
373
+            $bill_times_less
374
+        );
375
+
376
+    }
377
+
378
+    if ( empty( $bill_times ) ) {
379
+
380
+        return sprintf(
381
+            // translators: $1: is the recurring amount, $2: is the recurring period
382
+            _x( '%1$s / %2$s', 'Subscription amount. (e.g.: $120 / year)', 'invoicing' ),
383
+            $initial,
384
+            $period
385
+        );
386
+
387
+    }
388
+
389
+    return sprintf(
390
+        // translators: $1: is the bill times, $2: is the recurring amount, $3: is the recurring period
391
+        _x( '%2$s / %3$s for %1$s', 'Subscription amount. (e.g.: $120 / year for 5 years)', 'invoicing' ),
392
+        $bill_times,
393
+        $initial,
394
+        $period
395
+    );
396 396
 
397 397
 }
398 398
 
@@ -403,7 +403,7 @@  discard block
 block discarded – undo
403 403
  * @return WPInv_Subscription|false
404 404
  */
405 405
 function getpaid_get_invoice_subscription( $invoice ) {
406
-	return getpaid_subscriptions()->get_invoice_subscription( $invoice );
406
+    return getpaid_subscriptions()->get_invoice_subscription( $invoice );
407 407
 }
408 408
 
409 409
 /**
@@ -412,10 +412,10 @@  discard block
 block discarded – undo
412 412
  * @param WPInv_Invoice $invoice
413 413
  */
414 414
 function getpaid_activate_invoice_subscription( $invoice ) {
415
-	$subscription = getpaid_get_invoice_subscription( $invoice );
416
-	if ( is_a( $subscription, 'WPInv_Subscription' ) ) {
417
-		$subscription->activate();
418
-	}
415
+    $subscription = getpaid_get_invoice_subscription( $invoice );
416
+    if ( is_a( $subscription, 'WPInv_Subscription' ) ) {
417
+        $subscription->activate();
418
+    }
419 419
 }
420 420
 
421 421
 /**
@@ -424,7 +424,7 @@  discard block
 block discarded – undo
424 424
  * @return WPInv_Subscriptions
425 425
  */
426 426
 function getpaid_subscriptions() {
427
-	return getpaid()->get( 'subscriptions' );
427
+    return getpaid()->get( 'subscriptions' );
428 428
 }
429 429
 
430 430
 /**
@@ -443,15 +443,15 @@  discard block
 block discarded – undo
443 443
         return false;
444 444
     }
445 445
 
446
-	// Fetch the invoice subscription.
447
-	$subscription = getpaid_get_subscriptions(
448
-		array(
449
-			'invoice_in' => $invoice->is_renewal() ? $invoice->get_parent_id() : $invoice->get_id(),
450
-			'number'     => 1,
451
-		)
452
-	);
446
+    // Fetch the invoice subscription.
447
+    $subscription = getpaid_get_subscriptions(
448
+        array(
449
+            'invoice_in' => $invoice->is_renewal() ? $invoice->get_parent_id() : $invoice->get_id(),
450
+            'number'     => 1,
451
+        )
452
+    );
453 453
 
454
-	return empty( $subscription ) ? false : $subscription[0];
454
+    return empty( $subscription ) ? false : $subscription[0];
455 455
 
456 456
 }
457 457
 
@@ -468,48 +468,48 @@  discard block
 block discarded – undo
468 468
  */
469 469
 function getpaid_get_recurring_item_key( $cart_item ) {
470 470
 
471
-	$cart_key     = 'renews_';
472
-	$interval     = $cart_item->get_recurring_interval();
473
-	$period       = $cart_item->get_recurring_period( true );
474
-	$length       = $cart_item->get_recurring_limit() * $interval;
475
-	$trial_period = $cart_item->get_trial_period( true );
476
-	$trial_length = $cart_item->get_trial_interval();
477
-
478
-	// First start with the billing interval and period
479
-	switch ( $interval ) {
480
-		case 1:
481
-			if ( 'day' == $period ) {
482
-				$cart_key .= 'daily';
483
-			} else {
484
-				$cart_key .= sprintf( '%sly', $period );
485
-			}
486
-			break;
487
-		case 2:
488
-			$cart_key .= sprintf( 'every_2nd_%s', $period );
489
-			break;
490
-		case 3:
491
-			$cart_key .= sprintf( 'every_3rd_%s', $period );
492
-		    break;
493
-		default:
494
-			$cart_key .= sprintf( 'every_%dth_%s', $interval, $period );
495
-			break;
496
-	}
497
-
498
-	// Maybe add the optional maximum billing periods...
499
-	if ( $length > 0 ) {
500
-		$cart_key .= '_for_';
501
-		$cart_key .= sprintf( '%d_%s', $length, $period );
502
-		if ( $length > 1 ) {
503
-			$cart_key .= 's';
504
-		}
505
-	}
506
-
507
-	// And an optional free trial.
508
-	if ( $cart_item->has_free_trial() ) {
509
-		$cart_key .= sprintf( '_after_a_%d_%s_trial', $trial_length, $trial_period );
510
-	}
511
-
512
-	return apply_filters( 'getpaid_get_recurring_item_key', $cart_key, $cart_item );
471
+    $cart_key     = 'renews_';
472
+    $interval     = $cart_item->get_recurring_interval();
473
+    $period       = $cart_item->get_recurring_period( true );
474
+    $length       = $cart_item->get_recurring_limit() * $interval;
475
+    $trial_period = $cart_item->get_trial_period( true );
476
+    $trial_length = $cart_item->get_trial_interval();
477
+
478
+    // First start with the billing interval and period
479
+    switch ( $interval ) {
480
+        case 1:
481
+            if ( 'day' == $period ) {
482
+                $cart_key .= 'daily';
483
+            } else {
484
+                $cart_key .= sprintf( '%sly', $period );
485
+            }
486
+            break;
487
+        case 2:
488
+            $cart_key .= sprintf( 'every_2nd_%s', $period );
489
+            break;
490
+        case 3:
491
+            $cart_key .= sprintf( 'every_3rd_%s', $period );
492
+            break;
493
+        default:
494
+            $cart_key .= sprintf( 'every_%dth_%s', $interval, $period );
495
+            break;
496
+    }
497
+
498
+    // Maybe add the optional maximum billing periods...
499
+    if ( $length > 0 ) {
500
+        $cart_key .= '_for_';
501
+        $cart_key .= sprintf( '%d_%s', $length, $period );
502
+        if ( $length > 1 ) {
503
+            $cart_key .= 's';
504
+        }
505
+    }
506
+
507
+    // And an optional free trial.
508
+    if ( $cart_item->has_free_trial() ) {
509
+        $cart_key .= sprintf( '_after_a_%d_%s_trial', $trial_length, $trial_period );
510
+    }
511
+
512
+    return apply_filters( 'getpaid_get_recurring_item_key', $cart_key, $cart_item );
513 513
 }
514 514
 
515 515
 /**
@@ -520,16 +520,16 @@  discard block
 block discarded – undo
520 520
  */
521 521
 function getpaid_get_subscription_groups( $invoice ) {
522 522
 
523
-	// Generate subscription groups.
524
-	$subscription_groups = array();
525
-	foreach ( $invoice->get_items() as $item ) {
523
+    // Generate subscription groups.
524
+    $subscription_groups = array();
525
+    foreach ( $invoice->get_items() as $item ) {
526 526
 
527
-		if ( $item->is_recurring() ) {
528
-			$subscription_groups[ getpaid_get_recurring_item_key( $item ) ][] = $item;
529
-		}
527
+        if ( $item->is_recurring() ) {
528
+            $subscription_groups[ getpaid_get_recurring_item_key( $item ) ][] = $item;
529
+        }
530 530
 }
531 531
 
532
-	return $subscription_groups;
532
+    return $subscription_groups;
533 533
 }
534 534
 
535 535
 /**
@@ -543,56 +543,56 @@  discard block
 block discarded – undo
543 543
  */
544 544
 function getpaid_calculate_subscription_totals( $invoice ) {
545 545
 
546
-	// Generate subscription groups.
547
-	$subscription_groups = getpaid_get_subscription_groups( $invoice );
546
+    // Generate subscription groups.
547
+    $subscription_groups = getpaid_get_subscription_groups( $invoice );
548 548
 
549
-	// Now let's calculate the totals for each group of subscriptions
550
-	$subscription_totals = array();
549
+    // Now let's calculate the totals for each group of subscriptions
550
+    $subscription_totals = array();
551 551
 
552
-	foreach ( $subscription_groups as $subscription_key => $items ) {
552
+    foreach ( $subscription_groups as $subscription_key => $items ) {
553 553
 
554
-		if ( empty( $subscription_totals[ $subscription_key ] ) ) {
554
+        if ( empty( $subscription_totals[ $subscription_key ] ) ) {
555 555
 
556
-			$subscription_totals[ $subscription_key ] = array(
557
-				'initial_total'   => 0,
558
-				'recurring_total' => 0,
559
-				'items'           => array(),
560
-				'trialling'       => false,
561
-			);
556
+            $subscription_totals[ $subscription_key ] = array(
557
+                'initial_total'   => 0,
558
+                'recurring_total' => 0,
559
+                'items'           => array(),
560
+                'trialling'       => false,
561
+            );
562 562
 
563
-		}
563
+        }
564 564
 
565
-		/**
566
-		 * Get the totals of the group.
567
-		 * @var GetPaid_Form_Item $item
568
-		 */
569
-		foreach ( $items as $item ) {
565
+        /**
566
+         * Get the totals of the group.
567
+         * @var GetPaid_Form_Item $item
568
+         */
569
+        foreach ( $items as $item ) {
570 570
 
571
-			$subscription_totals[ $subscription_key ]['items'][ $item->get_id() ]  = $item->prepare_data_for_saving();
572
-			$subscription_totals[ $subscription_key ]['item_id']                 = $item->get_id();
573
-			$subscription_totals[ $subscription_key ]['period']                  = $item->get_recurring_period( true );
574
-			$subscription_totals[ $subscription_key ]['interval']                = $item->get_recurring_interval();
575
-			$subscription_totals[ $subscription_key ]['initial_total']          += $item->get_sub_total() + $item->item_tax - $item->item_discount;
576
-			$subscription_totals[ $subscription_key ]['recurring_total']        += $item->get_recurring_sub_total() + $item->item_tax - $item->recurring_item_discount;
577
-			$subscription_totals[ $subscription_key ]['recurring_limit']         = $item->get_recurring_limit();
571
+            $subscription_totals[ $subscription_key ]['items'][ $item->get_id() ]  = $item->prepare_data_for_saving();
572
+            $subscription_totals[ $subscription_key ]['item_id']                 = $item->get_id();
573
+            $subscription_totals[ $subscription_key ]['period']                  = $item->get_recurring_period( true );
574
+            $subscription_totals[ $subscription_key ]['interval']                = $item->get_recurring_interval();
575
+            $subscription_totals[ $subscription_key ]['initial_total']          += $item->get_sub_total() + $item->item_tax - $item->item_discount;
576
+            $subscription_totals[ $subscription_key ]['recurring_total']        += $item->get_recurring_sub_total() + $item->item_tax - $item->recurring_item_discount;
577
+            $subscription_totals[ $subscription_key ]['recurring_limit']         = $item->get_recurring_limit();
578 578
 
579
-			// Calculate the next renewal date.
580
-			$period       = $item->get_recurring_period( true );
581
-			$interval     = $item->get_recurring_interval();
579
+            // Calculate the next renewal date.
580
+            $period       = $item->get_recurring_period( true );
581
+            $interval     = $item->get_recurring_interval();
582 582
 
583
-			// If the subscription item has a trial period...
584
-			if ( $item->has_free_trial() ) {
585
-				$period   = $item->get_trial_period( true );
586
-				$interval = $item->get_trial_interval();
587
-				$subscription_totals[ $subscription_key ]['trialling'] = $interval . ' ' . $period;
588
-			}
583
+            // If the subscription item has a trial period...
584
+            if ( $item->has_free_trial() ) {
585
+                $period   = $item->get_trial_period( true );
586
+                $interval = $item->get_trial_interval();
587
+                $subscription_totals[ $subscription_key ]['trialling'] = $interval . ' ' . $period;
588
+            }
589 589
 
590
-			$subscription_totals[ $subscription_key ]['renews_on'] = date( 'Y-m-d H:i:s', strtotime( "+$interval $period", current_time( 'timestamp' ) ) );
590
+            $subscription_totals[ $subscription_key ]['renews_on'] = date( 'Y-m-d H:i:s', strtotime( "+$interval $period", current_time( 'timestamp' ) ) );
591 591
 
592
-		}
592
+        }
593 593
 }
594 594
 
595
-	return apply_filters( 'getpaid_calculate_subscription_totals', $subscription_totals, $invoice );
595
+    return apply_filters( 'getpaid_calculate_subscription_totals', $subscription_totals, $invoice );
596 596
 }
597 597
 
598 598
 /**
@@ -603,16 +603,16 @@  discard block
 block discarded – undo
603 603
  */
604 604
 function getpaid_should_group_subscriptions( $invoice ) {
605 605
 
606
-	$recurring_items = 0;
606
+    $recurring_items = 0;
607 607
 
608
-	foreach ( $invoice->get_items() as $item ) {
608
+    foreach ( $invoice->get_items() as $item ) {
609 609
 
610
-		if ( $item->is_recurring() ) {
611
-			$recurring_items ++;
612
-		}
610
+        if ( $item->is_recurring() ) {
611
+            $recurring_items ++;
612
+        }
613 613
 }
614 614
 
615
-	return apply_filters( 'getpaid_should_group_subscriptions', $recurring_items > 1, $invoice );
615
+    return apply_filters( 'getpaid_should_group_subscriptions', $recurring_items > 1, $invoice );
616 616
 }
617 617
 
618 618
 /**
@@ -623,39 +623,39 @@  discard block
 block discarded – undo
623 623
  * @return int
624 624
  */
625 625
 function getpaid_count_subscription_invoices( $parent_invoice_id, $subscription_id = false ) {
626
-	global $wpdb;
626
+    global $wpdb;
627 627
 
628
-	$parent_invoice_id = (int) $parent_invoice_id;
628
+    $parent_invoice_id = (int) $parent_invoice_id;
629 629
 
630
-	if ( false === $subscription_id || ! (bool) get_post_meta( $parent_invoice_id, '_wpinv_subscription_id', true ) ) {
630
+    if ( false === $subscription_id || ! (bool) get_post_meta( $parent_invoice_id, '_wpinv_subscription_id', true ) ) {
631 631
 
632
-		return (int) $wpdb->get_var(
633
-			$wpdb->prepare(
634
-				"SELECT COUNT(ID) FROM $wpdb->posts WHERE ( post_parent=%d OR ID=%d ) AND post_status IN ( 'publish', 'wpi-processing', 'wpi-renewal' )",
635
-				$parent_invoice_id,
636
-				$parent_invoice_id
637
-			)
638
-		);
632
+        return (int) $wpdb->get_var(
633
+            $wpdb->prepare(
634
+                "SELECT COUNT(ID) FROM $wpdb->posts WHERE ( post_parent=%d OR ID=%d ) AND post_status IN ( 'publish', 'wpi-processing', 'wpi-renewal' )",
635
+                $parent_invoice_id,
636
+                $parent_invoice_id
637
+            )
638
+        );
639 639
 
640
-	}
640
+    }
641 641
 
642
-	$invoice_ids = $wpdb->get_col(
643
-		$wpdb->prepare(
644
-			"SELECT ID FROM $wpdb->posts WHERE ( post_parent=%d OR ID=%d ) AND post_status IN ( 'publish', 'wpi-processing', 'wpi-renewal' )",
645
-			$parent_invoice_id,
646
-			$parent_invoice_id
647
-		)
648
-	);
642
+    $invoice_ids = $wpdb->get_col(
643
+        $wpdb->prepare(
644
+            "SELECT ID FROM $wpdb->posts WHERE ( post_parent=%d OR ID=%d ) AND post_status IN ( 'publish', 'wpi-processing', 'wpi-renewal' )",
645
+            $parent_invoice_id,
646
+            $parent_invoice_id
647
+        )
648
+    );
649 649
 
650
-	$count = 0;
650
+    $count = 0;
651 651
 
652
-	foreach ( wp_parse_id_list( $invoice_ids ) as $invoice_id ) {
652
+    foreach ( wp_parse_id_list( $invoice_ids ) as $invoice_id ) {
653 653
 
654
-		if ( $invoice_id == $parent_invoice_id || $subscription_id == (int) get_post_meta( $invoice_id, '_wpinv_subscription_id', true ) ) {
655
-			$count ++;
656
-			continue;
657
-		}
654
+        if ( $invoice_id == $parent_invoice_id || $subscription_id == (int) get_post_meta( $invoice_id, '_wpinv_subscription_id', true ) ) {
655
+            $count ++;
656
+            continue;
657
+        }
658 658
 }
659 659
 
660
-	return $count;
660
+    return $count;
661 661
 }
Please login to merge, or discard this patch.
includes/invoice-functions.php 1 patch
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -67,7 +67,7 @@  discard block
 block discarded – undo
67 67
  * Checks if the current user cna view an invoice receipt.
68 68
  */
69 69
 function wpinv_can_view_receipt( $invoice ) {
70
-	return (bool) apply_filters( 'wpinv_can_view_receipt', wpinv_user_can_view_invoice( $invoice ), $invoice );
70
+    return (bool) apply_filters( 'wpinv_can_view_receipt', wpinv_user_can_view_invoice( $invoice ), $invoice );
71 71
 }
72 72
 
73 73
 /**
@@ -556,37 +556,37 @@  discard block
 block discarded – undo
556 556
     $label   = empty( $label ) ? __( 'Invoice', 'invoicing' ) : sanitize_text_field( $label );
557 557
     $columns = array(
558 558
 
559
-		'invoice-number'  => array(
560
-			'title' => $label,
561
-			'class' => 'text-left',
562
-		),
559
+        'invoice-number'  => array(
560
+            'title' => $label,
561
+            'class' => 'text-left',
562
+        ),
563 563
 
564
-		'created-date'    => array(
565
-			'title' => __( 'Created Date', 'invoicing' ),
566
-			'class' => 'text-left',
567
-		),
564
+        'created-date'    => array(
565
+            'title' => __( 'Created Date', 'invoicing' ),
566
+            'class' => 'text-left',
567
+        ),
568 568
 
569
-		'payment-date'    => array(
570
-			'title' => __( 'Payment Date', 'invoicing' ),
571
-			'class' => 'text-left',
572
-		),
569
+        'payment-date'    => array(
570
+            'title' => __( 'Payment Date', 'invoicing' ),
571
+            'class' => 'text-left',
572
+        ),
573 573
 
574
-		'invoice-status'  => array(
575
-			'title' => __( 'Status', 'invoicing' ),
576
-			'class' => 'text-center',
577
-		),
574
+        'invoice-status'  => array(
575
+            'title' => __( 'Status', 'invoicing' ),
576
+            'class' => 'text-center',
577
+        ),
578 578
 
579
-		'invoice-total'   => array(
580
-			'title' => __( 'Total', 'invoicing' ),
581
-			'class' => 'text-right',
582
-		),
579
+        'invoice-total'   => array(
580
+            'title' => __( 'Total', 'invoicing' ),
581
+            'class' => 'text-right',
582
+        ),
583 583
 
584
-		'invoice-actions' => array(
585
-			'title' => '&nbsp;',
586
-			'class' => 'text-center',
587
-		),
584
+        'invoice-actions' => array(
585
+            'title' => '&nbsp;',
586
+            'class' => 'text-center',
587
+        ),
588 588
 
589
-	);
589
+    );
590 590
 
591 591
     return apply_filters( 'wpinv_user_invoices_columns', $columns, $post_type );
592 592
 }
@@ -1274,22 +1274,22 @@  discard block
 block discarded – undo
1274 1274
  */
1275 1275
 function getpaid_get_invoice_status_classes() {
1276 1276
 
1277
-	return apply_filters(
1278
-		'getpaid_get_invoice_status_classes',
1279
-		array(
1277
+    return apply_filters(
1278
+        'getpaid_get_invoice_status_classes',
1279
+        array(
1280 1280
             'wpi-quote-declined' => 'bg-danger',
1281 1281
             'wpi-failed'         => 'bg-danger',
1282
-			'wpi-processing'     => 'bg-info',
1283
-			'wpi-onhold'         => 'bg-warning text-dark',
1284
-			'wpi-quote-accepted' => 'bg-success',
1285
-			'publish'            => 'bg-success',
1286
-			'wpi-renewal'        => 'bg-primary',
1282
+            'wpi-processing'     => 'bg-info',
1283
+            'wpi-onhold'         => 'bg-warning text-dark',
1284
+            'wpi-quote-accepted' => 'bg-success',
1285
+            'publish'            => 'bg-success',
1286
+            'wpi-renewal'        => 'bg-primary',
1287 1287
             'wpi-cancelled'      => 'bg-secondary',
1288 1288
             'wpi-pending'        => 'bg-dark',
1289 1289
             'wpi-quote-pending'  => 'bg-dark',
1290 1290
             'wpi-refunded'       => 'bg-secondary',
1291
-		)
1292
-	);
1291
+        )
1292
+    );
1293 1293
 
1294 1294
 }
1295 1295
 
@@ -1303,7 +1303,7 @@  discard block
 block discarded – undo
1303 1303
 function getpaid_get_invoice_tax_rate( $invoice, $item ) {
1304 1304
 
1305 1305
     $rates   = getpaid_get_item_tax_rates( $item, $invoice->get_country(), $invoice->get_state() );
1306
-	$rates   = getpaid_filter_item_tax_rates( $item, $rates );
1306
+    $rates   = getpaid_filter_item_tax_rates( $item, $rates );
1307 1307
     $rates   = wp_list_pluck( $rates, 'rate' );
1308 1308
 
1309 1309
     return array_sum( $rates );
Please login to merge, or discard this patch.
includes/class-getpaid-daily-maintenance.php 1 patch
Indentation   +139 added lines, -139 removed lines patch added patch discarded remove patch
@@ -12,144 +12,144 @@
 block discarded – undo
12 12
  */
13 13
 class GetPaid_Daily_Maintenance {
14 14
 
15
-	/**
16
-	 * Class constructor.
17
-	 */
18
-	public function __construct() {
19
-
20
-		// Clear deprecated events.
21
-		add_action( 'wp', array( $this, 'maybe_clear_deprecated_events' ) );
22
-
23
-		// (Maybe) schedule a cron that runs daily.
24
-		add_action( 'wp', array( $this, 'maybe_create_scheduled_event' ) );
25
-
26
-		// Fired everyday at 7 a.m (this might vary for sites with few visitors)
27
-		add_action( 'getpaid_daily_maintenance', array( $this, 'log_cron_run' ) );
28
-		add_action( 'getpaid_daily_maintenance', array( $this, 'backwards_compat' ) );
29
-		add_action( 'getpaid_daily_maintenance', array( $this, 'maybe_expire_subscriptions' ) );
30
-		add_action( 'getpaid_daily_maintenance', array( $this, 'check_renewing_subscriptions' ) );
31
-		add_action( 'getpaid_daily_maintenance', array( $this, 'maybe_update_geoip_databases' ) );
32
-
33
-	}
34
-
35
-	/**
36
-	 * Schedules a cron to run every day at 7 a.m
37
-	 *
38
-	 */
39
-	public function maybe_create_scheduled_event() {
40
-
41
-		if ( ! wp_next_scheduled( 'getpaid_daily_maintenance' ) ) {
42
-			$timestamp = strtotime( 'tomorrow 07:00:00', current_time( 'timestamp' ) );
43
-			wp_schedule_event( $timestamp, 'daily', 'getpaid_daily_maintenance' );
44
-		}
45
-
46
-	}
47
-
48
-	/**
49
-	 * Clears deprecated events.
50
-	 *
51
-	 */
52
-	public function maybe_clear_deprecated_events() {
53
-
54
-		if ( ! get_option( 'wpinv_cleared_old_events' ) ) {
55
-			wp_clear_scheduled_hook( 'wpinv_register_schedule_event_twicedaily' );
56
-			wp_clear_scheduled_hook( 'wpinv_register_schedule_event_daily' );
57
-			update_option( 'wpinv_cleared_old_events', 1 );
58
-		}
59
-
60
-	}
61
-
62
-	/**
63
-	 * Fires the old hook for backwards compatibility.
64
-	 *
65
-	 */
66
-	public function backwards_compat() {
67
-		do_action( 'wpinv_register_schedule_event_daily' );
68
-	}
69
-
70
-	/**
71
-	 * Checks for subscriptions that are scheduled to renew.
72
-	 *
73
-	 */
74
-	public function check_renewing_subscriptions() {
75
-
76
-		// Fetch subscriptions that expire today.
77
-		$args  = array(
78
-			'number'             => -1,
79
-			'count_total'        => false,
80
-			'status'             => 'trialling active',
81
-			'date_expires_query' => array(
82
-				array(
83
-					'year'    => gmdate( 'Y' ),
84
-					'month'   => gmdate( 'n' ),
85
-					'day'     => gmdate( 'j' ),
86
-					'compare' => '=',
87
-				),
88
-			),
89
-		);
90
-
91
-		$subscriptions = new GetPaid_Subscriptions_Query( $args );
92
-
93
-		foreach ( $subscriptions->get_results() as $subscription ) {
94
-
95
-			/** @var WPInv_Subscription $subscription */
96
-			if ( $subscription->is_last_renewal() ) {
97
-				$subscription->complete();
98
-			} else {
99
-				do_action( 'getpaid_should_renew_subscription', $subscription );
100
-			}
101
-		}
102
-
103
-	}
104
-
105
-	/**
106
-	 * Expires expired subscriptions.
107
-	 *
108
-	 */
109
-	public function maybe_expire_subscriptions() {
110
-
111
-		// Fetch expired subscriptions (skips those that expire today).
112
-		$args  = array(
113
-			'number'             => -1,
114
-			'count_total'        => false,
115
-			'status'             => 'trialling active failing cancelled',
116
-			'date_expires_query' => array(
117
-				'before'    => 'yesterday',
118
-				'inclusive' => false,
119
-			),
120
-		);
121
-
122
-		$subscriptions = new GetPaid_Subscriptions_Query( $args );
123
-
124
-		foreach ( $subscriptions->get_results() as $subscription ) {
125
-			if ( apply_filters( 'getpaid_daily_maintenance_should_expire_subscription', false, $subscription ) ) {
126
-				$subscription->set_status( 'expired' );
127
-				$subscription->save();
128
-			}
129
-		}
130
-
131
-	}
132
-
133
-	/**
134
-	 * Logs cron runs.
135
-	 *
136
-	 */
137
-	public function log_cron_run() {
138
-		wpinv_error_log( 'GetPaid Daily Cron', false );
139
-	}
140
-
141
-	/**
142
-	 * Updates GeoIP databases.
143
-	 *
144
-	 */
145
-	public function maybe_update_geoip_databases() {
146
-		$updated = get_transient( 'getpaid_updated_geoip_databases' );
147
-
148
-		if ( false === $updated ) {
149
-			set_transient( 'getpaid_updated_geoip_databases', 1, 15 * DAY_IN_SECONDS );
150
-			do_action( 'getpaid_update_geoip_databases' );
151
-		}
152
-
153
-	}
15
+    /**
16
+     * Class constructor.
17
+     */
18
+    public function __construct() {
19
+
20
+        // Clear deprecated events.
21
+        add_action( 'wp', array( $this, 'maybe_clear_deprecated_events' ) );
22
+
23
+        // (Maybe) schedule a cron that runs daily.
24
+        add_action( 'wp', array( $this, 'maybe_create_scheduled_event' ) );
25
+
26
+        // Fired everyday at 7 a.m (this might vary for sites with few visitors)
27
+        add_action( 'getpaid_daily_maintenance', array( $this, 'log_cron_run' ) );
28
+        add_action( 'getpaid_daily_maintenance', array( $this, 'backwards_compat' ) );
29
+        add_action( 'getpaid_daily_maintenance', array( $this, 'maybe_expire_subscriptions' ) );
30
+        add_action( 'getpaid_daily_maintenance', array( $this, 'check_renewing_subscriptions' ) );
31
+        add_action( 'getpaid_daily_maintenance', array( $this, 'maybe_update_geoip_databases' ) );
32
+
33
+    }
34
+
35
+    /**
36
+     * Schedules a cron to run every day at 7 a.m
37
+     *
38
+     */
39
+    public function maybe_create_scheduled_event() {
40
+
41
+        if ( ! wp_next_scheduled( 'getpaid_daily_maintenance' ) ) {
42
+            $timestamp = strtotime( 'tomorrow 07:00:00', current_time( 'timestamp' ) );
43
+            wp_schedule_event( $timestamp, 'daily', 'getpaid_daily_maintenance' );
44
+        }
45
+
46
+    }
47
+
48
+    /**
49
+     * Clears deprecated events.
50
+     *
51
+     */
52
+    public function maybe_clear_deprecated_events() {
53
+
54
+        if ( ! get_option( 'wpinv_cleared_old_events' ) ) {
55
+            wp_clear_scheduled_hook( 'wpinv_register_schedule_event_twicedaily' );
56
+            wp_clear_scheduled_hook( 'wpinv_register_schedule_event_daily' );
57
+            update_option( 'wpinv_cleared_old_events', 1 );
58
+        }
59
+
60
+    }
61
+
62
+    /**
63
+     * Fires the old hook for backwards compatibility.
64
+     *
65
+     */
66
+    public function backwards_compat() {
67
+        do_action( 'wpinv_register_schedule_event_daily' );
68
+    }
69
+
70
+    /**
71
+     * Checks for subscriptions that are scheduled to renew.
72
+     *
73
+     */
74
+    public function check_renewing_subscriptions() {
75
+
76
+        // Fetch subscriptions that expire today.
77
+        $args  = array(
78
+            'number'             => -1,
79
+            'count_total'        => false,
80
+            'status'             => 'trialling active',
81
+            'date_expires_query' => array(
82
+                array(
83
+                    'year'    => gmdate( 'Y' ),
84
+                    'month'   => gmdate( 'n' ),
85
+                    'day'     => gmdate( 'j' ),
86
+                    'compare' => '=',
87
+                ),
88
+            ),
89
+        );
90
+
91
+        $subscriptions = new GetPaid_Subscriptions_Query( $args );
92
+
93
+        foreach ( $subscriptions->get_results() as $subscription ) {
94
+
95
+            /** @var WPInv_Subscription $subscription */
96
+            if ( $subscription->is_last_renewal() ) {
97
+                $subscription->complete();
98
+            } else {
99
+                do_action( 'getpaid_should_renew_subscription', $subscription );
100
+            }
101
+        }
102
+
103
+    }
104
+
105
+    /**
106
+     * Expires expired subscriptions.
107
+     *
108
+     */
109
+    public function maybe_expire_subscriptions() {
110
+
111
+        // Fetch expired subscriptions (skips those that expire today).
112
+        $args  = array(
113
+            'number'             => -1,
114
+            'count_total'        => false,
115
+            'status'             => 'trialling active failing cancelled',
116
+            'date_expires_query' => array(
117
+                'before'    => 'yesterday',
118
+                'inclusive' => false,
119
+            ),
120
+        );
121
+
122
+        $subscriptions = new GetPaid_Subscriptions_Query( $args );
123
+
124
+        foreach ( $subscriptions->get_results() as $subscription ) {
125
+            if ( apply_filters( 'getpaid_daily_maintenance_should_expire_subscription', false, $subscription ) ) {
126
+                $subscription->set_status( 'expired' );
127
+                $subscription->save();
128
+            }
129
+        }
130
+
131
+    }
132
+
133
+    /**
134
+     * Logs cron runs.
135
+     *
136
+     */
137
+    public function log_cron_run() {
138
+        wpinv_error_log( 'GetPaid Daily Cron', false );
139
+    }
140
+
141
+    /**
142
+     * Updates GeoIP databases.
143
+     *
144
+     */
145
+    public function maybe_update_geoip_databases() {
146
+        $updated = get_transient( 'getpaid_updated_geoip_databases' );
147
+
148
+        if ( false === $updated ) {
149
+            set_transient( 'getpaid_updated_geoip_databases', 1, 15 * DAY_IN_SECONDS );
150
+            do_action( 'getpaid_update_geoip_databases' );
151
+        }
152
+
153
+    }
154 154
 
155 155
 }
Please login to merge, or discard this patch.