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 +4 -4
- data/docs/CHANGELOG.md +46 -0
- data/docs/TODO.md +254 -55
- data/lib/printavo/client.rb +46 -6
- data/lib/printavo/models/account.rb +14 -0
- data/lib/printavo/models/contact.rb +17 -0
- data/lib/printavo/models/invoice.rb +42 -0
- data/lib/printavo/models/task.rb +13 -0
- data/lib/printavo/models/thread.rb +11 -0
- data/lib/printavo/models/transaction.rb +11 -0
- data/lib/printavo/models/transaction_payment.rb +12 -0
- data/lib/printavo/resources/account.rb +25 -0
- data/lib/printavo/resources/contacts.rb +57 -0
- data/lib/printavo/resources/invoices.rb +61 -0
- data/lib/printavo/resources/tasks.rb +65 -0
- data/lib/printavo/resources/threads.rb +59 -0
- data/lib/printavo/resources/transaction_payments.rb +37 -0
- data/lib/printavo/resources/transactions.rb +36 -0
- data/lib/printavo/version.rb +1 -1
- data/lib/printavo.rb +14 -0
- metadata +16 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4f1b8022189ac0b62b87b7d9770c08b3f2320c6804705c41afd6e2b03c7239ca
|
|
4
|
+
data.tar.gz: 94761c4186f08d33b841eb9d364350f142c5b7b007d0f1fce2c08e7e237156d8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
###
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
###
|
|
194
|
+
### Fees
|
|
96
195
|
|
|
97
|
-
- [ ] `Printavo::
|
|
98
|
-
- [ ] `
|
|
99
|
-
- [ ] `
|
|
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
|
-
- [ ] `
|
|
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
|
-
###
|
|
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
|
-
|
|
118
|
-
- [ ] `Transactions` resource: `all(order_id:)`, `find(id)`
|
|
119
|
-
- [ ] Payment request mutations
|
|
120
|
-
- [ ] Payment dispute handling
|
|
274
|
+
### Tasks ✅
|
|
121
275
|
|
|
122
|
-
|
|
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
|
-
|
|
125
|
-
- [ ] `Tasks` resource: `all`, `find(id)`, `create`, `update`, `complete`
|
|
126
|
-
- [ ] `taskCreate`, `taskUpdate` mutations
|
|
280
|
+
### Threads (Messages) ✅
|
|
127
281
|
|
|
128
|
-
|
|
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
|
-
|
|
131
|
-
- [ ] `Threads` resource: `all(order_id:)`, `find(id)`, `create`
|
|
132
|
-
- [ ] `threadCreate` mutation
|
|
287
|
+
### Transactions ✅
|
|
133
288
|
|
|
134
|
-
|
|
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
|
-
|
|
137
|
-
- [ ] `Account` resource: `find` (singleton — no ID needed)
|
|
138
|
-
- [ ] `account` query
|
|
295
|
+
### Types of Work
|
|
139
296
|
|
|
140
|
-
|
|
297
|
+
- [ ] `Printavo::TypeOfWork` model (`id`, `name`)
|
|
298
|
+
- [ ] `TypesOfWork` resource: `all` — reference data for order categorization
|
|
141
299
|
|
|
142
|
-
|
|
143
|
-
- [ ] `quoteDelete(id:)` / `invoiceDelete(id:)`
|
|
144
|
-
- [ ] `lineItemDelete(id:)`
|
|
145
|
-
- [ ] `taskDelete(id:)`
|
|
300
|
+
### Users
|
|
146
301
|
|
|
147
|
-
|
|
302
|
+
- [ ] `Printavo::User` model (`id`, `firstName`, `lastName`, `email`, `avatar`, `permissions`)
|
|
303
|
+
- [ ] `Users` resource: `all`, `find(id)` — shop staff members
|
|
148
304
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
- [ ]
|
|
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 &
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
- [ ] `
|
|
176
|
-
- [ ] `
|
|
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.
|
|
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.
|
|
384
|
+
### v0.99.0 — API Freeze
|
|
186
385
|
|
|
187
386
|
- [ ] Community feedback integration
|
|
188
387
|
- [ ] Deprecation notices for any renamed methods
|
data/lib/printavo/client.rb
CHANGED
|
@@ -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
|
|
33
|
-
Resources::
|
|
40
|
+
def inquiries
|
|
41
|
+
Resources::Inquiries.new(@graphql)
|
|
34
42
|
end
|
|
35
43
|
|
|
36
|
-
def
|
|
37
|
-
Resources::
|
|
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
|
|
45
|
-
|
|
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,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
|
data/lib/printavo/version.rb
CHANGED
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.
|
|
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-
|
|
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
|