printavo-ruby 0.14.0 → 0.16.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 (186) hide show
  1. checksums.yaml +4 -4
  2. data/bin/console +13 -0
  3. data/bin/lint +113 -0
  4. data/bin/printavo +8 -0
  5. data/bin/spec +113 -0
  6. data/docs/CHANGELOG.md +48 -0
  7. data/docs/TODO.md +27 -6
  8. data/lib/printavo/cli.rb +82 -0
  9. data/lib/printavo/client.rb +14 -6
  10. data/lib/printavo/connection.rb +37 -9
  11. data/lib/printavo/enums/approval_request_status.rb +17 -0
  12. data/lib/printavo/enums/contact_sort_field.rb +16 -0
  13. data/lib/printavo/enums/line_item_size.rb +48 -0
  14. data/lib/printavo/enums/line_item_status.rb +19 -0
  15. data/lib/printavo/enums/merch_order_delivery_method.rb +14 -0
  16. data/lib/printavo/enums/merch_order_status.rb +14 -0
  17. data/lib/printavo/enums/merch_store_status.rb +14 -0
  18. data/lib/printavo/enums/message_delivery_status.rb +23 -0
  19. data/lib/printavo/enums/order_payment_status.rb +15 -0
  20. data/lib/printavo/enums/order_sort_field.rb +18 -0
  21. data/lib/printavo/enums/payment_dispute_status_field.rb +17 -0
  22. data/lib/printavo/enums/payment_request_status.rb +15 -0
  23. data/lib/printavo/enums/po_goods_status.rb +17 -0
  24. data/lib/printavo/enums/status_type.rb +14 -0
  25. data/lib/printavo/enums/task_sort_field.rb +14 -0
  26. data/lib/printavo/enums/taskable_type.rb +15 -0
  27. data/lib/printavo/enums/transaction_category.rb +18 -0
  28. data/lib/printavo/enums/transaction_source.rb +14 -0
  29. data/lib/printavo/enums.rb +21 -0
  30. data/lib/printavo/graphql/account/find.graphql +11 -0
  31. data/lib/printavo/graphql/approval_requests/all.graphql +23 -0
  32. data/lib/printavo/graphql/approval_requests/approve.graphql +8 -0
  33. data/lib/printavo/graphql/approval_requests/create.graphql +15 -0
  34. data/lib/printavo/graphql/approval_requests/find.graphql +15 -0
  35. data/lib/printavo/graphql/approval_requests/revoke.graphql +8 -0
  36. data/lib/printavo/graphql/approval_requests/unapprove.graphql +8 -0
  37. data/lib/printavo/graphql/categories/all.graphql +12 -0
  38. data/lib/printavo/graphql/categories/find.graphql +6 -0
  39. data/lib/printavo/graphql/contacts/create.graphql +11 -0
  40. data/lib/printavo/graphql/contacts/delete.graphql +5 -0
  41. data/lib/printavo/graphql/contacts/find.graphql +11 -0
  42. data/lib/printavo/graphql/contacts/update.graphql +11 -0
  43. data/lib/printavo/graphql/contractor_profiles/all.graphql +13 -0
  44. data/lib/printavo/graphql/contractor_profiles/find.graphql +7 -0
  45. data/lib/printavo/graphql/custom_addresses/all.graphql +18 -0
  46. data/lib/printavo/graphql/custom_addresses/create.graphql +10 -0
  47. data/lib/printavo/graphql/custom_addresses/creates.graphql +10 -0
  48. data/lib/printavo/graphql/custom_addresses/delete.graphql +5 -0
  49. data/lib/printavo/graphql/custom_addresses/deletes.graphql +5 -0
  50. data/lib/printavo/graphql/custom_addresses/find.graphql +10 -0
  51. data/lib/printavo/graphql/custom_addresses/update.graphql +10 -0
  52. data/lib/printavo/graphql/custom_addresses/updates.graphql +10 -0
  53. data/lib/printavo/graphql/customers/all.graphql +16 -0
  54. data/lib/printavo/graphql/customers/create.graphql +13 -0
  55. data/lib/printavo/graphql/customers/delete.graphql +5 -0
  56. data/lib/printavo/graphql/customers/find.graphql +10 -0
  57. data/lib/printavo/graphql/customers/update.graphql +13 -0
  58. data/lib/printavo/graphql/delivery_methods/all.graphql +12 -0
  59. data/lib/printavo/graphql/delivery_methods/archive.graphql +5 -0
  60. data/lib/printavo/graphql/delivery_methods/create.graphql +6 -0
  61. data/lib/printavo/graphql/delivery_methods/find.graphql +6 -0
  62. data/lib/printavo/graphql/delivery_methods/update.graphql +6 -0
  63. data/lib/printavo/graphql/email_templates/all.graphql +14 -0
  64. data/lib/printavo/graphql/email_templates/find.graphql +8 -0
  65. data/lib/printavo/graphql/expenses/all.graphql +16 -0
  66. data/lib/printavo/graphql/expenses/create.graphql +8 -0
  67. data/lib/printavo/graphql/expenses/find.graphql +8 -0
  68. data/lib/printavo/graphql/expenses/update.graphql +8 -0
  69. data/lib/printavo/graphql/fees/all.graphql +16 -0
  70. data/lib/printavo/graphql/fees/create.graphql +8 -0
  71. data/lib/printavo/graphql/fees/creates.graphql +8 -0
  72. data/lib/printavo/graphql/fees/delete.graphql +5 -0
  73. data/lib/printavo/graphql/fees/deletes.graphql +5 -0
  74. data/lib/printavo/graphql/fees/find.graphql +8 -0
  75. data/lib/printavo/graphql/fees/update.graphql +8 -0
  76. data/lib/printavo/graphql/fees/updates.graphql +8 -0
  77. data/lib/printavo/graphql/imprints/all.graphql +16 -0
  78. data/lib/printavo/graphql/imprints/create.graphql +8 -0
  79. data/lib/printavo/graphql/imprints/creates.graphql +8 -0
  80. data/lib/printavo/graphql/imprints/delete.graphql +5 -0
  81. data/lib/printavo/graphql/imprints/deletes.graphql +5 -0
  82. data/lib/printavo/graphql/imprints/find.graphql +8 -0
  83. data/lib/printavo/graphql/imprints/mockup_create.graphql +7 -0
  84. data/lib/printavo/graphql/imprints/mockup_creates.graphql +7 -0
  85. data/lib/printavo/graphql/imprints/update.graphql +8 -0
  86. data/lib/printavo/graphql/imprints/updates.graphql +8 -0
  87. data/lib/printavo/graphql/inquiries/all.graphql +25 -0
  88. data/lib/printavo/graphql/inquiries/create.graphql +19 -0
  89. data/lib/printavo/graphql/inquiries/delete.graphql +5 -0
  90. data/lib/printavo/graphql/inquiries/find.graphql +19 -0
  91. data/lib/printavo/graphql/inquiries/update.graphql +19 -0
  92. data/lib/printavo/graphql/invoices/all.graphql +30 -0
  93. data/lib/printavo/graphql/invoices/delete.graphql +5 -0
  94. data/lib/printavo/graphql/invoices/duplicate.graphql +27 -0
  95. data/lib/printavo/graphql/invoices/find.graphql +24 -0
  96. data/lib/printavo/graphql/invoices/update.graphql +24 -0
  97. data/lib/printavo/graphql/jobs/all.graphql +17 -0
  98. data/lib/printavo/graphql/jobs/find.graphql +9 -0
  99. data/lib/printavo/graphql/line_item_groups/all.graphql +15 -0
  100. data/lib/printavo/graphql/line_item_groups/create.graphql +7 -0
  101. data/lib/printavo/graphql/line_item_groups/creates.graphql +7 -0
  102. data/lib/printavo/graphql/line_item_groups/delete.graphql +5 -0
  103. data/lib/printavo/graphql/line_item_groups/deletes.graphql +5 -0
  104. data/lib/printavo/graphql/line_item_groups/find.graphql +7 -0
  105. data/lib/printavo/graphql/line_item_groups/update.graphql +7 -0
  106. data/lib/printavo/graphql/line_item_groups/updates.graphql +7 -0
  107. data/lib/printavo/graphql/line_items/all.graphql +17 -0
  108. data/lib/printavo/graphql/line_items/create.graphql +9 -0
  109. data/lib/printavo/graphql/line_items/creates.graphql +9 -0
  110. data/lib/printavo/graphql/line_items/delete.graphql +5 -0
  111. data/lib/printavo/graphql/line_items/deletes.graphql +5 -0
  112. data/lib/printavo/graphql/line_items/find.graphql +9 -0
  113. data/lib/printavo/graphql/line_items/mockup_create.graphql +7 -0
  114. data/lib/printavo/graphql/line_items/mockup_creates.graphql +7 -0
  115. data/lib/printavo/graphql/line_items/update.graphql +9 -0
  116. data/lib/printavo/graphql/line_items/updates.graphql +9 -0
  117. data/lib/printavo/graphql/merch_orders/all.graphql +25 -0
  118. data/lib/printavo/graphql/merch_orders/find.graphql +19 -0
  119. data/lib/printavo/graphql/merch_stores/all.graphql +17 -0
  120. data/lib/printavo/graphql/merch_stores/find.graphql +11 -0
  121. data/lib/printavo/graphql/mockups/all.graphql +16 -0
  122. data/lib/printavo/graphql/mockups/delete.graphql +5 -0
  123. data/lib/printavo/graphql/mockups/deletes.graphql +5 -0
  124. data/lib/printavo/graphql/mockups/find.graphql +8 -0
  125. data/lib/printavo/graphql/orders/all.graphql +25 -0
  126. data/lib/printavo/graphql/orders/create.graphql +19 -0
  127. data/lib/printavo/graphql/orders/delete.graphql +5 -0
  128. data/lib/printavo/graphql/orders/duplicate.graphql +24 -0
  129. data/lib/printavo/graphql/orders/find.graphql +19 -0
  130. data/lib/printavo/graphql/orders/update.graphql +19 -0
  131. data/lib/printavo/graphql/orders/update_status.graphql +18 -0
  132. data/lib/printavo/graphql/payment_requests/all.graphql +21 -0
  133. data/lib/printavo/graphql/payment_requests/create.graphql +13 -0
  134. data/lib/printavo/graphql/payment_requests/delete.graphql +5 -0
  135. data/lib/printavo/graphql/payment_requests/find.graphql +13 -0
  136. data/lib/printavo/graphql/payment_terms/all.graphql +13 -0
  137. data/lib/printavo/graphql/payment_terms/archive.graphql +5 -0
  138. data/lib/printavo/graphql/payment_terms/create.graphql +7 -0
  139. data/lib/printavo/graphql/payment_terms/find.graphql +7 -0
  140. data/lib/printavo/graphql/payment_terms/update.graphql +7 -0
  141. data/lib/printavo/graphql/payments/all.graphql +16 -0
  142. data/lib/printavo/graphql/payments/find.graphql +8 -0
  143. data/lib/printavo/graphql/preset_task_groups/all.graphql +17 -0
  144. data/lib/printavo/graphql/preset_task_groups/apply.graphql +13 -0
  145. data/lib/printavo/graphql/preset_task_groups/create.graphql +11 -0
  146. data/lib/printavo/graphql/preset_task_groups/delete.graphql +5 -0
  147. data/lib/printavo/graphql/preset_task_groups/find.graphql +11 -0
  148. data/lib/printavo/graphql/preset_task_groups/update.graphql +11 -0
  149. data/lib/printavo/graphql/preset_tasks/create.graphql +12 -0
  150. data/lib/printavo/graphql/preset_tasks/delete.graphql +5 -0
  151. data/lib/printavo/graphql/preset_tasks/find.graphql +12 -0
  152. data/lib/printavo/graphql/preset_tasks/update.graphql +12 -0
  153. data/lib/printavo/graphql/pricing_matrices/all.graphql +12 -0
  154. data/lib/printavo/graphql/pricing_matrices/find.graphql +6 -0
  155. data/lib/printavo/graphql/production_files/all.graphql +16 -0
  156. data/lib/printavo/graphql/production_files/create.graphql +8 -0
  157. data/lib/printavo/graphql/production_files/creates.graphql +8 -0
  158. data/lib/printavo/graphql/production_files/delete.graphql +5 -0
  159. data/lib/printavo/graphql/production_files/deletes.graphql +5 -0
  160. data/lib/printavo/graphql/production_files/find.graphql +8 -0
  161. data/lib/printavo/graphql/products/all.graphql +14 -0
  162. data/lib/printavo/graphql/products/find.graphql +8 -0
  163. data/lib/printavo/graphql/statuses/all.graphql +13 -0
  164. data/lib/printavo/graphql/statuses/find.graphql +7 -0
  165. data/lib/printavo/graphql/tasks/all.graphql +19 -0
  166. data/lib/printavo/graphql/tasks/create.graphql +13 -0
  167. data/lib/printavo/graphql/tasks/delete.graphql +5 -0
  168. data/lib/printavo/graphql/tasks/find.graphql +13 -0
  169. data/lib/printavo/graphql/tasks/update.graphql +13 -0
  170. data/lib/printavo/graphql/threads/all.graphql +16 -0
  171. data/lib/printavo/graphql/threads/email_message_create.graphql +7 -0
  172. data/lib/printavo/graphql/threads/find.graphql +8 -0
  173. data/lib/printavo/graphql/threads/update.graphql +8 -0
  174. data/lib/printavo/graphql/transaction_payments/create.graphql +9 -0
  175. data/lib/printavo/graphql/transaction_payments/delete.graphql +5 -0
  176. data/lib/printavo/graphql/transaction_payments/update.graphql +9 -0
  177. data/lib/printavo/graphql/transactions/all.graphql +16 -0
  178. data/lib/printavo/graphql/transactions/find.graphql +8 -0
  179. data/lib/printavo/graphql/types_of_work/all.graphql +12 -0
  180. data/lib/printavo/graphql/users/all.graphql +14 -0
  181. data/lib/printavo/graphql/users/find.graphql +8 -0
  182. data/lib/printavo/graphql/vendors/all.graphql +14 -0
  183. data/lib/printavo/graphql/vendors/find.graphql +8 -0
  184. data/lib/printavo/version.rb +1 -1
  185. data/lib/printavo.rb +1 -0
  186. metadata +195 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b0c6bbdd1f2e7dec2d40c9c5386385083049aa9f7fdd71d97ff2d8c91e0256b0
