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.
Files changed (429) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +41 -0
  3. data/README.md +34 -0
  4. data/lib/class_level_inheritable_attributes.rb +28 -0
  5. data/lib/xeroizer.rb +117 -0
  6. data/lib/xeroizer/application_http_proxy.rb +30 -0
  7. data/lib/xeroizer/ca-certificates.crt +2694 -0
  8. data/lib/xeroizer/configuration.rb +19 -0
  9. data/lib/xeroizer/connection.rb +31 -0
  10. data/lib/xeroizer/exceptions.rb +161 -0
  11. data/lib/xeroizer/generic_application.rb +90 -0
  12. data/lib/xeroizer/http.rb +160 -0
  13. data/lib/xeroizer/http_encoding_helper.rb +49 -0
  14. data/lib/xeroizer/http_response.rb +154 -0
  15. data/lib/xeroizer/logging.rb +8 -0
  16. data/lib/xeroizer/models/account.rb +72 -0
  17. data/lib/xeroizer/models/accounts_payable.rb +13 -0
  18. data/lib/xeroizer/models/accounts_receivable.rb +13 -0
  19. data/lib/xeroizer/models/address.rb +41 -0
  20. data/lib/xeroizer/models/allocation.rb +13 -0
  21. data/lib/xeroizer/models/attachment.rb +95 -0
  22. data/lib/xeroizer/models/balances.rb +17 -0
  23. data/lib/xeroizer/models/bank_account.rb +13 -0
  24. data/lib/xeroizer/models/bank_transaction.rb +95 -0
  25. data/lib/xeroizer/models/bank_transfer.rb +28 -0
  26. data/lib/xeroizer/models/batch_payment.rb +24 -0
  27. data/lib/xeroizer/models/batch_payments.rb +14 -0
  28. data/lib/xeroizer/models/bills.rb +13 -0
  29. data/lib/xeroizer/models/branding_theme.rb +62 -0
  30. data/lib/xeroizer/models/contact.rb +77 -0
  31. data/lib/xeroizer/models/contact_group.rb +64 -0
  32. data/lib/xeroizer/models/contact_person.rb +20 -0
  33. data/lib/xeroizer/models/contact_purchases_tracking_category.rb +19 -0
  34. data/lib/xeroizer/models/contact_sales_tracking_category.rb +19 -0
  35. data/lib/xeroizer/models/credit_note.rb +164 -0
  36. data/lib/xeroizer/models/currency.rb +30 -0
  37. data/lib/xeroizer/models/employee.rb +73 -0
  38. data/lib/xeroizer/models/expense_claim.rb +29 -0
  39. data/lib/xeroizer/models/external_link.rb +16 -0
  40. data/lib/xeroizer/models/from_bank_account.rb +13 -0
  41. data/lib/xeroizer/models/invoice.rb +229 -0
  42. data/lib/xeroizer/models/invoice_reminder.rb +19 -0
  43. data/lib/xeroizer/models/item.rb +39 -0
  44. data/lib/xeroizer/models/item_purchase_details.rb +20 -0
  45. data/lib/xeroizer/models/item_sales_details.rb +19 -0
  46. data/lib/xeroizer/models/journal.rb +27 -0
  47. data/lib/xeroizer/models/journal_line.rb +29 -0
  48. data/lib/xeroizer/models/journal_line_tracking_category.rb +21 -0
  49. data/lib/xeroizer/models/line_amount_type.rb +11 -0
  50. data/lib/xeroizer/models/line_item.rb +64 -0
  51. data/lib/xeroizer/models/line_item_sum.rb +21 -0
  52. data/lib/xeroizer/models/manual_journal.rb +49 -0
  53. data/lib/xeroizer/models/manual_journal_line.rb +28 -0
  54. data/lib/xeroizer/models/online_invoice.rb +37 -0
  55. data/lib/xeroizer/models/option.rb +18 -0
  56. data/lib/xeroizer/models/organisation.rb +85 -0
  57. data/lib/xeroizer/models/overpayment.rb +40 -0
  58. data/lib/xeroizer/models/payment.rb +48 -0
  59. data/lib/xeroizer/models/payment_service.rb +22 -0
  60. data/lib/xeroizer/models/payment_terms.rb +16 -0
  61. data/lib/xeroizer/models/payroll/address.rb +53 -0
  62. data/lib/xeroizer/models/payroll/bank_account.rb +35 -0
  63. data/lib/xeroizer/models/payroll/benefit_line.rb +26 -0
  64. data/lib/xeroizer/models/payroll/benefit_type.rb +45 -0
  65. data/lib/xeroizer/models/payroll/deduction_line.rb +32 -0
  66. data/lib/xeroizer/models/payroll/deduction_type.rb +49 -0
  67. data/lib/xeroizer/models/payroll/earnings_line.rb +39 -0
  68. data/lib/xeroizer/models/payroll/earnings_type.rb +53 -0
  69. data/lib/xeroizer/models/payroll/employee.rb +67 -0
  70. data/lib/xeroizer/models/payroll/leave_application.rb +27 -0
  71. data/lib/xeroizer/models/payroll/leave_line.rb +30 -0
  72. data/lib/xeroizer/models/payroll/leave_period.rb +15 -0
  73. data/lib/xeroizer/models/payroll/pay_items.rb +22 -0
  74. data/lib/xeroizer/models/payroll/pay_run.rb +33 -0
  75. data/lib/xeroizer/models/payroll/pay_schedule.rb +40 -0
  76. data/lib/xeroizer/models/payroll/pay_template.rb +24 -0
  77. data/lib/xeroizer/models/payroll/payment_method.rb +24 -0
  78. data/lib/xeroizer/models/payroll/paystub.rb +44 -0
  79. data/lib/xeroizer/models/payroll/reimbursement_line.rb +21 -0
  80. data/lib/xeroizer/models/payroll/reimbursement_type.rb +22 -0
  81. data/lib/xeroizer/models/payroll/salary_and_wage.rb +29 -0
  82. data/lib/xeroizer/models/payroll/super_line.rb +40 -0
  83. data/lib/xeroizer/models/payroll/tax_declaration.rb +50 -0
  84. data/lib/xeroizer/models/payroll/time_off_line.rb +20 -0
  85. data/lib/xeroizer/models/payroll/time_off_type.rb +32 -0
  86. data/lib/xeroizer/models/payroll/work_location.rb +25 -0
  87. data/lib/xeroizer/models/phone.rb +26 -0
  88. data/lib/xeroizer/models/prepayment.rb +41 -0
  89. data/lib/xeroizer/models/purchase_order.rb +49 -0
  90. data/lib/xeroizer/models/receipt.rb +39 -0
  91. data/lib/xeroizer/models/repeating_invoice.rb +80 -0
  92. data/lib/xeroizer/models/sales.rb +13 -0
  93. data/lib/xeroizer/models/schedule.rb +34 -0
  94. data/lib/xeroizer/models/tax_component.rb +13 -0
  95. data/lib/xeroizer/models/tax_rate.rb +36 -0
  96. data/lib/xeroizer/models/to_bank_account.rb +13 -0
  97. data/lib/xeroizer/models/tracking_category.rb +23 -0
  98. data/lib/xeroizer/models/tracking_category_child.rb +20 -0
  99. data/lib/xeroizer/models/user.rb +26 -0
  100. data/lib/xeroizer/oauth.rb +162 -0
  101. data/lib/xeroizer/oauth2.rb +66 -0
  102. data/lib/xeroizer/oauth2_application.rb +42 -0
  103. data/lib/xeroizer/partner_application.rb +52 -0
  104. data/lib/xeroizer/payroll_application.rb +33 -0
  105. data/lib/xeroizer/private_application.rb +26 -0
  106. data/lib/xeroizer/public_application.rb +22 -0
  107. data/lib/xeroizer/record/application_helper.rb +32 -0
  108. data/lib/xeroizer/record/base.rb +203 -0
  109. data/lib/xeroizer/record/base_model.rb +253 -0
  110. data/lib/xeroizer/record/base_model_http_proxy.rb +141 -0
  111. data/lib/xeroizer/record/model_definition_helper.rb +101 -0
  112. data/lib/xeroizer/record/payroll_base.rb +29 -0
  113. data/lib/xeroizer/record/payroll_base_model.rb +29 -0
  114. data/lib/xeroizer/record/record_association_helper.rb +141 -0
  115. data/lib/xeroizer/record/validation_helper.rb +75 -0
  116. data/lib/xeroizer/record/validators/associated_validator.rb +34 -0
  117. data/lib/xeroizer/record/validators/block_validator.rb +22 -0
  118. data/lib/xeroizer/record/validators/inclusion_of_validator.rb +22 -0
  119. data/lib/xeroizer/record/validators/length_of_validator.rb +23 -0
  120. data/lib/xeroizer/record/validators/presence_of_validator.rb +19 -0
  121. data/lib/xeroizer/record/validators/validator.rb +33 -0
  122. data/lib/xeroizer/record/xml_helper.rb +144 -0
  123. data/lib/xeroizer/report/aged_receivables_by_contact.rb +42 -0
  124. data/lib/xeroizer/report/base.rb +42 -0
  125. data/lib/xeroizer/report/cell.rb +32 -0
  126. data/lib/xeroizer/report/cell_xml_helper.rb +74 -0
  127. data/lib/xeroizer/report/factory.rb +54 -0
  128. data/lib/xeroizer/report/row/header.rb +12 -0
  129. data/lib/xeroizer/report/row/row.rb +48 -0
  130. data/lib/xeroizer/report/row/section.rb +10 -0
  131. data/lib/xeroizer/report/row/summary.rb +9 -0
  132. data/lib/xeroizer/report/row/xml_helper.rb +77 -0
  133. data/lib/xeroizer/report/xml_helper.rb +58 -0
  134. data/lib/xeroizer/response.rb +74 -0
  135. data/lib/xeroizer/version.rb +3 -0
  136. data/test/acceptance/about_creating_bank_transactions_test.rb +170 -0
  137. data/test/acceptance/about_creating_prepayment_test.rb +41 -0
  138. data/test/acceptance/about_fetching_bank_transactions_test.rb +53 -0
  139. data/test/acceptance/about_online_invoice_test.rb +25 -0
  140. data/test/acceptance/acceptance_test.rb +77 -0
  141. data/test/acceptance/bank_transaction_reference_data.rb +32 -0
  142. data/test/acceptance/bank_transfer_test.rb +21 -0
  143. data/test/acceptance/bulk_operations_test.rb +50 -0
  144. data/test/acceptance/connections_test.rb +11 -0
  145. data/test/stub_responses/accounts.xml +589 -0
  146. data/test/stub_responses/api_exception.xml +153 -0
  147. data/test/stub_responses/bad_request.json +6 -0
  148. data/test/stub_responses/bogus_oauth_error +1 -0
  149. data/test/stub_responses/branding_themes.xml +20 -0
  150. data/test/stub_responses/connections.json +16 -0
  151. data/test/stub_responses/contact.xml +54 -0
  152. data/test/stub_responses/contact_with_details.xml +79 -0
  153. data/test/stub_responses/contacts.xml +0 -0
  154. data/test/stub_responses/create_credit_note.xml +104 -0
  155. data/test/stub_responses/create_invoice.xml +64 -0
  156. data/test/stub_responses/credit_note.xml +75 -0
  157. data/test/stub_responses/credit_note_not_found_error.xml +1 -0
  158. data/test/stub_responses/credit_notes.xml +169 -0
  159. data/test/stub_responses/currencies.xml +12 -0
  160. data/test/stub_responses/employees.xml +29 -0
  161. data/test/stub_responses/expired_oauth2_token.json +6 -0
  162. data/test/stub_responses/generic_response_error.json +6 -0
  163. data/test/stub_responses/invalid_api_key_error.xml +1 -0
  164. data/test/stub_responses/invalid_consumer_key +1 -0
  165. data/test/stub_responses/invalid_oauth2_request_token.json +6 -0
  166. data/test/stub_responses/invalid_request_token +1 -0
  167. data/test/stub_responses/invalid_tenant_header.json +6 -0
  168. data/test/stub_responses/invoice.xml +84 -0
  169. data/test/stub_responses/invoice_not_found_error.xml +1 -0
  170. data/test/stub_responses/invoices.xml +1899 -0
  171. data/test/stub_responses/items.xml +112 -0
  172. data/test/stub_responses/manual_journal.xml +45 -0
  173. data/test/stub_responses/manual_journals.xml +40 -0
  174. data/test/stub_responses/nonce_used +1 -0
  175. data/test/stub_responses/object_not_found.json +6 -0
  176. data/test/stub_responses/organisation.xml +55 -0
  177. data/test/stub_responses/organisations.xml +35 -0
  178. data/test/stub_responses/payment_service.xml +15 -0
  179. data/test/stub_responses/payments.xml +1121 -0
  180. data/test/stub_responses/prepayments.xml +27 -0
  181. data/test/stub_responses/rate_limit_exceeded +1 -0
  182. data/test/stub_responses/records/contact-043892a1-aef1-4c18-88d8-b8ccb6d31466.xml +38 -0
  183. data/test/stub_responses/records/contact-09664078-efe2-4a88-89a5-67eac9b0047b.xml +40 -0
  184. data/test/stub_responses/records/contact-0a4cf37b-a1a8-4753-9ee2-f9207f63a8ff.xml +48 -0
  185. data/test/stub_responses/records/contact-0e74f929-11b9-4255-a035-1fdfe573e676.xml +40 -0
  186. data/test/stub_responses/records/contact-0f471ca5-15c9-405e-a1b9-7cc35194b673.xml +38 -0
  187. data/test/stub_responses/records/contact-13cd4c47-baa6-4f07-93f6-6442310df4bf.xml +47 -0
  188. data/test/stub_responses/records/contact-158a2667-82ee-43bf-8f33-a6cc9524092d.xml +38 -0
  189. data/test/stub_responses/records/contact-17465072-6fa3-40bf-bc42-97765d9e1bea.xml +38 -0
  190. data/test/stub_responses/records/contact-1975b0ed-b7ba-4c61-bae8-2aa6d78b0dee.xml +39 -0
  191. data/test/stub_responses/records/contact-1b2be6e9-8d58-4da9-aaf8-4fe5471b653c.xml +53 -0
  192. data/test/stub_responses/records/contact-1c40da58-fe1d-4e97-b729-b2abdae94d9e.xml +38 -0
  193. data/test/stub_responses/records/contact-258176a5-c622-4394-9c94-6f88c3ea12e5.xml +40 -0
  194. data/test/stub_responses/records/contact-299dd3a0-a417-4a37-8a04-2f55e91963e5.xml +40 -0
  195. data/test/stub_responses/records/contact-2be39278-5154-4ed1-8eb0-676f25acfc66.xml +40 -0
  196. data/test/stub_responses/records/contact-2e58cff6-488c-4a32-884b-baf848010229.xml +40 -0
  197. data/test/stub_responses/records/contact-2faccd41-935e-40aa-b74e-e2fc28ac34c3.xml +38 -0
  198. data/test/stub_responses/records/contact-31af01e7-2ca7-45b9-a500-b02db996568e.xml +38 -0
  199. data/test/stub_responses/records/contact-344f1113-a25b-4344-b82e-bedeacc17c8e.xml +40 -0
  200. data/test/stub_responses/records/contact-3e776c4b-ea9e-4bb1-96be-6b0c7a71a37f.xml +39 -0
  201. data/test/stub_responses/records/contact-3fc1fc6c-e5ff-4e40-b6f3-7eb535637d87.xml +38 -0
  202. data/test/stub_responses/records/contact-416ab20c-5357-4beb-a740-e8d175d71efb.xml +38 -0
  203. data/test/stub_responses/records/contact-41a42865-f15a-4fa1-b643-47877608f557.xml +54 -0
  204. data/test/stub_responses/records/contact-42771b60-19a7-4692-af81-dd9f9b9362d4.xml +43 -0
  205. data/test/stub_responses/records/contact-451ceb28-9610-44c9-8f35-3225482f2413.xml +40 -0
  206. data/test/stub_responses/records/contact-4ab343ad-1ebb-4afe-9d48-1814a93c2081.xml +38 -0
  207. data/test/stub_responses/records/contact-4bb77692-42d4-4565-85a0-8849eb85e039.xml +39 -0
  208. data/test/stub_responses/records/contact-4dec292f-3ab7-46a8-83e4-5fb5eac42c7f.xml +40 -0
  209. data/test/stub_responses/records/contact-4e2f192e-8397-4d4d-97ca-a4fc5ac531bf.xml +38 -0
  210. data/test/stub_responses/records/contact-5188c17c-7786-4436-ad6e-9da2997386d0.xml +40 -0
  211. data/test/stub_responses/records/contact-52442753-b1c4-40b7-9b79-c33997de5837.xml +40 -0
  212. data/test/stub_responses/records/contact-565acaa9-e7f3-4fbf-80c3-16b081ddae10.xml +38 -0
  213. data/test/stub_responses/records/contact-571a2414-81ff-4f8f-8498-d91d83793131.xml +44 -0
  214. data/test/stub_responses/records/contact-58697449-85ef-46ae-83fc-6a9446f037fb.xml +40 -0
  215. data/test/stub_responses/records/contact-58bf2ae3-5144-4628-8de2-e165ac2bcdc6.xml +40 -0
  216. data/test/stub_responses/records/contact-5d41dafd-eb7e-42c1-bd5a-ba3be1da0960.xml +38 -0
  217. data/test/stub_responses/records/contact-5f005a09-5ce4-4fb4-8096-e69c18be636e.xml +38 -0
  218. data/test/stub_responses/records/contact-60d578d9-3e10-4aef-b5dc-9d9fd60a3633.xml +47 -0
  219. data/test/stub_responses/records/contact-62392126-dba4-4a75-b907-5875ebf75259.xml +40 -0
  220. data/test/stub_responses/records/contact-642c7fb5-e8e5-48e1-a710-39a18c6c3217.xml +40 -0
  221. data/test/stub_responses/records/contact-64aebf9c-bb89-4b38-b99b-405bd1ece6fd.xml +40 -0
  222. data/test/stub_responses/records/contact-64eedbc9-1fa0-485a-837f-705f23188161.xml +38 -0
  223. data/test/stub_responses/records/contact-65e96c9f-1595-4653-9a8a-2a36d49223c2.xml +40 -0
  224. data/test/stub_responses/records/contact-67d26b93-ccb4-4890-9bf1-284b70ea755d.xml +38 -0
  225. data/test/stub_responses/records/contact-69d3e538-44b3-4e00-a5f6-7dddcb6e0656.xml +40 -0
  226. data/test/stub_responses/records/contact-6a8450bc-f81a-4bb0-a8f6-aa4afe9497c7.xml +40 -0
  227. data/test/stub_responses/records/contact-6c70e424-41d6-4b9b-af3e-b3a9f3589106.xml +40 -0
  228. data/test/stub_responses/records/contact-6de0b0cf-560c-4503-aab3-e1543c329deb.xml +54 -0
  229. data/test/stub_responses/records/contact-72dd6a02-396e-42a2-a4d6-cc3fa75dfece.xml +41 -0
  230. data/test/stub_responses/records/contact-755f1475-d255-43a8-bedc-5ea7fd26c71f.xml +51 -0
  231. data/test/stub_responses/records/contact-78a9d0a0-3d8c-4f84-af3e-f260bf4a9dc0.xml +38 -0
  232. data/test/stub_responses/records/contact-79aa39ca-22b0-42c2-9026-78757a29d665.xml +42 -0
  233. data/test/stub_responses/records/contact-804f4140-5978-48fe-ba20-b56e5b834b18.xml +40 -0
  234. data/test/stub_responses/records/contact-812d4f28-1681-4241-8e34-d15c5520ba35.xml +38 -0
  235. data/test/stub_responses/records/contact-860b99a9-0958-4c8d-a98f-bb1f092b16bb.xml +60 -0
  236. data/test/stub_responses/records/contact-87c8da45-97cc-46be-b170-398da0eacfb8.xml +40 -0
  237. data/test/stub_responses/records/contact-8a154a19-6c6c-404b-bbc9-6deae2d18251.xml +38 -0
  238. data/test/stub_responses/records/contact-8bb6931d-2865-44e9-9a23-ed1fb9c7a46c.xml +40 -0
  239. data/test/stub_responses/records/contact-936c9759-01da-4063-b472-424ab9f48212.xml +38 -0
  240. data/test/stub_responses/records/contact-9d12a994-9640-4b75-95cc-3de1e9d0ef09.xml +38 -0
  241. data/test/stub_responses/records/contact-9fe59245-1fbb-4157-93c3-dc97388f3746.xml +40 -0
  242. data/test/stub_responses/records/contact-a06a7225-6f8a-4522-8400-c534dd43a16e.xml +40 -0
  243. data/test/stub_responses/records/contact-a76a85fe-73a2-46fa-aba7-791f36103cdb.xml +40 -0
  244. data/test/stub_responses/records/contact-a93b5f40-0346-4d21-9181-431e129911c0.xml +40 -0
  245. data/test/stub_responses/records/contact-abf272dd-6b1d-4829-af88-c57bf55855e3.xml +38 -0
  246. data/test/stub_responses/records/contact-ad24c33b-256b-4157-ad56-cbcf0e8db7b1.xml +47 -0
  247. data/test/stub_responses/records/contact-b107129d-f4c9-438e-9573-64b778527f4a.xml +40 -0
  248. data/test/stub_responses/records/contact-b233288a-aa26-4b26-9fc7-779d797dd56f.xml +40 -0
  249. data/test/stub_responses/records/contact-b2b5333a-2546-4975-891f-d71a8a640d23.xml +38 -0
  250. data/test/stub_responses/records/contact-b4d149bf-1823-4bd2-96da-9032388c9686.xml +40 -0
  251. data/test/stub_responses/records/contact-b78d4fd1-4306-4d83-a0b9-61458d1c53a2.xml +40 -0
  252. data/test/stub_responses/records/contact-b7d108a8-d5f7-4f16-a7c9-26eaed98e8de.xml +40 -0
  253. data/test/stub_responses/records/contact-baeed0f3-7989-4874-99b3-59f23032cb73.xml +38 -0
  254. data/test/stub_responses/records/contact-bc51a3a1-b7f6-46ca-ac9e-19b87e6ca100.xml +40 -0
  255. data/test/stub_responses/records/contact-be9f3aab-52f5-4d9c-94b4-87f7d9e5ee8b.xml +38 -0
  256. data/test/stub_responses/records/contact-c135f994-01e4-427b-9e15-acfe8a477c16.xml +49 -0
  257. data/test/stub_responses/records/contact-c14edf75-15e4-4a9c-86e4-f52e2fe7cfa4.xml +40 -0
  258. data/test/stub_responses/records/contact-ca9b9abc-c2dc-4221-8101-31f464d314cc.xml +44 -0
  259. data/test/stub_responses/records/contact-cc4db604-9ed8-4eef-8a29-51b5b70496a0.xml +38 -0
  260. data/test/stub_responses/records/contact-cce9b044-be4a-43b3-9dc7-c027d8dd35b2.xml +38 -0
  261. data/test/stub_responses/records/contact-d0cd2c4f-18a0-4f7c-a32a-2db00f29d298.xml +43 -0
  262. data/test/stub_responses/records/contact-d6851dc2-9ed9-4515-bc0b-810b09c06a6a.xml +38 -0
  263. data/test/stub_responses/records/contact-d6a384fb-f46f-41a3-8ac7-b7bc9e0b5efa.xml +46 -0
  264. data/test/stub_responses/records/contact-d74e61cf-2ad0-4f0d-b9d1-6a808e3f70cf.xml +40 -0
  265. data/test/stub_responses/records/contact-d9ab0f61-3b56-4e2b-be39-f33c11bd99e3.xml +40 -0
  266. data/test/stub_responses/records/contact-dbb1f0b5-a71b-4458-8462-104acd0fec6b.xml +38 -0
  267. data/test/stub_responses/records/contact-dd981bd6-40dd-496d-a282-bf7d3391b8b9.xml +40 -0
  268. data/test/stub_responses/records/contact-e1826204-cc0a-42a5-a6d0-4b352d9d5953.xml +40 -0
  269. data/test/stub_responses/records/contact-e2d955db-f366-42dd-87f7-fbdb4da2306f.xml +40 -0
  270. data/test/stub_responses/records/contact-e32e2130-3d27-443a-8313-48fffa03cf53.xml +40 -0
  271. data/test/stub_responses/records/contact-e3a68332-d322-4816-8678-73a537c8cd33.xml +38 -0
  272. data/test/stub_responses/records/contact-e6ac76a3-ca32-4fa1-8ef9-6a4bf8b0ec2a.xml +40 -0
  273. data/test/stub_responses/records/contact-e6ca965d-7c48-480e-be39-e847307f474a.xml +38 -0
  274. data/test/stub_responses/records/contact-e77d1f20-2e8e-46ec-9a10-50335a216724.xml +40 -0
  275. data/test/stub_responses/records/contact-e8b98c13-a424-41d2-ba0e-7b7621411e7a.xml +38 -0
  276. data/test/stub_responses/records/contact-e8e9a2c2-3e7e-48ed-8528-c3d61b28f276.xml +39 -0
  277. data/test/stub_responses/records/contact-eb43fcc6-87ec-4a0a-b243-d718bee4e2cb.xml +38 -0
  278. data/test/stub_responses/records/contact-ef6f54c1-eb45-4956-b8cd-1be82ad665f2.xml +43 -0
  279. data/test/stub_responses/records/contact-efdb3600-f233-42e2-8f18-ce7e2a95e4b1.xml +38 -0
  280. data/test/stub_responses/records/contact-f7eca431-5c97-4d24-93fd-004bb8a6c644.xml +40 -0
  281. data/test/stub_responses/records/contact-fb078879-5d6d-474f-825f-61dc90689349.xml +38 -0
  282. data/test/stub_responses/records/contact-fc39b273-4aa2-4785-99ca-24672f6c0000.xml +38 -0
  283. data/test/stub_responses/records/contact-fc9ec3a6-a2fe-4300-a8cb-ca8a0b3662e0.xml +40 -0
  284. data/test/stub_responses/records/contact-fdf96102-7491-44b6-bf4d-7a77ff25f890.xml +40 -0
  285. data/test/stub_responses/records/contact-fe61ead1-8afc-4f0b-beda-066620227aad.xml +38 -0
  286. data/test/stub_responses/records/credit_note-371cd138-1e5c-4ec1-a8c6-a1c10e8bdab1.xml +73 -0
  287. data/test/stub_responses/records/credit_note-3bffc09b-79f2-490d-b91b-c59b700b43a4.xml +95 -0
  288. data/test/stub_responses/records/credit_note-43c678ee-f357-48e2-b192-b6e3634762f9.xml +94 -0
  289. data/test/stub_responses/records/credit_note-482c018b-d329-4e05-9b4f-7a4cfc695aa0.xml +77 -0
  290. data/test/stub_responses/records/credit_note-4f67130a-749a-4ee6-98b2-743adbc11245.xml +62 -0
  291. data/test/stub_responses/records/credit_note-50e98404-2fba-4031-af67-8ba4bb227c44.xml +77 -0
  292. data/test/stub_responses/records/credit_note-7df8949c-b71f-40c0-bbcf-39f2f450f286.xml +75 -0
  293. data/test/stub_responses/records/credit_note-b356e488-2678-4be4-ad4b-d294df2d48d6.xml +78 -0
  294. data/test/stub_responses/records/invoice-0032f627-3156-4d30-9b1c-4d3b994dc921.xml +84 -0
  295. data/test/stub_responses/records/invoice-00c9511b-24b9-4190-a90a-8abf2fe9f4a0.xml +76 -0
  296. data/test/stub_responses/records/invoice-024d7994-a26c-4c20-9894-13934840fc31.xml +74 -0
  297. data/test/stub_responses/records/invoice-0e64a623-c2a1-446a-93ed-eb897f118cbc.xml +97 -0
  298. data/test/stub_responses/records/invoice-15e88e57-2554-4496-a18e-eb3f5c622345.xml +75 -0
  299. data/test/stub_responses/records/invoice-166f0588-d0ba-458c-b28a-8edd4c8fc463.xml +75 -0
  300. data/test/stub_responses/records/invoice-1d1ba340-afa2-4f4c-8ff7-a147bda9a47b.xml +93 -0
  301. data/test/stub_responses/records/invoice-290ef4c4-baec-492b-b4dd-c102826470ae.xml +87 -0
  302. data/test/stub_responses/records/invoice-30a87092-31b5-4a2c-831e-327486533dd2.xml +79 -0
  303. data/test/stub_responses/records/invoice-30dbd181-72a8-43df-b392-4241bf43d5fc.xml +79 -0
  304. data/test/stub_responses/records/invoice-33e4123e-7cdd-4f05-9a0a-eb8adeb2b868.xml +94 -0
  305. data/test/stub_responses/records/invoice-387db692-26ac-47e6-b6cc-015343809bda.xml +75 -0
  306. data/test/stub_responses/records/invoice-3b28bf11-ed2f-4cf4-8e9e-fcae730cc292.xml +91 -0
  307. data/test/stub_responses/records/invoice-3fcb9847-b350-412e-ab90-7d9d774ad881.xml +91 -0
  308. data/test/stub_responses/records/invoice-440613e4-4785-4eff-9ba1-c432816cf8c7.xml +78 -0
  309. data/test/stub_responses/records/invoice-4602eda6-abe9-448e-b65f-ae6bea21f0eb.xml +98 -0
  310. data/test/stub_responses/records/invoice-46441f63-873f-4cdc-a278-b8fe516f3abb.xml +94 -0
  311. data/test/stub_responses/records/invoice-4ad1ec01-f4a3-41d7-bbb4-d2ab2fec8e65.xml +74 -0
  312. data/test/stub_responses/records/invoice-4b9afceb-f7c7-4e64-8aac-7b009971fd52.xml +86 -0
  313. data/test/stub_responses/records/invoice-4edbf6d5-4e92-43af-bedd-7effc0b86833.xml +70 -0
  314. data/test/stub_responses/records/invoice-4fad1af2-b871-4ac5-a15a-3c5e32d2e2c4.xml +93 -0
  315. data/test/stub_responses/records/invoice-52ee4d67-cae4-462c-adb2-182c39017f3d.xml +83 -0
  316. data/test/stub_responses/records/invoice-54585f46-c1a0-4432-bd4f-c1fae2fba59b.xml +67 -0
  317. data/test/stub_responses/records/invoice-5613938b-9e27-472e-92ae-3b038b669d10.xml +87 -0
  318. data/test/stub_responses/records/invoice-5aa9451d-95d1-4f95-a966-bbab2573f71c.xml +75 -0
  319. data/test/stub_responses/records/invoice-5aadcd34-01a9-4b8d-a2bb-d7cc1de9fa45.xml +89 -0
  320. data/test/stub_responses/records/invoice-5f6deadf-36a2-495a-9980-ceb11e8af9a9.xml +85 -0
  321. data/test/stub_responses/records/invoice-625ffe1b-f5d8-438e-a376-981de5f5a733.xml +77 -0
  322. data/test/stub_responses/records/invoice-64cd559e-8e03-46af-b461-8555285cee71.xml +86 -0
  323. data/test/stub_responses/records/invoice-666f8dbb-bc9a-476c-8ec4-4665d7f83190.xml +63 -0
  324. data/test/stub_responses/records/invoice-66fbe37f-49b1-43fd-97ed-85114022cd2f.xml +79 -0
  325. data/test/stub_responses/records/invoice-673dd7cc-beb7-4697-83d4-0c47cb400cc2.xml +95 -0
  326. data/test/stub_responses/records/invoice-69fc971e-9b37-41c5-9c87-174330f22343.xml +66 -0
  327. data/test/stub_responses/records/invoice-70e6db69-e5a4-42c7-a397-aa3212c2945f.xml +75 -0
  328. data/test/stub_responses/records/invoice-762aa45d-4632-45b5-8087-b4f47690665e.xml +54 -0
  329. data/test/stub_responses/records/invoice-766d1289-b440-4675-a656-1a0612ecac77.xml +76 -0
  330. data/test/stub_responses/records/invoice-76bcb361-f93b-4513-b312-5a4af306d276.xml +67 -0
  331. data/test/stub_responses/records/invoice-76e3f056-479f-417c-a72b-f3d767899b87.xml +91 -0
  332. data/test/stub_responses/records/invoice-77b338ef-ecc0-4b95-a0d7-2617b0054611.xml +114 -0
  333. data/test/stub_responses/records/invoice-7be9956d-5316-4f6b-a66a-d355b3f159b2.xml +84 -0
  334. data/test/stub_responses/records/invoice-7dae876a-b424-436b-a4e6-17b3fdeec80c.xml +91 -0
  335. data/test/stub_responses/records/invoice-7e862d93-8dab-4856-8b0c-d844e09d750f.xml +68 -0
  336. data/test/stub_responses/records/invoice-803f70b0-56d9-4157-9787-41df271777a0.xml +84 -0
  337. data/test/stub_responses/records/invoice-86102312-aa3f-438c-9938-6840f4d8dda6.xml +75 -0
  338. data/test/stub_responses/records/invoice-8694c9c5-7097-4449-a708-b8c1982921a4.xml +69 -0
  339. data/test/stub_responses/records/invoice-86d6e00f-ef56-49f7-9a54-796ccd5ca057.xml +85 -0
  340. data/test/stub_responses/records/invoice-88e77f0f-54a5-4efc-a979-7e22223cc4d7.xml +66 -0
  341. data/test/stub_responses/records/invoice-8b0ccb6a-d9b7-4da5-8360-ef7fb157b5aa.xml +66 -0
  342. data/test/stub_responses/records/invoice-935fc854-8037-4111-8d91-993010c331cc.xml +74 -0
  343. data/test/stub_responses/records/invoice-95ef3000-c764-4ba9-a66a-b6e2d161f839.xml +62 -0
  344. data/test/stub_responses/records/invoice-962ef33f-c9d2-4602-9b9f-93a02bea23b3.xml +93 -0
  345. data/test/stub_responses/records/invoice-9868b472-1983-48e9-8edf-7e81ddf2c03a.xml +85 -0
  346. data/test/stub_responses/records/invoice-9a448e9b-a9fa-4a8b-98f5-6dc892a37374.xml +62 -0
  347. data/test/stub_responses/records/invoice-a1d04a14-96a8-4067-a0ff-8136990a354f.xml +91 -0
  348. data/test/stub_responses/records/invoice-a3bc62ef-f11b-4a9c-a4f9-a342bda371b5.xml +66 -0
  349. data/test/stub_responses/records/invoice-a6894ca0-60ee-4d45-9dd4-b44fcba46ec5.xml +90 -0
  350. data/test/stub_responses/records/invoice-a77268ce-74b2-483d-a2b3-70dbdc9e49d2.xml +78 -0
  351. data/test/stub_responses/records/invoice-a9f765e6-b9bc-4505-a47b-fb3ecb327e7b.xml +88 -0
  352. data/test/stub_responses/records/invoice-aa0173af-8707-4e7f-8dde-4c7a357bd312.xml +109 -0
  353. data/test/stub_responses/records/invoice-ab63738a-370a-43a5-bfa3-620d684e66d0.xml +83 -0
  354. data/test/stub_responses/records/invoice-b0344791-5a8a-40dd-a208-d99a461a6c10.xml +84 -0
  355. data/test/stub_responses/records/invoice-b1e53910-473c-46a3-b3cb-38ece571220e.xml +76 -0
  356. data/test/stub_responses/records/invoice-b2c02d0b-41a8-4d4d-97d7-014c78b3547d.xml +93 -0
  357. data/test/stub_responses/records/invoice-b75b3928-ab72-4424-8b93-9cdbbde4cd72.xml +90 -0
  358. data/test/stub_responses/records/invoice-bcd8a71f-aa31-4d0f-8a01-13ea26363ddf.xml +94 -0
  359. data/test/stub_responses/records/invoice-bfbb7c45-de02-45e7-b065-d9863ecfb0d8.xml +66 -0
  360. data/test/stub_responses/records/invoice-c12aff7e-12bf-4185-8702-460929f19674.xml +77 -0
  361. data/test/stub_responses/records/invoice-c3380b96-976d-4b3e-8b26-8d01eb6a3742.xml +87 -0
  362. data/test/stub_responses/records/invoice-c963f2b0-cbe1-4abd-9ccc-7e512c942068.xml +67 -0
  363. data/test/stub_responses/records/invoice-cba46b29-3788-4158-b668-ab10160ccbfe.xml +78 -0
  364. data/test/stub_responses/records/invoice-d62646b9-d0a9-4fdb-9561-756a8b7eba45.xml +63 -0
  365. data/test/stub_responses/records/invoice-dba2f021-f149-4191-a126-5351d587ab0e.xml +75 -0
  366. data/test/stub_responses/records/invoice-de5d9c29-21b3-4342-958b-ed72c4bd7ab0.xml +108 -0
  367. data/test/stub_responses/records/invoice-e3d96555-2876-4364-a46a-7551a4f52611.xml +123 -0
  368. data/test/stub_responses/records/invoice-e4a0afbd-aea0-450b-ae23-0ce921e84a77.xml +102 -0
  369. data/test/stub_responses/records/invoice-e9cb9ecb-58ef-43a8-bd20-69a85338142d.xml +76 -0
  370. data/test/stub_responses/records/invoice-ec9a6f67-7128-4a63-8ba3-5e516f455f9b.xml +94 -0
  371. data/test/stub_responses/records/invoice-ed0f2587-84fc-4aef-bc4b-b1a262e24484.xml +81 -0
  372. data/test/stub_responses/records/invoice-f362ca53-8ade-4047-865a-bb64bee5863d.xml +74 -0
  373. data/test/stub_responses/records/invoice-f571c38b-5be1-41e1-ad5a-ff6184284beb.xml +114 -0
  374. data/test/stub_responses/records/invoice-f5832195-5cd3-4660-ad3f-b73d9c64f263.xml +85 -0
  375. data/test/stub_responses/records/invoice-f9c857eb-64cd-4235-a078-d04b52c77ea7.xml +76 -0
  376. data/test/stub_responses/records/manual_journal-4765d07b-aa03-4e56-9166-50661958c864.xml +38 -0
  377. data/test/stub_responses/records/manual_journal-53fc5558-5b76-4ecd-ae5c-c4af3ccde87c.xml +31 -0
  378. data/test/stub_responses/records/manual_journal-bb6cfcfc-4500-4475-bd3a-93ee512428e0.xml +31 -0
  379. data/test/stub_responses/records/manual_journal-f00a355b-7374-445c-886b-0437bea4095c.xml +45 -0
  380. data/test/stub_responses/records/prepayment-7d3619b1-82cc-405b-8f44-9d4f9a787a8a.xml +92 -0
  381. data/test/stub_responses/records/repeating_invoice-ad3550bc-1ae0-45c0-a782-48c6d2061127.xml +43 -0
  382. data/test/stub_responses/refresh_responses.rb +29 -0
  383. data/test/stub_responses/repeating_invoices.xml +43 -0
  384. data/test/stub_responses/reports/trial_balance.xml +1435 -0
  385. data/test/stub_responses/tax_rates.xml +198 -0
  386. data/test/stub_responses/token_expired +1 -0
  387. data/test/stub_responses/tracking_categories.xml +27 -0
  388. data/test/stub_responses/unknown_error.xml +1 -0
  389. data/test/stub_responses/users.xml +17 -0
  390. data/test/test_helper.rb +72 -0
  391. data/test/unit/generic_application_test.rb +52 -0
  392. data/test/unit/http_test.rb +302 -0
  393. data/test/unit/models/address_test.rb +92 -0
  394. data/test/unit/models/bank_transaction_model_parsing_test.rb +133 -0
  395. data/test/unit/models/bank_transaction_test.rb +44 -0
  396. data/test/unit/models/bank_transaction_validation_test.rb +115 -0
  397. data/test/unit/models/contact_test.rb +132 -0
  398. data/test/unit/models/credit_note_test.rb +37 -0
  399. data/test/unit/models/employee_test.rb +43 -0
  400. data/test/unit/models/invoice_test.rb +133 -0
  401. data/test/unit/models/journal_line_test.rb +22 -0
  402. data/test/unit/models/journal_test.rb +44 -0
  403. data/test/unit/models/line_item_sum_test.rb +25 -0
  404. data/test/unit/models/line_item_test.rb +59 -0
  405. data/test/unit/models/manual_journal_test.rb +25 -0
  406. data/test/unit/models/organisation_test.rb +52 -0
  407. data/test/unit/models/payment_service_test.rb +29 -0
  408. data/test/unit/models/phone_test.rb +31 -0
  409. data/test/unit/models/prepayment_test.rb +21 -0
  410. data/test/unit/models/repeating_invoice_test.rb +36 -0
  411. data/test/unit/models/tax_rate_test.rb +132 -0
  412. data/test/unit/oauth2_test.rb +171 -0
  413. data/test/unit/oauth_config_test.rb +20 -0
  414. data/test/unit/oauth_test.rb +179 -0
  415. data/test/unit/private_application_test.rb +20 -0
  416. data/test/unit/record/base_model_test.rb +58 -0
  417. data/test/unit/record/base_test.rb +174 -0
  418. data/test/unit/record/block_validator_test.rb +125 -0
  419. data/test/unit/record/connection_test.rb +60 -0
  420. data/test/unit/record/model_definition_test.rb +165 -0
  421. data/test/unit/record/parse_params_test.rb +59 -0
  422. data/test/unit/record/parse_where_hash_test.rb +63 -0
  423. data/test/unit/record/record_association_test.rb +93 -0
  424. data/test/unit/record/validators_test.rb +228 -0
  425. data/test/unit/record_definition_test.rb +27 -0
  426. data/test/unit/report_definition_test.rb +26 -0
  427. data/test/unit/report_test.rb +154 -0
  428. data/test/unit_test_helper.rb +16 -0
  429. metadata +1024 -0
