printavo-ruby 0.5.2 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72653b7d55ebd17fbbc5331c50e530cbb15655175c35190ba3c740e5f53fad0f
4
- data.tar.gz: 2f0bd39de81b2862289510ec8b282e3009165d86aa8c32c27a96b6f03228fc9e
3
+ metadata.gz: 4f1b8022189ac0b62b87b7d9770c08b3f2320c6804705c41afd6e2b03c7239ca
4
+ data.tar.gz: 94761c4186f08d33b841eb9d364350f142c5b7b007d0f1fce2c08e7e237156d8
5
5
  SHA512:
6
- metadata.gz: 8dd07daab212f1a7cf4a137fd3890f099422f7fc24cb15a2368f30864d7d9c701c83c7d4d0d27a59dcec3ec11444ddb4f11acae4edf035d4033ab03523ad4127
7
- data.tar.gz: 013ea7ed343e5ee3915f9092609e756b4f917d0f1d24dd6c04b4a4c837dc0dbd5d2a3d475ac67e5bde40e9ff335b219c1b352627ae8e925ac857ac9fba17951f
6
+ metadata.gz: 5c22e476b535a7eebe9fba9a51ed5a36016a6da07c3f8f4e5cce478d609ee358316097f06bab770ebcdb3ec2cd43b0b5939bdc109394237691b0a4f8370cd6b4
7
+ data.tar.gz: 266b1fd4d0e738ca3928225681367371f6e3dc7ac26a1771e8758ff2ea6cac6adc40130e57bf7553d043a99fb2a464c1c0d609489c6f6ae83fde1568821ba716
data/docs/CHANGELOG.md CHANGED
@@ -6,6 +6,52 @@ 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.7.0] - 2026-03-30
10
+
11
+ ### Added
12
+ - `Printavo::Transaction` model (`id`, `amount`, `kind`, `created_at`)
13
+ - `Transactions` resource: `all(order_id:)`, `find(id)` — scoped to an order, same pattern as Jobs
14
+ - `Printavo::TransactionPayment` model (`id`, `amount`, `payment_method`, `paid_at`, `note`)
15
+ - `TransactionPayments` resource: `create(**input)`, `update(id, **input)`, `delete(id)` —
16
+ mutation-only; `transactionPaymentCreate/Update/Delete`
17
+ - `Printavo::Task` model (`id`, `body`, `due_at`, `completed_at`, `completed?`, `assignee`)
18
+ - `Tasks` resource: `all`, `find(id)`, `create(**input)`, `update(id, **input)`,
19
+ `complete(id)` (sets `completedAt` to now via `taskUpdate`), `delete(id)`
20
+ - `Printavo::Thread` model (`id`, `subject`, `created_at`, `updated_at`)
21
+ - `Threads` resource: `all(order_id:)`, `find(id)`, `update(id, **input)`,
22
+ `email_message_create(**input)` — `threadUpdate` + `emailMessageCreate` mutations;
23
+ returns raw hash (no `EmailMessage` model yet)
24
+ - `client.tasks`, `client.threads`, `client.transactions`, `client.transaction_payments`
25
+ entry points on `Printavo::Client`
26
+ - 14 new `.graphql` files under `lib/printavo/graphql/`
27
+ - `Client#login` / `Client#logout` raise `NotImplementedError` with a message directing
28
+ consumers to the `email` + `token` initializer; gem uses stateless header-based auth
29
+
30
+ ## [0.6.0] - 2026-03-30
31
+
32
+ ### Added
33
+ - `Printavo::Contact` model (`id`, `first_name`, `last_name`, `full_name`, `email`, `phone`, `fax`)
34
+ - `Contacts` resource: `find(id)`, `create(**input)`, `contactCreate` mutation,
35
+ `update(id, **input)`, `contactUpdate` mutation
36
+ - `Printavo::Invoice` model (`id`, `nickname`, `total`, `amount_paid`,
37
+ `amount_outstanding`, `paid_in_full?`, `invoice_at`, `payment_due_at`,
38
+ `status`, `status_key`, `status?`, `contact`)
39
+ - `Invoices` resource: `all`, `find(id)`, `update(id, **input)` (`invoiceUpdate` mutation);
40
+ note: invoices are promoted from quotes, so no `create` — use `client.orders.create`
41
+ - `Printavo::Account` model (`id`, `company_name`, `company_email`, `phone`,
42
+ `website`, `logo_url`, `locale`)
43
+ - `Account` resource: singleton `find` — no ID argument, returns the account
44
+ associated with the current API credentials
45
+ - `client.contacts`, `client.invoices`, `client.account` entry points on `Printavo::Client`
46
+ - 10 new `.graphql` files under `lib/printavo/graphql/` (contacts/find, create, update;
47
+ invoices/all, find, update; account/find)
48
+
49
+ ### Changed
50
+ - `spec/support/factories.rb` split into 9 domain files under `spec/support/factories/`
51
+ (`account`, `contact`, `customer`, `graphql`, `inquiry`, `invoice`, `job`, `order`, `status`)
52
+ - `spec/spec_helper.rb` loads factory files via `Dir` glob; `config.include Factories` moved here
53
+ - Removed `Metrics/ModuleLength` exclusion from `.rubocop.yml` — no longer needed
54
+
9
55
  ## [0.5.2] - 2026-03-30
10
56
 
11
57
  ### Changed
data/docs/TODO.md CHANGED
@@ -21,6 +21,7 @@ Full task list for `printavo-ruby` across all versions. Checked items are shippe
21
21
  - [x] GitHub Actions CI: Ruby 3.3 + Ruby 4.0 matrix
22
22
  - [x] Automated RubyGems publish on `v*` tag via trusted publishing (`release.yml`)
23
23
  - [x] Git pre-push hook: guards `Gemfile.lock` version sync and `x86_64-linux` platform
24
+ - [x] `Client#login` / `Client#logout` — raise `NotImplementedError`; gem uses header-based auth, not session mutations
24
25
 
25
26
  ---
26
27
 
@@ -51,6 +52,13 @@ Full task list for `printavo-ruby` across all versions. Checked items are shippe
51
52
  - [x] `Inquiries#update(id, **input)` — `inquiryUpdate`
52
53
  - [x] `camelize_keys` — snake_case → camelCase input conversion
53
54
  - [x] `build_customer` / `build_order` — mutation response normalization helpers
