Completed
Branch BETA-4.9-message-activity (c2a8e0)
by
unknown
18:28 queued 10s
created

EEM_Transaction::unset_locked_transactions()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
c 1
b 1
f 1
dl 0
loc 14
rs 9.2
cc 4
eloc 10
nc 6
nop 1
1
<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {exit('No direct script access allowed');}
2
require_once ( EE_MODELS . 'EEM_Base.model.php' );
3
/**
4
 *
5
 * Transaction Model
6
 *
7
 * @package			Event Espresso
8
 * @subpackage		includes/models/
9
 * @author			Brent Christensen
10
 *
11
 */
12
class EEM_Transaction extends EEM_Base {
13
14
	// private instance of the Transaction object
15
	protected static $_instance;
16
17
	/**
18
	 * Status ID(STS_ID on esp_status table) to indicate the transaction is complete,
19
	 * but payment is pending. This is the state for transactions where payment is promised
20
	 * from an offline gateway.
21
	 */
22
	//	const open_status_code = 'TPN';
23
24
	/**
25
	 * Status ID(STS_ID on esp_status table) to indicate the transaction failed,
26
	 * either due to a technical reason (server or computer crash during registration),
27
	 *  or some other reason that prevent the collection of any useful contact information from any of the registrants
28
	 */
29
	const failed_status_code = 'TFL';
30
31
	/**
32
	 * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned,
33
	 * either due to a technical reason (server or computer crash during registration),
34
	 * or due to an abandoned cart after registrant chose not to complete the registration process
35
	 * HOWEVER...
36
	 * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one registrant
37
	 */
38
	const abandoned_status_code = 'TAB';
39
40
	/**
41
	 * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction,
42
	 * meaning that monies are still owing: TXN_paid < TXN_total
43
	 */
44
	const incomplete_status_code = 'TIN';
45
46
	/**
47
	 * Status ID (STS_ID on esp_status table) to indicate a complete transaction.
48
	 * meaning that NO monies are owing: TXN_paid == TXN_total
49
	 */
50
	const complete_status_code = 'TCM';
51
52
	/**
53
	 *  Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid.
54
	 *  This is the same as complete, but site admins actually owe clients the moneys!  TXN_paid > TXN_total
55
	 */
56
	const overpaid_status_code = 'TOP';
57
58
59
60
	/**
61
	 *    private constructor to prevent direct creation
62
	 *
63
	 * @Constructor
64
	 * @access protected
65
	 * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any incoming timezone data that gets saved).
66
	 *                         Note this just sends the timezone info to the date time model field objects.  Default is NULL (and will be assumed using the set timezone in the 'timezone_string' wp option)
67
	 * @return EEM_Transaction
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
68
	 * @throws \EE_Error
69
	 */
70
	protected function __construct( $timezone ) {
71
		$this->singular_item = __('Transaction','event_espresso');
72
		$this->plural_item = __('Transactions','event_espresso');
73
74
		$this->_tables = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('Transaction' => n...ransaction', 'TXN_ID')) of type array<string,object<EE_P...ct<EE_Primary_Table>"}> is incompatible with the declared type array<integer,object<EE_Table_Base>> of property $_tables.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
75
			'Transaction'=>new EE_Primary_Table('esp_transaction','TXN_ID')
76
		);
77
		$this->_fields = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('Transaction' => a...so'), FALSE, array()))) of type array<string,array<strin...ized_Text_Field>\"}>"}> is incompatible with the declared type array<integer,object<EE_Model_Field_Base>> of property $_fields.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
78
			'Transaction'=>array(
79
				'TXN_ID'=>new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID','event_espresso')),
80
				'TXN_timestamp'=>new EE_Datetime_Field('TXN_timestamp', __('date when transaction was created','event_espresso'), false, time(), $timezone ),
81
				'TXN_total'=>new EE_Money_Field('TXN_total', __('Total value of Transaction','event_espresso'), false, 0),
82
				'TXN_paid'=>new EE_Money_Field('TXN_paid', __('Amount paid towards transaction to date','event_espresso'), false, 0),
83
				'STS_ID'=>new EE_Foreign_Key_String_Field('STS_ID', __('Status ID','event_espresso'), false, EEM_Transaction::failed_status_code, 'Status'),
84
				'TXN_session_data'=>new EE_Serialized_Text_Field('TXN_session_data', __('Serialized session data','event_espresso'), true, ''),
85
				'TXN_hash_salt'=>new EE_Plain_Text_Field('TXN_hash_salt', __('Transaction Hash Salt','event_espresso'), true, ''),
86
				'PMD_ID'=>new EE_Foreign_Key_Int_Field('PMD_ID', __("Last Used Payment Method", 'event_espresso'), true, NULL, 'Payment_Method'),
87
				'TXN_reg_steps' => new EE_Serialized_Text_Field( 'TXN_reg_steps', __( 'Registration Steps', 'event_espresso' ), FALSE, array() ),
88
			)
89
		);
90
		$this->_model_relations = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('Registration' => ...EE_Has_Many_Relation()) of type array<string,object<EE_H...E_Has_Many_Relation>"}> is incompatible with the declared type array<integer,object<EE_Model_Relation_Base>> of property $_model_relations.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
91
			'Registration'=>new EE_Has_Many_Relation(),
92
			'Payment'=>new EE_Has_Many_Relation(),
93
			'Status'=>new EE_Belongs_To_Relation(),
94
			'Line_Item'=>new EE_Has_Many_Relation(false),//you can delete a transaction without needing to delete its line items
95
			'Payment_Method'=>new EE_Belongs_To_Relation(),
96
			'Message' => new EE_Has_Many_Relation()
97
		);
98
		$this->_model_chain_to_wp_user = 'Registration.Event';
99
		parent::__construct( $timezone );
100
101
	}