4
- data.tar.gz: fca9352dae13007b7a319ec7414cf0699b2169040cd0ad94fe5683adc9506676
3
+ metadata.gz: b42e7a5ddd23b104e211fa3f98443f1b27ba3388131051800e9c7984c26a7cea
4
+ data.tar.gz: fad8a0df2cd70466b6251b11dc070e808cbe31eb4d2d60693f3e26ae489e1bc4
5
5
  SHA512:
6
- metadata.gz: 81dc61d793eb316a7e98ef4d89338229504c3f7be1c104fb24685ff108d7dc495270635a5413795b981c5e2377c3f74eb0bfe5cf86db1ca19a11afd1a09d4460
7
- data.tar.gz: 1ab1cb1bf5d4950c615e407ff4008db7e07e200869a2aac5859cbbb3f8380a8d19f7dab8ea83a0eafb6f8225901cf6ca62e661816c3fe185269eb1141fb5a8dd
6
+ metadata.gz: 7074d4f0acfdbf08619e21f37b1315dbfac60845469da6a667f00d849b04a94b89959cfddac94e502153c01354cdca2c08ca1161b8e7606e20414755448deb1d
7
+ data.tar.gz: ec2ee5c644a2d07c25931ee10621e3962a1ac5200207b905925bc8586a8e1c3002a58bb7595c8f6f19420db38edbff234c53da11e9968ba8ad81b7bf3555dbec
data/bin/console ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # bin/console
3
+ require "bundler/setup"
4
+ require "printavo"
5
+
6
+ # Start an interactive session with the gem loaded.
7
+ # Set PRINTAVO_EMAIL and PRINTAVO_TOKEN in your environment before running.
8
+ #
9
+ # Example:
10
+ # PRINTAVO_EMAIL=you@example.com PRINTAVO_TOKEN=your_token bin/console
11
+
12
+ require "irb"
13
+ IRB.start(__FILE__)
data/bin/lint ADDED
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env bash
2
+ # bin/lint
3
+ #
4
+ # Runs RuboCop against every Ruby version declared in .mise.toml.
5
+ # Any arguments are forwarded directly to rubocop.
6
+ #
7
+ # Usage:
8
+ # bin/lint # all versions, full inspection
9
+ # bin/lint -a # auto-correct safe offenses, all versions
10
+ # bin/lint lib/printavo/client.rb # one file, all versions
11
+ #
12
+ # Requires mise: https://mise.jdx.dev
13
+
14
+ set -uo pipefail
15
+
16
+ # ── Colours (only when writing to a real terminal) ─────────────────────────
17
+ if [[ -t 1 ]]; then
18
+ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
19
+ CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
20
+ else
21
+ RED=''; GREEN=''; YELLOW=''; CYAN=''; BOLD=''; RESET=''
22
+ fi
23
+
24
+ # ── Locate project root ────────────────────────────────────────────────────
25
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
26
+ TOML="$ROOT/.mise.toml"
27
+
28
+ if [[ ! -f "$TOML" ]]; then
29
+ printf '%bError:%b .mise.toml not found at %s\n' "$RED" "$RESET" "$TOML" >&2
30
+ exit 1
31
+ fi
32
+
33
+ # ── Parse ruby versions from .mise.toml ────────────────────────────────────
34
+ # Handles both:
35
+ # ruby = "4.0.2" (scalar)
36
+ # ruby = ["4.0.2", "3.3.10"] (array, with optional trailing comma/comment)
37
+ ruby_line=$(grep -E '^\s*ruby\s*=' "$TOML" | head -1)
38
+
39
+ if [[ -z "$ruby_line" ]]; then
40
+ printf '%bError:%b no ruby entry found in .mise.toml\n' "$RED" "$RESET" >&2
41
+ exit 1
42
+ fi
43
+
44
+ # Pull every quoted token from the line into an array (bash 3-compatible)
45
+ VERSIONS=()
46
+ while IFS= read -r v; do
47
+ VERSIONS+=("$v")
48
+ done < <(printf '%s\n' "$ruby_line" | grep -oE '"[^"]+"' | tr -d '"')
49
+
50
+ if [[ ${#VERSIONS[@]} -eq 0 ]]; then
51
+ printf '%bError:%b could not parse ruby versions from: %s\n' "$RED" "$RESET" "$ruby_line" >&2
52
+ exit 1
53
+ fi
54
+
55
+ # ── Locate mise ────────────────────────────────────────────────────────────
56
+ MISE="${HOME}/.local/bin/mise"
57
+ [[ -x "$MISE" ]] || MISE=$(command -v mise 2>/dev/null || true)
58
+
59
+ if [[ -z "$MISE" ]]; then
60
+ printf '%bError:%b mise not found — install from https://mise.jdx.dev\n' "$RED" "$RESET" >&2
61
+ exit 1
62
+ fi
63
+
64
+ # ── Helpers ────────────────────────────────────────────────────────────────
65
+ # Track results in parallel arrays (bash 3: no associative arrays)
66
+ RESULT_VERSIONS=()
67
+ RESULT_STATUSES=()
68
+
69
+ record() { RESULT_VERSIONS+=("$1"); RESULT_STATUSES+=("$2"); }
70
+
71
+ # ── Run each version ───────────────────────────────────────────────────────
72
+ printf '\n%bprintavo-ruby%b — running RuboCop across %d Ruby version(s)\n\n' \
73
+ "$BOLD" "$RESET" "${#VERSIONS[@]}"
74
+
75
+ for version in "${VERSIONS[@]}"; do
76
+ printf '%b── Ruby %s%b ─────────────────────────────────────────────\n' \
77
+ "$CYAN" "$version" "$RESET"
78
+
79
+ # Verify the version is installed before trying to use it
80
+ if ! "$MISE" exec "ruby@${version}" -- ruby --version &>/dev/null 2>&1; then
81
+ printf '%b skipped%b — ruby %s not installed\n' "$YELLOW" "$RESET" "$version"
82
+ printf ' run: mise install ruby@%s\n\n' "$version"
83
+ record "$version" "skip"
84
+ continue
85
+ fi
86
+
87
+ # bundle install (quiet) then rubocop, both executed under the target Ruby
88
+ if "$MISE" exec "ruby@${version}" -- \
89
+ bash -c "cd '$ROOT' && bundle install --quiet && bundle exec rubocop $*"; then
90
+ record "$version" "pass"
91
+ else
92
+ record "$version" "fail"
93
+ fi
94
+ printf '\n'
95
+ done
96
+
97
+ # ── Summary ────────────────────────────────────────────────────────────────
98
+ printf '%bResults%b\n' "$BOLD" "$RESET"
99
+ printf '──────────────────────\n'
100
+
101
+ overall=0
102
+ for i in "${!RESULT_VERSIONS[@]}"; do
103
+ v="${RESULT_VERSIONS[$i]}"
104
+ s="${RESULT_STATUSES[$i]}"
105
+ case "$s" in
106
+ pass) printf ' Ruby %-8s %b✓ pass%b\n' "$v" "$GREEN" "$RESET" ;;
107
+ fail) printf ' Ruby %-8s %b✗ fail%b\n' "$v" "$RED" "$RESET"; overall=1 ;;
108
+ skip) printf ' Ruby %-8s %b⚠ skip%b\n' "$v" "$YELLOW" "$RESET" ;;
109
+ esac
110
+ done
111
+
112
+ printf '──────────────────────\n\n'
113
+ exit $overall
data/bin/printavo ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.join(__dir__, '..', 'lib'))
5
+
6
+ require 'printavo/cli'
7
+
8
+ Printavo::CLI.start(ARGV)
data/bin/spec ADDED
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env bash
2
+ # bin/spec
3
+ #
4
+ # Runs the RSpec suite against every Ruby version declared in .mise.toml.
5
+ # Any arguments are forwarded directly to rspec.
6
+ #
7
+ # Usage:
8
+ # bin/spec # all versions, all specs
9
+ # bin/spec spec/printavo/client_spec.rb # one file, all versions
10
+ # bin/spec --format documentation # forward rspec flags
11
+ #
12
+ # Requires mise: https://mise.jdx.dev
13
+
14
+ set -uo pipefail
15
+
16
+ # ── Colours (only when writing to a real terminal) ─────────────────────────
17
+ if [[ -t 1 ]]; then
18
+ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
19
+ CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
20
+ else
21
+ RED=''; GREEN=''; YELLOW=''; CYAN=''; BOLD=''; RESET=''
22
+ fi
23
+
24
+ # ── Locate project root ────────────────────────────────────────────────────
25
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
26
+ TOML="$ROOT/.mise.toml"
27
+
28
+ if [[ ! -f "$TOML" ]]; then
29
+ printf '%bError:%b .mise.toml not found at %s\n' "$RED" "$RESET" "$TOML" >&2
30
+ exit 1
31
+ fi
32
+
33
+ # ── Parse ruby versions from .mise.toml ────────────────────────────────────
34
+ # Handles both:
35
+ # ruby = "4.0.2" (scalar)
36
+ # ruby = ["4.0.2", "3.3.10"] (array, with optional trailing comma/comment)
37
+ ruby_line=$(grep -E '^\s*ruby\s*=' "$TOML" | head -1)
38
+
39
+ if [[ -z "$ruby_line" ]]; then
40
+ printf '%bError:%b no ruby entry found in .mise.toml\n' "$RED" "$RESET" >&2
41
+ exit 1
42
+ fi
43
+
44
+ # Pull every quoted token from the line into an array (bash 3-compatible)
45
+ VERSIONS=()
46
+ while IFS= read -r v; do
47
+ VERSIONS+=("$v")
48
+ done < <(printf '%s\n' "$ruby_line" | grep -oE '"[^"]+"' | tr -d '"')
49
+
50
+ if [[ ${#VERSIONS[@]} -eq 0 ]]; then
51
+ printf '%bError:%b could not parse ruby versions from: %s\n' "$RED" "$RESET" "$ruby_line" >&2
52
+ exit 1
53
+ fi
54
+
55
+ # ── Locate mise ────────────────────────────────────────────────────────────
56
+ MISE="${HOME}/.local/bin/mise"
57
+ [[ -x "$MISE" ]] || MISE=$(command -v mise 2>/dev/null || true)
58
+
59
+ if [[ -z "$MISE" ]]; then
60
+ printf '%bError:%b mise not found — install from https://mise.jdx.dev\n' "$RED" "$RESET" >&2
61
+ exit 1
62
+ fi
63
+
64
+ # ── Helpers ────────────────────────────────────────────────────────────────
65
+ # Track results in parallel arrays (bash 3: no associative arrays)
66
+ RESULT_VERSIONS=()
67
+ RESULT_STATUSES=()
68
+
69
+ record() { RESULT_VERSIONS+=("$1"); RESULT_STATUSES+=("$2"); }
70
+
71
+ # ── Run each version ────────────────────────────────────────────────────────
72
+ printf '\n%bprintavo-ruby%b — running specs across %d Ruby version(s)\n\n' \
73
+ "$BOLD" "$RESET" "${#VERSIONS[@]}"
74
+
75
+ for version in "${VERSIONS[@]}"; do
76
+ printf '%b── Ruby %s%b ─────────────────────────────────────────────\n' \
77
+ "$CYAN" "$version" "$RESET"
78
+
79
+ # Verify the version is installed before trying to use it
80
+ if ! "$MISE" exec "ruby@${version}" -- ruby --version &>/dev/null 2>&1; then
81
+ printf '%b skipped%b — ruby %s not installed\n' "$YELLOW" "$RESET" "$version"
82
+ printf ' run: mise install ruby@%s\n\n' "$version"
83
+ record "$version" "skip"
84
+ continue
85
+ fi
86
+
87
+ # bundle install (quiet) then rspec, both executed under the target Ruby
88
+ if "$MISE" exec "ruby@${version}" -- \
89
+ bash -c "cd '$ROOT' && bundle install --quiet && bundle exec rspec $*"; then
90
+ record "$version" "pass"
91
+ else
92
+ record "$version" "fail"
93
+ fi
94
+ printf '\n'
95
+ done
96
+
97
+ # ── Summary ────────────────────────────────────────────────────────────────
98
+ printf '%bResults%b\n' "$BOLD" "$RESET"
99
+ printf '──────────────────────\n'
100
+
101
+ overall=0
102
+ for i in "${!RESULT_VERSIONS[@]}"; do
103
+ v="${RESULT_VERSIONS[$i]}"
104
+ s="${RESULT_STATUSES[$i]}"
105
+ case "$s" in
106
+ pass) printf ' Ruby %-8s %b✓ pass%b\n' "$v" "$GREEN" "$RESET" ;;
107
+ fail) printf ' Ruby %-8s %b✗ fail%b\n' "$v" "$RED" "$RESET"; overall=1 ;;
108
+ skip) printf ' Ruby %-8s %b⚠ skip%b\n' "$v" "$YELLOW" "$RESET" ;;
109
+ esac
110
+ done
111
+
112
+ printf '──────────────────────\n\n'
113
+ exit $overall
data/docs/CHANGELOG.md CHANGED
@@ -6,6 +6,54 @@ All notable changes to this project will be documented in this file.
6
6
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
7
7
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [0.16.0] - 2026-04-01
10
+
11
+ ### Added
12
+ - `Printavo::Enums` namespace — 18 enum modules covering every GraphQL enum in the
13
+ Printavo V2 schema (excluding `__DirectiveLocation` and `__TypeKind`, which are
14
+ GraphQL introspection internals):
15
+ - `ApprovalRequestStatus` — APPROVED, PENDING, REVOKED, UNAPPROVED
16
+ - `ContactSortField` — CREATED_AT, EMAIL, FIRST_NAME, LAST_NAME, UPDATED_AT
17
+ - `LineItemSize` — full garment size set (XS–6XL, youth, toddler, infant, OS, NONE)
18
+ - `LineItemStatus` — ACTIVE, CANCELLED
19
+ - `MerchOrderDeliveryMethod` — LOCAL_DELIVERY, PICKUP, SHIP
20
+ - `MerchOrderStatus` — CANCELLED, COMPLETE, PENDING, PROCESSING
21
+ - `MerchStoreStatus` — ACTIVE, ARCHIVED, CLOSED
22
+ - `MessageDeliveryStatus` — BOUNCED, DELIVERED, FAILED, PENDING, SENT
23
+ - `OrderPaymentStatus` — PAID, PARTIAL, UNPAID
24
+ - `OrderSortField` — CREATED_AT, CUSTOMER_DUE_AT, DUE_AT, UPDATED_AT, VISUAL_ID
25
+ - `PaymentDisputeStatusField` — LOST, NEEDS_RESPONSE, RESOLVED, UNDER_REVIEW, WON
26
+ - `PaymentRequestStatus` — CANCELLED, PAID, SENT
27
+ - `PoGoodsStatus` — CANCELLED, PARTIAL, PENDING, RECEIVED
28
+ - `StatusType` — INVOICE, QUOTE
29
+ - `TaskSortField` — BODY, CREATED_AT, DUE_AT, UPDATED_AT
30
+ - `TaskableType` — INVOICE, QUOTE
31
+ - `TransactionCategory` — PAYMENT, REFUND
32
+ - `TransactionSource` — CARD, CASH, CHECK, MANUAL, ONLINE
33
+ - Each enum exposes an `ALL` frozen array of all values
34
+ - Shared RSpec example `'a Printavo enum'` validates structure across all 18 modules
35
+
36
+ ### Notes
37
+ - Enum values are the best-effort representation of the Printavo V2 schema at time of
38
+ release. Values that differ from the live schema should be reported as patch issues.
39
+
40
+ ## [0.15.0] - 2026-04-01
41
+
42
+ ### Added
43
+ - `Printavo::Client` now accepts `max_retries:` (default: 2) and `retry_on_rate_limit:` (default: true)
44
+ - `Printavo::Connection` — exponential backoff with ±50% jitter on retries (`backoff_factor: 2`,
45
+ `interval_randomness: 0.5`); retry statuses are `[500, 502, 503]` plus `429` when
46
+ `retry_on_rate_limit: true`
47
+ - `Printavo::CLI` — Thor-based command-line interface:
48
+ - `printavo customers [--first N]` — list customers (tab-aligned output)
49
+ - `printavo orders [--first N]` — list orders (default subcommand)
50
+ - `printavo orders find ID` — find and display a single order
51
+ - Credentials read from `PRINTAVO_EMAIL` / `PRINTAVO_TOKEN` environment variables
52
+ - `bin/printavo` executable (installed to PATH as `printavo`)
53
+ - `thor ~> 1.0` added as a runtime dependency
54
+ - `.graphql` files and `bin/` now included in `spec.files` (fixes missing graphql files in
55
+ published gem)
56
+
9
57
  ## [0.14.0] - 2026-04-01
