xero-kiwi 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +2 -0
  3. data/CHANGELOG.md +5 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +89 -0
  6. data/Rakefile +89 -0
  7. data/docs/accounting/address.md +54 -0
  8. data/docs/accounting/branding-theme.md +92 -0
  9. data/docs/accounting/contact-group.md +91 -0
  10. data/docs/accounting/contact.md +166 -0
  11. data/docs/accounting/credit-note.md +97 -0
  12. data/docs/accounting/external-link.md +33 -0
  13. data/docs/accounting/invoice.md +134 -0
  14. data/docs/accounting/organisation.md +119 -0
  15. data/docs/accounting/overpayment.md +94 -0
  16. data/docs/accounting/payment-terms.md +58 -0
  17. data/docs/accounting/payment.md +99 -0
  18. data/docs/accounting/phone.md +45 -0
  19. data/docs/accounting/prepayment.md +111 -0
  20. data/docs/accounting/user.md +109 -0
  21. data/docs/client.md +174 -0
  22. data/docs/connections.md +166 -0
  23. data/docs/errors.md +271 -0
  24. data/docs/getting-started.md +138 -0
  25. data/docs/oauth.md +508 -0
  26. data/docs/retries-and-rate-limits.md +224 -0
  27. data/docs/tokens.md +339 -0
  28. data/lib/xero_kiwi/accounting/address.rb +58 -0
  29. data/lib/xero_kiwi/accounting/allocation.rb +66 -0
  30. data/lib/xero_kiwi/accounting/branding_theme.rb +76 -0
  31. data/lib/xero_kiwi/accounting/contact.rb +153 -0
  32. data/lib/xero_kiwi/accounting/contact_group.rb +57 -0
  33. data/lib/xero_kiwi/accounting/contact_person.rb +45 -0
  34. data/lib/xero_kiwi/accounting/credit_note.rb +115 -0
  35. data/lib/xero_kiwi/accounting/external_link.rb +38 -0
  36. data/lib/xero_kiwi/accounting/invoice.rb +142 -0
  37. data/lib/xero_kiwi/accounting/line_item.rb +64 -0
  38. data/lib/xero_kiwi/accounting/organisation.rb +138 -0
  39. data/lib/xero_kiwi/accounting/overpayment.rb +107 -0
  40. data/lib/xero_kiwi/accounting/payment.rb +105 -0
  41. data/lib/xero_kiwi/accounting/payment_terms.rb +77 -0
  42. data/lib/xero_kiwi/accounting/phone.rb +46 -0
  43. data/lib/xero_kiwi/accounting/prepayment.rb +109 -0
  44. data/lib/xero_kiwi/accounting/tracking_category.rb +42 -0
  45. data/lib/xero_kiwi/accounting/user.rb +80 -0
  46. data/lib/xero_kiwi/client.rb +576 -0
  47. data/lib/xero_kiwi/connection.rb +78 -0
  48. data/lib/xero_kiwi/errors.rb +34 -0
  49. data/lib/xero_kiwi/identity.rb +40 -0
  50. data/lib/xero_kiwi/oauth/id_token.rb +102 -0
  51. data/lib/xero_kiwi/oauth/pkce.rb +51 -0
  52. data/lib/xero_kiwi/oauth.rb +232 -0
  53. data/lib/xero_kiwi/token.rb +99 -0
  54. data/lib/xero_kiwi/token_refresher.rb +53 -0
  55. data/lib/xero_kiwi/version.rb +5 -0
  56. data/lib/xero_kiwi.rb +33 -0
  57. data/llms-full.txt +3351 -0
  58. data/llms.txt +56 -0
  59. data/sig/xero_kiwi.rbs +4 -0
  60. metadata +164 -0
