printavo-ruby 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +33 -0
- data/LICENSE +21 -0
- data/README.md +252 -0
- data/lib/printavo/client.rb +38 -0
- data/lib/printavo/config.rb +13 -0
- data/lib/printavo/connection.rb +31 -0
- data/lib/printavo/errors.rb +19 -0
- data/lib/printavo/graphql_client.rb +38 -0
- data/lib/printavo/models/base.rb +34 -0
- data/lib/printavo/models/customer.rb +15 -0
- data/lib/printavo/models/job.rb +14 -0
- data/lib/printavo/models/order.rb +27 -0
- data/lib/printavo/resources/base.rb +10 -0
- data/lib/printavo/resources/customers.rb +48 -0
- data/lib/printavo/resources/jobs.rb +48 -0
- data/lib/printavo/resources/orders.rb +64 -0
- data/lib/printavo/version.rb +4 -0
- data/lib/printavo/webhooks.rb +34 -0
- data/lib/printavo.rb +23 -0
- metadata +309 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f47615b00a6d63bc35e5d5cc74e5e8d591fe38218eadd0bb76e11798626f9f42
|
|
4
|
+
data.tar.gz: aa6d86cb12b1ea7617c8d97093993252fc30f1401fef8893263ed2ba4f277a48
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: '08fa3eb45c8ddef4ff5962c9bd59d01c14048d2c68fefb1b3e6ee526b6e4317b225958b5ed8865ba45fb42b35ef14d1c8f235a81b90a3c11e1e4dd661e2c1aa4'
|
|
7
|
+
data.tar.gz: 93ef9341891c36ab6ffa9fd61a9790b16662072a7ecb4bf733d6aa0f5cd9fe99ee75c77a47be7a023909b7468fb70abec3a8d5b076925a732c3cd8c6389ec1b6
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!-- CHANGELOG.md -->
|
|
2
|
+
# Changelog
|
|
3
|
+
|
|
4
|
+
All notable changes to this project will be documented in this file.
|
|
5
|
+
|
|
6
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
7
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
## [0.1.0] - 2026-03-29
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- `Printavo::Client` — instance-based, multi-client capable entry point
|
|
15
|
+
- `Printavo::Resources::Customers` — `all` and `find` via GraphQL
|
|
16
|
+
- `Printavo::Resources::Orders` — `all` and `find` with status + customer association
|
|
17
|
+
- `Printavo::Resources::Jobs` — `all` (by order) and `find` line item queries
|
|
18
|
+
- `Printavo::Customer`, `Printavo::Order`, `Printavo::Job` — rich domain models
|
|
19
|
+
- `Printavo::Order#status?` — dynamic status predicate (handles user-defined statuses)
|
|
20
|
+
- `Printavo::GraphqlClient` — raw GraphQL query/mutation interface
|
|
21
|
+
- `Printavo::Webhooks.verify` — Rack-compatible HMAC-SHA256 signature verification
|
|
22
|
+
- Error hierarchy: `AuthenticationError`, `RateLimitError`, `NotFoundError`, `ApiError`
|
|
23
|
+
- Faraday connection with retry middleware (max 2 retries; 429/5xx)
|
|
24
|
+
- RSpec test suite — 62 examples, 100% line coverage with VCR + WebMock + Faker sanitization
|
|
25
|
+
- Coveralls coverage badge (LCOV via `simplecov-lcov`)
|
|
26
|
+
- Guard + RuboCop DX setup with `bin/spec` multi-Ruby local runner
|
|
27
|
+
- GitHub Actions CI: Ruby 3.3 (primary) + Ruby 4.0 (`continue-on-error`)
|
|
28
|
+
- Automated RubyGems publish on `v*` tag via `release.yml`
|
|
29
|
+
- `docs/CACHING.md` — nine caching strategy patterns for rate-limit-aware consumers
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
— Stan Carver II / Made in Texas 🤠 / https://stancarver.com
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Stan Carver II
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
<!-- README.md -->
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="docs/printavo-ruby.png" alt="printavo-ruby" width="640">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
# printavo-ruby
|
|
8
|
+
|
|
9
|
+
[](https://github.com/scarver2/printavo-ruby/actions/workflows/ci.yml)
|
|
10
|
+
[](https://coveralls.io/github/scarver2/printavo-ruby?branch=master)
|
|
11
|
+
[](https://badge.fury.io/rb/printavo-ruby)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
|
|
14
|
+
A framework-agnostic Ruby SDK for the [Printavo](https://www.printavo.com) GraphQL API (v2).
|
|
15
|
+
|
|
16
|
+
> I use Printavo every day at [Texas Embroidery Ranch](https://texasembroideryranch.com). This gem was created to bridge Printavo
|
|
17
|
+
> with other operational systems—CRM, marketing, finance, and automation—so that print shops
|
|
18
|
+
> can build integrated workflows without writing raw GraphQL by hand.
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
- Full [Printavo v2 GraphQL API](https://www.printavo.com/docs/api/v2) support
|
|
23
|
+
- Resource-oriented interface: `client.customers.all`, `client.orders.find(id)`
|
|
24
|
+
- Raw GraphQL access: `client.graphql.query("{ ... }")`
|
|
25
|
+
- Rich domain models: `order.status`, `order.status?(:in_production)`, `order.customer`
|
|
26
|
+
- Rack-compatible webhook signature verification
|
|
27
|
+
- Multi-client support — no globals required
|
|
28
|
+
- Ruby 3.0+ required
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
Add to your Gemfile:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
gem "printavo-ruby"
|
|
36
|
+
```
|
|
37
|
+
or
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bundle add printavo-ruby
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
or install directly:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
gem install printavo-ruby
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Authentication
|
|
50
|
+
|
|
51
|
+
Printavo authenticates via your account **email** and **API token**
|
|
52
|
+
(found at My Account → API Token on [printavo.com](https://www.printavo.com)).
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
require "printavo"
|
|
56
|
+
|
|
57
|
+
client = Printavo::Client.new(
|
|
58
|
+
email: ENV["PRINTAVO_EMAIL"],
|
|
59
|
+
token: ENV["PRINTAVO_TOKEN"]
|
|
60
|
+
)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Rails Initializer
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
# config/initializers/printavo.rb
|
|
67
|
+
PRINTAVO = Printavo::Client.new(
|
|
68
|
+
email: ENV["PRINTAVO_EMAIL"],
|
|
69
|
+
token: ENV["PRINTAVO_TOKEN"]
|
|
70
|
+
)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Usage
|
|
74
|
+
|
|
75
|
+
### Customers
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
# List customers (25 per page by default)
|
|
79
|
+
customers = client.customers.all
|
|
80
|
+
customers.each { |c| puts "#{c.full_name} — #{c.email}" }
|
|
81
|
+
|
|
82
|
+
# Paginate
|
|
83
|
+
page_2 = client.customers.all(first: 25, after: cursor)
|
|
84
|
+
|
|
85
|
+
# Find a specific customer
|
|
86
|
+
customer = client.customers.find("12345")
|
|
87
|
+
puts customer.full_name # => "Jane Smith"
|
|
88
|
+
puts customer.company # => "Acme Shirts"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Orders
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
# List orders
|
|
95
|
+
orders = client.orders.all
|
|
96
|
+
orders.each { |o| puts "#{o.nickname}: #{o.status}" }
|
|
97
|
+
|
|
98
|
+
# Find an order
|
|
99
|
+
order = client.orders.find("99")
|
|
100
|
+
puts order.status # => "In Production"
|
|
101
|
+
puts order.status_key # => :in_production
|
|
102
|
+
puts order.status?(:in_production) # => true
|
|
103
|
+
puts order.total_price # => "1250.00"
|
|
104
|
+
puts order.customer.full_name # => "Bob Johnson"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Jobs (Line Items)
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
# List jobs for an order
|
|
111
|
+
jobs = client.jobs.all(order_id: "99")
|
|
112
|
+
jobs.each { |j| puts "#{j.name} x#{j.quantity} @ #{j.price}" }
|
|
113
|
+
|
|
114
|
+
# Find a specific job
|
|
115
|
+
job = client.jobs.find("77")
|
|
116
|
+
puts job.taxable? # => true
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Raw GraphQL
|
|
120
|
+
|
|
121
|
+
For queries not yet wrapped by a resource, use the raw GraphQL client directly:
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
result = client.graphql.query(<<~GQL)
|
|
125
|
+
{
|
|
126
|
+
customers(first: 5) {
|
|
127
|
+
nodes {
|
|
128
|
+
id
|
|
129
|
+
firstName
|
|
130
|
+
lastName
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
GQL
|
|
135
|
+
|
|
136
|
+
result["customers"]["nodes"].each { |c| puts c["firstName"] }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
With variables:
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
result = client.graphql.query(
|
|
143
|
+
"query Customer($id: ID!) { customer(id: $id) { id email } }",
|
|
144
|
+
variables: { id: "42" }
|
|
145
|
+
)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Webhooks
|
|
149
|
+
|
|
150
|
+
`Printavo::Webhooks.verify` provides Rack-compatible HMAC-SHA256 signature verification.
|
|
151
|
+
No extra dependencies required.
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
# Pure Ruby / Rack
|
|
155
|
+
valid = Printavo::Webhooks.verify(
|
|
156
|
+
signature, # X-Printavo-Signature header value
|
|
157
|
+
payload, # raw request body string
|
|
158
|
+
secret # your webhook secret
|
|
159
|
+
)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Rails Controller Example
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
class WebhooksController < ApplicationController
|
|
166
|
+
skip_before_action :verify_authenticity_token
|
|
167
|
+
|
|
168
|
+
def printavo
|
|
169
|
+
if Printavo::Webhooks.verify(
|
|
170
|
+
request.headers["X-Printavo-Signature"],
|
|
171
|
+
request.raw_post,
|
|
172
|
+
ENV["PRINTAVO_WEBHOOK_SECRET"]
|
|
173
|
+
)
|
|
174
|
+
event = JSON.parse(request.raw_post)
|
|
175
|
+
# process event["type"] ...
|
|
176
|
+
head :ok
|
|
177
|
+
else
|
|
178
|
+
head :unauthorized
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Error Handling
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
begin
|
|
188
|
+
client.orders.find("not_a_real_id")
|
|
189
|
+
rescue Printavo::AuthenticationError => e
|
|
190
|
+
# Bad email/token
|
|
191
|
+
rescue Printavo::RateLimitError => e
|
|
192
|
+
# Exceeded 10 req/5 sec — back off and retry
|
|
193
|
+
rescue Printavo::NotFoundError => e
|
|
194
|
+
# Resource doesn't exist
|
|
195
|
+
rescue Printavo::ApiError => e
|
|
196
|
+
# GraphQL error — e.message contains details, e.response has raw data
|
|
197
|
+
rescue Printavo::Error => e
|
|
198
|
+
# Catch-all for any Printavo error
|
|
199
|
+
end
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Versioning Roadmap
|
|
203
|
+
|
|
204
|
+
| Version | Milestone |
|
|
205
|
+
|---|---|
|
|
206
|
+
| 0.1.0 | Auth + Customers + Orders + Jobs |
|
|
207
|
+
| 0.2.0 | Status registry + Analytics/Reporting |
|
|
208
|
+
| 0.3.0 | Webhooks (Rack-compatible) |
|
|
209
|
+
| 0.4.0 | Expanded GraphQL DSL |
|
|
210
|
+
| 0.5.0 | Mutations (create/update) |
|
|
211
|
+
| 0.6.0 | Community burn-in / API stabilization |
|
|
212
|
+
| 0.7.0 | Pagination abstraction helpers |
|
|
213
|
+
| 0.8.0 | Retry/backoff + rate limit awareness |
|
|
214
|
+
| 0.9.0 | Community feedback + API freeze |
|
|
215
|
+
| 1.0.0 | Stable public SDK |
|
|
216
|
+
|
|
217
|
+
**Rules**: `PATCH` = bug fix · `MINOR` = new backward-compatible feature · `MAJOR` = breaking change
|
|
218
|
+
|
|
219
|
+
## API Documentation
|
|
220
|
+
|
|
221
|
+
- [Printavo v2 API Reference](https://www.printavo.com/docs/api/v2)
|
|
222
|
+
- [Printavo GraphQL API Blog Post](https://www.printavo.com/blog/new-graphql-api/)
|
|
223
|
+
|
|
224
|
+
## Development
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
git clone https://github.com/scarver2/printavo-ruby.git
|
|
228
|
+
cd printavo-ruby
|
|
229
|
+
bundle install
|
|
230
|
+
|
|
231
|
+
# Run specs
|
|
232
|
+
bundle exec rspec
|
|
233
|
+
|
|
234
|
+
# Lint
|
|
235
|
+
bundle exec rubocop
|
|
236
|
+
|
|
237
|
+
# Guard DX (watches files, re-runs tests + lint on save)
|
|
238
|
+
bundle exec guard
|
|
239
|
+
|
|
240
|
+
# Interactive console
|
|
241
|
+
PRINTAVO_EMAIL=you@example.com PRINTAVO_TOKEN=your_token bin/console
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for full contribution guidelines.
|
|
245
|
+
|
|
246
|
+
## Colophon
|
|
247
|
+
|
|
248
|
+
[MIT License](LICENSE)
|
|
249
|
+
|
|
250
|
+
©2026 [Stan Carver II](https://stancarver.com)
|
|
251
|
+
|
|
252
|
+

|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# lib/printavo/client.rb
|
|
2
|
+
module Printavo
|
|
3
|
+
class Client
|
|
4
|
+
attr_reader :graphql
|
|
5
|
+
|
|
6
|
+
# Creates a new Printavo API client. Each instance is independent —
|
|
7
|
+
# multiple clients with different credentials can coexist in one process.
|
|
8
|
+
#
|
|
9
|
+
# @param email [String] the email address associated with your Printavo account
|
|
10
|
+
# @param token [String] the API token from your Printavo My Account page
|
|
11
|
+
# @param timeout [Integer] HTTP timeout in seconds (default: 30)
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# client = Printavo::Client.new(
|
|
15
|
+
# email: ENV["PRINTAVO_EMAIL"],
|
|
16
|
+
# token: ENV["PRINTAVO_TOKEN"]
|
|
17
|
+
# )
|
|
18
|
+
# client.customers.all
|
|
19
|
+
# client.orders.find("12345")
|
|
20
|
+
# client.graphql.query("{ customers { nodes { id } } }")
|
|
21
|
+
def initialize(email:, token:, timeout: 30)
|
|
22
|
+
connection = Connection.new(email: email, token: token, timeout: timeout).build
|
|
23
|
+
@graphql = GraphqlClient.new(connection)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def customers
|
|
27
|
+
Resources::Customers.new(@graphql)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def orders
|
|
31
|
+
Resources::Orders.new(@graphql)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def jobs
|
|
35
|
+
Resources::Jobs.new(@graphql)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# lib/printavo/connection.rb
|
|
2
|
+
require 'faraday'
|
|
3
|
+
require 'faraday/retry'
|
|
4
|
+
|
|
5
|
+
module Printavo
|
|
6
|
+
class Connection
|
|
7
|
+
def initialize(email:, token:, base_url: Config::BASE_URL, timeout: 30)
|
|
8
|
+
@email = email
|
|
9
|
+
@token = token
|
|
10
|
+
@base_url = base_url
|
|
11
|
+
@timeout = timeout
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def build
|
|
15
|
+
Faraday.new(url: @base_url) do |f|
|
|
16
|
+
f.headers['Content-Type'] = 'application/json'
|
|
17
|
+
f.headers['Accept'] = 'application/json'
|
|
18
|
+
f.headers['email'] = @email
|
|
19
|
+
f.headers['token'] = @token
|
|
20
|
+
|
|
21
|
+
f.request :retry, max: 2, interval: 0.5, retry_statuses: [429, 500, 502, 503]
|
|
22
|
+
|
|
23
|
+
f.response :json
|
|
24
|
+
f.options.timeout = @timeout
|
|
25
|
+
f.options.open_timeout = @timeout
|
|
26
|
+
|
|
27
|
+
f.adapter Faraday.default_adapter
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# lib/printavo/errors.rb
|
|
2
|
+
module Printavo
|
|
3
|
+
class Error < StandardError; end
|
|
4
|
+
|
|
5
|
+
class AuthenticationError < Error; end
|
|
6
|
+
|
|
7
|
+
class RateLimitError < Error; end
|
|
8
|
+
|
|
9
|
+
class NotFoundError < Error; end
|
|
10
|
+
|
|
11
|
+
class ApiError < Error
|
|
12
|
+
attr_reader :response
|
|
13
|
+
|
|
14
|
+
def initialize(message, response: nil)
|
|
15
|
+
super(message)
|
|
16
|
+
@response = response
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# lib/printavo/graphql_client.rb
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Printavo
|
|
5
|
+
class GraphqlClient
|
|
6
|
+
def initialize(connection)
|
|
7
|
+
@connection = connection
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def query(query_string, variables: {})
|
|
11
|
+
response = @connection.post('') do |req|
|
|
12
|
+
req.body = JSON.generate(query: query_string, variables: variables)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
handle_response(response)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def handle_response(response)
|
|
21
|
+
body = response.body
|
|
22
|
+
|
|
23
|
+
case response.status
|
|
24
|
+
when 401 then raise AuthenticationError, 'Invalid credentials — check your email and token'
|
|
25
|
+
when 429 then raise RateLimitError, 'Printavo rate limit exceeded (10 req/5 sec)'
|
|
26
|
+
when 404 then raise NotFoundError, 'Resource not found'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
errors = body.is_a?(Hash) ? body['errors'] : nil
|
|
30
|
+
if errors&.any?
|
|
31
|
+
messages = errors.map { |e| e['message'] }.join(', ')
|
|
32
|
+
raise ApiError.new(messages, response: body)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
body.is_a?(Hash) ? body['data'] : body
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# lib/printavo/models/base.rb
|
|
2
|
+
module Printavo
|
|
3
|
+
module Models
|
|
4
|
+
class Base
|
|
5
|
+
def initialize(attributes = {})
|
|
6
|
+
@attributes = (attributes || {}).transform_keys(&:to_s)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def [](key)
|
|
10
|
+
@attributes[key.to_s]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def dig(*keys)
|
|
14
|
+
keys.map(&:to_s).reduce(@attributes) do |obj, key|
|
|
15
|
+
break nil unless obj.is_a?(Hash)
|
|
16
|
+
|
|
17
|
+
obj[key]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_h
|
|
22
|
+
@attributes.dup
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def ==(other)
|
|
26
|
+
other.is_a?(self.class) && other.to_h == to_h
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def inspect
|
|
30
|
+
"#<#{self.class.name} #{@attributes.inspect}>"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# lib/printavo/models/customer.rb
|
|
2
|
+
module Printavo
|
|
3
|
+
class Customer < Models::Base
|
|
4
|
+
def id = self['id']
|
|
5
|
+
def first_name = self['firstName']
|
|
6
|
+
def last_name = self['lastName']
|
|
7
|
+
def email = self['email']
|
|
8
|
+
def phone = self['phone']
|
|
9
|
+
def company = self['company']
|
|
10
|
+
|
|
11
|
+
def full_name
|
|
12
|
+
[first_name, last_name].compact.join(' ').strip
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# lib/printavo/models/job.rb
|
|
2
|
+
module Printavo
|
|
3
|
+
class Job < Models::Base
|
|
4
|
+
def id = self['id']
|
|
5
|
+
def name = self['name']
|
|
6
|
+
def quantity = self['quantity']
|
|
7
|
+
def price = self['price']
|
|
8
|
+
def taxable = self['taxable']
|
|
9
|
+
|
|
10
|
+
def taxable?
|
|
11
|
+
taxable == true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# lib/printavo/models/order.rb
|
|
2
|
+
module Printavo
|
|
3
|
+
class Order < Models::Base
|
|
4
|
+
def id = self['id']
|
|
5
|
+
def nickname = self['nickname']
|
|
6
|
+
def total_price = self['totalPrice']
|
|
7
|
+
|
|
8
|
+
def status
|
|
9
|
+
dig('status', 'name')
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def status_key
|
|
13
|
+
return nil if status.nil?
|
|
14
|
+
|
|
15
|
+
status.downcase.gsub(/\s+/, '_').to_sym
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def status?(key)
|
|
19
|
+
status_key == key.to_sym
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def customer
|
|
23
|
+
attrs = self['customer']
|
|
24
|
+
Customer.new(attrs) if attrs
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# lib/printavo/resources/customers.rb
|
|
2
|
+
module Printavo
|
|
3
|
+
module Resources
|
|
4
|
+
class Customers < Base
|
|
5
|
+
ALL_QUERY = <<~GQL.freeze
|
|
6
|
+
query Customers($first: Int, $after: String) {
|
|
7
|
+
customers(first: $first, after: $after) {
|
|
8
|
+
nodes {
|
|
9
|
+
id
|
|
10
|
+
firstName
|
|
11
|
+
lastName
|
|
12
|
+
email
|
|
13
|
+
phone
|
|
14
|
+
company
|
|
15
|
+
}
|
|
16
|
+
pageInfo {
|
|
17
|
+
hasNextPage
|
|
18
|
+
endCursor
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
GQL
|
|
23
|
+
|
|
24
|
+
FIND_QUERY = <<~GQL.freeze
|
|
25
|
+
query Customer($id: ID!) {
|
|
26
|
+
customer(id: $id) {
|
|
27
|
+
id
|
|
28
|
+
firstName
|
|
29
|
+
lastName
|
|
30
|
+
email
|
|
31
|
+
phone
|
|
32
|
+
company
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
GQL
|
|
36
|
+
|
|
37
|
+
def all(first: 25, after: nil)
|
|
38
|
+
data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
|
|
39
|
+
data['customers']['nodes'].map { |attrs| Printavo::Customer.new(attrs) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def find(id)
|
|
43
|
+
data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
|
|
44
|
+
Printavo::Customer.new(data['customer'])
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# lib/printavo/resources/jobs.rb
|
|
2
|
+
module Printavo
|
|
3
|
+
module Resources
|
|
4
|
+
class Jobs < Base
|
|
5
|
+
ALL_QUERY = <<~GQL.freeze
|
|
6
|
+
query LineItems($orderId: ID!, $first: Int, $after: String) {
|
|
7
|
+
order(id: $orderId) {
|
|
8
|
+
lineItems(first: $first, after: $after) {
|
|
9
|
+
nodes {
|
|
10
|
+
id
|
|
11
|
+
name
|
|
12
|
+
quantity
|
|
13
|
+
price
|
|
14
|
+
taxable
|
|
15
|
+
}
|
|
16
|
+
pageInfo {
|
|
17
|
+
hasNextPage
|
|
18
|
+
endCursor
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
GQL
|
|
24
|
+
|
|
25
|
+
FIND_QUERY = <<~GQL.freeze
|
|
26
|
+
query LineItem($id: ID!) {
|
|
27
|
+
lineItem(id: $id) {
|
|
28
|
+
id
|
|
29
|
+
name
|
|
30
|
+
quantity
|
|
31
|
+
price
|
|
32
|
+
taxable
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
GQL
|
|
36
|
+
|
|
37
|
+
def all(order_id:, first: 25, after: nil)
|
|
38
|
+
data = @graphql.query(ALL_QUERY, variables: { orderId: order_id.to_s, first: first, after: after })
|
|
39
|
+
data['order']['lineItems']['nodes'].map { |attrs| Printavo::Job.new(attrs) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def find(id)
|
|
43
|
+
data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
|
|
44
|
+
Printavo::Job.new(data['lineItem'])
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# lib/printavo/resources/orders.rb
|
|
2
|
+
module Printavo
|
|
3
|
+
module Resources
|
|
4
|
+
class Orders < Base
|
|
5
|
+
ALL_QUERY = <<~GQL.freeze
|
|
6
|
+
query Orders($first: Int, $after: String) {
|
|
7
|
+
orders(first: $first, after: $after) {
|
|
8
|
+
nodes {
|
|
9
|
+
id
|
|
10
|
+
nickname
|
|
11
|
+
totalPrice
|
|
12
|
+
status {
|
|
13
|
+
id
|
|
14
|
+
name
|
|
15
|
+
}
|
|
16
|
+
customer {
|
|
17
|
+
id
|
|
18
|
+
firstName
|
|
19
|
+
lastName
|
|
20
|
+
email
|
|
21
|
+
company
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
pageInfo {
|
|
25
|
+
hasNextPage
|
|
26
|
+
endCursor
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
GQL
|
|
31
|
+
|
|
32
|
+
FIND_QUERY = <<~GQL.freeze
|
|
33
|
+
query Order($id: ID!) {
|
|
34
|
+
order(id: $id) {
|
|
35
|
+
id
|
|
36
|
+
nickname
|
|
37
|
+
totalPrice
|
|
38
|
+
status {
|
|
39
|
+
id
|
|
40
|
+
name
|
|
41
|
+
}
|
|
42
|
+
customer {
|
|
43
|
+
id
|
|
44
|
+
firstName
|
|
45
|
+
lastName
|
|
46
|
+
email
|
|
47
|
+
company
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
GQL
|
|
52
|
+
|
|
53
|
+
def all(first: 25, after: nil)
|
|
54
|
+
data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
|
|
55
|
+
data['orders']['nodes'].map { |attrs| Printavo::Order.new(attrs) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def find(id)
|
|
59
|
+
data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
|
|
60
|
+
Printavo::Order.new(data['order'])
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# lib/printavo/webhooks.rb
|
|
2
|
+
require 'openssl'
|
|
3
|
+
|
|
4
|
+
module Printavo
|
|
5
|
+
module Webhooks
|
|
6
|
+
# Verifies a Printavo webhook signature using HMAC-SHA256.
|
|
7
|
+
#
|
|
8
|
+
# Uses a constant-time comparison to prevent timing attacks.
|
|
9
|
+
#
|
|
10
|
+
# @param signature [String] the signature from the X-Printavo-Signature header
|
|
11
|
+
# @param payload [String] the raw request body string
|
|
12
|
+
# @param secret [String] your webhook secret configured in Printavo
|
|
13
|
+
# @return [Boolean]
|
|
14
|
+
#
|
|
15
|
+
# @example Rails controller
|
|
16
|
+
# if Printavo::Webhooks.verify(
|
|
17
|
+
# request.headers["X-Printavo-Signature"],
|
|
18
|
+
# request.raw_post,
|
|
19
|
+
# ENV["PRINTAVO_WEBHOOK_SECRET"]
|
|
20
|
+
# )
|
|
21
|
+
# # process event
|
|
22
|
+
# else
|
|
23
|
+
# head :unauthorized
|
|
24
|
+
# end
|
|
25
|
+
def self.verify(signature, payload, secret)
|
|
26
|
+
return false if signature.nil? || payload.nil? || secret.nil?
|
|
27
|
+
|
|
28
|
+
expected = OpenSSL::HMAC.hexdigest('SHA256', secret, payload)
|
|
29
|
+
OpenSSL.secure_compare(expected, signature)
|
|
30
|
+
rescue ArgumentError, TypeError
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/printavo.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# lib/printavo.rb
|
|
2
|
+
require 'faraday'
|
|
3
|
+
require 'faraday/retry'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
require_relative 'printavo/version'
|
|
7
|
+
require_relative 'printavo/errors'
|
|
8
|
+
require_relative 'printavo/config'
|
|
9
|
+
require_relative 'printavo/connection'
|
|
10
|
+
require_relative 'printavo/graphql_client'
|
|
11
|
+
require_relative 'printavo/models/base'
|
|
12
|
+
require_relative 'printavo/models/customer'
|
|
13
|
+
require_relative 'printavo/models/order'
|
|
14
|
+
require_relative 'printavo/models/job'
|
|
15
|
+
require_relative 'printavo/resources/base'
|
|
16
|
+
require_relative 'printavo/resources/customers'
|
|
17
|
+
require_relative 'printavo/resources/orders'
|
|
18
|
+
require_relative 'printavo/resources/jobs'
|
|
19
|
+
require_relative 'printavo/webhooks'
|
|
20
|
+
require_relative 'printavo/client'
|
|
21
|
+
|
|
22
|
+
module Printavo
|
|
23
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: printavo-ruby
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Stan Carver II
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-03-30 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: faraday
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: faraday-retry
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: faker
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: guard
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '2.0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '2.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: guard-rspec
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '4.0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '4.0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: guard-rubocop
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '1.0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '1.0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rake
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '13.0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '13.0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rspec
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '3.0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - "~>"
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '3.0'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: rspec_junit_formatter
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - "~>"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0.6'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0.6'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: rubocop
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - "~>"
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '1.0'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - "~>"
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '1.0'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: rubocop-performance
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - "~>"
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '1.0'
|
|
160
|
+
type: :development
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - "~>"
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: '1.0'
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: rubocop-rake
|
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - "~>"
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '0.6'
|
|
174
|
+
type: :development
|
|
175
|
+
prerelease: false
|
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - "~>"
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: '0.6'
|
|
181
|
+
- !ruby/object:Gem::Dependency
|
|
182
|
+
name: rubocop-rspec
|
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
|
184
|
+
requirements:
|
|
185
|
+
- - "~>"
|
|
186
|
+
- !ruby/object:Gem::Version
|
|
187
|
+
version: '3.0'
|
|
188
|
+
type: :development
|
|
189
|
+
prerelease: false
|
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
191
|
+
requirements:
|
|
192
|
+
- - "~>"
|
|
193
|
+
- !ruby/object:Gem::Version
|
|
194
|
+
version: '3.0'
|
|
195
|
+
- !ruby/object:Gem::Dependency
|
|
196
|
+
name: simplecov
|
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
|
198
|
+
requirements:
|
|
199
|
+
- - "~>"
|
|
200
|
+
- !ruby/object:Gem::Version
|
|
201
|
+
version: '0.22'
|
|
202
|
+
type: :development
|
|
203
|
+
prerelease: false
|
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
205
|
+
requirements:
|
|
206
|
+
- - "~>"
|
|
207
|
+
- !ruby/object:Gem::Version
|
|
208
|
+
version: '0.22'
|
|
209
|
+
- !ruby/object:Gem::Dependency
|
|
210
|
+
name: simplecov-lcov
|
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
|
212
|
+
requirements:
|
|
213
|
+
- - "~>"
|
|
214
|
+
- !ruby/object:Gem::Version
|
|
215
|
+
version: '0.8'
|
|
216
|
+
type: :development
|
|
217
|
+
prerelease: false
|
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
219
|
+
requirements:
|
|
220
|
+
- - "~>"
|
|
221
|
+
- !ruby/object:Gem::Version
|
|
222
|
+
version: '0.8'
|
|
223
|
+
- !ruby/object:Gem::Dependency
|
|
224
|
+
name: vcr
|
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
|
226
|
+
requirements:
|
|
227
|
+
- - "~>"
|
|
228
|
+
- !ruby/object:Gem::Version
|
|
229
|
+
version: '6.0'
|
|
230
|
+
type: :development
|
|
231
|
+
prerelease: false
|
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
233
|
+
requirements:
|
|
234
|
+
- - "~>"
|
|
235
|
+
- !ruby/object:Gem::Version
|
|
236
|
+
version: '6.0'
|
|
237
|
+
- !ruby/object:Gem::Dependency
|
|
238
|
+
name: webmock
|
|
239
|
+
requirement: !ruby/object:Gem::Requirement
|
|
240
|
+
requirements:
|
|
241
|
+
- - "~>"
|
|
242
|
+
- !ruby/object:Gem::Version
|
|
243
|
+
version: '3.0'
|
|
244
|
+
type: :development
|
|
245
|
+
prerelease: false
|
|
246
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
247
|
+
requirements:
|
|
248
|
+
- - "~>"
|
|
249
|
+
- !ruby/object:Gem::Version
|
|
250
|
+
version: '3.0'
|
|
251
|
+
description: |
|
|
252
|
+
A framework-agnostic Ruby SDK for Printavo supporting the v2 GraphQL API.
|
|
253
|
+
Provides both a resource-oriented interface (client.orders.all) and rich domain
|
|
254
|
+
models (Printavo::Order), plus raw GraphQL access and Rack-compatible webhook
|
|
255
|
+
verification. Built to bridge Printavo with external operational systems.
|
|
256
|
+
email:
|
|
257
|
+
- stan@stancarver.com
|
|
258
|
+
executables: []
|
|
259
|
+
extensions: []
|
|
260
|
+
extra_rdoc_files: []
|
|
261
|
+
files:
|
|
262
|
+
- CHANGELOG.md
|
|
263
|
+
- LICENSE
|
|
264
|
+
- README.md
|
|
265
|
+
- lib/printavo.rb
|
|
266
|
+
- lib/printavo/client.rb
|
|
267
|
+
- lib/printavo/config.rb
|
|
268
|
+
- lib/printavo/connection.rb
|
|
269
|
+
- lib/printavo/errors.rb
|
|
270
|
+
- lib/printavo/graphql_client.rb
|
|
271
|
+
- lib/printavo/models/base.rb
|
|
272
|
+
- lib/printavo/models/customer.rb
|
|
273
|
+
- lib/printavo/models/job.rb
|
|
274
|
+
- lib/printavo/models/order.rb
|
|
275
|
+
- lib/printavo/resources/base.rb
|
|
276
|
+
- lib/printavo/resources/customers.rb
|
|
277
|
+
- lib/printavo/resources/jobs.rb
|
|
278
|
+
- lib/printavo/resources/orders.rb
|
|
279
|
+
- lib/printavo/version.rb
|
|
280
|
+
- lib/printavo/webhooks.rb
|
|
281
|
+
homepage: https://github.com/scarver2/printavo-ruby
|
|
282
|
+
licenses:
|
|
283
|
+
- MIT
|
|
284
|
+
metadata:
|
|
285
|
+
bug_tracker_uri: https://github.com/scarver2/printavo-ruby/issues
|
|
286
|
+
changelog_uri: https://github.com/scarver2/printavo-ruby/blob/master/CHANGELOG.md
|
|
287
|
+
documentation_uri: https://github.com/scarver2/printavo-ruby#readme
|
|
288
|
+
source_code_uri: https://github.com/scarver2/printavo-ruby
|
|
289
|
+
rubygems_mfa_required: 'true'
|
|
290
|
+
post_install_message:
|
|
291
|
+
rdoc_options: []
|
|
292
|
+
require_paths:
|
|
293
|
+
- lib
|
|
294
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
295
|
+
requirements:
|
|
296
|
+
- - ">="
|
|
297
|
+
- !ruby/object:Gem::Version
|
|
298
|
+
version: '3.0'
|
|
299
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
300
|
+
requirements:
|
|
301
|
+
- - ">="
|
|
302
|
+
- !ruby/object:Gem::Version
|
|
303
|
+
version: '0'
|
|
304
|
+
requirements: []
|
|
305
|
+
rubygems_version: 3.5.22
|
|
306
|
+
signing_key:
|
|
307
|
+
specification_version: 4
|
|
308
|
+
summary: Ruby SDK for the Printavo GraphQL API
|
|
309
|
+
test_files: []
|