10
58
 
11
59
  ### Added
data/docs/TODO.md CHANGED
@@ -374,12 +374,33 @@ return values — they are exposed via model field accessors, not separate resou
374
374
  - [x] `Orders#delete` — `quoteDelete`
375
375
  - [x] `Orders#duplicate` — `quoteDuplicate`
376
376
 
377
- ### v0.15.0 — Retry / Backoff & CLI
378
-
379
- - [ ] Configurable `max_retries` on `Printavo::Client`
380
- - [ ] Exponential backoff with jitter on 429 responses
381
- - [ ] `retry_on_rate_limit: true/false` client option
382
- - [ ] Thor-based `printavo` CLI (`customers`, `orders`, `orders find <id>`)
377
+ ### v0.15.0 — Retry / Backoff & CLI
378
+
379
+ - [x] Configurable `max_retries` on `Printavo::Client`
380
+ - [x] Exponential backoff with jitter on 429 responses
381
+ - [x] `retry_on_rate_limit: true/false` client option
382
+ - [x] Thor-based `printavo` CLI (`customers`, `orders`, `orders find <id>`)
383
+
384
+ ### v0.16.0 — Enums ✅
385
+
386
+ - [x] `Printavo::Enums::ApprovalRequestStatus`
387
+ - [x] `Printavo::Enums::ContactSortField`
388
+ - [x] `Printavo::Enums::LineItemSize`
389
+ - [x] `Printavo::Enums::LineItemStatus`
390
+ - [x] `Printavo::Enums::MerchOrderDeliveryMethod`
391
+ - [x] `Printavo::Enums::MerchOrderStatus`
392
+ - [x] `Printavo::Enums::MerchStoreStatus`
393
+ - [x] `Printavo::Enums::MessageDeliveryStatus`
394
+ - [x] `Printavo::Enums::OrderPaymentStatus`
395
+ - [x] `Printavo::Enums::OrderSortField`
396
+ - [x] `Printavo::Enums::PaymentDisputeStatusField`
397
+ - [x] `Printavo::Enums::PaymentRequestStatus`
398
+ - [x] `Printavo::Enums::PoGoodsStatus`
399
+ - [x] `Printavo::Enums::StatusType`
400
+ - [x] `Printavo::Enums::TaskSortField`
401
+ - [x] `Printavo::Enums::TaskableType`
402
+ - [x] `Printavo::Enums::TransactionCategory`
403
+ - [x] `Printavo::Enums::TransactionSource`
383
404
 
