affiliate-window 0.2.0.pre1 → 0.2.1.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +48 -0
  3. data/Gemfile.lock +70 -0
  4. data/VERSION +1 -0
  5. data/affiliate-window-0.2.0.pre1.gem +0 -0
  6. data/affiliate-window.gemspec +68 -0
  7. data/lib/affiliate-window/account.rb +48 -0
  8. data/lib/affiliate-window/clients/affiliate_service.rb +45 -0
  9. data/lib/affiliate-window/clients/category.rb +19 -0
  10. data/lib/affiliate-window/clients/merchant.rb +32 -0
  11. data/lib/affiliate-window/clients/shop_window.rb +45 -0
  12. data/lib/affiliate-window/helpers/account.rb +25 -0
  13. data/lib/affiliate-window/helpers/client.rb +23 -0
  14. data/lib/affiliate-window/helpers/csv.rb +24 -0
  15. data/lib/affiliate-window/models/transaction.rb +92 -0
  16. data/lib/affiliate-window/version.rb +10 -0
  17. data/spec/affiliate_window/account_spec.rb +33 -0
  18. data/spec/affiliate_window/clients/affiliate_service_spec.rb +51 -0
  19. data/spec/affiliate_window/clients/category_spec.rb +39 -0
  20. data/spec/affiliate_window/clients/merchant_spec.rb +48 -0
  21. data/spec/affiliate_window/clients/shop_window_spec.rb +41 -0
  22. data/spec/affiliate_window/helpers/account_spec.rb +0 -0
  23. data/spec/affiliate_window/helpers/csv_spec.rb +43 -0
  24. data/spec/affiliate_window/models/transaction_spec.rb +44 -0
  25. data/spec/affiliate_window_spec.rb +28 -0
  26. data/spec/fixtures/csv/merchants.csv +3 -0
  27. data/spec/fixtures/responses/affiliate_service_v3.wsdl +1039 -0
  28. data/spec/fixtures/responses/get_transaction_list.xml +310 -0
  29. data/spec/fixtures/responses/gtl.xml +300 -0
  30. data/spec/fixtures/responses/merchants.csv +32 -0
  31. data/spec/helper.rb +62 -0
  32. data/wsdl/affiliate_service_v3.wsdl +1029 -0
  33. metadata +32 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 09a0b44675f1e1152a6bbeb360477a476bc0dc23
4
- data.tar.gz: 7cead014031b5890df62655fa1856aab4d8638ed
3
+ metadata.gz: 9111b0e915d1b9ad173bb31f8eb7b75754d5cc39
4
+ data.tar.gz: 94b8e9859831f34d6b5b3384fa936a416a9f9fbb
5
5
  SHA512:
6
- metadata.gz: 3ee50bb4caf934327a14ae606ea343a3bad9566e4629002493154c8e5cc5324449921734e9fc248fa533a3fdf9c68521b8ac027b19c21026eb0e30e862fc4042
7
- data.tar.gz: cf74a49976d3648cdebfb2f665bec204c0e46647c22fa72c98d4dc6ae782d1aa1dd741f4e9d86a20e30a50d8c4adb63a901d10916a8b3bdec0a6768691ae76b9
6
+ metadata.gz: 5cb0c3655d7049a0850f436b9a546bd71ca2dcf93c6c4131a77c0cea812504a5f2dea360a6870632157a9fadfb16da88ab6ccee145669fbcd166672bbac9dd53
7
+ data.tar.gz: 42b1d02a62e570d392baaffe3f9839f5b03f8a7f36aec4b96252a0e5c1ca32614581dbdea530cc72754d1f89f1d488c9aa2bad5a5ec9bab6e94f7ab2e316118d
@@ -0,0 +1,48 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # rdoc generated
5
+ rdoc
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # bundler
12
+ .bundle
13
+
14
+ # jeweler generated
15
+ pkg
16
+
17
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
18
+ #
19
+ # * Create a file at ~/.gitignore
20
+ # * Include files you want ignored
21
+ # * Run: git config --global core.excludesfile ~/.gitignore
22
+ #
23
+ # After doing this, these files will be ignored in all your git projects,
24
+ # saving you from having to 'pollute' every project you touch with them
25
+ #
26
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
27
+ #
28
+ # For MacOS:
29
+ #
30
+ #.DS_Store
31
+
32
+ # For TextMate
33
+ #*.tmproj
34
+ #tmtags
35
+
36
+ # For emacs:
37
+ #*~
38
+ #\#*
39
+ #.\#*
40
+
41
+ # For vim:
42
+ #*.swp
43
+
44
+ # For redcar:
45
+ #.redcar
46
+
47
+ # For rubinius:
48
+ #*.rbc
@@ -0,0 +1,70 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ akami (1.0.0)
5
+ gyoku (>= 0.4.0)
6
+ ansi (1.4.1)
7
+ builder (3.0.0)
8
+ fakeweb (1.3.0)
9
+ git (1.2.5)
10
+ gyoku (0.4.4)
11
+ builder (>= 2.1.2)
12
+ hashie (1.2.0)
13
+ httpi (0.9.5)
14
+ rack
15
+ jeweler (1.6.4)
16
+ bundler (~> 1.0)
17
+ git (>= 1.2.5)
18
+ rake
19
+ json (1.6.1)
20
+ metaclass (0.0.1)
21
+ minitest (2.8.1)
22
+ minitest-reporters (0.4.0)
23
+ ansi
24
+ minitest (~> 2.0)
25
+ ruby-progressbar
26
+ mocha (0.10.0)
27
+ metaclass (~> 0.0.1)
28
+ multi_json (1.0.3)
29
+ nokogiri (1.5.0)
30
+ nori (1.0.2)
31
+ rack (1.3.5)
32
+ rake (0.9.2.2)
33
+ rcov (0.9.11)
34
+ rdoc (3.11)
35
+ json (~> 1.4)
36
+ ruby-progressbar (0.0.10)
37
+ savon (0.9.7)
38
+ akami (~> 1.0)
39
+ builder (>= 2.1.2)
40
+ gyoku (>= 0.4.0)
41
+ httpi (~> 0.9)
42
+ nokogiri (>= 1.4.0)
43
+ nori (~> 1.0)
44
+ wasabi (~> 2.0)
45
+ savon_model (1.1.0)
46
+ httpi (>= 0.7.8)
47
+ savon (>= 0.8.2)
48
+ simplecov (0.5.4)
49
+ multi_json (~> 1.0.3)
50
+ simplecov-html (~> 0.5.3)
51
+ simplecov-html (0.5.3)
52
+ wasabi (2.0.0)
53
+ nokogiri (>= 1.4.0)
54
+
55
+ PLATFORMS
56
+ ruby
57
+
58
+ DEPENDENCIES
59
+ bundler (~> 1.0.0)
60
+ fakeweb
61
+ hashie (>= 0.0.0)
62
+ jeweler (~> 1.6.4)
63
+ minitest
64
+ minitest-reporters
65
+ mocha
66
+ rcov
67
+ rdoc
68
+ savon (>= 0.9.7)
69
+ savon_model (>= 0.0.0)
70
+ simplecov
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.1
@@ -0,0 +1,68 @@
1
+ require File.expand_path('../lib/affiliate-window/version', __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "affiliate-window"
5
+ s.version = AffiliateWindow::Version::STRING
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["andy.triggs@gmail.com"]
9
+ s.date = "2011-11-30"
10
+ s.description = "Affiliate Window provide APIs for interacting with their merchant, product and transaction data via your publisher account. This gem provides clients for those APIs."
11
+ s.email = "andy.triggs@gmail.com"
12
+ s.extra_rdoc_files = [
13
+ "LICENSE.txt",
14
+ "README.rdoc"
15
+ ]
16
+ s.files = `git ls-files`.split("\n")
17
+ s.homepage = "http://github.com/andyt/affiliate-window"
18
+ s.licenses = ["MIT"]
19
+ s.require_paths = ["lib"]
20
+ s.rubygems_version = "1.8.10"
21
+ s.summary = "Clients and other publisher tools for using Affiliate Window APIs"
22
+
23
+ if s.respond_to? :specification_version then
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<savon>, [">= 0.9.7"])
28
+ s.add_runtime_dependency(%q<savon_model>, [">= 0.0.0"])
29
+ s.add_runtime_dependency(%q<hashie>, [">= 0.0.0"])
30
+ s.add_development_dependency(%q<minitest>, [">= 0"])
31
+ s.add_development_dependency(%q<minitest-reporters>, [">= 0"])
32
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
33
+ s.add_development_dependency(%q<fakeweb>, [">= 0"])
34
+ s.add_development_dependency(%q<mocha>, [">= 0"])
35
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
36
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
37
+ s.add_development_dependency(%q<rcov>, [">= 0"])
38
+ s.add_development_dependency(%q<rdoc>, [">= 0"])
39
+ else
40
+ s.add_dependency(%q<savon>, [">= 0.9.7"])
41
+ s.add_dependency(%q<savon_model>, [">= 0.0.0"])
42
+ s.add_dependency(%q<hashie>, [">= 0.0.0"])
43
+ s.add_dependency(%q<minitest>, [">= 0"])
44
+ s.add_dependency(%q<minitest-reporters>, [">= 0"])
45
+ s.add_dependency(%q<simplecov>, [">= 0"])
46
+ s.add_dependency(%q<fakeweb>, [">= 0"])
47
+ s.add_dependency(%q<mocha>, [">= 0"])
48
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
49
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
50
+ s.add_dependency(%q<rcov>, [">= 0"])
51
+ s.add_dependency(%q<rdoc>, [">= 0"])
52
+ end
53
+ else
54
+ s.add_dependency(%q<savon>, [">= 0.9.7"])
55
+ s.add_dependency(%q<savon_model>, [">= 0.0.0"])
56
+ s.add_dependency(%q<hashie>, [">= 0.0.0"])
57
+ s.add_dependency(%q<minitest>, [">= 0"])
58
+ s.add_dependency(%q<minitest-reporters>, [">= 0"])
59
+ s.add_dependency(%q<simplecov>, [">= 0"])
60
+ s.add_dependency(%q<fakeweb>, [">= 0"])
61
+ s.add_dependency(%q<mocha>, [">= 0"])
62
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
63
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
64
+ s.add_dependency(%q<rcov>, [">= 0"])
65
+ s.add_dependency(%q<rdoc>, [">= 0"])
66
+ end
67
+ end
68
+
@@ -0,0 +1,48 @@
1
+ module AffiliateWindow
2
+ class Account
3
+ attr_reader :user, :api_password, :api_key, :datafeed_password, :format, :compression
4
+
5
+ VALID_FORMATS = %w{CSV} # XML not yet supported.
6
+
7
+ # Unzipping is not supported for portability, but you can specify it to download a zipped file.
8
+ # CSV helper methods won't work with zipped downloads.
9
+ VALID_COMPRESSIONS = %w{none zip}
10
+
11
+ def initialize(options)
12
+ @user ||= options[:user] || raise(ArgumentError, ":user option is required.")
13
+ @api_password ||= options[:api_password] || raise(ArgumentError, ":api_password option is required.")
14
+ @api_key ||= options[:api_key] || raise(ArgumentError, ":api_key option is required.")
15
+ @datafeed_password ||= options[:datafeed_password] || raise(ArgumentError, ":datafeed_password option is required.")
16
+ self.format = options[:format] || VALID_FORMATS.first
17
+ self.compression = options[:compression] || VALID_COMPRESSIONS.first
18
+ end
19
+
20
+ def format=(value)
21
+ value = value.upcase.to_s
22
+ raise ArgumentError, "Invalid format #{value} - use #{VALID_FORMATS.join(', ')}." unless VALID_FORMATS.include?(value)
23
+ @format = value
24
+ end
25
+
26
+ def compression=(value)
27
+ value = value.downcase.to_s
28
+ raise ArgumentError, "Invalid compression #{value} - use #{VALID_COMPRESSIONS.join(', ')}." unless VALID_COMPRESSIONS.include?(value)
29
+ @compression = value
30
+ end
31
+
32
+ def compression_parameter
33
+ @compression == 'none' ? '' : @compression
34
+ end
35
+
36
+ def attributes
37
+ {
38
+ :user => user,
39
+ :api_password => api_password,
40
+ :api_key => api_key,
41
+ :datafeed_password => datafeed_password,
42
+ :format => format,
43
+ :compression => compression
44
+ }
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,45 @@
1
+ module AffiliateWindow::Clients
2
+
3
+ # SOAP client for the AffiliateWindow AffiliateService API.
4
+ #
5
+ # Instantiate carefully! This parses the WSDL document every time.
6
+ class AffiliateService < Savon::Client
7
+
8
+ include AffiliateWindow::Helpers::Account
9
+
10
+ ENDPOINT_URL = 'http://api.affiliatewindow.com/v3/AffiliateService'
11
+
12
+ WSDL_URL = ENDPOINT_URL + '?wsdl'
13
+
14
+ CACHED_WSDL_PATH = File.join(File.dirname(__FILE__), '..', '..', '..', 'wsdl', 'affiliate_service_v3.wsdl')
15
+
16
+ ACTIONS = [:get_transaction_list, :get_transaction_product, :get_transaction, :get_merchant_list, :get_merchant, :get_transaction_querys, :set_transaction_query, :get_impression_stats, :get_click_stats, :get_commission_group, :get_commission_group_list]
17
+
18
+ def initialize(account = nil)
19
+ set_account(account)
20
+ super(CACHED_WSDL_PATH)
21
+ end
22
+
23
+ # Override the request method so that we can inject the authentication header.
24
+ def request(*args, &block)
25
+ super(*args) do
26
+ soap.header = header
27
+ process &block if block
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # We need 'UserAuthenication' as a string due to the odd capitalisation.
34
+ def header
35
+ {
36
+ 'UserAuthentication' => {
37
+ :i_id => user,
38
+ :s_password => api_password,
39
+ :s_type => 'affiliate'
40
+ }
41
+ }
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,19 @@
1
+ module AffiliateWindow::Clients
2
+
3
+ class Category
4
+
5
+ include AffiliateWindow::Helpers::Account
6
+ include AffiliateWindow::Helpers::Csv
7
+
8
+ URL_TEMPLATE = 'http://datafeeds.productserve.com/datafeed_category.php?user=#{user}&password=#{datafeed_password}&format=#{format}&compression=#{compression_parameter}'
9
+
10
+ def initialize(account = nil)
11
+ set_account(account)
12
+ end
13
+
14
+ def url
15
+ @url ||= eval(%Q|"#{URL_TEMPLATE}"|)
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ module AffiliateWindow::Clients
2
+
3
+ class Merchant
4
+
5
+ include AffiliateWindow::Helpers::Account
6
+ include AffiliateWindow::Helpers::Csv
7
+
8
+ attr :filter
9
+
10
+ URL_TEMPLATE = 'https://www.affiliatewindow.com/affiliates/shopwindow/datafeed_metadata.php?user=#{user}&password=#{datafeed_password}&format=#{format}&filter=#{filter}&compression='
11
+
12
+ VALID_FILTERS = %w{SUBSCRIBED_ALL SUBSCRIBED_ENABLED ALL_ALL ALL_ENABLED}
13
+
14
+ def initialize(filter = nil, account = nil)
15
+ set_account(account)
16
+ self.filter = filter || VALID_FILTERS.first
17
+ end
18
+
19
+ def url
20
+ @url ||= eval(%Q|"#{URL_TEMPLATE}"|)
21
+ end
22
+
23
+ private
24
+
25
+ def filter=(value)
26
+ value = value.to_s.upcase
27
+ raise ArgumentError unless VALID_FILTERS.include?(value)
28
+ @filter = value
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ module AffiliateWindow
2
+ module Clients
3
+
4
+ class ShopWindow
5
+
6
+ include AffiliateWindow::Helpers::Client
7
+ include AffiliateWindow::Helpers::Account
8
+ include AffiliateWindow::Helpers::Csv
9
+
10
+ attr :merchant_ids
11
+
12
+ # This URL template only works for a selection of merchants by ID.
13
+ # It ignores the compression setting in account. Valid options are zip or gzip. We use zip.
14
+ URL_TEMPLATE = 'http://datafeed.api.productserve.com/datafeed/download/apikey/#{api_key}/mid/#{merchant_id_list}/columns/#{column_list}/format/#{format.downcase}/compression/zip/'
15
+
16
+ DEFAULT_COLUMNS = %w{ merchant_id merchant_name aw_product_id merchant_product_id product_name description
17
+ category_id category_name merchant_category aw_deep_link aw_image_url search_price
18
+ delivery_cost merchant_deep_link merchant_image_url mpn rrp_price stock_quantity
19
+ brand_id ean merchant_thumb_url brand_name in_stock model_number specifications upc }
20
+
21
+ def initialize(options = {})
22
+ parse_options(options)
23
+ end
24
+
25
+ def url
26
+ @url ||= eval(%Q|"#{URL_TEMPLATE}"|)
27
+ end
28
+
29
+ def columns
30
+ @columns || DEFAULT_COLUMNS
31
+ end
32
+
33
+ private
34
+
35
+ def column_list
36
+ columns.join(',')
37
+ end
38
+
39
+ def merchant_id_list
40
+ merchant_ids.join(',')
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,25 @@
1
+ module AffiliateWindow::Helpers
2
+
3
+ # Helper methods for account delegation and using a default account.
4
+ module Account
5
+
6
+ attr_accessor :account
7
+
8
+ # Some delegation methods (avoids having a delegation dependency).
9
+ def user; account.user; end
10
+ def datafeed_password; account.datafeed_password; end
11
+ def api_password; account.api_password; end
12
+ def api_key; account.api_key; end
13
+
14
+ def format; account.format; end
15
+ def compression_parameter; account.compression_parameter; end
16
+
17
+ # Sets @account to the passed account, or a defined default.
18
+ def set_account(account)
19
+ @account = account || AffiliateWindow.account
20
+ raise ArgumentError, "Pass the account parameter, or set AffiliateWindow.account." unless @account
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,23 @@
1
+ module AffiliateWindow::Helpers
2
+
3
+ # Helper methods for client classes.
4
+ module Client
5
+
6
+ def parse_options(options)
7
+ set_account(options.delete(:account))
8
+ options.each do |k, v|
9
+ if respond_to?(k)
10
+ instance_variable_set("@#{k}", v)
11
+ else
12
+ raise ArgumentError, "Unknown option #{k}."
13
+ end
14
+ end
15
+ end
16
+
17
+ def fetch(target = Tempfile.new('awin').path)
18
+ AffiliateWindow.fetch(url, target)
19
+ end
20
+
21
+ end
22
+
23
+ end