@@ -0,0 +1,141 @@
1
+ require 'xeroizer/application_http_proxy'
2
+
3
+ module Xeroizer
4
+ module Record
5
+ module BaseModelHttpProxy
6
+
7
+ def self.included(base)
8
+ base.send :include, Xeroizer::ApplicationHttpProxy
9
+ base.send :include, InstanceMethods
10
+ end
11
+
12
+ module InstanceMethods
13
+
14
+ protected
15
+
16
+ # Parse parameters for GET requests.
17
+ def parse_params(options)
18
+ params = {}
19
+ params[:ModifiedAfter] = options[:modified_since] if options[:modified_since]
20
+ params[:includeArchived] = options[:include_archived] if options[:include_archived]
21
+ params[:order] = options[:order] if options[:order]
22
+ params[:createdByMyApp] = options[:createdByMyApp] if options[:createdByMyApp]
23
+
24
+ params[:IDs] = filterize(options[:IDs]) if options[:IDs]
25
+ params[:InvoiceNumbers] = filterize(options[:InvoiceNumbers]) if options[:InvoiceNumbers]
26
+ params[:ContactIDs] = filterize(options[:ContactIDs]) if options[:ContactIDs]
27
+ params[:Statuses] = filterize(options[:Statuses]) if options[:Statuses]
28
+
29
+ if options[:where]
30
+ params[:where] = case options[:where]
31
+ when String then options[:where]
32
+ when Hash then parse_where_hash(options[:where])
33
+ end
34
+ end
35
+ params[:offset] = options[:offset] if options[:offset]
36
+ params[:Status] = options[:status] if options[:status]
37
+ params[:DateFrom] = options[:date_from] if options[:date_from]
38
+ params[:DateTo] = options[:date_to] if options[:date_to]
39
+ params[:page] = options[:page] if options[:page]
40
+ params
41
+ end
42
+
43
+ # Parse the :where part of the options for GET parameters and construct a valid
44
+ # .Net version of the criteria to pass to Xero.
45
+ #
46
+ # Attribute names can be modified as follows to change the expression used:
47
+ # {attribute_name}_is_greater_than or {attribute_name}> uses '>'
48
+ # {attribute_name}_is_greater_than_or_equal_to or {attribute_name}>= uses '>='
49
+ # {attribute_name}_is_less_than or {attribute_name}< uses '<'
50
+ # {attribute_name}_is_less_than_or_equal_to or {attribute_name}< uses '<='
51
+ # DEFAULT: '=='
52
+ def parse_where_hash(where)
53
+ conditions = []
54
+ where.each do | key, value |
55
+ (attribute_name, expression) = extract_expression_from_attribute_name(key)
56
+ (_, field) = model_class.fields.find { | k, v | v[:internal_name] == attribute_name }
57
+ if field
58
+ conditions << where_condition_part(field, expression, value)
59
+ else
60
+ raise InvalidAttributeInWhere.new(model_name, attribute_name)
61
+ end
62
+ end
63
+ conditions.map { | (attr, expression, value) | "#{attr}#{expression}#{value}"}.join('&&')
64
+ end
65
+
66
+ # Extract the attribute name and expression from the attribute.
67
+ #
68
+ # @return [Array] containing [actual_attribute_name, expression]
69
+ def extract_expression_from_attribute_name(key)
70
+ case key.to_s
71
+ when /(_is_not|\<\>)$/
72
+ [
73
+ key.to_s.gsub(/(_is_not|\<\>)$/, '').to_sym,
74
+ '<>'
75
+ ]
76
+
77
+ when /(_is_greater_than|\>)$/
78
+ [
79
+ key.to_s.gsub(/(_is_greater_than|\>)$/, '').to_sym,
80
+ '>'
81
+ ]
82
+
83
+ when /(_is_greater_than_or_equal_to|\>\=)$/
84
+ [
85
+ key.to_s.gsub(/(_is_greater_than_or_equal_to|\>\=)$/, '').to_sym,
86
+ '>='
87
+ ]
88
+
89
+ when /(_is_less_than|\<)$/
90
+ [
91
+ key.to_s.gsub(/(_is_less_than|\<)$/, '').to_sym,
92
+ '<'
93
+ ]
94
+
95
+ when /(_is_less_than_or_equal_to|\<\=)$/
96
+ [
97
+ key.to_s.gsub(/(_is_less_than_or_equal_to|\<\=)$/, '').to_sym,
98
+ '<='
99
+ ]
100
+
101
+ else
102
+ [key, '==']
103
+
104
+ end
105
+ end
106
+
107
+ # Creates a condition part array containing the:
108
+ # * Field's API name
109
+ # * Expression
110
+ # * .Net formatted value.
111
+ def where_condition_part(field, expression, value)
112
+ case field[:type]
113
+ when :guid then ["#{field[:api_name]}.ToString()", expression, "\"#{value}\""]
114
+ when :string then [field[:api_name], expression, "\"#{value}\""]
115
+ when :boolean then [field[:api_name], expression, value ? 'true' : 'false']
116
+ when :integer then [field[:api_name], expression, value.to_s]
117
+ when :decimal then [field[:api_name], expression, value.to_s]
118
+ when :date then [field[:api_name], expression, "DateTime.Parse(\"#{value.strftime("%Y-%m-%d")}\")"]
119
+ when :datetime then [field[:api_name], expression, "DateTime.Parse(\"#{value.utc.strftime("%Y-%m-%dT%H:%M:%S")}\")"]
120
+ when :datetime_utc then [field[:api_name], expression, "DateTime.Parse(\"#{value.utc.strftime("%Y-%m-%dT%H:%M:%S")}\")"]
121
+ when :belongs_to then
122
+ when :has_many then
123
+ when :has_one then
124
+ end
125
+ end
126
+
127
+ private
128
+
129
+ # Filtering params expect a comma separated list of strings
130
+ def filterize(values)
131
+ case values
132
+ when String then values
133
+ when Array then values.join(',')
134
+ end
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,101 @@
1
+ module Xeroizer
2
+ module Record
3
+ module ModelDefinitionHelper
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ base.send :include, InstanceMethods
8
+ end
9
+
10
+ module ClassMethods
11
+
12
+ # Possible primary keys. At least one of these must exist before attempting to update a record.
13
+ def set_possible_primary_keys(*args)
14
+ args = [args] unless args.is_a?(Array)
15
+ self.possible_primary_keys = args
16
+ end
17
+
18
+ # Set the actual Xero primary key for this record.
19
+ def set_primary_key(primary_key_name)
20
+ self.primary_key_name = primary_key_name
21
+ end
22
+
23
+ # Whether this record type's list results contain summary data only.
24
+ #
25
+ # Records like invoices, when returning a list, only show summary data for
26
+ # certain types of associations (like the contact record) and do not return
27
+ # any data for line items.
28
+ #
29
+ # Default: false
30
+ def list_contains_summary_only(status)
31
+ self.summary_only = status
32
+ end
33
+
34
+ def list_contains_summary_only?
35
+ !!summary_only
36
+ end
37
+
38
+ # Helper methods used to define the fields this model has.
39
+ def string(field_name, options = {}); define_simple_attribute(field_name, :string, options); end
40
+ def boolean(field_name, options = {}); define_simple_attribute(field_name, :boolean, options); end
41
+ def integer(field_name, options = {}); define_simple_attribute(field_name, :integer, options, 0); end
42
+ def decimal(field_name, options = {}); define_simple_attribute(field_name, :decimal, options, 0.0); end
43
+ def date(field_name, options = {}); define_simple_attribute(field_name, :date, options); end
44
+ def datetime(field_name, options = {}); define_simple_attribute(field_name, :datetime, options); end
45
+ def datetime_utc(field_name, options = {}); define_simple_attribute(field_name, :datetime_utc, options); end
46
+
47
+ def guid(field_name, options = {})
48
+ # Ensure all automated Id conversions are changed to ID.
49
+ options[:api_name] ||= field_name.to_s.camelize.gsub(/Id/, 'ID')
50
+ define_simple_attribute(field_name, :guid, options)
51
+ end
52
+
53
+ # Helper method to simplify field definition.
54
+ # Creates an accessor and reader for the field.
55
+ # Options:
56
+ # :internal_name => allows the specification of an internal field name differing from the API's field name.
57
+ # :api_name => allows the API name to be specified if it can't be properly converted from camelize.
58
+ # :model_name => allows class used for children to be different from it's ndoe name in the XML.
59
+ # :type => type of field
60
+ # :skip_writer => skip the writer method
61
+ def define_simple_attribute(field_name, field_type, options, value_if_nil = nil)
62
+ self.fields ||= {}
63
+
64
+ internal_field_name = options[:internal_name] || field_name
65
+ self.fields[field_name] = options.merge({
66
+ :internal_name => internal_field_name,
67
+ :api_name => options[:api_name] || field_name.to_s.camelize,
68
+ :type => field_type
69
+ })
70
+ define_method internal_field_name do
71
+ @attributes[field_name].nil? ? value_if_nil : @attributes[field_name]
72
+ end
73
+
74
+ unless options[:skip_writer]
75
+ define_method "#{internal_field_name}=".to_sym do | value |
76
+ parent.mark_dirty(self) if parent
77
+ @attributes[field_name] = value
78
+ end
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ module InstanceMethods
85
+
86
+ # Returns the value of the Xero primary key for this record if it exists.
87
+ def id
88
+ self[self.class.primary_key_name]
89
+ end
90
+
91
+ # Sets the value of the Xero primary key for this record if it exists.
92
+ def id=(new_id)
93
+ parent.mark_dirty(self) if parent
94
+ self[self.class.primary_key_name] = new_id
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,29 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class PayrollBase < Xeroizer::Record::Base
5
+
6
+ class_inheritable_attributes :fields, :possible_primary_keys, :primary_key_name, :summary_only, :validators
7
+
8
+ def self.belongs_to(field_name, options = {})
9
+ super(field_name, {:base_module => Xeroizer::Record::Payroll}.merge(options))
10
+ end
11
+
12
+ def self.has_many(field_name, options = {})
13
+ super(field_name, {:base_module => Xeroizer::Record::Payroll}.merge(options))
14
+ end
15
+
16
+ def self.has_one(field_name, options = {})
17
+ super(field_name, {:base_module => Xeroizer::Record::Payroll}.merge(options))
18
+ end
19
+
20
+ public
21
+
22
+ def new_model_class(model_name)
23
+ Xeroizer::Record::Payroll.const_get("#{model_name}Model".to_sym).new(parent.application, model_name.to_s)
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ require 'xeroizer/record/base_model_http_proxy'
2
+
3
+ module Xeroizer
4
+ module Record
5
+
6
+ class PayrollBaseModel < Xeroizer::Record::BaseModel
7
+
8
+ class_inheritable_attributes :api_controller_name
9
+ class_inheritable_attributes :permissions
10
+ class_inheritable_attributes :xml_root_name
11
+ class_inheritable_attributes :optional_xml_root_name
12
+ class_inheritable_attributes :xml_node_name
13
+
14
+ include BaseModelHttpProxy
15
+
16
+ public
17
+
18
+ def model_class
19
+ @model_class ||= Xeroizer::Record::Payroll.const_get(model_name.to_sym)
20
+ end
21
+
22
+ def parse_response(response_xml, options = {})
23
+ super(response_xml, {:base_module => Xeroizer::Record::Payroll}.merge(options))
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,141 @@
1
+ module Xeroizer
2
+ module Record
3
+ module RecordAssociationHelper
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def belongs_to(field_name, options = {})
12
+ internal_field_name = options[:internal_name] || field_name
13
+ internal_singular_field_name = options[:internal_name_singular] || internal_field_name.to_s.singularize
14
+
15
+ define_association_attribute(field_name, internal_singular_field_name, :belongs_to, options)
16
+
17
+ # Create a #build_record_name method to build the record.
18
+ define_method "build_#{internal_singular_field_name}" do | *args |
19
+ attributes = args.size == 1 ? args.first : {}
20
+
21
+ # The name of the record model.
22
+ model_name = options[:model_name] ? options[:model_name].to_sym : field_name.to_s.singularize.camelize.to_sym
23
+
24
+ # The record's parent instance for this current application.
25
+ model_parent = new_model_class(model_name)
26
+
27
+ # Create a new record, binding it to it's parent instance.
28
+ record = (options[:base_module] || Xeroizer::Record).const_get(model_name).build(attributes, model_parent)
29
+ self.attributes[field_name] = record
30
+ end
31
+ end
32
+
33
+ alias_method :has_one, :belongs_to
34
+
35
+ def has_many(field_name, options = {})
36
+ internal_field_name = options[:internal_name] || field_name
37
+ internal_singular_field_name = options[:internal_name_singular] || internal_field_name.to_s.singularize
38
+
39
+ define_association_attribute(field_name, internal_field_name, :has_many, options)
40
+
41
+ # Create an #add_record_name method to build the record and add to the attributes.
42
+ define_method "add_#{internal_singular_field_name}" do | *args |
43
+ # The name of the record model.
44
+ model_name = options[:model_name] ? options[:model_name].to_sym : field_name.to_s.singularize.camelize.to_sym
45
+
46
+ # The record's parent instance for this current application.
47
+ model_parent = new_model_class(model_name)
48
+
49
+ # The class of this record.
50
+ record_class = (options[:base_module] || Xeroizer::Record).const_get(model_name)
51
+
52
+ # Parse the *args variable so that we can use this method like:
53
+ # add_record({fields}, {fields}, ...)
54
+ # add_record(record_one, record_two, ...)
55
+ # add_record([{fields}, {fields}], ...)
56
+ # add_record(key => val, key2 => val)
57
+ records = []
58
+ if args.size == 1 && args.first.is_a?(Array)
59
+ records = args.first
60
+ elsif args.size > 0
61
+ records = args
62
+ else
63
+ raise XeroizerError.new("Invalid arguments for #{self.class.name}#add_#{internal_singular_field_name}(#{args.inspect}).")
64
+ end
65
+
66
+ # Ensure that complete record is downloaded before adding new records
67
+ self.send(internal_field_name)
68
+
69
+ # Add each record.
70
+ last_record = nil
71
+ records.each do | record |
72
+ record = record_class.build(record, model_parent) if record.is_a?(Hash)
73
+ raise XeroizerError.new("Record #{record.class.name} is not a #{record_class.name}.") unless record.is_a?(record_class)
74
+ self.attributes[field_name] ||= []
75
+ self.attributes[field_name] << record
76
+ last_record = record
77
+ end
78
+
79
+ last_record # last record
80
+ end
81
+
82
+ end
83
+
84
+ def define_association_attribute(field_name, internal_field_name, association_type, options)
85
+ define_simple_attribute(field_name, association_type, options.merge!(:skip_writer => true), ((association_type == :has_many) ? [] : nil))
86
+
87
+ internal_field_name = options[:internal_name] || field_name
88
+ internal_singular_field_name = options[:internal_name_singular] || internal_field_name.to_s.singularize
89
+ model_name = options[:model_name] ? options[:model_name].to_sym : field_name.to_s.singularize.camelize.to_sym
90
+ define_method "#{internal_field_name}=".to_sym do | value |
91
+ record_class = (options[:base_module] || Xeroizer::Record).const_get(model_name)
92
+ case value
93
+ when Hash
94
+ self.attributes[field_name] = ((association_type == :has_many) ? [] : nil)
95
+ case association_type
96
+ when :has_many
97
+ self.attributes[field_name] = []
98
+ self.send("add_#{internal_singular_field_name}".to_sym, value)
99
+
100
+ when :belongs_to
101
+ self.attributes[field_name] = (options[:base_module] || Xeroizer::Record).const_get(model_name).build(value, new_model_class(model_name))
102
+
103
+ end
104
+
105
+ when Array
106
+ self.attributes[field_name] = ((association_type == :has_many) ? [] : nil)
107
+ value.each do | single_value |
108
+ case single_value
109
+ when Hash then send("add_#{internal_singular_field_name}".to_sym, single_value)
110
+ when record_class then self.attributes[field_name] << single_value
111
+ else raise AssociationTypeMismatch.new(record_class, single_value.class)
112
+ end
113
+ end
114
+
115
+ when record_class
116
+ self.attributes[field_name] = ((association_type == :has_many) ? [value] : value)
117
+
118
+ when NilClass
119
+ self.attributes[field_name] = []
120
+
121
+ else
122
+ raise AssociationTypeMismatch.new(record_class, value.class)
123
+ end
124
+ end
125
+
126
+ # Override reader for this association if this association belongs
127
+ # to a summary-typed record. This will automatically attempt to download
128
+ # the complete version of the record before accessing the association.
129
+ if list_contains_summary_only?
130
+ define_method internal_field_name do
131
+ download_complete_record! unless new_record? || options[:list_complete] || options[:complete_on_page] && paged_record_downloaded? || complete_record_downloaded?
132
+ self.attributes[field_name] || ((association_type == :has_many) ? [] : nil)
133
+ end
134
+ end
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,75 @@
1
+ Dir.foreach(File.join(File.dirname(__FILE__), 'validators/')) { | file | require File.join(File.dirname(__FILE__), "validators/#{file}") if file =~ /\.rb$/ }
2
+
3
+ module Xeroizer
4
+ module Record
5
+ module ValidationHelper
6
+
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ base.send :include, InstanceMethods
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ # Adds a validator config for each attribute specified in args.
15
+ def validates_with_validator(validator, args)
16
+ options = args.extract_options!
17
+
18
+ self.validators ||= []
19
+ args.flatten.each do | attribute |
20
+ self.validators << validator.new(attribute, options)
21
+ end
22
+ end
23
+
24
+ def validates_associated(*args)
25
+ validates_with_validator(Validator::AssociatedValidator, args)
26
+ end
27
+
28
+ def validates_inclusion_of(*args)
29
+ validates_with_validator(Validator::InclusionOfValidator, args)
30
+ end
31
+
32
+ def validates_presence_of(*args)
33
+ validates_with_validator(Validator::PresenceOfValidator, args)
34
+ end
35
+
36
+ def validates_length_of(*args)
37
+ validates_with_validator(Validator::LengthOfValidator, args)
38
+ end
39
+
40
+ def validates(*args, &block)
41
+ fail "Block required" unless block_given?
42
+
43
+ if args.last.is_a? Hash
44
+ args.last[:block] = block
45
+ else
46
+ args << { :block => block }
47
+ end
48
+
49
+ validates_with_validator(Validator::BlockValidator, args)
50
+ end
51
+ end
52
+
53
+ module InstanceMethods
54
+
55
+ def valid?
56
+ @errors = []
57
+ if self.class.validators
58
+ self.class.validators.each do | validator |
59
+ validator.validate(self)
60
+ end
61
+ end
62
+ @errors.size == 0
63
+ end
64
+
65
+ def errors_for(attribute)
66
+ if errors.is_a?(Array)
67
+ errors.find_all { | (attr, _) | attr == attribute }.map { | (_, msg) | msg }
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
75
+ end