384
405
  ### v0.99.0 — API Freeze
385
406
 
@@ -0,0 +1,82 @@
1
+ # lib/printavo/cli.rb
2
+ # frozen_string_literal: true
3
+
4
+ require 'thor'
5
+ require 'printavo'
6
+
7
+ module Printavo
8
+ # Shared credential helper included by CLI and its subcommands.
9
+ module CLIHelpers
10
+ private
11
+
12
+ # Builds a Printavo::Client from PRINTAVO_EMAIL / PRINTAVO_TOKEN env vars.
13
+ # Raises Thor::Error with a human-readable message if either is missing.
14
+ def build_client
15
+ email = ENV.fetch('PRINTAVO_EMAIL', nil)
16
+ token = ENV.fetch('PRINTAVO_TOKEN', nil)
17
+ raise Thor::Error, 'PRINTAVO_EMAIL environment variable is required' unless email && !email.empty?
18
+ raise Thor::Error, 'PRINTAVO_TOKEN environment variable is required' unless token && !token.empty?
19
+
20
+ Printavo::Client.new(email: email, token: token)
21
+ end
22
+ end
23
+
24
+ class CLI < Thor
25
+ include CLIHelpers
26
+
27
+ package_name 'printavo'
28
+
29
+ def self.exit_on_failure? = true
30
+
31
+ # ---------------------------------------------------------------------------
32
+ # version
33
+ # ---------------------------------------------------------------------------
34
+
35
+ desc 'version', 'Print the printavo-ruby gem version'
36
+ def version
37
+ say Printavo::VERSION
38
+ end
39
+
40
+ # ---------------------------------------------------------------------------
41
+ # customers
42
+ # ---------------------------------------------------------------------------
43
+
44
+ desc 'customers', 'List customers'
45
+ method_option :first, type: :numeric, default: 25, desc: 'Number of records to return'
46
+ def customers
47
+ build_client.customers.all(first: options[:first]).each do |c|
48
+ say "#{c.id.to_s.ljust(10)} #{c.full_name.to_s.ljust(30)} #{c.email}"
49
+ end
50
+ end
51
+
52
+ # ---------------------------------------------------------------------------
53
+ # orders subcommand
54
+ # ---------------------------------------------------------------------------
55
+
56
+ class Orders < Thor
57
+ include CLIHelpers
58
+
59
+ default_task :list
60
+
61
+ desc 'list', 'List orders (default)'
62
+ method_option :first, type: :numeric, default: 25, desc: 'Number of records to return'
63
+ def list
64
+ build_client.orders.all(first: options[:first]).each do |o|
65
+ say "#{o.id.to_s.ljust(10)} #{o.nickname.to_s.ljust(30)} #{o.total_price}"
66
+ end
67
+ end
68
+
69
+ desc 'find ID', 'Find an order by ID'
70
+ def find(id)
71
+ o = build_client.orders.find(id)
72
+ say "id: #{o.id}"
73
+ say "nickname: #{o.nickname}"
74
+ say "total_price: #{o.total_price}"
75
+ say "status: #{o.status}"
76
+ end
77
+ end
78
+
79
+ desc 'orders SUBCOMMAND ...ARGS', 'List orders or find a specific order'
80
+ subcommand 'orders', Orders
81
+ end
82
+ end
@@ -8,9 +8,11 @@ module Printavo
8
8
  # Creates a new Printavo API client. Each instance is independent —
