prestashop 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1291cdd4ec02957e3b8058a784734e426df08d36
4
+ data.tar.gz: e0fe83e41d5c20b43eaf355119dfb9d6e39f8718
5
+ SHA512:
6
+ metadata.gz: 3a5fce92fe802fa44b438a79419a98f3fde3f5f4b2a19e8c459e8ba848f074d1dafee6aa0b04907bb5b5abe4c4b395106f69d2d45b5683c1c8b2dd3c27e8f84a
7
+ data.tar.gz: 05016ad705c0d9f49c352ef9d8dffaa203f267db3a60b0de632dbe0a363c176f2ad22c208087022a6e84fbf758a21828e99710617989eb4f6a15cca24ba7a760
@@ -0,0 +1,56 @@
1
+ Attribution-NonCommercial-NoDerivs 2.5
2
+
3
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.
4
+ License
5
+
6
+ THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
7
+
8
+ BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
9
+
10
+ 1. Definitions
11
+
12
+ "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.
13
+ "Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License.
14
+ "Licensor" means the individual or entity that offers the Work under the terms of this License.
15
+ "Original Author" means the individual or entity who created the Work.
16
+ "Work" means the copyrightable work of authorship offered under the terms of this License.
17
+ "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
18
+ 2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws.
19
+
20
+ 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
21
+
22
+ to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;
23
+ to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;
24
+ The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats, but otherwise you have no rights to make Derivative Works. All rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Sections 4(d) and 4(e).
25
+
26
+ 4. Restrictions.The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
27
+
28
+ You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by clause 4(c), as requested.
29
+ You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works.
30
+ If you distribute, publicly display, publicly perform, or publicly digitally perform the Work, You must keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; and to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work. Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit.
31
+ For the avoidance of doubt, where the Work is a musical composition:
32
+
33
+ Performance Royalties Under Blanket Licenses. Licensor reserves the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work if that performance is primarily intended for or directed toward commercial advantage or private monetary compensation.
34
+ Mechanical Rights and Statutory Royalties. Licensor reserves the exclusive right to collect, whether individually or via a music rights agency or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions), if Your distribution of such cover version is primarily intended for or directed toward commercial advantage or private monetary compensation.
35
+ Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor reserves the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions), if Your public digital performance is primarily intended for or directed toward commercial advantage or private monetary compensation.
36
+ 5. Representations, Warranties and Disclaimer
37
+
38
+ UNLESS OTHERWISE MUTUALLY AGREED BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
39
+
40
+ 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
41
+
42
+ 7. Termination
43
+
44
+ This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
45
+ Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
46
+ 8. Miscellaneous
47
+
48
+ Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
49
+ If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
50
+ No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
51
+ This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
52
+ Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor.
53
+
54
+ Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, neither party will use the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time.
55
+
56
+ Creative Commons may be contacted at http://creativecommons.org/.
@@ -0,0 +1,111 @@
1
+ # Prestashop
2
+
3
+ [![Build Status](https://travis-ci.org/werein/prestashop.svg)](https://travis-ci.org/werein/prestashop) [![Code Climate](https://codeclimate.com/github/werein/prestashop/badges/gpa.svg)](https://codeclimate.com/github/werein/prestashop) [![Test coverage](https://codeclimate.com/github/werein/prestashop/badges/coverage.svg)](https://codeclimate.com/github/werein/prestashop) [![Version](https://badge.fury.io/rb/prestashop.svg)](http://badge.fury.io/rb/prestashop) [![Dependencies](https://gemnasium.com/werein/prestashop.svg)](https://gemnasium.com/werein/prestashop)
4
+
5
+ Prestashop API for Ruby
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'prestashop', github: 'werein/prestashop'
13
+ ```
14
+
15
+ Use `branch: 'master'` for local repository in case of bundler global config
16
+
17
+ ## Usage
18
+
19
+ Create new client for connect to your Prestashop WebService
20
+
21
+ ```ruby
22
+ Prestashop::Client::Implementation.create 'api_key', 'api_url'
23
+ ```
24
+
25
+ Now you are able to communicate with Prestashop WebService
26
+
27
+ ### Low-level API
28
+
29
+ To call API request directly you can use this class.
30
+
31
+ ##### Head / Check
32
+
33
+ Call HEAD on WebService API, returns +true+ if was request successfull or raise error, when request failed.
34
+
35
+ ``` ruby
36
+ Prestashop::Client.head :customer, 2 # => true
37
+ Prestashop::Client.check :customer, 3 # => true
38
+ ```
39
+
40
+ ##### Get / Read
41
+
42
+ Call GET on WebService API, returns parsed Prestashop response or raise error, when request failed.
43
+
44
+ ```ruby
45
+ Prestashop::Client.get :customer, 1 # => {id: 1 ...}
46
+ Prestashop::Client.read :customer, [1,2] # => [{id: 1}, {id: 2}]
47
+ ```
48
+
49
+ When you are using get, you can also filter, sort or limit response. In case, when you need to get all users you need to set user id as `nil`
50
+
51
+ **Available options:**
52
+
53
+ * filter
54
+ * display
55
+ * sort
56
+ * limit
57
+ * schema
58
+ * date
59
+
60
+ ##### Post / Create
61
+ Call POST on WebService API, returns parsed Prestashop response if was request successfull or raise error, when request failed.
62
+
63
+ ```ruby
64
+ Prestashop::Client.post :customer, { name: 'Steve' } # => true
65
+ ```
66
+
67
+ ##### Put / Update
68
+
69
+ Call PUT on WebService API, returns parsed Prestashop response if was request successfull or raise error, when request failed.
70
+
71
+ ```ruby
72
+ Prestashop::Client.put :customer, 1, {surname: 'Jobs'} # => true
73
+ Prestashop::Client.update :customer, 1, {nope: 'Jobs'} # => false
74
+ ```
75
+
76
+ ##### Delete / Destroy
77
+
78
+ Call DELETE on WebService API, returns +true+ if was request successfull or raise error, when request failed.
79
+
80
+ ```ruby
81
+ Prestashop::Client.delete :customer, 1 # => true
82
+ ```
83
+
84
+ ### Mapper
85
+
86
+ Please read inline docs inside `lib/prestashop/mapper/extension.rb`, available models are defined in `lib/prestashop/mapper/models`
87
+
88
+ After reading that you can do something like this
89
+
90
+ ```ruby
91
+ id_lang = Prestashop::Mapper::Language.find_by_iso_code('cs')
92
+ id_supplier = Prestashop::Mapper::Supplier.new(name: 'apple').find_or_create
93
+
94
+ product = Prestashop::Mapper::Product.new(id_lang: id_lang, id_supplier: id_supplier, reference: 'apple-macbook')
95
+
96
+ if product.find?
97
+ product.update price: '1299'
98
+ else
99
+ product.description = 'My description'
100
+ product.price = '1299'
101
+ product.create
102
+ end
103
+ ```
104
+
105
+ ## Contributing
106
+
107
+ 1. Fork it
108
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
109
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
110
+ 4. Push to the branch (`git push origin my-new-feature`)
111
+ 5. Create new Pull Request
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ end
7
+
8
+ desc 'Run tests'
9
+ task default: :test
@@ -0,0 +1,21 @@
1
+ require 'prestashop/api'
2
+ require 'prestashop/client'
3
+ require 'prestashop/mapper'
4
+
5
+ # == This module is wrapper of three submodules API, Client and Mapper
6
+ #
7
+ # === API
8
+ # Is used for comunication with Prestashop WebService
9
+ #
10
+ # === Client
11
+ # Create instance of API, it's holded on current thread
12
+ #
13
+ # === Mapper
14
+ # Map available Prestashop objects to class and instances.
15
+ #
16
+ # @see Api
17
+ # @see Client
18
+ # @see Mapper
19
+ #
20
+ module Prestashop
21
+ end
@@ -0,0 +1,9 @@
1
+ require 'prestashop/api/refinement'
2
+ require 'prestashop/api/error'
3
+ require 'prestashop/api/converter'
4
+ require 'prestashop/api/connection'
5
+
6
+ module Prestashop
7
+ module Api
8
+ end
9
+ end
@@ -0,0 +1,225 @@
1
+ require 'faraday'
2
+ require 'mini_magick'
3
+ require 'tempfile'
4
+
5
+ using Prestashop::Api::Refinement
6
+ module Prestashop
7
+ module Api
8
+ class Connection
9
+ attr_reader :api_key, :api_url
10
+
11
+ # Create new connection. Raise error, when is not possible validate connection from any reason
12
+ #
13
+ # Prestashop::Api::Connection.new 'TOKEN342', 'mystore.com'
14
+ #
15
+ def initialize api_key, api_url
16
+ @api_key = api_key
17
+ self.api_url = api_url
18
+
19
+ raise InvalidCredentials unless self.test
20
+ end
21
+
22
+ # Convert url to suitable for Prestashop API
23
+ #
24
+ # @connection.api_url = 'mystore.com' # => http://mystore.com/api/
25
+ #
26
+ def api_url= url
27
+ url.gsub!(/^(http|https):\/\//,'')
28
+ url = 'http://' + url
29
+ url << '/' unless url.end_with? '/'
30
+ url << 'api/' unless url.end_with? 'api/'
31
+ @api_url = url
32
+ end
33
+
34
+ # Create connection based on connection instance, returns +Faraday::Connection+
35
+ # which can be usedo for API call
36
+ #
37
+ def connection
38
+ Faraday.new do |builder|
39
+ builder.url_prefix = api_url
40
+ builder.request :multipart
41
+ builder.request :url_encoded
42
+ builder.request :retry, 5
43
+ # builder.response :logger
44
+ builder.adapter :net_http
45
+ builder.basic_auth api_key, ''
46
+ end
47
+ end
48
+
49
+ # Generate path for API request
50
+ #
51
+ # path(:customers, 1) # => "customers/1"
52
+ # path(:customers, [1, 5]) # => "customers?id=[1,5]"
53
+ #
54
+ def path resource, id = nil
55
+ path = resource.to_s
56
+ path += id.kind_of?(Array) ? "?id=[#{id.join(',')}]" : "/#{id}" if id
57
+ path
58
+ end
59
+
60
+ # Generate path for API upload request
61
+ #
62
+ # upload_path :image, :products, 2 # => /images/products/2
63
+ #
64
+ def upload_path type, resource, id
65
+ "#{type}/#{resource}/#{id}"
66
+ end
67
+
68
+ # Call HEAD on WebService API, returns +true+ if was request successfull or raise error, when request failed.
69
+ # Can be called as +check+ instead +head+
70
+ #
71
+ # head :customer, 2 # => true
72
+ # check :customer, 3 # => true
73
+ #
74
+ def head resource, id = nil
75
+ raise ArgumentError, "resource: #{resource} must be string or symbol" unless resource.kind_of?(String) or resource.kind_of?(Symbol)
76
+ raise ArgumentError, "id: #{id} must be integer or nil" unless id.to_i.kind_of?(Integer) or id == nil
77
+
78
+ request_path = path(resource, id)
79
+ response = connection.head request_path
80
+ if response.success?
81
+ true # response.body
82
+ else
83
+ raise RequestFailed.new(response), response.body.parse_error
84
+ end
85
+ rescue ParserError
86
+ raise ParserError, "Response couldn't be parsed for: #{request_path}. RESPONSE: #{response.body}"
87
+ end
88
+ alias :check :head
89
+
90
+ # Call GET on WebService API, returns parsed Prestashop response or raise error, when request failed.
91
+ # Can be called as +read+ instead +get+
92
+ #
93
+ # get :customer, 1 # => {id: 1 ...}
94
+ # read :customer, [1,2] # => [{id: 1}, {id: 2}]
95
+ #
96
+ # available options::
97
+ # * filter
98
+ # * display
99
+ # * sort
100
+ # * limit
101
+ # * schema
102
+ # * date
103
+ #
104
+ def get resource, id = nil, opts = {}
105
+ id.to_i unless id.kind_of?(Array)
106
+ raise ArgumentError, "resource: #{resource} must be string or symbol" unless resource.kind_of?(String) or resource.kind_of?(Symbol)
107
+ raise ArgumentError, "id: #{id} must be integer, array or nil" unless id.kind_of?(Integer) or id.kind_of?(Array) or id == nil
108
+
109
+ white_list = %w(filter display sort limit schema date)
110
+ params = {}
111
+ opts.each do |name, value|
112
+ if white_list.include? name.to_s.split('[').first
113
+ params[name.to_sym] = value
114
+ end
115
+ end
116
+
117
+ request_path = path(resource, id)
118
+ response = connection.get request_path, params
119
+ if response.success?
120
+ response.body.parse
121
+ else
122
+ raise RequestFailed.new(response), response.body.parse_error
123
+ end
124
+ rescue ParserError
125
+ raise ParserError, "Response couldn't be parsed for: #{request_path} with #{params}. RESPONSE: #{response.body}"
126
+ end
127
+ alias :read :get
128
+
129
+ # Call POST on WebService API, returns parsed Prestashop response if was request successfull or raise error, when request failed.
130
+ # Can be called as +create+ insted of +put+
131
+ #
132
+ # post :customer, { name: 'Steve' } # => true
133
+ #
134
+ def post resource, payload
135
+ raise ArgumentError, "resource: #{resource} must be string or symbol" unless resource.kind_of?(String) or resource.kind_of?(Symbol)
136
+
137
+ request_path = path(resource)
138
+ response = connection.post request_path, payload
139
+ if response.success?
140
+ response.body.parse
141
+ else
142
+ raise RequestFailed.new(response), "#{response.body.parse_error}. XML SENT: #{payload}"
143
+ end
144
+ rescue ParserError
145
+ raise ParserError, "Response couldn't be parsed for: #{request_path}. RESPONSE: #{response.body} XML SENT: #{payload}"
146
+ end
147
+ alias :create :post
148
+
149
+ # Call PUT on WebService API, returns parsed Prestashop response if was request successfull or raise error, when request failed.
150
+ # Can be called as +update+ instead +put+
151
+ #
152
+ # put :customer, 1, {surname: 'Jobs'} # => true
153
+ # update :customer, 1, {nope: 'Jobs'} # => false
154
+ #
155
+ def put resource, id, payload
156
+ raise ArgumentError, "resource: #{resource} must be string or symbol" unless resource.kind_of?(String) or resource.kind_of?(Symbol)
157
+ raise ArgumentError, "id: #{id} must be integer" unless id.to_i.kind_of?(Integer)
158
+
159
+ request_path = path(resource, id)
160
+ response = connection.put request_path, payload
161
+ if response.success?
162
+ response.body.parse
163
+ else
164
+ raise RequestFailed.new(response), "#{response.body.parse_error}. XML SENT: #{payload}"
165
+ end
166
+ rescue ParserError
167
+ raise ParserError, "Response couldn't be parsed for: #{request_path}. RESPONSE: #{response.body} XML SENT: #{payload}"
168
+ end
169
+ alias :update :put
170
+
171
+ # Call DELETE on WebService API, returns +true+ if was request successfull or raise error, when request failed.
172
+ #
173
+ # delete :customer, 1 # => true
174
+ #
175
+ def delete resource, id
176
+ raise ArgumentError, "resource: #{resource} must be string or symbol" unless resource.kind_of?(String) or resource.kind_of?(Symbol)
177
+ raise ArgumentError, "id: #{id} must be integer" unless id.to_i.kind_of?(Integer)
178
+
179
+ request_path = path(resource, id)
180
+ response = connection.delete request_path
181
+ if response.success?
182
+ true # response.body
183
+ else
184
+ raise RequestFailed.new(response), response.body.parse_error
185
+ end
186
+ rescue ParserError
187
+ raise ParserError, "Response couldn't be parsed for: #{request_path}. RESPONSE: #{response.body} XML SENT: #{payload}"
188
+ end
189
+ alias :destroy :delete
190
+
191
+
192
+ # Send file via payload After that call POST on WebService API, returns parsed Prestashop response if was request successfull or raise error, when request failed.
193
+ #
194
+ # upload :image, :customer, 2, {image: '/file/to/path.png'}, file
195
+ #
196
+ # @param type [Type (image, attachement)]
197
+ # @param resource [Resource of uploaded item]
198
+ # @param id [ID of uploaded item]
199
+ # @param payload [Attachement in hash with file path]
200
+ # @param file [Original file]
201
+ #
202
+ def upload type, resource, id, payload, file
203
+ raise ArgumentError, "type: #{type} must be string or symbol" unless resource.kind_of?(String) or resource.kind_of?(Symbol)
204
+ raise ArgumentError, "resource: #{resource} must be string or symbol" unless resource.kind_of?(String) or resource.kind_of?(Symbol)
205
+ raise ArgumentError, "id: #{id} must be integer" unless id.to_i.kind_of?(Integer)
206
+
207
+ request_path = upload_path(type, resource, id)
208
+ response = connection.post request_path, payload
209
+ file.destroy!
210
+ if response.success?
211
+ response.body.parse
212
+ else
213
+ raise RequestFailed.new(response), response.body.parse_error
214
+ end
215
+ rescue ParserError
216
+ raise ParserError, "Response couldn't be parsed for: #{request_path}. RESPONSE: #{response.body} XML SENT: #{payload}"
217
+ end
218
+
219
+ # Test connection based on current credentials and connection, return true or false, based if request was successfull or not.
220
+ def test
221
+ connection.get.status == 200 ? true : false
222
+ end
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,152 @@
1
+ require 'nokogiri'
2
+
3
+ module Prestashop
4
+ module Api
5
+ module Converter
6
+
7
+ # Build XML from given params and hash. This XML is compatible with Prestashop WebService
8
+ #
9
+ # Converter.build :customers, :customer, { name: 'Steve' } # => <prestashop><customers><customer>....</customer></customers></prestashop>
10
+ #
11
+ def self.build resource, model, hash
12
+ Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |ml|
13
+ ml.prestashop("xmlns:xlink" => "http://www.w3.org/1999/xlink") {
14
+ ml.send(model.to_s) {
15
+ build_nodes ml, hash
16
+ }
17
+ }
18
+ end.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION).strip
19
+ end
20
+
21
+ # Parse XML (response from WebService call) to Hash, skipping first <prestashop> node.
22
+ #
23
+ # Converter.parse('<prestashop><customers><customer><name>Steve</customer></customers></prestashop>')
24
+ # # => {customers: [ customer: { name: 'Steve' } ]}
25
+ #
26
+ def self.parse xml
27
+ result = Nokogiri::XML xml
28
+
29
+ raise ParserError unless result.root
30
+
31
+ xml_node_to_hash result.root
32
+ end
33
+
34
+ # Parse XML to Hash, call parse and skip everything to error message
35
+ #
36
+ def self.parse_error response
37
+ parsed = parse(response)
38
+ if parsed[:errors] and parsed[:errors][:error] and parsed[:errors][:error][:message]
39
+ parsed[:errors][:error][:message]
40
+ else
41
+ raise ParserError
42
+ end
43
+ end
44
+
45
+ # Build XML nodes based from given source parameter, skipping +attr+ or +val+ keys if source is Hash
46
+ #
47
+ # ==== Parameters:
48
+ # * +ml+ - Current XML
49
+ # * +source+ - Source, which will be converted into the XML
50
+ #
51
+ def self.build_nodes ml, source, mkey = nil
52
+ unless source[:attr] and source[:val]
53
+ source.each do |key, value|
54
+ if value.kind_of? Hash
55
+ if value[:attr]
56
+ ml.send(key, value[:attr]){
57
+ cdata ml, value[:val]
58
+ build_nodes ml, value
59
+ }
60
+ elsif key != :attr
61
+ ml.send(key){
62
+ unless value.kind_of? Hash
63
+ cdata ml, value
64
+ end
65
+ build_nodes ml, value
66
+ }
67
+ end
68
+ elsif value.kind_of? Array
69
+ value.each do |item|
70
+ hash = {}
71
+ hash[key] = item
72
+ build_nodes ml, hash
73
+ end
74
+ elsif key != :val
75
+ ml.send(key){
76
+ cdata ml, value
77
+ }
78
+ end
79
+ end if source.kind_of? Hash
80
+ end
81
+ end
82
+
83
+ # Create CDATA tag into XML, when is not empty
84
+ #
85
+ def self.cdata ml, value
86
+ if value and value != ''
87
+ ml.cdata value
88
+ end
89
+ end
90
+
91
+ # Parse XML node and covert it to hash
92
+ #
93
+ # Converter.xml_node_to_hash '<customer id_lang="1">Steve</customer>'
94
+ # # => { attr: { id_lang: 1 }, val: 'Steve' }
95
+ #
96
+ def self.xml_node_to_hash node
97
+ # If we are at the root of the document, start the hash
98
+ if node.element?
99
+ result_hash = {}
100
+ if node.attributes != {}
101
+ if node.attributes
102
+ node.attributes.each do |key, value|
103
+ unless value.name == 'href'
104
+ result_hash[:attr] = {} unless result_hash[:attr]
105
+ result_hash[:attr][value.name.to_sym] = prepare(value.value)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ if node.children.size > 0
111
+ node.children.each do |child|
112
+ result = xml_node_to_hash(child)
113
+ if child.name == "text"
114
+ unless child.next_sibling || child.previous_sibling
115
+ if !result_hash.empty?
116
+ result_hash[:val] = prepare(result)
117
+ return result_hash
118
+ end
119
+ return prepare(result)
120
+ end
121
+ elsif child.name == "#cdata-section"
122
+ if !result_hash.empty?
123
+ result_hash[:val] = prepare(result)
124
+ return result_hash
125
+ end
126
+ return prepare(result)
127
+ elsif result_hash[child.name.to_sym]
128
+ if result_hash[child.name.to_sym].is_a?(Object::Array)
129
+ result_hash[child.name.to_sym] << prepare(result)
130
+ else
131
+ result_hash[child.name.to_sym] = [result_hash[child.name.to_sym]] << prepare(result)
132
+ end
133
+ else
134
+ result_hash[child.name.to_sym] = prepare(result)
135
+ end
136
+ end
137
+
138
+ return result_hash
139
+ else
140
+ return result_hash
141
+ end
142
+ else
143
+ return prepare(node.content.to_s)
144
+ end
145
+ end
146
+
147
+ def self.prepare data
148
+ (data.class == String && data.to_i.to_s == data) ? data.to_i : data
149
+ end
150
+ end
151
+ end
152
+ end