magento 0.26.1 → 0.27.0

Sign up to get free protection for your applications and to get access to all the features.
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'))
@@ -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
- if attributes.is_a?(String)
75
- self.sort_orders = [{ field: verify_id(attributes), direction: :asc }]
76
- elsif attributes.is_a?(Hash)
77
- self.sort_orders = []
78
- attributes.each do |field, direction|
79
- raise "Invalid sort order direction '#{direction}'" unless %w[asc desc].include?(direction.to_s)
80
-
81
- sort_orders << { field: verify_id(field), direction: direction }
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
@@ -1,3 +1,3 @@
1
1
  module Magento
2
- VERSION = '0.26.1'
2
+ VERSION = '0.27.0'
3
3
  end
@@ -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
@@ -0,0 +1,71 @@
1
+ RSpec.describe Magento::Model do
2
+ describe 'public method' do
3
+ describe '.find' do
4
+ it 'is pending'
5
+ end
6
+
7
+ describe '.create' do
8
+ it 'is pending'
9
+ end
10
+
11
+ describe '.update' do
12
+ it 'is pending'
13
+ end
14
+
15
+ describe '.delete' do
16
+ it 'is pending'
17
+ end
18
+
19
+ describe '#save' do
20
+ it 'calls the update class method'
21
+ end
22
+
23
+ describe '#update' do
24
+ it 'calls the update class method'
25
+ end
26
+
27
+ describe '#delete' do
28
+ it 'calls the delete class method'
29
+ end
30
+
31
+ describe '.api_resource' do
32
+ it 'is pending'
33
+ end
34
+
35
+ describe '.entity_name' do
36
+ it 'is pending'
37
+ end
38
+
39
+ describe '.primary_key' do
40
+ it 'is pending'
41
+ end
42
+
43
+ describe 'delegated methods from query' do
44
+ it 'respond to .all'
45
+ it 'respond to .find_each'
46
+ it 'respond to .page'
47
+ it 'respond to .per'
48
+ it 'respond to .page_size'
49
+ it 'respond to .order'
50
+ it 'respond to .select'
51
+ it 'respond to .where'
52
+ it 'respond to .first'
53
+ it 'respond to .find_by'
54
+ it 'respond to .count'
55
+ end
56
+ end
57
+
58
+ describe 'protected method' do
59
+ describe '.entity_key' do
60
+ it 'is pending'
61
+ end
62
+
63
+ describe '.query' do
64
+ it 'is pending'
65
+ end
66
+
67
+ describe '.request' do
68
+ it 'is pending'
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,207 @@
1
+ class Magento::Faker < Magento::Model; end
2
+
3
+ RSpec.describe Magento::Query do
4
+ subject { Magento::Query.new(Magento::Faker) }
5
+
6
+ describe '#where' do
7
+ it 'add the filter to group of filters' do
8
+ subject.where(price_gt: 50)
9
+
10
+ expect(subject.send(:filter_groups)).to eql([
11
+ { filters: [{ field: 'price', conditionType: 'gt', value: 50 }] }
12
+ ])
13
+ end
14
+
15
+ context 'when the condition is not passed' do
16
+ it 'the "eq" condition is used as default' do
17
+ subject.where(price: 50)
18
+
19
+ expect(subject.send(:filter_groups)).to eql([
20
+ { filters: [{ field: :price, conditionType: 'eq', value: 50 }] }
21
+ ])
22
+ end
23
+ end
24
+
25
+ context 'when it is called more than once' do
26
+ it 'adds filter in diferent groups' do
27
+ subject.where(price_gt: 10).where(price_lt: 20)
28
+
29
+ expect(subject.send(:filter_groups)).to eql([
30
+ { filters: [{ field: 'price', conditionType: 'gt', value: 10 }] },
31
+ { filters: [{ field: 'price', conditionType: 'lt', value: 20 }] }
32
+ ])
33
+ end
34
+ end
35
+
36
+ context 'when it is called with more than one filter' do
37
+ it 'adds the filters in same group' do
38
+ subject.where(price_gt: 10, price_lt: 20)
39
+
40
+ expect(subject.send(:filter_groups)).to eql([
41
+ {
42
+ filters: [
43
+ { field: 'price', conditionType: 'gt', value: 10 },
44
+ { field: 'price', conditionType: 'lt', value: 20 }
45
+ ]
46
+ }
47
+ ])
48
+ end
49
+ end
50
+
51
+ context 'when the condition is "in" or "nin" and value is a Array' do
52
+ it 'converts the value to string' do
53
+ subject.where(status_in: [:pending, :new])
54
+ subject.where(entity_id_nin: [123, 321])
55
+
56
+ expect(subject.send(:filter_groups)).to eql([
57
+ { filters: [{ field: 'status', conditionType: 'in', value: 'pending,new' }] },
58
+ { filters: [{ field: 'entity_id', conditionType: 'nin', value: '123,321' }] }
59
+ ])
60
+ end
61
+ end
62
+ end
63
+
64
+ describe '#page' do
65
+ it do
66
+ subject.page(2)
67
+ expect(subject.send(:current_page)).to eql(2)
68
+ end
69
+ end
70
+
71
+ describe '#page_size' do
72
+ it do
73
+ subject.page_size(5)
74
+ expect(subject.instance_variable_get(:@page_size)).to eql(5)
75
+ end
76
+ end
77
+
78
+ describe '#select' do
79
+ it 'set fields inside items[]' do
80
+ subject.select(:id, :name)
81
+
82
+ expect(subject.send(:fields)).to eql('items[id,name],search_criteria,total_count')
83
+ end
84
+
85
+ it 'allow hash' do
86
+ subject.select(:id, nested_attribute: :name)
87
+
88
+ expect(subject.send(:fields)).to eql('items[id,nested_attribute[name]],search_criteria,total_count')
89
+ end
90
+
91
+ it 'allow hash with key and value as array' do
92
+ subject.select(:id, nested_attribute: [:id, :name])
93
+
94
+ expect(subject.send(:fields)).to eql('items[id,nested_attribute[id,name]],search_criteria,total_count')
95
+ end
96
+
97
+ it 'allow hash multiple level' do
98
+ subject.select(:id, nested_attribute: [:id, :name, stock: :quantity])
99
+
100
+ expect(subject.send(:fields)).to eql(
101
+ 'items[id,nested_attribute[id,name,stock[quantity]]],search_criteria,total_count'
102
+ )
103
+ end
104
+
105
+ context 'when model is Magento::Category' do
106
+ class Magento::Category < Magento::Model; end
107
+
108
+ subject { Magento::Query.new(Magento::Category) }
109
+
110
+ it 'set fields inseide children_data[]' do
111
+ subject.select(:id, :name)
112
+
113
+ expect(subject.send(:fields)).to eql('children_data[id,name]')
114
+ end
115
+ end
116
+ end
117
+
118
+ describe '#order' do
119
+ it 'set order in sort_orders' do
120
+ subject.order(name: :desc)
121
+
122
+ expect(subject.send(:sort_orders)).to eql(
123
+ [{ field: :name, direction: :desc }]
124
+ )
125
+
126
+ subject.order(created_at: :desc, name: :asc)
127
+
128
+ expect(subject.send(:sort_orders)).to eql(
129
+ [
130
+ { field: :created_at, direction: :desc },
131
+ { field: :name, direction: :asc }
132
+ ]
133
+ )
134
+ end
135
+
136
+ context 'when the direction is not passed' do
137
+ it 'the :asc direction is used as default' do
138
+ subject.order(:name)
139
+
140
+ expect(subject.send(:sort_orders)).to eql(
141
+ [{ field: :name, direction: :asc }]
142
+ )
143
+
144
+ subject.order(:created_at, :name)
145
+
146
+ expect(subject.send(:sort_orders)).to eql([
147
+ { field: :created_at, direction: :asc },
148
+ { field: :name, direction: :asc }
149
+ ])
150
+ end
151
+ end
152
+ end
153
+
154
+ describe '#all' do
155
+ it 'is pending'
156
+ end
157
+
158
+ describe '#first' do
159
+ it 'is pending'
160
+ end
161
+
162
+ describe '#find_by' do
163
+ it 'is pending'
164
+ end
165
+
166
+ describe '#count' do
167
+ it 'is pending'
168
+ end
169
+
170
+ describe '#find_each' do
171
+ it 'is pending'
172
+ end
173
+
174
+ describe 'private mathods' do
175
+ describe 'endpoint' do
176
+ it 'is pending'
177
+ end
178
+
179
+ describe 'verify_id' do
180
+ it 'is pending'
181
+ end
182
+
183
+ describe 'query_params' do
184
+ it 'is pending'
185
+ end
186
+
187
+ describe 'parse_filter' do
188
+ it 'is pending'
189
+ end
190
+
191
+ describe 'parse_value_filter' do
192
+ it 'is pending'
193
+ end
194
+
195
+ describe 'parse_field' do
196
+ it 'is pending'
197
+ end
198
+
199
+ describe 'encode' do
200
+ it 'is pending'
201
+ end
202
+
203
+ describe 'append_key' do
204
+ it 'is pending'
205
+ end
206
+ end
207
+ end