prestashop 2.0.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.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +56 -0
  3. data/README.md +111 -0
  4. data/Rakefile +9 -0
  5. data/lib/prestashop.rb +21 -0
  6. data/lib/prestashop/api.rb +9 -0
  7. data/lib/prestashop/api/connection.rb +225 -0
  8. data/lib/prestashop/api/converter.rb +152 -0
  9. data/lib/prestashop/api/error.rb +18 -0
  10. data/lib/prestashop/api/refinement.rb +14 -0
  11. data/lib/prestashop/client.rb +19 -0
  12. data/lib/prestashop/client/cache.rb +53 -0
  13. data/lib/prestashop/client/error.rb +9 -0
  14. data/lib/prestashop/client/implementation.rb +33 -0
  15. data/lib/prestashop/mapper.rb +9 -0
  16. data/lib/prestashop/mapper/extension.rb +161 -0
  17. data/lib/prestashop/mapper/model.rb +38 -0
  18. data/lib/prestashop/mapper/models.rb +1 -0
  19. data/lib/prestashop/mapper/models/address.rb +9 -0
  20. data/lib/prestashop/mapper/models/carrier.rb +9 -0
  21. data/lib/prestashop/mapper/models/cart.rb +9 -0
  22. data/lib/prestashop/mapper/models/cart_rule.rb +9 -0
  23. data/lib/prestashop/mapper/models/category.rb +114 -0
  24. data/lib/prestashop/mapper/models/combination.rb +81 -0
  25. data/lib/prestashop/mapper/models/contact.rb +9 -0
  26. data/lib/prestashop/mapper/models/content_management_system.rb +9 -0
  27. data/lib/prestashop/mapper/models/country.rb +15 -0
  28. data/lib/prestashop/mapper/models/currency.rb +9 -0
  29. data/lib/prestashop/mapper/models/customer.rb +9 -0
  30. data/lib/prestashop/mapper/models/customer_message.rb +9 -0
  31. data/lib/prestashop/mapper/models/customer_thread.rb +9 -0
  32. data/lib/prestashop/mapper/models/delivery.rb +9 -0
  33. data/lib/prestashop/mapper/models/employee.rb +9 -0
  34. data/lib/prestashop/mapper/models/group.rb +9 -0
  35. data/lib/prestashop/mapper/models/guest.rb +9 -0
  36. data/lib/prestashop/mapper/models/image.rb +52 -0
  37. data/lib/prestashop/mapper/models/image_type.rb +9 -0
  38. data/lib/prestashop/mapper/models/language.rb +15 -0
  39. data/lib/prestashop/mapper/models/manufacturer.rb +79 -0
  40. data/lib/prestashop/mapper/models/order.rb +9 -0
  41. data/lib/prestashop/mapper/models/order_carrier.rb +9 -0
  42. data/lib/prestashop/mapper/models/order_detail.rb +9 -0
  43. data/lib/prestashop/mapper/models/order_discount.rb +9 -0
  44. data/lib/prestashop/mapper/models/order_history.rb +9 -0
  45. data/lib/prestashop/mapper/models/order_invoice.rb +9 -0
  46. data/lib/prestashop/mapper/models/order_payment.rb +9 -0
  47. data/lib/prestashop/mapper/models/order_state.rb +9 -0
  48. data/lib/prestashop/mapper/models/price_range.rb +9 -0
  49. data/lib/prestashop/mapper/models/product.rb +198 -0
  50. data/lib/prestashop/mapper/models/product_feature.rb +69 -0
  51. data/lib/prestashop/mapper/models/product_feature_value.rb +60 -0
  52. data/lib/prestashop/mapper/models/product_option.rb +72 -0
  53. data/lib/prestashop/mapper/models/product_option_value.rb +56 -0
  54. data/lib/prestashop/mapper/models/product_supplier.rb +31 -0
  55. data/lib/prestashop/mapper/models/search.rb +9 -0
  56. data/lib/prestashop/mapper/models/shop.rb +9 -0
  57. data/lib/prestashop/mapper/models/shop_group.rb +9 -0
  58. data/lib/prestashop/mapper/models/specific_price.rb +9 -0
  59. data/lib/prestashop/mapper/models/specific_price_rule.rb +9 -0
  60. data/lib/prestashop/mapper/models/state.rb +9 -0
  61. data/lib/prestashop/mapper/models/stock.rb +9 -0
  62. data/lib/prestashop/mapper/models/stock_available.rb +35 -0
  63. data/lib/prestashop/mapper/models/stock_movement.rb +9 -0
  64. data/lib/prestashop/mapper/models/stock_movement_reason.rb +9 -0
  65. data/lib/prestashop/mapper/models/store.rb +9 -0
  66. data/lib/prestashop/mapper/models/supplier.rb +45 -0
  67. data/lib/prestashop/mapper/models/supply_order.rb +9 -0
  68. data/lib/prestashop/mapper/models/supply_order_detail.rb +9 -0
  69. data/lib/prestashop/mapper/models/supply_order_history.rb +9 -0
  70. data/lib/prestashop/mapper/models/supply_order_receipt_history.rb +9 -0
  71. data/lib/prestashop/mapper/models/supply_order_state.rb +9 -0
  72. data/lib/prestashop/mapper/models/tag.rb +9 -0
  73. data/lib/prestashop/mapper/models/tax.rb +24 -0
  74. data/lib/prestashop/mapper/models/tax_rule.rb +15 -0
  75. data/lib/prestashop/mapper/models/tax_rule_group.rb +9 -0
  76. data/lib/prestashop/mapper/models/translated_configuration.rb +9 -0
  77. data/lib/prestashop/mapper/models/warehouse.rb +9 -0
  78. data/lib/prestashop/mapper/models/warehouse_product_location.rb +9 -0
  79. data/lib/prestashop/mapper/models/weight_range.rb +9 -0
  80. data/lib/prestashop/mapper/models/zone.rb +9 -0
  81. data/lib/prestashop/mapper/refinement.rb +43 -0
  82. data/lib/prestashop/version.rb +3 -0
  83. metadata +279 -0
