xero_gateway 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@ class AccountTest < Test::Unit::TestCase
4
4
  # Tests that an account can be converted into XML that Xero can understand, and then converted back to an account
5
5
  def test_build_and_parse_xml
6
6
  account = create_test_account
7
-
7
+
8
8
  # Generate the XML message
9
9
  account_as_xml = account.to_xml
10
10
 
@@ -13,30 +13,34 @@ class AccountTest < Test::Unit::TestCase
13
13
 
14
14
  # Build a new account from the XML
15
15
  result_account = XeroGateway::Account.from_xml(account_element)
16
-
16
+
17
17
  # Check the account details
18
18
  assert_equal account, result_account
19
19
  end
20
-
20
+
21
21
  def test_build_and_parse_xml_for_bank_accounts
22
- account = create_test_account(:type => 'BANK', :currency_code => 'NZD')
22
+ account = create_test_account(:type => 'BANK', :status => 'ACTIVE', :account_class => 'ASSET', :currency_code => 'NZD')
23
23
  account_as_xml = account.to_xml
24
24
  assert_match 'CurrencyCode', account_as_xml.to_s
25
25
 
26
26
  account_element = REXML::XPath.first(REXML::Document.new(account_as_xml), "/Account")
27
27
  result_account = XeroGateway::Account.from_xml(account_element)
28
28
  assert_equal 'BANK', result_account.type
29
+ assert_equal 'ACTIVE', result_account.status
30
+ assert_equal 'ASSET', result_account.account_class
29
31
  assert_equal 'NZD', result_account.currency_code
30
32
  assert_equal account, result_account
31
33
  end
32
-
34
+
33
35
  private
34
-
36
+
35
37
  def create_test_account(options={})
36
38
  account = XeroGateway::Account.new(:account_id => "57cedda9")
37
39
  account.code = "200"
38
40
  account.name = "Sales"
39
41
  account.type = options[:type] || "REVENUE"
42
+ account.status = options[:status] || "ACTIVE"
43
+ account.account_class = options[:account_class] || "REVENUE"
40
44
  account.tax_type = "OUTPUT"
41
45
  account.description = "Income from any normal business activity"
42
46
  account.enable_payments_to_account = false
@@ -37,6 +37,15 @@ class BankTransactionTest < Test::Unit::TestCase
37
37
  should "allow overriding transaction defaults" do
38
38
  assert_equal 'SPEND', create_test_bank_transaction(:type => 'SPEND').type
39
39
  end
40
+
41
+ should "support another currency" do
42
+ usd_code = "USD"
43
+ usd_rate = 1.402
44
+ bank_transaction = create_test_bank_transaction(:currency_code => usd_code,
45
+ :currency_rate => usd_rate)
46
+ assert_equal usd_code, bank_transaction.currency_code
47
+ assert_equal usd_rate, bank_transaction.currency_rate
48
+ end
40
49
  end
41
50
 
42
51
  context "adding line items" do
@@ -124,9 +133,9 @@ class BankTransactionTest < Test::Unit::TestCase
124
133
  private
125
134
 
126
135
  def assert_xml_field(xml, field_name, options={})
