magento 0.10.0 → 0.14.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.
@@ -2,10 +2,13 @@
2
2
 
3
3
  require 'time'
4
4
  require 'dry/inflector'
5
+ require 'active_support/core_ext/string/inflections'
6
+ require 'active_support/core_ext/hash/keys'
5
7
 
6
8
  require_relative 'magento/errors'
7
9
  require_relative 'magento/request'
8
10
  require_relative 'magento/model_mapper'
11
+ require_relative 'magento/params'
9
12
  require_relative 'magento/polymorphic_model'
10
13
  require_relative 'magento/model'
11
14
  require_relative 'magento/record_collection'
@@ -17,8 +20,10 @@ require_relative 'magento/customer'
17
20
  require_relative 'magento/order'
18
21
  require_relative 'magento/invoice'
19
22
  require_relative 'magento/guest_cart'
23
+ require_relative 'magento/sales_rule'
20
24
 
21
25
  Dir[File.expand_path('magento/shared/*.rb', __dir__)].map { |f| require f }
26
+ Dir[File.expand_path('magento/params/*.rb', __dir__)].map { |f| require f }
22
27
 
23
28
  module Magento
24
29
  class << self
@@ -37,12 +42,12 @@ module Magento
37
42
  self.token = ENV['MAGENTO_TOKEN']
38
43
  self.store = ENV['MAGENTO_STORE'] || :all
39
44
 
40
- def self.with_config(utl: Magento.url, token: Magento.token, store: Magento.store)
45
+ def self.with_config(url: Magento.url, token: Magento.token, store: Magento.store)
41
46
  @old_url = self.url
42
47
  @old_token = self.token
43
48
  @old_store = self.store
44
-
45
- self.url = utl
49
+
50
+ self.url = url
46
51
  self.token = token
47
52
  self.store = store
48
53
 
@@ -6,15 +6,30 @@ module Magento
6
6
  "#{@firstname} #{@lastname}"
7
7
  end
8
8
 
9
+ def update(attributes)
10
+ raise "id not present" if @id.nil?
11
+
12
+ attributes.each { |key, value| send("#{key}=", value) }
13
+ save
14
+ end
15
+
9
16
  class << self
10
17
  alias_method :find_by_id, :find
11
18
 
12
- def update(*_attributes)
13
- raise NotImplementedError
19
+ def update(id, attributes)
20
+ hash = request.put("customers/#{id}", { customer: attributes }).parse
21
+
22
+ block_given? ? yield(hash) : build(hash)
14
23
  end
15
24
 
16
- def create(*_attributes)
17
- raise NotImplementedError
25
+ def create(attributes)
26
+ attributes.transform_keys!(&:to_sym)
27
+ password = attributes.delete :password
28
+ hash = request.post("customers", {
29
+ customer: attributes,
30
+ password: password
31
+ }).parse
32
+ build(hash)
18
33
  end
19
34
 
20
35
  def find_by_token(token)
@@ -32,6 +32,18 @@ module Magento
32
32
  self.class.payment_information(attributes)
33
33
  end
34
34
 
35
+ #
36
+ # Add a coupon by code to the current cart.
37
+ #
38
+ # Example
39
+ # cart = Magento::GuestCart.find('gXsepZcgJbY8RCJXgGioKOO9iBCR20r7')
40
+ # cart.add_coupon('COAU4HXE0I')
41
+ #
42
+ # @return Boolean: true on success, false otherwise
43
+ def add_coupon(coupon)
44
+ self.class.add_coupon(cart_id, coupon)
45
+ end
46
+
35
47
  class << self
36
48
  def create(load_cart_info: false)
37
49
  cart = build(cart_id: request.post(api_resource).parse)
@@ -64,6 +76,21 @@ module Magento
64
76
  hash = request.post(url, attributes).parse
65
77
  Magento::ModelMapper.map_hash(Magento::Item, hash)
66
78
  end
