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.
- checksums.yaml +4 -4
- data/.gitignore +48 -0
- data/Gemfile.lock +70 -0
- data/VERSION +1 -0
- data/affiliate-window-0.2.0.pre1.gem +0 -0
- data/affiliate-window.gemspec +68 -0
- data/lib/affiliate-window/account.rb +48 -0
- data/lib/affiliate-window/clients/affiliate_service.rb +45 -0
- data/lib/affiliate-window/clients/category.rb +19 -0
- data/lib/affiliate-window/clients/merchant.rb +32 -0
- data/lib/affiliate-window/clients/shop_window.rb +45 -0
- data/lib/affiliate-window/helpers/account.rb +25 -0
- data/lib/affiliate-window/helpers/client.rb +23 -0
- data/lib/affiliate-window/helpers/csv.rb +24 -0
- data/lib/affiliate-window/models/transaction.rb +92 -0
- data/lib/affiliate-window/version.rb +10 -0
- data/spec/affiliate_window/account_spec.rb +33 -0
- data/spec/affiliate_window/clients/affiliate_service_spec.rb +51 -0
- data/spec/affiliate_window/clients/category_spec.rb +39 -0
- data/spec/affiliate_window/clients/merchant_spec.rb +48 -0
- data/spec/affiliate_window/clients/shop_window_spec.rb +41 -0
- data/spec/affiliate_window/helpers/account_spec.rb +0 -0
- data/spec/affiliate_window/helpers/csv_spec.rb +43 -0
- data/spec/affiliate_window/models/transaction_spec.rb +44 -0
- data/spec/affiliate_window_spec.rb +28 -0
- data/spec/fixtures/csv/merchants.csv +3 -0
- data/spec/fixtures/responses/affiliate_service_v3.wsdl +1039 -0
- data/spec/fixtures/responses/get_transaction_list.xml +310 -0
- data/spec/fixtures/responses/gtl.xml +300 -0
- data/spec/fixtures/responses/merchants.csv +32 -0
- data/spec/helper.rb +62 -0
- data/wsdl/affiliate_service_v3.wsdl +1029 -0
- metadata +32 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9111b0e915d1b9ad173bb31f8eb7b75754d5cc39
|
4
|
+
data.tar.gz: 94b8e9859831f34d6b5b3384fa936a416a9f9fbb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5cb0c3655d7049a0850f436b9a546bd71ca2dcf93c6c4131a77c0cea812504a5f2dea360a6870632157a9fadfb16da88ab6ccee145669fbcd166672bbac9dd53
|
7
|
+
data.tar.gz: 42b1d02a62e570d392baaffe3f9839f5b03f8a7f36aec4b96252a0e5c1ca32614581dbdea530cc72754d1f89f1d488c9aa2bad5a5ec9bab6e94f7ab2e316118d
|
data/.gitignore
ADDED
@@ -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
|
data/Gemfile.lock
ADDED
@@ -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
|
Binary file
|
@@ -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
|