magento 0.26.1 → 0.29.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/Gemfile +5 -3
- data/README.md +636 -226
- data/lib/magento/cart.rb +104 -0
- data/lib/magento/order.rb +39 -2
- data/lib/magento/params/create_image.rb +43 -0
- data/lib/magento/product.rb +88 -0
- data/lib/magento/query.rb +11 -9
- data/lib/magento/request.rb +6 -1
- data/lib/magento/version.rb +1 -1
- data/lib/magento.rb +1 -0
- data/spec/magento/core/model_mapper_spec.rb +74 -0
- data/spec/magento/core/model_spec.rb +71 -0
- data/spec/magento/core/query_spec.rb +207 -0
- data/spec/magento/core/record_collection_spec.rb +116 -0
- data/spec/magento/core/request_spec.rb +141 -0
- data/spec/magento/order_spec.rb +28 -29
- data/spec/{product_spec.rb → magento/product_spec.rb} +21 -0
- data/spec/spec_helper.rb +17 -3
- data/spec/vcr_cassettes/order/send_email.yml +65 -0
- data/spec/vcr_cassettes/product/find.yml +72 -0
- metadata +11 -3
data/lib/magento/cart.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Magento
|
4
|
+
class Cart < Model
|
5
|
+
self.endpoint = 'carts'
|
6
|
+
self.primary_key = :id
|
7
|
+
|
8
|
+
#
|
9
|
+
# Add a coupon by code to the current cart.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# cart = Magento::Cart.find(1)
|
14
|
+
# cart.add_coupon('COAU4HXE0I')
|
15
|
+
#
|
16
|
+
# @return Boolean: true on success, false otherwise
|
17
|
+
def add_coupon(coupon)
|
18
|
+
self.class.add_coupon(id, coupon)
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Delete cart's coupon
|
23
|
+
#
|
24
|
+
# Example:
|
25
|
+
#
|
26
|
+
# cart = Magento::Cart.find(1)
|
27
|
+
# cart.delete_coupon()
|
28
|
+
#
|
29
|
+
# @return Boolean: true on success, raise exception otherwise
|
30
|
+
def delete_coupon
|
31
|
+
self.class.delete_coupon(id)
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Place order for cart
|
36
|
+
#
|
37
|
+
# Example:
|
38
|
+
#
|
39
|
+
# cart = Magento::Cart.find('12345')
|
40
|
+
#
|
41
|
+
# # or use "build" to not request information from the magento API
|
42
|
+
# cart = Magento::GuestCart.build({ 'cart_id' => '12345' })
|
43
|
+
#
|
44
|
+
# cart.order(
|
45
|
+
# email: 'customer@gmail.com',
|
46
|
+
# payment: { method: 'cashondelivery' }
|
47
|
+
# )
|
48
|
+
#
|
49
|
+
# @return String: return the order id
|
50
|
+
def order(email:, payment:)
|
51
|
+
attributes = { cartId: id, paymentMethod: payment, email: email }
|
52
|
+
self.class.order(attributes)
|
53
|
+
end
|
54
|
+
|
55
|
+
class << self
|
56
|
+
#
|
57
|
+
# Add a coupon by code to a specified cart.
|
58
|
+
#
|
59
|
+
# Example:
|
60
|
+
#
|
61
|
+
# Magento::Cart.add_coupon(
|
62
|
+
# 1,
|
63
|
+
# 'COAU4HXE0I'
|
64
|
+
# )
|
65
|
+
#
|
66
|
+
# @return Boolean: true on success, false otherwise
|
67
|
+
def add_coupon(id, coupon)
|
68
|
+
url = "#{api_resource}/#{id}/coupons/#{coupon}"
|
69
|
+
request.put(url, nil).parse
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Delete a coupon from a specified cart.
|
74
|
+
#
|
75
|
+
# Example:
|
76
|
+
#
|
77
|
+
# Magento::Cart.delete_coupon(1)
|
78
|
+
#
|
79
|
+
# @return Boolean: true on success, raise exception otherwise
|
80
|
+
def delete_coupon(id)
|
81
|
+
url = "#{api_resource}/#{id}/coupons"
|
82
|
+
request.delete(url).parse
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Place order for cart
|
87
|
+
#
|
88
|
+
# Example:
|
89
|
+
#
|
90
|
+
# Magento::Cart.order(
|
91
|
+
# cartId: '12345',
|
92
|
+
# paymentMethod: { method: 'cashondelivery' },
|
93
|
+
# email: email
|
94
|
+
# )
|
95
|
+
#
|
96
|
+
# @return String: return the order id
|
97
|
+
def order(attributes)
|
98
|
+
attributes.transform_keys(&:to_sym)
|
99
|
+
url = "#{api_resource}/#{attributes[:cartId]}/order"
|
100
|
+
request.put(url, attributes).parse
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/magento/order.rb
CHANGED
@@ -34,7 +34,6 @@ module Magento
|
|
34
34
|
self.class.invoice(id, params)
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
37
|
#
|
39
38
|
# Create offline refund for order
|
40
39
|
#
|
@@ -65,6 +64,22 @@ module Magento
|
|
65
64
|
self.class.send_email(id)
|
66
65
|
end
|
67
66
|
|
67
|
+
#
|
68
|
+
# Creates a comment on the given Order
|
69
|
+
#
|
70
|
+
# order = Magento::Order.find(order_id)
|
71
|
+
#
|
72
|
+
# order.add_comment(
|
73
|
+
# 'comment',
|
74
|
+
# is_customer_notified: 0,
|
75
|
+
# is_visible_on_front: 1
|
76
|
+
# )
|
77
|
+
#
|
78
|
+
# Return true on success
|
79
|
+
def add_comment(comment, comment_params = nil)
|
80
|
+
self.class.add_comment(id, comment, comment_params)
|
81
|
+
end
|
82
|
+
|
68
83
|
class << self
|
69
84
|
def update(entity_id, attributes)
|
70
85
|
attributes[:entity_id] = entity_id
|
@@ -104,7 +119,6 @@ module Magento
|
|
104
119
|
request.post("order/#{order_id}/invoice", invoice_params).parse
|
105
120
|
end
|
106
121
|
|
107
|
-
|
108
122
|
#
|
109
123
|
# Create offline refund for order
|
110
124
|
#
|
@@ -180,6 +194,29 @@ module Magento
|
|
180
194
|
def send_email(order_id)
|
181
195
|
request.post("orders/#{order_id}/emails").parse
|
182
196
|
end
|
197
|
+
|
198
|
+
#
|
199
|
+
# Creates a comment on the given Order
|
200
|
+
#
|
201
|
+
# Magento::Order.add_comment(
|
202
|
+
# order_id,
|
203
|
+
# 'comment',
|
204
|
+
# is_customer_notified: 0,
|
205
|
+
# is_visible_on_front: 1
|
206
|
+
# )
|
207
|
+
#
|
208
|
+
# to complete [documentation](https://magento.redoc.ly/2.4.2-admin/tag/ordersidcomments#operation/salesOrderManagementV1AddCommentPost)
|
209
|
+
#
|
210
|
+
# @return {Boolean}: return true on success
|
211
|
+
def add_comment(order_id, comment, comment_params = nil)
|
212
|
+
request.post(
|
213
|
+
"orders/#{order_id}/comments",
|
214
|
+
statusHistory: {
|
215
|
+
comment: comment,
|
216
|
+
**comment_params
|
217
|
+
}
|
218
|
+
).parse
|
219
|
+
end
|
183
220
|
end
|
184
221
|
end
|
185
222
|
end
|
@@ -5,6 +5,35 @@ require 'mini_magick'
|
|
5
5
|
|
6
6
|
module Magento
|
7
7
|
module Params
|
8
|
+
|
9
|
+
# Helper class to create product image params.
|
10
|
+
# before generating the hash, the following image treatments are performed:
|
11
|
+
# - resize image
|
12
|
+
# - remove alpha
|
13
|
+
# - leaves square
|
14
|
+
# - convert image to jpg
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
#
|
18
|
+
# params = Magento::Params::CreateImage.new(
|
19
|
+
# title: 'Image title',
|
20
|
+
# path: '/path/to/image.jpg', # or url
|
21
|
+
# position: 1,
|
22
|
+
# size: 'small', # options: 'large'(defaut), 'medium' and 'small',
|
23
|
+
# disabled: true, # default is false,
|
24
|
+
# main: true, # default is false,
|
25
|
+
# ).to_h
|
26
|
+
#
|
27
|
+
# Magento::Product.add_media('sku', params)
|
28
|
+
#
|
29
|
+
# The resize defaut confiruration is:
|
30
|
+
#
|
31
|
+
# Magento.configure do |config|
|
32
|
+
# config.product_image.small_size = '200x200>'
|
33
|
+
# config.product_image.medium_size = '400x400>'
|
34
|
+
# config.product_image.large_size = '800x800>'
|
35
|
+
# end
|
36
|
+
#
|
8
37
|
class CreateImage < Dry::Struct
|
9
38
|
VARIANTS = {
|
10
39
|
'large' => :image,
|
@@ -34,6 +63,20 @@ module Magento
|
|
34
63
|
}
|
35
64
|
end
|
36
65
|
|
66
|
+
# Generates a list containing an Magento::Params::CreateImage
|
67
|
+
# instance for each size of the same image.
|
68
|
+
#
|
69
|
+
# Example:
|
70
|
+
#
|
71
|
+
# params = Magento::Params::CreateImage.new(
|
72
|
+
# title: 'Image title',
|
73
|
+
# path: '/path/to/image.jpg', # or url
|
74
|
+
# position: 1,
|
75
|
+
# ).variants
|
76
|
+
#
|
77
|
+
# params.map(&:size)
|
78
|
+
# => ['large', 'medium', 'small']
|
79
|
+
#
|
37
80
|
def variants
|
38
81
|
VARIANTS.keys.map do |size|
|
39
82
|
CreateImage.new(attributes.merge(size: size, disabled: size != 'large'))
|
data/lib/magento/product.rb
CHANGED
@@ -38,6 +38,34 @@ module Magento
|
|
38
38
|
super || @custom_attributes&.any? { |a| a.attribute_code == attribute_code.to_s }
|
39
39
|
end
|
40
40
|
|
41
|
+
# Create new gallery entry
|
42
|
+
#
|
43
|
+
# Example:
|
44
|
+
#
|
45
|
+
# product = Magento::Product.find('sku')
|
46
|
+
#
|
47
|
+
# product.add_media(
|
48
|
+
# media_type: 'image',
|
49
|
+
# label: 'Image label',
|
50
|
+
# position: 1,
|
51
|
+
# content: {
|
52
|
+
# base64_encoded_data: 'image-string-base64',
|
53
|
+
# type: 'image/jpg',
|
54
|
+
# name: 'filename.jpg'
|
55
|
+
# },
|
56
|
+
# types: ['image']
|
57
|
+
# )
|
58
|
+
#
|
59
|
+
# Or you can use the Magento::Params::CreateImage helper class
|
60
|
+
#
|
61
|
+
# params = Magento::Params::CreateImage.new(
|
62
|
+
# title: 'Image title',
|
63
|
+
# path: '/path/to/image.jpg', # or url
|
64
|
+
# position: 1,
|
65
|
+
# ).to_h
|
66
|
+
#
|
67
|
+
# product.add_media(params)
|
68
|
+
#
|
41
69
|
def add_media(attributes)
|
42
70
|
self.class.add_media(sku, attributes)
|
43
71
|
end
|
@@ -88,9 +116,57 @@ module Magento
|
|
88
116
|
self.class.update_stock(sku, id, attributes)
|
89
117
|
end
|
90
118
|
|
119
|
+
# Assign a product link to another product
|
120
|
+
#
|
121
|
+
# product = Magento::Product.find('sku')
|
122
|
+
#
|
123
|
+
# product.create_links([
|
124
|
+
# {
|
125
|
+
# link_type: 'upsell',
|
126
|
+
# linked_product_sku: 'linked_product_sku',
|
127
|
+
# linked_product_type: 'simple',
|
128
|
+
# position: position,
|
129
|
+
# sku: 'product-sku'
|
130
|
+
# }
|
131
|
+
# ])
|
132
|
+
#
|
133
|
+
def create_links(product_links)
|
134
|
+
self.class.create_links(sku, product_links)
|
135
|
+
end
|
136
|
+
|
137
|
+
def remove_link(link_type:, linked_product_sku:)
|
138
|
+
self.class.remove_link(sku, link_type: link_type, linked_product_sku: linked_product_sku)
|
139
|
+
end
|
140
|
+
|
91
141
|
class << self
|
92
142
|
alias_method :find_by_sku, :find
|
93
143
|
|
144
|
+
# Create new gallery entry
|
145
|
+
#
|
146
|
+
# Example:
|
147
|
+
#
|
148
|
+
# Magento::Product.add_media('sku', {
|
149
|
+
# media_type: 'image',
|
150
|
+
# label: 'Image title',
|
151
|
+
# position: 1,
|
152
|
+
# content: {
|
153
|
+
# base64_encoded_data: 'image-string-base64',
|
154
|
+
# type: 'image/jpg',
|
155
|
+
# name: 'filename.jpg'
|
156
|
+
# },
|
157
|
+
# types: ['image']
|
158
|
+
# })
|
159
|
+
#
|
160
|
+
# Or you can use the Magento::Params::CreateImage helper class
|
161
|
+
#
|
162
|
+
# params = Magento::Params::CreateImage.new(
|
163
|
+
# title: 'Image title',
|
164
|
+
# path: '/path/to/image.jpg', # or url
|
165
|
+
# position: 1,
|
166
|
+
# ).to_h
|
167
|
+
#
|
168
|
+
# Magento::Product.add_media('sku', params)
|
169
|
+
#
|
94
170
|
def add_media(sku, attributes)
|
95
171
|
request.post("products/#{sku}/media", { entry: attributes }).parse
|
96
172
|
end
|
@@ -134,6 +210,18 @@ module Magento
|
|
134
210
|
request.put("products/#{sku}/stockItems/#{id}", stockItem: attributes).parse
|
135
211
|
end
|
136
212
|
|
213
|
+
# Assign a product link to another product
|
214
|
+
#
|
215
|
+
# Product.create_links('product-sku', [
|
216
|
+
# {
|
217
|
+
# link_type: 'upsell',
|
218
|
+
# linked_product_sku: 'linked_product_sku',
|
219
|
+
# linked_product_type: 'simple',
|
220
|
+
# position: position,
|
221
|
+
# sku: 'product-sku'
|
222
|
+
# }
|
223
|
+
# ])
|
224
|
+
#
|
137
225
|
def create_links(sku, product_links)
|
138
226
|
request.post("products/#{sku}/links", { items: product_links })
|
139
227
|
end
|
data/lib/magento/query.rb
CHANGED
@@ -70,15 +70,17 @@ module Magento
|
|
70
70
|
self
|
71
71
|
end
|
72
72
|
|
73
|
-
def order(attributes)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
73
|
+
def order(*attributes)
|
74
|
+
self.sort_orders = []
|
75
|
+
attributes.each do |sort_order|
|
76
|
+
if sort_order.is_a?(String) || sort_order.is_a?(Symbol)
|
77
|
+
sort_orders << { field: verify_id(sort_order), direction: :asc }
|
78
|
+
elsif sort_order.is_a?(Hash)
|
79
|
+
sort_order.each do |field, direction|
|
80
|
+
raise "Invalid sort order direction '#{direction}'" unless %w[asc desc].include?(direction.to_s)
|
81
|
+
|
82
|
+
sort_orders << { field: verify_id(field), direction: direction }
|
83
|
+
end
|
82
84
|
end
|
83
85
|
end
|
84
86
|
self
|
data/lib/magento/request.rb
CHANGED
@@ -54,7 +54,12 @@ module Magento
|
|
54
54
|
begin
|
55
55
|
msg = resp.parse['message']
|
56
56
|
errors = resp.parse['errors'] || resp.parse['parameters']
|
57
|
-
|
57
|
+
case errors
|
58
|
+
when Hash
|
59
|
+
errors.each { |k, v| msg.sub! "%#{k}", v }
|
60
|
+
when Array
|
61
|
+
errors.each_with_index { |v, i| msg.sub! "%#{i + 1}", v.to_s }
|
62
|
+
end
|
58
63
|
rescue StandardError
|
59
64
|
msg = 'Failed access to the magento server'
|
60
65
|
errors = []
|
data/lib/magento/version.rb
CHANGED
data/lib/magento.rb
CHANGED
@@ -25,6 +25,7 @@ require_relative 'magento/guest_cart'
|
|
25
25
|
require_relative 'magento/sales_rule'
|
26
26
|
require_relative 'magento/inventory'
|
27
27
|
require_relative 'magento/import'
|
28
|
+
require_relative 'magento/cart'
|
28
29
|
|
29
30
|
require_relative 'magento/params/create_custom_attribute'
|
30
31
|
require_relative 'magento/params/create_image'
|
@@ -0,0 +1,74 @@
|
|
1
|
+
RSpec.describe Magento::ModelMapper do
|
2
|
+
describe '.to_hash' do
|
3
|
+
it 'serializes object to hash' do
|
4
|
+
class Magento::SameClass
|
5
|
+
attr_accessor :name, :description, :items
|
6
|
+
end
|
7
|
+
|
8
|
+
object = Magento::SameClass.new
|
9
|
+
object.name = 'Some name'
|
10
|
+
object.description = 'Some description'
|
11
|
+
object.items = [object.dup]
|
12
|
+
|
13
|
+
expect(Magento::ModelMapper.to_hash(object)).to eql({
|
14
|
+
'name' => 'Some name',
|
15
|
+
'description' => 'Some description',
|
16
|
+
'items' => [{ 'name' => 'Some name', 'description' => 'Some description' }]
|
17
|
+
})
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.map_hash' do
|
22
|
+
it 'returns magento object from hash' do
|
23
|
+
class Magento::SameClass; end
|
24
|
+
hash = { name: 'Some name', price: 10.99 }
|
25
|
+
|
26
|
+
object = Magento::ModelMapper.map_hash(Magento::SameClass, hash)
|
27
|
+
|
28
|
+
expect(object).to be_instance_of(Magento::SameClass)
|
29
|
+
expect(object.name).to eql hash[:name]
|
30
|
+
expect(object.price).to eql hash[:price]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.map_array' do
|
35
|
+
it 'returns magento object list from array of hash' do
|
36
|
+
class Magento::SameClass; end
|
37
|
+
array = [{ name: 'Some name', price: 10.99 }]
|
38
|
+
|
39
|
+
object = Magento::ModelMapper.map_array('same_class', array)
|
40
|
+
|
41
|
+
expect(object).to be_a(Array)
|
42
|
+
expect(object).to all be_instance_of(Magento::SameClass)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'include ModelParser' do
|
47
|
+
before do
|
48
|
+
class Magento::SameClass
|
49
|
+
include Magento::ModelParser
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
let(:hash) { { name: 'Same name' } }
|
54
|
+
|
55
|
+
describe '.build' do
|
56
|
+
it 'calls Magento::ModelMapper.map_hash' do
|
57
|
+
expect(Magento::ModelMapper).to receive(:map_hash)
|
58
|
+
.with(Magento::SameClass, hash)
|
59
|
+
|
60
|
+
Magento::SameClass.build(hash)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#to_h' do
|
65
|
+
it 'calls Magento::ModelMapper.to_hash' do
|
66
|
+
object = Magento::SameClass.build(hash)
|
67
|
+
|
68
|
+
expect(Magento::ModelMapper).to receive(:to_hash).with(object)
|
69
|
+
|
70
|
+
object.to_h
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|