affiliate-window 0.2.0.pre1 → 0.2.1.pre1

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 (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