@@ -0,0 +1,18 @@
1
+ module Prestashop
2
+ module Api
3
+ class InvalidCredentials < RuntimeError
4
+ def initialize
5
+ super "Your credentials are invalid"
6
+ end
7
+ end
8
+
9
+ class RequestFailed < RuntimeError
10
+ attr_reader :response
11
+ def initialize response
12
+ @response = response
13
+ end
14
+ end
15
+
16
+ class ParserError < RuntimeError; end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module Prestashop
2
+ module Api
3
+ module Refinement
4
+ refine String do
5
+ def parse
6
+ Converter.parse self
7
+ end
8
+ def parse_error
9
+ Converter.parse_error self
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ require 'prestashop/client/error'
2
+ require 'prestashop/client/implementation'
3
+ require 'prestashop/client/cache'
4
+
5
+ module Prestashop
6
+ module Client
7
+ extend SingleForwardable
8
+ def_delegators :current, :connection, :cache
9
+ def_delegators :connection, :create, :read, :update, :delete, :check, :upload
10
+ def_delegators :cache, :manufacturers_cache, :clear_manufacturers_cache, :categories_cache, :clear_categories_cache, :features_cache, :clear_features_cache,
11
+ :feature_values_cache, :clear_feature_values_cache, :options_cache, :clear_options_cache, :option_values_cache, :clear_option_values_cache
12
+
13
+ # Delegate to current user implementation
14
+ #
15
+ def self.current
16
+ Implementation.current
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,53 @@
1
+ module Prestashop
2
+ module Client
3
+ class Cache
4
+ def manufacturers_cache
5
+ @manufacturers_cache ||= Mapper::Manufacturer.cache
6
+ end
7
+
8
+ def clear_manufacturers_cache
9
+ @manufacturers_cache = nil
10
+ end
11
+
12
+ def categories_cache
13
+ @categories_cache ||= Mapper::Category.cache
14
+ end
15
+
16
+ def clear_categories_cache
17
+ @categories_cache = nil
18
+ end
19
+
20
+ def features_cache
21
+ @features_cache ||= Mapper::ProductFeature.cache
22
+ end
23
+
24
+ def clear_features_cache
25
+ @features_cache = nil
26
+ end
27
+
28
+ def feature_values_cache
29
+ @feature_values_cache ||= Mapper::ProductFeatureValue.cache
30
+ end
31
+
32
+ def clear_feature_values_cache
33
+ @feature_values_cache = nil
34
+ end
35
+
36
+ def options_cache
37
+ @options_cache ||= Mapper::ProductOption.cache
38
+ end
39
+
40
+ def clear_options_cache
41
+ @options_cache = nil
42
+ end
43
+
44
+ def option_values_cache
45
+ @option_values_cache ||= Mapper::ProductOptionValue.cache
46
+ end
47
+
48
+ def clear_option_values_cache
49
+ @option_values_cache = nil
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,9 @@
1
+ module Prestashop
2
+ module Client
3
+ class UnitializedClient < RuntimeError
4
+ def initialize
5
+ super "Client isn't initialized"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ require 'singleton'
2
+
3
+ module Prestashop
4
+ module Client
5
+ class Implementation
6
+ include Singleton
7
+ attr_reader :connection, :cache
8
+
9
+ # Initialize new client see +Api::Connection#new+
10
+ #
11
+ def initialize api_key, api_url
12
+ @connection = Api::Connection.new api_key, api_url
13
+ @cache = Cache.new
14
+ end
15
+
16
+ class << self
17
+
18
+ # Create new user implementation, keep it in current thread to allow multithearding, see +#new+
19
+ #
20
+ def create api_key, api_url
21
+ Thread.current[:prestashop_client] = new api_key, api_url
22
+ current
23
+ end
24
+
25
+ # Get current client or raise exception, when client isn't initialized
26
+ #
27
+ def current
28
+ Thread.current[:prestashop_client] ? Thread.current[:prestashop_client] : raise(UnitializedClient)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ require 'prestashop/mapper/refinement'
2
+ require 'prestashop/mapper/extension'
3
+ require 'prestashop/mapper/model'
4
+ require 'prestashop/mapper/models'
5
+
6
+ module Prestashop
7
+ module Mapper
8
+ end
9
+ end
@@ -0,0 +1,161 @@
1
+ module Prestashop
2
+ module Mapper
3
+ module Extension
4
+ module ClassMethods
5
+
6
+ # Determinate if model with class resource exists with given id
7
+ #
8
+ # Car.exists?(1) # => true # if given car exist
9
+ # Car.exists?(2) # => false # if given car don't exist
10
+ #
11
+ def exists? id
12
+ Client.check self.resource, id
13
+ end
14
+
15
+ # Find model by class resource and given id, returns hash
16
+ # with all nodes, based on node name as key, node value as value
17
+ #
18
+ # Car.find(1) # => { id: 1, name: 'BMW' }
19
+ # Car.find(2) # => nil
20
+ #
21
+ def find id
22
+ result = Client.read self.resource, id
23
+ result ? result[self.model] : nil
24
+ end
25
+
26
+ # Find model by class resource and params in hash
27
+ # Returns first result, see #where for more informations
28
+ #
29
+ # Car.find_by(name: 'BMW') # => 1
30
+ #
31
+ def find_by options = {}
32
+ results = where(options)
33
+ results ? results.first : nil
34
+ end
35
+
36
+ # Get models all results by class resource, you can specifi what
37
+ # you should to see as result by specifiyng +:display+
38
+ #
39
+ # Car.all # => [1,2,3]
40
+ # Car.all(display: ['name']) # => [{ name: { language: { attr: { id: 2, href: 'http://localhost.com/api/languages/2'}, val: 'BMW 7'} }]
41
+ #
42
+ def all options = {}
43
+ result = if options[:display]
44
+ Client.read self.resource, nil, display: options[:display]
45
+ else
46
+ Client.read self.resource
47
+ end
48
+ handle_result result, options
49
+ end
50
+
51
+ # Get results by class resource and given conditionals
52
+ #
53
+ # Car.where('filter[id_supplier' => 1) # => [1, 2]
54
+ #
55
+ def where options = {}
56
+ result = Client.read self.resource, nil, options
57
+ handle_result result, options
58
+ end
59
+
60
+ # Destroy model by class resource and given id
61
+ #
62
+ # Car.destroy(1) # => true
63
+ #
64
+ def destroy id
65
+ Client.delete self.resource, id
66
+ end
67
+
68
+ # Create hash suitable for update, contains #fixed_hash as hash with deleted
69
+ # keys, which shouldn't be in payload, if exist
70
+ #
71
+ # Car.update_hash(1, name: 'BMW7') # => {name: 'BMW7', manufacturer: 'BMW'}
72
+ #
73
+ def update_hash id, options = {}
74
+ original = defined?(fixed_hash(nil)) ? fixed_hash(id) : find(id)
75
+ original.merge(options)
76
+ end
77
+
78
+ # Create payload for update, converts hash to XML
79
+ #
80
+ # Car.update_payload(1, name: 'BMW 7') # => <prestashop xmlns:xlink="http://www.w3.org/1999/xlink"><car><name><![CDATA[BMW 7]]></name></car></prestashop>
81
+ #
82
+ def update_payload id, options = {}
83
+ Api::Converter.build(self.resource, self.model, update_hash(id, options))
84
+ end
85
+
86
+ # Update model, with class resource by +id+ and given updates
87
+ #
88
+ # Car.update(1, name: 'BMW 7') # => {id: 1, name: 'BMW 7'}
89
+ #
90
+ def update id, options = {}
91
+ result = Client.update self.resource, id, update_payload(id, options)
92
+ result ? result[self.model] : nil
93
+ end
94
+
95
+ private
96
+ # Handle result to return +id+ or array with +ids+ of requested objects
97
+ #
98
+ # handle_result({ customers: { customer: [ 1,2 ] } }) # => [1, 2]
99
+ # handle_result({ customers: { customer: { attr: { id: 1 }} } }) # => [1]
100
+ #
101
+ def handle_result result, options = {}
102
+ if options[:display]
103
+ if result[self.resource].kind_of?(Hash) and result[self.resource][self.model]
104
+ objects = result[self.resource][self.model]
105
+ objects.kind_of?(Array) ? objects : [objects]
106
+ end
107
+ else
108
+ if result[self.resource].kind_of?(Hash) and result[self.resource][self.model]
109
+ [objects = result[self.resource][self.model]]
110
+ objects.kind_of?(Array) ? objects.map{ |o| o[:attr][:id] } : [ objects[:attr][:id] ]
111
+ else
112
+ nil
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ module InstanceMethods
119
+
120
+ # Generate hash with ID
121
+ #
122
+ # car.hash_id(1) # => {id: 1}
123
+ #
124
+ def hash_id id
125
+ { id: id } if id
126
+ end
127
+
128
+ # Make array of unique IDs in hash
129
+ #
130
+ # car.hash_ids(1,2,3) # => [{id: 1},{id: 2},{id: 3}]
131
+ #
132
+ def hash_ids ids
133
+ ids.flatten.uniq.map{|id| hash_id(id)} if ids
134
+ end
135
+
136
+ # Create payload for create new object, coverts hash to XML
137
+ #
138
+ # car.payload # => '<prestashop xmlns:xlink="http://www.w3.org/1999/xlink"><car><name><![CDATA[BMW 7]]></name><manufacturer><![CDATA[BMW]]></manufacturer></car></prestashop>'
139
+ #
140
+ def payload
141
+ Api::Converter.build(self.class.resource, self.class.model, hash)
142
+ end
143
+
144
+ # Create new model from instance, based on class resource a payload generated from
145
+ # hash method
146
+ #
147
+ # Car.new(name: 'BMW 7', manufacturer: 'BMW').create # => { id: 1, name: 'BMW 7', manufacturer: 'BMW' }
148
+ #
149
+ def create
150
+ result = Client.create self.class.resource, payload
151
+ result ? result[self.class.model] : nil
152
+ end
153
+ end
154
+
155
+ def self.included(receiver)
156
+ receiver.extend ClassMethods
157
+ receiver.send :include, InstanceMethods
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,38 @@
1
+ using Prestashop::Mapper::Refinement
2
+ module Prestashop
3
+ module Mapper
4
+ class Model
5
+ include Extension
6
+ extend Extension
7
+
8
+ # Meta title is same as name, when is not given
9
+ def meta_title
10
+ @meta_title ? @meta_title.plain.truncate(61) : name
11
+ end
12
+
13
+ # Meta description is same as description, when is not given
14
+ def meta_description
15
+ @meta_description ? @meta_description.restricted.truncate(252) : ( description_short.plain if description_short )
16
+ end
17
+
18
+ # Meta keywords are generated from name, when are not given
19
+ def meta_keywords
20
+ @meta_keywords ? @meta_keywords.plain.truncate(61) : name.split(' ').join(', ')
21
+ end
22
+
23
+ def hash_lang name, id_lang
24
+ { language: { val: name, attr: { id: id_lang }}} if name
25
+ end
26
+
27
+ class << self
28
+ def resource value = nil
29
+ value.nil? ? @resource : @resource = value
30
+ end
31
+
32
+ def model value = nil
33
+ value.nil? ? @model : @model = value
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1 @@
1
+ Dir[File.dirname(__FILE__) + '/models/*.rb'].each {|file| require file }
@@ -0,0 +1,9 @@
1
+ using Prestashop::Mapper::Refinement
2
+ module Prestashop
3
+ module Mapper
4
+ class Address < Model
5
+ resource :addresses
6
+ model :address
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ using Prestashop::Mapper::Refinement
2
+ module Prestashop
3
+ module Mapper
4
+ class Carrier < Model
5
+ resource :carriers
6
+ model :carrier
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ using Prestashop::Mapper::Refinement
2
+ module Prestashop
3
+ module Mapper
4
+ class Cart < Model
5
+ resource :carts
6
+ model :cart
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ using Prestashop::Mapper::Refinement
2
+ module Prestashop
3
+ module Mapper
4
+ class CartRule < Model
5
+ resource :cart_rules
6
+ model :cart_rule
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,114 @@
1
+ using Prestashop::Mapper::Refinement
2
+ module Prestashop
3
+ module Mapper
4
+ class Category < Model
5
+ resource :categories
6
+ model :category
7
+
8
+ attr_accessor :id_lang
9
+ attr_accessor :id, :id_parent, :level_depth, :active, :id_shop_default, :is_root_category, :position
10
+ attr_writer :name, :description, :link_rewrite
11
+
12
+ def initialize args = {}
13
+ @id = args[:id]
14
+ @id_parent = args.fetch(:id_parent, 2)
15
+ @level_depth = args[:level_depth]
16
+ # nb_products_recursive
17
+ @active = args.fetch(:active, 1)
18
+ @id_shop_default = args.fetch(:id_shop_default, 1)
19
+ @is_root_category = 0
20
+ @position = args[:position]
21
+ # date_add
22
+ # date_upd
23
+ @name = args.fetch(:name)
24
+ @link_rewrite = args[:link_rewrite]
25
+ @description = args[:description]
26
+ @meta_title = args[:meta_title]
27
+ @meta_description = args[:meta_description]
28
+ @meta_keywords = args[:meta_keywords]
29
+
30
+ @id_lang = args.fetch(:id_lang)
31
+ end
32
+
33
+ # Category name can't have some symbols and can't be longer than 63
34
+ def name
35
+ @name.plain.truncate(61)
36
+ end
37
+
38
+ # Description can have additional symbols and can't be longer than 255
39
+ def description
40
+ @description.restricted.truncate(252) if @description
41
+ end
42
+
43
+ # Link rewrite must be usable in uri
44
+ def link_rewrite
45
+ @link_rewrite ? @link_rewrite.parameterize : name.parameterize
46
+ end
47
+
48
+ # Category hash structure, which will be converted to XML
49
+ def hash
50
+ { id_parent: id_parent,
51
+ active: active ,
52
+ id_shop_default: id_shop_default,
53
+ is_root_category: is_root_category,
54
+ name: hash_lang(name, id_lang),
55
+ link_rewrite: hash_lang(link_rewrite, id_lang),
56
+ description: hash_lang(description, id_lang),
57
+ meta_title: hash_lang(name, id_lang),
58
+ meta_description: hash_lang(description, id_lang),
59
+ meta_keywords: hash_lang(meta_keywords, id_lang) }
60
+ end
61
+
62
+ # Find category by name and id parent, create new one from hash, when doesn't exist
63
+ def find_or_create
64
+ category = self.class.find_in_cache id_parent, name, id_lang
65
+ unless category
66
+ category = create
67
+ Client.clear_categories_cache
68
+ end
69
+ category[:id]
70
+ end
71
+
72
+ class << self
73
+
74
+ # Search for category based on args on cached categories, see #cache and #Client::Settings.categories_cache
75
+ # Returns founded category or nil
76
+ #
77
+ def find_in_cache id_parent, name, id_lang
78
+ Client.categories_cache.find{ |c| c[:id_parent] == id_parent and c[:name].find_lang(name, id_lang) }
79
+ end
80
+
81
+ # Requesting all on Prestashop API, displaying id, id_parent, name
82
+ def cache
83
+ all display: '[id, id_parent, name]'
84
+ end
85
+
86
+ # Create new category based on given param, delimited by delimiter in settings
87
+ #
88
+ # ==== Example:
89
+ # Category.create_from_name('Apple||iPhone', 2) # => [1, 2]
90
+ #
91
+ def create_from_name category_name, id_lang
92
+ if category_name and !category_name.empty?
93
+ names = [category_name.split('||')].flatten!
94
+ categories = []
95
+ id_parent = 2
96
+ names.each do |name|
97
+ id_parent = new(name: name, id_parent: id_parent, id_lang: id_lang).find_or_create
98
+ categories << id_parent
99
+ end
100
+ categories
101
+ end
102
+ end
103
+
104
+ def create_from_names category_names, id_lang
105
+ categories = []
106
+ category_names.each do |category_name|
107
+ categories << create_from_name(category_name, id_lang)
108
+ end
109
+ categories.flatten.uniq
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end