9
9
  # multiple clients with different credentials can coexist in one process.
10
10
  #
11
- # @param email [String] the email address associated with your Printavo account
12
- # @param token [String] the API token from your Printavo My Account page
13
- # @param timeout [Integer] HTTP timeout in seconds (default: 30)
11
+ # @param email [String] the email address associated with your Printavo account
12
+ # @param token [String] the API token from your Printavo My Account page
13
+ # @param timeout [Integer] HTTP timeout in seconds (default: 30)
14
+ # @param max_retries [Integer] max retry attempts on 5xx/429 responses (default: 2)
15
+ # @param retry_on_rate_limit [Boolean] retry automatically on 429 Too Many Requests (default: true)
14
16
  #
15
17
  # @example
16
18
  # client = Printavo::Client.new(
@@ -20,9 +22,15 @@ module Printavo
20
22
  # client.customers.all
21
23
  # client.orders.find("12345")
22
24
  # client.graphql.query("{ customers { nodes { id } } }")
23
- def initialize(email:, token:, timeout: 30)
24
- connection = Connection.new(email: email, token: token, timeout: timeout).build
25
- @graphql = GraphqlClient.new(connection)
25
+ def initialize(email:, token:, timeout: 30, max_retries: 2, retry_on_rate_limit: true)
26
+ connection = Connection.new(
27
+ email: email,
28
+ token: token,
29
+ timeout: timeout,
30
+ max_retries: max_retries,
31
+ retry_on_rate_limit: retry_on_rate_limit
32
+ ).build
33
+ @graphql = GraphqlClient.new(connection)
26
34
  end