127
- assert_match /#{field_name}/, xml.to_s, "Didn't find the field #{field_name} in the XML document!"
136
+ assert_match(/#{field_name}/, xml.to_s, "Didn't find the field #{field_name} in the XML document!")
128
137
  if options[:value]
129
- assert_match /#{field_name}.*#{options[:value]}.*#{field_name}/, xml.to_s, "The field #{field_name} was expected to be '#{options[:value]}'!"
138
+ assert_match(/#{field_name}.*#{options[:value]}.*#{field_name}/, xml.to_s, "The field #{field_name} was expected to be '#{options[:value]}'!")
130
139
  end
131
140
  end
132
141
 
@@ -32,6 +32,68 @@ class ContactTest < Test::Unit::TestCase
32
32
  assert_equal contact, result_contact
33
33
  end
34
34
 
35
+ # this allows you to remove addresses from Xero
36
+ test "explicity passing an empty array for addresses should include an empty element" do
37
+ contact = create_test_contact
38
+ contact.addresses = nil
39
+
40
+ parsed = REXML::XPath.first(REXML::Document.new(contact.to_xml), "/Contact")
41
+ assert !parsed.children.map(&:name).include?("Addresses")
42
+
43
+ contact.addresses = []
44
+ parsed = REXML::XPath.first(REXML::Document.new(contact.to_xml), "/Contact")
45
+ assert parsed.children.map(&:name).include?("Addresses")
46
+ end
47
+
48
+ test "should be able to set addresses as part of initialize" do
49
+ contact = XeroGateway::Contact.new(contact_id: "abcdef-3abe", name: "Test", addresses: [])
50
+
51
+ parsed = REXML::XPath.first(REXML::Document.new(contact.to_xml), "/Contact")
52
+ assert parsed.children.map(&:name).include?("Addresses")
53
+ end
54
+
55
+ test "parsing from XML" do
56
+ test_xml = <<-TESTING.strip_heredoc.chomp
57
+ <Contact>
58
+ <ContactID>f1d403d1-7d30-46c2-a2be-fc2bb29bd295</ContactID>
59
+ <ContactStatus>ACTIVE</ContactStatus>
60
+ <Name>24 Locks</Name>
61
+ <Addresses>
62
+ <Address>
63
+ <AddressType>POBOX</AddressType>
64
+ </Address>
65
+ <Address>
66
+ <AddressType>STREET</AddressType>
67
+ </Address>
68
+ </Addresses>
69
+ <Phones>
70
+ <Phone>
71
+ <PhoneType>DDI</PhoneType>
72
+ </Phone>
73
+ <Phone>
74
+ <PhoneType>DEFAULT</PhoneType>
75
+ </Phone>
76
+ <Phone>
77
+ <PhoneType>FAX</PhoneType>
78
+ </Phone>
79
+ <Phone>
80
+ <PhoneType>MOBILE</PhoneType>
81
+ </Phone>
82
+ </Phones>
83
+ <UpdatedDateUTC>2016-08-31T04:55:39.217</UpdatedDateUTC>
84
+ <IsSupplier>false</IsSupplier>
85
+ <IsCustomer>false</IsCustomer>
86
+ <HasAttachments>false</HasAttachments>
87
+ </Contact>
88
+ TESTING
89
+
90
+ contact_element = REXML::XPath.first(REXML::Document.new(test_xml.gsub(/\s/, "")), "/Contact")
91
+ contact = XeroGateway::Contact.from_xml(contact_element)
92
+
93
+ assert_equal Time.new(2016, 8, 31, 04, 55, 39), contact.updated_at.utc
94
+
95
+ end
96
+
35
97
  # Test Contact#add_address helper creates a valid XeroGateway::Contact object with the passed in values
36
98
  # and appends it to the Contact#addresses attribute.
37
99
  def test_add_address_helper
@@ -1,11 +1,11 @@
1
1
  require File.join(File.dirname(__FILE__), '../test_helper.rb')
2
2
 
3
3
  class CreditNoteTest < Test::Unit::TestCase
4
-
4
+
5
5
  # Tests that a credit note can be converted into XML that Xero can understand, and then converted back to a credit note
6
6
  def test_build_and_parse_xml
7
7
  credit_note = create_test_credit_note
8
-
8
+
9
9
  # Generate the XML message
10
10
  credit_note_as_xml = credit_note.to_xml
11
11
 
@@ -17,46 +17,38 @@ class CreditNoteTest < Test::Unit::TestCase
17
17
 
18
18
  assert_equal(credit_note, result_credit_note)
19
19
  end
20
-
20
+
21
21
  # Tests the sub_total calculation and that setting it manually doesn't modify the data.
22
22
  def test_credit_note_sub_total_calculation
23
23
  credit_note = create_test_credit_note
24
24
  line_item = credit_note.line_items.first
25
-
25
+
26
26
  # Make sure that everything adds up to begin with.
27
- expected_sub_total = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.line_amount }
28
- assert_equal(expected_sub_total, credit_note.sub_total)
29
-
30
- # Change the sub_total and check that it doesn't modify anything.
31
- credit_note.sub_total = expected_sub_total * 10
27
+ expected_sub_total = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, l | l.line_amount }
32
28
  assert_equal(expected_sub_total, credit_note.sub_total)
