magento 0.24.0 → 0.28.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.
data/lib/magento.rb CHANGED
@@ -25,9 +25,15 @@ 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'
29
+
30
+ require_relative 'magento/params/create_custom_attribute'
31
+ require_relative 'magento/params/create_image'
32
+ require_relative 'magento/params/create_category'
33
+ require_relative 'magento/params/create_product'
34
+ require_relative 'magento/params/create_product_link'
28
35
 
29
36
  Dir[File.expand_path('magento/shared/*.rb', __dir__)].map { |f| require f }
30
- Dir[File.expand_path('magento/params/*.rb', __dir__)].map { |f| require f }
31
37
 
32
38
  module Magento
33
39
  class << self
@@ -0,0 +1,65 @@
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
+ class << self
35
+ #
36
+ # Add a coupon by code to a specified cart.
37
+ #
38
+ # Example:
39
+ #
40
+ # Magento::Cart.add_coupon(
41
+ # 1,
42
+ # 'COAU4HXE0I'
43
+ # )
44
+ #
45
+ # @return Boolean: true on success, false otherwise
46
+ def add_coupon(id, coupon)
47
+ url = "#{api_resource}/#{id}/coupons/#{coupon}"
48
+ request.put(url, nil).parse
49
+ end
50
+
51
+ #
52
+ # Delete a coupon from a specified cart.
53
+ #
54
+ # Example:
55
+ #
56
+ # Magento::Cart.delete_coupon(1)
57
+ #
58
+ # @return Boolean: true on success, raise exception otherwise
59
+ def delete_coupon(id)
60
+ url = "#{api_resource}/#{id}/coupons"
61
+ request.delete(url).parse
62
+ end
63
+ end
64
+ end
65
+ 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
  #
@@ -61,6 +60,26 @@ module Magento
61
60
  self.class.ship(id, params)
62
61
  end
63
62
 
63
+ def send_email
64
+ self.class.send_email(id)
65
+ end
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
+
64
83
  class << self
65
84
  def update(entity_id, attributes)
66
85
  attributes[:entity_id] = entity_id
@@ -100,7 +119,6 @@ module Magento
100
119
  request.post("order/#{order_id}/invoice", invoice_params).parse
101
120
  end
102
121
 
103
-
104
122
  #
105
123
  # Create offline refund for order
106
124
  #
@@ -172,6 +190,33 @@ module Magento
172
190
  def ship(order_id, shipment_params = nil)
173
191
  request.post("order/#{order_id}/ship", shipment_params).parse
174
192
  end
193
+
194
+ def send_email(order_id)
195
+ request.post("orders/#{order_id}/emails").parse
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
175
220
  end
176
221
  end
177
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'))
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Magento
4
+ module Params
5
+ class CreateProductLink < Dry::Struct
6
+ LinkType = Type::String.enum(
7
+ 'related',
8
+ 'upsell',
9
+ 'crosssell',
10
+ 'associated'
11
+ )
12
+
13
+ attribute :link_type, LinkType
14
+ attribute :linked_product_sku, Type::String
15
+ attribute :linked_product_type, Magento::Params::CreateProduct::ProductTypes
16
+ attribute :position, Type::Integer
17
+ attribute :sku, Type::String
18
+
19
+ def to_h
20
+ {
21
+ link_type: link_type,
22
+ linked_product_sku: linked_product_sku,
23
+ linked_product_type: linked_product_type,
24
+ position: position,
25
+ sku: sku
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -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
@@ -47,7 +75,6 @@ module Magento
47
75
  self.class.remove_media(sku, media_id)
48
76
  end
49
77
 
50
- #
51
78
  # Add {price} on product {sku} for specified {customer_group_id}
52
79
  #
53
80
  # Param {quantity} is the minimun amount to apply the price
@@ -89,9 +116,57 @@ module Magento
89
116
  self.class.update_stock(sku, id, attributes)
90
117
  end
91
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
+
92
141
  class << self
93
142
  alias_method :find_by_sku, :find
94
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
+ #
95
170
  def add_media(sku, attributes)
96
171
  request.post("products/#{sku}/media", { entry: attributes }).parse
97
172
  end
@@ -134,6 +209,26 @@ module Magento
134
209
  def update_stock(sku, id, attributes)
135
210
  request.put("products/#{sku}/stockItems/#{id}", stockItem: attributes).parse
136
211
  end
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
+ #
225
+ def create_links(sku, product_links)
226
+ request.post("products/#{sku}/links", { items: product_links })
227
+ end
228
+
229
+ def remove_link(sku, link_type:, linked_product_sku:)
230
+ request.delete("products/#{sku}/links/#{link_type}/#{linked_product_sku}")
231
+ end
137
232
  end
138
233
  end
139
234
  end
data/lib/magento/query.rb CHANGED
@@ -23,7 +23,7 @@ module Magento
23
23
  'to' # The end of a range. Must be used with from
24
24
  ].freeze
25
25
 
26
- def initialize(model, request: Request.new)
26
+ def initialize(model, request: Request.new, api_resource: nil)
27
27
  @model = model
28
28
  @request = request
29
29
  @filter_groups = nil
@@ -31,6 +31,7 @@ module Magento
31
31
  @page_size = 50
32
32
  @sort_orders = nil
33
33
  @fields = nil
34
+ @endpoint = api_resource || model.api_resource
34
35
  end
35
36
 
36
37
  def where(attributes)
@@ -69,15 +70,17 @@ module Magento
69
70
  self
70
71
  end
71
72
 
72
- def order(attributes)
73
- if attributes.is_a?(String)
74
- self.sort_orders = [{ field: verify_id(attributes), direction: :asc }]
75
- elsif attributes.is_a?(Hash)
76
- self.sort_orders = []
77
- attributes.each do |field, direction|
78
- raise "Invalid sort order direction '#{direction}'" unless %w[asc desc].include?(direction.to_s)
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)
79
81
 
80
- sort_orders << { field: verify_id(field), direction: direction }
82
+ sort_orders << { field: verify_id(field), direction: direction }
83
+ end
81
84
  end
82
85
  end
83
86
  self
@@ -131,7 +134,7 @@ module Magento
131
134
  attr_accessor :current_page, :filter_groups, :request, :sort_orders, :model, :fields
132
135
 
133
136
  def endpoint
134
- model.api_resource
137
+ @endpoint
135
138
  end
136
139
 
137
140
  def verify_id(field)
@@ -27,6 +27,10 @@ module Magento
27
27
  def generate_coupon(attributes)
28
28
  request.post('coupons/generate', attributes).parse
29
29
  end
30
+
31
+ protected def query
32
+ Query.new(self, api_resource: 'salesRules/search')
33
+ end
30
34
  end
31
35
  end
32
36
  end
@@ -1,3 +1,3 @@
1
1
  module Magento
2
- VERSION = '0.24.0'
2
+ VERSION = '0.28.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