xeroizer-float 2.15.3.1

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 (337) hide show
  1. data/.bundle/config +2 -0
  2. data/.gitattributes +22 -0
  3. data/Gemfile +19 -0
  4. data/Gemfile.lock +57 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +529 -0
  7. data/Rakefile +55 -0
  8. data/VERSION +1 -0
  9. data/lib/big_decimal_to_s.rb +9 -0
  10. data/lib/class_level_inheritable_attributes.rb +25 -0
  11. data/lib/xeroizer.rb +64 -0
  12. data/lib/xeroizer/application_http_proxy.rb +30 -0
  13. data/lib/xeroizer/ca-certificates.crt +2642 -0
  14. data/lib/xeroizer/configuration.rb +19 -0
  15. data/lib/xeroizer/exceptions.rb +129 -0
  16. data/lib/xeroizer/generic_application.rb +54 -0
  17. data/lib/xeroizer/http.rb +167 -0
  18. data/lib/xeroizer/http_encoding_helper.rb +49 -0
  19. data/lib/xeroizer/logging.rb +8 -0
  20. data/lib/xeroizer/models/account.rb +67 -0
  21. data/lib/xeroizer/models/address.rb +32 -0
  22. data/lib/xeroizer/models/bank_account.rb +12 -0
  23. data/lib/xeroizer/models/bank_transaction.rb +75 -0
  24. data/lib/xeroizer/models/branding_theme.rb +22 -0
  25. data/lib/xeroizer/models/contact.rb +49 -0
  26. data/lib/xeroizer/models/contact_group.rb +16 -0
  27. data/lib/xeroizer/models/credit_note.rb +130 -0
  28. data/lib/xeroizer/models/currency.rb +18 -0
  29. data/lib/xeroizer/models/employee.rb +28 -0
  30. data/lib/xeroizer/models/external_link.rb +16 -0
  31. data/lib/xeroizer/models/invoice.rb +192 -0
  32. data/lib/xeroizer/models/item.rb +27 -0
  33. data/lib/xeroizer/models/item_purchase_details.rb +19 -0
  34. data/lib/xeroizer/models/item_sales_details.rb +19 -0
  35. data/lib/xeroizer/models/journal.rb +25 -0
  36. data/lib/xeroizer/models/journal_line.rb +28 -0
  37. data/lib/xeroizer/models/journal_line_tracking_category.rb +20 -0
  38. data/lib/xeroizer/models/line_amount_type.rb +11 -0
  39. data/lib/xeroizer/models/line_item.rb +40 -0
  40. data/lib/xeroizer/models/line_item_sum.rb +21 -0
  41. data/lib/xeroizer/models/manual_journal.rb +42 -0
  42. data/lib/xeroizer/models/manual_journal_line.rb +27 -0
  43. data/lib/xeroizer/models/option.rb +18 -0
  44. data/lib/xeroizer/models/organisation.rb +34 -0
  45. data/lib/xeroizer/models/payment.rb +42 -0
  46. data/lib/xeroizer/models/phone.rb +25 -0
  47. data/lib/xeroizer/models/tax_rate.rb +25 -0
  48. data/lib/xeroizer/models/tracking_category.rb +23 -0
  49. data/lib/xeroizer/models/tracking_category_child.rb +20 -0
  50. data/lib/xeroizer/oauth.rb +130 -0
  51. data/lib/xeroizer/partner_application.rb +46 -0
  52. data/lib/xeroizer/private_application.rb +27 -0
  53. data/lib/xeroizer/public_application.rb +21 -0
  54. data/lib/xeroizer/record/application_helper.rb +32 -0
  55. data/lib/xeroizer/record/base.rb +155 -0
  56. data/lib/xeroizer/record/base_model.rb +144 -0
  57. data/lib/xeroizer/record/base_model_http_proxy.rb +117 -0
  58. data/lib/xeroizer/record/model_definition_helper.rb +99 -0
  59. data/lib/xeroizer/record/record_association_helper.rb +140 -0
  60. data/lib/xeroizer/record/validation_helper.rb +71 -0
  61. data/lib/xeroizer/record/validators/associated_validator.rb +33 -0
  62. data/lib/xeroizer/record/validators/block_validator.rb +22 -0
  63. data/lib/xeroizer/record/validators/inclusion_of_validator.rb +22 -0
  64. data/lib/xeroizer/record/validators/presence_of_validator.rb +19 -0
  65. data/lib/xeroizer/record/validators/validator.rb +33 -0
  66. data/lib/xeroizer/record/xml_helper.rb +133 -0
  67. data/lib/xeroizer/report/aged_receivables_by_contact.rb +43 -0
  68. data/lib/xeroizer/report/base.rb +43 -0
  69. data/lib/xeroizer/report/cell.rb +32 -0
  70. data/lib/xeroizer/report/cell_xml_helper.rb +74 -0
  71. data/lib/xeroizer/report/factory.rb +53 -0
  72. data/lib/xeroizer/report/row/header.rb +12 -0
  73. data/lib/xeroizer/report/row/row.rb +48 -0
  74. data/lib/xeroizer/report/row/section.rb +10 -0
  75. data/lib/xeroizer/report/row/summary.rb +9 -0
  76. data/lib/xeroizer/report/row/xml_helper.rb +77 -0
  77. data/lib/xeroizer/report/xml_helper.rb +58 -0
  78. data/lib/xeroizer/response.rb +55 -0
  79. data/test/acceptance/about_creating_bank_transactions_test.rb +162 -0
  80. data/test/acceptance/about_fetching_bank_transactions_test.rb +56 -0
  81. data/test/acceptance/acceptance_test.rb +53 -0
  82. data/test/acceptance/bank_transaction_reference_data.rb +31 -0
  83. data/test/stub_responses/accounts.xml +589 -0
  84. data/test/stub_responses/api_exception.xml +153 -0
  85. data/test/stub_responses/bogus_oauth_error +1 -0
  86. data/test/stub_responses/branding_themes.xml +20 -0
  87. data/test/stub_responses/contact.xml +40 -0
  88. data/test/stub_responses/contacts.xml +0 -0
  89. data/test/stub_responses/create_credit_note.xml +104 -0
  90. data/test/stub_responses/create_invoice.xml +64 -0
  91. data/test/stub_responses/credit_note.xml +75 -0
  92. data/test/stub_responses/credit_note_not_found_error.xml +1 -0
  93. data/test/stub_responses/credit_notes.xml +169 -0
  94. data/test/stub_responses/currencies.xml +12 -0
  95. data/test/stub_responses/employees.xml +29 -0
  96. data/test/stub_responses/invalid_api_key_error.xml +1 -0
  97. data/test/stub_responses/invalid_consumer_key +1 -0
  98. data/test/stub_responses/invalid_request_token +1 -0
  99. data/test/stub_responses/invoice.xml +84 -0
  100. data/test/stub_responses/invoice_not_found_error.xml +1 -0
  101. data/test/stub_responses/invoices.xml +1899 -0
  102. data/test/stub_responses/items.xml +112 -0
  103. data/test/stub_responses/manual_journal.xml +45 -0
  104. data/test/stub_responses/manual_journals.xml +40 -0
  105. data/test/stub_responses/organisation.xml +25 -0
  106. data/test/stub_responses/organisations.xml +25 -0
  107. data/test/stub_responses/payments.xml +1121 -0
  108. data/test/stub_responses/rate_limit_exceeded +1 -0
  109. data/test/stub_responses/records/contact-043892a1-aef1-4c18-88d8-b8ccb6d31466.xml +38 -0
  110. data/test/stub_responses/records/contact-09664078-efe2-4a88-89a5-67eac9b0047b.xml +40 -0
  111. data/test/stub_responses/records/contact-0a4cf37b-a1a8-4753-9ee2-f9207f63a8ff.xml +48 -0
  112. data/test/stub_responses/records/contact-0e74f929-11b9-4255-a035-1fdfe573e676.xml +40 -0
  113. data/test/stub_responses/records/contact-0f471ca5-15c9-405e-a1b9-7cc35194b673.xml +38 -0
  114. data/test/stub_responses/records/contact-13cd4c47-baa6-4f07-93f6-6442310df4bf.xml +47 -0
  115. data/test/stub_responses/records/contact-158a2667-82ee-43bf-8f33-a6cc9524092d.xml +38 -0
  116. data/test/stub_responses/records/contact-17465072-6fa3-40bf-bc42-97765d9e1bea.xml +38 -0
  117. data/test/stub_responses/records/contact-1975b0ed-b7ba-4c61-bae8-2aa6d78b0dee.xml +39 -0
  118. data/test/stub_responses/records/contact-1b2be6e9-8d58-4da9-aaf8-4fe5471b653c.xml +53 -0
  119. data/test/stub_responses/records/contact-1c40da58-fe1d-4e97-b729-b2abdae94d9e.xml +38 -0
  120. data/test/stub_responses/records/contact-258176a5-c622-4394-9c94-6f88c3ea12e5.xml +40 -0
  121. data/test/stub_responses/records/contact-299dd3a0-a417-4a37-8a04-2f55e91963e5.xml +40 -0
  122. data/test/stub_responses/records/contact-2be39278-5154-4ed1-8eb0-676f25acfc66.xml +40 -0
  123. data/test/stub_responses/records/contact-2e58cff6-488c-4a32-884b-baf848010229.xml +40 -0
  124. data/test/stub_responses/records/contact-2faccd41-935e-40aa-b74e-e2fc28ac34c3.xml +38 -0
  125. data/test/stub_responses/records/contact-31af01e7-2ca7-45b9-a500-b02db996568e.xml +38 -0
  126. data/test/stub_responses/records/contact-344f1113-a25b-4344-b82e-bedeacc17c8e.xml +40 -0
  127. data/test/stub_responses/records/contact-3e776c4b-ea9e-4bb1-96be-6b0c7a71a37f.xml +39 -0
  128. data/test/stub_responses/records/contact-3fc1fc6c-e5ff-4e40-b6f3-7eb535637d87.xml +38 -0
  129. data/test/stub_responses/records/contact-416ab20c-5357-4beb-a740-e8d175d71efb.xml +38 -0
  130. data/test/stub_responses/records/contact-41a42865-f15a-4fa1-b643-47877608f557.xml +54 -0
  131. data/test/stub_responses/records/contact-42771b60-19a7-4692-af81-dd9f9b9362d4.xml +43 -0
  132. data/test/stub_responses/records/contact-451ceb28-9610-44c9-8f35-3225482f2413.xml +40 -0
  133. data/test/stub_responses/records/contact-4ab343ad-1ebb-4afe-9d48-1814a93c2081.xml +38 -0
  134. data/test/stub_responses/records/contact-4bb77692-42d4-4565-85a0-8849eb85e039.xml +39 -0
  135. data/test/stub_responses/records/contact-4dec292f-3ab7-46a8-83e4-5fb5eac42c7f.xml +40 -0
  136. data/test/stub_responses/records/contact-4e2f192e-8397-4d4d-97ca-a4fc5ac531bf.xml +38 -0
  137. data/test/stub_responses/records/contact-5188c17c-7786-4436-ad6e-9da2997386d0.xml +40 -0
  138. data/test/stub_responses/records/contact-52442753-b1c4-40b7-9b79-c33997de5837.xml +40 -0
  139. data/test/stub_responses/records/contact-565acaa9-e7f3-4fbf-80c3-16b081ddae10.xml +38 -0
  140. data/test/stub_responses/records/contact-571a2414-81ff-4f8f-8498-d91d83793131.xml +44 -0
  141. data/test/stub_responses/records/contact-58697449-85ef-46ae-83fc-6a9446f037fb.xml +40 -0
  142. data/test/stub_responses/records/contact-58bf2ae3-5144-4628-8de2-e165ac2bcdc6.xml +40 -0
  143. data/test/stub_responses/records/contact-5d41dafd-eb7e-42c1-bd5a-ba3be1da0960.xml +38 -0
  144. data/test/stub_responses/records/contact-5f005a09-5ce4-4fb4-8096-e69c18be636e.xml +38 -0
  145. data/test/stub_responses/records/contact-60d578d9-3e10-4aef-b5dc-9d9fd60a3633.xml +47 -0
  146. data/test/stub_responses/records/contact-62392126-dba4-4a75-b907-5875ebf75259.xml +40 -0
  147. data/test/stub_responses/records/contact-642c7fb5-e8e5-48e1-a710-39a18c6c3217.xml +40 -0
  148. data/test/stub_responses/records/contact-64aebf9c-bb89-4b38-b99b-405bd1ece6fd.xml +40 -0
  149. data/test/stub_responses/records/contact-64eedbc9-1fa0-485a-837f-705f23188161.xml +38 -0
  150. data/test/stub_responses/records/contact-65e96c9f-1595-4653-9a8a-2a36d49223c2.xml +40 -0
  151. data/test/stub_responses/records/contact-67d26b93-ccb4-4890-9bf1-284b70ea755d.xml +38 -0
  152. data/test/stub_responses/records/contact-69d3e538-44b3-4e00-a5f6-7dddcb6e0656.xml +40 -0
  153. data/test/stub_responses/records/contact-6a8450bc-f81a-4bb0-a8f6-aa4afe9497c7.xml +40 -0
  154. data/test/stub_responses/records/contact-6c70e424-41d6-4b9b-af3e-b3a9f3589106.xml +40 -0
  155. data/test/stub_responses/records/contact-6de0b0cf-560c-4503-aab3-e1543c329deb.xml +54 -0
  156. data/test/stub_responses/records/contact-72dd6a02-396e-42a2-a4d6-cc3fa75dfece.xml +41 -0
  157. data/test/stub_responses/records/contact-755f1475-d255-43a8-bedc-5ea7fd26c71f.xml +51 -0
  158. data/test/stub_responses/records/contact-78a9d0a0-3d8c-4f84-af3e-f260bf4a9dc0.xml +38 -0
  159. data/test/stub_responses/records/contact-79aa39ca-22b0-42c2-9026-78757a29d665.xml +42 -0
  160. data/test/stub_responses/records/contact-804f4140-5978-48fe-ba20-b56e5b834b18.xml +40 -0
  161. data/test/stub_responses/records/contact-812d4f28-1681-4241-8e34-d15c5520ba35.xml +38 -0
  162. data/test/stub_responses/records/contact-860b99a9-0958-4c8d-a98f-bb1f092b16bb.xml +60 -0
  163. data/test/stub_responses/records/contact-87c8da45-97cc-46be-b170-398da0eacfb8.xml +40 -0
  164. data/test/stub_responses/records/contact-8a154a19-6c6c-404b-bbc9-6deae2d18251.xml +38 -0
  165. data/test/stub_responses/records/contact-8bb6931d-2865-44e9-9a23-ed1fb9c7a46c.xml +40 -0
  166. data/test/stub_responses/records/contact-936c9759-01da-4063-b472-424ab9f48212.xml +38 -0
  167. data/test/stub_responses/records/contact-9d12a994-9640-4b75-95cc-3de1e9d0ef09.xml +38 -0
  168. data/test/stub_responses/records/contact-9fe59245-1fbb-4157-93c3-dc97388f3746.xml +40 -0
  169. data/test/stub_responses/records/contact-a06a7225-6f8a-4522-8400-c534dd43a16e.xml +40 -0
  170. data/test/stub_responses/records/contact-a76a85fe-73a2-46fa-aba7-791f36103cdb.xml +40 -0
  171. data/test/stub_responses/records/contact-a93b5f40-0346-4d21-9181-431e129911c0.xml +40 -0
  172. data/test/stub_responses/records/contact-abf272dd-6b1d-4829-af88-c57bf55855e3.xml +38 -0
  173. data/test/stub_responses/records/contact-ad24c33b-256b-4157-ad56-cbcf0e8db7b1.xml +47 -0
  174. data/test/stub_responses/records/contact-b107129d-f4c9-438e-9573-64b778527f4a.xml +40 -0
  175. data/test/stub_responses/records/contact-b233288a-aa26-4b26-9fc7-779d797dd56f.xml +40 -0
  176. data/test/stub_responses/records/contact-b2b5333a-2546-4975-891f-d71a8a640d23.xml +38 -0
  177. data/test/stub_responses/records/contact-b4d149bf-1823-4bd2-96da-9032388c9686.xml +40 -0
  178. data/test/stub_responses/records/contact-b78d4fd1-4306-4d83-a0b9-61458d1c53a2.xml +40 -0
  179. data/test/stub_responses/records/contact-b7d108a8-d5f7-4f16-a7c9-26eaed98e8de.xml +40 -0
  180. data/test/stub_responses/records/contact-baeed0f3-7989-4874-99b3-59f23032cb73.xml +38 -0
  181. data/test/stub_responses/records/contact-bc51a3a1-b7f6-46ca-ac9e-19b87e6ca100.xml +40 -0
  182. data/test/stub_responses/records/contact-be9f3aab-52f5-4d9c-94b4-87f7d9e5ee8b.xml +38 -0
  183. data/test/stub_responses/records/contact-c135f994-01e4-427b-9e15-acfe8a477c16.xml +49 -0
  184. data/test/stub_responses/records/contact-c14edf75-15e4-4a9c-86e4-f52e2fe7cfa4.xml +40 -0
  185. data/test/stub_responses/records/contact-ca9b9abc-c2dc-4221-8101-31f464d314cc.xml +44 -0
  186. data/test/stub_responses/records/contact-cc4db604-9ed8-4eef-8a29-51b5b70496a0.xml +38 -0
  187. data/test/stub_responses/records/contact-cce9b044-be4a-43b3-9dc7-c027d8dd35b2.xml +38 -0
  188. data/test/stub_responses/records/contact-d0cd2c4f-18a0-4f7c-a32a-2db00f29d298.xml +43 -0
  189. data/test/stub_responses/records/contact-d6851dc2-9ed9-4515-bc0b-810b09c06a6a.xml +38 -0
  190. data/test/stub_responses/records/contact-d6a384fb-f46f-41a3-8ac7-b7bc9e0b5efa.xml +46 -0
  191. data/test/stub_responses/records/contact-d74e61cf-2ad0-4f0d-b9d1-6a808e3f70cf.xml +40 -0
  192. data/test/stub_responses/records/contact-d9ab0f61-3b56-4e2b-be39-f33c11bd99e3.xml +40 -0
  193. data/test/stub_responses/records/contact-dbb1f0b5-a71b-4458-8462-104acd0fec6b.xml +38 -0
  194. data/test/stub_responses/records/contact-dd981bd6-40dd-496d-a282-bf7d3391b8b9.xml +40 -0
  195. data/test/stub_responses/records/contact-e1826204-cc0a-42a5-a6d0-4b352d9d5953.xml +40 -0
  196. data/test/stub_responses/records/contact-e2d955db-f366-42dd-87f7-fbdb4da2306f.xml +40 -0
  197. data/test/stub_responses/records/contact-e32e2130-3d27-443a-8313-48fffa03cf53.xml +40 -0
  198. data/test/stub_responses/records/contact-e3a68332-d322-4816-8678-73a537c8cd33.xml +38 -0
  199. data/test/stub_responses/records/contact-e6ac76a3-ca32-4fa1-8ef9-6a4bf8b0ec2a.xml +40 -0
  200. data/test/stub_responses/records/contact-e6ca965d-7c48-480e-be39-e847307f474a.xml +38 -0
  201. data/test/stub_responses/records/contact-e77d1f20-2e8e-46ec-9a10-50335a216724.xml +40 -0
  202. data/test/stub_responses/records/contact-e8b98c13-a424-41d2-ba0e-7b7621411e7a.xml +38 -0
  203. data/test/stub_responses/records/contact-e8e9a2c2-3e7e-48ed-8528-c3d61b28f276.xml +39 -0
  204. data/test/stub_responses/records/contact-eb43fcc6-87ec-4a0a-b243-d718bee4e2cb.xml +38 -0
  205. data/test/stub_responses/records/contact-ef6f54c1-eb45-4956-b8cd-1be82ad665f2.xml +43 -0
  206. data/test/stub_responses/records/contact-efdb3600-f233-42e2-8f18-ce7e2a95e4b1.xml +38 -0
  207. data/test/stub_responses/records/contact-f7eca431-5c97-4d24-93fd-004bb8a6c644.xml +40 -0
  208. data/test/stub_responses/records/contact-fb078879-5d6d-474f-825f-61dc90689349.xml +38 -0
  209. data/test/stub_responses/records/contact-fc39b273-4aa2-4785-99ca-24672f6c0000.xml +38 -0
  210. data/test/stub_responses/records/contact-fc9ec3a6-a2fe-4300-a8cb-ca8a0b3662e0.xml +40 -0
  211. data/test/stub_responses/records/contact-fdf96102-7491-44b6-bf4d-7a77ff25f890.xml +40 -0
  212. data/test/stub_responses/records/contact-fe61ead1-8afc-4f0b-beda-066620227aad.xml +38 -0
  213. data/test/stub_responses/records/credit_note-371cd138-1e5c-4ec1-a8c6-a1c10e8bdab1.xml +73 -0
  214. data/test/stub_responses/records/credit_note-3bffc09b-79f2-490d-b91b-c59b700b43a4.xml +95 -0
  215. data/test/stub_responses/records/credit_note-43c678ee-f357-48e2-b192-b6e3634762f9.xml +94 -0
  216. data/test/stub_responses/records/credit_note-482c018b-d329-4e05-9b4f-7a4cfc695aa0.xml +77 -0
  217. data/test/stub_responses/records/credit_note-4f67130a-749a-4ee6-98b2-743adbc11245.xml +62 -0
  218. data/test/stub_responses/records/credit_note-50e98404-2fba-4031-af67-8ba4bb227c44.xml +77 -0
  219. data/test/stub_responses/records/credit_note-7df8949c-b71f-40c0-bbcf-39f2f450f286.xml +75 -0
  220. data/test/stub_responses/records/credit_note-b356e488-2678-4be4-ad4b-d294df2d48d6.xml +78 -0
  221. data/test/stub_responses/records/invoice-0032f627-3156-4d30-9b1c-4d3b994dc921.xml +84 -0
  222. data/test/stub_responses/records/invoice-00c9511b-24b9-4190-a90a-8abf2fe9f4a0.xml +76 -0
  223. data/test/stub_responses/records/invoice-024d7994-a26c-4c20-9894-13934840fc31.xml +74 -0
  224. data/test/stub_responses/records/invoice-0e64a623-c2a1-446a-93ed-eb897f118cbc.xml +97 -0
  225. data/test/stub_responses/records/invoice-15e88e57-2554-4496-a18e-eb3f5c622345.xml +75 -0
  226. data/test/stub_responses/records/invoice-166f0588-d0ba-458c-b28a-8edd4c8fc463.xml +75 -0
  227. data/test/stub_responses/records/invoice-1d1ba340-afa2-4f4c-8ff7-a147bda9a47b.xml +93 -0
  228. data/test/stub_responses/records/invoice-290ef4c4-baec-492b-b4dd-c102826470ae.xml +87 -0
  229. data/test/stub_responses/records/invoice-30a87092-31b5-4a2c-831e-327486533dd2.xml +79 -0
  230. data/test/stub_responses/records/invoice-30dbd181-72a8-43df-b392-4241bf43d5fc.xml +79 -0
  231. data/test/stub_responses/records/invoice-33e4123e-7cdd-4f05-9a0a-eb8adeb2b868.xml +94 -0
  232. data/test/stub_responses/records/invoice-387db692-26ac-47e6-b6cc-015343809bda.xml +75 -0
  233. data/test/stub_responses/records/invoice-3b28bf11-ed2f-4cf4-8e9e-fcae730cc292.xml +91 -0
  234. data/test/stub_responses/records/invoice-3fcb9847-b350-412e-ab90-7d9d774ad881.xml +91 -0
  235. data/test/stub_responses/records/invoice-440613e4-4785-4eff-9ba1-c432816cf8c7.xml +78 -0
  236. data/test/stub_responses/records/invoice-4602eda6-abe9-448e-b65f-ae6bea21f0eb.xml +98 -0
  237. data/test/stub_responses/records/invoice-46441f63-873f-4cdc-a278-b8fe516f3abb.xml +94 -0
  238. data/test/stub_responses/records/invoice-4ad1ec01-f4a3-41d7-bbb4-d2ab2fec8e65.xml +74 -0
  239. data/test/stub_responses/records/invoice-4b9afceb-f7c7-4e64-8aac-7b009971fd52.xml +86 -0
  240. data/test/stub_responses/records/invoice-4edbf6d5-4e92-43af-bedd-7effc0b86833.xml +70 -0
  241. data/test/stub_responses/records/invoice-4fad1af2-b871-4ac5-a15a-3c5e32d2e2c4.xml +93 -0
  242. data/test/stub_responses/records/invoice-52ee4d67-cae4-462c-adb2-182c39017f3d.xml +83 -0
  243. data/test/stub_responses/records/invoice-54585f46-c1a0-4432-bd4f-c1fae2fba59b.xml +67 -0
  244. data/test/stub_responses/records/invoice-5613938b-9e27-472e-92ae-3b038b669d10.xml +87 -0
  245. data/test/stub_responses/records/invoice-5aa9451d-95d1-4f95-a966-bbab2573f71c.xml +75 -0
  246. data/test/stub_responses/records/invoice-5aadcd34-01a9-4b8d-a2bb-d7cc1de9fa45.xml +89 -0
  247. data/test/stub_responses/records/invoice-5f6deadf-36a2-495a-9980-ceb11e8af9a9.xml +85 -0
  248. data/test/stub_responses/records/invoice-625ffe1b-f5d8-438e-a376-981de5f5a733.xml +77 -0
  249. data/test/stub_responses/records/invoice-64cd559e-8e03-46af-b461-8555285cee71.xml +86 -0
  250. data/test/stub_responses/records/invoice-666f8dbb-bc9a-476c-8ec4-4665d7f83190.xml +63 -0
  251. data/test/stub_responses/records/invoice-66fbe37f-49b1-43fd-97ed-85114022cd2f.xml +79 -0
  252. data/test/stub_responses/records/invoice-673dd7cc-beb7-4697-83d4-0c47cb400cc2.xml +95 -0
  253. data/test/stub_responses/records/invoice-69fc971e-9b37-41c5-9c87-174330f22343.xml +66 -0
  254. data/test/stub_responses/records/invoice-70e6db69-e5a4-42c7-a397-aa3212c2945f.xml +75 -0
  255. data/test/stub_responses/records/invoice-762aa45d-4632-45b5-8087-b4f47690665e.xml +54 -0
  256. data/test/stub_responses/records/invoice-766d1289-b440-4675-a656-1a0612ecac77.xml +76 -0
  257. data/test/stub_responses/records/invoice-76bcb361-f93b-4513-b312-5a4af306d276.xml +67 -0
  258. data/test/stub_responses/records/invoice-76e3f056-479f-417c-a72b-f3d767899b87.xml +91 -0
  259. data/test/stub_responses/records/invoice-77b338ef-ecc0-4b95-a0d7-2617b0054611.xml +114 -0
  260. data/test/stub_responses/records/invoice-7be9956d-5316-4f6b-a66a-d355b3f159b2.xml +84 -0
  261. data/test/stub_responses/records/invoice-7dae876a-b424-436b-a4e6-17b3fdeec80c.xml +91 -0
  262. data/test/stub_responses/records/invoice-7e862d93-8dab-4856-8b0c-d844e09d750f.xml +68 -0
  263. data/test/stub_responses/records/invoice-803f70b0-56d9-4157-9787-41df271777a0.xml +84 -0
  264. data/test/stub_responses/records/invoice-86102312-aa3f-438c-9938-6840f4d8dda6.xml +75 -0
  265. data/test/stub_responses/records/invoice-8694c9c5-7097-4449-a708-b8c1982921a4.xml +69 -0
  266. data/test/stub_responses/records/invoice-86d6e00f-ef56-49f7-9a54-796ccd5ca057.xml +85 -0
  267. data/test/stub_responses/records/invoice-88e77f0f-54a5-4efc-a979-7e22223cc4d7.xml +66 -0
  268. data/test/stub_responses/records/invoice-8b0ccb6a-d9b7-4da5-8360-ef7fb157b5aa.xml +66 -0
  269. data/test/stub_responses/records/invoice-935fc854-8037-4111-8d91-993010c331cc.xml +74 -0
  270. data/test/stub_responses/records/invoice-95ef3000-c764-4ba9-a66a-b6e2d161f839.xml +62 -0
  271. data/test/stub_responses/records/invoice-962ef33f-c9d2-4602-9b9f-93a02bea23b3.xml +93 -0
  272. data/test/stub_responses/records/invoice-9868b472-1983-48e9-8edf-7e81ddf2c03a.xml +85 -0
  273. data/test/stub_responses/records/invoice-9a448e9b-a9fa-4a8b-98f5-6dc892a37374.xml +62 -0
  274. data/test/stub_responses/records/invoice-a1d04a14-96a8-4067-a0ff-8136990a354f.xml +91 -0
  275. data/test/stub_responses/records/invoice-a3bc62ef-f11b-4a9c-a4f9-a342bda371b5.xml +66 -0
  276. data/test/stub_responses/records/invoice-a6894ca0-60ee-4d45-9dd4-b44fcba46ec5.xml +90 -0
  277. data/test/stub_responses/records/invoice-a77268ce-74b2-483d-a2b3-70dbdc9e49d2.xml +78 -0
  278. data/test/stub_responses/records/invoice-a9f765e6-b9bc-4505-a47b-fb3ecb327e7b.xml +88 -0
  279. data/test/stub_responses/records/invoice-aa0173af-8707-4e7f-8dde-4c7a357bd312.xml +109 -0
  280. data/test/stub_responses/records/invoice-ab63738a-370a-43a5-bfa3-620d684e66d0.xml +83 -0
  281. data/test/stub_responses/records/invoice-b0344791-5a8a-40dd-a208-d99a461a6c10.xml +84 -0
  282. data/test/stub_responses/records/invoice-b1e53910-473c-46a3-b3cb-38ece571220e.xml +76 -0
  283. data/test/stub_responses/records/invoice-b2c02d0b-41a8-4d4d-97d7-014c78b3547d.xml +93 -0
  284. data/test/stub_responses/records/invoice-b75b3928-ab72-4424-8b93-9cdbbde4cd72.xml +90 -0
  285. data/test/stub_responses/records/invoice-bcd8a71f-aa31-4d0f-8a01-13ea26363ddf.xml +94 -0
  286. data/test/stub_responses/records/invoice-bfbb7c45-de02-45e7-b065-d9863ecfb0d8.xml +66 -0
  287. data/test/stub_responses/records/invoice-c12aff7e-12bf-4185-8702-460929f19674.xml +77 -0
  288. data/test/stub_responses/records/invoice-c3380b96-976d-4b3e-8b26-8d01eb6a3742.xml +87 -0
  289. data/test/stub_responses/records/invoice-c963f2b0-cbe1-4abd-9ccc-7e512c942068.xml +67 -0
  290. data/test/stub_responses/records/invoice-cba46b29-3788-4158-b668-ab10160ccbfe.xml +78 -0
  291. data/test/stub_responses/records/invoice-d62646b9-d0a9-4fdb-9561-756a8b7eba45.xml +63 -0
  292. data/test/stub_responses/records/invoice-dba2f021-f149-4191-a126-5351d587ab0e.xml +75 -0
  293. data/test/stub_responses/records/invoice-de5d9c29-21b3-4342-958b-ed72c4bd7ab0.xml +108 -0
  294. data/test/stub_responses/records/invoice-e3d96555-2876-4364-a46a-7551a4f52611.xml +123 -0
  295. data/test/stub_responses/records/invoice-e4a0afbd-aea0-450b-ae23-0ce921e84a77.xml +102 -0
  296. data/test/stub_responses/records/invoice-e9cb9ecb-58ef-43a8-bd20-69a85338142d.xml +76 -0
  297. data/test/stub_responses/records/invoice-ec9a6f67-7128-4a63-8ba3-5e516f455f9b.xml +94 -0
  298. data/test/stub_responses/records/invoice-ed0f2587-84fc-4aef-bc4b-b1a262e24484.xml +81 -0
  299. data/test/stub_responses/records/invoice-f362ca53-8ade-4047-865a-bb64bee5863d.xml +74 -0
  300. data/test/stub_responses/records/invoice-f571c38b-5be1-41e1-ad5a-ff6184284beb.xml +114 -0
  301. data/test/stub_responses/records/invoice-f5832195-5cd3-4660-ad3f-b73d9c64f263.xml +85 -0
  302. data/test/stub_responses/records/invoice-f9c857eb-64cd-4235-a078-d04b52c77ea7.xml +76 -0
  303. data/test/stub_responses/records/manual_journal-4765d07b-aa03-4e56-9166-50661958c864.xml +38 -0
  304. data/test/stub_responses/records/manual_journal-53fc5558-5b76-4ecd-ae5c-c4af3ccde87c.xml +31 -0
  305. data/test/stub_responses/records/manual_journal-bb6cfcfc-4500-4475-bd3a-93ee512428e0.xml +31 -0
  306. data/test/stub_responses/records/manual_journal-f00a355b-7374-445c-886b-0437bea4095c.xml +45 -0
  307. data/test/stub_responses/refresh_responses.rb +29 -0
  308. data/test/stub_responses/reports/trial_balance.xml +1435 -0
  309. data/test/stub_responses/tax_rates.xml +118 -0
  310. data/test/stub_responses/token_expired +1 -0
  311. data/test/stub_responses/tracking_categories.xml +27 -0
  312. data/test/stub_responses/unknown_error.xml +1 -0
  313. data/test/test_helper.rb +67 -0
  314. data/test/unit/models/bank_transaction_model_parsing_test.rb +133 -0
  315. data/test/unit/models/bank_transaction_test.rb +47 -0
  316. data/test/unit/models/bank_transaction_validation_test.rb +87 -0
  317. data/test/unit/models/contact_test.rb +26 -0
  318. data/test/unit/models/credit_note_test.rb +37 -0
  319. data/test/unit/models/invoice_test.rb +113 -0
  320. data/test/unit/models/journal_line_test.rb +22 -0
  321. data/test/unit/models/line_item_sum_test.rb +24 -0
  322. data/test/unit/models/line_item_test.rb +70 -0
  323. data/test/unit/oauth_config_test.rb +20 -0
  324. data/test/unit/oauth_test.rb +97 -0
  325. data/test/unit/private_application_test.rb +20 -0
  326. data/test/unit/record/base_model_test.rb +50 -0
  327. data/test/unit/record/base_test.rb +94 -0
  328. data/test/unit/record/block_validator_test.rb +125 -0
  329. data/test/unit/record/model_definition_test.rb +159 -0
  330. data/test/unit/record/parse_where_hash_test.rb +63 -0
  331. data/test/unit/record/record_association_test.rb +93 -0
  332. data/test/unit/record/validators_test.rb +228 -0
  333. data/test/unit/record_definition_test.rb +27 -0
  334. data/test/unit/report_definition_test.rb +26 -0
  335. data/test/unit/report_test.rb +145 -0
  336. data/xeroizer.gemspec +405 -0
  337. metadata +561 -0