55
+ - [ ] `Contacts#delete(id)` — `contactDelete`
56
+ - [ ] `Customers#delete(id)` — `customerDelete`
57
+ - [ ] `Inquiries#delete(id)` — `inquiryDelete`
58
+ - [ ] `Invoices#delete(id)` — `invoiceDelete`
59
+ - [ ] `Invoices#duplicate(id)` — `invoiceDuplicate`
60
+ - [ ] `Orders#delete(id)` — `quoteDelete`
61
+ - [ ] `Orders#duplicate(id)` — `quoteDuplicate`
54
62
 
55
63
  ---
56
64
 
@@ -69,6 +77,7 @@ Full task list for `printavo-ruby` across all versions. Checked items are shippe
69
77
  - [x] Extract 17 GraphQL heredocs into external `.graphql` files (`lib/printavo/graphql/<resource>/<op>.graphql`)
70
78
  - [x] `docs/` consolidation — `CHANGELOG.md`, `CONTRIBUTING.md`, `FUTURE.md`, `CACHING.md`
71
79
  - [x] `docs/CACHING.md` — nine caching strategy patterns for rate-limit-aware consumers
80
+ - [x] Split `spec/support/factories.rb` monolith into 9 domain files under `spec/support/factories/`
72
81
 
73
82
  ---
74
83
 
@@ -86,103 +95,293 @@ Resources and mutations present in the Printavo V2 GraphQL API that are not yet
86
95
  wrapped by a resource class. Raw GraphQL access works for all of these today via
87
96
  `client.graphql.query(...)` — these tasks add first-class resource support.
88
97
 
89
- ### Contacts
98
+ ### Embedded / Infrastructure Types (no standalone resource needed)
99
+
100
+ These types appear in the schema but are sub-objects, pagination wrappers, or
101
+ return values — they are exposed via model field accessors, not separate resources.
102
+
103
+ - `*Connection` / `*Edge` (all variants) — GraphQL pagination wrappers; handled by `Printavo::Page`
104
+ - `Address`, `BillingAddress`, `CustomerAddress`, `MerchAddress`, `CustomAddress` — embedded address shapes
105
+ - `Avatar` — embedded in `User`
106
+ - `CatalogInformation`, `InvoiceInformation` — embedded in `Account`
107
+ - `DeletedID` — return type for delete mutations
108
+ - `EmailMessage`, `TextMessage` — message subtypes under `Thread`
109
+ - `Feature`, `FeatureRestriction` — embedded in `Account.features`
110
+ - `LineItemEnabledColumns`, `LineItemGroupSize`, `LineItemPriceReceipt`, `LineItemSizeCount` — embedded in `LineItemGroup` / `LineItem`
111
+ - `LoggedIn` — auth response type for `login` / `logout` mutations; not wrapped — gem uses
112
+ header-based auth. Both methods raise `NotImplementedError` on `Printavo::Client` with a
113
+ message directing consumers to the `email` + `token` initializer pattern.
114
+ - `MerchOrderDelivery`, `MerchStoreSummary` — embedded in `MerchOrder` / `MerchStore`
115
+ - `MessageAttachment` — embedded in `Thread` messages
116
+ - `ObjectTimestamps` — `createdAt` / `updatedAt` on all objects
117
+ - `OrderUnionConnection` / `OrderUnionEdge` — union pagination for `Quote | Invoice`; handled via inline fragments
118
+ - `PageInfo` — cursor pagination metadata; handled by `Printavo::Page`
119
+ - `PaymentRequestDetail` — embedded in `PaymentRequest`
120
+ - `Permission` — embedded in `User`
121
+ - `Personalization` — size/color breakdown embedded in `LineItem` / `Imprint`
122
+ - `PricingMatrixCell`, `PricingMatrixColumn` — sub-objects of `PricingMatrix`
123
+ - `ProductCatalog` — configuration embedded in `Account`
124
+ - `Social` — social media links embedded in `Account`
125
+ - `ThreadSummary` — preview summary embedded on orders; not a standalone query
126
+ - `TransactionDetails`, `TransactionUnionConnection`, `TransactionUnionEdge` — embedded / pagination wrappers
90
127
 