33
-
34
- # Change the amount of the first line item and make sure that
29
+
30
+ # Change the amount of the first line item and make sure that
35
31
  # everything still continues to add up.
36
32
  line_item.unit_amount = line_item.unit_amount + 10
37
33
  assert_not_equal(expected_sub_total, credit_note.sub_total)
38
- expected_sub_total = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.line_amount }
34
+ expected_sub_total = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, l | l.line_amount }
39
35
  assert_equal(expected_sub_total, credit_note.sub_total)
40
36
  end
41
-
37
+
42
38
  # Tests the total_tax calculation and that setting it manually doesn't modify the data.
43
39
  def test_credit_note_sub_total_calculation2
44
40
  credit_note = create_test_credit_note
45
41
  line_item = credit_note.line_items.first
46
-
42
+
47
43
  # Make sure that everything adds up to begin with.
48
- expected_total_tax = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.tax_amount }
49
- assert_equal(expected_total_tax, credit_note.total_tax)
50
-
51
- # Change the total_tax and check that it doesn't modify anything.
52
- credit_note.total_tax = expected_total_tax * 10
44
+ expected_total_tax = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, l | l.tax_amount }
53
45
  assert_equal(expected_total_tax, credit_note.total_tax)
54
-
55
- # Change the tax_amount of the first line item and make sure that
46
+
47
+ # Change the tax_amount of the first line item and make sure that
56
48
  # everything still continues to add up.
57
49
  line_item.tax_amount = line_item.tax_amount + 10
58
50
  assert_not_equal(expected_total_tax, credit_note.total_tax)
59
- expected_total_tax = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.tax_amount }
51
+ expected_total_tax = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, l | l.tax_amount }
60
52
  assert_equal(expected_total_tax, credit_note.total_tax)
61
53
  end
62
54
 
@@ -64,16 +56,12 @@ class CreditNoteTest < Test::Unit::TestCase
64
56
  def test_credit_note_sub_total_calculation3
65
57
  credit_note = create_test_credit_note
66
58
  line_item = credit_note.line_items.first
67
-
59
+
68
60
  # Make sure that everything adds up to begin with.
69
61
  expected_total = credit_note.sub_total + credit_note.total_tax
70
62
  assert_equal(expected_total, credit_note.total)
71
-
72
- # Change the total and check that it doesn't modify anything.
73
- credit_note.total = expected_total * 10
74
- assert_equal(expected_total, credit_note.total)
75
-
76
- # Change the quantity of the first line item and make sure that
63
+
64
+ # Change the quantity of the first line item and make sure that
77
65
  # everything still continues to add up.
78
66
  line_item.quantity = line_item.quantity + 5
79
67
  assert_not_equal(expected_total, credit_note.total)
@@ -85,72 +73,72 @@ class CreditNoteTest < Test::Unit::TestCase
85
73
  def test_line_amount_calculation
86
74
  credit_note = create_test_credit_note
87
75
  line_item = credit_note.line_items.first
88
-
76
+
89
77
  # Make sure that everything adds up to begin with.
90
78
  expected_amount = line_item.quantity * line_item.unit_amount
91
79
  assert_equal(expected_amount, line_item.line_amount)
92
-
80
+
93
81
  # Change the line_amount and check that it doesn't modify anything.
94
82
  line_item.line_amount = expected_amount * 10
95
83
  assert_equal(expected_amount, line_item.line_amount)
96
-
84
+
97
85
  # Change the quantity and check that the line_amount has been updated.
98
86
  quantity = line_item.quantity + 2
99
87
  line_item.quantity = quantity
100
88
  assert_not_equal(expected_amount, line_item.line_amount)
101
89
  assert_equal(quantity * line_item.unit_amount, line_item.line_amount)
102
90
  end
103
-
91
+
104
92
  # Ensure that the totalling methods don't raise exceptions, even when
105
93
  # credit_note.line_items is empty.
