require File.join(File.dirname(__FILE__), '../test_helper.rb') class CreditNoteTest < Test::Unit::TestCase # Tests that a credit note can be converted into XML that Xero can understand, and then converted back to a credit note def test_build_and_parse_xml credit_note = create_test_credit_note # Generate the XML message credit_note_as_xml = credit_note.to_xml # Parse the XML message and retrieve the credit_note element credit_note_element = REXML::XPath.first(REXML::Document.new(credit_note_as_xml), "/CreditNote") # Build a new credit_note from the XML result_credit_note = XeroGateway::CreditNote.from_xml(credit_note_element) assert_equal(credit_note, result_credit_note) end # Tests the sub_total calculation and that setting it manually doesn't modify the data. def test_credit_note_sub_total_calculation credit_note = create_test_credit_note line_item = credit_note.line_items.first # Make sure that everything adds up to begin with. expected_sub_total = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, l | l.line_amount } assert_equal(expected_sub_total, credit_note.sub_total) # Change the amount of the first line item and make sure that # everything still continues to add up. line_item.unit_amount = line_item.unit_amount + 10 assert_not_equal(expected_sub_total, credit_note.sub_total) expected_sub_total = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, l | l.line_amount } assert_equal(expected_sub_total, credit_note.sub_total) end # Tests the total_tax calculation and that setting it manually doesn't modify the data. def test_credit_note_sub_total_calculation2 credit_note = create_test_credit_note line_item = credit_note.line_items.first # Make sure that everything adds up to begin with. expected_total_tax = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, l | l.tax_amount } assert_equal(expected_total_tax, credit_note.total_tax) # Change the tax_amount of the first line item and make sure that # everything still continues to add up. line_item.tax_amount = line_item.tax_amount + 10 assert_not_equal(expected_total_tax, credit_note.total_tax) expected_total_tax = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, l | l.tax_amount } assert_equal(expected_total_tax, credit_note.total_tax) end # Tests the total calculation and that setting it manually doesn't modify the data. def test_credit_note_sub_total_calculation3 credit_note = create_test_credit_note line_item = credit_note.line_items.first # Make sure that everything adds up to begin with. expected_total = credit_note.sub_total + credit_note.total_tax assert_equal(expected_total, credit_note.total) # Change the quantity of the first line item and make sure that # everything still continues to add up. line_item.quantity = line_item.quantity + 5 assert_not_equal(expected_total, credit_note.total) expected_total = credit_note.sub_total + credit_note.total_tax assert_equal(expected_total, credit_note.total) end # Tests that the LineItem#line_amount calculation is working correctly. def test_line_amount_calculation credit_note = create_test_credit_note line_item = credit_note.line_items.first # Make sure that everything adds up to begin with. expected_amount = line_item.quantity * line_item.unit_amount assert_equal(expected_amount, line_item.line_amount) # Change the line_amount and check that it doesn't modify anything. line_item.line_amount = expected_amount * 10 assert_equal(expected_amount, line_item.line_amount) # Change the quantity and check that the line_amount has been updated. quantity = line_item.quantity + 2 line_item.quantity = quantity assert_not_equal(expected_amount, line_item.line_amount) assert_equal(quantity * line_item.unit_amount, line_item.line_amount) end # Ensure that the totalling methods don't raise exceptions, even when # credit_note.line_items is empty. def test_totalling_methods_when_line_items_empty credit_note = create_test_credit_note credit_note.line_items = [] assert_nothing_raised(Exception) { assert_equal(BigDecimal.new('0'), credit_note.sub_total) assert_equal(BigDecimal.new('0'), credit_note.total_tax) assert_equal(BigDecimal.new('0'), credit_note.total) } end def test_type_helper_methods # Test accounts receivable credit_notes. credit_note = create_test_credit_note({:type => 'ACCRECCREDIT'}) assert_equal(true, credit_note.accounts_receivable?, "Accounts RECEIVABLE credit_note doesn't think it is.") assert_equal(false, credit_note.accounts_payable?, "Accounts RECEIVABLE credit_note thinks it's payable.") # Test accounts payable credit_notes. credit_note = create_test_credit_note({:type => 'ACCPAYCREDIT'}) assert_equal(false, credit_note.accounts_receivable?, "Accounts PAYABLE credit_note doesn't think it is.") assert_equal(true, credit_note.accounts_payable?, "Accounts PAYABLE credit_note thinks it's receivable.") end # Make sure that the create_test_credit_note method is working correctly # with all the defaults and overrides. def test_create_test_credit_note_defaults_working credit_note = create_test_credit_note # Test credit_note defaults. assert_equal('ACCRECCREDIT', credit_note.type) assert_kind_of(Date, credit_note.date) assert_equal('12345', credit_note.credit_note_number) assert_equal('MY REFERENCE FOR THIS CREDIT NOTE', credit_note.reference) assert_equal("Exclusive", credit_note.line_amount_types) # Test the contact defaults. assert_equal('00000000-0000-0000-0000-000000000000', credit_note.contact.contact_id) assert_equal('CONTACT NAME', credit_note.contact.name) # Test address defaults. assert_equal('DEFAULT', credit_note.contact.address.address_type) assert_equal('LINE 1 OF THE ADDRESS', credit_note.contact.address.line_1) # Test phone defaults. assert_equal('DEFAULT', credit_note.contact.phone.phone_type) assert_equal('12345678', credit_note.contact.phone.number) # Test the line_item defaults. assert_equal('A LINE ITEM', credit_note.line_items.first.description) assert_equal('200', credit_note.line_items.first.account_code) assert_equal(BigDecimal.new('100'), credit_note.line_items.first.unit_amount) assert_equal(BigDecimal.new('12.5'), credit_note.line_items.first.tax_amount) # Test overriding an credit_note parameter (assume works for all). credit_note = create_test_credit_note({:type => 'ACCPAYCREDIT'}) assert_equal('ACCPAYCREDIT', credit_note.type) # Test overriding a contact/address/phone parameter (assume works for all). credit_note = create_test_credit_note({}, {:name => 'OVERRIDDEN NAME', :address => {:line_1 => 'OVERRIDDEN LINE 1'}, :phone => {:number => '999'}}) assert_equal('OVERRIDDEN NAME', credit_note.contact.name) assert_equal('OVERRIDDEN LINE 1', credit_note.contact.address.line_1) assert_equal('999', credit_note.contact.phone.number) # Test overriding line_items with hash. credit_note = create_test_credit_note({}, {}, {:description => 'OVERRIDDEN LINE ITEM'}) assert_equal(1, credit_note.line_items.size) assert_equal('OVERRIDDEN LINE ITEM', credit_note.line_items.first.description) assert_equal(BigDecimal.new('100'), credit_note.line_items.first.unit_amount) # Test overriding line_items with array of 2 line_items. credit_note = create_test_credit_note({}, {}, [ {:description => 'OVERRIDDEN ITEM 1'}, {:description => 'OVERRIDDEN ITEM 2', :account_code => '200', :unit_amount => BigDecimal.new('200'), :tax_amount => '25.0'} ]) assert_equal(2, credit_note.line_items.size) assert_equal('OVERRIDDEN ITEM 1', credit_note.line_items[0].description) assert_equal(BigDecimal.new('100'), credit_note.line_items[0].unit_amount) assert_equal('OVERRIDDEN ITEM 2', credit_note.line_items[1].description) assert_equal(BigDecimal.new('200'), credit_note.line_items[1].unit_amount) end def test_auto_creation_of_associated_contact credit_note = create_test_credit_note({}, nil) # no contact assert(!credit_note.instance_variable_defined?("@contact")) new_contact = credit_note.contact assert_kind_of(XeroGateway::Contact, new_contact) end def test_add_line_item credit_note = create_test_credit_note({}, {}, nil) # no line_items assert_equal(0, credit_note.line_items.size) line_item_params = {:description => "Test Item 1", :unit_amount => 100} # Test adding line item by hash line_item = credit_note.add_line_item(line_item_params) assert_kind_of(XeroGateway::LineItem, line_item) assert_equal(line_item_params[:description], line_item.description) assert_equal(line_item_params[:unit_amount], line_item.unit_amount) assert_equal(1, credit_note.line_items.size) # Test adding line item by XeroGateway::LineItem line_item = credit_note.add_line_item(line_item_params) assert_kind_of(XeroGateway::LineItem, line_item) assert_equal(line_item_params[:description], line_item.description) assert_equal(line_item_params[:unit_amount], line_item.unit_amount) assert_equal(2, credit_note.line_items.size) # Test that pushing anything else into add_line_item fails. ["invalid", 100, nil, []].each do | invalid_object | assert_raise(XeroGateway::InvalidLineItemError) { credit_note.add_line_item(invalid_object) } assert_equal(2, credit_note.line_items.size) end end private def create_test_credit_note(credit_note_params = {}, contact_params = {}, line_item_params = []) unless credit_note_params.nil? credit_note_params = { :type => 'ACCRECCREDIT', :date => Date.today, :credit_note_number => '12345', :reference => "MY REFERENCE FOR THIS CREDIT NOTE", :line_amount_types => "Exclusive" }.merge(credit_note_params) end credit_note = XeroGateway::CreditNote.new(credit_note_params || {}) unless contact_params.nil? # Strip out :address key from contact_params to use as the default address. stripped_address = { :address_type => 'DEFAULT', :line_1 => 'LINE 1 OF THE ADDRESS' }.merge(contact_params.delete(:address) || {}) # Strip out :phone key from contact_params to use at the default phone. stripped_phone = { :phone_type => 'DEFAULT', :number => '12345678' }.merge(contact_params.delete(:phone) || {}) contact_params = { :contact_id => '00000000-0000-0000-0000-000000000000', # Just any valid GUID :name => "CONTACT NAME", :first_name => "Bob", :last_name => "Builder" }.merge(contact_params) # Create credit_note.contact from contact_params. credit_note.contact = XeroGateway::Contact.new(contact_params) credit_note.contact.address = XeroGateway::Address.new(stripped_address) credit_note.contact.phone = XeroGateway::Phone.new(stripped_phone) end unless line_item_params.nil? line_item_params = [line_item_params].flatten # always use an array, even if only a single hash passed in # At least one line item, make first have some defaults. line_item_params << {} if line_item_params.size == 0 line_item_params[0] = { :description => "A LINE ITEM", :account_code => "200", :unit_amount => BigDecimal.new("100"), :tax_amount => BigDecimal.new("12.5"), :tracking => XeroGateway::TrackingCategory.new(:name => "blah", :options => "hello") }.merge(line_item_params[0]) # Create credit_note.line_items from line_item_params line_item_params.each do | line_item | credit_note.add_line_item(line_item) end end credit_note end end