@@ -0,0 +1,97 @@
1
+ # Credit Notes
2
+
3
+ A Xero **credit note** is a document that reduces the amount owed on an
4
+ invoice. Credit notes can be applied (allocated) to outstanding invoices. You
5
+ need a `tenant_id` from a [connection](../connections.md) before you can fetch
6
+ credit notes.
7
+
8
+ > See: [Xero docs — Credit Notes](https://developer.xero.com/documentation/api/accounting/creditnotes)
9
+
10
+ ## Listing credit notes
11
+
12
+ ```ruby
13
+ client = XeroKiwi::Client.new(access_token: "ya29...")
14
+
15
+ # Pass a tenant ID string…
16
+ credit_notes = client.credit_notes("70784a63-d24b-46a9-a4db-0e70a274b056")
17
+
18
+ # …or a XeroKiwi::Connection (its tenant_id is used automatically).
19
+ connection = client.connections.first
20
+ credit_notes = client.credit_notes(connection)
21
+ ```
22
+
23
+ `client.credit_notes` hits `GET /api.xro/2.0/CreditNotes` with the
24
+ `Xero-Tenant-Id` header set to the tenant you specify. It returns an
25
+ `Array<XeroKiwi::Accounting::CreditNote>`.
26
+
27
+ ## Fetching a single credit note
28
+
29
+ ```ruby
30
+ cn = client.credit_note(tenant_id, "aea95d78-ea48-456b-9b08-6bc012600072")
31
+ cn.total # => 100.00
32
+ ```
33
+
34
+ `client.credit_note` hits `GET /api.xro/2.0/CreditNotes/{CreditNoteID}` and
35
+ returns a single `XeroKiwi::Accounting::CreditNote`, or `nil` if the response is
36
+ empty. The single-credit-note response includes full line item details.
37
+
38
+ ## The CreditNote object
39
+
40
+ Each `XeroKiwi::Accounting::CreditNote` is an immutable value object exposing the
41
+ fields Xero returns:
42
+
43
+ | Attribute | Type | What it is |
44
+ |-----------|------|------------|
45
+ | `credit_note_id` | `String` | The unique Xero identifier. |
46
+ | `credit_note_number` | `String` | The credit note number (e.g. `"CN-0002"`). |
47
+ | `type` | `String` | `"ACCRECCREDIT"` (accounts receivable) or `"ACCPAYCREDIT"` (accounts payable). |
48
+ | `contact` | `XeroKiwi::Accounting::Contact` | The contact (reference — use `contact.reference?` to check). See [Contacts](contact.md). |
49
+ | `date` | `Time` | The date the credit note was issued, parsed as UTC. |
50
+ | `status` | `String` | e.g. `"DRAFT"`, `"SUBMITTED"`, `"AUTHORISED"`, `"PAID"`, `"VOIDED"`. |
51
+ | `line_amount_types` | `String` | `"Inclusive"`, `"Exclusive"`, or `"NoTax"`. |
52
+ | `line_items` | `Array<XeroKiwi::Accounting::LineItem>` | The line items. See [Prepayments — LineItem](prepayment.md#the-lineitem-object). |
53
+ | `sub_total` | `Numeric` | The subtotal excluding taxes. |
54
+ | `total_tax` | `Numeric` | The total tax amount. |
55
+ | `total` | `Numeric` | The total (subtotal + total tax). |
56
+ | `cis_deduction` | `Numeric` | CIS deduction (UK Construction Industry Scheme only). |
57
+ | `updated_date_utc` | `Time` | When the credit note was last modified, parsed as UTC. |
58
+ | `currency_code` | `String` | The currency code (e.g. `"NZD"`). |
59
+ | `currency_rate` | `Numeric` | The currency rate (1.0 for base currency). |
60
+ | `fully_paid_on_date` | `Time` | When the credit note was fully allocated, parsed as UTC. |
61
+ | `reference` | `String` | Additional reference number (ACCRECCREDIT only). |
62
+ | `sent_to_contact` | `Boolean` | Whether the credit note has been sent to the contact. |
63
+ | `remaining_credit` | `Numeric` | The remaining credit balance. |
64
+ | `allocations` | `Array<XeroKiwi::Accounting::Allocation>` | Allocations to invoices. Each allocation has an `invoice` reference. |
65
+ | `branding_theme_id` | `String` | The branding theme ID applied to the credit note. |
66
+ | `has_attachments` | `Boolean` | Whether the credit note has attachments. |
67
+
68
+ ## Predicates
69
+
70
+ ```ruby
71
+ cn.accounts_receivable? # type == "ACCRECCREDIT"
72
+ cn.accounts_payable? # type == "ACCPAYCREDIT"
73
+ ```
74
+
75
+ ## Equality and hashing
76
+
77
+ Two credit notes are `==` if they share the same `credit_note_id`. `#hash` is
78
+ consistent with `==`, so credit notes work as hash keys and in sets.
79
+
80
+ ## Error behaviour
81
+
82
+ | HTTP status | Exception | What it usually means |
83
+ |-------------|-----------|------------------------|
84
+ | 200 | (none — returns credit notes) | Success |
85
+ | 401 | `XeroKiwi::AuthenticationError` | Access token is invalid or expired |
86
+ | 403 | `XeroKiwi::ClientError` | The token doesn't have the required scope |
87
+ | 404 | `XeroKiwi::ClientError` | The credit note ID doesn't exist |
88
+
89
+ ## Common patterns
90
+
91
+ ### Listing credit notes with remaining credit
92
+
93
+ ```ruby
94
+ credit_notes = client.credit_notes(tenant_id)
95
+ with_credit = credit_notes.select { |cn| cn.remaining_credit.to_f > 0 }
96
+ with_credit.each { |cn| puts "#{cn.credit_note_number}: #{cn.remaining_credit} remaining" }
97
+ ```
@@ -0,0 +1,33 @@
1
+ # XeroKiwi::Accounting::ExternalLink
2
+
3
+ A Xero external link (social or web profile). Used by
4
+ [Organisation](organisation.md).
5
+
6
+ > See: [Xero docs — External link types](https://developer.xero.com/documentation/api/accounting/types#externallinks)
7
+
8
+ ## Usage
9
+
10
+ ```ruby
11
+ org.external_links.each do |link|
12
+ puts "#{link.link_type}: #{link.url}"
13
+ end
14
+ ```
15
+
16
+ ## Attributes
17
+
18
+ | Attribute | Type | Notes |
19
+ |-----------|------|-------|
20
+ | `link_type` | `String` | `"Facebook"`, `"GooglePlus"`, `"LinkedIn"`, `"Twitter"`, or `"Website"` |
21
+ | `url` | `String` | The URL for the service |
22
+
23
+ ## Equality
24
+
25
+ Two external links are `==` if all their attributes match. `#hash` is
26
+ consistent with `==`.
27
+
28
+ ## Serialisation
29
+
30
+ ```ruby
31
+ link.to_h
32
+ # => { link_type: "Facebook", url: "https://facebook.com/example" }
33
+ ```
@@ -0,0 +1,134 @@
1
+ # Invoices
2
+
3
+ A Xero **invoice** is either a sales invoice (accounts receivable, `ACCREC`) or
4
+ a purchase bill (accounts payable, `ACCPAY`). Invoices carry line items,
5
+ payments, credit notes, and allocation details. You need a `tenant_id` from a
6
+ [connection](../connections.md) before you can fetch invoices.
7
+
8
+ > See: [Xero docs — Invoices](https://developer.xero.com/documentation/api/accounting/invoices)
9
+
10
+ ## Listing invoices
11
+
12
+ ```ruby
13
+ client = XeroKiwi::Client.new(access_token: "ya29...")
14
+
15
+ # Pass a tenant ID string…
16
+ invoices = client.invoices("70784a63-d24b-46a9-a4db-0e70a274b056")
17
+
18
+ # …or a XeroKiwi::Connection (its tenant_id is used automatically).
19
+ connection = client.connections.first
20
+ invoices = client.invoices(connection)
21
+ ```
22
+
23
+ `client.invoices` hits `GET /api.xro/2.0/Invoices` with the `Xero-Tenant-Id`
24
+ header set to the tenant you specify. It returns an
25
+ `Array<XeroKiwi::Accounting::Invoice>`.
26
+
27
+ **Note:** The list response returns only a summary of each contact and no line
28
+ items. Fetch an individual invoice for full details including line items.
29
+
30
+ ## Fetching a single invoice
31
+
32
+ ```ruby
33
+ inv = client.invoice(tenant_id, "243216c5-369e-4056-ac67-05388f86dc81")
34
+ inv.total # => "2025.00"
35
+ inv.invoice_number # => "OIT00546"
36
+ ```
37
+
38
+ `client.invoice` hits `GET /api.xro/2.0/Invoices/{InvoiceID}` and returns a
39
+ single `XeroKiwi::Accounting::Invoice`, or `nil` if the response is empty.
40
+
41
+ ## The Invoice object
42
+
43
+ Each `XeroKiwi::Accounting::Invoice` is an immutable value object. The fields below
44
+ cover both the list and single-invoice responses:
45
+
46
+ | Attribute | Type | What it is |
47
+ |-----------|------|------------|
48
+ | `invoice_id` | `String` | The unique Xero identifier. |
49
+ | `invoice_number` | `String` | The invoice number (e.g. `"OIT00546"`). |
50
+ | `type` | `String` | `"ACCREC"` (sales) or `"ACCPAY"` (bills). |
51
+ | `contact` | `XeroKiwi::Accounting::Contact` | The contact (reference — use `contact.reference?` to check). See [Contacts](contact.md). |
52
+ | `date` | `Time` | The invoice date, parsed as UTC. |
53
+ | `due_date` | `Time` | The due date, parsed as UTC. |
54
+ | `status` | `String` | e.g. `"DRAFT"`, `"SUBMITTED"`, `"AUTHORISED"`, `"PAID"`, `"VOIDED"`, `"DELETED"`. |
55
+ | `line_amount_types` | `String` | `"Inclusive"`, `"Exclusive"`, or `"NoTax"`. |
56
+ | `line_items` | `Array<XeroKiwi::Accounting::LineItem>` | The line items (empty on list, populated on single). See [Prepayments — LineItem](prepayment.md#the-lineitem-object). |
57
+ | `sub_total` | `String/Numeric` | The subtotal excluding taxes. |
58
+ | `total_tax` | `String/Numeric` | The total tax amount. |
59
+ | `total` | `String/Numeric` | The total (subtotal + total tax). |
60
+ | `total_discount` | `String/Numeric` | Total discounts on line items. |
61
+ | `updated_date_utc` | `Time` | When the invoice was last modified, parsed as UTC. |
62
+ | `currency_code` | `String` | The currency code (e.g. `"NZD"`). |
63
+ | `currency_rate` | `Numeric` | The currency rate (1.0 for base currency). |
64
+ | `reference` | `String` | Additional reference number (ACCREC only). |
65
+ | `branding_theme_id` | `String` | The branding theme ID. |
66
+ | `url` | `String` | URL link to a source document. |
67
+ | `sent_to_contact` | `Boolean` | Whether the invoice displays as "sent" in Xero. |
68
+ | `expected_payment_date` | `Time` | Expected payment date (ACCREC only). |
69
+ | `planned_payment_date` | `Time` | Planned payment date (ACCPAY only). |
70
+ | `has_attachments` | `Boolean` | Whether the invoice has attachments. |
71
+ | `repeating_invoice_id` | `String` | The repeating invoice template ID, if applicable. |
72
+ | `payments` | `Array<XeroKiwi::Accounting::Payment>` | Payment records (references). See [Payments](payment.md). |
73
+ | `credit_notes` | `Array<Hash>` | Credit notes applied (raw hashes). |
74
+ | `prepayments` | `Array<Hash>` | Prepayments applied (raw hashes). |
75
+ | `overpayments` | `Array<Hash>` | Overpayments applied (raw hashes). |
76
+ | `amount_due` | `String/Numeric` | Amount remaining to be paid. |
77
+ | `amount_paid` | `String/Numeric` | Sum of payments received. |
78
+ | `amount_credited` | `String/Numeric` | Sum of credit notes, overpayments, and prepayments applied. |
79
+ | `cis_deduction` | `Numeric` | CIS deduction (UK Construction Industry Scheme only). |
80
+ | `fully_paid_on_date` | `Time` | When the invoice was fully paid, parsed as UTC. |
81
+ | `sales_tax_calculation_type_code` | `String` | US auto sales tax calculation type. |
82
+ | `invoice_addresses` | `Array<Hash>` | Invoice addresses (US auto sales tax only). |
83
+
84
+ ## Predicates
85
+
86
+ ```ruby
87
+ inv.accounts_receivable? # type == "ACCREC"
88
+ inv.accounts_payable? # type == "ACCPAY"
89
+ ```
90
+
91
+ ## Equality and hashing
92
+
93
+ Two invoices are `==` if they share the same `invoice_id`. `#hash` is consistent
94
+ with `==`, so invoices work as hash keys and in sets.
95
+
96
+ ## Error behaviour
97
+
98
+ | HTTP status | Exception | What it usually means |
99
+ |-------------|-----------|------------------------|
100
+ | 200 | (none — returns invoices) | Success |
101
+ | 401 | `XeroKiwi::AuthenticationError` | Access token is invalid or expired |
102
+ | 403 | `XeroKiwi::ClientError` | The token doesn't have the required scope |
103
+ | 404 | `XeroKiwi::ClientError` | The invoice ID doesn't exist |
104
+
105
+ ## Common patterns
106
+
107
+ ### Retrieving the online invoice URL
108
+
109
+ For sales (ACCREC) invoices that are not in DRAFT status, you can retrieve the
110
+ online invoice URL that customers can use to view and pay:
111
+
112
+ ```ruby
113
+ url = client.online_invoice_url(tenant_id, "243216c5-369e-4056-ac67-05388f86dc81")
114
+ puts url # => "https://in.xero.com/iztKMjyAEJT7MVnmruxgCdIJUDStfRgmtdQSIW13"
115
+ ```
116
+
117
+ Returns `nil` if no online invoice URL is available.
118
+
119
+ ### Listing outstanding invoices
120
+
121
+ ```ruby
122
+ invoices = client.invoices(tenant_id)
123
+ outstanding = invoices.select { |inv| inv.amount_due.to_f > 0 }
124
+ outstanding.each { |inv| puts "#{inv.invoice_number}: #{inv.amount_due} due" }
125
+ ```
126
+
127
+ ### Fetching an invoice with full line items
128
+
129
+ ```ruby
130
+ inv = client.invoice(tenant_id, "243216c5-369e-4056-ac67-05388f86dc81")
131
+ inv.line_items.each do |li|
132
+ puts " #{li.description}: #{li.line_amount}"
133
+ end
134
+ ```
@@ -0,0 +1,119 @@
1
+ # Organisation
2
+
3
+ A Xero **organisation** is the actual accounting entity — the company, sole
4
+ trader, trust, etc. that owns the books. You need a `tenant_id` from a
5
+ [connection](../connections.md) before you can fetch one.
6
+
7
+ > See: [Xero docs — Organisation](https://developer.xero.com/documentation/api/accounting/organisation)
8
+
9
+ ## Fetching an organisation
10
+
11
+ ```ruby
12
+ client = XeroKiwi::Client.new(access_token: "ya29...")
13
+
14
+ # Pass a tenant ID string…
15
+ org = client.organisation("70784a63-d24b-46a9-a4db-0e70a274b056")
16
+
17
+ # …or a XeroKiwi::Connection (its tenant_id is used automatically).
18
+ connection = client.connections.first
19
+ org = client.organisation(connection)
20
+ ```
21
+
22
+ `client.organisation` hits `GET /api.xro/2.0/Organisation` with the
23
+ `Xero-Tenant-Id` header set to the tenant you specify. It returns a single
24
+ `XeroKiwi::Accounting::Organisation`.
25
+
26
+ ## The Organisation object
27
+
28
+ Each `XeroKiwi::Accounting::Organisation` is an immutable value object exposing the fields
29
+ Xero returns:
30
+
31
+ | Attribute | Type | What it is |
32
+ |-----------|------|------------|
33
+ | `organisation_id` | `String` | The unique identifier for the organisation. |
34
+ | `api_key` | `String` | The API key (if set). |
35
+ | `name` | `String` | The display name (e.g. "Maple Florists Ltd"). |
36
+ | `legal_name` | `String` | The registered legal name. |
37
+ | `pays_tax` | `Boolean` | Whether the organisation is registered for tax. |
38
+ | `version` | `String` | The Xero edition version code (e.g. `"NZ"`, `"GLOBAL"`). |
39
+ | `organisation_type` | `String` | The type — `"COMPANY"`, `"SOLE_TRADER"`, `"TRUST"`, etc. |
40
+ | `base_currency` | `String` | The base currency code (e.g. `"NZD"`, `"ZAR"`). |
41
+ | `country_code` | `String` | The two-letter country code (e.g. `"NZ"`, `"ZA"`). |
42
+ | `is_demo_company` | `Boolean` | Whether this is a Xero demo company. |
43
+ | `organisation_status` | `String` | `"ACTIVE"` or otherwise. |
44
+ | `registration_number` | `String` | The company registration number. |
45
+ | `employer_identification_number` | `String` | The EIN (US organisations). |
46
+ | `tax_number` | `String` | The tax/VAT number. |
47
+ | `financial_year_end_day` | `Integer` | Day of month the financial year ends (1–31). |
48
+ | `financial_year_end_month` | `Integer` | Month the financial year ends (1–12). |
49
+ | `sales_tax_basis` | `String` | e.g. `"Payments"`, `"CASH"`, `"ACCRUALS"`. |
50
+ | `sales_tax_period` | `String` | e.g. `"TWOMONTHS"`, `"MONTHLY"`. |
51
+ | `default_sales_tax` | `String` | e.g. `"Tax Exclusive"`. |
52
+ | `default_purchases_tax` | `String` | e.g. `"Tax Exclusive"`. |
53
+ | `period_lock_date` | `Time` | The period lock date, parsed as UTC. |
54
+ | `end_of_year_lock_date` | `Time` | The end-of-year lock date, parsed as UTC. |
55
+ | `created_date_utc` | `Time` | When the organisation was created, parsed as UTC. |
56
+ | `timezone` | `String` | The organisation's timezone code (e.g. `"NEWZEALANDSTANDARDTIME"`). |
57
+ | `organisation_entity_type` | `String` | The entity type (e.g. `"COMPANY"`). |
58
+ | `short_code` | `String` | The Xero short code for this organisation. |
59
+ | `organisation_class` | `String` | The Xero subscription class (e.g. `"PREMIUM"`, `"STARTER"`). |
60
+ | `edition` | `String` | The Xero subscription edition (e.g. `"BUSINESS"`). |
61
+ | `line_of_business` | `String` | The industry / line of business. |
62
+ | `addresses` | `Array<XeroKiwi::Accounting::Address>` | The organisation's addresses. See [Address](address.md). |
63
+ | `phones` | `Array<XeroKiwi::Accounting::Phone>` | The organisation's phone numbers. See [Phone](phone.md). |
64
+ | `external_links` | `Array<XeroKiwi::Accounting::ExternalLink>` | Social/web profile links. See [ExternalLink](external-link.md). |
65
+ | `payment_terms` | `XeroKiwi::Accounting::PaymentTerms` | Default payment terms for bills and sales. See [PaymentTerms](payment-terms.md). |
66
+
67
+ ## Predicates
68
+
69
+ ```ruby
70
+ org.demo_company? # is_demo_company == true
71
+ ```
72
+
73
+ ## Equality and hashing
74
+
75
+ Two organisations are `==` if they share the same `organisation_id`. `#hash`
76
+ is consistent with `==`, so organisations work as hash keys and in sets.
77
+
78
+ ## Date parsing
79
+
80
+ The Xero Accounting API serialises timestamps differently from the Connections
81
+ API. Connections use ISO 8601 strings (e.g. `"2019-07-09T23:40:30.1833130"`),
82
+ but the Accounting API (including Organisation) uses the legacy .NET JSON
83
+ format: `/Date(1574275974000)/`.
84
+
85
+ XeroKiwi handles both transparently — all `Time` attributes are parsed to UTC
86
+ `Time` objects regardless of which format Xero sends. You don't need to think
87
+ about this unless you're looking at raw cassette data or debugging timestamp
88
+ issues.
89
+
90
+ ## Error behaviour
91
+
92
+ | HTTP status | Exception | What it usually means |
93
+ |-------------|-----------|------------------------|
94
+ | 200 | (none — returns the organisation) | Success |
95
+ | 401 | `XeroKiwi::AuthenticationError` | Access token is invalid or expired |
96
+ | 403 | `XeroKiwi::ClientError` | The token doesn't have the `accounting.settings.read` scope |
97
+ | 404 | `XeroKiwi::ClientError` | The tenant ID doesn't correspond to an organisation |
98
+
99
+ ## Common patterns
100
+
101
+ ### From connection to organisation
102
+
103
+ ```ruby
104
+ client = XeroKiwi::Client.new(access_token: "ya29...")
105
+
106
+ client.connections.each do |conn|
107
+ org = client.organisation(conn)
108
+ puts "#{org.name} (#{org.base_currency}) — #{org.country_code}"
109
+ end
110
+ ```
111
+
112
+ ### Checking if it's a demo company
113
+
114
+ ```ruby
115
+ org = client.organisation(tenant_id)
116
+ if org.demo_company?
117
+ puts "This is a demo company — data isn't real"
118
+ end
119
+ ```
@@ -0,0 +1,94 @@
1
+ # Overpayments
2
+
3
+ A Xero **overpayment** is an excess payment received or made beyond the amount
4
+ of an invoice. Overpayments are created via the BankTransactions endpoint and
5
+ refunded via the Payments endpoint. This resource lets you retrieve overpayments
6
+ and their allocations. You need a `tenant_id` from a
7
+ [connection](../connections.md) before you can fetch overpayments.
8
+
9
+ > See: [Xero docs — Overpayments](https://developer.xero.com/documentation/api/accounting/overpayments)
10
+
11
+ ## Listing overpayments
12
+
13
+ ```ruby
14
+ client = XeroKiwi::Client.new(access_token: "ya29...")
15
+
16
+ # Pass a tenant ID string…
17
+ overpayments = client.overpayments("70784a63-d24b-46a9-a4db-0e70a274b056")
18
+
19
+ # …or a XeroKiwi::Connection (its tenant_id is used automatically).
20
+ connection = client.connections.first
21
+ overpayments = client.overpayments(connection)
22
+ ```
23
+
24
+ `client.overpayments` hits `GET /api.xro/2.0/Overpayments` with the
25
+ `Xero-Tenant-Id` header set to the tenant you specify. It returns an
26
+ `Array<XeroKiwi::Accounting::Overpayment>`.
27
+
28
+ ## Fetching a single overpayment
29
+
30
+ ```ruby
31
+ op = client.overpayment(tenant_id, "aea95d78-ea48-456b-9b08-6bc012600072")
32
+ op.total # => "100.00"
33
+ ```
34
+
35
+ `client.overpayment` hits `GET /api.xro/2.0/Overpayments/{OverpaymentID}` and
36
+ returns a single `XeroKiwi::Accounting::Overpayment`, or `nil` if the response is
37
+ empty.
38
+
39
+ ## The Overpayment object
40
+
41
+ Each `XeroKiwi::Accounting::Overpayment` is an immutable value object exposing the
42
+ fields Xero returns:
43
+
44
+ | Attribute | Type | What it is |
45
+ |-----------|------|------------|
46
+ | `overpayment_id` | `String` | The unique Xero identifier. |
47
+ | `type` | `String` | `"RECEIVE-OVERPAYMENT"` or `"SPEND-OVERPAYMENT"`. |
48
+ | `contact` | `XeroKiwi::Accounting::Contact` | The contact (reference — use `contact.reference?` to check). See [Contacts](contact.md). |
49
+ | `date` | `Time` | The date the overpayment was made, parsed as UTC. |
50
+ | `status` | `String` | e.g. `"AUTHORISED"`, `"PAID"`, `"VOIDED"`. |
51
+ | `line_amount_types` | `String` | `"Inclusive"`, `"Exclusive"`, or `"NoTax"`. |
52
+ | `line_items` | `Array<XeroKiwi::Accounting::LineItem>` | The line items. See [Prepayments — LineItem](prepayment.md#the-lineitem-object). |
53
+ | `sub_total` | `String` | The subtotal excluding taxes. |
54
+ | `total_tax` | `String` | The total tax amount. |
55
+ | `total` | `String` | The total (subtotal + total tax). |
56
+ | `updated_date_utc` | `Time` | When the overpayment was last modified, parsed as UTC. |
57
+ | `currency_code` | `String` | The currency code (e.g. `"NZD"`). |
58
+ | `currency_rate` | `String` | The currency rate (1.0 for base currency). |
59
+ | `remaining_credit` | `String` | The remaining credit balance. |
60
+ | `allocations` | `Array<XeroKiwi::Accounting::Allocation>` | Allocations to invoices. Each allocation has an `invoice` reference. |
61
+ | `payments` | `Array<XeroKiwi::Accounting::Payment>` | Payment records (references). See [Payments](payment.md). |
62
+ | `has_attachments` | `Boolean` | Whether the overpayment has attachments. |
63
+ | `reference` | `String` | Reference for the overpayment. |
64
+
65
+ ## Predicates
66
+
67
+ ```ruby
68
+ op.receive? # type == "RECEIVE-OVERPAYMENT"
69
+ op.spend? # type == "SPEND-OVERPAYMENT"
70
+ ```
71
+
72
+ ## Equality and hashing
73
+
74
+ Two overpayments are `==` if they share the same `overpayment_id`. `#hash` is
75
+ consistent with `==`, so overpayments work as hash keys and in sets.
76
+
77
+ ## Error behaviour
78
+
79
+ | HTTP status | Exception | What it usually means |
80
+ |-------------|-----------|------------------------|
81
+ | 200 | (none — returns overpayments) | Success |
82
+ | 401 | `XeroKiwi::AuthenticationError` | Access token is invalid or expired |
83
+ | 403 | `XeroKiwi::ClientError` | The token doesn't have the required scope |
84
+ | 404 | `XeroKiwi::ClientError` | The overpayment ID doesn't exist |
85
+
86
+ ## Common patterns
87
+
88
+ ### Listing overpayments with remaining credit
89
+
90
+ ```ruby
91
+ overpayments = client.overpayments(tenant_id)
92
+ with_credit = overpayments.select { |op| op.remaining_credit.to_f > 0 }
93
+ with_credit.each { |op| puts "#{op.overpayment_id}: #{op.remaining_credit} remaining" }
94
+ ```
@@ -0,0 +1,58 @@
1
+ # XeroKiwi::Accounting::PaymentTerms
2
+
3
+ Default payment terms for an organisation or contact, containing separate
4
+ terms for bills (accounts payable) and sales invoices (accounts receivable).
5
+
6
+ > See: [Xero docs — Payment terms](https://developer.xero.com/documentation/api/accounting/types#paymentterms)
7
+
8
+ ## Usage
9
+
10
+ ```ruby
11
+ if org.payment_terms
12
+ bills = org.payment_terms.bills
13
+ sales = org.payment_terms.sales
14
+
15
+ puts "Bills due: day #{bills.day} (#{bills.type})" if bills
16
+ puts "Sales due: day #{sales.day} (#{sales.type})" if sales
17
+ end
18
+ ```
19
+
20
+ ## PaymentTerms attributes
21
+
22
+ | Attribute | Type | Notes |
23
+ |-----------|------|-------|
24
+ | `bills` | `XeroKiwi::Accounting::PaymentTerm` | Default terms for accounts payable. `nil` if not configured. |
25
+ | `sales` | `XeroKiwi::Accounting::PaymentTerm` | Default terms for accounts receivable. `nil` if not configured. |
26
+
27
+ `PaymentTerms` itself is `nil` on the parent object when the organisation or
28
+ contact has no payment terms configured at all.
29
+
30
+ ## PaymentTerm attributes
31
+
32
+ Each side (bills or sales) is a `XeroKiwi::Accounting::PaymentTerm`:
33
+
34
+ | Attribute | Type | Notes |
35
+ |-----------|------|-------|
36
+ | `day` | `Integer` | Day of month (0–31) |
37
+ | `type` | `String` | The payment term type (see below) |
38
+
39
+ ### Payment term types
40
+
41
+ | Type | Meaning |
42
+ |------|---------|
43
+ | `DAYSAFTERBILLDATE` | Day(s) after bill date |
44
+ | `DAYSAFTERBILLMONTH` | Day(s) after bill month |
45
+ | `OFCURRENTMONTH` | Of the current month |
46
+ | `OFFOLLOWINGMONTH` | Of the following month |
47
+
48
+ ## Equality
49
+
50
+ Two `PaymentTerms` are `==` if both their `bills` and `sales` are equal. Two
51
+ `PaymentTerm` objects are `==` if they share the same `day` and `type`.
52
+
53
+ ## Serialisation
54
+
55
+ ```ruby
56
+ org.payment_terms.to_h
57
+ # => { bills: { day: 15, type: "OFCURRENTMONTH" }, sales: { day: 20, type: "OFFOLLOWINGMONTH" } }
58
+ ```
@@ -0,0 +1,99 @@
1
+ # Payments
2
+
3
+ A Xero **payment** records money received or paid against an invoice, credit
4
+ note, prepayment, or overpayment. Payments can be applied to approved AR and AP
5
+ invoices, and used to refund credit notes, prepayments, and overpayments. You
6
+ need a `tenant_id` from a [connection](../connections.md) before you can fetch
7
+ payments.
8
+
9
+ > See: [Xero docs — Payments](https://developer.xero.com/documentation/api/accounting/payments)
10
+
11
+ ## Listing payments
12
+
13
+ ```ruby
14
+ client = XeroKiwi::Client.new(access_token: "ya29...")
15
+
16
+ # Pass a tenant ID string…
17
+ payments = client.payments("70784a63-d24b-46a9-a4db-0e70a274b056")
18
+
19
+ # …or a XeroKiwi::Connection (its tenant_id is used automatically).
20
+ connection = client.connections.first
21
+ payments = client.payments(connection)
22
+ ```
23
+
24
+ `client.payments` hits `GET /api.xro/2.0/Payments` with the `Xero-Tenant-Id`
25
+ header set to the tenant you specify. It returns an
26
+ `Array<XeroKiwi::Accounting::Payment>`.
27
+
28
+ ## Fetching a single payment
29
+
30
+ ```ruby
31
+ payment = client.payment(tenant_id, "b26fd49a-cbae-470a-a8f8-bcbc119e0379")
32
+ payment.amount # => 500.00
33
+ ```
34
+
35
+ `client.payment` hits `GET /api.xro/2.0/Payments/{PaymentID}` and returns a
36
+ single `XeroKiwi::Accounting::Payment`, or `nil` if the response is empty.
37
+
38
+ ## The Payment object
39
+
40
+ Each `XeroKiwi::Accounting::Payment` is an immutable value object exposing the
41
+ fields Xero returns:
42
+
43
+ | Attribute | Type | What it is |
44
+ |-----------|------|------------|
45
+ | `payment_id` | `String` | The unique Xero identifier. |
46
+ | `date` | `Time` | The date the payment was made, parsed as UTC. |
47
+ | `currency_rate` | `Numeric` | Exchange rate (1.0 for base currency). |
48
+ | `amount` | `Numeric` | The payment amount in the invoice's currency. |
49
+ | `bank_amount` | `Numeric` | The payment amount in the account's currency. |
50
+ | `reference` | `String` | An optional description for the payment. |
51
+ | `is_reconciled` | `Boolean` | Whether the payment has been reconciled. |
52
+ | `status` | `String` | e.g. `"AUTHORISED"`, `"DELETED"`. |
53
+ | `payment_type` | `String` | e.g. `"ACCRECPAYMENT"`, `"ACCPAYPAYMENT"`. See Xero docs for all types. |
54
+ | `updated_date_utc` | `Time` | When the payment was last modified, parsed as UTC. |
55
+ | `batch_payment_id` | `String` | The batch payment ID, if created as part of a batch. |
56
+ | `batch_payment` | `Hash` | Batch payment details (raw hash). |
57
+ | `account` | `Hash` | The account the payment was made from (raw hash with `AccountID`, `Code`, `Name`). |
58
+ | `invoice` | `Hash` | The invoice the payment was made against (raw hash). |
59
+ | `credit_note` | `Hash` | The credit note being refunded (raw hash), if applicable. |
60
+ | `prepayment` | `Hash` | The prepayment being refunded (raw hash), if applicable. |
61
+ | `overpayment` | `Hash` | The overpayment being refunded (raw hash), if applicable. |
62
+ | `has_account` | `Boolean` | Whether the payment has an associated account. |
63
+
64
+ ## Predicates
65
+
66
+ ```ruby
67
+ payment.reconciled? # is_reconciled == true
68
+ ```
69
+
70
+ ## Equality and hashing
71
+
72
+ Two payments are `==` if they share the same `payment_id`. `#hash` is consistent
73
+ with `==`, so payments work as hash keys and in sets.
74
+
75
+ ## Error behaviour
76
+
77
+ | HTTP status | Exception | What it usually means |
78
+ |-------------|-----------|------------------------|
79
+ | 200 | (none — returns payments) | Success |
80
+ | 401 | `XeroKiwi::AuthenticationError` | Access token is invalid or expired |
81
+ | 403 | `XeroKiwi::ClientError` | The token doesn't have the required scope |
82
+ | 404 | `XeroKiwi::ClientError` | The payment ID doesn't exist |
83
+
84
+ ## Common patterns
85
+
86
+ ### Listing reconciled payments
87
+
88
+ ```ruby
89
+ payments = client.payments(tenant_id)
90
+ reconciled = payments.select(&:reconciled?)
91
+ reconciled.each { |p| puts "#{p.reference}: #{p.amount}" }
92
+ ```
93
+
94
+ ### Finding payments for a specific invoice
95
+
96
+ ```ruby
97
+ payments = client.payments(tenant_id)
98
+ for_invoice = payments.select { |p| p.invoice&.dig("InvoiceNumber") == "INV-0001" }
99
+ ```
@@ -0,0 +1,45 @@
1
+ # XeroKiwi::Accounting::Phone
2
+
3
+ A Xero phone number. Used by [Organisation](organisation.md), and in future by
4
+ Contact and other resources.
5
+
6
+ > See: [Xero docs — Phone types](https://developer.xero.com/documentation/api/accounting/types#phones)
7
+
8
+ ## Usage
9
+
10
+ ```ruby
11
+ org.phones.each do |phone|
12
+ puts "#{phone.phone_type}: #{phone.phone_country_code} #{phone.phone_area_code} #{phone.phone_number}"
13
+ end
14
+
15
+ mobile = org.phones.find(&:mobile?)
16
+ ```
17
+
18
+ ## Attributes
19
+
20
+ | Attribute | Type | Notes |
21
+ |-----------|------|-------|
22
+ | `phone_type` | `String` | `"DEFAULT"`, `"DDI"`, `"MOBILE"`, or `"FAX"` |
23
+ | `phone_number` | `String` | Max 50 characters |
24
+ | `phone_area_code` | `String` | Max 10 characters |
25
+ | `phone_country_code` | `String` | Max 20 characters |
26
+
27
+ ## Predicates
28
+
29
+ ```ruby
30
+ phone.default? # phone_type == "DEFAULT"
31
+ phone.mobile? # phone_type == "MOBILE"
32
+ phone.fax? # phone_type == "FAX"
33
+ ```
34
+
35
+ ## Equality
36
+
37
+ Two phones are `==` if all their attributes match. `#hash` is consistent
38
+ with `==`.
39
+
40
+ ## Serialisation
41
+
42
+ ```ruby
43
+ phone.to_h
44
+ # => { phone_type: "DEFAULT", phone_number: "1234567", phone_area_code: "09", phone_country_code: "64" }
45
+ ```