27
35
 
28
36
  def account
@@ -6,11 +6,20 @@ require 'faraday/retry'
6
6
 
7
7
  module Printavo
8
8
  class Connection
9
- def initialize(email:, token:, base_url: Config::BASE_URL, timeout: 30)
10
- @email = email
11
- @token = token
12
- @base_url = base_url
13
- @timeout = timeout
9
+ # @param email [String] Printavo account email
10
+ # @param token [String] Printavo API token
11
+ # @param base_url [String] API base URL (default: Config::BASE_URL)
12
+ # @param timeout [Integer] HTTP timeout in seconds (default: 30)
13
+ # @param max_retries [Integer] Max retry attempts on 5xx/429 (default: 2)
14
+ # @param retry_on_rate_limit [Boolean] Retry on 429 Too Many Requests (default: true)
15
+ def initialize(email:, token:, base_url: Config::BASE_URL, timeout: 30, # rubocop:disable Metrics/ParameterLists
16
+ max_retries: 2, retry_on_rate_limit: true)
17
+ @email = email
18
+ @token = token
19
+ @base_url = base_url
20
+ @timeout = timeout
21
+ @max_retries = max_retries
22
+ @retry_on_rate_limit = retry_on_rate_limit
14
23
  end
15
24
 
16
25
  def build
