/** * @group 7965 */ function test_delete_junk_transactions() { $old_txn_count = EEM_Transaction::instance()->count(); $pretend_bot_creations = 9; $pretend_real_recent_txns = 3; $pretend_real_good_txns = 5; $this->factory->transaction->create_many($pretend_bot_creations, array('TXN_timestamp' => time() - WEEK_IN_SECONDS * 2, 'STS_ID' => EEM_Transaction::failed_status_code)); $this->factory->transaction->create_many($pretend_real_recent_txns, array('TXN_timestamp' => time() - EE_Registry::instance()->SSN->lifespan() + MINUTE_IN_SECONDS, 'STS_ID' => EEM_Transaction::failed_status_code)); $this->factory->transaction->create_many($pretend_real_good_txns, array('STS_ID' => EEM_Transaction::abandoned_status_code)); $num_deleted = EEM_Transaction::instance()->delete_junk_transactions(); $this->assertEquals($pretend_bot_creations, $num_deleted); }
function test_save_autoincrement_pk() { //test saving something with an auto-increment PK $t = EE_Transaction::new_instance(); $id = $t->save(); $this->assertNotNull($id); $this->assertEquals($t->ID(), $id); $t2 = EEM_Transaction::instance()->get_one_by_ID($id); $this->assertEquals($id, $t2->ID()); //and check that its correctly saved to the model's entity map $existing_t_in_entity_map = EEM_Transaction::instance()->get_from_entity_map($id); $this->assertInstanceOf('EE_Transaction', $existing_t_in_entity_map); }
function test_generate_restrictions__basic_only() { //currently transactions only have the basic cap //if they get an 'ee_edit_others_transactions' cap, this test will need updating $generator = new EE_Restriction_Generator_Protected(); $generator->_construct_finalize(EEM_Transaction::instance(), EEM_Base::caps_read); $restrictions = $generator->generate_restrictions(); foreach ($restrictions as $default_where_conditions) { $default_where_conditions->_finalize_construct(EEM_Registration::instance()); } $this->assertArrayHasKey('ee_read_transactions', $restrictions); $this->assertInstanceOf('EE_Return_None_Where_Conditions', $restrictions['ee_read_transactions']); $this->assertEquals(1, count($restrictions)); }
/** * This generates the dummy relation objects for use in a new registration. * * @since 4.3.0 * * @param array $args */ private function _set_new_relations($args) { //transaction $this->_transaction = empty($args['TXN_ID']) ? $this->factory->transaction->create() : EEM_Transaction::instance()->get_one_by_ID($args['TXN_ID']); $this->_transaction = empty($this->_transaction) ? $this->factory->transaction->create() : $this->_transaction; //ticket $this->_ticket = empty($args['TKT_ID']) ? $this->factory->ticket_chained->create() : EEM_Ticket::instance()->get_one_by_ID($args['TKT_ID']); $this->_ticket = empty($this->_ticket) ? $this->factory->ticket_chained->create() : $this->_ticket; //attendee $this->_attendee = empty($args['ATT_ID']) ? $this->factory->attendee->create() : EEM_Attendee::instance()->get_one_by_ID($args['ATT_ID']); $this->_attendee = empty($this->_attendee) ? $this->factory->attendee->create() : $this->_attendee; //status $this->_status = empty($arg['STS_ID']) ? $this->factory->status->create(array('STS_ID' => EEM_Registration::status_id_pending_payment, 'STS_type' => 'registration', 'STS_code' => 'PENDING_PAYMENT')) : EEM_Status::instance()->get_one_by_ID($args['STS_ID']); $this->_status = empty($this->_status) ? $this->factory->status->create(array('STS_ID' => EEM_Registration::status_id_pending_payment, 'STS_type' => 'registration', 'STS_code' => 'PENDING_PAYMENT')) : $this->_status; }
/** * Callback for FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg for adding * helpful title. * * @param string $content Current content * @param string $page_slug Page slug for page * @param array $req_data Incoming request data * @param string $req_action 'action' value for page * * @return string If correct page and conditions are met, the new string. Otherwise existing string. */ public static function before_events_list_table_content($content, $page_slug, $req_data, $req_action) { if ($page_slug !== 'espresso_events' || $req_action !== 'default' || empty($req_data['TXN_ID'])) { return $content; } $transaction = EEM_Transaction::instance()->get_one_by_ID($req_data['TXN_ID']); if ($transaction instanceof EE_Transaction) { $query_args = array('page' => 'espresso_transactions', 'action' => 'view_transaction', 'TXN_ID' => $req_data['TXN_ID']); EE_Registry::instance()->load_helper('URL'); $url = EEH_URL::add_query_args_and_nonce($query_args, admin_url('admin.php')); $link_text = '<a href="' . $url . '">' . $transaction->ID() . '</a>'; $content .= '<h2>' . sprintf(__('Events Registered for in Transaction # %s', 'event_espresso'), $link_text) . '</h2>'; } return $content; }
/** * _validate_return * * @access private * @return bool */ private function _validate_offsite_return() { $TXN_ID = (int) EE_Registry::instance()->REQ->get('spco_txn', 0); if ($TXN_ID != $this->checkout->transaction->ID()) { // Houston... we might have a problem $invalid_TXN = false; // first gather some info $valid_TXN = EEM_Transaction::instance()->get_one_by_ID($TXN_ID); $primary_registrant = $valid_TXN instanceof EE_Transaction ? $valid_TXN->primary_registration() : null; // let's start by retrieving the cart for this TXN $cart = EE_Cart::get_cart_from_txn($this->checkout->transaction); if ($cart instanceof EE_Cart) { // verify that the current cart has tickets $tickets = $cart->get_tickets(); if (empty($tickets)) { $invalid_TXN = true; } } else { $invalid_TXN = true; } $valid_TXN_SID = $primary_registrant instanceof EE_Registration ? $primary_registrant->session_ID() : null; // validate current Session ID and compare against valid TXN session ID if (EE_Session::instance()->id() === null) { $invalid_TXN = true; } else { if (EE_Session::instance()->id() === $valid_TXN_SID) { // WARNING !!! // this could be PayPal sending back duplicate requests (ya they do that) // or it **could** mean someone is simply registering AGAIN after having just done so // so now we need to determine if this current TXN looks valid or not /** @type EE_Transaction_Processor $transaction_processor */ $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); // has this step even been started ? if ($transaction_processor->reg_step_completed($this->checkout->transaction, $this->slug() === false)) { // really? you're half way through this reg step, but you never started it ? $invalid_TXN = true; } } } if ($invalid_TXN) { // is the valid TXN completed ? if ($valid_TXN instanceof EE_Transaction) { /** @type EE_Transaction_Processor $transaction_processor */ $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); // has this step even been started ? $reg_step_completed = $transaction_processor->reg_step_completed($valid_TXN, $this->slug()); if ($reg_step_completed !== false && $reg_step_completed !== true) { // so it **looks** like this is a double request from PayPal // so let's try to pick up where we left off $this->checkout->transaction = $valid_TXN; $this->checkout->refresh_all_entities(true); return; } } // you appear to be lost? $this->_redirect_wayward_request($primary_registrant); } } }
public static function clean_out_junk_transactions() { if (EE_Maintenance_Mode::instance()->models_can_query()) { EEM_Transaction::instance('')->delete_junk_transactions(); EEM_Registration::instance('')->delete_registrations_with_no_transaction(); EEM_Line_Item::instance('')->delete_line_items_with_no_transaction(); } }
/** * Handles an instant payment notification when the transaction is known (by default). * @param array $req_data * @param EE_Transaction $transaction * @return EE_Payment * @throws EE_Error */ public function handle_ipn($req_data, $transaction) { $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); if (!$this->_gateway instanceof EE_Offsite_Gateway) { throw new EE_Error(sprintf(__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"), print_r($this->_gateway, TRUE))); } $payment = $this->_gateway->handle_payment_update($req_data, $transaction); return $payment; }
/** * Deletes all registrations with no transactions. Note that this needs to be very efficient * and so it uses wpdb directly * @global WPDB $wpdb * @return int number deleted */ public function delete_registrations_with_no_transaction() { /** @type WPDB $wpdb */ global $wpdb; return $wpdb->query('DELETE r FROM ' . $this->table() . ' r LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON r.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL'); }
/** * Data that has been stored in persistent storage that was prepped by _convert_data_for_persistent_storage * can be sent into this method and converted back into the format used for instantiating with this data handler. * * @param array $data * * @return array */ public static function convert_data_from_persistent_storage($data) { $prepped_data = array(0 => isset($data['Transaction']) ? EEM_Transaction::instance()->get_one_by_ID($data['Transaction']) : null, 1 => isset($data['Payment']) ? EEM_Payment::instance()->get_one_by_ID($data['Payment']) : null, 2 => isset($data['filter']) ? $data['filter'] : null); return $prepped_data; }
/** * _revenue_per_event_report * generates Business Report showing total revenue per event * * @access private * @param string $period * @return int */ private function _revenue_per_event_report($period = '-1 month') { $report_ID = 'txn-admin-revenue-per-event-report-dv'; $report_JS = 'espresso_txn_admin_revenue_per_event'; wp_enqueue_script($report_JS, TXN_CAF_ASSETS_URL . $report_JS . '_report.js', array('jqplot-all'), '1.0', TRUE); $TXN = EEM_Transaction::instance(); $results = $TXN->get_revenue_per_event_report($period); //EEH_Debug_Tools::printr( $results, '$registrations_per_event' ); $revenue = array(); $results = (array) $results; foreach ($results as $result) { $event_name = stripslashes(html_entity_decode($result->event_name, ENT_QUOTES, 'UTF-8')); $event_name = wp_trim_words($event_name, 5, '...'); $revenue[] = array($event_name, (double) $result->revenue); } $span = $period == 'week' ? 9 : 33; $report_title = __('Total Revenue per Event'); $report_params = array('title' => $report_title, 'id' => $report_ID, 'revenue' => $revenue, 'span' => $span, 'width' => ceil(900 / $span), 'noTxnMsg' => sprintf(__('<h2>%s</h2><p>There are currently no transaction records in the last month for this report.</p>', 'event_espresso'), $report_title)); wp_localize_script($report_JS, 'revenuePerEvent', $report_params); return $report_ID; }
/** * _payments_and_amount_owing_rows * * @param EE_Line_Item $line_item * @return mixed */ private function _payments_and_amount_owing_rows(EE_Line_Item $line_item) { $html = ''; $transaction = EEM_Transaction::instance()->get_one_by_ID($line_item->TXN_ID()); if ($transaction instanceof EE_Transaction) { $payments = $transaction->approved_payments(); if (!empty($payments)) { foreach ($payments as $payment) { if ($payment instanceof EE_Payment) { //$owing = $owing - $payment->amount(); $payment_desc = sprintf(__('Payment%1$s Received: %2$s', 'event_espresso'), $payment->txn_id_chq_nmbr() != '' ? ' <span class="small-text">(#' . $payment->txn_id_chq_nmbr() . ')</span> ' : '', $payment->timestamp()); // start of row $html .= EEH_HTML::tr('', '', 'total_tr odd'); // payment desc $html .= EEH_HTML::td($payment_desc, '', '', '', ' colspan="3"'); // total td $html .= EEH_HTML::td(EEH_Template::format_currency($payment->amount(), false, false), '', 'total jst-rght'); // end of row $html .= EEH_HTML::trx(); } } //if ( $line_item->total() ) { // // start of row // $html .= EEH_HTML::tr( '', '', 'total_tr odd' ); // // total td // $html .= EEH_HTML::td( __('Amount Owing', 'event_espresso'), '', 'total_currency total jst-rght', '', ' colspan="3"' ); // // total td // $html .= EEH_HTML::td( EEH_Template::format_currency( $this->grand_total(), false, false ), '', 'total jst-rght' ); // // end of row // $html .= EEH_HTML::trx(); //} } } return $html; }
/** * The purpose of this method is to just initialize SPCO for manual admin registration handling * * Note, it is fully expected that eventually things will be abstracted a bit more conveniently for the Admin usage of SPCO but this is a quick and dirty method to get things implemented with as much DRY as possible. * * @access public * @return void */ public function init_for_admin() { // load classes EE_Registry::instance()->load_model('Gateways'); $this->_cart = EE_Registry::instance()->load_core('Cart'); if (empty(EE_Registry::instance()->REQ)) { EE_Registry::instance()->load_core('Request_Handler'); } $this->_current_step = 'attendee_information'; $this->_transaction = EE_Registry::instance()->SSN->get_session_data('transaction'); // verify transaction if ($this->_transaction instanceof EE_Transaction) { // but if this transaction has already been saved to the db... then let's pull that $ID = $this->_transaction->ID(); if ($ID) { if (!($this->_transaction = EEM_Transaction::instance()->get_one_by_ID($ID))) { EE_Error::add_error(__('The Transaction could not be retrieved from the db when attempting to process your registration information', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__); return; } } } else { $this->_initialize_transaction(); } // and verify registrations have been set (first check cached REGs) if ($this->_transaction->registrations(array(), TRUE) == NULL) { // then check the db if ($this->_transaction->registrations() == NULL) { $this->_initialize_registrations(); } } if (!defined('SPCO_TEMPLATES_PATH')) { self::set_definitions(); } $this->set_templates(); }
function test_wp_user_field_name() { $this->assertEquals('EVT_wp_user', EEM_Event::instance()->wp_user_field_name()); $this->assertEquals('Registration.Event.EVT_wp_user', EEM_Transaction::instance()->wp_user_field_name()); $this->assertEquals('TKT_wp_user', EEM_Ticket::instance()->wp_user_field_name()); }
/** * return the transaction object for a given transaction ID. * * @since 4.3.0 * * @param int $TXN_ID the transaction id for the transaction to attempt to retrieve * * @return mixed null|EE_Transaction */ public function get_object_by_id($TXN_ID) { return EEM_Transaction::instance()->get_one_by_ID($TXN_ID); }
/** * Update lead status of the specified payment * * @param Pronamic_Pay_Payment $payment * @param bool $can_redirect */ public function update_status_unknown_to_success(Pronamic_Pay_Payment $payment, $can_redirect = false) { if (!(version_compare(EVENT_ESPRESSO_VERSION, '4', '>=') && version_compare(EVENT_ESPRESSO_VERSION, '4.6', '<'))) { return; } // Eevent Espresso 4.0 to 4.6 $gateway = EEM_Gateways::instance()->get_gateway('pronamic_pay_ideal'); if ($gateway) { $transaction_id = $payment->get_source_id(); // @see https://github.com/eventespresso/event-espresso-core/blob/4.2.2.reg/admin_pages/transactions/Transactions_Admin_Page.core.php#L332-L337 $transaction_model = EEM_Transaction::instance(); $transaction = $transaction_model->get_one_by_ID($transaction_id); global $pronamic_payment, $pronamic_url; $pronamic_payment = $payment; $gateway->handle_ipn_for_transaction($transaction); unset($pronamic_payment); // Redirect URL if ($can_redirect) { wp_redirect($pronamic_url, 303); exit; } } }
/** * Checks that we can correctly apply backend read caps where there is only * one cap controlling access to the model * @group model_caps */ public function test_get_all__caps_admin_read__basic() { $this->assertEquals(0, EEM_Transaction::instance()->count()); $this->new_typical_transaction(); $current_user = $this->_ensure_current_user_set(); //let's test first on transactions, which just have a single cap controlling access //which the current user doesn't have so nothing should be found $this->assertEquals(0, EEM_Transaction::instance()->count(array('caps' => EEM_Base::caps_read_admin))); //now give the user permission to access transactions and make sure he can $current_user->add_cap('ee_read_transactions'); $this->assertEquals(EEM_Transaction::instance()->count(), EEM_Transaction::instance()->count(array('caps' => EEM_Base::caps_read_admin))); }
protected function __construct(EEM_Gateways &$model) { do_action('AHEE_log', __FILE__, __FUNCTION__, ''); //echo '<h4>$this->_gateway_name : ' . $this->_gateway_name . ' <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span></h4>'; if (!defined('GATEWAYS_ADMIN_URL')) { define('GATEWAYS_ADMIN_URL', admin_url('admin.php?page=espresso_payment_settings')); } $this->_EEM_Gateways = $model; require_once EE_MODELS . 'EEM_Transaction.model.php'; require_once EE_CLASSES . 'EE_Transaction.class.php'; $this->_TXN = EEM_Transaction::instance(); require_once EE_MODELS . 'EEM_Payment.model.php'; require_once EE_CLASSES . 'EE_Payment.class.php'; $this->_PAY = EEM_Payment::instance(); require_once EE_MODELS . 'EEM_Registration.model.php'; require_once EE_CLASSES . 'EE_Registration.class.php'; $this->_REG = EEM_Registration::instance(); if (!$this->_btn_img) { $this->_btn_img = EE_GATEWAYS_URL . $this->_gateway_name . DS . 'lib' . DS . $this->_button_base; } $this->_set_default_properties(); $this->_handle_payment_settings(); if (is_admin() && !empty($_GET['page']) && $_GET['page'] == 'espresso_payment_settings') { $this->_gateways_admin(); } else { $this->_gateways_frontend(); } //load formatter helper and form fields helper EE_Registry::instance()->load_helper('Formatter'); EE_Registry::instance()->load_helper('Form_Fields'); }
/** * get_transactions * get transactions for given parameters (used by list table) * * @param int $perpage how many transactions displayed per page * @param boolean $count return the count or objects * @param string $view * @return mixed int = count || array of transaction objects */ public function get_transactions($perpage, $count = FALSE, $view = '') { $TXN = EEM_Transaction::instance(); $start_date = isset($this->_req_data['txn-filter-start-date']) ? wp_strip_all_tags($this->_req_data['txn-filter-start-date']) : date('D M j, Y', strtotime('-10 year')); $end_date = isset($this->_req_data['txn-filter-end-date']) ? wp_strip_all_tags($this->_req_data['txn-filter-end-date']) : date('D M j, Y'); //make sure our timestamps start and end right at the boundaries for each day $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00'; $end_date = date('Y-m-d', strtotime($end_date)) . ' 23:59:59'; //convert to timestamps $start_date = strtotime($start_date); $end_date = strtotime($end_date); //makes sure start date is the lowest value and vice versa $start_date = min($start_date, $end_date); $end_date = max($start_date, $end_date); //set orderby $this->_req_data['orderby'] = !empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : ''; switch ($this->_req_data['orderby']) { case 'TXN_ID': $orderby = 'TXN_ID'; break; case 'ATT_fname': $orderby = 'Registration.Attendee.ATT_fname'; break; case 'event_name': $orderby = 'Registration.Event.EVT_name'; break; default: //'TXN_timestamp' $orderby = 'TXN_timestamp'; } $sort = isset($this->_req_data['order']) && !empty($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC'; $current_page = isset($this->_req_data['paged']) && !empty($this->_req_data['paged']) ? $this->_req_data['paged'] : 1; $per_page = isset($perpage) && !empty($perpage) ? $perpage : 10; $per_page = isset($this->_req_data['perpage']) && !empty($this->_req_data['perpage']) ? $this->_req_data['perpage'] : $per_page; $offset = ($current_page - 1) * $per_page; $limit = array($offset, $per_page); $_where = array('TXN_timestamp' => array('BETWEEN', array($start_date, $end_date)), 'Registration.REG_count' => 1); if (isset($this->_req_data['EVT_ID'])) { $_where['Registration.EVT_ID'] = $this->_req_data['EVT_ID']; } if (isset($this->_req_data['s'])) { $search_string = '%' . $this->_req_data['s'] . '%'; $_where['OR'] = array('Registration.Event.EVT_name' => array('LIKE', $search_string), 'Registration.Event.EVT_desc' => array('LIKE', $search_string), 'Registration.Event.EVT_short_desc' => array('LIKE', $search_string), 'Registration.Attendee.ATT_fname' => array('LIKE', $search_string), 'Registration.Attendee.ATT_lname' => array('LIKE', $search_string), 'Registration.Attendee.ATT_short_bio' => array('LIKE', $search_string), 'Registration.Attendee.ATT_email' => array('LIKE', $search_string), 'Registration.Attendee.ATT_address' => array('LIKE', $search_string), 'Registration.Attendee.ATT_address2' => array('LIKE', $search_string), 'Registration.Attendee.ATT_city' => array('LIKE', $search_string), 'Registration.REG_final_price' => array('LIKE', $search_string), 'Registration.REG_code' => array('LIKE', $search_string), 'Registration.REG_count' => array('LIKE', $search_string), 'Registration.REG_group_size' => array('LIKE', $search_string), 'Registration.Ticket.TKT_name' => array('LIKE', $search_string), 'Registration.Ticket.TKT_description' => array('LIKE', $search_string), 'Payment.PAY_source' => array('LIKE', $search_string), 'Payment.Payment_Method.PMD_name' => array('LIKE', $search_string), 'TXN_session_data' => array('LIKE', $search_string)); } //failed transactions $failed = !empty($this->_req_data['status']) && $this->_req_data['status'] == 'failed' && !$count || $count && $view == 'failed' ? TRUE : FALSE; $abandoned = !empty($this->_req_data['status']) && $this->_req_data['status'] == 'abandoned' && !$count || $count && $view == 'abandoned' ? TRUE : FALSE; if ($failed) { $_where['STS_ID'] = EEM_Transaction::failed_status_code; } else { if ($abandoned) { $_where['STS_ID'] = EEM_Transaction::abandoned_status_code; } else { $_where['STS_ID'] = array('!=', EEM_Transaction::failed_status_code); $_where['STS_ID*'] = array('!=', EEM_Transaction::abandoned_status_code); } } $query_params = array($_where, 'order_by' => array($orderby => $sort), 'limit' => $limit); $transactions = $count ? $TXN->count(array($_where), 'TXN_ID', TRUE) : $TXN->get_all($query_params); return $transactions; }
/** * _revenue_per_event_report * generates Business Report showing total revenue per event. * * @param string $period The period (acceptable by PHP Datetime constructor) for which the report is generated. * @return int */ private function _revenue_per_event_report($period = '-1 month') { $report_ID = 'txn-admin-revenue-per-event-report-dv'; $TXN = EEM_Transaction::instance(); $results = $TXN->get_revenue_per_event_report($period); $results = (array) $results; $revenue = array(); $subtitle = ''; if ($results) { $revenue[] = array(__('Event (only events that have a revenue greater than 1 are shown)', 'event_espresso'), __('Total Revenue', 'event_espresso')); foreach ($results as $result) { if ($result->revenue > 1) { $event_name = stripslashes(html_entity_decode($result->event_name, ENT_QUOTES, 'UTF-8')); $event_name = wp_trim_words($event_name, 5, '...'); $revenue[] = array($event_name, (double) $result->revenue); } } //setup the date range. EE_Registry::instance()->load_helper('DTT_Helper'); $beginning_date = new DateTime('now' . $period, new DateTimeZone(EEH_DTT_Helper::get_timezone())); $ending_date = new DateTime('now', new DateTimeZone(EEH_DTT_Helper::get_timezone())); $subtitle = sprintf(_x('For the period: %s to %s', 'Used to give date range', 'event_espresso'), $beginning_date->format('Y-m-d'), $ending_date->format('Y-m-d')); } $report_title = __('Total Revenue per Event'); $report_params = array('title' => $report_title, 'subtitle' => $subtitle, 'id' => $report_ID, 'revenue' => $revenue, 'noResults' => empty($revenue), 'noTxnMsg' => sprintf(__('%sThere are currently no transaction records in the last month for this report.%s', 'event_espresso'), '<h2>' . $report_title . '</h2><p>', '</p>')); wp_localize_script('ee-txn-reports-js', 'txnRevPerEvent', $report_params); return $report_ID; }
/** * Deletes line items with no transaction who have passed the transaction cutoff time. * This needs to be very efficient * because if there are spam bots afoot there will be LOTS of line items * @return int count of how many deleted */ public function delete_line_items_with_no_transaction() { /** @type WPDB $wpdb */ global $wpdb; $time_to_leave_alone = apply_filters('FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', WEEK_IN_SECONDS); $query = $wpdb->prepare('DELETE li FROM ' . $this->table() . ' li LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON li.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL AND li.LIN_timestamp < %s', gmdate('Y-m-d H:i:s', time() - $time_to_leave_alone)); return $wpdb->query($query); }
/** * _payments_and_amount_owing_rows * * @param EE_Line_Item $line_item * @param array $options * @return mixed */ private function _payments_and_amount_owing_rows(EE_Line_Item $line_item, $options = array()) { $html = ''; $owing = $line_item->total(); $transaction = EEM_Transaction::instance()->get_one_by_ID($line_item->TXN_ID()); if ($transaction instanceof EE_Transaction) { $registration_payments = array(); $registrations = !empty($options['registrations']) ? $options['registrations'] : $transaction->registrations(); foreach ($registrations as $registration) { if ($registration instanceof EE_Registration && $registration->owes_monies_and_can_pay()) { $registration_payments = $registration_payments + $registration->registration_payments(); } } if (!empty($registration_payments)) { foreach ($registration_payments as $registration_payment) { if ($registration_payment instanceof EE_Registration_Payment) { $owing = $owing - $registration_payment->amount(); $payment = $registration_payment->payment(); if ($payment instanceof EE_Payment) { $payment_desc = sprintf(__('Payment%1$s Received: %2$s', 'event_espresso'), $payment->txn_id_chq_nmbr() != '' ? ' <span class="small-text">(#' . $payment->txn_id_chq_nmbr() . ')</span> ' : '', $payment->timestamp()); } else { $payment_desc = ''; } // start of row $html .= EEH_HTML::tr('', '', 'total_tr odd'); // payment desc $html .= EEH_HTML::td($payment_desc, '', '', '', ' colspan="3"'); // total td $html .= EEH_HTML::td(EEH_Template::format_currency($registration_payment->amount(), false, false), '', 'total jst-rght'); // end of row $html .= EEH_HTML::trx(); } } if ($line_item->total()) { // start of row $html .= EEH_HTML::tr('', '', 'total_tr odd'); // total td $html .= EEH_HTML::td(__('Amount Owing', 'event_espresso'), '', 'total_currency total jst-rght', '', ' colspan="3"'); // total td $html .= EEH_HTML::td(EEH_Template::format_currency($owing, false, false), '', 'total jst-rght'); // end of row $html .= EEH_HTML::trx(); } } } $this->_grand_total = $owing; return $html; }
/** * This should be called each time there may have been an update to a * payment on a transaction (ie, we asked for a payment to process a * payment for a transaction, or we told a payment method about an IPN, or * we told a payment method to * "finalize_payment_for" (a transaction), or we told a payment method to * process a refund. This should handle firing the correct hooks to * indicate * what exactly happened and updating the transaction appropriately). This * could be integrated directly into EE_Transaction upon save, but we want * this logic to be separate from 'normal' plain-jane saving and updating * of transactions and payments, and to be tied to payment processing. * Note: this method DOES NOT save the payment passed into it. It is the responsibility * of previous code to decide whether or not to save (because the payment passed into * this method might be a temporary, never-to-be-saved payment from an offline gateway, * in which case we only want that payment object for some temporary usage during this request, * but we don't want it to be saved). * * @param EE_Transaction|int $transaction * @param EE_Payment $payment * @param boolean $update_txn * whether or not to call * EE_Transaction_Processor:: * update_transaction_and_registrations_after_checkout_or_payment() * (you can save 1 DB query if you know you're going * to save it later instead) * @param bool $IPN * if processing IPNs or other similar payment * related activities that occur in alternate * requests than the main one that is processing the * TXN, then set this to true to check whether the * TXN is locked before updating * @throws \EE_Error */ public function update_txn_based_on_payment($transaction, $payment, $update_txn = true, $IPN = false) { $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__not_successful'; /** @type EE_Transaction $transaction */ $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); // can we freely update the TXN at this moment? if ($IPN && $transaction->is_locked()) { // don't update the transaction at this exact moment // because the TXN is active in another request EE_Cron_Tasks::schedule_update_transaction_with_payment(time(), $transaction->ID(), $payment->ID()); } else { // verify payment and that it has been saved if ($payment instanceof EE_Payment && $payment->ID()) { if ($payment->payment_method() instanceof EE_Payment_Method && $payment->payment_method()->type_obj() instanceof EE_PMT_Base) { $payment->payment_method()->type_obj()->update_txn_based_on_payment($payment); // update TXN registrations with payment info $this->process_registration_payments($transaction, $payment); } $do_action = $payment->just_approved() ? 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__successful' : $do_action; } else { // send out notifications add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true'); $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__no_payment_made'; } // if this is an IPN, then we want to know the initial TXN status prior to updating the TXN // so that we know whether the status has changed and notifications should be triggered if ($IPN) { /** @type EE_Transaction_Processor $transaction_processor */ $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); $transaction_processor->set_old_txn_status($transaction->status_ID()); } if ($payment->status() !== EEM_Payment::status_id_failed) { /** @type EE_Transaction_Payments $transaction_payments */ $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments'); // set new value for total paid $transaction_payments->calculate_total_payments_and_update_status($transaction); // call EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() ??? if ($update_txn) { $this->_post_payment_processing($transaction, $payment, $IPN); } } // granular hook for others to use. do_action($do_action, $transaction, $payment); do_action('AHEE_log', __CLASS__, __FUNCTION__, $do_action, '$do_action'); //global hook for others to use. do_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', $transaction, $payment); } }
/** * Deletes "junk" transactions that were probably added by bots. There might be TONS * of these, so we are very careful to NOT select (which the models do even when deleting), * and so we only use wpdb directly and NOT do any joins. * The downside to this approach is that is addons are listening for object deletions * on EEM_Base::delete() they won't be notified of this. * @global WPDB $wpdb * @return mixed */ public function delete_junk_transactions() { /** @type WPDB $wpdb */ global $wpdb; $deleted = false; $time_to_leave_alone = apply_filters('FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone', WEEK_IN_SECONDS); /** * This allows code to filter the query arguments used for retrieving the transaction IDs to delete. * Useful for plugins that want to exclude transactions matching certain query parameters. * The query parameters should be in the format accepted by the EEM_Base model queries. */ $ids_query = apply_filters('FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args', array(0 => array('STS_ID' => EEM_Transaction::failed_status_code, 'TXN_timestamp' => array('<', time() - $time_to_leave_alone))), $time_to_leave_alone); /** * This filter is for when code needs to filter the list of transaction ids that represent transactions * about to be deleted based on some other criteria that isn't easily done via the query args filter. */ $txn_ids = apply_filters('FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete', EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'), $time_to_leave_alone); //now that we have the ids to delete if (!empty($txn_ids) && is_array($txn_ids)) { // first, make sure these TXN's are removed the "ee_locked_transactions" array EEM_Transaction::unset_locked_transactions($txn_ids); // let's get deletin'... // Why no wpdb->prepare? Because the data is trusted. // We got the ids from the original query to get them FROM // the db (which is sanitized) so no need to prepare them again. $query = ' DELETE FROM ' . $this->table() . ' WHERE TXN_ID IN ( ' . implode(",", $txn_ids) . ')'; $deleted = $wpdb->query($query); } if ($deleted) { /** * Allows code to do something after the transactions have been deleted. */ do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids); } return $deleted; }
/** * Export a custom CSV of registration info including: A bunch of the reg fields, the time of the event, the price name, * and the questions associated with the registrations * @param int $event_id */ function report_registrations_for_event($event_id = NULL) { $reg_fields_to_include = array('TXN_ID', 'ATT_ID', 'REG_ID', 'REG_date', 'REG_code', 'REG_count', 'REG_final_price'); $att_fields_to_include = array('ATT_fname', 'ATT_lname', 'ATT_email', 'ATT_address', 'ATT_address2', 'ATT_city', 'STA_ID', 'CNT_ISO', 'ATT_zip', 'ATT_phone'); $registrations_csv_ready_array = array(); $reg_model = EE_Registry::instance()->load_model('Registration'); $query_params = apply_filters('FHEE__EE_Export__report_registration_for_event', array(array('OR' => array('Transaction.STS_ID' => array('NOT IN', array(EEM_Transaction::failed_status_code, EEM_Transaction::abandoned_status_code)), 'STS_ID' => EEM_Registration::status_id_approved), 'Ticket.TKT_deleted' => array('IN', array(true, false))), 'order_by' => array('Transaction.TXN_ID' => 'asc', 'REG_count' => 'asc'), 'force_join' => array('Transaction', 'Ticket', 'Attendee'), 'caps' => EEM_Base::caps_read_admin), $event_id); if ($event_id) { $query_params[0]['EVT_ID'] = $event_id; } else { $query_params['force_join'][] = 'Event'; } $registration_rows = $reg_model->get_all_wpdb_results($query_params); //get all questions which relate to someone in this group $registration_ids = array(); foreach ($registration_rows as $reg_row) { $registration_ids[] = intval($reg_row['Registration.REG_ID']); } // EEM_Question::instance()->show_next_x_db_queries(); $questions_for_these_regs_rows = EEM_Question::instance()->get_all_wpdb_results(array(array('Answer.REG_ID' => array('IN', $registration_ids)))); foreach ($registration_rows as $reg_row) { if (is_array($reg_row)) { $reg_csv_array = array(); if (!$event_id) { //get the event's name and Id $reg_csv_array[__('Event', 'event_espresso')] = sprintf(__('%1$s (%2$s)', 'event_espresso'), $this->_prepare_value_from_db_for_display(EEM_Event::instance(), 'EVT_name', $reg_row['Event_CPT.post_title']), $reg_row['Event_CPT.ID']); } $is_primary_reg = $reg_row['Registration.REG_count'] == '1' ? true : false; /*@var $reg_row EE_Registration */ foreach ($reg_fields_to_include as $field_name) { $field = $reg_model->field_settings_for($field_name); if ($field_name == 'REG_final_price') { $value = $this->_prepare_value_from_db_for_display($reg_model, $field_name, $reg_row['Registration.REG_final_price'], 'localized_float'); } elseif ($field_name == 'REG_count') { $value = sprintf(__('%s of %s', 'event_espresso'), $this->_prepare_value_from_db_for_display($reg_model, 'REG_count', $reg_row['Registration.REG_count']), $this->_prepare_value_from_db_for_display($reg_model, 'REG_group_size', $reg_row['Registration.REG_group_size'])); } elseif ($field_name == 'REG_date') { $value = $this->_prepare_value_from_db_for_display($reg_model, $field_name, $reg_row['Registration.REG_date'], 'no_html'); } else { $value = $this->_prepare_value_from_db_for_display($reg_model, $field_name, $reg_row[$field->get_qualified_column()]); } $reg_csv_array[$this->_get_column_name_for_field($field)] = $value; if ($field_name == 'REG_final_price') { //add a column named Currency after the final price $reg_csv_array[__("Currency", "event_espresso")] = EE_Config::instance()->currency->code; } } //get pretty status $stati = EEM_Status::instance()->localized_status(array($reg_row['Registration.STS_ID'] => __('unknown', 'event_espresso'), $reg_row['TransactionTable.STS_ID'] => __('unknown', 'event_espresso')), FALSE, 'sentence'); $reg_csv_array[__("Registration Status", 'event_espresso')] = $stati[$reg_row['Registration.STS_ID']]; //get pretty trnasaction status $reg_csv_array[__("Transaction Status", 'event_espresso')] = $stati[$reg_row['TransactionTable.STS_ID']]; $reg_csv_array[__('Transaction Amount Due', 'event_espresso')] = $is_primary_reg ? $this->_prepare_value_from_db_for_display(EEM_Transaction::instance(), 'TXN_total', $reg_row['TransactionTable.TXN_total'], 'localized_float') : '0.00'; $reg_csv_array[__('Amount Paid', 'event_espresso')] = $is_primary_reg ? $this->_prepare_value_from_db_for_display(EEM_Transaction::instance(), 'TXN_paid', $reg_row['TransactionTable.TXN_paid'], 'localized_float') : '0.00'; $payment_methods = array(); $gateway_txn_ids_etc = array(); $payment_times = array(); if ($is_primary_reg && $reg_row['TransactionTable.TXN_ID']) { $payments_info = EEM_Payment::instance()->get_all_wpdb_results(array(array('TXN_ID' => $reg_row['TransactionTable.TXN_ID'], 'STS_ID' => EEM_Payment::status_id_approved), 'force_join' => array('Payment_Method')), ARRAY_A, 'Payment_Method.PMD_admin_name as name, Payment.PAY_txn_id_chq_nmbr as gateway_txn_id, Payment.PAY_timestamp as payment_time'); foreach ($payments_info as $payment_method_and_gateway_txn_id) { $payment_methods[] = isset($payment_method_and_gateway_txn_id['name']) ? $payment_method_and_gateway_txn_id['name'] : __('Unknown', 'event_espresso'); $gateway_txn_ids_etc[] = isset($payment_method_and_gateway_txn_id['gateway_txn_id']) ? $payment_method_and_gateway_txn_id['gateway_txn_id'] : ''; $payment_times[] = isset($payment_method_and_gateway_txn_id['payment_time']) ? $payment_method_and_gateway_txn_id['payment_time'] : ''; } } $reg_csv_array[__('Payment Date(s)', 'event_espresso')] = implode(',', $payment_times); $reg_csv_array[__('Payment Method(s)', 'event_espresso')] = implode(",", $payment_methods); $reg_csv_array[__('Gateway Transaction ID(s)', 'event_espresso')] = implode(',', $gateway_txn_ids_etc); //get whether or not the user has checked in $reg_csv_array[__("Check-Ins", "event_espresso")] = $reg_model->count_related($reg_row['Registration.REG_ID'], 'Checkin'); //get ticket of registration and its price $ticket_model = EE_Registry::instance()->load_model('Ticket'); if ($reg_row['Ticket.TKT_ID']) { $ticket_name = $this->_prepare_value_from_db_for_display($ticket_model, 'TKT_name', $reg_row['Ticket.TKT_name']); $datetimes_strings = array(); foreach (EEM_Datetime::instance()->get_all_wpdb_results(array(array('Ticket.TKT_ID' => $reg_row['Ticket.TKT_ID']), 'order_by' => array('DTT_EVT_start' => 'ASC'), 'default_where_conditions' => 'none')) as $datetime) { $datetimes_strings[] = $this->_prepare_value_from_db_for_display(EEM_Datetime::instance(), 'DTT_EVT_start', $datetime['Datetime.DTT_EVT_start']); } } else { $ticket_name = __('Unknown', 'event_espresso'); $datetimes_strings = array(__('Unknown', 'event_espresso')); } $reg_csv_array[$ticket_model->field_settings_for('TKT_name')->get_nicename()] = $ticket_name; $reg_csv_array[__("Datetimes of Ticket", "event_espresso")] = implode(", ", $datetimes_strings); //get datetime(s) of registration //add attendee columns foreach ($att_fields_to_include as $att_field_name) { $field_obj = EEM_Attendee::instance()->field_settings_for($att_field_name); if ($reg_row['Attendee_CPT.ID']) { if ($att_field_name == 'STA_ID') { $value = EEM_State::instance()->get_var(array(array('STA_ID' => $reg_row['Attendee_Meta.STA_ID'])), 'STA_name'); } elseif ($att_field_name == 'CNT_ISO') { $value = EEM_Country::instance()->get_var(array(array('CNT_ISO' => $reg_row['Attendee_Meta.CNT_ISO'])), 'CNT_name'); } else { $value = $this->_prepare_value_from_db_for_display(EEM_Attendee::instance(), $att_field_name, $reg_row[$field_obj->get_qualified_column()]); } } else { $value = ''; } $reg_csv_array[$this->_get_column_name_for_field($field_obj)] = $value; } //make sure each registration has the same questions in the same order foreach ($questions_for_these_regs_rows as $question_row) { if (!isset($reg_csv_array[$question_row['Question.QST_admin_label']])) { $reg_csv_array[$question_row['Question.QST_admin_label']] = null; } } //now fill out the questions THEY answered foreach (EEM_Answer::instance()->get_all_wpdb_results(array(array('REG_ID' => $reg_row['Registration.REG_ID']), 'force_join' => array('Question'))) as $answer_row) { /* @var $answer EE_Answer */ if ($answer_row['Question.QST_ID']) { $question_label = $this->_prepare_value_from_db_for_display(EEM_Question::instance(), 'QST_admin_label', $answer_row['Question.QST_admin_label']); } else { $question_label = sprintf(__('Question $s', 'event_espresso'), $answer_row['Answer.QST_ID']); } if (isset($answer_row['Question.QST_type']) && $answer_row['Question.QST_type'] == EEM_Question::QST_type_state) { $reg_csv_array[$question_label] = EEM_State::instance()->get_state_name_by_ID($answer_row['Answer.ANS_value']); } else { $reg_csv_array[$question_label] = $this->_prepare_value_from_db_for_display(EEM_Answer::instance(), 'ANS_value', $answer_row['Answer.ANS_value']); } } $registrations_csv_ready_array[] = apply_filters('FHEE__EE_Export__report_registrations__reg_csv_array', $reg_csv_array, $reg_row); } } //if we couldn't export anything, we want to at least show the column headers if (empty($registrations_csv_ready_array)) { $reg_csv_array = array(); $model_and_fields_to_include = array('Registration' => $reg_fields_to_include, 'Attendee' => $att_fields_to_include); foreach ($model_and_fields_to_include as $model_name => $field_list) { $model = EE_Registry::instance()->load_model($model_name); foreach ($field_list as $field_name) { $field = $model->field_settings_for($field_name); $reg_csv_array[$this->_get_column_name_for_field($field)] = null; //$registration->get($field->get_name()); } } $registrations_csv_ready_array[] = $reg_csv_array; } if ($event_id) { $event_slug = EEM_Event::instance()->get_var(array(array('EVT_ID' => $event_id)), 'EVT_slug'); if (!$event_slug) { $event_slug = __('unknown', 'event_espresso'); } } else { $event_slug = __('all', 'event_espresso'); } $filename = sprintf("registrations-for-%s", $event_slug); $handle = $this->EE_CSV->begin_sending_csv($filename); $this->EE_CSV->write_data_array_to_csv($handle, $registrations_csv_ready_array); $this->EE_CSV->end_sending_csv($handle); }
/** * Creates a line item for the taxes subtotal and finds all the tax prices * and applies taxes to it * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total * @param EE_Transaction $transaction * @return EE_Line_Item */ protected static function create_default_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = NULL) { $tax_line_item = EE_Line_Item::new_instance(array('LIN_code' => 'taxes', 'LIN_name' => __('Taxes', 'event_espresso'), 'LIN_type' => EEM_Line_Item::type_tax_sub_total)); if ($transaction) { $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); $total_line_item->set_TXN_ID($transaction); } $total_line_item->add_child_line_item($tax_line_item); //and lastly, add the actual taxes self::apply_taxes($total_line_item); return $tax_line_item; }