79
+
80
+ #
81
+ # Add a coupon by code to a specified cart.
82
+ #
83
+ # Example
84
+ # Magento::GuestCart.add_coupon(
85
+ # 'aj8oUtY1Qi44Fror6UWVN7ftX1idbBKN',
86
+ # 'COAU4HXE0I'
87
+ # )
88
+ #
89
+ # @return Boolean: true on success, false otherwise
90
+ def add_coupon(id, coupon)
91
+ url = "#{api_resource}/#{id}/coupons/#{coupon}"
92
+ request.put(url, nil).parse
93
+ end
67
94
  end
68
95
  end
69
96
  end
@@ -7,13 +7,17 @@ module Magento
7
7
  include Magento::ModelParser
8
8
 
9
9
  def save
10
- self.class.update(send(self.class.primary_key), to_h)
10
+ self.class.update(send(self.class.primary_key), to_h) do |hash|
11
+ update_attributes(hash)
12
+ end
11
13
  end
12
14
 
13
15
  def update(attrs)
14
16
  raise "#{self.class.name} not saved" if send(self.class.primary_key).nil?
15
17
 
16
- self.class.update(send(self.class.primary_key), attrs)
18
+ self.class.update(send(self.class.primary_key), attrs) do |hash|
19
+ update_attributes(hash)
20
+ end
17
21
  end
18
22
 
19
23
  def delete
@@ -24,6 +28,10 @@ module Magento
24
28
  @id || send(self.class.primary_key)
25
29
  end
26
30
 
31
+ protected def update_attributes(hash)
32
+ ModelMapper.map_hash(self, hash)
33
+ end
34
+
27
35
  class << self
28
36
  extend Forwardable
29
37
 
@@ -48,7 +56,8 @@ module Magento
48
56
  def update(id, attributes)
49
57
  body = { entity_key => attributes }
50
58
  hash = request.put("#{api_resource}/#{id}", body).parse
51
- build(hash)
59
+
60
+ block_given? ? yield(hash) : build(hash)
52
61
  end
53
62
 
54
63
  def api_resource
@@ -17,9 +17,12 @@ module Magento
17
17
  end
18
18
 
19
19
  def self.map_hash(model, values)
20
- object = model.new
20
+ object = model.is_a?(Class) ? model.new : model
21
21
  values.each do |key, value|
22
- object.singleton_class.instance_eval { attr_accessor key }
22
+ unless object.respond_to?(key) && object.respond_to?("#{key}=")
23
+ object.singleton_class.instance_eval { attr_accessor key }
24
+ end
25
+
23
26
  if value.is_a?(Hash)
24
27
  class_name = Magento.inflector.camelize(Magento.inflector.singularize(key))
25
28
  value = map_hash(Object.const_get("Magento::#{class_name}"), value)
@@ -12,7 +12,9 @@ module Magento
12
12
  def update(attrs)
13
13
  raise "'entity_id' not found" if @entity_id.nil?
14
14
 
15
- self.class.update(@entity_id, attrs)
15
+ self.class.update(@entity_id, attrs) do |hash|
16
+ update_attributes(hash)
17
+ end
16
18
  end
17
19
 
18
20
  def cancel
@@ -63,7 +65,7 @@ module Magento
63
65
  def update(entity_id, attributes)
64
66
  attributes[:entity_id] = entity_id
65
67
  hash = request.put('orders/create', { entity_key => attributes }).parse
66
- build(hash)
68
+ block_given? ? yield(hash) : build(hash)
67
69
  end
68
70
 
69
71
  # @return {Boolean}
