magentor 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Preston Stuteville
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,45 @@
1
+ = Magentor
2
+ Simple wrapper for the Magento XMLRPC api
3
+
4
+ Magento api documentation: http://www.magentocommerce.com/support/magento_core_api
5
+
6
+
7
+ = Usage
8
+ Setup your connection to magento
9
+
10
+ Magento::Base.connection = Magento::Connection.new({
11
+ :username => 'username',
12
+ :api_key => 'api_key',
13
+ :host => 'magento.example.org',
14
+ :path => '/magento/api/xmlrpc',
15
+ :port => '80'
16
+ })
17
+
18
+ Then get down to business
19
+
20
+ Magento::Customer.list
21
+ Magento::Product.info(1).sku
22
+ customer = Magento::Customer.find(:first, {:email => 'example@magentor.ccc'})
23
+ customer.update_attributes({:firstname => 'duke', :lastname => 'magentor'})
24
+ customer.delete
25
+
26
+ = License
27
+ Copyright (c) 2010 Preston Stuteville
28
+
29
+ Permission is hereby granted, free of charge, to any person obtaining a copy
30
+ of this software and associated documentation files (the "Software"), to deal
31
+ in the Software without restriction, including without limitation the rights
32
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
+ copies of the Software, and to permit persons to whom the Software is
34
+ furnished to do so, subject to the following conditions:
35
+
36
+ The above copyright notice and this permission notice shall be included in
37
+ all copies or substantial portions of the Software.
38
+
39
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "magentor"
5
+ gemspec.summary = "Ruby wrapper for the Magento xmlrpc api"
6
+ gemspec.email = "preston.stuteville@gmail.com"
7
+ gemspec.homepage = "http://github.com/pstuteville/magentor"
8
+ gemspec.authors = ["Preston Stuteville"]
9
+
10
+ gemspec.has_rdoc = true
11
+ gemspec.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"]
12
+ gemspec.extra_rdoc_files = ["README.rdoc"]
13
+ end
14
+ rescue LoadError
15
+ puts "Jeweler not available. Install it with: gem install jeweler"
16
+ end
data/TODOS ADDED
@@ -0,0 +1,3 @@
1
+ - Implement correct method signatures instead of passing *args to most api calls
2
+ - Validation
3
+ - Add more convenience methods to objects
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'magento'
@@ -0,0 +1,55 @@
1
+ # Base Magento model handles basic crud operations and stores connection to magento instance.
2
+ # It has the following class attributes:
3
+ #
4
+ # * <tt>connection</tt>: the Magento::Connection to use
5
+ #
6
+ # And the following instance attributes:
7
+ # * <tt>attributes</tt>: the attributes of the magento object
8
+ #
9
+ module Magento
10
+ class Base
11
+ attr_accessor :attributes
12
+ class << self; attr_accessor :connection end
13
+
14
+ module ClassMethods
15
+ # Uses the classes name and method to make an rpc call through connection
16
+ def commit(method, *args)
17
+ # TODO: need to catch errors sent back from magento and bubble them up appropriately
18
+ method = "#{to_s.split('::').last.underscore.downcase}.#{method}"
19
+ Magento::Base.connection.call(method, *args)
20
+ end
21
+ end
22
+
23
+ module InstanceMethods
24
+ def initialize(attributes = {})
25
+ @attributes = attributes.dup
26
+ end
27
+
28
+ # TODO: find out if the id naming is consistent
29
+ def id
30
+ @attributes["#{self.class.to_s.split('::').last.underscore.downcase}_id"]
31
+ end
32
+
33
+ def id=(_id)
34
+ @attributes["#{self.class.to_s.split('::').last.underscore.downcase}_id"] = _id
35
+ end
36
+
37
+ def object_attributes=(new_attributes)
38
+ return if new_attributes.nil?
39
+ attributes = new_attributes.dup
40
+ attributes.stringify_keys!
41
+ attributes.each do |k, v|
42
+ send(k + "=", v)
43
+ end
44
+ end
45
+
46
+ def method_missing(method, *args)
47
+ return nil unless @attributes
48
+ @attributes[method.to_s]
49
+ end
50
+ end
51
+
52
+ include InstanceMethods
53
+ extend ClassMethods
54
+ end
55
+ end
@@ -0,0 +1,215 @@
1
+ module Magento
2
+ # http://www.magentocommerce.com/wiki/doc/webservices-api/api/catalog_category
3
+ # 100 Requested store view not found.
4
+ # 101 Requested website not found.
5
+ # 102 Category not exists.
6
+ # 103 Invalid data given. Details in error message.
7
+ # 104 Category not moved. Details in error message.
8
+ # 105 Category not deleted. Details in error message.
9
+ # 106 Requested product is not assigned to category.
10
+ class Category < Base
11
+ class << self
12
+ # catalog_category.create
13
+ # Create new category and return its id.
14
+ #
15
+ # Return: int
16
+ #
17
+ # Arguments:
18
+ #
19
+ # int $parentId - ID of parent category
20
+ # array $categoryData - category data ( array(’attribute_code’⇒‘attribute_value’ )
21
+ # mixed $storeView - store view ID or code (optional)
22
+ def create(attributes)
23
+ id = commit("create", attributes)
24
+ record = new(attributes)
25
+ record.id = id
26
+ record
27
+ end
28
+
29
+ # catalog_category.info
30
+ # Retrieve category data
31
+ #
32
+ # Return: array
33
+ #
34
+ # Arguments:
35
+ #
36
+ # int $categoryId - category ID
37
+ # mixed $storeView - store view id or code (optional)
38
+ # array $attributes - return only specified attributes (optional)
39
+ def info(*args)
40
+ new(commit("info", *args))
41
+ end
42
+
43
+ # catalog_category.update
44
+ # Update category
45
+ #
46
+ # Return: boolean
47
+ #
48
+ # Arguments:
49
+ #
50
+ # int $categoryId - ID of category for updating
51
+ # array $categoryData - category data ( array(’attribute_code’⇒‘attribute_value’ )
52
+ # mixed storeView - store view ID or code (optional)
53
+ def update(*args)
54
+ commit("update", *args)
55
+ end
56
+
57
+ # catalog_category.delete
58
+ # Delete category
59
+ #
60
+ # Return: boolean
61
+ #
62
+ # Arguments:
63
+ #
64
+ # int $categoryId - category ID
65
+ def delete(*args)
66
+ commit("delete", *args)
67
+ end
68
+
69
+ # catalog_category.currentStore
70
+ # Set/Get current store view
71
+ #
72
+ # Return: int
73
+ #
74
+ # Arguments:
75
+ #
76
+ # mixed storeView - Store view ID or code.
77
+ def current_store(*args)
78
+ commit("currentStore", *args)
79
+ end
80
+
81
+ # catalog_category.tree
82
+ # Retrieve hierarchical tree of categories.
83
+ #
84
+ # Return: array
85
+ #
86
+ # Arguments:
87
+ #
88
+ # int parentId - parent category id (optional)
89
+ # mixed storeView - store view (optional)
90
+ def tree(*args)
91
+ commit("tree", *args)
92
+ end
93
+
94
+ # catalog_category.level
95
+ # Retrieve one level of categories by website/store view/parent category
96
+ #
97
+ # Return: array
98
+ #
99
+ # Arguments:
100
+ #
101
+ # mixed website - website code or Id (optional)
102
+ # mixed storeView - store view code or Id (optional)
103
+ # mixed parentCategory - parent category Id (optional)
104
+ def level(*args)
105
+ commit("level", *args)
106
+ end
107
+
108
+ # catalog_category.move
109
+ # Move category in tree
110
+ #
111
+ # Return: boolean
112
+ #
113
+ # Arguments:
114
+ #
115
+ # int $categoryId - category ID for moving
116
+ # int $parentId - new category parent
117
+ # int $afterId - category ID after what position it will be moved (optional)
118
+ #
119
+ # NOTE Please make sure that you are not moving category to any of its own children.
120
+ # There are no extra checks to prevent doing it through webservices API, and you won’t
121
+ # be able to fix this from admin interface then
122
+ def move(*args)
123
+ commit("move", *args)
124
+ end
125
+
126
+ # catalog_category.assignedProducts
127
+ # Retrieve list of assigned products
128
+ #
129
+ # Return: array
130
+ #
131
+ # Arguments:
132
+ #
133
+ # int $categoryId - category ID
134
+ # mixed $store - store ID or code
135
+ def assigned_products(*args)
136
+ commit("assignedProducts", *args)
137
+ end
138
+
139
+ # catalog_category.assignProduct
140
+ # Assign product to category
141
+ #
142
+ # Return: boolean
143
+ #
144
+ # Arguments:
145
+ #
146
+ # int $categoryId - category ID
147
+ # mixed $product - product ID or sku
148
+ # int $position - position of product in category (optional)
149
+ def assign_product(*args)
150
+ commit("assignProduct", *args)
151
+ end
152
+
153
+ # catalog_category.updateProduct
154
+ # Update assigned product
155
+ #
156
+ # Return: boolean
157
+ #
158
+ # Arguments:
159
+ #
160
+ # int $categoryId - category ID
161
+ # mixed $product - product ID or sku
162
+ # int $position - position of product in category (optional)
163
+ def update_product(*args)
164
+ commit("updateProduct", *args)
165
+ end
166
+
167
+ # catalog_category.removeProduct
168
+ # Remove product assignment from category
169
+ #
170
+ # Return: boolean
171
+ #
172
+ # Arguments:
173
+ #
174
+ # int $categoryId - category ID
175
+ # mixed $product - product ID or sku
176
+ def remove_product(*args)
177
+ commit("removeProduct", *args)
178
+ end
179
+
180
+ def find_by_id(id)
181
+ info(id)
182
+ end
183
+ end
184
+
185
+ def delete
186
+ self.class.delete(self.id)
187
+ end
188
+
189
+ def update_attribute(name, value)
190
+ @attributes[name] = value
191
+ self.class.update(self.id, Hash[*[name.to_sym, value]])
192
+ end
193
+
194
+ def update_attributes(attrs)
195
+ attrs.each_pair { |k, v| @attributes[k] = v }
196
+ self.class.update(self.id, attrs)
197
+ end
198
+
199
+ def assigned_products(*args)
200
+ self.class.assigned_products(self.id, *args)
201
+ end
202
+
203
+ def assign_product(*args)
204
+ self.class.assign_product(self.id, *args)
205
+ end
206
+
207
+ def update_product(*args)
208
+ self.class.update_product(self.id, *args)
209
+ end
210
+
211
+ def remove_product(*args)
212
+ self.class.remove_product(self.id, *args)
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,42 @@
1
+ module Magento
2
+ # http://www.magentocommerce.com/wiki/doc/webservices-api/api/catalog_category_attribute
3
+ # 100 Requested store view not found.
4
+ # 101 Requested attribute not found.
5
+ class CategoryAttribute < Base
6
+ class << self
7
+ # catalog_category_attribute.list
8
+ # Retrieve category attributes
9
+ #
10
+ # Return: array
11
+ def list
12
+ results = commit("list", nil)
13
+ results.collect do |result|
14
+ new(result)
15
+ end
16
+ end
17
+
18
+ # catalog_category_attribute.currentStore
19
+ # Set/Get current store view
20
+ #
21
+ # Return: int
22
+ #
23
+ # Arguments:
24
+ #
25
+ # mixed storeView - Store view ID or code. (optional)
26
+ def current_store(*args)
27
+ commit("currentStore", *args)
28
+ end
29
+
30
+ # catalog_category_attribute.options
31
+ # Retrieve attribute options
32
+ #
33
+ # Arguments:
34
+ #
35
+ # attributeId - attribute id or code
36
+ # storeView - store view id or code
37
+ def options(*args)
38
+ commit("options", *args)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,23 @@
1
+ module Magento
2
+ class Connection
3
+ attr_accessor :client, :config, :logger
4
+ def initialize(config = {})
5
+ @logger ||= Logger.new(STDOUT)
6
+ @config = config
7
+ self
8
+ end
9
+
10
+ def connect
11
+ @client = XMLRPC::Client.new(config[:host], config[:path], config[:port])
12
+ @session = @client.call("login", config[:username], config[:api_key])
13
+ end
14
+
15
+ def call(method = nil, *args)
16
+ @logger.debug "call: #{method}, #{args.inspect}"
17
+ connect
18
+ @client.call("call", @session, method, args)
19
+ rescue XMLRPC::FaultException => e
20
+ @logger.debug "exception: #{e.faultCode} -> #{e.faultString}"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ module Magento
2
+ # http://www.magentocommerce.com/wiki/doc/webservices-api/api/directory_country
3
+ class Country < Base
4
+ class << self
5
+ # directory_country.list
6
+ # Retrieve list of countries.
7
+ #
8
+ # Return: array.
9
+ def list
10
+ results = commit("list", nil)
11
+ results.collect do |result|
12
+ new(result)
13
+ end
14
+ end
15
+
16
+ def all
17
+ list
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,122 @@
1
+ module Magento
2
+ # http://www.magentocommerce.com/wiki/doc/webservices-api/api/customer
3
+ # 100 Invalid customer data. Details in error message.
4
+ # 101 Invalid filters specified. Details in error message.
5
+ # 102 Customer does not exist.
6
+ # 103 Customer not deleted. Details in error message.
7
+ class Customer < Base
8
+ class << self
9
+ # customer.list
10
+ # Retrieve customers
11
+ #
12
+ # Return: array
13
+ #
14
+ # Arguments:
15
+ #
16
+ # array filters - filters by customer attributes (optional)
17
+ # filter list - “updated_at”, “website_id”, “increment_id”, “lastname”, “group_id”,
18
+ # “firstname”, “created_in”, “customer_id”, “password_hash”, “store_id”, “email”, “created_at”
19
+ #
20
+ # Note: password_hash will only match exactly with the same MD5 and salt as was used when
21
+ # Magento stored the value. If you try to match with an unsalted MD5 hash, or any salt other
22
+ # than what Magento used, it will not match. This is just a straight string comparison.
23
+ def list(*args)
24
+ results = commit("list", *args)
25
+ results.collect do |result|
26
+ new(result)
27
+ end
28
+ end
29
+
30
+ # customer.create
31
+ # Create customer
32
+ #
33
+ # Return: int
34
+ #
35
+ # Arguments:
36
+ #
37
+ # array customerData - cutomer data (email, firstname, lastname, etc...)
38
+ def create(attributes)
39
+ id = commit("create", attributes)
40
+ record = new(attributes)
41
+ record.id = id
42
+ record
43
+ end
44
+
45
+
46
+ # customer.info
47
+ # Retrieve customer data
48
+ #
49
+ # Return: array
50
+ #
51
+ # Arguments:
52
+ #
53
+ # int customerId - Customer ID.
54
+ # array attributes | string attribute (optional depending on version) -
55
+ # return only these attributes. Possible attributes are updated_at, increment_id,
56
+ # customer_id, created_at. The value, customer_id, is always returned.
57
+ def info(*args)
58
+ new(commit("info", *args))
59
+ end
60
+
61
+ # customer.update
62
+ # Update customer data
63
+ #
64
+ # Return: boolean
65
+ #
66
+ # Arguments:
67
+ #
68
+ # int customerId - customer ID
69
+ # array customerData - customer data (email, firstname, etc...)
70
+ def update(*args)
71
+ commit("update", *args)
72
+ end
73
+
74
+
75
+ # customer.delete
76
+ # Delete customer
77
+ #
78
+ # Return: boolean
79
+ #
80
+ # Arguments:
81
+ #
82
+ # int customerId - customer ID.
83
+ def delete(*args)
84
+ commit("delete", *args)
85
+ end
86
+
87
+ def find_by_id(id)
88
+ info(id)
89
+ end
90
+
91
+ def find(find_type, options = {})
92
+ filters = {}
93
+ options.each_pair { |k, v| filters[k] = {:eq => v} }
94
+ results = list(filters)
95
+ if find_type == :first
96
+ results.first
97
+ else
98
+ results
99
+ end
100
+ end
101
+
102
+ def all
103
+ list
104
+ end
105
+
106
+ end
107
+
108
+ def delete
109
+ self.class.delete(self.id)
110
+ end
111
+
112
+ def update_attribute(name, value)
113
+ @attributes[name] = value
114
+ self.class.update(self.id, Hash[*[name.to_sym, value]])
115
+ end
116
+
117
+ def update_attributes(attrs)
118
+ attrs.each_pair { |k, v| @attributes[k] = v }
119
+ self.class.update(self.id, attrs)
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,101 @@
1
+ module Magento
2
+ # http://www.magentocommerce.com/wiki/doc/webservices-api/api/customer_address
3
+ # 100 Invalid address data. Details in error message.
4
+ # 101 Customer not exists.
5
+ # 102 Address not exists.
6
+ # 103 Address not deleted. Details in error message.
7
+ class CustomerAddress < Base
8
+ class << self
9
+ # customer_address.list
10
+ # Retrieve customer addresses
11
+ #
12
+ # Return: array
13
+ #
14
+ # Arguments:
15
+ #
16
+ # int customerId - Customer Id
17
+ def list(*args)
18
+ results = commit("list", *args)
19
+ results.collect do |result|
20
+ new(result)
21
+ end
22
+ end
23
+
24
+ # customer_address.create
25
+ # Create customer address
26
+ #
27
+ # Return: int
28
+ #
29
+ # Arguments:
30
+ #
31
+ # int customerId - customer ID
32
+ # array addressData - adress data (country, zip, city, etc...)
33
+ def create(attributes)
34
+ id = commit("create", attributes)
35
+ record = new(attributes)
36
+ record.id = id
37
+ record
38
+ end
39
+
40
+ # customer_address.info
41
+ # Retrieve customer address data
42
+ #
43
+ # Return: array
44
+ #
45
+ # Arguments:
46
+ #
47
+ # int addressId - customer address ID
48
+ def info(*args)
49
+ new(commit("info", *args))
50
+ end
51
+
52
+ # customer_address.update
53
+ # Update customer address data
54
+ #
55
+ # Return: boolean
56
+ #
57
+ # Arguments:
58
+ #
59
+ # int addressId - customer address ID
60
+ # array addressData - adress data (country, zip, city, etc...)
61
+ def update(*args)
62
+ commit("update", *args)
63
+ end
64
+
65
+ # customer_address.delete
66
+ # Delete customer address
67
+ #
68
+ # Return: boolean
69
+ #
70
+ # Arguments:
71
+ #
72
+ # int addressId - customer address ID
73
+ def delete(*args)
74
+ commit("delete", *args)
75
+ end
76
+
77
+ def find_by_id(id)
78
+ info(id)
79
+ end
80
+
81
+ def find_by_customer_id(id)
82
+ list(id)
83
+ end
84
+
85
+ end
86
+
87
+ def delete
88
+ self.class.delete(self.id)
89
+ end
90
+
91
+ def update_attribute(name, value)
92
+ @attributes[name] = value
93
+ self.class.update(self.id, Hash[*[name.to_sym, value]])
94
+ end
95
+
96
+ def update_attributes(attrs)
97
+ attrs.each_pair { |k, v| @attributes[k] = v }
98
+ self.class.update(self.id, attrs)
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,17 @@
1
+ module Magento
2
+ # http://www.magentocommerce.com/wiki/doc/webservices-api/api/customer_group
3
+ class CustomerGroup < Base
4
+ class << self
5
+ # customer_group.list
6
+ # Retrieve customer groups
7
+ #
8
+ # Return: array
9
+ def list
10
+ results = commit("list", nil)
11
+ results.collect do |result|
12
+ new(result)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ module Magento
2
+ class Inventory < Base
3
+ end
4
+ end