102
103
	/**
104
	 *        get the revenue per day  for the Transaction Admin page Reports Tab
105
	 *
106
	 * @access        public
107
	 * @param string $period
108
	 * @return \stdClass[]
109
	 */
110
	public function get_revenue_per_day_report( $period = '-1 month' ) {
111
		$sql_date = $this->convert_datetime_for_query( 'TXN_timestamp', date( 'Y-m-d H:i:s', strtotime( $period ) ), 'Y-m-d H:i:s', 'UTC' );
112
113
		$query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset( $this->get_timezone(), 'TXN_timestamp' );
114
		return $this->_get_all_wpdb_results(
115
			array(
116
				array(
117
					'TXN_timestamp' => array( '>=', $sql_date )
118
				),
119
				'group_by' => 'txnDate',
120
				'order_by' => array( 'TXN_timestamp' => 'ASC' )
121
			),
122
			OBJECT,
123
			array(
124
				'txnDate' => array( 'DATE(' . $query_interval . ')', '%s' ),
125
				'revenue' => array( 'SUM(Transaction.TXN_paid)', '%d' )
126
			)
127
		);
128
	}
129
130
131
132
	/**
133
	 *        get the revenue per event  for the Transaction Admin page Reports Tab
134
	 *
135
	 * @access        public
136
	 * @param string $period
137
	 * @throws \EE_Error
138
	 * @return mixed
139
	 */
140
	public function get_revenue_per_event_report( $period = '-1 month' ) {
141
		global $wpdb;
142
		$transaction_table = $wpdb->prefix . 'esp_transaction';
143
		$registration_table = $wpdb->prefix . 'esp_registration';
144
		$event_table = $wpdb->posts;
145
		$payment_table = $wpdb->prefix . 'esp_payment';
146
		$sql_date = date( 'Y-m-d H:i:s', strtotime( $period ) );
147
		$approved_payment_status = EEM_Payment::status_id_approved;
148
		$extra_event_on_join = '';
149
		//exclude events not authored by user if permissions in effect
150
		if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_registrations', 'reg_per_event_report' ) ) {
151
			$extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id();
152
		}
153
154
		return $wpdb->get_results(
155
			"SELECT
156
			Transaction_Event.event_name AS event_name,
157
			SUM(Transaction_Event.paid) AS revenue
158
			FROM
159
				(
160
					SELECT
161
						DISTINCT Payment.TXN_ID,
162
						Event.post_title AS event_name,
163
						Payment.PAY_amount AS paid
164
					FROM $transaction_table AS Transaction
165
						JOIN $registration_table AS Registration
166
							ON Registration.TXN_ID = Transaction.TXN_ID
167
						JOIN $payment_table AS Payment
168
							ON Payment.TXN_ID = Registration.TXN_ID
169
							AND Payment.PAY_timestamp > '$sql_date'
170
							AND Payment.STS_ID = '$approved_payment_status'
171
						JOIN $event_table AS Event ON Registration.EVT_ID = Event.ID
172
							$extra_event_on_join
173
				) AS Transaction_Event
174
			GROUP BY event_name",
175
			OBJECT
176
		);
177
	}
178
179
180
181
182
183
184
	/**
185
	 * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the
186
	 * $_REQUEST global variable. Either way, tries to find the current transaction (through
187
	 * the registration pointed to by reg_url_link), if not returns null
188
	 * @param string $reg_url_link
189
	 * @return EE_Transaction
190
	 */
191
	public function get_transaction_from_reg_url_link( $reg_url_link = '' ){
192
		return $this->get_one( array(
193
			array(
194
				'Registration.REG_url_link' => ! empty( $reg_url_link ) ? $reg_url_link : EE_Registry::instance()->REQ->get( 'e_reg_url_link', '' )
195
			)
196
		));
197
	}