@@ -0,0 +1,32 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class AddressModel < BaseModel
5
+
6
+ end
7
+
8
+ class Address < Base
9
+
10
+ ADDRESS_TYPE = {
11
+ 'STREET' => 'Street',
12
+ 'POBOX' => 'PO Box',
13
+ 'DEFAULT' => 'Default address type'
14
+ } unless defined?(ADDRESS_TYPE)
15
+
16
+ string :address_type, :internal_name => :type
17
+ string :attention_to
18
+ string :address_line1, :internal_name => :line1
19
+ string :address_line2, :internal_name => :line2
20
+ string :address_line3, :internal_name => :line3
21
+ string :address_line4, :internal_name => :line4
22
+ string :city
23
+ string :region
24
+ string :postal_code
25
+ string :country
26
+
27
+ validates_inclusion_of :type, :in => ADDRESS_TYPE.keys
28
+
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ module Xeroizer
2
+ module Record
3
+ class BankAccountModel < BaseModel
4
+ set_permissions :read
5
+ end
6
+
7
+ class BankAccount < Base
8
+ guid :account_id
9
+ string :code
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,75 @@
1
+ require 'xeroizer/models/line_item'
2
+ require 'xeroizer/models/line_item_sum'
3
+
4
+ module Xeroizer
5
+ module Record
6
+ class BankTransactionModel < BaseModel
7
+ set_permissions :read
8
+ end
9
+
10
+ class BankTransaction < Base
11
+ def initialize(parent)
12
+ super parent
13
+ self.line_amount_types = "Exclusive"
14
+ end
15
+
16
+ set_primary_key :bank_transaction_id
17
+ string :type
18
+ date :date
19
+
20
+ datetime_utc :updated_date_utc, :api_name => "UpdatedDateUTC"
21
+ date :fully_paid_on_date
22
+ string :reference
23
+ string :bank_transaction_id, :api_name => "BankTransactionID"
24
+ boolean :is_reconciled
25
+
26
+ alias_method :reconciled?, :is_reconciled
27
+
28
+ belongs_to :contact, :model_name => 'Contact'
29
+ string :line_amount_types
30
+ has_many :line_items, :model_name => 'LineItem'
31
+ belongs_to :bank_account, :model_name => 'BankAccount'
32
+
33
+ validates_inclusion_of :line_amount_types,
34
+ :in => Xeroizer::Record::LINE_AMOUNT_TYPES, :allow_blanks => false
35
+
36
+ validates_inclusion_of :type,
37
+ :in => %w{SPEND RECEIVE}, :allow_blanks => false,
38
+ :message => "Invalid type. Expected either SPEND or RECEIVE."
39
+
40
+ validates_presence_of :contact, :bank_account, :allow_blanks => false
41
+
42
+ validates :line_items, :message => "Invalid line items. Must supply at least one." do
43
+ self.line_items.size > 0
44
+ end
45
+
46
+ def sub_total=(value); raise SettingTotalDirectlyNotSupported.new(:sub_total); end
47
+ def total_tax=(value); raise SettingTotalDirectlyNotSupported.new(:total_tax); end
48
+ def total=(value); raise SettingTotalDirectlyNotSupported.new(:total); end
49
+
50
+ def total; sub_total + total_tax; end
51
+
52
+ def sub_total
53
+ if ought_to_recalculate_totals?
54
+ result = LineItemSum.sub_total(self.line_items)
55
+ result -= total_tax if line_amount_types == 'Inclusive'
56
+ result
57
+ else
58
+ attributes[:sub_total]
59
+ end
60
+ end
61
+
62
+ def total_tax
63
+ return ought_to_recalculate_totals? ?
64
+ LineItemSum.total_tax(self.line_items) :
65
+ attributes[:total_tax]
66
+ end
67
+
68
+ private
69
+
70
+ def ought_to_recalculate_totals?
71
+ new_record? || line_items && line_items.size > 0
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,22 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class BrandingThemeModel < BaseModel
5
+
6
+ set_permissions :read
7
+
8
+ end
9
+
10
+ class BrandingTheme < Base
11
+
12
+ set_primary_key :branding_theme_id
13
+
14
+ guid :branding_theme_id
15
+ string :name
16
+ integer :sort_order
17
+ datetime :created_date_utc, :api_name => 'CreatedDateUTC'
18
+
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,49 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class ContactModel < BaseModel
5
+
6
+ set_permissions :read, :write, :update
7
+
8
+ end
9
+
10
+ class Contact < Base
11
+
12
+ CONTACT_STATUS = {
13
+ 'ACTIVE' => 'Active',
14
+ 'DELETED' => 'Deleted'
15
+ } unless defined?(CONTACT_STATUS)
16
+
17
+ set_primary_key :contact_id
18
+ set_possible_primary_keys :contact_id, :contact_number
19
+ list_contains_summary_only true
20
+
21
+ guid :contact_id
22
+ string :contact_number
23
+ string :contact_status
24
+ string :name
25
+ string :tax_number
26
+ string :bank_account_details
27
+ string :accounts_receivable_tax_type
28
+ string :accounts_payable_tax_type
29
+ string :first_name
30
+ string :last_name
31
+ string :email_address
32
+ string :skype_user_name
33
+ string :contact_groups
34
+ string :default_currency
35
+ datetime_utc :updated_date_utc, :api_name => 'UpdatedDateUTC'
36
+ boolean :is_supplier
37
+ boolean :is_customer
38
+
39
+ has_many :addresses, :list_complete => true
40
+ has_many :phones, :list_complete => true
41
+ has_many :contact_groups
42
+
43
+ validates_presence_of :name
44
+ validates_inclusion_of :contact_status, :in => CONTACT_STATUS.keys, :allow_blanks => true
45
+
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,16 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class ContactGroupModel < BaseModel
5
+ end
6
+
7
+ class ContactGroup < Base
8
+
9
+ guid :contact_group_id
10
+ string :name
11
+ string :status
12
+
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,130 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class CreditNoteModel < BaseModel
5
+
6
+ set_permissions :read, :write, :update
7
+
8
+ public
9
+
10
+ # Retrieve the PDF version of the credit matching the `id`.
11
+ # @param [String] id invoice's ID.
12
+ # @param [String] filename optional filename to store the PDF in instead of returning the data.
13
+ def pdf(id, filename = nil)
14
+ pdf_data = @application.http_get(@application.client, "#{url}/#{CGI.escape(id)}", :response => :pdf)
15
+ if filename
16
+ File.open(filename, "w") { | fp | fp.write pdf_data }
17
+ nil
18
+ else
19
+ pdf_data
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ class CreditNote < Base
26
+
27
+ CREDIT_NOTE_STATUS = {
28
+ 'AUTHORISED' => 'Approved credit_notes awaiting payment',
29
+ 'DELETED' => 'Draft credit_notes that are deleted',
30
+ 'DRAFT' => 'CreditNotes saved as draft or entered via API',
31
+ 'PAID' => 'CreditNotes approved and fully paid',
32
+ 'SUBMITTED' => 'CreditNotes entered by an employee awaiting approval',
33
+ 'VOIDED' => 'Approved credit_notes that are voided'
34
+ } unless defined?(CREDIT_NOTE_STATUS)
35
+ CREDIT_NOTE_STATUSES = CREDIT_NOTE_STATUS.keys.sort
36
+
37
+ CREDIT_NOTE_TYPE = {
38
+ 'ACCRECCREDIT' => 'Accounts Receivable',
39
+ 'ACCPAYCREDIT' => 'Accounts Payable'
40
+ } unless defined?(CREDIT_NOTE_TYPE)
41
+ CREDIT_NOTE_TYPES = CREDIT_NOTE_TYPE.keys.sort
42
+
43
+ set_primary_key :credit_note_id
44
+ set_possible_primary_keys :credit_note_id, :credit_note_number
45
+ list_contains_summary_only true
46
+
47
+ guid :credit_note_id
48
+ string :credit_note_number
49
+ string :reference
50
+ string :type
51
+ date :date
52
+ date :due_date
53
+ string :status
54
+ string :line_amount_types
55
+ decimal :sub_total, :calculated => true
56
+ decimal :total_tax, :calculated => true
57
+ decimal :total, :calculated => true
58
+ datetime_utc :updated_date_utc, :api_name => 'UpdatedDateUTC'
59
+ string :currency_code
60
+ datetime :fully_paid_on_date
61
+ boolean :sent_to_contact
62
+
63
+ belongs_to :contact
64
+ has_many :line_items
65
+
66
+ validates_inclusion_of :type, :in => CREDIT_NOTE_TYPES
67
+ validates_inclusion_of :status, :in => CREDIT_NOTE_STATUSES, :allow_blanks => true
68
+ validates_associated :contact
69
+ validates_associated :line_items
70
+
71
+ public
72
+
73
+ # Access the contact name without forcing a download of
74
+ # an incomplete, summary credit note.
75
+ def contact_name
76
+ attributes[:contact] && attributes[:contact][:name]
77
+ end
78
+
79
+ # Access the contact ID without forcing a download of an
80
+ # incomplete, summary credit note.
81
+ def contact_id
82
+ attributes[:contact] && attributes[:contact][:contact_id]
83
+ end
84
+
85
+ # Swallow assignment of attributes that should only be calculated automatically.
86
+ def sub_total=(value); raise SettingTotalDirectlyNotSupported.new(:sub_total); end
87
+ def total_tax=(value); raise SettingTotalDirectlyNotSupported.new(:total_tax); end
88
+ def total=(value); raise SettingTotalDirectlyNotSupported.new(:total); end
89
+
90
+ # Calculate sub_total from line_items.
91
+ def sub_total(always_summary = false)
92
+ if !always_summary && (new_record? || (!new_record? && line_items && line_items.size > 0))
93
+ sum = (line_items || []).inject(BigDecimal.new('0')) { | sum, line_item | sum + line_item.line_amount }
94
+
95
+ # If the default amount types are inclusive of 'tax' then remove the tax amount from this sub-total.
96
+ sum -= total_tax if line_amount_types == 'Inclusive'
97
+ sum
98
+ else
99
+ attributes[:sub_total]
100
+ end
101
+ end
102
+
103
+ # Calculate total_tax from line_items.
104
+ def total_tax(always_summary = false)
105
+ if !always_summary && (new_record? || (!new_record? && line_items && line_items.size > 0))
106
+ (line_items || []).inject(BigDecimal.new('0')) { | sum, line_item | sum + line_item.tax_amount }
107
+ else
108
+ attributes[:total_tax]
109
+ end
110
+ end
111
+
112
+ # Calculate the total from line_items.
113
+ def total(always_summary = false)
114
+ unless always_summary
115
+ sub_total + total_tax
116
+ else
117
+ attributes[:total]
118
+ end
119
+ end
120
+
121
+ # Retrieve the PDF version of this credit note.
122
+ # @param [String] filename optional filename to store the PDF in instead of returning the data.
123
+ def pdf(filename = nil)
124
+ parent.pdf(id, filename)
125
+ end
126
+
127
+ end
128
+
129
+ end
130
+ end
@@ -0,0 +1,18 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class CurrencyModel < BaseModel
5
+
6
+ set_permissions :read
7
+
8
+ end
9
+
10
+ class Currency < Base
11
+
12
+ string :code
13
+ string :description
14
+
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ require 'xeroizer/models/external_link'
2
+
3
+ module Xeroizer
4
+ module Record
5
+
6
+ class EmployeeModel < BaseModel
7
+
8
+ set_permissions :read, :write, :update
9
+
10
+ end
11
+
12
+ class Employee < Base
13
+
14
+ set_primary_key :employee_id
15
+
16
+ guid :employee_id
17
+ string :status
18
+ string :first_name
19
+ string :last_name
20
+
21
+ belongs_to :external_link
22
+
23
+ validates_presence_of :first_name, :last_name
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class ExternalLinkModel < BaseModel
5
+
6
+ end
7
+
8
+ class ExternalLink < Base
9
+
10
+ string :url
11
+ string :description
12
+
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,192 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class InvoiceModel < BaseModel
5
+
6
+ set_permissions :read, :write, :update
7
+
8
+ public
9
+
10
+ # Retrieve the PDF version of the invoice matching the `id`.
11
+ # @param [String] id invoice's ID.
12
+ # @param [String] filename optional filename to store the PDF in instead of returning the data.
13
+ def pdf(id, filename = nil)
14
+ pdf_data = @application.http_get(@application.client, "#{url}/#{CGI.escape(id)}", :response => :pdf)
15
+ if filename
16
+ File.open(filename, "w") { | fp | fp.write pdf_data }
17
+ nil
18
+ else
19
+ pdf_data
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ class Invoice < Base
26
+
27
+ INVOICE_TYPE = {
28
+ 'ACCREC' => 'Accounts Receivable',
29
+ 'ACCPAY' => 'Accounts Payable'
30
+ } unless defined?(INVOICE_TYPE)
31
+ INVOICE_TYPES = INVOICE_TYPE.keys.sort
32
+
33
+ INVOICE_STATUS = {
34
+ 'AUTHORISED' => 'Approved invoices awaiting payment',
35
+ 'DELETED' => 'Draft invoices that are deleted',
36
+ 'DRAFT' => 'Invoices saved as draft or entered via API',
37
+ 'PAID' => 'Invoices approved and fully paid',
38
+ 'SUBMITTED' => 'Invoices entered by an employee awaiting approval',
39
+ 'VOIDED' => 'Approved invoices that are voided'
40
+ } unless defined?(INVOICE_STATUS)
41
+ INVOICE_STATUSES = INVOICE_STATUS.keys.sort
42
+
43
+ set_primary_key :invoice_id
44
+ set_possible_primary_keys :invoice_id, :invoice_number
45
+ list_contains_summary_only true
46
+
47
+ guid :invoice_id
48
+ string :invoice_number
49
+ string :reference
50
+ guid :branding_theme_id
51
+ string :url
52
+ string :type
53
+ date :date
54
+ date :due_date
55
+ string :status
56
+ string :line_amount_types
57
+ decimal :sub_total, :calculated => true
58
+ decimal :total_tax, :calculated => true
59
+ decimal :total, :calculated => true
60
+ decimal :amount_due
61
+ decimal :amount_paid
62
+ decimal :amount_credited
63
+ datetime_utc :updated_date_utc, :api_name => 'UpdatedDateUTC'
64
+ string :currency_code
65
+ datetime :fully_paid_on_date
66
+ boolean :sent_to_contact
67
+
68
+ belongs_to :contact
69
+ has_many :line_items
70
+ has_many :payments
71
+ has_many :credit_notes
72
+
73
+ validates_presence_of :date, :due_date, :unless => :new_record?
74
+ validates_inclusion_of :type, :in => INVOICE_TYPES
75
+ validates_inclusion_of :status, :in => INVOICE_STATUSES, :unless => :new_record?
76
+ validates_inclusion_of :line_amount_types, :in => LINE_AMOUNT_TYPES, :unless => :new_record?
77
+ validates_associated :contact
78
+ validates_associated :line_items, :allow_blanks => true, :unless => :approved?
79
+ validates_associated :line_items, :if => :approved?
80
+
81
+ public
82
+
83
+ # Access the contact name without forcing a download of
84
+ # an incomplete, summary invoice.
85
+ def contact_name
86
+ attributes[:contact] && attributes[:contact][:name]
87
+ end
88
+
89
+ # Access the contact ID without forcing a download of an
90
+ # incomplete, summary invoice.
91
+ def contact_id
92
+ attributes[:contact] && attributes[:contact][:contact_id]
93
+ end
94
+
95
+ # Helper method to check if the invoice has been approved.
96
+ def approved?
97
+ [ 'AUTHORISED', 'PAID', 'VOIDED' ].include? status
98
+ end
99
+
100
+ # Helper method to check if the invoice is accounts payable.
101
+ def accounts_payable?
102
+ type == 'ACCPAY'
103
+ end
104
+
105
+ # Helper method to check if the invoice is accounts receivable.
106
+ def accounts_receivable?
107
+ type == 'ACCREC'
108
+ end
109
+
110
+ def sub_total=(sub_total)
111
+ @sub_total_is_set = true
112
+ attributes[:sub_total] = sub_total
113
+ end
114
+
115
+ def total_tax=(total_tax)
116
+ @total_tax_is_set = true
117
+ attributes[:total_tax] = total_tax
118
+ end
119
+
120
+ def total=(total)
121
+ @total_is_set = true
122
+ attributes[:total] = total
123
+ end
124
+
125
+ # Calculate sub_total from line_items.
126
+ def sub_total(always_summary = false)
127
+ if !@sub_total_is_set && not_summary_or_loaded_record(always_summary)
128
+ sum = (line_items || []).inject(BigDecimal.new('0')) { | sum, line_item | sum + line_item.line_amount }
129
+
130
+ # If the default amount types are inclusive of 'tax' then remove the tax amount from this sub-total.
131
+ sum -= total_tax if line_amount_types == 'Inclusive'
132
+ sum
133
+ else
134
+ attributes[:sub_total]
135
+ end
136
+ end
137
+
138
+ # Calculate total_tax from line_items.
139
+ def total_tax(always_summary = false)
140
+ if !@total_tax_is_set && not_summary_or_loaded_record(always_summary)
141
+ (line_items || []).inject(BigDecimal.new('0')) { | sum, line_item | sum + line_item.tax_amount }
142
+ else
143
+ attributes[:total_tax]
144
+ end
145
+ end
146
+
147
+ # Calculate the total from line_items.
148
+ def total(always_summary = false)
149
+ if !@total_is_set && not_summary_or_loaded_record(always_summary)
150
+ sub_total + total_tax
151
+ else
152
+ attributes[:total]
153
+ end
154
+ end
155
+
156
+ def not_summary_or_loaded_record(always_summary)
157
+ !always_summary && loaded_record?
158
+ end
159
+
160
+ def loaded_record?
161
+ new_record? ||
162
+ (!new_record? && line_items && line_items.size > 0)
163
+ end
164
+
165
+ # Retrieve the PDF version of this invoice.
166
+ # @param [String] filename optional filename to store the PDF in instead of returning the data.
167
+ def pdf(filename = nil)
168
+ parent.pdf(id, filename)
169
+ end
170
+
171
+ # Delete an approved invoice with no payments.
172
+ def delete!
173
+ delete_or_void_invoice!('DELETED')
174
+ end
175
+
176
+ # Void an approved invoice with no payments.
177
+ def void!
178
+ delete_or_void_invoice!('VOIDED')
179
+ end
180
+
181
+ protected
182
+
183
+ def delete_or_void_invoice!(new_status)
184
+ raise CannotChangeInvoiceStatus.new(record, new_status) unless self.payments.size == 0
185
+ self.status = new_status
186
+ self.save
187
+ end
188
+
189
+ end
190
+
191
+ end
192
+ end