91
- - [ ] `Printavo::Contact` model (`id`, `firstName`, `lastName`, `email`, `phone`)
92
- - [ ] `Contacts` resource: `find(id)`
93
- - [ ] `contact` query (contacts are distinct from the customer's `primaryContact`)
128
+ ---
129
+
130
+ ### Account
131
+
132
+ - [x] `Printavo::Account` model (shop-level info: name, address, phone, logo)
133
+ - [x] `Account` resource: `find` (singleton — no ID needed)
134
+ - [x] `account` query
135
+
136
+ ### Contacts ✅
137
+
138
+ - [x] `Printavo::Contact` model (`id`, `firstName`, `lastName`, `email`, `phone`)
139
+ - [x] `Contacts` resource: `find(id)`, `create`, `update`
140
+ - [x] `contact` query (contacts are distinct from the customer's `primaryContact`)
141
+
142
+ ### Invoices ✅
143
+
144
+ - [x] `Printavo::Invoice` model (mirrors Order; has `amountPaid`, `amountOutstanding`, `paidInFull?`)
145
+ - [x] `Invoices` resource: `all`, `find(id)`, `update`
146
+ - [x] `client.invoices` entry point on `Printavo::Client`
147
+
148
+ ---
149
+
150
+ ### Approvals
151
+
152
+ - [ ] `Printavo::ApprovalRequest` model (`id`, `status`, `sentAt`, `expiresAt`, `contact`)
153
+ - [ ] `ApprovalRequests` resource: `all(order_id:)`, `find(id)`
154
+ - [ ] `approvalRequestCreate` mutation
155
+ - [ ] `approvalRequestApprove(id:)` mutation
156
+ - [ ] `approvalRequestRevoke(id:)` mutation
157
+ - [ ] `approvalRequestUnapprove(id:)` mutation
158
+
159
+ ### Categories
160
+
161
+ - [ ] `Printavo::Category` model (`id`, `name`)
162
+ - [ ] `Categories` resource: `all`, `find(id)` — reference data for products/line items
163
+
164
+ ### Contractor Profiles
165
+
166
+ - [ ] `Printavo::ContractorProfile` model (`id`, `name`, `email`)
167
+ - [ ] `ContractorProfiles` resource: `all`, `find(id)` — contractors assignable to invoices
168
+
169
+ ### Custom Addresses
170
+
171
+ - [ ] `Printavo::CustomAddress` model (`id`, `name`, `address`, `city`, `state`, `zip`)
172
+ - [ ] `CustomAddresses` resource: `all(order_id:)`, `find(id)`, `create`, `update`, `delete`
173
+ - [ ] `customAddressCreate` / `customAddressCreates` (bulk) mutations
174
+ - [ ] `customAddressUpdate` / `customAddressUpdates` (bulk) mutations
175
+ - [ ] `customAddressDelete` / `customAddressDeletes` (bulk) mutations
176
+
177
+ ### Delivery Methods
178
+
179
+ - [ ] `Printavo::DeliveryMethod` model (`id`, `name`)
180
+ - [ ] `DeliveryMethods` resource: `all`, `find(id)`, `create`, `update`, `archive`
181
+ - [ ] `deliveryMethodCreate`, `deliveryMethodUpdate`, `deliveryMethodArchive` mutations
182
+
183
+ ### Email Templates
184
+
185
+ - [ ] `Printavo::EmailTemplate` model (`id`, `name`, `subject`, `body`)
186
+ - [ ] `EmailTemplates` resource: `all`, `find(id)`
187
+
188
+ ### Expenses
189
+
190
+ - [ ] `Printavo::Expense` model (`id`, `name`, `amount`, `category`)
191
+ - [ ] `Expenses` resource: `all(order_id:)`, `find(id)`, `create`, `update`
192
+ - [ ] `expenseCreate`, `expenseUpdate` mutations
94
193
 
95
- ### Invoices
194
+ ### Fees
96
195
 
97
- - [ ] `Printavo::Invoice` model (mirrors Order; has `invoiceNumber`, `paidAt`, `balanceDue`)
98
- - [ ] `Invoices` resource: `all`, `find(id)`
99
- - [ ] `client.invoices` entry point on `Printavo::Client`
196
+ - [ ] `Printavo::Fee` model (`id`, `name`, `amount`, `taxable`)
197
+ - [ ] `Fees` resource: `all(order_id:)`, `find(id)`, `create`, `update`, `delete`
198
+ - [ ] `feeCreate` / `feeCreates` (bulk) mutations
199
+ - [ ] `feeUpdate` / `feeUpdates` (bulk) mutations
200
+ - [ ] `feeDelete` / `feeDeletes` (bulk) mutations
201
+
202
+ ### Imprints
203
+
204
+ - [ ] `Printavo::Imprint` model (`id`, `name`, `position`, `colors`, `personalization`)
205
+ - [ ] `Imprints` resource: `all(line_item_group_id:)`, `find(id)`, `create`, `update`, `delete`
206
+ - [ ] `imprintCreate` / `imprintCreates` (bulk) mutations
207
+ - [ ] `imprintUpdate` / `imprintUpdates` (bulk) mutations
208
+ - [ ] `imprintDelete` / `imprintDeletes` (bulk) mutations
209
+ - [ ] `imprintMockupCreate` / `imprintMockupCreates` (bulk) — attach mockup to imprint
210
+
211
+ ### Line Items
212
+
213
+ - [ ] `Printavo::LineItem` model (`id`, `name`, `quantity`, `price`, `taxable`)
214
+ - [ ] `LineItems` resource: `all(line_item_group_id:)`, `find(id)`, `create`, `update`, `delete`
215
+ - [ ] `lineItemCreate` / `lineItemCreates` (bulk) mutations
216
+ - [ ] `lineItemUpdate` / `lineItemUpdates` (bulk) mutations
217
+ - [ ] `lineItemDelete` / `lineItemDeletes` (bulk) mutations
218
+ - [ ] `lineItemMockupCreate` / `lineItemMockupCreates` (bulk) — attach mockup to line item
100
219
 
101
220
  ### Line Item Groups
102
221
 
103
- - [ ] `Printavo::LineItemGroup` model (`id`, `name`, `description`)
104
- - [ ] `LineItemGroups` resource: `all(order_id:)`, `find(id)`
105
- - [ ] `lineItemGroup` / `lineItemGroups` queries
222
+ - [ ] `Printavo::LineItemGroup` model (`id`, `name`, `description`, `sizes`, `enabled_columns`)
223
+ - [ ] `LineItemGroups` resource: `all(order_id:)`, `find(id)`, `create`, `update`, `delete`
224
+ - [ ] `lineItemGroupCreate` / `lineItemGroupCreates` (bulk) mutations
225
+ - [ ] `lineItemGroupUpdate` / `lineItemGroupUpdates` (bulk) mutations
226
+ - [ ] `lineItemGroupDelete` / `lineItemGroupDeletes` (bulk) mutations
106
227
 
107
228
  ### Merch
108
229
 
109
- - [ ] `Printavo::MerchStore` model
110
- - [ ] `Printavo::MerchOrder` model
230
+ - [ ] `Printavo::MerchStore` model (`id`, `name`, `url`, `summary`)
231
+ - [ ] `Printavo::MerchOrder` model (`id`, `status`, `delivery`, `contact`)
111
232
  - [ ] `MerchStores` resource: `all`, `find(id)`
112
233
  - [ ] `MerchOrders` resource: `all`, `find(id)`
113
234
  - [ ] `client.merch_stores` / `client.merch_orders` entry points
114
235
 
115
- ### Transactions & Payments
236
+ ### Mockups & Production Files
237
+
238
+ - [ ] `Printavo::Mockup` model (`id`, `url`, `position`, `createdAt`)
239
+ - [ ] `Printavo::ProductionFile` model (`id`, `url`, `filename`, `createdAt`)
240
+ - [ ] `Mockups` resource: `all(order_id:)`, `find(id)`, `delete`
241
+ - [ ] `mockupDelete` / `mockupDeletes` (bulk) mutations
242
+ - [ ] `ProductionFiles` resource: `all(order_id:)`, `find(id)`, `create`, `delete`
243
+ - [ ] `productionFileCreate` / `productionFileCreates` (bulk) mutations
244
+ - [ ] `productionFileDelete` / `productionFileDeletes` (bulk) mutations
245
+
246
+ ### Payments
247
+
248
+ - [ ] `Printavo::Payment` model (`id`, `amount`, `method`, `paidAt`)
249
+ - [ ] `Printavo::PaymentRequest` model (`id`, `amount`, `sentAt`, `paidAt`, `details`)
250
+ - [ ] `Printavo::PaymentTerm` model (`id`, `name`, `netDays`)
251
+ - [ ] `Payments` resource: `all(order_id:)`, `find(id)`
252
+ - [ ] `PaymentRequests` resource: `all(order_id:)`, `find(id)`, `create`, `delete`
253
+ - [ ] `paymentRequestCreate`, `paymentRequestDelete` mutations
254
+ - [ ] `PaymentTerms` resource: `all`, `find(id)`, `create`, `update`, `archive`
255
+ - [ ] `paymentTermCreate`, `paymentTermUpdate`, `paymentTermArchive` mutations
256
+
257
+ ### Preset Tasks
258
+
259
+ - [ ] `Printavo::PresetTask` model (`id`, `body`, `dueOffsetDays`, `assignee`)
260
+ - [ ] `Printavo::PresetTaskGroup` model (`id`, `name`, `tasks`)
261
+ - [ ] `PresetTasks` resource: `find(id)`, `create`, `update`, `delete`
262
+ - [ ] `presetTaskCreate`, `presetTaskUpdate`, `presetTaskDelete` mutations
263
+ - [ ] `PresetTaskGroups` resource: `all`, `find(id)`, `create`, `update`, `delete`, `apply`
264
+ - [ ] `presetTaskGroupCreate`, `presetTaskGroupUpdate`, `presetTaskGroupDelete` mutations
265
+ - [ ] `presetTaskGroupApply(id:, order_id:)` mutation — applies a group to an order
266
+
267
+ ### Product Catalog & Pricing
268
+
269
+ - [ ] `Printavo::Product` model (`id`, `name`, `sku`, `description`)
270
+ - [ ] `Printavo::PricingMatrix` model (`id`, `name`, `cells`, `columns`)
271
+ - [ ] `Products` resource: `all`, `find(id)`
272
+ - [ ] `PricingMatrices` resource: `all`, `find(id)`
116
273
 
117
- - [ ] `Printavo::Transaction` model (`id`, `amount`, `kind`, `createdAt`)
118
- - [ ] `Transactions` resource: `all(order_id:)`, `find(id)`
119
- - [ ] Payment request mutations
120
- - [ ] Payment dispute handling
274
+ ### Tasks
121
275
 
122
- ### Tasks
276
+ - [x] `Printavo::Task` model (`id`, `body`, `dueAt`, `completedAt`, `assignee`)
277
+ - [x] `Tasks` resource: `all`, `find(id)`, `create`, `update`, `complete`, `delete`
278
+ - [x] `taskCreate`, `taskUpdate`, `taskDelete` mutations
123
279
 
124
- - [ ] `Printavo::Task` model (`id`, `body`, `dueAt`, `completedAt`, `assignee`)
125
- - [ ] `Tasks` resource: `all`, `find(id)`, `create`, `update`, `complete`
126
- - [ ] `taskCreate`, `taskUpdate` mutations
280
+ ### Threads (Messages)
127
281
 
128
- ### Threads (Messages)
282
+ - [x] `Printavo::Thread` model (`id`, `subject`, `createdAt`, `updatedAt`)
283
+ - [x] `Threads` resource: `all(order_id:)`, `find(id)`, `update`
284
+ - [x] `threadUpdate` mutation
285
+ - [x] `emailMessageCreate` mutation — send an email message on a thread
129
286
 
130
- - [ ] `Printavo::Thread` model (`id`, `body`, `author`, `createdAt`)
131
- - [ ] `Threads` resource: `all(order_id:)`, `find(id)`, `create`
132
- - [ ] `threadCreate` mutation
287
+ ### Transactions
133
288
 
134
- ### Account
289
+ - [x] `Printavo::Transaction` model (`id`, `amount`, `kind`, `createdAt`)
290
+ - [x] `Transactions` resource: `all(order_id:)`, `find(id)`
291
+ - [x] `Printavo::TransactionPayment` model (`id`, `amount`, `paymentMethod`, `paidAt`, `note`)
292
+ - [x] `TransactionPayments` resource: `create`, `update`, `delete`
293
+ - [x] `transactionPaymentCreate`, `transactionPaymentUpdate`, `transactionPaymentDelete` mutations
135
294
 
136
- - [ ] `Printavo::Account` model (shop-level info: name, address, phone, logo)
137
- - [ ] `Account` resource: `find` (singleton — no ID needed)
138
- - [ ] `account` query
295
+ ### Types of Work
139
296
 
140
- ### Delete Mutations
297
+ - [ ] `Printavo::TypeOfWork` model (`id`, `name`)
298
+ - [ ] `TypesOfWork` resource: `all` — reference data for order categorization
141
299
 
142
- - [ ] `customerDelete(id:)`
143
- - [ ] `quoteDelete(id:)` / `invoiceDelete(id:)`
144
- - [ ] `lineItemDelete(id:)`
145
- - [ ] `taskDelete(id:)`
300
+ ### Users
146
301
 
147
- ### Product Catalog & Pricing
302
+ - [ ] `Printavo::User` model (`id`, `firstName`, `lastName`, `email`, `avatar`, `permissions`)
303
+ - [ ] `Users` resource: `all`, `find(id)` — shop staff members
148
304
 
149
- - [ ] `Printavo::Product` model
150
- - [ ] `Products` resource: `all`, `find(id)`
151
- - [ ] Pricing matrix queries
305
+ ### Vendors
306
+
307
+ - [ ] `Printavo::Vendor` model (`id`, `name`, `email`, `phone`)
308
+ - [ ] `Vendors` resource: `all`, `find(id)` — read-only; no create/update/delete in V2 API
152
309
 
153
310
  ---
154
311
 
155
312
  ## Planned Versions
156
313
 
157
- ### v0.6.0 — Invoices, Contacts & Analytics
314
+ ### v0.6.0 — Invoices, Contacts & Account ✅
315
+
316
+ - [x] `Invoices` resource (`all`, `find`, `update`)
317
+ - [x] `Contacts` resource (`find`, `create`, `update`)
318
+ - [x] `Account` resource (singleton `find`)
158
319
 
159
- - [ ] `Invoices` resource (`all`, `find`)
160
- - [ ] `Contacts` resource (`find`)
161
- - [ ] `Account` resource (singleton)
162
- - [ ] Analytics/Reporting resource: revenue, job counts, customer activity, turnaround times
163
- - [ ] Community burn-in — gather feedback on 0.5.x API surface
320
+ ### v0.7.0 Transactions, Tasks & Threads ✅
164
321
 
165
- ### v0.7.0 Transactions, Tasks & Threads
322
+ - [x] `Transactions` resource (`all`, `find`) + `TransactionPayments` (`create`, `update`, `delete`)
323
+ - [x] `Tasks` resource (`all`, `find`, `create`, `update`, `complete`, `delete`)
324
+ - [x] `Threads` resource (`all`, `find`, `update`) + `emailMessageCreate`
166
325
 
167
- - [ ] `Transactions` resource (`all`, `find`)
168
- - [ ] `Tasks` resource (`all`, `find`, `create`, `update`, `complete`)
169
- - [ ] `Threads` resource (`all`, `find`, `create`)
170
- - [ ] Delete mutations for Customer, Order, LineItem, Task
326
+ ### v0.8.0 Order Structure: Line Items, Line Item Groups, Imprints & Fees
171
327
 
172
- ### v0.8.0 Merch & Products
328
+ - [ ] `LineItems` resource (`all`, `find`, `create`/`creates`, `update`/`updates`, `delete`/`deletes`)
329
+ - [ ] `LineItemGroups` resource (`all`, `find`, `create`/`creates`, `update`/`updates`, `delete`/`deletes`)
330
+ - [ ] `Imprints` resource (`all`, `find`, `create`/`creates`, `update`/`updates`, `delete`/`deletes`, mockup attach)
331
+ - [ ] `Fees` resource (`all`, `find`, `create`/`creates`, `update`/`updates`, `delete`/`deletes`)
332
+ - [ ] `Expenses` resource (`all`, `find`, `create`, `update`)
333
+
334
+ ### v0.9.0 — Merch, Products & Pricing
173
335
 
174
336
  - [ ] `MerchStores` + `MerchOrders` resources
175
- - [ ] `LineItemGroups` resource
176
- - [ ] `Products` resource + pricing matrix queries
337
+ - [ ] `Products` resource + `PricingMatrices` resource
338
+ - [ ] `Categories` resource (reference data)
339
+
340
+ ### v0.10.0 — Financial: Payments, Payment Terms & Requests
341
+
342
+ - [ ] `Payments` resource (`all`, `find`)
343
+ - [ ] `PaymentRequests` resource (`all`, `find`, `create`, `delete`)
344
+ - [ ] `PaymentTerms` resource (`all`, `find`, `create`, `update`, `archive`)
345
+
346
+ ### v0.11.0 — Workflow: Approvals & Preset Tasks
347
+
348
+ - [ ] `ApprovalRequests` resource (`all`, `find`, `create`, `approve`, `revoke`, `unapprove`)
349
+ - [ ] `PresetTasks` resource (`find`, `create`, `update`, `delete`)
350
+ - [ ] `PresetTaskGroups` resource (`all`, `find`, `create`, `update`, `delete`, `apply`)
351
+
352
+ ### v0.12.0 — Files, Media & Communication
353
+
354
+ - [ ] `ProductionFiles` resource (`all`, `find`, `create`/`creates`, `delete`/`deletes`)
355
+ - [ ] `Mockups` resource (`all`, `find`, `delete`/`deletes`)
356
+ - [ ] `EmailTemplates` resource (`all`, `find`)
357
+ - [ ] `CustomAddresses` resource (`all`, `find`, `create`/`creates`, `update`/`updates`, `delete`/`deletes`)
358
+
359
+ ### v0.13.0 — People, Orgs & Reference Data
360
+
361
+ - [ ] `Users` resource (`all`, `find`)
362
+ - [ ] `Vendors` resource (`all`, `find`) — read-only
363
+ - [ ] `ContractorProfiles` resource (`all`, `find`)
364
+ - [ ] `DeliveryMethods` resource (`all`, `find`, `create`, `update`, `archive`)
365
+ - [ ] `TypesOfWork` resource (`all`)
366
+
367
+ ### v0.14.0 — Delete & Duplicate Mutations for Shipped Resources
368
+
369
+ - [ ] `Contacts#delete` — `contactDelete`
370
+ - [ ] `Customers#delete` — `customerDelete`
371
+ - [ ] `Inquiries#delete` — `inquiryDelete`
372
+ - [ ] `Invoices#delete` — `invoiceDelete`
373
+ - [ ] `Invoices#duplicate` — `invoiceDuplicate`
374
+ - [ ] `Orders#delete` — `quoteDelete`
375
+ - [ ] `Orders#duplicate` — `quoteDuplicate`
177
376
 
178
- ### v0.9.0 — Retry / Backoff & CLI
377
+ ### v0.15.0 — Retry / Backoff & CLI
179
378
 
180
379
  - [ ] Configurable `max_retries` on `Printavo::Client`
181
380
  - [ ] Exponential backoff with jitter on 429 responses
182
381
  - [ ] `retry_on_rate_limit: true/false` client option
183
382
  - [ ] Thor-based `printavo` CLI (`customers`, `orders`, `orders find <id>`)
184
383
 
185
- ### v0.10.0 — API Freeze
384
+ ### v0.99.0 — API Freeze
186
385
 
187
386
  - [ ] Community feedback integration
188
387
  - [ ] Deprecation notices for any renamed methods
@@ -25,24 +25,64 @@ module Printavo
25
25
  @graphql = GraphqlClient.new(connection)
26
26
  end
27
27
 
28
+ def account
29
+ Resources::Account.new(@graphql)
30
+ end
31
+
32
+ def contacts
33
+ Resources::Contacts.new(@graphql)
34
+ end
35
+
28
36
  def customers
29
37
  Resources::Customers.new(@graphql)
30
38
  end
31
39
 
32
- def statuses
33
- Resources::Statuses.new(@graphql)
40
+ def inquiries
41
+ Resources::Inquiries.new(@graphql)
34
42
  end
35
43
 
36
- def orders
37
- Resources::Orders.new(@graphql)
44
+ def invoices
45
+ Resources::Invoices.new(@graphql)
38
46
  end
39
47
 
40
48
  def jobs
41
49
  Resources::Jobs.new(@graphql)
42
50
  end
43
51
 
44
- def inquiries
45
- Resources::Inquiries.new(@graphql)
52
+ def login(*)
53
+ raise NotImplementedError,
54
+ 'login is not supported — this gem authenticates via email + token headers. ' \
55
+ 'Pass credentials to Printavo::Client.new(email:, token:) instead.'
56
+ end
57
+
58
+ def logout(*)
59
+ raise NotImplementedError,
60
+ 'logout is not supported — this gem uses stateless header-based auth. ' \
61
+ 'Simply discard the client instance when done.'
62
+ end
63
+
64
+ def orders
65
+ Resources::Orders.new(@graphql)
66
+ end
67
+
68
+ def statuses
69
+ Resources::Statuses.new(@graphql)
70
+ end
71
+
72
+ def tasks
73
+ Resources::Tasks.new(@graphql)
74
+ end
75
+
76
+ def threads
77
+ Resources::Threads.new(@graphql)
78
+ end
79
+
80
+ def transaction_payments
81
+ Resources::TransactionPayments.new(@graphql)
82
+ end
83
+
84
+ def transactions
85
+ Resources::Transactions.new(@graphql)
46
86
  end
47
87
  end
48
88
  end
@@ -0,0 +1,14 @@
1
+ # lib/printavo/models/account.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ class Account < Models::Base
6
+ def id = self['id']
7
+ def company_name = self['companyName']
8
+ def company_email = self['companyEmail']
9
+ def phone = self['phone']
10
+ def website = self['website']
11
+ def logo_url = self['logoUrl']
12
+ def locale = self['locale']
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ # lib/printavo/models/contact.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ class Contact < Models::Base
6
+ def id = self['id']
7
+ def first_name = self['firstName']
8
+ def last_name = self['lastName']
9
+ def email = self['email']
10
+ def phone = self['phone']
11
+ def fax = self['fax']
12
+
13
+ def full_name
14
+ self['fullName'] || [first_name, last_name].compact.join(' ').strip
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+ # lib/printavo/models/invoice.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ class Invoice < Models::Base
6
+ def id = self['id']
7
+ def nickname = self['nickname']
8
+ def total = self['total']
9
+ def amount_paid = self['amountPaid']
10
+ def amount_outstanding = self['amountOutstanding']
11
+ def paid_in_full? = self['paidInFull']
12
+ def invoice_at = self['invoiceAt']
13
+ def payment_due_at = self['paymentDueAt']
14
+
15
+ def status
16
+ dig('status', 'name')
17
+ end
18
+
19
+ def status_id
20
+ dig('status', 'id')
21
+ end
22
+
23
+ def status_color
24
+ dig('status', 'color')
25
+ end
26
+
27
+ def status_key
28
+ return nil if status.nil?
29
+
30
+ status.downcase.gsub(/\s+/, '_').to_sym
31
+ end
32
+
33
+ def status?(key)
34
+ status_key == key.to_sym
35
+ end
36
+
37
+ def contact
38
+ attrs = self['contact']
39
+ Contact.new(attrs) if attrs
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ # lib/printavo/models/task.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ class Task < Models::Base
6
+ def id = self['id']
7
+ def body = self['body']
8
+ def due_at = self['dueAt']
9
+ def completed_at = self['completedAt']
10
+ def completed? = !completed_at.nil?
11
+ def assignee = self['assignee']
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ # lib/printavo/models/thread.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ class Thread < Models::Base
6
+ def id = self['id']
7
+ def subject = self['subject']
8
+ def created_at = self['createdAt']
9
+ def updated_at = self['updatedAt']
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # lib/printavo/models/transaction.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ class Transaction < Models::Base
6
+ def id = self['id']
7
+ def amount = self['amount']
8
+ def kind = self['kind']
9
+ def created_at = self['createdAt']
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ # lib/printavo/models/transaction_payment.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ class TransactionPayment < Models::Base
6
+ def id = self['id']
7
+ def amount = self['amount']
8
+ def payment_method = self['paymentMethod']
9
+ def paid_at = self['paidAt']
10
+ def note = self['note']
11
+ end
12
+ end
@@ -0,0 +1,25 @@
1
+ # lib/printavo/resources/account.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Resources
6
+ # Singleton resource — Printavo exposes one account per API credential.
7
+ # Use +client.account.find+ (no ID argument required).
8
+ class Account < Base
9
+ FIND_QUERY = File.read(File.join(__dir__, '../graphql/account/find.graphql')).freeze
10
+
11
+ # Returns the account associated with the current API credentials.
12
+ #
13
+ # @return [Printavo::Account]
14
+ #
15
+ # @example
16
+ # account = client.account.find
17
+ # puts account.company_name # => "Texas Embroidery Ranch"
18
+ # puts account.locale # => "en-US"
19
+ def find
20
+ data = @graphql.query(FIND_QUERY)
21
+ Printavo::Account.new(data['account'])
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,57 @@
1
+ # lib/printavo/resources/contacts.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Resources
6
+ class Contacts < Base
7
+ FIND_QUERY = File.read(File.join(__dir__, '../graphql/contacts/find.graphql')).freeze
8
+ CREATE_MUTATION = File.read(File.join(__dir__, '../graphql/contacts/create.graphql')).freeze
9
+ UPDATE_MUTATION = File.read(File.join(__dir__, '../graphql/contacts/update.graphql')).freeze
10
+
11
+ # Finds a contact by ID.
12
+ #
13
+ # @param id [String, Integer]
14
+ # @return [Printavo::Contact]
15
+ #
16
+ # @example
17
+ # client.contacts.find("123")
18
+ def find(id)
19
+ data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
20
+ Printavo::Contact.new(data['contact'])
21
+ end
22
+
23
+ # Creates a new contact. Requires at minimum +email:+.
24
+ #
25
+ # @return [Printavo::Contact]
26
+ #
27
+ # @example
28
+ # client.contacts.create(first_name: "Jane", last_name: "Smith",
29
+ # email: "jane@example.com", phone: "555-867-5309")
30
+ def create(**input)
31
+ data = @graphql.mutate(CREATE_MUTATION, variables: { input: camelize_keys(input) })
32
+ Printavo::Contact.new(data['contactCreate'])
33
+ end
34
+
35
+ # Updates an existing contact by ID.
36
+ #
37
+ # @param id [String, Integer]
38
+ # @return [Printavo::Contact]
39
+ #
40
+ # @example
41
+ # client.contacts.update("123", phone: "555-999-0000")
42
+ def update(id, **input)
43
+ data = @graphql.mutate(UPDATE_MUTATION,
44
+ variables: { id: id.to_s, input: camelize_keys(input) })
45
+ Printavo::Contact.new(data['contactUpdate'])
46
+ end
47
+
48
+ private
49
+
50
+ def camelize_keys(hash)
51
+ hash.transform_keys do |key|
52
+ key.to_s.gsub(/_([a-z])/) { ::Regexp.last_match(1).upcase }
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,61 @@
1
+ # lib/printavo/resources/invoices.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Resources
6
+ class Invoices < Base
7
+ ALL_QUERY = File.read(File.join(__dir__, '../graphql/invoices/all.graphql')).freeze
8
+ FIND_QUERY = File.read(File.join(__dir__, '../graphql/invoices/find.graphql')).freeze
9
+ UPDATE_MUTATION = File.read(File.join(__dir__, '../graphql/invoices/update.graphql')).freeze
10
+
11
+ def all(first: 25, after: nil)
12
+ fetch_page(first: first, after: after).records
13
+ end
14
+
15
+ # Finds an invoice by ID.
16
+ #
17
+ # @param id [String, Integer]
18
+ # @return [Printavo::Invoice]
19
+ #
20
+ # @example
21
+ # client.invoices.find("456")
22
+ def find(id)
23
+ data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
24
+ Printavo::Invoice.new(data['invoice'])
25
+ end
26
+
27
+ # Updates an existing invoice by ID.
28
+ # Note: invoices are promoted from quotes — use +client.orders.create+ to originate.
29
+ #
30
+ # @param id [String, Integer]
31
+ # @return [Printavo::Invoice]
32
+ #
33
+ # @example
34
+ # client.invoices.update("456", nickname: "Final Invoice", payment_due_at: "2026-05-01")
35
+ def update(id, **input)
36
+ data = @graphql.mutate(UPDATE_MUTATION,
37
+ variables: { id: id.to_s, input: camelize_keys(input) })
38
+ Printavo::Invoice.new(data['invoiceUpdate'])
39
+ end
40
+
41
+ private
42
+
43
+ def fetch_page(first: 25, after: nil, **)
44
+ data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
45
+ nodes = data['invoices']['nodes'].map { |attrs| Printavo::Invoice.new(attrs) }
46
+ page_info = data['invoices']['pageInfo']
47
+ Printavo::Page.new(
48
+ records: nodes,
49
+ has_next_page: page_info['hasNextPage'],
50
+ end_cursor: page_info['endCursor']
51
+ )
52
+ end
53
+
54
+ def camelize_keys(hash)
55
+ hash.transform_keys do |key|
56
+ key.to_s.gsub(/_([a-z])/) { ::Regexp.last_match(1).upcase }
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,65 @@
1
+ # lib/printavo/resources/tasks.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Resources
6
+ class Tasks < Base
7
+ ALL_QUERY = File.read(File.join(__dir__, '../graphql/tasks/all.graphql')).freeze
8
+ FIND_QUERY = File.read(File.join(__dir__, '../graphql/tasks/find.graphql')).freeze
9
+ CREATE_MUTATION = File.read(File.join(__dir__, '../graphql/tasks/create.graphql')).freeze
10
+ UPDATE_MUTATION = File.read(File.join(__dir__, '../graphql/tasks/update.graphql')).freeze
11
+ DELETE_MUTATION = File.read(File.join(__dir__, '../graphql/tasks/delete.graphql')).freeze
12
+
13
+ def all(first: 25, after: nil)
14
+ fetch_page(first: first, after: after).records
15
+ end
16
+
17
+ def find(id)
18
+ data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
19
+ Printavo::Task.new(data['task'])
20
+ end
21
+
22
+ def create(**input)
23
+ data = @graphql.mutate(CREATE_MUTATION, variables: { input: camelize_keys(input) })
24
+ Printavo::Task.new(data['taskCreate'])
25
+ end
26
+
27
+ def update(id, **input)
28
+ data = @graphql.mutate(UPDATE_MUTATION,
29
+ variables: { id: id.to_s, input: camelize_keys(input) })
30
+ Printavo::Task.new(data['taskUpdate'])
31
+ end
32
+
33
+ # Marks a task complete by setting completedAt to the current time.
34
+ def complete(id)
35
+ require 'time'
36
+ update(id, completed_at: Time.now.utc.iso8601)
37
+ end
38
+
39
+ # Deletes a task. Raises on failure; returns nil on success.
40
+ def delete(id)
41
+ @graphql.mutate(DELETE_MUTATION, variables: { id: id.to_s })
42
+ nil
43
+ end
44
+
45
+ private
46
+
47
+ def fetch_page(first: 25, after: nil, **)
48
+ data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
49
+ nodes = data['tasks']['nodes'].map { |attrs| Printavo::Task.new(attrs) }
50
+ page_info = data['tasks']['pageInfo']
51
+ Printavo::Page.new(
52
+ records: nodes,
53
+ has_next_page: page_info['hasNextPage'],
54
+ end_cursor: page_info['endCursor']
55
+ )
56
+ end
57
+
58
+ def camelize_keys(hash)
59
+ hash.transform_keys do |key|
60
+ key.to_s.gsub(/_([a-z])/) { ::Regexp.last_match(1).upcase }
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,59 @@
1
+ # lib/printavo/resources/threads.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Resources
6
+ class Threads < Base
7
+ ALL_QUERY = File.read(File.join(__dir__, '../graphql/threads/all.graphql')).freeze
8
+ FIND_QUERY = File.read(File.join(__dir__, '../graphql/threads/find.graphql')).freeze
9
+ UPDATE_MUTATION = File.read(File.join(__dir__, '../graphql/threads/update.graphql')).freeze
10
+ EMAIL_MESSAGE_CREATE_MUTATION =
11
+ File.read(File.join(__dir__, '../graphql/threads/email_message_create.graphql')).freeze
12
+
13
+ def all(order_id:, first: 25, after: nil)
14
+ fetch_page(order_id: order_id, first: first, after: after).records
15
+ end
16
+
17
+ def find(id)
18
+ data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
19
+ Printavo::Thread.new(data['thread'])
20
+ end
21
+
22
+ def update(id, **input)
23
+ data = @graphql.mutate(UPDATE_MUTATION,
24
+ variables: { id: id.to_s, input: camelize_keys(input) })
25
+ Printavo::Thread.new(data['threadUpdate'])
26
+ end
27
+
28
+ # Sends an email message on a thread. Returns the raw message hash.
29
+ # A dedicated EmailMessage model is planned for a future version.
30
+ def email_message_create(**input)
31
+ data = @graphql.mutate(EMAIL_MESSAGE_CREATE_MUTATION,
32
+ variables: { input: camelize_keys(input) })
33
+ data['emailMessageCreate']
34
+ end
35
+
36
+ private
37
+
38
+ def fetch_page(order_id:, first: 25, after: nil, **)
39
+ data = @graphql.query(
40
+ ALL_QUERY,
41
+ variables: { orderId: order_id.to_s, first: first, after: after }
42
+ )
43
+ nodes = data['order']['threads']['nodes'].map { |attrs| Printavo::Thread.new(attrs) }
44
+ page_info = data['order']['threads']['pageInfo']
45
+ Printavo::Page.new(
46
+ records: nodes,
47
+ has_next_page: page_info['hasNextPage'],
48
+ end_cursor: page_info['endCursor']
49
+ )
50
+ end
51
+
52
+ def camelize_keys(hash)
53
+ hash.transform_keys do |key|
54
+ key.to_s.gsub(/_([a-z])/) { ::Regexp.last_match(1).upcase }
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,37 @@
1
+ # lib/printavo/resources/transaction_payments.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Resources
6
+ class TransactionPayments < Base
7
+ CREATE_MUTATION = File.read(File.join(__dir__, '../graphql/transaction_payments/create.graphql')).freeze
8
+ UPDATE_MUTATION = File.read(File.join(__dir__, '../graphql/transaction_payments/update.graphql')).freeze
9
+ DELETE_MUTATION = File.read(File.join(__dir__, '../graphql/transaction_payments/delete.graphql')).freeze
10
+
11
+ def create(**input)
12
+ data = @graphql.mutate(CREATE_MUTATION, variables: { input: camelize_keys(input) })
13
+ Printavo::TransactionPayment.new(data['transactionPaymentCreate'])
14
+ end
15
+
16
+ def update(id, **input)
17
+ data = @graphql.mutate(UPDATE_MUTATION,
18
+ variables: { id: id.to_s, input: camelize_keys(input) })
19
+ Printavo::TransactionPayment.new(data['transactionPaymentUpdate'])
20
+ end
21
+
22
+ # Deletes a transaction payment. Raises on failure; returns nil on success.
23
+ def delete(id)
24
+ @graphql.mutate(DELETE_MUTATION, variables: { id: id.to_s })
25
+ nil
26
+ end
27
+
28
+ private
29
+
30
+ def camelize_keys(hash)
31
+ hash.transform_keys do |key|
32
+ key.to_s.gsub(/_([a-z])/) { ::Regexp.last_match(1).upcase }
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ # lib/printavo/resources/transactions.rb
2
+ # frozen_string_literal: true
3
+
4
+ module Printavo
5
+ module Resources
6
+ class Transactions < Base
7
+ ALL_QUERY = File.read(File.join(__dir__, '../graphql/transactions/all.graphql')).freeze
8
+ FIND_QUERY = File.read(File.join(__dir__, '../graphql/transactions/find.graphql')).freeze
9
+
10
+ def all(order_id:, first: 25, after: nil)
11
+ fetch_page(order_id: order_id, first: first, after: after).records
12
+ end
13
+
14
+ def find(id)
15
+ data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
16
+ Printavo::Transaction.new(data['transaction'])
17
+ end
18
+
19
+ private
20
+
21
+ def fetch_page(order_id:, first: 25, after: nil, **)
22
+ data = @graphql.query(
23
+ ALL_QUERY,
24
+ variables: { orderId: order_id.to_s, first: first, after: after }
25
+ )
26
+ nodes = data['order']['transactions']['nodes'].map { |attrs| Printavo::Transaction.new(attrs) }
27
+ page_info = data['order']['transactions']['pageInfo']
28
+ Printavo::Page.new(
29
+ records: nodes,
30
+ has_next_page: page_info['hasNextPage'],
31
+ end_cursor: page_info['endCursor']
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Printavo
5
- VERSION = '0.5.2'
5
+ VERSION = '0.7.0'
6
6
  end
data/lib/printavo.rb CHANGED
@@ -12,17 +12,31 @@ require_relative 'printavo/connection'
12
12
  require_relative 'printavo/graphql_client'
13
13
  require_relative 'printavo/page'
14
14
  require_relative 'printavo/models/base'
15
+ require_relative 'printavo/models/account'
16
+ require_relative 'printavo/models/contact'
15
17
  require_relative 'printavo/models/customer'
18
+ require_relative 'printavo/models/invoice'
16
19
  require_relative 'printavo/models/status'
17
20
  require_relative 'printavo/models/order'
18
21
  require_relative 'printavo/models/job'
19
22
  require_relative 'printavo/models/inquiry'
23
+ require_relative 'printavo/models/task'
24
+ require_relative 'printavo/models/thread'
25
+ require_relative 'printavo/models/transaction'
26
+ require_relative 'printavo/models/transaction_payment'
20
27
  require_relative 'printavo/resources/base'
28
+ require_relative 'printavo/resources/account'
29
+ require_relative 'printavo/resources/contacts'
21
30
  require_relative 'printavo/resources/customers'
31
+ require_relative 'printavo/resources/invoices'
22
32
  require_relative 'printavo/resources/statuses'
23
33
  require_relative 'printavo/resources/orders'
24
34
  require_relative 'printavo/resources/jobs'
25
35
  require_relative 'printavo/resources/inquiries'
36
+ require_relative 'printavo/resources/tasks'
37
+ require_relative 'printavo/resources/threads'
38
+ require_relative 'printavo/resources/transactions'
39
+ require_relative 'printavo/resources/transaction_payments'
26
40
  require_relative 'printavo/webhooks'
27
41
  require_relative 'printavo/client'
28
42
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: printavo-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stan Carver II
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-30 00:00:00.000000000 Z
11
+ date: 2026-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -272,19 +272,33 @@ files:
272
272
  - lib/printavo/connection.rb
273
273
  - lib/printavo/errors.rb
274
274
  - lib/printavo/graphql_client.rb
275
+ - lib/printavo/models/account.rb
275
276
  - lib/printavo/models/base.rb
277
+ - lib/printavo/models/contact.rb
276
278
  - lib/printavo/models/customer.rb
277
279
  - lib/printavo/models/inquiry.rb
280
+ - lib/printavo/models/invoice.rb
278
281
  - lib/printavo/models/job.rb
279
282
  - lib/printavo/models/order.rb
280
283
  - lib/printavo/models/status.rb
284
+ - lib/printavo/models/task.rb
285
+ - lib/printavo/models/thread.rb
286
+ - lib/printavo/models/transaction.rb
287
+ - lib/printavo/models/transaction_payment.rb
281
288
  - lib/printavo/page.rb
289
+ - lib/printavo/resources/account.rb
282
290
  - lib/printavo/resources/base.rb
291
+ - lib/printavo/resources/contacts.rb
283
292
  - lib/printavo/resources/customers.rb
284
293
  - lib/printavo/resources/inquiries.rb
294
+ - lib/printavo/resources/invoices.rb
285
295
  - lib/printavo/resources/jobs.rb
286
296
  - lib/printavo/resources/orders.rb
287
297
  - lib/printavo/resources/statuses.rb
298
+ - lib/printavo/resources/tasks.rb
299
+ - lib/printavo/resources/threads.rb
300
+ - lib/printavo/resources/transaction_payments.rb
301
+ - lib/printavo/resources/transactions.rb
288
302
  - lib/printavo/version.rb
289
303
  - lib/printavo/webhooks.rb
290
304
  homepage: https://github.com/scarver2/printavo-ruby