printful_api 1.0.1
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/.gitignore +1 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +211 -0
- data/VERSION +1 -0
- data/lib/printful_api.rb +65 -0
- data/lib/printful_api/address.rb +9 -0
- data/lib/printful_api/api_operations/create.rb +27 -0
- data/lib/printful_api/api_operations/delete.rb +29 -0
- data/lib/printful_api/api_operations/get.rb +30 -0
- data/lib/printful_api/api_operations/list.rb +35 -0
- data/lib/printful_api/api_operations/save.rb +25 -0
- data/lib/printful_api/api_operations/update.rb +24 -0
- data/lib/printful_api/api_resource.rb +104 -0
- data/lib/printful_api/card_info.rb +9 -0
- data/lib/printful_api/cost.rb +9 -0
- data/lib/printful_api/country.rb +34 -0
- data/lib/printful_api/file.rb +17 -0
- data/lib/printful_api/file_type.rb +9 -0
- data/lib/printful_api/gift_data.rb +9 -0
- data/lib/printful_api/item.rb +14 -0
- data/lib/printful_api/item_option.rb +11 -0
- data/lib/printful_api/option_type.rb +9 -0
- data/lib/printful_api/order.rb +39 -0
- data/lib/printful_api/packing_slip.rb +22 -0
- data/lib/printful_api/product.rb +48 -0
- data/lib/printful_api/product_variant.rb +14 -0
- data/lib/printful_api/shipment.rb +10 -0
- data/lib/printful_api/shipping_rate.rb +29 -0
- data/lib/printful_api/state.rb +9 -0
- data/lib/printful_api/store.rb +29 -0
- data/lib/printful_api/tax_rate.rb +21 -0
- data/lib/printful_api/variant.rb +16 -0
- data/lib/printful_api/version.rb +3 -0
- data/lib/printful_api/webhooks.rb +35 -0
- data/lib/printful_client.rb +144 -0
- data/printful_api.gemspec +18 -0
- metadata +81 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ab40c8602c1fed1d573a8fa4d72a4f30142534df
|
4
|
+
data.tar.gz: c5f7c5ba10a4096a227fb446dd4977dd1dc2ea08
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 255311dbf606b5cf05ddb6b3b5a22dc2fd1854491bc57332952dfa5f78b80d8bb540cd65db6764a06daa72df963ea50bbc21eea5e390758fb6e2fe85d3120375
|
7
|
+
data.tar.gz: 294b885561272ac8aa28ea013baef04f7c006aaf2357629a292d6752b7f02495483c1af97eba857a224b022160eec61e0c0f149647b41db3b2d992068bc43371
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017- Groundswell Enterprises (http://www.groundswellenterprises.com)
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
# Printful API Ruby Bindings
|
2
|
+
|
3
|
+
The Printful API gem provides a ruby bindings SDK for quick and easy access to
|
4
|
+
the Printful service. Printful is a online company that will print custom
|
5
|
+
designs onto a variety of different apparel/accessories, then ship that item
|
6
|
+
with custom packaging directly to your customer. Printful make custom:
|
7
|
+
|
8
|
+
* T-shirts
|
9
|
+
* Sweatshirts
|
10
|
+
* Wall art (prints, posters, canvas, ...)
|
11
|
+
* Mugs
|
12
|
+
* Pillows
|
13
|
+
* Totes
|
14
|
+
* Hats
|
15
|
+
* Leggings
|
16
|
+
* Phone Cases
|
17
|
+
* Socks
|
18
|
+
* Dresses
|
19
|
+
* Skirts
|
20
|
+
* and more
|
21
|
+
|
22
|
+
[Sign up here](https://printful.com/a/amrap) to explore the full list of products, start creating,
|
23
|
+
previewing, and selling your designs.
|
24
|
+
|
25
|
+
We provide a comprehensive list of classes which map to the Printful data model,
|
26
|
+
allowing developers to pull and manipulate data with ease. This gem wraps
|
27
|
+
[the official Printful client library](https://www.printful.com/docs/libraries).
|
28
|
+
|
29
|
+
|
30
|
+
## Installation
|
31
|
+
|
32
|
+
You don't need this source code unless you want to modify the gem. If you just
|
33
|
+
want to use the Printful API Ruby bindings, you should run:
|
34
|
+
|
35
|
+
gem install printful_api
|
36
|
+
|
37
|
+
If you want to build the gem from source:
|
38
|
+
|
39
|
+
gem build printful_api.gemspec
|
40
|
+
|
41
|
+
### Requirements
|
42
|
+
|
43
|
+
* Ruby 1.9.3 or above.
|
44
|
+
* A Printful account, and api key. [Sign up here](https://printful.com/a/amrap)
|
45
|
+
|
46
|
+
### Bundler
|
47
|
+
|
48
|
+
If you are installing via bundler, you should be sure to use the https rubygems
|
49
|
+
source in your Gemfile, as any gems fetched over http could potentially be
|
50
|
+
compromised in transit and alter the code of gems fetched securely over https:
|
51
|
+
|
52
|
+
``` ruby
|
53
|
+
source 'https://rubygems.org'
|
54
|
+
|
55
|
+
gem 'rails'
|
56
|
+
gem 'printful_api'
|
57
|
+
```
|
58
|
+
|
59
|
+
## Usage
|
60
|
+
|
61
|
+
In order to access the Printful API you must first have an api key, which get
|
62
|
+
after creating [a Printful account](https://printful.com/a/amrap). After signing in, go to your
|
63
|
+
[store dashboard](https://www.printful.com/dashboard/store). If you haven't yet
|
64
|
+
create a store, otherwise click on the store to get to the "Update Store" screen.
|
65
|
+
Click on the "API" tab, to get to the "API Access" view. In a box below, there
|
66
|
+
will be a random set of letters and numbers, this is your api key. You will
|
67
|
+
need to assign the api to `PrintfulAPI.api_key` so the gem can give you access
|
68
|
+
to your store.
|
69
|
+
|
70
|
+
Or you can set the api key into the `PRINTFUL_API_KEY` environment variable.
|
71
|
+
|
72
|
+
``` ruby
|
73
|
+
require "printful_api"
|
74
|
+
PrintfulAPI.api_key = "g1n1h..."
|
75
|
+
|
76
|
+
# list all products
|
77
|
+
PrintfulAPI::Product.all
|
78
|
+
|
79
|
+
# get a single order by external ID (your order id)
|
80
|
+
PrintfulAPI::Order.get( '@YOUR_ORDER_ID' )
|
81
|
+
|
82
|
+
|
83
|
+
# get a single order by Printful's order ID
|
84
|
+
PrintfulAPI::Order.get( 342342 )
|
85
|
+
```
|
86
|
+
|
87
|
+
Once assigned, the gem will use it as necessary to authenticate requests for your
|
88
|
+
store.
|
89
|
+
|
90
|
+
## Products / Variations
|
91
|
+
|
92
|
+
``` ruby
|
93
|
+
|
94
|
+
# get a single product, in this case a T-SHIRT
|
95
|
+
product = PrintfulAPI::Product.get(5)
|
96
|
+
|
97
|
+
product.type # "T-SHIRT"
|
98
|
+
product.brand # "American Apparel"
|
99
|
+
product.model # "2001 Fine Jersey Short Sleeve Men T-Shirt"
|
100
|
+
product.image # "https://d1yg28hrivmbqm.cloudfront.net/products/5/product_1483514498.jpg"
|
101
|
+
product.variant_count # 270
|
102
|
+
|
103
|
+
# a list of different file types you can provide for printing, and the cost for using them
|
104
|
+
product.files # FileType[]
|
105
|
+
|
106
|
+
# list the various, some 260+ variations, cut, color, etc
|
107
|
+
product.variants # Variant[]
|
108
|
+
|
109
|
+
# list the different options, options for configuring the process
|
110
|
+
product.options # OptionType[]
|
111
|
+
|
112
|
+
# a list of dimensions for the product
|
113
|
+
product.dimensions # Hash
|
114
|
+
|
115
|
+
```
|
116
|
+
|
117
|
+
|
118
|
+
## Orders
|
119
|
+
|
120
|
+
``` ruby
|
121
|
+
|
122
|
+
order = PrintfulAPI::Order.create( {
|
123
|
+
"recipient": {
|
124
|
+
"name": "John Doe",
|
125
|
+
"address1": "19749 Dearborn St",
|
126
|
+
"city": "Chatsworth",
|
127
|
+
"state_code": "CA",
|
128
|
+
"country_code": "US",
|
129
|
+
"zip": "91311"
|
130
|
+
},
|
131
|
+
"external_id": 'order_1112',
|
132
|
+
"items": [{
|
133
|
+
"variant_id": 1,
|
134
|
+
"quantity": 1,
|
135
|
+
"files": [{
|
136
|
+
"url": "http://example.com/files/posters/poster_1.jpg"
|
137
|
+
}]
|
138
|
+
}]
|
139
|
+
} )
|
140
|
+
|
141
|
+
order.id # 2071687
|
142
|
+
order.external_id # "order_1112"
|
143
|
+
order.status # "draft"
|
144
|
+
order.shipping # "FEDEX_SMART_POST"
|
145
|
+
order.created # 1485550869
|
146
|
+
order.updated # 1485550869
|
147
|
+
order.recipient # PrintfulAPI::Address
|
148
|
+
order.items # PrintfulAPI::Item[]
|
149
|
+
order.costs # PrintfulAPI::Cost
|
150
|
+
order.retail_costs # PrintfulAPI::Cost
|
151
|
+
order.shipments # []
|
152
|
+
order.gift # nil
|
153
|
+
order.packing_slip # nil
|
154
|
+
|
155
|
+
# once all order information is confirmed and correct, run the confirm command
|
156
|
+
# and the store owner will be charged, and the printing begins.
|
157
|
+
order.confirm_for_fulfillment()
|
158
|
+
|
159
|
+
# didn't mean to process the order? delete it and the order will be canceled,
|
160
|
+
# and money returned to the store owner.
|
161
|
+
order.delete()
|
162
|
+
|
163
|
+
```
|
164
|
+
|
165
|
+
## Shipping and Tax Rates
|
166
|
+
|
167
|
+
``` ruby
|
168
|
+
|
169
|
+
# shipping options available for a set of items
|
170
|
+
shipping_rates = PrintfulAPI::ShippingRate.list( { address1: '12372 Carmel Country Rd', city: 'San Diego', country_code: 'US', state_code: 'CA', zip: 92130}, [{quantity: 2, variant_id: PrintfulAPI::Product.get(1).variants.first.id}], 'USD' )
|
171
|
+
|
172
|
+
shipping_rate = shipping_rates.first
|
173
|
+
|
174
|
+
shipping_rate.id # "USPS_FIRST"
|
175
|
+
shipping_rate.name # "USPS First Class Mail (3-5 business days after fulfillment)"
|
176
|
+
shipping_rate.rate # "3.05"
|
177
|
+
shipping_rate.currency # "USD"
|
178
|
+
|
179
|
+
```
|
180
|
+
|
181
|
+
``` ruby
|
182
|
+
|
183
|
+
# tax rates Printful will charge on orders to a specific location
|
184
|
+
tax_rate = PrintfulAPI::TaxRate.get( country_code: 'US', state_code: 'CA', city: 'San Diego', zip: 92130 )
|
185
|
+
tax_rate.required # true
|
186
|
+
tax_rate.rate # 0.775
|
187
|
+
tax_rate.shipping_taxable # false
|
188
|
+
|
189
|
+
```
|
190
|
+
|
191
|
+
## Country/State Lists
|
192
|
+
|
193
|
+
``` ruby
|
194
|
+
|
195
|
+
# list all countries that are valid for Printful shipping. A country and State
|
196
|
+
# core a required for orders, when available from this api.
|
197
|
+
countries = PrintfulAPI::Country.list()
|
198
|
+
country = countries.find{|country| country.code == 'US' }
|
199
|
+
|
200
|
+
# use the code values when referencing a country or state in an order
|
201
|
+
|
202
|
+
country.code # "US"
|
203
|
+
country.name # "United States"
|
204
|
+
|
205
|
+
# a list of states/provinces/regions for that country
|
206
|
+
country.states # State[]
|
207
|
+
|
208
|
+
country.states.first.code # "AA"
|
209
|
+
country.states.first.name # "Armed Forces Americas (except Canada)"
|
210
|
+
|
211
|
+
```
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.1
|
data/lib/printful_api.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# Printful Ruby bindings
|
2
|
+
# API spec at https://www.printful.com/docs
|
3
|
+
|
4
|
+
require 'printful_api/version'
|
5
|
+
|
6
|
+
require 'printful_client'
|
7
|
+
|
8
|
+
require 'printful_api/api_resource'
|
9
|
+
require 'printful_api/api_operations/create'
|
10
|
+
require 'printful_api/api_operations/delete'
|
11
|
+
require 'printful_api/api_operations/get'
|
12
|
+
require 'printful_api/api_operations/list'
|
13
|
+
require 'printful_api/api_operations/save'
|
14
|
+
require 'printful_api/api_operations/update'
|
15
|
+
require 'printful_api/address'
|
16
|
+
require 'printful_api/card_info'
|
17
|
+
require 'printful_api/country'
|
18
|
+
require 'printful_api/cost'
|
19
|
+
require 'printful_api/file'
|
20
|
+
require 'printful_api/file_type'
|
21
|
+
require 'printful_api/gift_data'
|
22
|
+
require 'printful_api/item'
|
23
|
+
require 'printful_api/item_option'
|
24
|
+
require 'printful_api/option_type'
|
25
|
+
require 'printful_api/order'
|
26
|
+
require 'printful_api/packing_slip'
|
27
|
+
require 'printful_api/product'
|
28
|
+
require 'printful_api/product_variant'
|
29
|
+
require 'printful_api/shipping_rate'
|
30
|
+
require 'printful_api/state'
|
31
|
+
require 'printful_api/store'
|
32
|
+
require 'printful_api/tax_rate'
|
33
|
+
require 'printful_api/variant'
|
34
|
+
require 'printful_api/webhooks'
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
module PrintfulAPI
|
39
|
+
|
40
|
+
@@client = PrintfulClient.new( ENV['PRINTFUL_API_KEY'] )
|
41
|
+
|
42
|
+
def self.api_key=( api_key )
|
43
|
+
@@client = PrintfulClient.new( api_key )
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.request( method, path, opts = {} )
|
47
|
+
|
48
|
+
# puts "#{method}, #{path}, #{opts}"
|
49
|
+
|
50
|
+
case method.to_s.upcase
|
51
|
+
when "GET"
|
52
|
+
@@client.get(path, opts[:params])
|
53
|
+
when "DELETE"
|
54
|
+
@@client.delete(path, opts[:params])
|
55
|
+
when "POST"
|
56
|
+
@@client.post(path, opts[:data], opts[:params])
|
57
|
+
when "PUT"
|
58
|
+
@@client.put(path, opts[:data], opts[:params])
|
59
|
+
else
|
60
|
+
die()
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
module APIOperations
|
4
|
+
|
5
|
+
module Create
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
def create( data={}, params={} )
|
14
|
+
|
15
|
+
result = PrintfulAPI.request( :POST, params.delete(:resource_path) || self.resource_path, params: params, data: data )
|
16
|
+
|
17
|
+
self.new.load_data( result )
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
module APIOperations
|
4
|
+
|
5
|
+
module Delete
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
def delete( id, opts={} )
|
14
|
+
|
15
|
+
PrintfulAPI.request( :DELETE, "#{opts.delete(:resource_path) || self.resource_path}/#{id}" )
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete()
|
22
|
+
self.class.delete( self.id )
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
module APIOperations
|
4
|
+
|
5
|
+
module Get
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
def get( id, opts={} )
|
14
|
+
|
15
|
+
data = PrintfulAPI.request( :GET, "#{opts.delete(:resource_path) || self.resource_path}/#{id}" )
|
16
|
+
|
17
|
+
model = self.new
|
18
|
+
model.load_data( data )
|
19
|
+
|
20
|
+
model
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
module APIOperations
|
4
|
+
|
5
|
+
module List
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
def list( filters={}, opts={} )
|
14
|
+
|
15
|
+
data_list = PrintfulAPI.request( :GET, opts.delete(:resource_path) || self.resource_path, params: filters )
|
16
|
+
|
17
|
+
data_list.collect do |data|
|
18
|
+
|
19
|
+
model = self.new
|
20
|
+
model.load_data( data )
|
21
|
+
|
22
|
+
model
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
alias :all :list
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
module APIOperations
|
4
|
+
|
5
|
+
module Save
|
6
|
+
|
7
|
+
def save( opts = {} )
|
8
|
+
|
9
|
+
if self.id.present?
|
10
|
+
|
11
|
+
self.class.update( self.to_h, opts )
|
12
|
+
|
13
|
+
else
|
14
|
+
|
15
|
+
self.class.create( self.to_h, opts )
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
module APIOperations
|
4
|
+
|
5
|
+
module Update
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
def update( id, data={}, params={} )
|
14
|
+
|
15
|
+
PrintfulAPI.request( :PUT, "#{self.resource_path}/#{id}", params: params, data: data )
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
class APIResource
|
3
|
+
|
4
|
+
attr_accessor :raw_data
|
5
|
+
|
6
|
+
class << self; attr_accessor :api_attribute_list end
|
7
|
+
|
8
|
+
|
9
|
+
def self.api_attributes( *args )
|
10
|
+
self.api_attribute_list = (self.api_attribute_list || []).concat(args)
|
11
|
+
|
12
|
+
attr_accessor *args
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.has_many( attribute_name, args = {} )
|
16
|
+
args[:class] = args[:class] if args[:class].is_a? String
|
17
|
+
args[:class] ||= "PrintfulAPI::#{APIResource.singularize( APIResource.camelize(attribute_name.to_s ) )}"
|
18
|
+
|
19
|
+
self.api_attributes *[attribute_name.to_sym]
|
20
|
+
|
21
|
+
define_method("#{attribute_name}=") do |array|
|
22
|
+
if array.present?
|
23
|
+
array = array.collect do |data|
|
24
|
+
args[:class].constantize.new.load_data(data)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
self.instance_variable_set("@#{attribute_name}", array)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.belongs_to( attribute_name, args = {} )
|
32
|
+
args[:class] = args[:class] if args[:class].is_a? String
|
33
|
+
args[:class] ||= "PrintfulAPI::#{APIResource.camelize( attribute_name.to_s )}"
|
34
|
+
args[:foreign_key] ||= "#{attribute_name}_id"
|
35
|
+
|
36
|
+
self.api_attributes *[attribute_name.to_sym]
|
37
|
+
|
38
|
+
define_method("#{attribute_name}") do
|
39
|
+
attribute_value = self.instance_variable_get( "@#{attribute_name}" )
|
40
|
+
attribute_value ||= args[:class].new.get( args[:foreign_key] ) if self.respond_to?( args[:foreign_key] )
|
41
|
+
self.instance_variable_set( "@#{attribute_name}", attribute_value )
|
42
|
+
end
|
43
|
+
|
44
|
+
define_method("#{attribute_name}=") do |data|
|
45
|
+
if data.is_a?(PrintfulAPI::APIResource)
|
46
|
+
self.instance_variable_set("@#{attribute_name}", data)
|
47
|
+
else
|
48
|
+
model = args[:class].constantize.new.load_data(data) if data.present?
|
49
|
+
self.instance_variable_set( "@#{attribute_name}", model )
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def load_data( data )
|
55
|
+
self.raw_data = data
|
56
|
+
data.each do |key,value|
|
57
|
+
|
58
|
+
if self.respond_to? "#{key}="
|
59
|
+
self.send("#{key}=", value)
|
60
|
+
else
|
61
|
+
puts "Accessor doesn't exist #{self.class.name}\##{"#{key}="}"
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
self
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_h()
|
71
|
+
hash = {}
|
72
|
+
self.class.api_attribute_list.each do |attribute_name|
|
73
|
+
value = self.send(attribute_name)
|
74
|
+
if value.is_a? Array
|
75
|
+
|
76
|
+
hash[attribute_name] = value.collect do |array_item|
|
77
|
+
if array_item.is_a? APIResource
|
78
|
+
hash[attribute_name] = array_item.to_h
|
79
|
+
else
|
80
|
+
hash[attribute_name] = array_item
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
elsif value.is_a? APIResource
|
85
|
+
hash[attribute_name] = value.to_h
|
86
|
+
else
|
87
|
+
hash[attribute_name] = value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
hash
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.camelize( str )
|
95
|
+
str.split('_').map {|w| w.capitalize}.join
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.singularize( str )
|
99
|
+
str = str[0..-2] if str[-1] == 's'
|
100
|
+
str
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
class Country < APIResource
|
4
|
+
include PrintfulAPI::APIOperations::List
|
5
|
+
|
6
|
+
api_attributes :code, :name
|
7
|
+
has_many :states
|
8
|
+
|
9
|
+
def self.list( filters={}, opts={} )
|
10
|
+
taxable = filters.delete(:taxable)
|
11
|
+
|
12
|
+
puts "Country.list taxable: #{taxable}, #{filters}, #{opts}"
|
13
|
+
|
14
|
+
if taxable
|
15
|
+
super( filters, opts.merge( resource_path: '/tax/countries' ) )
|
16
|
+
else
|
17
|
+
super( filters, opts )
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def states
|
22
|
+
@states
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.resource_path
|
26
|
+
'/countries'
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
class File < APIResource
|
4
|
+
include PrintfulAPI::APIOperations::List
|
5
|
+
include PrintfulAPI::APIOperations::Create
|
6
|
+
include PrintfulAPI::APIOperations::Get
|
7
|
+
|
8
|
+
api_attributes :id, :type, :hash, :url, :filename, :mime_type, :size, :width, :height, :dpi, :status, :created, :thumbnail_url, :preview_url, :visible
|
9
|
+
|
10
|
+
|
11
|
+
def self.resource_path
|
12
|
+
'/files'
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
class Item < APIResource
|
4
|
+
|
5
|
+
|
6
|
+
api_attributes :id, :external_id, :variant_id, :quantity, :price, :retail_price, :name, :sku
|
7
|
+
has_many :files
|
8
|
+
has_many :options, class: 'PrintfulAPI::ItemOption'
|
9
|
+
belongs_to :product, class: 'PrintfulAPI::ProductVariant'
|
10
|
+
# belongs_to :variant
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
class Order < APIResource
|
4
|
+
include PrintfulAPI::APIOperations::Create
|
5
|
+
include PrintfulAPI::APIOperations::Delete
|
6
|
+
include PrintfulAPI::APIOperations::Get
|
7
|
+
include PrintfulAPI::APIOperations::List
|
8
|
+
include PrintfulAPI::APIOperations::Update
|
9
|
+
include PrintfulAPI::APIOperations::Save
|
10
|
+
|
11
|
+
api_attributes :id, :external_id, :status, :created, :updated, :costs, :shipping, :currency
|
12
|
+
belongs_to :recipient, class: 'PrintfulAPI::Address'
|
13
|
+
has_many :items
|
14
|
+
belongs_to :costs, class: 'PrintfulAPI::Cost'
|
15
|
+
belongs_to :retail_costs, class: 'PrintfulAPI::Cost'
|
16
|
+
belongs_to :gift, class: 'PrintfulAPI::GiftData'
|
17
|
+
belongs_to :packing_slip
|
18
|
+
has_many :shipments
|
19
|
+
|
20
|
+
|
21
|
+
def self.resource_path
|
22
|
+
'/orders'
|
23
|
+
end
|
24
|
+
|
25
|
+
# Confirm draft for fulfillment
|
26
|
+
# Approves for fulfillment an order that was saved as a draft. Store owner's credit card is charged when the order is submitted for fulfillment.
|
27
|
+
def confirm_for_fulfillment
|
28
|
+
|
29
|
+
result = PrintfulAPI.request( :POST, "/orders/#{self.id}/confirm", {} )
|
30
|
+
|
31
|
+
self.load_data( result )
|
32
|
+
|
33
|
+
return true
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
class PackingSlip < APIResource
|
4
|
+
include APIOperations::Create
|
5
|
+
|
6
|
+
api_attributes :email, :phone, :message
|
7
|
+
|
8
|
+
def self.get( opts={} )
|
9
|
+
|
10
|
+
store = Store.get()
|
11
|
+
|
12
|
+
store.packing_slip
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.resource_path
|
17
|
+
'/store/packing-slip'
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
class Product < APIResource
|
4
|
+
include PrintfulAPI::APIOperations::List
|
5
|
+
include PrintfulAPI::APIOperations::Get
|
6
|
+
|
7
|
+
api_attributes :id, :type, :brand, :model, :image, :variant_count, :dimensions
|
8
|
+
|
9
|
+
# has_many :allowed_files, class: 'PrintfulAPI::FileType'
|
10
|
+
has_many :files, class: 'PrintfulAPI::FileType'
|
11
|
+
# has_many :allowed_options, class: 'PrintfulAPI::OptionType'
|
12
|
+
has_many :options, class: 'PrintfulAPI::OptionType'
|
13
|
+
|
14
|
+
def variants
|
15
|
+
@variants ||= PrintfulAPI::Variant.list( product_id: self.id )
|
16
|
+
@variants
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.resource_path
|
20
|
+
'/products'
|
21
|
+
end
|
22
|
+
|
23
|
+
def load_data( data )
|
24
|
+
|
25
|
+
if data['product'].present?
|
26
|
+
|
27
|
+
super(data['product'])
|
28
|
+
|
29
|
+
@variants = data['variants'].collect do |variant_data|
|
30
|
+
variant = PrintfulAPI::Variant.new.load_data( variant_data )
|
31
|
+
variant.product = self
|
32
|
+
variant
|
33
|
+
end
|
34
|
+
|
35
|
+
else
|
36
|
+
|
37
|
+
super( data )
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
class ShippingRate < APIResource
|
4
|
+
|
5
|
+
api_attributes :id, :name, :rate, :currency
|
6
|
+
|
7
|
+
# PrintfulAPI::ShippingRate.list( { address1: '12372 Carmel Country Rd', city: 'San Diego', country_code: 'US', state_code: 'CA', zip: 92130}, [{quantity: 2, variant_id: PrintfulAPI::Product.get(1).variants.first.id}], 'USD' )
|
8
|
+
def self.list( recipient = {}, items = [], currency = 'USD', opts = {} )
|
9
|
+
|
10
|
+
request_data = {
|
11
|
+
recipient: recipient,
|
12
|
+
items: items,
|
13
|
+
currency: currency
|
14
|
+
}
|
15
|
+
|
16
|
+
results = PrintfulAPI.request( :POST, "/shipping/rates", data: request_data, params: opts )
|
17
|
+
|
18
|
+
results.collect do |data|
|
19
|
+
model = self.new
|
20
|
+
model.load_data( data )
|
21
|
+
|
22
|
+
model
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
class Store < APIResource
|
4
|
+
|
5
|
+
api_attributes :id, :name, :website, :created
|
6
|
+
belongs_to :packing_slip
|
7
|
+
belongs_to :return_address, class: 'PrintfulAPI::Address'
|
8
|
+
belongs_to :billing_address, class: 'PrintfulAPI::Address'
|
9
|
+
belongs_to :payment_card, class: 'PrintfulAPI::CardInfo'
|
10
|
+
|
11
|
+
|
12
|
+
def self.get( opts={} )
|
13
|
+
|
14
|
+
data = PrintfulAPI.request( :GET, self.resource_path )
|
15
|
+
|
16
|
+
model = self.new
|
17
|
+
model.load_data( data )
|
18
|
+
|
19
|
+
model
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.resource_path
|
24
|
+
'/store'
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
class TaxRate < APIResource
|
4
|
+
|
5
|
+
api_attributes :required, :rate, :shipping_taxable
|
6
|
+
|
7
|
+
# PrintfulAPI::TaxRate.get( country_code: 'US', state_code: 'CA', city: 'San Diego', zip: 92130 )
|
8
|
+
def self.get( recipient = {}, opts = {} )
|
9
|
+
|
10
|
+
data = PrintfulAPI.request( :POST, "/tax/rates", data: { recipient: recipient }, params: opts )
|
11
|
+
|
12
|
+
model = self.new
|
13
|
+
model.load_data( data )
|
14
|
+
|
15
|
+
model
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
class Variant < APIResource
|
4
|
+
include PrintfulAPI::APIOperations::Get
|
5
|
+
|
6
|
+
api_attributes :id, :product_id, :name, :size, :color, :color_code, :image, :price, :in_stock
|
7
|
+
|
8
|
+
belongs_to :product
|
9
|
+
|
10
|
+
def self.resource_path
|
11
|
+
'/products/variant'
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module PrintfulAPI
|
2
|
+
|
3
|
+
class Webhook < APIResource
|
4
|
+
include PrintfulAPI::APIOperations::Create
|
5
|
+
|
6
|
+
api_attributes :url, :types, :params
|
7
|
+
|
8
|
+
def self.get( opts={} )
|
9
|
+
|
10
|
+
data = PrintfulAPI.request( :GET, self.resource_path )
|
11
|
+
|
12
|
+
model = self.new
|
13
|
+
model.load_data( data )
|
14
|
+
|
15
|
+
model
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.delete( opts={} )
|
20
|
+
|
21
|
+
PrintfulAPI.request( :DELETE, self.resource_path )
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def delete
|
26
|
+
self.class.delete()
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.resource_path
|
30
|
+
'/webhooks'
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
# This class helps to use the Printful API
|
4
|
+
#
|
5
|
+
# version 1.0
|
6
|
+
# copyright 2014 Idea Bits LLC
|
7
|
+
#
|
8
|
+
##
|
9
|
+
|
10
|
+
require 'net/http'
|
11
|
+
require 'json'
|
12
|
+
require 'uri'
|
13
|
+
|
14
|
+
module PrintfulClientModule
|
15
|
+
|
16
|
+
API_URL = 'https://api.theprintful.com/'
|
17
|
+
USER_AGENT = 'Printful API Ruby Library 1.0'
|
18
|
+
|
19
|
+
@api_key
|
20
|
+
@last_response_raw
|
21
|
+
@last_response
|
22
|
+
|
23
|
+
|
24
|
+
# Initialize API library
|
25
|
+
# key - Printful Store API key
|
26
|
+
def initialize(key)
|
27
|
+
@api_key = key
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# Returns total available item count from the last request if it supports paging (e.g order list) or nil otherwise
|
32
|
+
def item_count
|
33
|
+
return last_response && last_response.key?('paging') ? last_response['paging']['total'] : nil
|
34
|
+
end
|
35
|
+
|
36
|
+
# Perform a GET request to the API
|
37
|
+
# path - Request path (e.g. 'orders' or 'orders/123')
|
38
|
+
# params - Additional GET parameters as a hash
|
39
|
+
def get(path, params=nil)
|
40
|
+
request('GET', path, params)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
# Perform a DELETE request to the API
|
45
|
+
# path - Request path (e.g. 'orders' or 'orders/123')
|
46
|
+
# params - Additional GET parameters as a hash
|
47
|
+
def delete(path, params=nil)
|
48
|
+
request('DELETE', path, params)
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# Perform a POST request to the API
|
53
|
+
# path - Request path (e.g. 'orders' or 'orders/123')
|
54
|
+
# data - Request body data as a hash
|
55
|
+
# params - Additional GET parameters as a hash
|
56
|
+
def post(path, data=nil, params=nil)
|
57
|
+
request('POST', path, params, data)
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Perform a PUT request to the API
|
62
|
+
# path - Request path (e.g. 'orders' or 'orders/123')
|
63
|
+
# data - Request body data as a hash
|
64
|
+
# params - Additional GET parameters as a hash
|
65
|
+
def put(path, data=nil, params=nil)
|
66
|
+
request('PUT', path, params, data)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Internal generic request wrapper
|
70
|
+
def request (method, path, params=nil, data=nil)
|
71
|
+
|
72
|
+
@last_response_raw = nil
|
73
|
+
@last_response = nil
|
74
|
+
|
75
|
+
uri = URI.join(API_URL, path)
|
76
|
+
if params
|
77
|
+
query = URI.encode_www_form(params)
|
78
|
+
uri.query = query
|
79
|
+
end
|
80
|
+
|
81
|
+
body = data ? JSON.generate(data) : nil
|
82
|
+
|
83
|
+
headers = {
|
84
|
+
'User-Agent' => USER_AGENT
|
85
|
+
}
|
86
|
+
begin
|
87
|
+
http = Net::HTTP.start(
|
88
|
+
uri.host,
|
89
|
+
uri.port,
|
90
|
+
:use_ssl => uri.scheme=='https',
|
91
|
+
:open_timeout => 10,
|
92
|
+
:read_timeout => 20
|
93
|
+
) do |http|
|
94
|
+
|
95
|
+
request = Net::HTTPGenericRequest.new(method,(body ? true : false), true, uri.request_uri ,headers)
|
96
|
+
request.basic_auth @api_key, ''
|
97
|
+
response = http.request(request, body)
|
98
|
+
|
99
|
+
@last_response_raw = response.body
|
100
|
+
|
101
|
+
begin
|
102
|
+
result = JSON.parse(response.body)
|
103
|
+
@last_response = result
|
104
|
+
rescue JSON::ParserError
|
105
|
+
raise PrintfulException, "API response was not valid JSON"
|
106
|
+
end
|
107
|
+
|
108
|
+
if !result.key?('code') || !result.key?('result')
|
109
|
+
raise PrintfulException, "Invalid API response"
|
110
|
+
end
|
111
|
+
|
112
|
+
status = result['code']
|
113
|
+
if status<200 || status >=300
|
114
|
+
raise PrintfulApiException.new(status), result['result']
|
115
|
+
end
|
116
|
+
|
117
|
+
result['result']
|
118
|
+
end
|
119
|
+
rescue PrintfulException
|
120
|
+
raise
|
121
|
+
rescue Exception => e
|
122
|
+
raise PrintfulException, 'API request failed: ' + e.message
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
private :request
|
127
|
+
attr_accessor :last_response, :last_response_raw
|
128
|
+
end
|
129
|
+
|
130
|
+
class PrintfulClient
|
131
|
+
include PrintfulClientModule
|
132
|
+
end
|
133
|
+
|
134
|
+
# Generic Printful exception
|
135
|
+
class PrintfulException < RuntimeError
|
136
|
+
end
|
137
|
+
|
138
|
+
# Printful exception returned from the API
|
139
|
+
class PrintfulApiException < PrintfulException
|
140
|
+
def initialize(code)
|
141
|
+
@code = code
|
142
|
+
end
|
143
|
+
attr_accessor :code
|
144
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
2
|
+
|
3
|
+
require 'printful_api/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'printful_api'
|
7
|
+
s.version = PrintfulAPI::VERSION
|
8
|
+
s.date = '2017-01-25'
|
9
|
+
s.summary = "Ruby bindings for the Printful API"
|
10
|
+
s.description = "Printful is the easiest way to sell, print and ship custom posters, shirts, mugs, pillows, leggings, totes ..."
|
11
|
+
s.authors = ["Michael Ferguson"]
|
12
|
+
s.email = 'meister@spacekace.com'
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.require_paths = ['lib']
|
15
|
+
s.homepage = 'https://github.com/Groundswell/printful-ruby'
|
16
|
+
s.license = 'MIT'
|
17
|
+
s.required_ruby_version = '>= 1.9.3'
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: printful_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Ferguson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-01-25 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Printful is the easiest way to sell, print and ship custom posters, shirts,
|
14
|
+
mugs, pillows, leggings, totes ...
|
15
|
+
email: meister@spacekace.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".gitignore"
|
21
|
+
- Gemfile
|
22
|
+
- LICENSE
|
23
|
+
- README.md
|
24
|
+
- VERSION
|
25
|
+
- lib/printful_api.rb
|
26
|
+
- lib/printful_api/address.rb
|
27
|
+
- lib/printful_api/api_operations/create.rb
|
28
|
+
- lib/printful_api/api_operations/delete.rb
|
29
|
+
- lib/printful_api/api_operations/get.rb
|
30
|
+
- lib/printful_api/api_operations/list.rb
|
31
|
+
- lib/printful_api/api_operations/save.rb
|
32
|
+
- lib/printful_api/api_operations/update.rb
|
33
|
+
- lib/printful_api/api_resource.rb
|
34
|
+
- lib/printful_api/card_info.rb
|
35
|
+
- lib/printful_api/cost.rb
|
36
|
+
- lib/printful_api/country.rb
|
37
|
+
- lib/printful_api/file.rb
|
38
|
+
- lib/printful_api/file_type.rb
|
39
|
+
- lib/printful_api/gift_data.rb
|
40
|
+
- lib/printful_api/item.rb
|
41
|
+
- lib/printful_api/item_option.rb
|
42
|
+
- lib/printful_api/option_type.rb
|
43
|
+
- lib/printful_api/order.rb
|
44
|
+
- lib/printful_api/packing_slip.rb
|
45
|
+
- lib/printful_api/product.rb
|
46
|
+
- lib/printful_api/product_variant.rb
|
47
|
+
- lib/printful_api/shipment.rb
|
48
|
+
- lib/printful_api/shipping_rate.rb
|
49
|
+
- lib/printful_api/state.rb
|
50
|
+
- lib/printful_api/store.rb
|
51
|
+
- lib/printful_api/tax_rate.rb
|
52
|
+
- lib/printful_api/variant.rb
|
53
|
+
- lib/printful_api/version.rb
|
54
|
+
- lib/printful_api/webhooks.rb
|
55
|
+
- lib/printful_client.rb
|
56
|
+
- printful_api.gemspec
|
57
|
+
homepage: https://github.com/Groundswell/printful-ruby
|
58
|
+
licenses:
|
59
|
+
- MIT
|
60
|
+
metadata: {}
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.9.3
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 2.5.2
|
78
|
+
signing_key:
|
79
|
+
specification_version: 4
|
80
|
+
summary: Ruby bindings for the Printful API
|
81
|
+
test_files: []
|