@@ -19,15 +28,34 @@ module Printavo
19
28
  f.headers['Accept'] = 'application/json'
20
29
  f.headers['email'] = @email
21
30
  f.headers['token'] = @token
22
-
23
- f.request :retry, max: 2, interval: 0.5, retry_statuses: [429, 500, 502, 503]
24
-
31
+ f.request :retry, **retry_options
25
32
  f.response :json
26
33
  f.options.timeout = @timeout
27
34
  f.options.open_timeout = @timeout
28
-
29
35
  f.adapter Faraday.default_adapter
30
36
  end
31
37
  end
38
+
39
+ private
40
+
41
+ # Exponential backoff: base interval × 2^attempt, ±50% jitter.
42
+ # interval_randomness adds up to 50% random variance per retry.
43
+ def retry_options
44
+ {
45
+ max: @max_retries,
46
+ interval: 0.5,
47
+ backoff_factor: 2,
48
+ interval_randomness: 0.5,
49
+ retry_statuses: retry_statuses
50
+ }
51
+ end
52
+
53
+ # Returns the set of HTTP status codes that trigger a retry.
54
+ # 429 is only included when +retry_on_rate_limit+ is true (the default).
55
+ def retry_statuses
56
+ statuses = [500, 502, 503]
57
+ statuses << 429 if @retry_on_rate_limit
58
+ statuses
59
+ end
32
60
  end
