/** * test_add_ticket_purchase */ public function test_add_ticket_purchase() { // create grand total $total_line_item = EEH_Line_Item::create_default_total_line_item(); $this->assertEquals(0, $total_line_item->total()); // create a ticket $ticket = $this->new_ticket(array('dollar_surcharge' => 5, 'percent_surcharge' => 10, 'datetimes' => 2)); // need to save ticket for other tests to work $ticket->save(); // two tickets plz $ticket_line_item = EEH_Line_Item::add_ticket_purchase($total_line_item, $ticket, 2); // confirm totals $this->assertEquals(2, $ticket_line_item->quantity()); $this->assertEquals(33, $ticket_line_item->total()); $this->assertEquals(4.95, EEH_Line_Item::get_taxes_subtotal($total_line_item)->total()); $this->assertEquals(33, EEH_Line_Item::get_items_subtotal($total_line_item)->total()); $this->assertEquals(37.95, $total_line_item->total()); $this->assertNotEquals(0, $total_line_item->total()); // one moar ticket plz $ticket_line_item = EEH_Line_Item::add_ticket_purchase($total_line_item, $ticket); // confirm totals $this->assertEquals(3, $ticket_line_item->quantity()); $this->assertEquals(49.5, $ticket_line_item->total()); $this->assertEquals(7.43, EEH_Line_Item::get_taxes_subtotal($total_line_item)->total()); $this->assertEquals(49.5, EEH_Line_Item::get_items_subtotal($total_line_item)->total()); $this->assertEquals(56.93, $total_line_item->total()); $this->assertNotEquals(0, $total_line_item->total()); // total ticket line items count? should just be one ticket line item $this->assertEquals(1, count($total_line_item->get_child_line_item('tickets')->children())); // now add a different ticket $new_ticket = $this->new_ticket(array('ticket_price' => 10, 'ticket_taxable' => false, 'datetimes' => 1)); $new_ticket->save(); // add one $new_ticket_line_item = EEH_Line_Item::add_ticket_purchase($total_line_item, $new_ticket); $this->assertEquals(1, $new_ticket_line_item->quantity()); // add one moar $new_ticket_line_item = EEH_Line_Item::add_ticket_purchase($total_line_item, $new_ticket); $this->assertEquals(2, $new_ticket_line_item->quantity()); // confirm totals $this->assertEquals(20, $new_ticket_line_item->total()); // should be same taxes as before $this->assertEquals(7.43, EEH_Line_Item::get_taxes_subtotal($total_line_item)->total()); $this->assertEquals(69.5, EEH_Line_Item::get_items_subtotal($total_line_item)->total()); $this->assertEquals(76.93000000000001, $total_line_item->total()); $this->assertNotEquals(0, $total_line_item->total()); // total ticket ticket line items? $this->assertEquals(2, count($total_line_item->get_child_line_item('tickets')->children())); }
/** * @group 8964 * Uses a particular number and quantity that has been shown to cause rounding problems * prior to the work on 8964 (specifically, if you had 2 transactions for 1 ticket purchase each * the total for both transactions was NOT the same as 1 transaction for 2 ticket purchases) */ function test_recalculate_pre_tax_total__rounding_issues() { EE_Registry::instance()->load_helper('Line_Item'); $flat_base_price_type_id = EEM_Price_Type::instance()->get_var(array(array('PRT_name' => 'Base Price'))); $percent_surcharge_price_type_id = EEM_Price_Type::instance()->get_var(array(array('PRT_name' => 'Percent Surcharge'))); $base_price = $this->new_model_obj_with_dependencies('Price', array('PRT_ID' => $flat_base_price_type_id, 'PRC_amount' => 21.67)); $percent_surcharge = $this->new_model_obj_with_dependencies('Price', array('PRT_ID' => $percent_surcharge_price_type_id, 'PRC_amount' => 20)); $ticket = $this->new_model_obj_with_dependencies('Ticket', array('TKT_price' => $base_price->amount() + $base_price->amount() * $percent_surcharge->amount() / 100, 'TKT_taxable' => false)); $ticket->_add_relation_to($base_price, 'Price'); $ticket->_add_relation_to($percent_surcharge, 'Price'); $event = $this->new_model_obj_with_dependencies('Event'); $datetime = $this->new_model_obj_with_dependencies('Datetime'); $ticket->_add_relation_to($datetime, 'Datetime'); $quantity = 2; $total_line_item = EEH_Line_Item::add_ticket_purchase(EEH_Line_Item::create_total_line_item(), $ticket, $quantity); $this->assertEquals($ticket->price() * $quantity, $total_line_item->total()); }
/** * Makes a complete transaction record with all associated data (ie, its line items, * registrations, tickets, datetimes, events, attendees, questions, answers, etc). * * @param array $options { * @type int $ticket_types the number of different ticket types in this transaction. Default 1 * @type int $taxable_tickets how many of those ticket types should be taxable. Default EE_INF * @return EE_Transaction */ protected function new_typical_transaction($options = array()) { EE_Registry::instance()->load_helper('Line_Item'); $txn = $this->new_model_obj_with_dependencies('Transaction'); $total_line_item = EEH_Line_Item::create_total_line_item($txn->ID()); $total_line_item->save_this_and_descendants_to_txn($txn->ID()); if (isset($options['ticket_types'])) { $ticket_types = $options['ticket_types']; } else { $ticket_types = 1; } if (isset($options['taxable_tickets'])) { $taxable_tickets = $options['taxable_tickets']; } else { $taxable_tickets = EE_INF; } if (isset($options['fixed_ticket_price_modifiers'])) { $fixed_ticket_price_modifiers = $options['fixed_ticket_price_modifiers']; } else { $fixed_ticket_price_modifiers = 1; } $taxes = EEM_Price::instance()->get_all_prices_that_are_taxes(); for ($i = 1; $i <= $ticket_types; $i++) { $ticket = $this->new_model_obj_with_dependencies('Ticket', array('TKT_price' => $i * 10, 'TKT_taxable' => $taxable_tickets-- > 0 ? true : false)); $sum_of_sub_prices = 0; for ($j = 1; $j <= $fixed_ticket_price_modifiers; $j++) { if ($j == $fixed_ticket_price_modifiers) { $price_amount = $ticket->price() - $sum_of_sub_prices; } else { $price_amount = $i * 10 / $fixed_ticket_price_modifiers; } $price = $this->new_model_obj_with_dependencies('Price', array('PRC_amount' => $price_amount, 'PRC_order' => $j)); $sum_of_sub_prices += $price->amount(); $ticket->_add_relation_to($price, 'Price'); } $a_datetime = $this->new_model_obj_with_dependencies('Datetime'); $ticket->_add_relation_to($a_datetime, 'Datetime'); $this->assertInstanceOf('EE_Line_Item', EEH_Line_Item::add_ticket_purchase($total_line_item, $ticket)); $reg_final_price = $ticket->price(); foreach ($taxes as $taxes_at_priority) { foreach ($taxes_at_priority as $tax) { $reg_final_price += $reg_final_price * $tax->amount() / 100; } } $this->new_model_obj_with_dependencies('Registration', array('TXN_ID' => $txn->ID(), 'TKT_ID' => $ticket->ID(), 'STS_ID' => EEM_Registration::status_id_approved, 'EVT_ID' => $a_datetime->get('EVT_ID'), 'REG_count' => 1, 'REG_group_size' => 1, 'REG_final_price' => $reg_final_price)); } $txn->set_total($total_line_item->total()); $txn->save(); return $txn; }
protected function _setup_data() { //need to figure out the running total for test purposes so... we're going to create a temp cart and add the tickets to it! EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__); $cart = EE_Cart::reset(); //add tickets to cart foreach ($this->tickets as $ticket) { $cart->add_ticket_to_cart($ticket['ticket']); } //setup txn property $this->txn = EE_Transaction::new_instance(array('TXN_timestamp' => time(), 'TXN_total' => 0, 'TXN_paid' => 0, 'STS_ID' => EEM_Transaction::incomplete_status_code, 'TXN_session_data' => NULL, 'TXN_hash_salt' => NULL, 'TXN_ID' => 999999)); //setup reg_objects //note we're setting up a reg object for each attendee in each event but ALSO adding to the reg_object array. $this->reg_objs = array(); $regid = 9999990; foreach ($this->_attendees as $key => $attendee) { //note we need to setup reg_objects for each event this attendee belongs to $regatt = $attendee['att_obj']->ID(); $regtxn = $this->txn->ID(); $regcnt = 1; foreach ($attendee['line_ref'] as $evtid) { foreach ($this->_events[$evtid]['tkt_objs'] as $ticket) { $reg_array = array('EVT_ID' => $evtid, 'ATT_ID' => $regatt, 'TXN_ID' => $regtxn, 'TKT_ID' => $ticket->ID(), 'STS_ID' => EEM_Registration::status_id_pending_payment, 'REG_date' => time(), 'REG_final_price' => $ticket->get('TKT_price'), 'REG_session' => 'dummy_session_id', 'REG_code' => $regid . '-dummy-generated-code', 'REG_url_link' => $regcnt . '-daafpapasdlfakasdfpqasdfasdf', 'REG_count' => $regcnt, 'REG_group_size' => $this->_events[$evtid]['total_attendees'], 'REG_att_is_going' => TRUE, 'REG_ID' => $regid); $REG_OBJ = EE_Registration::new_instance($reg_array); $this->_attendees[$key]['reg_objs'][$regid] = $REG_OBJ; $this->_events[$evtid]['reg_objs'][] = $REG_OBJ; $this->reg_objs[] = $REG_OBJ; $this->tickets[$ticket->ID()]['reg_objs'][$regid] = $REG_OBJ; $regcnt++; $regid++; } } } //setup line items! EE_Registry::instance()->load_helper('Line_Item'); $line_item_total = EEH_Line_Item::create_total_line_item($this->txn); //add tickets foreach ($this->tickets as $tktid => $item) { $qty = $item['count']; $ticket = $item['ticket']; EEH_Line_Item::add_ticket_purchase($line_item_total, $ticket, $qty); } $shipping_line_item = EE_Line_Item::new_instance(array('LIN_name' => __('Shipping Surcharge', 'event_espresso'), 'LIN_desc' => __('Sent via Millenium Falcon', 'event_espresso'), 'LIN_unit_price' => 20, 'LIN_quantity' => 1, 'LIN_is_taxable' => TRUE, 'LIN_total' => 20, 'LIN_type' => EEM_Line_Item::type_line_item)); EEH_Line_Item::add_item($line_item_total, $shipping_line_item); $this->additional_line_items = array($shipping_line_item); //now let's add taxes EEH_Line_Item::apply_taxes($line_item_total); //now we should be able to get the items we need from this object $event_line_items = EEH_Line_Item::get_pre_tax_subtotal($line_item_total)->children(); $line_items = array(); foreach ($event_line_items as $line_id => $line_item) { if (!$line_item instanceof EE_Line_Item || $line_item->OBJ_type() !== 'Event') { continue; } $ticket_line_items = EEH_Line_Item::get_ticket_line_items($line_item); foreach ($ticket_line_items as $ticket_line_id => $ticket_line_item) { if (!$ticket_line_item instanceof EE_Line_Item) { continue; } $this->tickets[$ticket_line_item->OBJ_ID()]['line_item'] = $ticket_line_item; $this->tickets[$ticket_line_item->OBJ_ID()]['sub_line_items'] = $ticket_line_item->children(); $line_items[$ticket_line_item->ID()]['children'] = $ticket_line_item->children(); $line_items[$ticket_line_item->ID()]['EE_Ticket'] = $this->tickets[$ticket_line_item->OBJ_ID()]['ticket']; } } $this->line_items_with_children = $line_items; $this->tax_line_items = $line_item_total->tax_descendants(); //add proper total to transaction object. $grand_total = $line_item_total->recalculate_total_including_taxes(); $this->grand_total_line_item = $line_item_total; $this->txn->set_total($grand_total); //add additional details for each registration foreach ($this->reg_objs as $reg) { $this->_registrations[$reg->ID()]['tkt_obj'] = $this->tickets[$reg->get('TKT_ID')]['ticket']; $this->_registrations[$reg->ID()]['evt_obj'] = $this->_events[$reg->get('EVT_ID')]['event']; $this->_registrations[$reg->ID()]['reg_obj'] = $reg; $this->_registrations[$reg->ID()]['ans_objs'] = $this->_attendees[$reg->get('ATT_ID')]['ans_objs']; $this->_registrations[$reg->ID()]['att_obj'] = $this->_attendees[$reg->get('ATT_ID')]['att_obj']; $this->_registrations[$reg->ID()]['dtt_objs'] = $this->tickets[$reg->get('TKT_ID')]['dtt_objs']; } //events and attendees $this->events = $this->_events; $this->attendees = $this->_attendees; $this->registrations = $this->_registrations; $attendees_to_shift = $this->_attendees; //setup primary attendee property $this->primary_attendee_data = array('fname' => $this->_attendees[999999991]['att_obj']->fname(), 'lname' => $this->_attendees[999999991]['att_obj']->lname(), 'email' => $this->_attendees[999999991]['att_obj']->email(), 'att_obj' => $this->_attendees[999999991]['att_obj'], 'reg_obj' => array_shift($attendees_to_shift[999999991]['reg_objs'])); //reg_info property //note this isn't referenced by any shortcode parsers so we'll ignore for now. $this->reg_info = array(); //let's set a reg_obj for messengers expecting one. $this->reg_obj = array_pop($this->_attendees[999999991]['reg_objs']); //the below are just dummy items. $this->user_id = 1; $this->ip_address = '192.0.2.1'; $this->user_agent = ''; $this->init_access = time(); $this->last_access = time(); }
/** * @process items for adding to cart * @access public * @param EE_Ticket $ticket * @param int $qty * @return TRUE on success, FALSE on fail */ public function add_ticket_to_cart(EE_Ticket $ticket, $qty = 1) { EEH_Line_Item::add_ticket_purchase($this->_grand_total, $ticket, $qty); return $this->save_cart() ? TRUE : FALSE; }
/** * Makes a complete transaction record with all associated data (ie, its line items, * registrations, tickets, datetimes, events, attendees, questions, answers, etc). * * @param array $options { * @type int $ticket_types the number of different ticket types in this transaction. Deafult 1 * @type int $taxable_tickets how many of those ticket types should be taxable. Default INF * @return EE_Transaction */ protected function new_typical_transaction($options = array()) { EE_Registry::instance()->load_helper('Line_Item'); $txn = $this->new_model_obj_with_dependencies('Transaction'); $total_line_item = EEH_Line_Item::create_default_total_line_item($txn->ID()); $total_line_item->save_this_and_descendants_to_txn($txn->ID()); if (isset($options['ticket_types'])) { $ticket_types = $options['ticket_types']; } else { $ticket_types = 1; } if (isset($options['taxable_tickets'])) { $taxable_tickets = $options['taxable_tickets']; } else { $taxable_tickets = INF; } $taxes = EEM_Price::instance()->get_all_prices_that_are_taxes(); for ($i = 1; $i <= $ticket_types; $i++) { $ticket = $this->new_model_obj_with_dependencies('Ticket', array('TKT_price' => $i * 10, 'TKT_taxable' => $taxable_tickets--)); $this->assertInstanceOf('EE_Line_Item', EEH_Line_Item::add_ticket_purchase($total_line_item, $ticket)); $reg_final_price = $ticket->price(); foreach ($taxes as $taxes_at_priority) { foreach ($taxes_at_priority as $tax) { $reg_final_price += $reg_final_price * $tax->amount() / 100; } } $this->new_model_obj_with_dependencies('Registration', array('TXN_ID' => $txn->ID(), 'TKT_ID' => $ticket->ID(), 'REG_count' => 1, 'REG_group_size' => 1, 'REG_final_price' => $reg_final_price)); } $txn->set_total($total_line_item->total()); $txn->save(); return $txn; }
/** * @group 8193 */ public function test_calculate_reg_final_prices_per_line_item__3_taxable_tickets_with_a_discount() { $transaction = $this->new_typical_transaction(array('ticket_types' => 2)); //add another ticket purchase for one of the same events $event1 = EEM_Event::instance()->get_one(array(array('Registration.TXN_ID' => $transaction->ID()))); $dtt = $event1->get_first_related('Datetime'); $new_tkt = $this->new_model_obj_with_dependencies('Ticket', array('TKT_price' => 6)); $new_tkt->_add_relation_to($dtt, 'Datetime'); $quantity_of_new_tks_purchased = 2; EEH_Line_Item::add_ticket_purchase($transaction->total_line_item(), $new_tkt, $quantity_of_new_tks_purchased); for ($i = 0; $i < 2; $i++) { $this->new_model_obj_with_dependencies('Registration', array('TXN_ID' => $transaction->ID(), 'EVT_ID' => $dtt->get('EVT_ID'), 'TKT_ID' => $new_tkt->ID())); } //and add an unrelated purchase EEH_Line_Item::add_unrelated_item($transaction->total_line_item(), 'Transaction-Wide Discount', -5); $totals = EEH_Line_Item::calculate_reg_final_prices_per_line_item($transaction->total_line_item()); // honestly the easiest way to confirm the total was right is to visualize the tree // var_dump( $totals ); // EEH_Line_Item::visualize( $transaction->total_line_item() ); //verify that if we added the REG_final_prices onto the regs as derived from $totals, //that it would equal the grand total $sum_of_regs_final_prices = 0; foreach ($transaction->registrations() as $reg) { $ticket_line_item = EEM_Line_Item::instance()->get_line_item_for_registration($reg); $sum_of_regs_final_prices += $totals[$ticket_line_item->ID()]; } $this->assertEquals($totals['total'], $sum_of_regs_final_prices); //ok now let's verify the 'REG_final_price' for each ticket's line item is what we expect it to be //so there should be 3 ticket line items right? $ticket_line_items = EEM_Line_Item::instance()->get_all(array(array('TXN_ID' => $transaction->ID(), 'OBJ_type' => 'Ticket'))); //one ticket should be 10 pre-tax $ten_dollar_ticket = EEM_Line_Item::instance()->get_one(array(array('TXN_ID' => $transaction->ID(), 'LIN_unit_price' => 10, 'LIN_type' => EEM_Line_Item::type_line_item))); $this->assertEquals(10.31, round($totals[$ten_dollar_ticket->ID()], 2)); //one ticket should be 20 pre-tax $twenty_dollar_ticket = EEM_Line_Item::instance()->get_one(array(array('TXN_ID' => $transaction->ID(), 'LIN_unit_price' => 20, 'LIN_type' => EEM_Line_Item::type_line_item))); $this->assertEquals(20.62, round($totals[$twenty_dollar_ticket->ID()], 2)); //one ticket should be for 6 pre-tax (although its non-taxable anyway) $six_dollar_ticket = EEM_Line_Item::instance()->get_one(array(array('TXN_ID' => $transaction->ID(), 'LIN_unit_price' => 6, 'LIN_type' => EEM_Line_Item::type_line_item))); $this->assertEquals(5.29, round($totals[$six_dollar_ticket->ID()], 2)); }