106
94
  def test_totalling_methods_when_line_items_empty
107
95
  credit_note = create_test_credit_note
108
96
  credit_note.line_items = []
109
-
97
+
110
98
  assert_nothing_raised(Exception) {
111
99
  assert_equal(BigDecimal.new('0'), credit_note.sub_total)
112
100
  assert_equal(BigDecimal.new('0'), credit_note.total_tax)
113
101
  assert_equal(BigDecimal.new('0'), credit_note.total)
114
102
  }
115
103
  end
116
-
104
+
117
105
  def test_type_helper_methods
118
106
  # Test accounts receivable credit_notes.
119
107
  credit_note = create_test_credit_note({:type => 'ACCRECCREDIT'})
120
108
  assert_equal(true, credit_note.accounts_receivable?, "Accounts RECEIVABLE credit_note doesn't think it is.")
121
109
  assert_equal(false, credit_note.accounts_payable?, "Accounts RECEIVABLE credit_note thinks it's payable.")
122
-
110
+
123
111
  # Test accounts payable credit_notes.
124
112
  credit_note = create_test_credit_note({:type => 'ACCPAYCREDIT'})
125
113
  assert_equal(false, credit_note.accounts_receivable?, "Accounts PAYABLE credit_note doesn't think it is.")
126
114
  assert_equal(true, credit_note.accounts_payable?, "Accounts PAYABLE credit_note thinks it's receivable.")
127
115
  end
128
-
129
-
116
+
117
+
130
118
  # Make sure that the create_test_credit_note method is working correctly
131
119
  # with all the defaults and overrides.
132
120
  def test_create_test_credit_note_defaults_working
133
121
  credit_note = create_test_credit_note
134
-
122
+
135
123
  # Test credit_note defaults.
136
124
  assert_equal('ACCRECCREDIT', credit_note.type)
137
125
  assert_kind_of(Date, credit_note.date)
138
126
  assert_equal('12345', credit_note.credit_note_number)
139
127
  assert_equal('MY REFERENCE FOR THIS CREDIT NOTE', credit_note.reference)
140
128
  assert_equal("Exclusive", credit_note.line_amount_types)
141
-
129
+
142
130
  # Test the contact defaults.
143
131
  assert_equal('00000000-0000-0000-0000-000000000000', credit_note.contact.contact_id)
144
132
  assert_equal('CONTACT NAME', credit_note.contact.name)
145
-
133
+
146
134
  # Test address defaults.
147
135
  assert_equal('DEFAULT', credit_note.contact.address.address_type)
148
136
  assert_equal('LINE 1 OF THE ADDRESS', credit_note.contact.address.line_1)
149
-
137
+
150
138
  # Test phone defaults.
151
139
  assert_equal('DEFAULT', credit_note.contact.phone.phone_type)
152
140
  assert_equal('12345678', credit_note.contact.phone.number)
153
-
141
+
154
142
  # Test the line_item defaults.
155
143
  assert_equal('A LINE ITEM', credit_note.line_items.first.description)
156
144
  assert_equal('200', credit_note.line_items.first.account_code)
@@ -160,19 +148,19 @@ class CreditNoteTest < Test::Unit::TestCase
160
148
  # Test overriding an credit_note parameter (assume works for all).
161
149
  credit_note = create_test_credit_note({:type => 'ACCPAYCREDIT'})
162
150
  assert_equal('ACCPAYCREDIT', credit_note.type)
163
-
151
+
164
152
  # Test overriding a contact/address/phone parameter (assume works for all).
165
153
  credit_note = create_test_credit_note({}, {:name => 'OVERRIDDEN NAME', :address => {:line_1 => 'OVERRIDDEN LINE 1'}, :phone => {:number => '999'}})
166
154
  assert_equal('OVERRIDDEN NAME', credit_note.contact.name)
167
155
  assert_equal('OVERRIDDEN LINE 1', credit_note.contact.address.line_1)
168
156
  assert_equal('999', credit_note.contact.phone.number)
169
-
157
+
170
158
  # Test overriding line_items with hash.
