jekyll-spree-client 0.1.8 → 0.1.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +73 -18
- data/lib/jekyll-spree-client.rb +14 -11
- data/lib/jekyll/spree_client.rb +50 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3313a5acca299870b21648a253999a7bda4fae1c50a8ada64ba08bf710ee677
|
4
|
+
data.tar.gz: 15ce97b96ab22eb484960cea96a98549bc6ba972ba82599442f67d5ed6c32925
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 061be8dc0a119fd8b106e08dd5edc7506aa2d297fd213012f1442744349bcb8d0e955c1887597154510368e9c866e59e597d484f33ede18cf74e76caeb28c27e
|
7
|
+
data.tar.gz: 2a6e0c0e080ba05a8d94d7b383d445fe7e7aa96b113f053ece6b9528d9e80ad1bfc886f41cad37e97c5bfbb533ab44d4e4099600ef7e6501cc3d4a6ea05d4db3
|
data/README.md
CHANGED
@@ -16,16 +16,6 @@ conversion unless you store prices as strings.
|
|
16
16
|
|
17
17
|
You can use Integer and Floats now!
|
18
18
|
|
19
|
-
### Update
|
20
|
-
|
21
|
-
The issue is that Spree expects to receive prices in the locale format
|
22
|
-
(ie, "200,00") but will return them on Ruby's `to_s` conversion
|
23
|
-
("200.0") so we need to reconvert them to our current format and juggle
|
24
|
-
between them.
|
25
|
-
|
26
|
-
We'll deal with `Integer` for now until we find [a better
|
27
|
-
solution](https://github.com/spree/spree/issues/10556).
|
28
|
-
|
29
19
|
## Installation
|
30
20
|
|
31
21
|
Add this line to your site's Gemfile:
|
@@ -77,8 +67,10 @@ Add the required fields in their frontmatter:
|
|
77
67
|
---
|
78
68
|
layout: post
|
79
69
|
title: A product
|
70
|
+
description: With a description
|
80
71
|
sku: A unique ID
|
81
72
|
price: 100.00
|
73
|
+
cost_price: 50.0
|
82
74
|
stock: 100
|
83
75
|
weight: 100
|
84
76
|
height: 100
|
@@ -90,18 +82,64 @@ depth: 100
|
|
90
82
|
The layout doesn't matter, but we recommend to use a layout for
|
91
83
|
products.
|
92
84
|
|
85
|
+
### Layouts
|
86
|
+
|
87
|
+
You'll need four layouts and at least a corresponding post, one for each
|
88
|
+
step of the buying process.
|
89
|
+
|
90
|
+
* `cart` the cart, shows the order details
|
91
|
+
* `shipment` shipping and billing addresses, shipping rates apply here
|
92
|
+
* `payment` select payment methods
|
93
|
+
* `confirmation` order confirmation page
|
94
|
+
|
95
|
+
They'll be available on Liquid under the `site.STEP` keys.
|
96
|
+
|
97
|
+
### Hooks
|
98
|
+
|
99
|
+
If you need to do some data manipulation before and after
|
100
|
+
synchronization is done, you can use hooks. In a `_plugins/spree.rb`
|
101
|
+
file:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
Jekyll::Hooks.register :spree, :pre_render do |spree|
|
105
|
+
spree.local_products.each do |product|
|
106
|
+
product.data['_description'] = product.data['description']
|
107
|
+
product.data['description'] = product.data['productore']&.data&.dig('title')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
Jekyll::Hooks.register :spree, :post_render do |spree|
|
112
|
+
spree.local_products.each do |product|
|
113
|
+
product.data['description'] = product.data.delete '_description'
|
114
|
+
|
115
|
+
product.data.delete 'description' unless product.data['description']
|
116
|
+
end
|
117
|
+
end
|
118
|
+
```
|
119
|
+
|
120
|
+
This plugin gets the description value from another document (they're
|
121
|
+
linked using
|
122
|
+
[jekyll-linked-posts](https://0xacab.org/sutty/jekyll/jekyll-linked-posts/),
|
123
|
+
it's a real example!), and then recovers it.
|
124
|
+
|
125
|
+
* `pre_render` runs just before starting synchronization
|
126
|
+
* `post_render` run after synchronization and before writing changes
|
127
|
+
|
93
128
|
### Building the site
|
94
129
|
|
95
130
|
During site build, the plugin will communicate with the Spree API and
|
96
|
-
create products when they don't exist or update their price,
|
97
|
-
stock and the other values.
|
131
|
+
create products when they don't exist or locally update their price,
|
132
|
+
current stock and the other values.
|
98
133
|
|
99
134
|
Some fields will appear on the frontmatter:
|
100
135
|
|
101
136
|
```yaml
|
102
137
|
variant_id: 1
|
103
138
|
in_stock: true
|
104
|
-
|
139
|
+
errors:
|
140
|
+
time: 2020-10-10 00:00:00 UTC
|
141
|
+
messages:
|
142
|
+
- Something went wrong
|
105
143
|
```
|
106
144
|
|
107
145
|
* `variant_id` is the ID in the Spree database.
|
@@ -109,11 +147,27 @@ sync_error: 2020-10-10 00:00:00 UTC
|
|
109
147
|
* `in_stock` is true or false according to availability (Spree decides
|
110
148
|
this).
|
111
149
|
|
112
|
-
* `
|
113
|
-
here.
|
150
|
+
* `errors` if the synchronization fails there will be a timestamp and
|
151
|
+
some messages here.
|
114
152
|
|
115
153
|
## Notes
|
116
154
|
|
155
|
+
* Synchronization follows this rules.
|
156
|
+
|
157
|
+
If the product doesn't exist on Spree, it's created.
|
158
|
+
|
159
|
+
If it does, the Jekyll document is updated with price, weight,
|
160
|
+
dimensions and stock.
|
161
|
+
|
162
|
+
It means once the product is created on Spree, Spree manages this
|
163
|
+
variables.
|
164
|
+
|
165
|
+
But Product properties like description and metadata are updated from
|
166
|
+
Jekyll to Spree.
|
167
|
+
|
168
|
+
We want this to change in the near future but we need to think a way
|
169
|
+
to prevent conflicts.
|
170
|
+
|
117
171
|
* All products are created as "master variants" on Spree. There will be
|
118
172
|
no pictures, taxonomies or other values, only basic product
|
119
173
|
information.
|
@@ -126,11 +180,12 @@ sync_error: 2020-10-10 00:00:00 UTC
|
|
126
180
|
* Stock is added to the default stock location, meaning the first active
|
127
181
|
one. The API doesn't show or allows to query the actual default.
|
128
182
|
|
129
|
-
*
|
183
|
+
* `price` and `cost_price` are expressed in Spree's default currency.
|
130
184
|
|
131
185
|
* If you install the `jekyll-write-and-commit-changes` plugin it will
|
132
|
-
save the data back to disk when you build
|
133
|
-
environment variable
|
186
|
+
save the data back to disk when you build. Using the
|
187
|
+
`JEKYLL_ENV=production` environment variable will also commit changes
|
188
|
+
to git.
|
134
189
|
|
135
190
|
* Check the shipping category ID on Spree, since there's no API for it,
|
136
191
|
you need to provide it manually, default is `1`.
|
data/lib/jekyll-spree-client.rb
CHANGED
@@ -6,7 +6,20 @@ require_relative 'jekyll/spree_client'
|
|
6
6
|
# matter. The SKU needs to be unique, but this plugin doesn't ensure
|
7
7
|
# that. Duplicated SKUs will be silently ignored for now.
|
8
8
|
Jekyll::Hooks.register :site, :post_read do |site|
|
9
|
-
|
9
|
+
# Ordered articles
|
10
|
+
posts = site.site_payload['site']['posts']
|
11
|
+
|
12
|
+
# Make steps available to other articles
|
13
|
+
%w[cart shipment payment confirmation].each do |step|
|
14
|
+
site.config[step] = posts.find do |doc|
|
15
|
+
doc.data['layout'] == step
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if ENV['SPREE_API_KEY'].nil? || ENV['SPREE_API_KEY'].empty?
|
20
|
+
Jekyll.logger.warn "SPREE_API_KEY environment variable missing, skipping syncrhonization"
|
21
|
+
next
|
22
|
+
end
|
10
23
|
|
11
24
|
config = site.config['spree']&.transform_keys(&:to_sym) || {}
|
12
25
|
config.merge!(site: site, api_key: ENV['SPREE_API_KEY'], spree_url: ENV['SPREE_URL'])
|
@@ -18,14 +31,4 @@ Jekyll::Hooks.register :site, :post_read do |site|
|
|
18
31
|
if ENV['JEKYLL_ENV'] == 'production' && site.respond_to?(:repository)
|
19
32
|
site.repository.commit site.data.dig(site.config['locale'], 'spree', 'commit') || 'Spree synchronization'
|
20
33
|
end
|
21
|
-
|
22
|
-
# Ordered articles
|
23
|
-
posts = site.site_payload['site']['posts']
|
24
|
-
|
25
|
-
# Make steps available to other articles
|
26
|
-
%w[cart shipment payment confirmation].each do |step|
|
27
|
-
site.config[step] = posts.find do |doc|
|
28
|
-
doc.data['layout'] == step
|
29
|
-
end
|
30
|
-
end
|
31
34
|
end
|
data/lib/jekyll/spree_client.rb
CHANGED
@@ -33,7 +33,21 @@ module Jekyll
|
|
33
33
|
#
|
34
34
|
# @return [Array]
|
35
35
|
def variant_fields
|
36
|
-
@variant_fields ||= %w[price weight height width depth].freeze
|
36
|
+
@variant_fields ||= %w[price weight height width depth cost_price pay_what_you_can].freeze
|
37
|
+
end
|
38
|
+
|
39
|
+
# Fields that can change locally and we need to sync to Spree
|
40
|
+
#
|
41
|
+
# @return [Array]
|
42
|
+
def product_fields
|
43
|
+
@product_fields ||= %w[name description meta_description meta_keywords meta_title].freeze
|
44
|
+
end
|
45
|
+
|
46
|
+
# All fields, using during creation
|
47
|
+
#
|
48
|
+
# @return [Array]
|
49
|
+
def create_fields
|
50
|
+
@create_fields ||= product_fields + variant_fields
|
37
51
|
end
|
38
52
|
|
39
53
|
# Spree Client
|
@@ -56,6 +70,8 @@ module Jekyll
|
|
56
70
|
end
|
57
71
|
|
58
72
|
def sync!
|
73
|
+
Jekyll::Hooks.trigger :spree, :pre_render, self
|
74
|
+
|
59
75
|
# The API allows to query several SKUs at the same time, so we send
|
60
76
|
# groups of 10 products.
|
61
77
|
local_products.each_slice(10) do |products|
|
@@ -68,13 +84,18 @@ module Jekyll
|
|
68
84
|
products.each do |p|
|
69
85
|
mark_with_error p,
|
70
86
|
i18n.dig('spree', 'errors', 'api') || "Couldn't obtain variants, the store may be down or API key is incorrect"
|
71
|
-
local_save p.save
|
72
87
|
end
|
73
88
|
|
74
89
|
next
|
75
90
|
end
|
76
91
|
|
77
92
|
products.each do |product|
|
93
|
+
# Products have names, not titles, so we save them for later
|
94
|
+
product.data['_name'] = product.data['name'] if product.data.key? 'name'
|
95
|
+
product.data['name'] = product.data['title']
|
96
|
+
|
97
|
+
# Remove previous errors
|
98
|
+
product.data.delete 'errors'
|
78
99
|
# Find the corresponding Spree variant in the response
|
79
100
|
variant = response['variants'].find do |v|
|
80
101
|
v[sku_field] == product.data[sku_field]
|
@@ -86,8 +107,16 @@ module Jekyll
|
|
86
107
|
else
|
87
108
|
create product
|
88
109
|
end
|
110
|
+
|
111
|
+
product.data['name'] = product.data.delete('_name') if product.data.key? '_name'
|
89
112
|
end
|
90
113
|
end
|
114
|
+
|
115
|
+
Jekyll::Hooks.trigger :spree, :post_render, self
|
116
|
+
|
117
|
+
local_products.each do |product|
|
118
|
+
local_save product
|
119
|
+
end
|
91
120
|
end
|
92
121
|
|
93
122
|
private
|
@@ -150,6 +179,22 @@ module Jekyll
|
|
150
179
|
# @param [Hash]
|
151
180
|
# @return [true,false]
|
152
181
|
def update(product, variant)
|
182
|
+
# Sync local changes to Spree
|
183
|
+
remote_product = product.data.slice(*product_fields).transform_keys(&:to_sym)
|
184
|
+
# Only when they haven't changed, so we don't waste time sending a
|
185
|
+
# request.
|
186
|
+
unless remote_product == variant.slice(*product_fields).transform_keys(&:to_sym)
|
187
|
+
# XXX: We don't have the product ID with the variant but we have
|
188
|
+
# the slug.
|
189
|
+
remote_product[:id] = variant['slug']
|
190
|
+
remote_product[:sku] = product.data[sku_field]
|
191
|
+
|
192
|
+
unless remote_products.update **remote_product
|
193
|
+
Jekyll.logger.error "Couldn't update #{product.data['title']}"
|
194
|
+
mark_with_error product, error_messages
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
153
198
|
# XXX: The API replies with stringified numbers so we convert them
|
154
199
|
# back to the type we're using locally.
|
155
200
|
variant.slice(*variant_fields).each do |k, v|
|
@@ -162,9 +207,8 @@ module Jekyll
|
|
162
207
|
|
163
208
|
product.data['in_stock'] = variant['in_stock']
|
164
209
|
product.data['variant_id'] = variant['id']
|
165
|
-
product.data.delete 'errors'
|
166
210
|
|
167
|
-
|
211
|
+
product
|
168
212
|
end
|
169
213
|
|
170
214
|
# If the product doesn't exist, create it.
|
@@ -172,23 +216,18 @@ module Jekyll
|
|
172
216
|
# @param [Jekyll::Document]
|
173
217
|
# @return [true,false]
|
174
218
|
def create(product)
|
175
|
-
new_product = product.data.slice(*
|
219
|
+
new_product = product.data.slice(*create_fields).transform_keys(&:to_sym)
|
176
220
|
new_product[:sku] = product.data[sku_field]
|
177
|
-
new_product[:name] = product.data['title']
|
178
221
|
|
179
222
|
unless remote_products.create **new_product
|
180
223
|
Jekyll.logger.error "Couldn't create #{product.data['title']}"
|
181
224
|
mark_with_error product, error_messages
|
182
|
-
local_save product
|
183
225
|
|
184
226
|
return false
|
185
227
|
end
|
186
228
|
|
187
229
|
product.data['variant_id'] = remote_products.response.dig('master', 'id')
|
188
230
|
|
189
|
-
# Save the variant ID
|
190
|
-
local_save product
|
191
|
-
|
192
231
|
# Add the initial stock
|
193
232
|
spree.stock_items(id: product.data['variant_id'], stock_location_id: stock_location['id'])
|
194
233
|
.stock_movements.create(quantity: product.data['stock'])
|
@@ -202,7 +241,7 @@ module Jekyll
|
|
202
241
|
errors.map do |error|
|
203
242
|
field + ' ' + error
|
204
243
|
end
|
205
|
-
end
|
244
|
+
end&.flatten
|
206
245
|
end
|
207
246
|
end
|
208
247
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll-spree-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- f
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: spree-api-client
|