33
61
  end
@@ -0,0 +1,17 @@
1
+ # lib/printavo/enums/approval_request_status.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Enums
6
+ # Possible values for the +ApprovalRequest+ status field.
7
+ module ApprovalRequestStatus
8
+ APPROVED = 'approved'
9
+ DECLINED = 'declined'
10
+ PENDING = 'pending'
11
+ REVOKED = 'revoked'
12
+ UNAPPROVED = 'unapproved'
13
+
14
+ ALL = [APPROVED, DECLINED, PENDING, REVOKED, UNAPPROVED].freeze
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ # lib/printavo/enums/contact_sort_field.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Enums
6
+ # Fields by which a contact list can be sorted.
7
+ module ContactSortField
8
+ CONTACT_EMAIL = 'CONTACT_EMAIL'
9
+ CONTACT_NAME = 'CONTACT_NAME'
10
+ CUSTOMER_NAME = 'CUSTOMER_NAME'
11
+ ORDER_COUNT = 'ORDER_COUNT'
12
+
13
+ ALL = [CONTACT_EMAIL, CONTACT_NAME, CUSTOMER_NAME, ORDER_COUNT].freeze
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,48 @@
1
+ # lib/printavo/enums/line_item_size.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Enums
6
+ # Garment size values for line items. All values carry the +size_+ prefix
7
+ # as returned by the Printavo V2 GraphQL API.
8
+ module LineItemSize
9
+ # Adult
10
+ XS = 'size_xs'
11
+ S = 'size_s'
12
+ M = 'size_m'
13
+ L = 'size_l'
14
+ XL = 'size_xl'
15
+ TWO_XL = 'size_2xl'
16
+ THREE_XL = 'size_3xl'
17
+ FOUR_XL = 'size_4xl'
18
+ FIVE_XL = 'size_5xl'
19
+ SIX_XL = 'size_6xl'
20
+ # Youth
21
+ YOUTH_XS = 'size_yxs'
22
+ YOUTH_S = 'size_ys'
23
+ YOUTH_M = 'size_ym'
24
+ YOUTH_L = 'size_yl'
25
+ YOUTH_XL = 'size_yxl'
26
+ # Toddler
27
+ TODDLER_2T = 'size_2t'
28
+ TODDLER_3T = 'size_3t'
29
+ TODDLER_4T = 'size_4t'
30
+ TODDLER_5T = 'size_5t'
31
+ # Infant
32
+ INFANT_6M = 'size_6m'
33
+ INFANT_12M = 'size_12m'
34
+ INFANT_18M = 'size_18m'
35
+ INFANT_24M = 'size_24m'
36
+ # Other
37
+ OTHER = 'size_other'
38
+
39
+ ALL = [
40
+ XS, S, M, L, XL, TWO_XL, THREE_XL, FOUR_XL, FIVE_XL, SIX_XL,
41
+ YOUTH_XS, YOUTH_S, YOUTH_M, YOUTH_L, YOUTH_XL,
42
+ TODDLER_2T, TODDLER_3T, TODDLER_4T, TODDLER_5T,
43
+ INFANT_6M, INFANT_12M, INFANT_18M, INFANT_24M,
44
+ OTHER
45
+ ].freeze
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,19 @@
1
+ # lib/printavo/enums/line_item_status.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Enums
6
+ # Inventory / fulfillment status of a +LineItem+.
7
+ module LineItemStatus
8
+ ARRIVED = 'arrived'
9
+ ATTACHED_TO_PO = 'attached_to_po'
10
+ IN = 'in'
11
+ NEED_ORDERING = 'need_ordering'
12
+ ORDERED = 'ordered'
13
+ PARTIALLY_RECEIVED = 'partially_received'
14
+ RECEIVED = 'received'
15
+
16
+ ALL = [ARRIVED, ATTACHED_TO_PO, IN, NEED_ORDERING, ORDERED, PARTIALLY_RECEIVED, RECEIVED].freeze
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ # lib/printavo/enums/merch_order_delivery_method.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Enums
6
+ # How a merch order will be fulfilled and delivered to the buyer.
7
+ module MerchOrderDeliveryMethod
8
+ DELIVERY = 'DELIVERY'
9
+ PICKUP = 'PICKUP'
10
+
11
+ ALL = [DELIVERY, PICKUP].freeze
12
+ end
13
+ end
14
+ end