198
199
200
201
	/**
202
	 * Updates the provided EE_Transaction with all the applicable payments
203
	 * (or fetch the EE_Transaction from its ID)
204
	 *
205
	 * @deprecated
206
	 * @param EE_Transaction|int $transaction_obj_or_id
207
	 * @param boolean            $save_txn whether or not to save the transaction during this function call
208
	 * @return boolean
209
	 * @throws \EE_Error
210
	 */
211 View Code Duplication
	public function update_based_on_payments( $transaction_obj_or_id, $save_txn = TRUE ){
0 ignored issues
show
Unused Code introduced by
The parameter $save_txn is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
212
		EE_Error::doing_it_wrong(
213
			__CLASS__ . '::' . __FUNCTION__,
214
			sprintf( __( 'This method is deprecated. Please use "%s" instead', 'event_espresso' ), 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()' ),
215
			'4.6.0'
216
		);
217
		/** @type EE_Transaction_Processor $transaction_processor */
218
		$transaction_processor = EE_Registry::instance()->load_class( 'Transaction_Processor' );
219
		return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
220
			$this->ensure_is_obj( $transaction_obj_or_id )
0 ignored issues
show
Documentation introduced by
$this->ensure_is_obj($transaction_obj_or_id) is of type object<EE_Base_Class>|null, but the function expects a object<EE_Transaction>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
221
		);
222
	}
223
224
	/**
225
	 * Deletes "junk" transactions that were probably added by bots. There might be TONS
226
	 * of these, so we are very careful to NOT select (which the models do even when deleting),
227
	 * and so we only use wpdb directly and NOT do any joins.
228
	 * The downside to this approach is that is addons are listening for object deletions
229
	 * on EEM_Base::delete() they won't be notified of this.
230
	 * @global WPDB $wpdb
231
	 * @return mixed
232
	 */
233
	public function delete_junk_transactions() {
234
		/** @type WPDB $wpdb */
235
		global $wpdb;
236
		$deleted = false;
237
		$time_to_leave_alone = apply_filters(
238
			'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone', WEEK_IN_SECONDS
239
		);
240
241
242
		/**
243
		 * This allows code to filter the query arguments used for retrieving the transaction IDs to delete.
244
		 * Useful for plugins that want to exclude transactions matching certain query parameters.
245
		 * The query parameters should be in the format accepted by the EEM_Base model queries.
246
		 */
247
		$ids_query = apply_filters(
248
			'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args',
249
			array(
250
				0 => array(
251
					'STS_ID' => EEM_Transaction::failed_status_code,
252
					'TXN_timestamp' => array( '<', time() - $time_to_leave_alone )
253
				)
254
			),
255
			$time_to_leave_alone
256
		);
257
258
259
		/**
260
		 * This filter is for when code needs to filter the list of transaction ids that represent transactions
261
		 * about to be deleted based on some other criteria that isn't easily done via the query args filter.
262
		 */
263
		$txn_ids = apply_filters(
264
			'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete',
265
			EEM_Transaction::instance()->get_col( $ids_query, 'TXN_ID' ),
266
			$time_to_leave_alone
267
		);
268
		//now that we have the ids to delete
269
		if ( ! empty( $txn_ids ) && is_array( $txn_ids ) ) {
270
			// first, make sure these TXN's are removed the "ee_locked_transactions" array
271
			EEM_Transaction::unset_locked_transactions( $txn_ids );
272
			// let's get deletin'...
273
			// Why no wpdb->prepare?  Because the data is trusted.
274
			// We got the ids from the original query to get them FROM
275
			// the db (which is sanitized) so no need to prepare them again.
276
			$query   = '
277
				DELETE
278
				FROM ' . $this->table() . '
279
				WHERE
280
					TXN_ID IN ( ' . implode( ",", $txn_ids ) . ')';
281
			$deleted = $wpdb->query( $query );
282
		}
283
		if ( $deleted ) {
284
			/**
285
			 * Allows code to do something after the transactions have been deleted.
286
			 */
287
			do_action( 'AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids );
288
		}
289
		return $deleted;
290
	}
291
292
293
294
	/**
295
	 * @param array $transaction_IDs
296
	 * @return bool
297
	 */
298
	public static function unset_locked_transactions( array $transaction_IDs ) {
299
		$locked_transactions = get_option( 'ee_locked_transactions', array() );
300
		$update = false;
301
		foreach ( $transaction_IDs as $TXN_ID ) {
302
			if ( isset( $locked_transactions[ $TXN_ID ] ) ) {
303
				unset( $locked_transactions[ $TXN_ID ] );
304
				$update = true;
305
			}
306
		}
307
		if ( $update ) {
308
			update_option( 'ee_locked_transactions', $locked_transactions );
309
		}
310
		return $update;
311
	}
312
313
314
}
315
// End of file EEM_Transaction.model.php
316
// Location: /includes/models/EEM_Transaction.model.php
317