@@ -0,0 +1,9 @@
1
+ require 'dry/struct'
2
+
3
+ module Magento
4
+ module Params
5
+ module Type
6
+ include Dry.Types()
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Magento
4
+ module Params
5
+ class CreateCategoria < Dry::Struct
6
+ attribute :name, Type::String
7
+ attribute :parent_id, Type::String.optional
8
+ attribute :path, Type::String.optional
9
+ attribute :is_active, Type::Bool.default(true)
10
+
11
+ def to_h
12
+ {
13
+ "name": name,
14
+ "parent_id": parent_id,
15
+ "is_active": is_active,
16
+ "path": path
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Magento
4
+ module Params
5
+ class CreateCustomAttribute < Dry::Struct
6
+ attribute :code, Type::String
7
+ attribute :value, Type::String
8
+
9
+ def to_h
10
+ {
11
+ "attribute_code": code,
12
+ "value": value
13
+ }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open-uri'
4
+ require 'mini_magick'
5
+
6
+ module Magento
7
+ module Params
8
+ class CreateImage < Dry::Struct
9
+ VARIANTS = {
10
+ 'large' => { size: '800x800', type: :image },
11
+ 'medium' => { size: '300x300', type: :small_image },
12
+ 'small' => { size: '100x100', type: :thumbnail }
13
+ }.freeze
14
+
15
+ attribute :title, Type::String
16
+ attribute :path, Type::String
17
+ attribute :position, Type::Integer
18
+ attribute :size, Type::String.default('large').enum(*VARIANTS.keys)
19
+ attribute :disabled, Type::Bool.default(false)
20
+ attribute :main, Type::Bool.default(false)
21
+
22
+ def to_h
23
+ {
24
+ "disabled": disabled,
25
+ "media_type": 'image',
26
+ "label": title,
27
+ "position": position,
28
+ "content": {
29
+ "base64_encoded_data": base64,
30
+ "type": mini_type,
31
+ "name": filename
32
+ },
33
+ "types": main ? [VARIANTS[size][:type]] : []
34
+ }
35
+ end
36
+
37
+ def variants
38
+ VARIANTS.keys.map do |size|
39
+ CreateImage.new(attributes.merge(size: size, disabled: size != 'large'))
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def base64
46
+ Base64.strict_encode64(File.open(file.path).read).to_s
47
+ end
48
+
49
+ def file
50
+ @file ||= MiniMagick::Image.open(path).tap do |b|
51
+ b.resize VARIANTS[size][:size]
52
+ b.strip
53
+ end
54
+ end
55
+
56
+ def filename
57
+ title.parameterize
58
+ end
59
+
60
+ def mini_type
61
+ file.mime_type
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,147 @@
1
+ require_relative 'create_image'
2
+ require_relative 'create_custom_attribute'
3
+
4
+ module Magento
5
+ module Params
6
+ # Example
7
+ #
8
+ # params = Magento::Params::CreateProduct.new(
9
+ # sku: '556-teste-builder',
10
+ # name: 'REFRIGERANTE PET COCA-COLA 1,5L ORIGINAL',
11
+ # description: 'Descrição do produto',
12
+ # brand: 'Coca-Cola',
13
+ # price: 4.99,
14
+ # special_price: 3.49,
15
+ # quantity: 2,
16
+ # weight: 0.3,
17
+ # attribute_set_id: 4,
18
+ # images: [
19
+ # *Magento::Params::CreateImage.new(
20
+ # path: 'https://urltoimage.com/image.jpg',
21
+ # title: 'REFRIGERANTE PET COCA-COLA 1,5L ORIGINAL',
22
+ # position: 0,
23
+ # main: true
24
+ # ).variants, # it's generate all variants thumbnail => '100x100', small_image => '300x300' and image => '800x800'
25
+ # Magento::Params::CreateImage.new(
26
+ # path: '/path/to/image.jpg',
27
+ # title: 'REFRIGERANTE PET COCA-COLA 1,5L ORIGINAL',
28
+ # position: 1
29
+ # )
30
+ # ]
31
+ # )
32
+ #
33
+ # Magento::Product.create(params.to_h)
34
+ #
35
+ class CreateProduct < Dry::Struct
36
+ ProductTypes = Type::String.default('simple'.freeze).enum(
37
+ 'simple',
38
+ 'bundle',
39
+ 'configurable',
40
+ 'downloadable',
41
+ 'grouped',
42
+ 'Virtual'
43
+ )
44
+
45
+ Visibilities = Type::String.default('catalog_and_search'.freeze).enum(
46
+ 'not_visible_individually' => 1,
47
+ 'catalog' => 1,
48
+ 'search' => 3,
49
+ 'catalog_and_search' => 4
50
+ )
51
+
52
+ Statuses = Type::String.default('enabled'.freeze).enum('enabled' => 1, 'disabled' => 2)
53
+
54
+ attribute :sku, Type::String
55
+ attribute :name, Type::String
56
+ attribute :description, Type::String
57
+ attribute :brand, Type::String
58
+ attribute :price, Type::Coercible::Float
59
+ attribute :special_price, Type::Float.optional.default(nil)
60
+ attribute :attribute_set_id, Type::Integer
61
+ attribute :status, Statuses
62
+ attribute :visibility, Visibilities
63
+ attribute :type_id, ProductTypes
64
+ attribute :weight, Type::Coercible::Float
65
+ attribute :quantity, Type::Coercible::Float
66
+ attribute :featured, Type::String.default('0'.freeze).enum('0', '1')
67
+ attribute :is_qty_decimal, Type::Bool.default(false)
68
+ attribute :manage_stock, Type::Bool.default(true)
69
+ attribute :category_ids, Type::Array.of(Type::Integer).default([].freeze)
70
+ attribute :images, Type::Array.of(Type::Instance(CreateImage)).default([].freeze)
71
+ attribute :website_ids, Type::Array.of(Type::Integer).default([0].freeze)
72
+ attribute :custom_attributes, Type::Array.default([], shared: true) do
73
+ attribute :attribute_code, Type::String
74
+ attribute :value, Type::Coercible::String
75
+ end
76
+
77
+ alias orig_custom_attributes custom_attributes
78
+
79
+ def to_h
80
+ {
81
+ sku: sku,
82
+ name: name.titlecase,
83
+ price: price,
84
+ status: Statuses.mapping[status],
85
+ visibility: Visibilities.mapping[visibility],
86
+ type_id: type_id,
87
+ weight: weight,
88
+ attribute_set_id: attribute_set_id,
89
+ extension_attributes: {
90
+ website_ids: website_ids,
91
+ category_links: categories,
92
+ stock_item: stock
93
+ },
94
+ media_gallery_entries: images.map(&:to_h),
95
+ custom_attributes: custom_attributes.map(&:to_h)
96
+ }
97
+ end
98
+
99
+ def stock
100
+ {
101
+ qty: quantity,
102
+ is_in_stock: quantity.to_i > 0,
103
+ is_qty_decimal: is_qty_decimal,
104
+ show_default_notification_message: false,
105
+ use_config_min_qty: true,
106
+ min_qty: 1,
107
+ use_config_min_sale_qty: 0,
108
+ min_sale_qty: 0,
109
+ use_config_max_sale_qty: true,
110
+ max_sale_qty: 0,
111
+ use_config_backorders: true,
112
+ backorders: 0,
113
+ use_config_notify_stock_qty: true,
114
+ notify_stock_qty: 0,
115
+ use_config_qty_increments: true,
116
+ qty_increments: 0,
117
+ use_config_enable_qty_inc: true,
118
+ enable_qty_increments: true,
119
+ use_config_manage_stock: manage_stock,
120
+ manage_stock: manage_stock,
121
+ low_stock_date: 'string',
122
+ is_decimal_divided: is_qty_decimal,
123
+ stock_status_changed_auto: 0
124
+ }
125
+ end
126
+
127
+ def custom_attributes
128
+ default_attributes = [
129
+ CustomAttribute.new(attribute_code: 'description', value: description),
130
+ CustomAttribute.new(attribute_code: 'url_key', value: name.parameterize ),
131
+ CustomAttribute.new(attribute_code: 'product_brand', value: brand ),
132
+ CustomAttribute.new(attribute_code: 'featured', value: featured)
133
+ ]
134
+
135
+ if special_price.to_f > 0
136
+ default_attributes << CustomAttribute.new(attribute_code: 'special_price', value: special_price.to_s)
137
+ end
138
+
139
+ default_attributes + orig_custom_attributes
140
+ end
141
+
142
+ def categories
143
+ category_ids.map { |c| { "category_id": c, "position": 0 } }
144
+ end
145
+ end
146
+ end
147
+ end