171
159
  credit_note = create_test_credit_note({}, {}, {:description => 'OVERRIDDEN LINE ITEM'})
172
160
  assert_equal(1, credit_note.line_items.size)
173
161
  assert_equal('OVERRIDDEN LINE ITEM', credit_note.line_items.first.description)
174
162
  assert_equal(BigDecimal.new('100'), credit_note.line_items.first.unit_amount)
175
-
163
+
176
164
  # Test overriding line_items with array of 2 line_items.
177
165
  credit_note = create_test_credit_note({}, {}, [
178
166
  {:description => 'OVERRIDDEN ITEM 1'},
@@ -184,28 +172,28 @@ class CreditNoteTest < Test::Unit::TestCase
184
172
  assert_equal('OVERRIDDEN ITEM 2', credit_note.line_items[1].description)
185
173
  assert_equal(BigDecimal.new('200'), credit_note.line_items[1].unit_amount)
186
174
  end
187
-
175
+
188
176
  def test_auto_creation_of_associated_contact
189
177
  credit_note = create_test_credit_note({}, nil) # no contact
190
- assert_nil(credit_note.instance_variable_get("@contact"))
191
-
178
+ assert(!credit_note.instance_variable_defined?("@contact"))
179
+
192
180
  new_contact = credit_note.contact
193
181
  assert_kind_of(XeroGateway::Contact, new_contact)
194
182
  end
195
-
183
+
196
184
  def test_add_line_item
197
185
  credit_note = create_test_credit_note({}, {}, nil) # no line_items
198
186
  assert_equal(0, credit_note.line_items.size)
199
-
187
+
200
188
  line_item_params = {:description => "Test Item 1", :unit_amount => 100}
201
-
189
+
202
190
  # Test adding line item by hash
203
191
  line_item = credit_note.add_line_item(line_item_params)
204
192
  assert_kind_of(XeroGateway::LineItem, line_item)
205
193
  assert_equal(line_item_params[:description], line_item.description)
206
194
  assert_equal(line_item_params[:unit_amount], line_item.unit_amount)
207
195
  assert_equal(1, credit_note.line_items.size)
208
-
196
+
209
197
  # Test adding line item by XeroGateway::LineItem
210
198
  line_item = credit_note.add_line_item(line_item_params)
211
199
  assert_kind_of(XeroGateway::LineItem, line_item)
@@ -219,9 +207,9 @@ class CreditNoteTest < Test::Unit::TestCase
219
207
  assert_equal(2, credit_note.line_items.size)
220
208
  end
221
209
  end
222
-
210
+
223
211
  private
224
-
212
+
225
213
  def create_test_credit_note(credit_note_params = {}, contact_params = {}, line_item_params = [])
226
214
  unless credit_note_params.nil?
227
215
  credit_note_params = {
@@ -233,36 +221,36 @@ class CreditNoteTest < Test::Unit::TestCase
233
221
  }.merge(credit_note_params)
234
222
  end
235
223
  credit_note = XeroGateway::CreditNote.new(credit_note_params || {})
236
-
224
+
237
225
  unless contact_params.nil?
238
226
  # Strip out :address key from contact_params to use as the default address.
239
227
  stripped_address = {
240
228
  :address_type => 'DEFAULT',
241
229
  :line_1 => 'LINE 1 OF THE ADDRESS'
242
230
  }.merge(contact_params.delete(:address) || {})
243
-
231
+
244
232
  # Strip out :phone key from contact_params to use at the default phone.
245
233
  stripped_phone = {
246
234
  :phone_type => 'DEFAULT',
247
235
  :number => '12345678'
248
236
  }.merge(contact_params.delete(:phone) || {})
249
-
237
+
250
238
  contact_params = {
251
239
  :contact_id => '00000000-0000-0000-0000-000000000000', # Just any valid GUID
252
240
  :name => "CONTACT NAME",
253
241
  :first_name => "Bob",
254
242
  :last_name => "Builder"
255
243
  }.merge(contact_params)
256
-
244
+
257
245
  # Create credit_note.contact from contact_params.
258
246
  credit_note.contact = XeroGateway::Contact.new(contact_params)
259
247
  credit_note.contact.address = XeroGateway::Address.new(stripped_address)
260
248
  credit_note.contact.phone = XeroGateway::Phone.new(stripped_phone)
261
249
  end
262
-
250
+
263
251
  unless line_item_params.nil?
264
252
  line_item_params = [line_item_params].flatten # always use an array, even if only a single hash passed in
265
-
253
+
266
254
  # At least one line item, make first have some defaults.
267
255
  line_item_params << {} if line_item_params.size == 0
268
256
  line_item_params[0] = {
@@ -272,13 +260,13 @@ class CreditNoteTest < Test::Unit::TestCase
272
260
  :tax_amount => BigDecimal.new("12.5"),
273
261
  :tracking => XeroGateway::TrackingCategory.new(:name => "blah", :options => "hello")
274
262
  }.merge(line_item_params[0])
275
-
263
+
276
264
  # Create credit_note.line_items from line_item_params
277
265
  line_item_params.each do | line_item |
278
266
  credit_note.add_line_item(line_item)
279
267
  end
280
268
  end
281
-
269
+
282
270
  credit_note
283
271
  end
284
272
  end
@@ -14,6 +14,19 @@ class GatewayTest < Test::Unit::TestCase
14
14
  assert result.response_item.first.is_a? XeroGateway::Invoice
15
15
  end
16
16
 
17
+ should "get invoices by contact ids" do
18
+ contact_id = 'a99a9aaa-9999-99a9-9aa9-aaaaaa9a9999'
19
+ stub_response = stub(:plain_body => get_file_as_string("invoices.xml"),
20
+ :code => "200")
21
+ expected_url = /.+\/Invoices\?ContactIDs=#{contact_id}/
22
+ XeroGateway::OAuth.any_instance
23
+ .stubs(:get)
24
+ .with(regexp_matches(expected_url), anything)
25
+ .returns(stub_response)
26
+ result = @gateway.get_invoices(:contact_ids => [contact_id])
27
+ assert result.response_item.first.is_a? XeroGateway::Invoice
28
+ end
29
+
17
30
  should :get_invoice do
18
31
  XeroGateway::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("invoice.xml"), :code => "200"))
