magento 0.9.1 → 0.13.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/.gitignore +1 -1
- data/Gemfile +1 -1
- data/README.md +592 -506
- data/lib/magento.rb +5 -0
- data/lib/magento/customer.rb +30 -0
- data/lib/magento/model.rb +14 -4
- data/lib/magento/model_mapper.rb +5 -2
- data/lib/magento/order.rb +4 -2
- data/lib/magento/params.rb +9 -0
- data/lib/magento/params/create_category.rb +21 -0
- data/lib/magento/params/create_custom_attribute.rb +17 -0
- data/lib/magento/params/create_image.rb +65 -0
- data/lib/magento/params/create_product.rb +147 -0
- data/lib/magento/product.rb +14 -0
- data/lib/magento/query.rb +16 -3
- data/lib/magento/request.rb +1 -1
- data/lib/magento/sales_rule.rb +32 -0
- data/lib/magento/shared/action_condition.rb +4 -0
- data/lib/magento/shared/condition.rb +4 -0
- data/lib/magento/version.rb +1 -1
- data/magento-ruby.gemspec +3 -0
- data/magento.gemspec +3 -0
- metadata +51 -1
data/lib/magento.rb
CHANGED
@@ -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
|
data/lib/magento/customer.rb
CHANGED
@@ -1,17 +1,47 @@
|
|
1
1
|
module Magento
|
2
2
|
class Customer < Model
|
3
|
+
self.endpoint = 'customers/search'
|
4
|
+
|
3
5
|
def fullname
|
4
6
|
"#{@firstname} #{@lastname}"
|
5
7
|
end
|
6
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
|
+
|
7
16
|
class << self
|
8
17
|
alias_method :find_by_id, :find
|
9
18
|
|
19
|
+
def update(id, attributes)
|
20
|
+
hash = request.put("customers/#{id}", { customer: attributes }).parse
|
21
|
+
|
22
|
+
block_given? ? yield(hash) : build(hash)
|
23
|
+
end
|
24
|
+
|
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)
|
33
|
+
end
|
34
|
+
|
10
35
|
def find_by_token(token)
|
11
36
|
user_request = Request.new(token: token)
|
12
37
|
customer_hash = user_request.get('customers/me').parse
|
13
38
|
build(customer_hash)
|
14
39
|
end
|
40
|
+
|
41
|
+
def find(id)
|
42
|
+
hash = request.get("customers/#{id}").parse
|
43
|
+
build(hash)
|
44
|
+
end
|
15
45
|
end
|
16
46
|
end
|
17
47
|
end
|
data/lib/magento/model.rb
CHANGED
@@ -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,10 +28,15 @@ 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
|
|
30
|
-
def_delegators :query, :all, :page, :per, :page_size, :order, :select,
|
38
|
+
def_delegators :query, :all, :page, :per, :page_size, :order, :select,
|
39
|
+
:where, :first, :find_by, :count
|
31
40
|
|
32
41
|
def find(id)
|
33
42
|
hash = request.get("#{api_resource}/#{id}").parse
|
@@ -47,7 +56,8 @@ module Magento
|
|
47
56
|
def update(id, attributes)
|
48
57
|
body = { entity_key => attributes }
|
49
58
|
hash = request.put("#{api_resource}/#{id}", body).parse
|
50
|
-
|
59
|
+
|
60
|
+
block_given? ? yield(hash) : build(hash)
|
51
61
|
end
|
52
62
|
|
53
63
|
def api_resource
|
data/lib/magento/model_mapper.rb
CHANGED
@@ -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.
|
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)
|
data/lib/magento/order.rb
CHANGED
@@ -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,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: true,
|
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
|
data/lib/magento/product.rb
CHANGED
@@ -2,6 +2,20 @@ module Magento
|
|
2
2
|
class Product < Model
|
3
3
|
self.primary_key = :sku
|
4
4
|
|
5
|
+
def method_missing(m)
|
6
|
+
attr(m) || super
|
7
|
+
end
|
8
|
+
|
9
|
+
# returns custom_attribute value by custom_attribute code
|
10
|
+
# return nil if custom_attribute is not present
|
11
|
+
def attr(attribute_code)
|
12
|
+
@custom_attributes&.find { |a| a.attribute_code == attribute_code.to_s }&.value
|
13
|
+
end
|
14
|
+
|
15
|
+
def respond_to?(attribute_code)
|
16
|
+
super || @custom_attributes&.any? { |a| a.attribute_code == attribute_code.to_s }
|
17
|
+
end
|
18
|
+
|
5
19
|
class << self
|
6
20
|
alias_method :find_by_sku, :find
|
7
21
|
end
|
data/lib/magento/query.rb
CHANGED
@@ -89,6 +89,18 @@ module Magento
|
|
89
89
|
RecordCollection.from_magento_response(result, model: model, iterable_field: field)
|
90
90
|
end
|
91
91
|
|
92
|
+
def first
|
93
|
+
page_size(1).page(1).all.first
|
94
|
+
end
|
95
|
+
|
96
|
+
def find_by(attributes)
|
97
|
+
where(attributes).first
|
98
|
+
end
|
99
|
+
|
100
|
+
def count
|
101
|
+
select(:id).page_size(1).page(1).all.total_count
|
102
|
+
end
|
103
|
+
|
92
104
|
private
|
93
105
|
|
94
106
|
attr_accessor :current_page, :filter_groups, :request, :sort_orders, :model, :fields
|
@@ -119,10 +131,11 @@ module Magento
|
|
119
131
|
|
120
132
|
def parse_filter(key)
|
121
133
|
patter = /(.*)_([a-z]+)$/
|
122
|
-
|
123
|
-
|
134
|
+
match = key.match(patter)
|
135
|
+
|
136
|
+
return match.to_a[1..2] if match && ACCEPTED_CONDITIONS.include?(match[2])
|
124
137
|
|
125
|
-
key
|
138
|
+
[key, 'eq']
|
126
139
|
end
|
127
140
|
|
128
141
|
def parse_value_filter(condition, value)
|