/**
  * debug
  *
  * @param string $class
  * @param string $func
  * @param string $line
  * @param \EE_Transaction $transaction
  * @param array $info
  * @param bool $display_request
  */
 protected function log($class = '', $func = '', $line = '', EE_Transaction $transaction, $info = array(), $display_request = false)
 {
     if (WP_DEBUG && false) {
         if ($transaction instanceof EE_Transaction) {
             // don't serialize objects
             $info = EEH_Debug_Tools::strip_objects($info);
             if ($transaction->ID()) {
                 $info['TXN_status'] = $transaction->status_ID();
                 $info['TXN_reg_steps'] = $transaction->reg_steps();
                 $index = 'EE_Transaction: ' . $transaction->ID();
                 EEH_Debug_Tools::log($class, $func, $line, $info, $display_request, $index);
             }
         }
     }
 }
 function espresso_replace_invoice_shortcodes($content)
 {
     $EE = EE_Registry::instance();
     //Create the logo
     if (!empty($this->invoice_settings['invoice_logo_url'])) {
         $invoice_logo_url = $this->invoice_settings['invoice_logo_url'];
     } else {
         $invoice_logo_url = $EE->CFG->organization->logo_url;
     }
     if (!empty($invoice_logo_url)) {
         $image_size = getimagesize($invoice_logo_url);
         $invoice_logo_image = '<img class="logo screen" src="' . $invoice_logo_url . '" ' . $image_size[3] . ' alt="logo" /> ';
     } else {
         $invoice_logo_image = '';
     }
     $SearchValues = array("[organization]", "[registration_code]", "[transaction_id]", "[name]", "[base_url]", "[download_link]", "[invoice_logo_image]", "[street]", "[city]", "[state]", "[zip]", "[email]", "[vat]", "[registration_date]", "[instructions]");
     $primary_attendee = $this->transaction->primary_registration()->attendee();
     $org_state = EE_Registry::instance()->load_model('State')->get_one_by_ID($EE->CFG->organization->STA_ID);
     if ($org_state) {
         $org_state_name = $org_state->name();
     } else {
         $org_state_name = '';
     }
     $ReplaceValues = array(stripslashes($EE->CFG->organization->name), $this->registration->reg_code(), $this->transaction->ID(), $primary_attendee->full_name(), is_dir(EVENT_ESPRESSO_GATEWAY_DIR . '/invoice') ? EVENT_ESPRESSO_GATEWAY_URL . 'Invoice/lib/templates/' : EE_GATEWAYS_URL . 'Invoice/lib/templates/', $this->registration->invoice_url(), $invoice_logo_image, empty($EE->CFG->organization->address_2) ? $EE->CFG->organization->address_1 : $EE->CFG->organization->address_1 . '<br>' . $EE->CFG->organization->address_2, $EE->CFG->organization->city, $org_state_name, $EE->CFG->organization->zip, $EE->CFG->organization->email, $EE->CFG->organization->vat, date_i18n(get_option('date_format'), strtotime($this->registration->date())), $this->invoice_settings['pdf_instructions']);
     return str_replace($SearchValues, $ReplaceValues, $content);
 }
 /**
  *    get_payment_details
  *
  * @access    public
  * @param    array $payments
  * @return    string
  */
 public function get_payment_details($payments = array())
 {
     //prepare variables for displaying
     $template_args = array();
     $template_args['transaction'] = $this->_current_txn;
     $template_args['reg_url_link'] = $this->_reg_url_link;
     $template_args['payments'] = array();
     foreach ($payments as $payment) {
         $template_args['payments'][] = $this->get_payment_row_html($payment);
     }
     //create a hacky payment object, but dont save it
     $payment = EE_Payment::new_instance(array('TXN_ID' => $this->_current_txn->ID(), 'STS_ID' => EEM_Payment::status_id_pending, 'PAY_timestamp' => time(), 'PAY_amount' => $this->_current_txn->total(), 'PMD_ID' => $this->_current_txn->payment_method_ID()));
     $payment_method = $this->_current_txn->payment_method();
     if ($payment_method instanceof EE_Payment_Method && $payment_method->type_obj() instanceof EE_PMT_Base) {
         $template_args['gateway_content'] = $payment_method->type_obj()->payment_overview_content($payment);
     } else {
         $template_args['gateway_content'] = '';
     }
     // link to SPCO payment_options
     $template_args['show_try_pay_again_link'] = $this->_show_try_pay_again_link;
     $template_args['SPCO_payment_options_url'] = $this->_SPCO_payment_options_url;
     // verify template arguments
     EEH_Template_Validator::verify_instanceof($template_args['transaction'], '$transaction', 'EE_Transaction');
     EEH_Template_Validator::verify_isnt_null($template_args['payments'], '$payments');
     EEH_Template_Validator::verify_isnt_null($template_args['show_try_pay_again_link'], '$show_try_pay_again_link');
     EEH_Template_Validator::verify_isnt_null($template_args['gateway_content'], '$gateway_content');
     EEH_Template_Validator::verify_isnt_null($template_args['SPCO_payment_options_url'], '$SPCO_payment_options_url');
     return EEH_Template::locate_template(THANK_YOU_TEMPLATES_PATH . 'thank-you-page-payment-details.template.php', $template_args, TRUE, TRUE);
 }
 /**
  * 		generates HTML for the Attendees Transaction main meta box
  *		@access private
  *		@return void
  */
 function _txn_attendees_meta_box($post, $metabox = array('args' => array()))
 {
     global $wpdb;
     extract($metabox['args']);
     // process items in cart
     $line_items = $this->_transaction->get_many_related('Line_Item', array(array('LIN_type' => 'line-item')));
     $this->_template_args['event_attendees'] = array();
     if (!empty($line_items)) {
         foreach ($line_items as $item) {
             $ticket = $item->ticket();
             if (empty($ticket)) {
                 continue;
             }
             //right now we're only handling tickets here.  Cause its expected that only tickets will have attendees right?
             $registrations = $ticket->get_many_related('Registration', array(array('TXN_ID' => $this->_transaction->ID())));
             $event = $ticket->get_first_related('Registration')->get_first_related('Event');
             foreach ($registrations as $registration) {
                 $attendee = $registration->get_first_related('Attendee');
                 $this->_template_args['event_attendees'][$registration->ID()]['att_num'] = $registration->get('REG_count');
                 $this->_template_args['event_attendees'][$registration->ID()]['event_ticket_name'] = $event->get('EVT_name') . ' - ' . $item->get('LIN_name');
                 $this->_template_args['event_attendees'][$registration->ID()]['attendee'] = $attendee->full_name();
                 $this->_template_args['event_attendees'][$registration->ID()]['ticket_price'] = EEH_Template::format_currency($item->get('LIN_unit_price'));
                 $this->_template_args['event_attendees'][$registration->ID()]['email'] = $attendee->email();
                 $this->_template_args['event_attendees'][$registration->ID()]['address'] = implode(',<br>', $attendee->full_address_as_array());
                 $this->_template_args['event_attendees'][$registration->ID()]['att_id'] = $attendee->ID();
             }
         }
         $this->_template_args['transaction_form_url'] = add_query_arg(array('action' => 'edit_transaction', 'process' => 'attendees'), TXN_ADMIN_URL);
         $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php';
         echo EEH_Template::display_template($template_path, $this->_template_args, TRUE);
     }
 }
 /**
  * 	process_shortcode - EES_Espresso_Txn_Page
  *
  *  @access 	public
  *  @param		array 	$attributes
  *  @return 	void
  */
 public function process_shortcode($attributes = array())
 {
     if ($this->_current_txn) {
         printf(__("IPN successfully received for Transaction with ID '%d'", "event_espresso"), $this->_current_txn->ID());
     } else {
         printf(__("No IPN (or incomplete IPN) received.", "event_espresso"));
     }
 }
 /**
  * txn_attendees_meta_box
  *    generates HTML for the Attendees Transaction main meta box
  *
  * @access public
  * @param WP_Post $post
  * @param array $metabox
  * @return void
  */
 public function txn_attendees_meta_box($post, $metabox = array('args' => array()))
 {
     extract($metabox['args']);
     $this->_template_args['post'] = $post;
     $this->_template_args['event_attendees'] = array();
     // process items in cart
     $line_items = $this->_transaction->get_many_related('Line_Item', array(array('LIN_type' => 'line-item')));
     if (!empty($line_items)) {
         foreach ($line_items as $item) {
             if ($item instanceof EE_Line_Item) {
                 switch ($item->OBJ_type()) {
                     case 'Event':
                         break;
                     case 'Ticket':
                         $ticket = $item->ticket();
                         if (empty($ticket)) {
                             continue;
                             //right now we're only handling tickets here.  Cause its expected that only tickets will have attendees right?
                         }
                         $ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
                         $event = $ticket->get_first_related('Registration')->get_first_related('Event');
                         $event_name = $event instanceof EE_Event ? $event->get('EVT_name') . ' - ' . $item->get('LIN_name') : '';
                         $registrations = $ticket->get_many_related('Registration', array(array('TXN_ID' => $this->_transaction->ID())));
                         foreach ($registrations as $registration) {
                             $this->_template_args['event_attendees'][$registration->ID()]['att_num'] = $registration->get('REG_count');
                             $this->_template_args['event_attendees'][$registration->ID()]['event_ticket_name'] = $event_name;
                             $this->_template_args['event_attendees'][$registration->ID()]['ticket_price'] = $ticket_price;
                             // attendee info
                             $attendee = $registration->get_first_related('Attendee');
                             if ($attendee instanceof EE_Attendee) {
                                 $this->_template_args['event_attendees'][$registration->ID()]['att_id'] = $attendee->ID();
                                 $this->_template_args['event_attendees'][$registration->ID()]['attendee'] = $attendee->full_name();
                                 $this->_template_args['event_attendees'][$registration->ID()]['email'] = '<a href="mailto:' . $attendee->email() . '?subject=' . $event->get('EVT_name') . __(' Event', 'event_espresso') . '">' . $attendee->email() . '</a>';
                                 $this->_template_args['event_attendees'][$registration->ID()]['address'] = implode(',<br>', $attendee->full_address_as_array());
                             } else {
                                 $this->_template_args['event_attendees'][$registration->ID()]['att_id'] = '';
                                 $this->_template_args['event_attendees'][$registration->ID()]['attendee'] = '';
                                 $this->_template_args['event_attendees'][$registration->ID()]['email'] = '';
                                 $this->_template_args['event_attendees'][$registration->ID()]['address'] = '';
                             }
                         }
                         break;
                 }
             }
         }
         $this->_template_args['transaction_form_url'] = add_query_arg(array('action' => 'edit_transaction', 'process' => 'attendees'), TXN_ADMIN_URL);
         echo EEH_Template::display_template(TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php', $this->_template_args, TRUE);
     } else {
         echo sprintf(__('%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s', 'event_espresso'), '<p class="important-notice">', '</p>');
     }
 }
 /**
  * Updates the transaction in the session to acknowledge the registrant is done
  * the registration process, all that remains is for them ot make the offline
  * payment. Was renamed from 'set_transaction_details' to 'thank_you_page()', because it served the same purpose
  * as it's parent's 'thank_you_page()', which is to update the transaction (but not the payment
  * because in this case no payment has been made)
  * @global type $EE_Session
  * @param EE_Transaction
  * @return void
  */
 public function thank_you_page_logic(EE_Transaction $transaction)
 {
     do_action('AHEE_log', __FILE__, __FUNCTION__, '');
     //check for an existing payment from this gateway
     $payments = $this->_PAY->get_all(array(array('PAY_gateway' => $this->gateway(), 'TXN_ID' => $transaction->ID())));
     //if it already exists, short-circuit updating the transaction
     if (empty($payments)) {
         $this->update_transaction_with_payment($transaction, null);
         $transaction->save();
     }
     //createa hackey payment object, but dont save it
     $payment = EE_Payment::new_instance(array('TXN_ID' => $transaction->ID(), 'STS_ID' => EEM_Payment::status_id_pending, 'PAY_timestamp' => current_time('timestamp'), 'PAY_amount' => $transaction->total(), 'PAY_gateway' => $this->_gateway_name));
     do_action('AHEE_EE_Gateway__update_transaction_with_payment__done', $transaction, $payment);
     parent::thank_you_page_logic($transaction);
 }
 /**
  * 	_process_finalize_registration
  *
  * 	@access private
  * 	@return 	void
  */
 private function _process_finalize_registration()
 {
     do_action('AHEE_log', __FILE__, __FUNCTION__, '');
     // save everything
     if ($this->_continue_reg && $this->_save_all_registration_information()) {
         //			echo '<h2 style="color:#E76700;">_process_finalize_registration<br/><span style="font-size:9px;font-weight:normal;color:#666">' . __FILE__ . '</span>    <b style="font-size:10px;color:#333">  ' . __LINE__ . ' </b></h2>';
         // save TXN data to the cart
         $this->_cart->get_grand_total()->save_this_and_descendants_to_txn($this->_transaction->ID());
         do_action('AHEE__EE_Single_Page_Checkout__process_finalize_registration__before_gateway', $this->_transaction);
         // if Default REG Status is set to REQUIRES APPROVAL... then payments are NOT allowed
         if (EE_Registry::instance()->REQ->is_set('selected_gateway') && EE_Registry::instance()->REQ->get('selected_gateway') == 'payments_closed') {
             //				echo '<h2 style="color:#E76700;">payments_closed<br/><span style="font-size:9px;font-weight:normal;color:#666">' . __FILE__ . '</span>    <b style="font-size:10px;color:#333">  ' . __LINE__ . ' </b></h2>';
             // set TXN Status to Open
             $this->_transaction->set_status(EEM_Transaction::incomplete_status_code);
             $this->_transaction->save();
             $this->_transaction->finalize();
             $notices = EE_Error::get_notices(FALSE);
             $response = array('msg' => array('success' => isset($notices['success']) ? $notices['success'] : '', 'errors' => isset($notices['errors']) ? $notices['errors'] : ''));
             $this->_thank_you_page_url = add_query_arg(array('e_reg_url_link' => $this->_transaction->primary_registration()->reg_url_link()), get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
             // Default REG Status is set to PENDING PAYMENT OR APPROVED, and payments are allowed
         } else {
             // attempt to perform transaction via payment gateway
             $response = EE_Registry::instance()->load_model('Gateways')->process_payment_start($this->_cart->get_grand_total(), $this->_transaction);
             $this->_thank_you_page_url = $response['forward_url'];
         }
         if (isset($response['msg']['success'])) {
             $response_data = array('success' => $response['msg']['success'], 'return_data' => array('redirect-to-thank-you-page' => $this->_thank_you_page_url));
             $response_data = apply_filters('FHEE__EE_Single_Page_Checkout__JSON_response', $response_data);
             //				printr( $response_data, '$response_data  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
             //				echo '<h4>thank_you_page_url : ' . $this->_thank_you_page_url . '  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span></h4>';
             if (EE_Registry::instance()->REQ->front_ajax) {
                 echo json_encode($response_data);
                 die;
             } else {
                 wp_safe_redirect($this->_thank_you_page_url);
                 exit;
             }
         } else {
             EE_Error::add_error($response['msg']['error'], __FILE__, __FUNCTION__, __LINE__);
         }
         //			printr( $response, '$response  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
     }
     $this->go_to_next_step(__FUNCTION__);
 }
 function espresso_replace_invoice_shortcodes($content)
 {
     $EE = EE_Registry::instance();
     //Create the logo
     $invoice_logo_url = $this->invoice_payment_method->get_extra_meta('pdf_logo_image', TRUE, $EE->CFG->organization->logo_url);
     if (!empty($invoice_logo_url)) {
         $image_size = getimagesize($invoice_logo_url);
         $invoice_logo_image = '<img class="logo screen" src="' . $invoice_logo_url . '" ' . $image_size[3] . ' alt="logo" /> ';
     } else {
         $invoice_logo_image = '';
     }
     $SearchValues = array("[organization]", "[registration_code]", "[transaction_id]", "[name]", "[base_url]", "[download_link]", "[invoice_logo_image]", "[street]", "[city]", "[state]", "[zip]", "[email]", "[vat]", "[registration_date]", "[instructions]");
     $primary_attendee = $this->transaction->primary_registration()->attendee();
     $org_state = EE_Registry::instance()->load_model('State')->get_one_by_ID($EE->CFG->organization->STA_ID);
     if ($org_state) {
         $org_state_name = $org_state->name();
     } else {
         $org_state_name = '';
     }
     $ReplaceValues = array($EE->CFG->organization->get_pretty('name'), $this->registration->reg_code(), $this->transaction->ID(), $primary_attendee->full_name(), is_dir(EVENT_ESPRESSO_GATEWAY_DIR . '/invoice') ? EVENT_ESPRESSO_GATEWAY_URL . 'Invoice/lib/templates/' : EE_GATEWAYS_URL . 'Invoice/lib/templates/', $this->registration->invoice_url(), $invoice_logo_image, empty($EE->CFG->organization->address_2) ? $EE->CFG->organization->get_pretty('address_1') : $EE->CFG->organization->get_pretty('address_1') . '<br>' . $EE->CFG->organization->get_pretty('address_2'), $EE->CFG->organization->get_pretty('city'), $org_state_name, $EE->CFG->organization->get_pretty('zip'), $EE->CFG->organization->get_pretty('email'), $EE->CFG->organization->vat, $this->registration->get_i18n_datetime('REG_date', get_option('date_format')), $this->invoice_payment_method->get_extra_meta('pdf_instructions', TRUE));
     return str_replace($SearchValues, $ReplaceValues, $content);
 }
 /**
  * Callback for transaction list table column action for new events column.
  *
  * @param EE_Transaction $transaction
  * @return string
  */
 public function transaction_list_table_events_column_content($transaction)
 {
     if (!$transaction instanceof EE_Transaction) {
         return;
     }
     //get event ids
     $registrations = $transaction->registrations();
     $event_IDs = array();
     foreach ($registrations as $registration) {
         if ($registration instanceof EE_Registration) {
             if ($registration->event_ID() && !in_array($registration->event_ID(), $event_IDs)) {
                 $event_IDs[] = $registration->event_ID();
             }
         }
     }
     if (!empty($event_IDs)) {
         $count = count($event_IDs);
         $event_IDs = implode(',', $event_IDs);
         $url = add_query_arg(array('EVT_IDs' => $event_IDs, 'TXN_ID' => $transaction->ID(), 'page' => 'espresso_events', 'action' => 'default'), admin_url('admin.php'));
         echo '<a href="' . $url . '">' . sprintf(_n('1 Event', '%d Events', $count, 'event_espresso'), $count) . '</a>';
     }
 }
 /**
  * Get order ID
  *
  * @see Pronamic_Pay_PaymentDataInterface::get_order_id()
  * @return string
  */
 public function get_order_id()
 {
     return $this->transaction->ID();
 }
 /**
  * recalculate_total_payments_for_transaction
  *
  * @access public
  * @param EE_Transaction $transaction
  * @param string         $payment_status One of EEM_Payment's statuses, like 'PAP' (Approved).
  *                                       By default, searches for approved payments
  * @return float|false   float on success, false on fail
  * @throws \EE_Error
  */
 public function recalculate_total_payments_for_transaction(EE_Transaction $transaction, $payment_status = EEM_Payment::status_id_approved)
 {
     // verify transaction
     if (!$transaction instanceof EE_Transaction) {
         EE_Error::add_error(__('Please provide a valid EE_Transaction object.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
         return false;
     }
     // ensure Payment model is loaded
     EE_Registry::instance()->load_model('Payment');
     // calls EEM_Base::sum()
     return EEM_Payment::instance()->sum(array(array('TXN_ID' => $transaction->ID(), 'STS_ID' => $payment_status)), 'PAY_amount');
 }
 /**
  * Checks line item and children list $txn as their transaction.
  * Used by E_UnitTestCase_Test::test_new_typical_transaction()
  * @param EE_Transaction $txn
  * @param EE_Line_Item $line_item
  */
 private function _ensure_txn_on_line_item_and_children($txn, $line_item)
 {
     $this->assertEquals($txn->ID(), $line_item->TXN_ID());
     foreach ($line_item->children() as $child_line_item) {
         $this->_ensure_txn_on_line_item_and_children($txn, $child_line_item);
     }
 }
 /**
  * This helper method can be used by any incoming data handlers to setup the data correctly.  All that is required is that $this->reg_objs be set.
  * @throws \EE_Error
  */
 protected function _assemble_data()
 {
     //verify that reg_objs is set
     if (!is_array($this->reg_objs) && !reset($this->reg_objs) instanceof EE_Registration) {
         throw new EE_Error(__('In order to assemble the data correctly, the "reg_objs" property must be an array of EE_Registration objects', 'event_espresso'));
     }
     //get all attendee and events associated with the registrations in this transaction
     $events = $event_setup = $evtcache = $tickets = $datetimes = array();
     $answers = $questions = $attendees = $line_items = $registrations = array();
     $total_ticket_count = 0;
     if (!empty($this->reg_objs)) {
         $event_attendee_count = array();
         foreach ($this->reg_objs as $reg) {
             //account for filtered registrations by status.
             if (!empty($this->filtered_reg_status) && $this->filtered_reg_status !== $reg->status_ID()) {
                 continue;
             }
             $evt_id = $reg->event_ID();
             /** @type EE_Ticket $ticket */
             $ticket = $reg->get_first_related('Ticket');
             $relateddatetime = $ticket->datetimes();
             $total_ticket_count++;
             $tickets[$ticket->ID()]['ticket'] = $ticket;
             $tickets[$ticket->ID()]['count'] = is_array($tickets[$ticket->ID()]) && isset($tickets[$ticket->ID()]['count']) ? $tickets[$ticket->ID()]['count'] + 1 : 1;
             $tickets[$ticket->ID()]['att_objs'][$reg->attendee_ID()] = $reg->attendee();
             $tickets[$ticket->ID()]['dtt_objs'] = $relateddatetime;
             $tickets[$ticket->ID()]['reg_objs'][$reg->ID()] = $reg;
             $event = $reg->event();
             $tickets[$ticket->ID()]['EE_Event'] = $event;
             $evtcache[$evt_id] = $event;
             $eventsetup[$evt_id]['reg_objs'][$reg->ID()] = $reg;
             $eventsetup[$evt_id]['tkt_objs'][$ticket->ID()] = $ticket;
             $eventsetup[$evt_id]['att_objs'][$reg->attendee_ID()] = $reg->attendee();
             $event_attendee_count[$evt_id] = isset($event_attendee_count[$evt_id]) ? $event_attendee_count[$evt_id] + 1 : 0;
             $attendees[$reg->attendee_ID()]['line_ref'][] = $evt_id;
             $attendees[$reg->attendee_ID()]['att_obj'] = $reg->attendee();
             $attendees[$reg->attendee_ID()]['reg_objs'][$reg->ID()] = $reg;
             //$attendees[ $reg->attendee_ID() ]['registration_id'] = $reg->ID();
             $attendees[$reg->attendee_ID()]['attendee_email'] = $reg->attendee() instanceof EE_Attendee ? $reg->attendee()->email() : '';
             $attendees[$reg->attendee_ID()]['tkt_objs'][$ticket->ID()] = $ticket;
             $attendees[$reg->attendee_ID()]['evt_objs'][$evt_id] = $event;
             //registrations
             $registrations[$reg->ID()]['tkt_obj'] = $ticket;
             $registrations[$reg->ID()]['evt_obj'] = $event;
             $registrations[$reg->ID()]['reg_obj'] = $reg;
             $registrations[$reg->ID()]['att_obj'] = $reg->attendee();
             //set up answer objects
             $rel_ans = $reg->get_many_related('Answer');
             foreach ($rel_ans as $ansid => $answer) {
                 if (!isset($questions[$ansid])) {
                     $questions[$ansid] = $answer->get_first_related('Question');
                 }
                 $answers[$ansid] = $answer;
                 $registrations[$reg->ID()]['ans_objs'][$ansid] = $answer;
             }
             foreach ($relateddatetime as $dtt_id => $datetime) {
                 $eventsetup[$evt_id]['dtt_objs'][$dtt_id] = $datetime;
                 $registrations[$reg->ID()]['dtt_objs'][$dtt_id] = $datetime;
                 if (isset($datetimes[$dtt_id])) {
                     continue;
                     //already have this info in the datetimes array.
                 }
                 $datetimes[$dtt_id]['tkt_objs'][] = $ticket;
                 $datetimes[$dtt_id]['datetime'] = $datetime;
                 $datetimes[$dtt_id]['evt_objs'][$evt_id] = $event;
                 $datetimes[$dtt_id]['reg_objs'][$reg->ID()] = $reg;
             }
         }
         //let's loop through the unique event=>reg items and setup data on them
         if (!empty($eventsetup)) {
             foreach ($eventsetup as $evt_id => $items) {
                 if ($this->txn instanceof EE_Transaction) {
                     $ticket_line_items_for_event = EEM_Line_Item::instance()->get_all(array(array('Ticket.Datetime.EVT_ID' => $evt_id, 'TXN_ID' => $this->txn->ID()), 'default_where_conditions' => 'none'));
                 } else {
                     $ticket_line_items_for_event = array();
                 }
                 $events[$evt_id] = array('ID' => $evt_id, 'event' => $evtcache[$evt_id], 'name' => $evtcache[$evt_id] instanceof EE_Event ? $evtcache[$evt_id]->name() : '', 'total_attendees' => $event_attendee_count[$evt_id], 'reg_objs' => $items['reg_objs'], 'tkt_objs' => $items['tkt_objs'], 'att_objs' => $items['att_objs'], 'dtt_objs' => isset($items['dtt_objs']) ? $items['dtt_objs'] : array(), 'line_items' => $ticket_line_items_for_event);
                 //make sure the tickets have the line items setup for them.
                 foreach ($ticket_line_items_for_event as $line_id => $line_item) {
                     if ($line_item instanceof EE_Line_Item) {
                         $tickets[$line_item->ticket()->ID()]['line_item'] = $line_item;
                         $tickets[$line_item->ticket()->ID()]['sub_line_items'] = $line_item->children();
                         $line_items[$line_item->ID()]['children'] = $line_item->children();
                         $line_items[$line_item->ID()]['EE_Ticket'] = $line_item->ticket();
                     }
                 }
             }
         }
         $this->grand_total_line_item = $this->txn instanceof EE_Transaction ? $this->txn->total_line_item() : null;
     }
     //lets set the attendees and events properties
     $this->attendees = $attendees;
     $this->events = $events;
     $this->tickets = $tickets;
     $this->line_items_with_children = $line_items;
     $this->datetimes = $datetimes;
     $this->questions = $questions;
     $this->answers = $answers;
     $this->total_ticket_count = $total_ticket_count;
     $this->registrations = $registrations;
     if ($this->txn instanceof EE_Transaction) {
         $this->tax_line_items = $this->txn->tax_items();
         $this->additional_line_items = $this->txn->non_ticket_line_items();
         $this->payments = $this->txn->payments();
         //setup primary registration if we have a single transaction object to work with
         //let's get just the primary_attendee_data!  First we get the primary registration object.
         $primary_reg = $this->txn->primary_registration();
         // verify
         if ($primary_reg instanceof EE_Registration) {
             // get attendee object
             if ($primary_reg->attendee() instanceof EE_Attendee) {
                 //now we can setup the primary_attendee_data array
                 $this->primary_attendee_data = array('registration_id' => $primary_reg->ID(), 'att_obj' => $primary_reg->attendee(), 'reg_obj' => $primary_reg, 'primary_att_obj' => $primary_reg->attendee(), 'primary_reg_obj' => $primary_reg);
             } else {
                 EE_Error::add_error(__('Incoming data does not have a valid Attendee object for the primary registrant.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
             }
         } else {
             EE_Error::add_error(__('Incoming data does not have a valid Registration object for the primary registrant.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
         }
     }
 }
 /**
  * Makes sure there is no rounding errors for the REG_final_prices.
  * Eg, if we have 3 registrations for $1, and there is a $0.01 discount between the three of them,
  * they will each be for $0.99333333, which gets rounded to $1 again.
  * So the transaction total will be $2.99, but each registration will be for $1,
  * so if each registrant paid individually they will have overpaid by $0.01.
  * So in order to overcome this, we check for any difference, and if there is a difference
  * we just grab one registrant at random and make them responsible for it.
  * This should be used after setting REG_final_prices (it's done automatically as part of
  * EE_Registration_Processor::update_registration_final_prices())
  * @param EE_Transaction $transaction
  * @return boolean success verifying that there is NO difference after this method is done
  */
 public function fix_reg_final_price_rounding_issue($transaction)
 {
     $reg_final_price_sum = EEM_Registration::instance()->sum(array(array('TXN_ID' => $transaction->ID())), 'REG_final_price');
     $diff = $transaction->total() - floatval($reg_final_price_sum);
     //ok then, just grab one of the registrations
     if ($diff != 0) {
         $a_reg = EEM_Registration::instance()->get_one(array(array('TXN_ID' => $transaction->ID())));
         $success = $a_reg instanceof EE_Registration ? $a_reg->save(array('REG_final_price' => $a_reg->final_price() + $diff)) : false;
         return $success ? true : false;
     } else {
         return true;
     }
 }
 /**
  * _generate_payment_details_array
  *
  * @since 4.8
  * @param EE_Transaction $transaction
  * @param float          $amount
  * @param int            $PAY_ID
  * @param bool           $refund
  * @return array
  */
 protected function _generate_details_array_for_payment_or_refund(EE_Transaction $transaction, $amount = 10.0, $PAY_ID = null, $refund = false)
 {
     return array('type' => $refund !== true ? 1 : -1, 'PAY_ID' => $PAY_ID, 'TXN_ID' => $transaction->ID(), 'PMD_ID' => $this->_payment_method()->ID(), 'STS_ID' => EEM_Payment::status_id_approved, 'PAY_source' => EEM_Payment_Method::scope_admin, 'PAY_details' => array(), 'PAY_amount' => $amount, 'PAY_timestamp' => time() - 86400, 'PAY_po_number' => rand(100, 1000), 'PAY_extra_accntng' => rand(100, 1000), 'PAY_txn_id_chq_nmbr' => rand(100, 1000), 'PAY_gateway_response' => 'You are a true champion!');
 }
 /**
  *
  * @param EE_Transaction       $transaction
  * @param float                $amount
  * @param EE_Billing_Info_Form $billing_info
  * @param string               $return_url
  * @param string                 $fail_url
  * @param string               $method
  * @param bool           $by_admin
  * @return EE_Payment
  * @throws EE_Error
  */
 function process_payment(EE_Transaction $transaction, $amount = null, $billing_info = null, $return_url = null, $fail_url = '', $method = 'CART', $by_admin = false)
 {
     // @todo: add surcharge for the payment method, if any
     if ($this->_gateway) {
         //there is a gateway, so we're going to make a payment object
         //but wait! do they already have a payment in progress that we thought was failed?
         $duplicate_properties = array('STS_ID' => EEM_Payment::status_id_failed, 'TXN_ID' => $transaction->ID(), 'PMD_ID' => $this->_pm_instance->ID(), 'PAY_source' => $method, 'PAY_amount' => $amount !== null ? $amount : $transaction->remaining(), 'PAY_gateway_response' => null);
         $payment = EEM_Payment::instance()->get_one(array($duplicate_properties));
         //if we didn't already have a payment in progress for the same thing,
         //then we actually want to make a new payment
         if (!$payment instanceof EE_Payment) {
             $payment = EE_Payment::new_instance(array_merge($duplicate_properties, array('PAY_timestamp' => time(), 'PAY_txn_id_chq_nmbr' => null, 'PAY_po_number' => null, 'PAY_extra_accntng' => null, 'PAY_details' => null)));
         }
         //make sure the payment has been saved to show we started it, and so it has an ID should the gateway try to log it
         $payment->save();
         $billing_values = $this->_get_billing_values_from_form($billing_info);
         //  Offsite Gateway
         if ($this->_gateway instanceof EE_Offsite_Gateway) {
             $payment = $this->_gateway->set_redirection_info($payment, $billing_values, $return_url, EE_Config::instance()->core->txn_page_url(array('e_reg_url_link' => $transaction->primary_registration()->reg_url_link(), 'ee_payment_method' => $this->_pm_instance->slug())), $fail_url);
             $payment->save();
             //  Onsite Gateway
         } elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
             $payment = $this->_gateway->do_direct_payment($payment, $billing_values);
             $payment->save();
         } else {
             throw new EE_Error(sprintf(__('Gateway for payment method type "%s" is "%s", not a subclass of either EE_Offsite_Gateway or EE_Onsite_Gateway, or null (to indicate NO gateway)', 'event_espresso'), get_class($this), gettype($this->_gateway)));
         }
     } else {
         // no gateway provided
         // there is no payment. Must be an offline gateway
         // create a payment object anyways, but dont save it
         $payment = EE_Payment::new_instance(array('STS_ID' => EEM_Payment::status_id_pending, 'TXN_ID' => $transaction->ID(), 'PMD_ID' => $transaction->payment_method_ID(), 'PAY_amount' => 0.0, 'PAY_timestamp' => time()));
     }
     // if there is billing info, clean it and save it now
     if ($billing_info instanceof EE_Billing_Attendee_Info_Form) {
         $this->_save_billing_info_to_attendee($billing_info, $transaction);
     }
     return $payment;
 }
 /**
  * debug
  *
  * @param string $class
  * @param string $func
  * @param string $line
  * @param array $info
  * @param bool $display_request
  */
 function log($class = '', $func = '', $line = '', $info = array(), $display_request = false)
 {
     if (WP_DEBUG && false) {
         $debug_data = get_option('EE_DEBUG_SPCO_' . EE_Session::instance()->id(), array());
         $default_data = array($class => $func . '() : ' . $line, 'request->step' => $this->step, 'request->action' => $this->action, 'current_step->slug' => $this->current_step instanceof EE_SPCO_Reg_Step ? $this->current_step->slug() : '', 'current_step->completed' => $this->current_step instanceof EE_SPCO_Reg_Step ? $this->current_step->completed() : '', 'txn_status_updated' => $this->txn_status_updated, 'reg_status_updated' => $this->reg_status_updated, 'reg_url_link' => $this->reg_url_link, 'REQ' => $display_request ? $_REQUEST : '');
         if ($this->transaction instanceof EE_Transaction) {
             $default_data['TXN_status'] = $this->transaction->status_ID();
             $default_data['TXN_reg_steps'] = $this->transaction->reg_steps();
             foreach ($this->transaction->registrations($this->reg_cache_where_params) as $REG_ID => $registration) {
                 $default_data['registrations'][$REG_ID] = $registration->status_ID();
             }
             if ($this->transaction->ID()) {
                 $TXN_ID = 'EE_Transaction: ' . $this->transaction->ID();
                 // don't serialize objects
                 $info = $this->_strip_objects($info);
                 if (!isset($debug_data[$TXN_ID])) {
                     $debug_data[$TXN_ID] = array();
                 }
                 $debug_data[$TXN_ID][microtime()] = array_merge($default_data, $info);
                 update_option('EE_DEBUG_SPCO_' . EE_Session::instance()->id(), $debug_data);
             }
         }
     }
 }
 /**
  * generate_ONE_registration_from_line_item
  *
  * Although a ticket line item may have a quantity greater than 1,
  * this method will ONLY CREATE ONE REGISTRATION !!!
  * Regardless of the ticket line item quantity.
  * This means that any code calling this method is responsible for ensuring
  * that the final registration count matches the ticket line item quantity.
  * This was done to make it easier to match the number of registrations
  * to the number of tickets in the cart, when the cart has been edited
  * after SPCO has already been initialized. So if an additional ticket was added to the cart, you can simply pass
  * the line item to this method to add a second ticket, and in this case, you would not want to add 2 tickets.
  *
  * @param EE_Line_Item $line_item
  * @param \EE_Transaction $transaction
  * @param int $att_nmbr
  * @param int $total_ticket_count
  * @return \EE_Registration | null
  * @throws \EE_Error
  */
 public function generate_ONE_registration_from_line_item(EE_Line_Item $line_item, EE_Transaction $transaction, $att_nmbr = 1, $total_ticket_count = 1)
 {
     // grab the related ticket object for this line_item
     $ticket = $line_item->ticket();
     if (!$ticket instanceof EE_Ticket) {
         EE_Error::add_error(sprintf(__("Line item %s did not contain a valid ticket", "event_espresso"), $line_item->ID()), __FILE__, __FUNCTION__, __LINE__);
         return null;
     }
     $first_datetime = $ticket->get_first_related('Datetime');
     if (!$first_datetime instanceof EE_Datetime) {
         EE_Error::add_error(sprintf(__("The ticket (%s) is not associated with any valid datetimes.", "event_espresso"), $ticket->name()), __FILE__, __FUNCTION__, __LINE__);
         return null;
     }
     $event = $first_datetime->get_first_related('Event');
     if (!$event instanceof EE_Event) {
         EE_Error::add_error(sprintf(__("The ticket (%s) is not associated with a valid event.", "event_espresso"), $ticket->name()), __FILE__, __FUNCTION__, __LINE__);
         return null;
     }
     $reg_url_link = $this->generate_reg_url_link($att_nmbr, $line_item);
     // now create a new registration for the ticket
     $registration = EE_Registration::new_instance(array('EVT_ID' => $event->ID(), 'TXN_ID' => $transaction->ID(), 'TKT_ID' => $ticket->ID(), 'STS_ID' => EEM_Registration::status_id_incomplete, 'REG_date' => $transaction->datetime(), 'REG_final_price' => $ticket->get_ticket_total_with_taxes(), 'REG_session' => EE_Registry::instance()->SSN->id(), 'REG_count' => $att_nmbr, 'REG_group_size' => $total_ticket_count, 'REG_url_link' => $reg_url_link));
     $registration->set_reg_code($this->generate_reg_code($registration));
     $registration->save();
     $registration->_add_relation_to($event, 'Event', array(), $event->ID());
     $registration->_add_relation_to($line_item->ticket(), 'Ticket', array(), $line_item->ticket()->ID());
     $transaction->_add_relation_to($registration, 'Registration');
     return $registration;
 }
    /**
     * 	column_actions
     * @param \EE_Transaction $item
     * @return string
     */
    function column_actions(EE_Transaction $item)
    {
        $registration = $item->primary_registration();
        $attendee = $registration->attendee();
        EE_Registry::instance()->load_helper('MSG_Template');
        //Build row actions
        $view_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'view_transaction', 'TXN_ID' => $item->ID()), TXN_ADMIN_URL);
        $dl_invoice_lnk_url = $registration->invoice_url();
        $dl_receipt_lnk_url = $registration->receipt_url();
        $view_reg_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'view_registration', '_REG_ID' => $registration->ID()), REG_ADMIN_URL);
        $send_pay_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'send_payment_reminder', 'TXN_ID' => $item->ID()), TXN_ADMIN_URL);
        //Build row actions
        $view_lnk = '
			<li>
				<a href="' . $view_lnk_url . '" title="' . esc_attr__('View Transaction Details', 'event_espresso') . '" class="tiny-text">
					<span class="dashicons dashicons-cart"></span>
				</a>
			</li>';
        //only show invoice link if message type is active.
        if ($attendee instanceof EE_Attendee && EEH_MSG_Template::is_mt_active('invoice')) {
            $dl_invoice_lnk = '
		<li>
			<a title="' . esc_attr__('View Transaction Invoice', 'event_espresso') . '" target="_blank" href="' . $dl_invoice_lnk_url . '" class="tiny-text">
				<span class="dashicons dashicons-media-spreadsheet ee-icon-size-18"></span>
			</a>
		</li>';
        } else {
            $dl_invoice_lnk = '';
        }
        //only show receipt link if message type is active.
        if ($attendee instanceof EE_Attendee && EEH_MSG_Template::is_mt_active('receipt')) {
            $dl_receipt_lnk = '
		<li>
			<a title="' . esc_attr__('View Transaction Receipt', 'event_espresso') . '" target="_blank" href="' . $dl_receipt_lnk_url . '" class="tiny-text">
				<span class="dashicons dashicons-media-default ee-icon-size-18"></span>
			</a>
		</li>';
        } else {
            $dl_receipt_lnk = '';
        }
        //only show payment reminder link if the message type is active.
        if (EEH_MSG_Template::is_mt_active('payment_reminder')) {
            $send_pay_lnk = $attendee instanceof EE_Attendee && EE_Registry::instance()->CAP->current_user_can('ee_send_message', 'espresso_transactions_send_payment_reminder') ? '
			<li>
				<a href="' . $send_pay_lnk_url . '" title="' . esc_attr__('Send Payment Reminder', 'event_espresso') . '" class="tiny-text">
					<span class="dashicons dashicons-email-alt"></span>
				</a>
			</li>' : '';
            $send_pay_lnk = $item->get('STS_ID') != EEM_Transaction::complete_status_code && $item->get('STS_ID') != EEM_Transaction::overpaid_status_code ? $send_pay_lnk : '';
        } else {
            $send_pay_lnk = '';
        }
        $view_reg_lnk = EE_Registry::instance()->CAP->current_user_can('ee_read_registration', 'espresso_registrations_view_registration', $registration->ID()) ? '
			<li>
				<a href="' . $view_reg_lnk_url . '" title="' . esc_attr__('View Registration Details', 'event_espresso') . '" class="tiny-text">
					<span class="dashicons dashicons-clipboard"></span>
				</a>
			</li>' : '';
        return $this->_action_string($view_lnk . $dl_invoice_lnk . $dl_receipt_lnk . $view_reg_lnk . $send_pay_lnk, $item, 'ul', 'txn-overview-actions-ul');
    }
 /**
  * Process the IPN. Firstly, we'll hope we put the standard args into the IPN URL so
  * we can easily find what registration the IPN is for and what payment method.
  * However, if not, we'll give all payment methods a chance to claim it and process it.
  * If a payment is found for the IPN info, it is saved.
  *
  * @param array             $_req_data eg $_REQUEST
  * @param EE_Transaction|int $transaction          optional (or a transactions id)
  * @param EE_Payment_Method $payment_method       (or a slug or id of one)
  * @param boolean           $update_txn           whether or not to call
  *                                                EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
  * @param bool              $separate_IPN_request whether the IPN uses a separate request ( true like PayPal )
  *                                                or is processed manually ( false like Mijireh )
  * @throws EE_Error
  * @throws Exception
  * @return EE_Payment
  */
 public function process_ipn($_req_data, $transaction = null, $payment_method = null, $update_txn = true, $separate_IPN_request = true)
 {
     EE_Registry::instance()->load_model('Change_Log');
     $_req_data = $this->_remove_unusable_characters_from_array((array) $_req_data);
     EE_Processor_Base::set_IPN($separate_IPN_request);
     $obj_for_log = null;
     if ($transaction instanceof EE_Transaction) {
         $obj_for_log = $transaction;
         if ($payment_method instanceof EE_Payment_Method) {
             $obj_for_log = EEM_Payment::instance()->get_one(array(array('TXN_ID' => $transaction->ID(), 'PMD_ID' => $payment_method->ID()), 'order_by' => array('PAY_timestamp' => 'desc')));
         }
     } else {
         if ($payment_method instanceof EE_Payment) {
             $obj_for_log = $payment_method;
         }
     }
     $log = EEM_Change_Log::instance()->log(EEM_Change_Log::type_gateway, array('IPN data received' => $_req_data), $obj_for_log);
     try {
         /**
          * @var EE_Payment $payment
          */
         $payment = NULL;
         if ($transaction && $payment_method) {
             /** @type EE_Transaction $transaction */
             $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
             /** @type EE_Payment_Method $payment_method */
             $payment_method = EEM_Payment_Method::instance()->ensure_is_obj($payment_method);
             if ($payment_method->type_obj() instanceof EE_PMT_Base) {
                 $payment = $payment_method->type_obj()->handle_ipn($_req_data, $transaction);
                 $log->set_object($payment);
             } else {
                 // not a payment
                 EE_Error::add_error(sprintf(__('A valid payment method could not be determined due to a technical issue.%sPlease refresh your browser and try again or contact %s for assistance.', 'event_espresso'), '<br/>', EE_Registry::instance()->CFG->organization->get_pretty('email')), __FILE__, __FUNCTION__, __LINE__);
             }
         } else {
             //that's actually pretty ok. The IPN just wasn't able
             //to identify which transaction or payment method this was for
             // give all active payment methods a chance to claim it
             $active_payment_methods = EEM_Payment_Method::instance()->get_all_active();
             foreach ($active_payment_methods as $active_payment_method) {
                 try {
                     $payment = $active_payment_method->type_obj()->handle_unclaimed_ipn($_req_data);
                     $payment_method = $active_payment_method;
                     EEM_Change_Log::instance()->log(EEM_Change_Log::type_gateway, array('IPN data' => $_req_data), $payment);
                     break;
                 } catch (EE_Error $e) {
                     //that's fine- it apparently couldn't handle the IPN
                 }
             }
         }
         // 			EEM_Payment_Log::instance()->log("got to 7",$transaction,$payment_method);
         if ($payment instanceof EE_Payment) {
             $payment->save();
             //  update the TXN
             $this->update_txn_based_on_payment($transaction, $payment, $update_txn, $separate_IPN_request);
         } else {
             //we couldn't find the payment for this IPN... let's try and log at least SOMETHING
             if ($payment_method) {
                 EEM_Change_Log::instance()->log(EEM_Change_Log::type_gateway, array('IPN data' => $_req_data), $payment_method);
             } elseif ($transaction) {
                 EEM_Change_Log::instance()->log(EEM_Change_Log::type_gateway, array('IPN data' => $_req_data), $transaction);
             }
         }
         return $payment;
     } catch (EE_Error $e) {
         do_action('AHEE__log', __FILE__, __FUNCTION__, sprintf(__('Error occurred while receiving IPN. Transaction: %1$s, req data: %2$s. The error was "%3$s"', 'event_espresso'), print_r($transaction, TRUE), print_r($_req_data, TRUE), $e->getMessage()));
         throw $e;
     }
 }
 /**
  * This handles connecting a transaction to related items when the chained flag is true.
  *
  * @since 4.3.0
  *
  * @param EE_Transaction $transaction
  * @param array $args incoming arguments from caller for specifying overrides.
  *
  * @return EE_Transaction
  */
 private function _maybe_chained(EE_Transaction $transaction, $args)
 {
     if ($this->_chained) {
         if (empty($this->_status)) {
             $this->_set_repeated_relation($args, $transaction->ID());
         }
         //YES we DO want to set brand new relation objects because multiple transactions do not share the same related objects (for the purpose of tests at least)
         $this->_set_new_relations($args, $transaction->ID());
         //note relation to registration should already be set via the factory->registration_chained->create() method.
         //add relation to status
         $transaction->_add_relation_to($this->_status, 'Status');
         $transaction->save();
         return $transaction;
     }
     return $transaction;
 }
 /**
  * Handle IPN for transaction
  */
 public function handle_ipn_for_transaction(EE_Transaction $transaction)
 {
     global $pronamic_payment, $pronamic_url;
     // Transaction ID
     $transaction_id = $transaction->ID();
     // Payment
     $payment = $this->_PAY->get_payment_by_txn_id_chq_nmbr($transaction_id);
     if (empty($payment)) {
         $payment = EE_Payment::new_instance(array('TXN_ID' => $transaction_id, 'STS_ID' => EEM_Payment::status_id_approved, 'PAY_timestamp' => $transaction->datetime(), 'PAY_amount' => $pronamic_payment->amount, 'PAY_gateway' => __('iDEAL', 'pronamic_ideal'), 'PAY_txn_id_chq_nmbr' => $transaction_id));
     } else {
         $payment->set_status(EEM_Payment::status_id_approved);
     }
     // Save
     $payment->save();
     // URL
     $registration = $transaction->primary_registration();
     $pronamic_url = $this->_get_return_url($registration);
     // Return update
     return $this->update_transaction_with_payment($transaction, $payment);
 }
 /**
  * Handles a paypal IPN, verifies we haven't already processed this IPN, creates a payment (regardless of success or not)
  * and updates the provided transaction, and saves to DB
  * @param EE_Transaction or ID $transaction
  * @return boolean
  */
 public function handle_ipn_for_transaction(EE_Transaction $transaction)
 {
     $this->_debug_log("<hr><br>" . get_class($this) . ":start handle_ipn_for_transaction on transaction:" . $transaction instanceof EE_Transaction ? $transaction->ID() : 'unknown');
     //verify there's payment data that's been sent
     if (empty($_POST['payment_status']) || empty($_POST['txn_id'])) {
         return false;
     }
     $this->_debug_log("<hr><br>" . get_class($this) . ": payment_status and txn_id sent properly. payment_status:" . $_POST['payment_status'] . ", txn_id:" . $_POST['txn_id']);
     //ok, then validate the IPN. Even if we've already processed this payment, let paypal know we don't want to hear from them anymore!
     if (!$this->validateIpn()) {
         //huh, something's wack... the IPN didn't validate. We must have replied to the IPN incorrectly,
         //or their API must ahve changed: http://www.paypalobjects.com/en_US/ebook/PP_OrderManagement_IntegrationGuide/ipn.html
         EE_Error::add_error(__("PayPal IPN Validation failed!", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
         return false;
     }
     //if the transaction's just an ID, swap it for a real EE_Transaction
     $transaction = $this->_TXN->ensure_is_obj($transaction);
     //verify the transaction exists
     if (empty($transaction)) {
         return false;
     }
     //ok, well let's process this payment then!
     if ($_POST['payment_status'] == 'Completed') {
         //the old code considered 'Pending' as completed too..
         $status = EEM_Payment::status_id_approved;
         //approved
         $gateway_response = __('Your payment is approved.', 'event_espresso');
     } elseif ($_POST['payment_status'] == 'Pending') {
         $status = EEM_Payment::status_id_pending;
         //approved
         $gateway_response = __('Your payment is in progress. Another message will be sent when payment is approved.', 'event_espresso');
     } else {
         $status = EEM_Payment::status_id_declined;
         //declined
         $gateway_response = __('Your payment has been declined.', 'event_espresso');
     }
     $this->_debug_log("<hr>Payment is interpreted as {$status}, and the gateway's response set to '{$gateway_response}'");
     //check if we've already processed this payment
     $payment = $this->_PAY->get_payment_by_txn_id_chq_nmbr($_POST['txn_id']);
     if (!empty($payment)) {
         //payment exists. if this has the exact same status and amount, don't bother updating. just return
         if ($payment->STS_ID() == $status && $payment->amount() == $_POST['mc_gross']) {
             //echo "duplicated ipn! dont bother updating transaction foo!";
             $this->_debug_log("<hr>Duplicated IPN! ignore it...");
             return false;
         } else {
             $this->_debug_log("<hr>Existing IPN for this paypal transaction, but it\\'s got some new info. Old status:" . $payment->STS_ID() . ", old amount:" . $payment->amount());
             $payment->set_status($status);
             $payment->set_amount($_POST['mc_gross']);
             $payment->set_gateway_response($gateway_response);
             $payment->set_details($_POST);
         }
     } else {
         $this->_debug_log("<hr>No Previous IPN payment received. Create a new one");
         //no previous payment exists, create one
         $primary_registrant = $transaction->primary_registration();
         $primary_registration_code = !empty($primary_registrant) ? $primary_registrant->reg_code() : '';
         $payment = EE_Payment::new_instance(array('TXN_ID' => $transaction->ID(), 'STS_ID' => $status, 'PAY_timestamp' => current_time('mysql', FALSE), 'PAY_method' => sanitize_text_field($_POST['txn_type']), 'PAY_amount' => floatval($_REQUEST['mc_gross']), 'PAY_gateway' => $this->_gateway_name, 'PAY_gateway_response' => $gateway_response, 'PAY_txn_id_chq_nmbr' => $_POST['txn_id'], 'PAY_po_number' => NULL, 'PAY_extra_accntng' => $primary_registration_code, 'PAY_via_admin' => false, 'PAY_details' => $_POST));
     }
     $payment->save();
     return $this->update_transaction_with_payment($transaction, $payment);
 }
 /**
  * @param \EE_Transaction $transaction
  * @param \EE_Ticket $ticket
  * @param \EE_Event $event
  * @param float $REG_final_price
  * @return \EE_Registration
  * @throws \EE_Error
  */
 public function get_registration_mock(EE_Transaction $transaction, EE_Ticket $ticket, EE_Event $event, $REG_final_price = 10.0)
 {
     return $this->new_model_obj_with_dependencies('Registration', array('TXN_ID' => $transaction->ID(), 'TKT_ID' => $ticket->ID(), 'EVT_ID' => $event->ID(), 'REG_final_price' => $REG_final_price, 'REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT));
 }
 /**
  * Send a request to Payflow.
  *
  * @param array $payment_request_args
  * @param EE_Transaction $transaction
  * @return void
  */
 private function _request_to_payflow($payment_request_args, $transaction)
 {
     $request_url = $this->_debug_mode ? 'https://pilot-payflowpro.paypal.com' : 'https://payflowpro.paypal.com';
     $partner = $this->_partner == NULL ? 'PayPal' : $this->_partner;
     $headers = array();
     // Max 32 chars.
     $unique_id = substr($transaction->ID() . '_' . wp_generate_password(22, false), 0, 32);
     $headers[] = "Content-Type: text/namevalue";
     // Set the server timeout value to 45, but notice below in the cURL section, the timeout
     // for cURL is set to 90 seconds.  Make sure the server timeout is less than the connection.
     $headers[] = "X-VPS-CLIENT-TIMEOUT: 45";
     $headers[] = "X-VPS-REQUEST-ID:" . $unique_id;
     // Merchant info.
     $nvp_request = 'USER='******'&VENDOR=' . $this->_vendor . '&PARTNER=' . $partner . '&PWD=' . $this->_password . '&BUTTONSOURCE=EventEspresso_SP';
     foreach ($payment_request_args as $ref => $value) {
         $nvp_request .= '&' . $ref . '=' . $value;
     }
     $request_response = wp_remote_post($request_url, array('method' => 'POST', 'timeout' => 60, 'redirection' => 5, 'blocking' => true, 'headers' => $headers, 'body' => $nvp_request, 'cookies' => array(), 'httpversion' => '1.1'));
     return $this->_decode_response($request_response['body']);
 }