19
32
  result = @gateway.get_invoice('a99a9aaa-9999-99a9-9aa9-aaaaaa9a9999')
@@ -62,7 +75,6 @@ class GatewayTest < Test::Unit::TestCase
62
75
  assert result.response_item.first.is_a? XeroGateway::Payment
63
76
  end
64
77
 
65
-
66
78
  should :get_contacts do
67
79
  XeroGateway::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("contacts.xml"), :code => "200"))
68
80
  result = @gateway.get_contacts
@@ -84,13 +96,13 @@ class GatewayTest < Test::Unit::TestCase
84
96
  should :get_contact_groups do
85
97
  XeroGateway::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("contact_groups.xml"), :code => "200"))
86
98
  result = @gateway.get_contact_groups
87
- assert result.response_item.first.is_a? XeroGateway::ContactGroup
99
+ assert result.response_item.first.is_a? XeroGateway::ContactGroup
88
100
  end
89
101
 
90
102
  should :get_contact_group_by_id do
91
103
  XeroGateway::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("contact_group.xml"), :code => "200"))
92
104
  result = @gateway.get_contact_group_by_id('a99a9aaa-9999-99a9-9aa9-aaaaaa9a9999')
93
- assert result.response_item.is_a? XeroGateway::ContactGroup
105
+ assert result.response_item.is_a? XeroGateway::ContactGroup
94
106
  end
95
107
 
96
108
  context :get_report do
@@ -255,7 +267,7 @@ class GatewayTest < Test::Unit::TestCase
255
267
  XeroGateway::OAuth.any_instance.stubs(:put).returns(stub(:plain_body => get_file_as_string("no_certificates_registered"), :code => 400))
256
268
 
257
269
  assert_raises RuntimeError do
258
- response = @gateway.create_invoice(XeroGateway::Invoice.new)
270
+ @gateway.create_invoice(XeroGateway::Invoice.new)
259
271
  end
260
272
  end
261
273
  end