xeroizer-3-pre-beta 3.0.0.pre.beta
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +41 -0
- data/README.md +34 -0
- data/lib/class_level_inheritable_attributes.rb +28 -0
- data/lib/xeroizer.rb +117 -0
- data/lib/xeroizer/application_http_proxy.rb +30 -0
- data/lib/xeroizer/ca-certificates.crt +2694 -0
- data/lib/xeroizer/configuration.rb +19 -0
- data/lib/xeroizer/connection.rb +31 -0
- data/lib/xeroizer/exceptions.rb +161 -0
- data/lib/xeroizer/generic_application.rb +90 -0
- data/lib/xeroizer/http.rb +160 -0
- data/lib/xeroizer/http_encoding_helper.rb +49 -0
- data/lib/xeroizer/http_response.rb +154 -0
- data/lib/xeroizer/logging.rb +8 -0
- data/lib/xeroizer/models/account.rb +72 -0
- data/lib/xeroizer/models/accounts_payable.rb +13 -0
- data/lib/xeroizer/models/accounts_receivable.rb +13 -0
- data/lib/xeroizer/models/address.rb +41 -0
- data/lib/xeroizer/models/allocation.rb +13 -0
- data/lib/xeroizer/models/attachment.rb +95 -0
- data/lib/xeroizer/models/balances.rb +17 -0
- data/lib/xeroizer/models/bank_account.rb +13 -0
- data/lib/xeroizer/models/bank_transaction.rb +95 -0
- data/lib/xeroizer/models/bank_transfer.rb +28 -0
- data/lib/xeroizer/models/batch_payment.rb +24 -0
- data/lib/xeroizer/models/batch_payments.rb +14 -0
- data/lib/xeroizer/models/bills.rb +13 -0
- data/lib/xeroizer/models/branding_theme.rb +62 -0
- data/lib/xeroizer/models/contact.rb +77 -0
- data/lib/xeroizer/models/contact_group.rb +64 -0
- data/lib/xeroizer/models/contact_person.rb +20 -0
- data/lib/xeroizer/models/contact_purchases_tracking_category.rb +19 -0
- data/lib/xeroizer/models/contact_sales_tracking_category.rb +19 -0
- data/lib/xeroizer/models/credit_note.rb +164 -0
- data/lib/xeroizer/models/currency.rb +30 -0
- data/lib/xeroizer/models/employee.rb +73 -0
- data/lib/xeroizer/models/expense_claim.rb +29 -0
- data/lib/xeroizer/models/external_link.rb +16 -0
- data/lib/xeroizer/models/from_bank_account.rb +13 -0
- data/lib/xeroizer/models/invoice.rb +229 -0
- data/lib/xeroizer/models/invoice_reminder.rb +19 -0
- data/lib/xeroizer/models/item.rb +39 -0
- data/lib/xeroizer/models/item_purchase_details.rb +20 -0
- data/lib/xeroizer/models/item_sales_details.rb +19 -0
- data/lib/xeroizer/models/journal.rb +27 -0
- data/lib/xeroizer/models/journal_line.rb +29 -0
- data/lib/xeroizer/models/journal_line_tracking_category.rb +21 -0
- data/lib/xeroizer/models/line_amount_type.rb +11 -0
- data/lib/xeroizer/models/line_item.rb +64 -0
- data/lib/xeroizer/models/line_item_sum.rb +21 -0
- data/lib/xeroizer/models/manual_journal.rb +49 -0
- data/lib/xeroizer/models/manual_journal_line.rb +28 -0
- data/lib/xeroizer/models/online_invoice.rb +37 -0
- data/lib/xeroizer/models/option.rb +18 -0
- data/lib/xeroizer/models/organisation.rb +85 -0
- data/lib/xeroizer/models/overpayment.rb +40 -0
- data/lib/xeroizer/models/payment.rb +48 -0
- data/lib/xeroizer/models/payment_service.rb +22 -0
- data/lib/xeroizer/models/payment_terms.rb +16 -0
- data/lib/xeroizer/models/payroll/address.rb +53 -0
- data/lib/xeroizer/models/payroll/bank_account.rb +35 -0
- data/lib/xeroizer/models/payroll/benefit_line.rb +26 -0
- data/lib/xeroizer/models/payroll/benefit_type.rb +45 -0
- data/lib/xeroizer/models/payroll/deduction_line.rb +32 -0
- data/lib/xeroizer/models/payroll/deduction_type.rb +49 -0
- data/lib/xeroizer/models/payroll/earnings_line.rb +39 -0
- data/lib/xeroizer/models/payroll/earnings_type.rb +53 -0
- data/lib/xeroizer/models/payroll/employee.rb +67 -0
- data/lib/xeroizer/models/payroll/leave_application.rb +27 -0
- data/lib/xeroizer/models/payroll/leave_line.rb +30 -0
- data/lib/xeroizer/models/payroll/leave_period.rb +15 -0
- data/lib/xeroizer/models/payroll/pay_items.rb +22 -0
- data/lib/xeroizer/models/payroll/pay_run.rb +33 -0
- data/lib/xeroizer/models/payroll/pay_schedule.rb +40 -0
- data/lib/xeroizer/models/payroll/pay_template.rb +24 -0
- data/lib/xeroizer/models/payroll/payment_method.rb +24 -0
- data/lib/xeroizer/models/payroll/paystub.rb +44 -0
- data/lib/xeroizer/models/payroll/reimbursement_line.rb +21 -0
- data/lib/xeroizer/models/payroll/reimbursement_type.rb +22 -0
- data/lib/xeroizer/models/payroll/salary_and_wage.rb +29 -0
- data/lib/xeroizer/models/payroll/super_line.rb +40 -0
- data/lib/xeroizer/models/payroll/tax_declaration.rb +50 -0
- data/lib/xeroizer/models/payroll/time_off_line.rb +20 -0
- data/lib/xeroizer/models/payroll/time_off_type.rb +32 -0
- data/lib/xeroizer/models/payroll/work_location.rb +25 -0
- data/lib/xeroizer/models/phone.rb +26 -0
- data/lib/xeroizer/models/prepayment.rb +41 -0
- data/lib/xeroizer/models/purchase_order.rb +49 -0
- data/lib/xeroizer/models/receipt.rb +39 -0
- data/lib/xeroizer/models/repeating_invoice.rb +80 -0
- data/lib/xeroizer/models/sales.rb +13 -0
- data/lib/xeroizer/models/schedule.rb +34 -0
- data/lib/xeroizer/models/tax_component.rb +13 -0
- data/lib/xeroizer/models/tax_rate.rb +36 -0
- data/lib/xeroizer/models/to_bank_account.rb +13 -0
- data/lib/xeroizer/models/tracking_category.rb +23 -0
- data/lib/xeroizer/models/tracking_category_child.rb +20 -0
- data/lib/xeroizer/models/user.rb +26 -0
- data/lib/xeroizer/oauth.rb +162 -0
- data/lib/xeroizer/oauth2.rb +66 -0
- data/lib/xeroizer/oauth2_application.rb +42 -0
- data/lib/xeroizer/partner_application.rb +52 -0
- data/lib/xeroizer/payroll_application.rb +33 -0
- data/lib/xeroizer/private_application.rb +26 -0
- data/lib/xeroizer/public_application.rb +22 -0
- data/lib/xeroizer/record/application_helper.rb +32 -0
- data/lib/xeroizer/record/base.rb +203 -0
- data/lib/xeroizer/record/base_model.rb +253 -0
- data/lib/xeroizer/record/base_model_http_proxy.rb +141 -0
- data/lib/xeroizer/record/model_definition_helper.rb +101 -0
- data/lib/xeroizer/record/payroll_base.rb +29 -0
- data/lib/xeroizer/record/payroll_base_model.rb +29 -0
- data/lib/xeroizer/record/record_association_helper.rb +141 -0
- data/lib/xeroizer/record/validation_helper.rb +75 -0
- data/lib/xeroizer/record/validators/associated_validator.rb +34 -0
- data/lib/xeroizer/record/validators/block_validator.rb +22 -0
- data/lib/xeroizer/record/validators/inclusion_of_validator.rb +22 -0
- data/lib/xeroizer/record/validators/length_of_validator.rb +23 -0
- data/lib/xeroizer/record/validators/presence_of_validator.rb +19 -0
- data/lib/xeroizer/record/validators/validator.rb +33 -0
- data/lib/xeroizer/record/xml_helper.rb +144 -0
- data/lib/xeroizer/report/aged_receivables_by_contact.rb +42 -0
- data/lib/xeroizer/report/base.rb +42 -0
- data/lib/xeroizer/report/cell.rb +32 -0
- data/lib/xeroizer/report/cell_xml_helper.rb +74 -0
- data/lib/xeroizer/report/factory.rb +54 -0
- data/lib/xeroizer/report/row/header.rb +12 -0
- data/lib/xeroizer/report/row/row.rb +48 -0
- data/lib/xeroizer/report/row/section.rb +10 -0
- data/lib/xeroizer/report/row/summary.rb +9 -0
- data/lib/xeroizer/report/row/xml_helper.rb +77 -0
- data/lib/xeroizer/report/xml_helper.rb +58 -0
- data/lib/xeroizer/response.rb +74 -0
- data/lib/xeroizer/version.rb +3 -0
- data/test/acceptance/about_creating_bank_transactions_test.rb +170 -0
- data/test/acceptance/about_creating_prepayment_test.rb +41 -0
- data/test/acceptance/about_fetching_bank_transactions_test.rb +53 -0
- data/test/acceptance/about_online_invoice_test.rb +25 -0
- data/test/acceptance/acceptance_test.rb +77 -0
- data/test/acceptance/bank_transaction_reference_data.rb +32 -0
- data/test/acceptance/bank_transfer_test.rb +21 -0
- data/test/acceptance/bulk_operations_test.rb +50 -0
- data/test/acceptance/connections_test.rb +11 -0
- data/test/stub_responses/accounts.xml +589 -0
- data/test/stub_responses/api_exception.xml +153 -0
- data/test/stub_responses/bad_request.json +6 -0
- data/test/stub_responses/bogus_oauth_error +1 -0
- data/test/stub_responses/branding_themes.xml +20 -0
- data/test/stub_responses/connections.json +16 -0
- data/test/stub_responses/contact.xml +54 -0
- data/test/stub_responses/contact_with_details.xml +79 -0
- data/test/stub_responses/contacts.xml +0 -0
- data/test/stub_responses/create_credit_note.xml +104 -0
- data/test/stub_responses/create_invoice.xml +64 -0
- data/test/stub_responses/credit_note.xml +75 -0
- data/test/stub_responses/credit_note_not_found_error.xml +1 -0
- data/test/stub_responses/credit_notes.xml +169 -0
- data/test/stub_responses/currencies.xml +12 -0
- data/test/stub_responses/employees.xml +29 -0
- data/test/stub_responses/expired_oauth2_token.json +6 -0
- data/test/stub_responses/generic_response_error.json +6 -0
- data/test/stub_responses/invalid_api_key_error.xml +1 -0
- data/test/stub_responses/invalid_consumer_key +1 -0
- data/test/stub_responses/invalid_oauth2_request_token.json +6 -0
- data/test/stub_responses/invalid_request_token +1 -0
- data/test/stub_responses/invalid_tenant_header.json +6 -0
- data/test/stub_responses/invoice.xml +84 -0
- data/test/stub_responses/invoice_not_found_error.xml +1 -0
- data/test/stub_responses/invoices.xml +1899 -0
- data/test/stub_responses/items.xml +112 -0
- data/test/stub_responses/manual_journal.xml +45 -0
- data/test/stub_responses/manual_journals.xml +40 -0
- data/test/stub_responses/nonce_used +1 -0
- data/test/stub_responses/object_not_found.json +6 -0
- data/test/stub_responses/organisation.xml +55 -0
- data/test/stub_responses/organisations.xml +35 -0
- data/test/stub_responses/payment_service.xml +15 -0
- data/test/stub_responses/payments.xml +1121 -0
- data/test/stub_responses/prepayments.xml +27 -0
- data/test/stub_responses/rate_limit_exceeded +1 -0
- data/test/stub_responses/records/contact-043892a1-aef1-4c18-88d8-b8ccb6d31466.xml +38 -0
- data/test/stub_responses/records/contact-09664078-efe2-4a88-89a5-67eac9b0047b.xml +40 -0
- data/test/stub_responses/records/contact-0a4cf37b-a1a8-4753-9ee2-f9207f63a8ff.xml +48 -0
- data/test/stub_responses/records/contact-0e74f929-11b9-4255-a035-1fdfe573e676.xml +40 -0
- data/test/stub_responses/records/contact-0f471ca5-15c9-405e-a1b9-7cc35194b673.xml +38 -0
- data/test/stub_responses/records/contact-13cd4c47-baa6-4f07-93f6-6442310df4bf.xml +47 -0
- data/test/stub_responses/records/contact-158a2667-82ee-43bf-8f33-a6cc9524092d.xml +38 -0
- data/test/stub_responses/records/contact-17465072-6fa3-40bf-bc42-97765d9e1bea.xml +38 -0
- data/test/stub_responses/records/contact-1975b0ed-b7ba-4c61-bae8-2aa6d78b0dee.xml +39 -0
- data/test/stub_responses/records/contact-1b2be6e9-8d58-4da9-aaf8-4fe5471b653c.xml +53 -0
- data/test/stub_responses/records/contact-1c40da58-fe1d-4e97-b729-b2abdae94d9e.xml +38 -0
- data/test/stub_responses/records/contact-258176a5-c622-4394-9c94-6f88c3ea12e5.xml +40 -0
- data/test/stub_responses/records/contact-299dd3a0-a417-4a37-8a04-2f55e91963e5.xml +40 -0
- data/test/stub_responses/records/contact-2be39278-5154-4ed1-8eb0-676f25acfc66.xml +40 -0
- data/test/stub_responses/records/contact-2e58cff6-488c-4a32-884b-baf848010229.xml +40 -0
- data/test/stub_responses/records/contact-2faccd41-935e-40aa-b74e-e2fc28ac34c3.xml +38 -0
- data/test/stub_responses/records/contact-31af01e7-2ca7-45b9-a500-b02db996568e.xml +38 -0
- data/test/stub_responses/records/contact-344f1113-a25b-4344-b82e-bedeacc17c8e.xml +40 -0
- data/test/stub_responses/records/contact-3e776c4b-ea9e-4bb1-96be-6b0c7a71a37f.xml +39 -0
- data/test/stub_responses/records/contact-3fc1fc6c-e5ff-4e40-b6f3-7eb535637d87.xml +38 -0
- data/test/stub_responses/records/contact-416ab20c-5357-4beb-a740-e8d175d71efb.xml +38 -0
- data/test/stub_responses/records/contact-41a42865-f15a-4fa1-b643-47877608f557.xml +54 -0
- data/test/stub_responses/records/contact-42771b60-19a7-4692-af81-dd9f9b9362d4.xml +43 -0
- data/test/stub_responses/records/contact-451ceb28-9610-44c9-8f35-3225482f2413.xml +40 -0
- data/test/stub_responses/records/contact-4ab343ad-1ebb-4afe-9d48-1814a93c2081.xml +38 -0
- data/test/stub_responses/records/contact-4bb77692-42d4-4565-85a0-8849eb85e039.xml +39 -0
- data/test/stub_responses/records/contact-4dec292f-3ab7-46a8-83e4-5fb5eac42c7f.xml +40 -0
- data/test/stub_responses/records/contact-4e2f192e-8397-4d4d-97ca-a4fc5ac531bf.xml +38 -0
- data/test/stub_responses/records/contact-5188c17c-7786-4436-ad6e-9da2997386d0.xml +40 -0
- data/test/stub_responses/records/contact-52442753-b1c4-40b7-9b79-c33997de5837.xml +40 -0
- data/test/stub_responses/records/contact-565acaa9-e7f3-4fbf-80c3-16b081ddae10.xml +38 -0
- data/test/stub_responses/records/contact-571a2414-81ff-4f8f-8498-d91d83793131.xml +44 -0
- data/test/stub_responses/records/contact-58697449-85ef-46ae-83fc-6a9446f037fb.xml +40 -0
- data/test/stub_responses/records/contact-58bf2ae3-5144-4628-8de2-e165ac2bcdc6.xml +40 -0
- data/test/stub_responses/records/contact-5d41dafd-eb7e-42c1-bd5a-ba3be1da0960.xml +38 -0
- data/test/stub_responses/records/contact-5f005a09-5ce4-4fb4-8096-e69c18be636e.xml +38 -0
- data/test/stub_responses/records/contact-60d578d9-3e10-4aef-b5dc-9d9fd60a3633.xml +47 -0
- data/test/stub_responses/records/contact-62392126-dba4-4a75-b907-5875ebf75259.xml +40 -0
- data/test/stub_responses/records/contact-642c7fb5-e8e5-48e1-a710-39a18c6c3217.xml +40 -0
- data/test/stub_responses/records/contact-64aebf9c-bb89-4b38-b99b-405bd1ece6fd.xml +40 -0
- data/test/stub_responses/records/contact-64eedbc9-1fa0-485a-837f-705f23188161.xml +38 -0
- data/test/stub_responses/records/contact-65e96c9f-1595-4653-9a8a-2a36d49223c2.xml +40 -0
- data/test/stub_responses/records/contact-67d26b93-ccb4-4890-9bf1-284b70ea755d.xml +38 -0
- data/test/stub_responses/records/contact-69d3e538-44b3-4e00-a5f6-7dddcb6e0656.xml +40 -0
- data/test/stub_responses/records/contact-6a8450bc-f81a-4bb0-a8f6-aa4afe9497c7.xml +40 -0
- data/test/stub_responses/records/contact-6c70e424-41d6-4b9b-af3e-b3a9f3589106.xml +40 -0
- data/test/stub_responses/records/contact-6de0b0cf-560c-4503-aab3-e1543c329deb.xml +54 -0
- data/test/stub_responses/records/contact-72dd6a02-396e-42a2-a4d6-cc3fa75dfece.xml +41 -0
- data/test/stub_responses/records/contact-755f1475-d255-43a8-bedc-5ea7fd26c71f.xml +51 -0
- data/test/stub_responses/records/contact-78a9d0a0-3d8c-4f84-af3e-f260bf4a9dc0.xml +38 -0
- data/test/stub_responses/records/contact-79aa39ca-22b0-42c2-9026-78757a29d665.xml +42 -0
- data/test/stub_responses/records/contact-804f4140-5978-48fe-ba20-b56e5b834b18.xml +40 -0
- data/test/stub_responses/records/contact-812d4f28-1681-4241-8e34-d15c5520ba35.xml +38 -0
- data/test/stub_responses/records/contact-860b99a9-0958-4c8d-a98f-bb1f092b16bb.xml +60 -0
- data/test/stub_responses/records/contact-87c8da45-97cc-46be-b170-398da0eacfb8.xml +40 -0
- data/test/stub_responses/records/contact-8a154a19-6c6c-404b-bbc9-6deae2d18251.xml +38 -0
- data/test/stub_responses/records/contact-8bb6931d-2865-44e9-9a23-ed1fb9c7a46c.xml +40 -0
- data/test/stub_responses/records/contact-936c9759-01da-4063-b472-424ab9f48212.xml +38 -0
- data/test/stub_responses/records/contact-9d12a994-9640-4b75-95cc-3de1e9d0ef09.xml +38 -0
- data/test/stub_responses/records/contact-9fe59245-1fbb-4157-93c3-dc97388f3746.xml +40 -0
- data/test/stub_responses/records/contact-a06a7225-6f8a-4522-8400-c534dd43a16e.xml +40 -0
- data/test/stub_responses/records/contact-a76a85fe-73a2-46fa-aba7-791f36103cdb.xml +40 -0
- data/test/stub_responses/records/contact-a93b5f40-0346-4d21-9181-431e129911c0.xml +40 -0
- data/test/stub_responses/records/contact-abf272dd-6b1d-4829-af88-c57bf55855e3.xml +38 -0
- data/test/stub_responses/records/contact-ad24c33b-256b-4157-ad56-cbcf0e8db7b1.xml +47 -0
- data/test/stub_responses/records/contact-b107129d-f4c9-438e-9573-64b778527f4a.xml +40 -0
- data/test/stub_responses/records/contact-b233288a-aa26-4b26-9fc7-779d797dd56f.xml +40 -0
- data/test/stub_responses/records/contact-b2b5333a-2546-4975-891f-d71a8a640d23.xml +38 -0
- data/test/stub_responses/records/contact-b4d149bf-1823-4bd2-96da-9032388c9686.xml +40 -0
- data/test/stub_responses/records/contact-b78d4fd1-4306-4d83-a0b9-61458d1c53a2.xml +40 -0
- data/test/stub_responses/records/contact-b7d108a8-d5f7-4f16-a7c9-26eaed98e8de.xml +40 -0
- data/test/stub_responses/records/contact-baeed0f3-7989-4874-99b3-59f23032cb73.xml +38 -0
- data/test/stub_responses/records/contact-bc51a3a1-b7f6-46ca-ac9e-19b87e6ca100.xml +40 -0
- data/test/stub_responses/records/contact-be9f3aab-52f5-4d9c-94b4-87f7d9e5ee8b.xml +38 -0
- data/test/stub_responses/records/contact-c135f994-01e4-427b-9e15-acfe8a477c16.xml +49 -0
- data/test/stub_responses/records/contact-c14edf75-15e4-4a9c-86e4-f52e2fe7cfa4.xml +40 -0
- data/test/stub_responses/records/contact-ca9b9abc-c2dc-4221-8101-31f464d314cc.xml +44 -0
- data/test/stub_responses/records/contact-cc4db604-9ed8-4eef-8a29-51b5b70496a0.xml +38 -0
- data/test/stub_responses/records/contact-cce9b044-be4a-43b3-9dc7-c027d8dd35b2.xml +38 -0
- data/test/stub_responses/records/contact-d0cd2c4f-18a0-4f7c-a32a-2db00f29d298.xml +43 -0
- data/test/stub_responses/records/contact-d6851dc2-9ed9-4515-bc0b-810b09c06a6a.xml +38 -0
- data/test/stub_responses/records/contact-d6a384fb-f46f-41a3-8ac7-b7bc9e0b5efa.xml +46 -0
- data/test/stub_responses/records/contact-d74e61cf-2ad0-4f0d-b9d1-6a808e3f70cf.xml +40 -0
- data/test/stub_responses/records/contact-d9ab0f61-3b56-4e2b-be39-f33c11bd99e3.xml +40 -0
- data/test/stub_responses/records/contact-dbb1f0b5-a71b-4458-8462-104acd0fec6b.xml +38 -0
- data/test/stub_responses/records/contact-dd981bd6-40dd-496d-a282-bf7d3391b8b9.xml +40 -0
- data/test/stub_responses/records/contact-e1826204-cc0a-42a5-a6d0-4b352d9d5953.xml +40 -0
- data/test/stub_responses/records/contact-e2d955db-f366-42dd-87f7-fbdb4da2306f.xml +40 -0
- data/test/stub_responses/records/contact-e32e2130-3d27-443a-8313-48fffa03cf53.xml +40 -0
- data/test/stub_responses/records/contact-e3a68332-d322-4816-8678-73a537c8cd33.xml +38 -0
- data/test/stub_responses/records/contact-e6ac76a3-ca32-4fa1-8ef9-6a4bf8b0ec2a.xml +40 -0
- data/test/stub_responses/records/contact-e6ca965d-7c48-480e-be39-e847307f474a.xml +38 -0
- data/test/stub_responses/records/contact-e77d1f20-2e8e-46ec-9a10-50335a216724.xml +40 -0
- data/test/stub_responses/records/contact-e8b98c13-a424-41d2-ba0e-7b7621411e7a.xml +38 -0
- data/test/stub_responses/records/contact-e8e9a2c2-3e7e-48ed-8528-c3d61b28f276.xml +39 -0
- data/test/stub_responses/records/contact-eb43fcc6-87ec-4a0a-b243-d718bee4e2cb.xml +38 -0
- data/test/stub_responses/records/contact-ef6f54c1-eb45-4956-b8cd-1be82ad665f2.xml +43 -0
- data/test/stub_responses/records/contact-efdb3600-f233-42e2-8f18-ce7e2a95e4b1.xml +38 -0
- data/test/stub_responses/records/contact-f7eca431-5c97-4d24-93fd-004bb8a6c644.xml +40 -0
- data/test/stub_responses/records/contact-fb078879-5d6d-474f-825f-61dc90689349.xml +38 -0
- data/test/stub_responses/records/contact-fc39b273-4aa2-4785-99ca-24672f6c0000.xml +38 -0
- data/test/stub_responses/records/contact-fc9ec3a6-a2fe-4300-a8cb-ca8a0b3662e0.xml +40 -0
- data/test/stub_responses/records/contact-fdf96102-7491-44b6-bf4d-7a77ff25f890.xml +40 -0
- data/test/stub_responses/records/contact-fe61ead1-8afc-4f0b-beda-066620227aad.xml +38 -0
- data/test/stub_responses/records/credit_note-371cd138-1e5c-4ec1-a8c6-a1c10e8bdab1.xml +73 -0
- data/test/stub_responses/records/credit_note-3bffc09b-79f2-490d-b91b-c59b700b43a4.xml +95 -0
- data/test/stub_responses/records/credit_note-43c678ee-f357-48e2-b192-b6e3634762f9.xml +94 -0
- data/test/stub_responses/records/credit_note-482c018b-d329-4e05-9b4f-7a4cfc695aa0.xml +77 -0
- data/test/stub_responses/records/credit_note-4f67130a-749a-4ee6-98b2-743adbc11245.xml +62 -0
- data/test/stub_responses/records/credit_note-50e98404-2fba-4031-af67-8ba4bb227c44.xml +77 -0
- data/test/stub_responses/records/credit_note-7df8949c-b71f-40c0-bbcf-39f2f450f286.xml +75 -0
- data/test/stub_responses/records/credit_note-b356e488-2678-4be4-ad4b-d294df2d48d6.xml +78 -0
- data/test/stub_responses/records/invoice-0032f627-3156-4d30-9b1c-4d3b994dc921.xml +84 -0
- data/test/stub_responses/records/invoice-00c9511b-24b9-4190-a90a-8abf2fe9f4a0.xml +76 -0
- data/test/stub_responses/records/invoice-024d7994-a26c-4c20-9894-13934840fc31.xml +74 -0
- data/test/stub_responses/records/invoice-0e64a623-c2a1-446a-93ed-eb897f118cbc.xml +97 -0
- data/test/stub_responses/records/invoice-15e88e57-2554-4496-a18e-eb3f5c622345.xml +75 -0
- data/test/stub_responses/records/invoice-166f0588-d0ba-458c-b28a-8edd4c8fc463.xml +75 -0
- data/test/stub_responses/records/invoice-1d1ba340-afa2-4f4c-8ff7-a147bda9a47b.xml +93 -0
- data/test/stub_responses/records/invoice-290ef4c4-baec-492b-b4dd-c102826470ae.xml +87 -0
- data/test/stub_responses/records/invoice-30a87092-31b5-4a2c-831e-327486533dd2.xml +79 -0
- data/test/stub_responses/records/invoice-30dbd181-72a8-43df-b392-4241bf43d5fc.xml +79 -0
- data/test/stub_responses/records/invoice-33e4123e-7cdd-4f05-9a0a-eb8adeb2b868.xml +94 -0
- data/test/stub_responses/records/invoice-387db692-26ac-47e6-b6cc-015343809bda.xml +75 -0
- data/test/stub_responses/records/invoice-3b28bf11-ed2f-4cf4-8e9e-fcae730cc292.xml +91 -0
- data/test/stub_responses/records/invoice-3fcb9847-b350-412e-ab90-7d9d774ad881.xml +91 -0
- data/test/stub_responses/records/invoice-440613e4-4785-4eff-9ba1-c432816cf8c7.xml +78 -0
- data/test/stub_responses/records/invoice-4602eda6-abe9-448e-b65f-ae6bea21f0eb.xml +98 -0
- data/test/stub_responses/records/invoice-46441f63-873f-4cdc-a278-b8fe516f3abb.xml +94 -0
- data/test/stub_responses/records/invoice-4ad1ec01-f4a3-41d7-bbb4-d2ab2fec8e65.xml +74 -0
- data/test/stub_responses/records/invoice-4b9afceb-f7c7-4e64-8aac-7b009971fd52.xml +86 -0
- data/test/stub_responses/records/invoice-4edbf6d5-4e92-43af-bedd-7effc0b86833.xml +70 -0
- data/test/stub_responses/records/invoice-4fad1af2-b871-4ac5-a15a-3c5e32d2e2c4.xml +93 -0
- data/test/stub_responses/records/invoice-52ee4d67-cae4-462c-adb2-182c39017f3d.xml +83 -0
- data/test/stub_responses/records/invoice-54585f46-c1a0-4432-bd4f-c1fae2fba59b.xml +67 -0
- data/test/stub_responses/records/invoice-5613938b-9e27-472e-92ae-3b038b669d10.xml +87 -0
- data/test/stub_responses/records/invoice-5aa9451d-95d1-4f95-a966-bbab2573f71c.xml +75 -0
- data/test/stub_responses/records/invoice-5aadcd34-01a9-4b8d-a2bb-d7cc1de9fa45.xml +89 -0
- data/test/stub_responses/records/invoice-5f6deadf-36a2-495a-9980-ceb11e8af9a9.xml +85 -0
- data/test/stub_responses/records/invoice-625ffe1b-f5d8-438e-a376-981de5f5a733.xml +77 -0
- data/test/stub_responses/records/invoice-64cd559e-8e03-46af-b461-8555285cee71.xml +86 -0
- data/test/stub_responses/records/invoice-666f8dbb-bc9a-476c-8ec4-4665d7f83190.xml +63 -0
- data/test/stub_responses/records/invoice-66fbe37f-49b1-43fd-97ed-85114022cd2f.xml +79 -0
- data/test/stub_responses/records/invoice-673dd7cc-beb7-4697-83d4-0c47cb400cc2.xml +95 -0
- data/test/stub_responses/records/invoice-69fc971e-9b37-41c5-9c87-174330f22343.xml +66 -0
- data/test/stub_responses/records/invoice-70e6db69-e5a4-42c7-a397-aa3212c2945f.xml +75 -0
- data/test/stub_responses/records/invoice-762aa45d-4632-45b5-8087-b4f47690665e.xml +54 -0
- data/test/stub_responses/records/invoice-766d1289-b440-4675-a656-1a0612ecac77.xml +76 -0
- data/test/stub_responses/records/invoice-76bcb361-f93b-4513-b312-5a4af306d276.xml +67 -0
- data/test/stub_responses/records/invoice-76e3f056-479f-417c-a72b-f3d767899b87.xml +91 -0
- data/test/stub_responses/records/invoice-77b338ef-ecc0-4b95-a0d7-2617b0054611.xml +114 -0
- data/test/stub_responses/records/invoice-7be9956d-5316-4f6b-a66a-d355b3f159b2.xml +84 -0
- data/test/stub_responses/records/invoice-7dae876a-b424-436b-a4e6-17b3fdeec80c.xml +91 -0
- data/test/stub_responses/records/invoice-7e862d93-8dab-4856-8b0c-d844e09d750f.xml +68 -0
- data/test/stub_responses/records/invoice-803f70b0-56d9-4157-9787-41df271777a0.xml +84 -0
- data/test/stub_responses/records/invoice-86102312-aa3f-438c-9938-6840f4d8dda6.xml +75 -0
- data/test/stub_responses/records/invoice-8694c9c5-7097-4449-a708-b8c1982921a4.xml +69 -0
- data/test/stub_responses/records/invoice-86d6e00f-ef56-49f7-9a54-796ccd5ca057.xml +85 -0
- data/test/stub_responses/records/invoice-88e77f0f-54a5-4efc-a979-7e22223cc4d7.xml +66 -0
- data/test/stub_responses/records/invoice-8b0ccb6a-d9b7-4da5-8360-ef7fb157b5aa.xml +66 -0
- data/test/stub_responses/records/invoice-935fc854-8037-4111-8d91-993010c331cc.xml +74 -0
- data/test/stub_responses/records/invoice-95ef3000-c764-4ba9-a66a-b6e2d161f839.xml +62 -0
- data/test/stub_responses/records/invoice-962ef33f-c9d2-4602-9b9f-93a02bea23b3.xml +93 -0
- data/test/stub_responses/records/invoice-9868b472-1983-48e9-8edf-7e81ddf2c03a.xml +85 -0
- data/test/stub_responses/records/invoice-9a448e9b-a9fa-4a8b-98f5-6dc892a37374.xml +62 -0
- data/test/stub_responses/records/invoice-a1d04a14-96a8-4067-a0ff-8136990a354f.xml +91 -0
- data/test/stub_responses/records/invoice-a3bc62ef-f11b-4a9c-a4f9-a342bda371b5.xml +66 -0
- data/test/stub_responses/records/invoice-a6894ca0-60ee-4d45-9dd4-b44fcba46ec5.xml +90 -0
- data/test/stub_responses/records/invoice-a77268ce-74b2-483d-a2b3-70dbdc9e49d2.xml +78 -0
- data/test/stub_responses/records/invoice-a9f765e6-b9bc-4505-a47b-fb3ecb327e7b.xml +88 -0
- data/test/stub_responses/records/invoice-aa0173af-8707-4e7f-8dde-4c7a357bd312.xml +109 -0
- data/test/stub_responses/records/invoice-ab63738a-370a-43a5-bfa3-620d684e66d0.xml +83 -0
- data/test/stub_responses/records/invoice-b0344791-5a8a-40dd-a208-d99a461a6c10.xml +84 -0
- data/test/stub_responses/records/invoice-b1e53910-473c-46a3-b3cb-38ece571220e.xml +76 -0
- data/test/stub_responses/records/invoice-b2c02d0b-41a8-4d4d-97d7-014c78b3547d.xml +93 -0
- data/test/stub_responses/records/invoice-b75b3928-ab72-4424-8b93-9cdbbde4cd72.xml +90 -0
- data/test/stub_responses/records/invoice-bcd8a71f-aa31-4d0f-8a01-13ea26363ddf.xml +94 -0
- data/test/stub_responses/records/invoice-bfbb7c45-de02-45e7-b065-d9863ecfb0d8.xml +66 -0
- data/test/stub_responses/records/invoice-c12aff7e-12bf-4185-8702-460929f19674.xml +77 -0
- data/test/stub_responses/records/invoice-c3380b96-976d-4b3e-8b26-8d01eb6a3742.xml +87 -0
- data/test/stub_responses/records/invoice-c963f2b0-cbe1-4abd-9ccc-7e512c942068.xml +67 -0
- data/test/stub_responses/records/invoice-cba46b29-3788-4158-b668-ab10160ccbfe.xml +78 -0
- data/test/stub_responses/records/invoice-d62646b9-d0a9-4fdb-9561-756a8b7eba45.xml +63 -0
- data/test/stub_responses/records/invoice-dba2f021-f149-4191-a126-5351d587ab0e.xml +75 -0
- data/test/stub_responses/records/invoice-de5d9c29-21b3-4342-958b-ed72c4bd7ab0.xml +108 -0
- data/test/stub_responses/records/invoice-e3d96555-2876-4364-a46a-7551a4f52611.xml +123 -0
- data/test/stub_responses/records/invoice-e4a0afbd-aea0-450b-ae23-0ce921e84a77.xml +102 -0
- data/test/stub_responses/records/invoice-e9cb9ecb-58ef-43a8-bd20-69a85338142d.xml +76 -0
- data/test/stub_responses/records/invoice-ec9a6f67-7128-4a63-8ba3-5e516f455f9b.xml +94 -0
- data/test/stub_responses/records/invoice-ed0f2587-84fc-4aef-bc4b-b1a262e24484.xml +81 -0
- data/test/stub_responses/records/invoice-f362ca53-8ade-4047-865a-bb64bee5863d.xml +74 -0
- data/test/stub_responses/records/invoice-f571c38b-5be1-41e1-ad5a-ff6184284beb.xml +114 -0
- data/test/stub_responses/records/invoice-f5832195-5cd3-4660-ad3f-b73d9c64f263.xml +85 -0
- data/test/stub_responses/records/invoice-f9c857eb-64cd-4235-a078-d04b52c77ea7.xml +76 -0
- data/test/stub_responses/records/manual_journal-4765d07b-aa03-4e56-9166-50661958c864.xml +38 -0
- data/test/stub_responses/records/manual_journal-53fc5558-5b76-4ecd-ae5c-c4af3ccde87c.xml +31 -0
- data/test/stub_responses/records/manual_journal-bb6cfcfc-4500-4475-bd3a-93ee512428e0.xml +31 -0
- data/test/stub_responses/records/manual_journal-f00a355b-7374-445c-886b-0437bea4095c.xml +45 -0
- data/test/stub_responses/records/prepayment-7d3619b1-82cc-405b-8f44-9d4f9a787a8a.xml +92 -0
- data/test/stub_responses/records/repeating_invoice-ad3550bc-1ae0-45c0-a782-48c6d2061127.xml +43 -0
- data/test/stub_responses/refresh_responses.rb +29 -0
- data/test/stub_responses/repeating_invoices.xml +43 -0
- data/test/stub_responses/reports/trial_balance.xml +1435 -0
- data/test/stub_responses/tax_rates.xml +198 -0
- data/test/stub_responses/token_expired +1 -0
- data/test/stub_responses/tracking_categories.xml +27 -0
- data/test/stub_responses/unknown_error.xml +1 -0
- data/test/stub_responses/users.xml +17 -0
- data/test/test_helper.rb +72 -0
- data/test/unit/generic_application_test.rb +52 -0
- data/test/unit/http_test.rb +302 -0
- data/test/unit/models/address_test.rb +92 -0
- data/test/unit/models/bank_transaction_model_parsing_test.rb +133 -0
- data/test/unit/models/bank_transaction_test.rb +44 -0
- data/test/unit/models/bank_transaction_validation_test.rb +115 -0
- data/test/unit/models/contact_test.rb +132 -0
- data/test/unit/models/credit_note_test.rb +37 -0
- data/test/unit/models/employee_test.rb +43 -0
- data/test/unit/models/invoice_test.rb +133 -0
- data/test/unit/models/journal_line_test.rb +22 -0
- data/test/unit/models/journal_test.rb +44 -0
- data/test/unit/models/line_item_sum_test.rb +25 -0
- data/test/unit/models/line_item_test.rb +59 -0
- data/test/unit/models/manual_journal_test.rb +25 -0
- data/test/unit/models/organisation_test.rb +52 -0
- data/test/unit/models/payment_service_test.rb +29 -0
- data/test/unit/models/phone_test.rb +31 -0
- data/test/unit/models/prepayment_test.rb +21 -0
- data/test/unit/models/repeating_invoice_test.rb +36 -0
- data/test/unit/models/tax_rate_test.rb +132 -0
- data/test/unit/oauth2_test.rb +171 -0
- data/test/unit/oauth_config_test.rb +20 -0
- data/test/unit/oauth_test.rb +179 -0
- data/test/unit/private_application_test.rb +20 -0
- data/test/unit/record/base_model_test.rb +58 -0
- data/test/unit/record/base_test.rb +174 -0
- data/test/unit/record/block_validator_test.rb +125 -0
- data/test/unit/record/connection_test.rb +60 -0
- data/test/unit/record/model_definition_test.rb +165 -0
- data/test/unit/record/parse_params_test.rb +59 -0
- data/test/unit/record/parse_where_hash_test.rb +63 -0
- data/test/unit/record/record_association_test.rb +93 -0
- data/test/unit/record/validators_test.rb +228 -0
- data/test/unit/record_definition_test.rb +27 -0
- data/test/unit/report_definition_test.rb +26 -0
- data/test/unit/report_test.rb +154 -0
- data/test/unit_test_helper.rb +16 -0
- metadata +1024 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Xeroizer
|
|
2
|
+
class PrivateApplication < GenericApplication
|
|
3
|
+
|
|
4
|
+
extend Forwardable
|
|
5
|
+
def_delegators :client, :authorize_from_access
|
|
6
|
+
|
|
7
|
+
public
|
|
8
|
+
|
|
9
|
+
# Private applications are defined in the Xero API website and can be accessed in the
|
|
10
|
+
# background without ever requiring a redirect to the Xero website for authorisation.
|
|
11
|
+
#
|
|
12
|
+
# @param [String] consumer_key consumer key/token from application developer (found at http://api.xero.com for your application).
|
|
13
|
+
# @param [String] consumer_secret consumer secret from application developer (found at http://api.xero.com for your application).
|
|
14
|
+
# @param [String] path_to_private_key application's private key for message signing (uploaded to http://api.xero.com)
|
|
15
|
+
# @param [Hash] options other options to pass to the GenericApplication constructor
|
|
16
|
+
# @return [PrivateApplication] instance of PrivateApplication
|
|
17
|
+
def initialize(consumer_key, consumer_secret, path_to_private_key, options = {})
|
|
18
|
+
options[:signature_method] = 'RSA-SHA1'
|
|
19
|
+
options[:private_key_file] = path_to_private_key
|
|
20
|
+
client = OAuth.new(consumer_key, consumer_secret, options)
|
|
21
|
+
super(client, options)
|
|
22
|
+
@client.authorize_from_access(consumer_key, consumer_secret)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Xeroizer
|
|
2
|
+
class PublicApplication < GenericApplication
|
|
3
|
+
|
|
4
|
+
extend Forwardable
|
|
5
|
+
def_delegators :client, :request_token, :authorize_from_request, :authorize_from_access
|
|
6
|
+
|
|
7
|
+
public
|
|
8
|
+
|
|
9
|
+
# Public appliations are authenticated via the Xero website via OAuth. AccessTokens are valid for 30 minutes
|
|
10
|
+
# after authentication. To extend this time you must redirect the user to Xero's OAuth server again.
|
|
11
|
+
#
|
|
12
|
+
# @param [String] consumer_key consumer key/token from application developer (found at http://api.xero.com for your application)
|
|
13
|
+
# @param [String] consumer_secret consumer secret from application developer (found at http://api.xero.com for your application)
|
|
14
|
+
# @param [Hash] options other options to pass to the GenericApplication constructor
|
|
15
|
+
# @return [PublicApplication] instance of PrivateApplication
|
|
16
|
+
def initialize(consumer_key, consumer_secret, options = {})
|
|
17
|
+
client = OAuth.new(consumer_key, consumer_secret, options)
|
|
18
|
+
super(client, options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Xeroizer
|
|
2
|
+
module Record
|
|
3
|
+
module ApplicationHelper
|
|
4
|
+
|
|
5
|
+
# Factory for new BaseModel instances with the class name `record_type`.
|
|
6
|
+
# Only creates the instance if one doesn't already exist.
|
|
7
|
+
#
|
|
8
|
+
# @param [Symbol] record_type Symbol of the record type (e.g. :Invoice)
|
|
9
|
+
# @return [BaseModel] instance of BaseModel subclass matching `record_type`
|
|
10
|
+
def record(record_type)
|
|
11
|
+
define_method record_type do
|
|
12
|
+
var_name = "@#{record_type}_cache".to_sym
|
|
13
|
+
unless instance_variable_defined?(var_name)
|
|
14
|
+
instance_variable_set(var_name, Xeroizer::Record.const_get("#{record_type}Model".to_sym).new(self, record_type.to_s))
|
|
15
|
+
end
|
|
16
|
+
instance_variable_get(var_name)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def report(report_type)
|
|
21
|
+
define_method report_type do
|
|
22
|
+
var_name = "@#{report_type}_cache".to_sym
|
|
23
|
+
unless instance_variable_defined?(var_name)
|
|
24
|
+
instance_variable_set(var_name, Xeroizer::Report::Factory.new(self, report_type.to_s))
|
|
25
|
+
end
|
|
26
|
+
instance_variable_get(var_name)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
require 'xeroizer/record/model_definition_helper'
|
|
2
|
+
require 'xeroizer/record/record_association_helper'
|
|
3
|
+
require 'xeroizer/record/validation_helper'
|
|
4
|
+
require 'xeroizer/record/xml_helper'
|
|
5
|
+
require 'xeroizer/logging'
|
|
6
|
+
|
|
7
|
+
module Xeroizer
|
|
8
|
+
module Record
|
|
9
|
+
|
|
10
|
+
class Base
|
|
11
|
+
|
|
12
|
+
include ClassLevelInheritableAttributes
|
|
13
|
+
class_inheritable_attributes :fields, :possible_primary_keys, :primary_key_name, :summary_only, :validators
|
|
14
|
+
|
|
15
|
+
attr_reader :attributes
|
|
16
|
+
attr_reader :parent
|
|
17
|
+
attr_reader :model
|
|
18
|
+
attr_accessor :errors
|
|
19
|
+
attr_accessor :complete_record_downloaded
|
|
20
|
+
attr_accessor :paged_record_downloaded
|
|
21
|
+
|
|
22
|
+
include ModelDefinitionHelper
|
|
23
|
+
include RecordAssociationHelper
|
|
24
|
+
include ValidationHelper
|
|
25
|
+
include XmlHelper
|
|
26
|
+
|
|
27
|
+
class << self
|
|
28
|
+
|
|
29
|
+
# Build a record with attributes set to the value of attributes.
|
|
30
|
+
def build(attributes, parent)
|
|
31
|
+
record = new(parent)
|
|
32
|
+
attributes.each do | key, value |
|
|
33
|
+
attr = record.respond_to?("#{key}=") || record.class.fields[key].nil? ? key : record.class.fields[key][:internal_name]
|
|
34
|
+
record.send("#{attr}=", value)
|
|
35
|
+
end
|
|
36
|
+
record
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
public
|
|
42
|
+
|
|
43
|
+
def initialize(parent)
|
|
44
|
+
@parent = parent
|
|
45
|
+
@model = new_model_class(self.class.name.demodulize)
|
|
46
|
+
@attributes = {}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def new_model_class(model_name)
|
|
50
|
+
Xeroizer::Record.const_get("#{model_name}Model".to_sym).new(parent.try(:application), model_name.to_s)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def [](attribute)
|
|
54
|
+
self.send(attribute)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def []=(attribute, value)
|
|
58
|
+
parent.mark_dirty(self) if parent
|
|
59
|
+
self.send("#{attribute}=".to_sym, value)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def non_calculated_attributes
|
|
63
|
+
attributes.reject {|name| self.class.fields[name][:calculated] }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def attributes=(new_attributes)
|
|
67
|
+
return unless new_attributes.is_a?(Hash)
|
|
68
|
+
parent.mark_dirty(self) if parent
|
|
69
|
+
new_attributes.each do | key, value |
|
|
70
|
+
attr = respond_to?("#{key}=") ? key : self.class.fields[key][:internal_name]
|
|
71
|
+
self.send("#{attr}=", value)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def update_attributes(attributes)
|
|
76
|
+
self.attributes = attributes
|
|
77
|
+
save
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def new_record?
|
|
81
|
+
id.nil?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Check to see if the complete record is downloaded.
|
|
85
|
+
def complete_record_downloaded?
|
|
86
|
+
if !!self.class.list_contains_summary_only?
|
|
87
|
+
!!complete_record_downloaded
|
|
88
|
+
else
|
|
89
|
+
true
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def paged_record_downloaded?
|
|
95
|
+
!!paged_record_downloaded
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Downloads the complete record if we only have a summary of the record.
|
|
99
|
+
def download_complete_record!
|
|
100
|
+
record = self.parent.find(self.id)
|
|
101
|
+
@attributes = record.attributes if record
|
|
102
|
+
@complete_record_downloaded = true
|
|
103
|
+
parent.mark_clean(self)
|
|
104
|
+
self
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def save
|
|
108
|
+
save!
|
|
109
|
+
true
|
|
110
|
+
rescue XeroizerError => e
|
|
111
|
+
log "[ERROR SAVING] (#{__FILE__}:#{__LINE__}) - #{e.message}"
|
|
112
|
+
false
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def save!
|
|
116
|
+
raise RecordInvalid unless valid?
|
|
117
|
+
if new_record?
|
|
118
|
+
create
|
|
119
|
+
else
|
|
120
|
+
update
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
saved!
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def saved!
|
|
127
|
+
@complete_record_downloaded = true
|
|
128
|
+
parent.mark_clean(self)
|
|
129
|
+
true
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def to_json(*args)
|
|
133
|
+
to_h.to_json(*args)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Deprecated
|
|
137
|
+
def as_json(options = {})
|
|
138
|
+
to_h.to_json
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def to_h
|
|
142
|
+
attrs = self.attributes.reject {|k, v| k == :parent }.map do |k, v|
|
|
143
|
+
[k, v.kind_of?(Array) ? v.map(&:to_h) : (v.respond_to?(:to_h) ? v.to_h : v)]
|
|
144
|
+
end
|
|
145
|
+
Hash[attrs]
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def inspect
|
|
149
|
+
attribute_string = self.attributes.collect do |attr, value|
|
|
150
|
+
"#{attr.inspect}: #{value.inspect}"
|
|
151
|
+
end.join(", ")
|
|
152
|
+
"#<#{self.class} #{attribute_string}>"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
protected
|
|
156
|
+
|
|
157
|
+
# Attempt to create a new record.
|
|
158
|
+
def create
|
|
159
|
+
request = to_xml
|
|
160
|
+
log "[CREATE SENT] (#{__FILE__}:#{__LINE__}) #{request}"
|
|
161
|
+
|
|
162
|
+
response = parent.send(parent.create_method, request)
|
|
163
|
+
|
|
164
|
+
log "[CREATE RECEIVED] (#{__FILE__}:#{__LINE__}) #{response}"
|
|
165
|
+
|
|
166
|
+
parse_save_response(response)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Attempt to update an existing record.
|
|
170
|
+
def update
|
|
171
|
+
if self.class.possible_primary_keys && self.class.possible_primary_keys.all? { | possible_key | self[possible_key].nil? }
|
|
172
|
+
raise RecordKeyMustBeDefined.new(self.class.possible_primary_keys)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
request = to_xml
|
|
176
|
+
|
|
177
|
+
log "[UPDATE SENT] (#{__FILE__}:#{__LINE__}) \r\n#{request}"
|
|
178
|
+
|
|
179
|
+
response = parent.http_post(request)
|
|
180
|
+
|
|
181
|
+
log "[UPDATE RECEIVED] (#{__FILE__}:#{__LINE__}) \r\n#{response}"
|
|
182
|
+
|
|
183
|
+
parse_save_response(response)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Parse the response from a create/update request.
|
|
187
|
+
def parse_save_response(response_xml)
|
|
188
|
+
response = parent.parse_response(response_xml)
|
|
189
|
+
record = response.response_items.first if response.response_items.is_a?(Array)
|
|
190
|
+
if record && record.is_a?(self.class)
|
|
191
|
+
@attributes = record.attributes
|
|
192
|
+
end
|
|
193
|
+
self
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def log(what)
|
|
197
|
+
Xeroizer::Logging::Log.info what
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
end
|
|
203
|
+
end
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
require 'xeroizer/record/base_model_http_proxy'
|
|
2
|
+
|
|
3
|
+
module Xeroizer
|
|
4
|
+
module Record
|
|
5
|
+
|
|
6
|
+
class BaseModel
|
|
7
|
+
|
|
8
|
+
include ClassLevelInheritableAttributes
|
|
9
|
+
class_inheritable_attributes :api_controller_name
|
|
10
|
+
|
|
11
|
+
module InvaidPermissionError; end
|
|
12
|
+
class InvalidPermissionError < XeroizerError
|
|
13
|
+
include InvaidPermissionError
|
|
14
|
+
end
|
|
15
|
+
ALLOWED_PERMISSIONS = [:read, :write, :update]
|
|
16
|
+
class_inheritable_attributes :permissions
|
|
17
|
+
|
|
18
|
+
class_inheritable_attributes :xml_root_name
|
|
19
|
+
class_inheritable_attributes :optional_xml_root_name
|
|
20
|
+
class_inheritable_attributes :xml_node_name
|
|
21
|
+
|
|
22
|
+
DEFAULT_RECORDS_PER_BATCH_SAVE = 50
|
|
23
|
+
|
|
24
|
+
include BaseModelHttpProxy
|
|
25
|
+
|
|
26
|
+
attr_reader :application
|
|
27
|
+
attr_reader :model_name
|
|
28
|
+
attr_writer :model_class
|
|
29
|
+
attr_reader :response
|
|
30
|
+
|
|
31
|
+
class << self
|
|
32
|
+
|
|
33
|
+
# Method to allow override of the default controller name used
|
|
34
|
+
# in the API URLs.
|
|
35
|
+
#
|
|
36
|
+
# Default: pluaralized model name (e.g. if the controller name is
|
|
37
|
+
# Invoice then the default is Invoices.
|
|
38
|
+
def set_api_controller_name(controller_name)
|
|
39
|
+
self.api_controller_name = controller_name
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Set the permissions allowed for this class type.
|
|
43
|
+
# There are no permissions set by default.
|
|
44
|
+
# Valid permissions are :read, :write, :update.
|
|
45
|
+
def set_permissions(*args)
|
|
46
|
+
self.permissions = {}
|
|
47
|
+
args.each do | permission |
|
|
48
|
+
raise InvalidPermissionError.new("Permission #{permission} is invalid.") unless ALLOWED_PERMISSIONS.include?(permission)
|
|
49
|
+
self.permissions[permission] = true
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Method to allow override of the default XML node name.
|
|
54
|
+
#
|
|
55
|
+
# Default: singularized model name in camel-case.
|
|
56
|
+
def set_xml_node_name(node_name)
|
|
57
|
+
self.xml_node_name = node_name
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Method to allow override of the default XML root name to use
|
|
61
|
+
# in has_many associations.
|
|
62
|
+
def set_xml_root_name(root_name)
|
|
63
|
+
self.xml_root_name = root_name
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Method to add an extra top-level node to use in has_many associations.
|
|
67
|
+
def set_optional_xml_root_name(optional_root_name)
|
|
68
|
+
self.optional_xml_root_name = optional_root_name
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
public
|
|
74
|
+
|
|
75
|
+
def initialize(application, model_name)
|
|
76
|
+
@application = application
|
|
77
|
+
@model_name = model_name
|
|
78
|
+
@allow_batch_operations = false
|
|
79
|
+
@objects = {}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Retrieve the controller name.
|
|
83
|
+
#
|
|
84
|
+
# Default: pluaralized model name (e.g. if the controller name is
|
|
85
|
+
# Invoice then the default is Invoices.
|
|
86
|
+
def api_controller_name
|
|
87
|
+
self.class.api_controller_name || model_name.pluralize
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def model_class
|
|
91
|
+
@model_class ||= Xeroizer::Record.const_get(model_name.to_sym)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Build a record with attributes set to the value of attributes.
|
|
95
|
+
def build(attributes = {})
|
|
96
|
+
model_class.build(attributes, self).tap do |resource|
|
|
97
|
+
mark_dirty(resource)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def mark_dirty(resource)
|
|
102
|
+
if @allow_batch_operations
|
|
103
|
+
@objects[model_class] ||= {}
|
|
104
|
+
@objects[model_class][resource.object_id] ||= resource
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def mark_clean(resource)
|
|
109
|
+
if @objects and @objects[model_class]
|
|
110
|
+
@objects[model_class].delete(resource.object_id)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Create (build and save) a record with attributes set to the value of attributes.
|
|
115
|
+
def create(attributes = {})
|
|
116
|
+
build(attributes).tap { |resource| resource.save }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Retrieve full record list for this model.
|
|
120
|
+
def all(options = {})
|
|
121
|
+
raise MethodNotAllowed.new(self, :all) unless self.class.permissions[:read]
|
|
122
|
+
response_xml = http_get(parse_params(options))
|
|
123
|
+
response = parse_response(response_xml, options)
|
|
124
|
+
response.response_items || []
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# allow invoices to be process in batches of 100 as per xero documentation
|
|
128
|
+
# https://developer.xero.com/documentation/api/invoices/
|
|
129
|
+
def find_in_batches(options = {}, &block)
|
|
130
|
+
options[:page] ||= 1
|
|
131
|
+
while results = all(options)
|
|
132
|
+
if results.any?
|
|
133
|
+
yield results
|
|
134
|
+
options[:page] += 1
|
|
135
|
+
else
|
|
136
|
+
break
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Helper method to retrieve just the first element from
|
|
142
|
+
# the full record list.
|
|
143
|
+
def first(options = {})
|
|
144
|
+
raise MethodNotAllowed.new(self, :all) unless self.class.permissions[:read]
|
|
145
|
+
result = all(options)
|
|
146
|
+
result.first if result.is_a?(Array)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Retrieve record matching the passed in ID.
|
|
150
|
+
def find(id, options = {})
|
|
151
|
+
raise MethodNotAllowed.new(self, :all) unless self.class.permissions[:read]
|
|
152
|
+
response_xml = @application.http_get(@application.client, "#{url}/#{CGI.escape(id)}", options)
|
|
153
|
+
response = parse_response(response_xml, options)
|
|
154
|
+
result = response.response_items.first if response.response_items.is_a?(Array)
|
|
155
|
+
result.complete_record_downloaded = true if result
|
|
156
|
+
result
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def save_records(records, chunk_size = DEFAULT_RECORDS_PER_BATCH_SAVE)
|
|
160
|
+
no_errors = true
|
|
161
|
+
return false unless records.all?(&:valid?)
|
|
162
|
+
|
|
163
|
+
actions = records.group_by {|o| o.new_record? ? create_method : :http_post }
|
|
164
|
+
actions.each_pair do |http_method, records_for_method|
|
|
165
|
+
records_for_method.each_slice(chunk_size) do |some_records|
|
|
166
|
+
request = to_bulk_xml(some_records)
|
|
167
|
+
response = parse_response(self.send(http_method, request, {:summarizeErrors => false}))
|
|
168
|
+
response.response_items.each_with_index do |record, i|
|
|
169
|
+
if record and record.is_a?(model_class)
|
|
170
|
+
some_records[i].attributes = record.non_calculated_attributes
|
|
171
|
+
some_records[i].errors = record.errors
|
|
172
|
+
no_errors = record.errors.nil? || record.errors.empty? if no_errors
|
|
173
|
+
some_records[i].saved!
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
no_errors
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def batch_save(chunk_size = DEFAULT_RECORDS_PER_BATCH_SAVE)
|
|
183
|
+
@objects = {}
|
|
184
|
+
@allow_batch_operations = true
|
|
185
|
+
|
|
186
|
+
begin
|
|
187
|
+
yield
|
|
188
|
+
|
|
189
|
+
if @objects[model_class]
|
|
190
|
+
objects = @objects[model_class].values.compact
|
|
191
|
+
save_records(objects, chunk_size)
|
|
192
|
+
end
|
|
193
|
+
ensure
|
|
194
|
+
@objects = {}
|
|
195
|
+
@allow_batch_operations = false
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def parse_response(response_xml, options = {})
|
|
200
|
+
Response.parse(response_xml, options) do | response, elements, response_model_name |
|
|
201
|
+
if model_name == response_model_name
|
|
202
|
+
@response = response
|
|
203
|
+
parse_records(response, elements, paged_records_requested?(options), (options[:base_module] || Xeroizer::Record))
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def create_method
|
|
209
|
+
:http_put
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
protected
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def paged_records_requested?(options)
|
|
216
|
+
options.has_key?(:page) and options[:page].to_i >= 0
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Parse the records part of the XML response and builds model instances as necessary.
|
|
220
|
+
def parse_records(response, elements, paged_results, base_module)
|
|
221
|
+
elements.each do | element |
|
|
222
|
+
new_record = model_class.build_from_node(element, self, base_module)
|
|
223
|
+
if element.attribute('status').try(:value) == 'ERROR'
|
|
224
|
+
new_record.errors = []
|
|
225
|
+
element.xpath('.//ValidationError').each do |err|
|
|
226
|
+
new_record.errors << err.text.gsub(/^\s+/, '').gsub(/\s+$/, '')
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
new_record.paged_record_downloaded = paged_results
|
|
230
|
+
response.response_items << new_record
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def to_bulk_xml(records, builder = Builder::XmlMarkup.new(:indent => 2))
|
|
235
|
+
tag = (self.class.optional_xml_root_name || model_name).pluralize
|
|
236
|
+
builder.tag!(tag) do
|
|
237
|
+
records.each {|r| r.to_xml(builder) }
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Parse the response from a create/update request.
|
|
242
|
+
def parse_save_response(response_xml)
|
|
243
|
+
response = parse_response(response_xml)
|
|
244
|
+
record = response.response_items.first if response.response_items.is_a?(Array)
|
|
245
|
+
if record && record.is_a?(self.class)
|
|
246
|
+
@attributes = record.attributes
|
|
247
|
+
end
|
|
248
|
+
self
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
end
|
|
253
|
+
end
|