itunes_ingestion 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/LICENSE +22 -0
- data/README.md +27 -0
- data/VERSION +1 -1
- data/lib/itunes_ingestion.rb +5 -88
- data/lib/itunes_ingestion/fetcher.rb +54 -0
- data/lib/itunes_ingestion/sales_report_parser.rb +59 -0
- data/spec/fetcher_spec.rb +6 -0
- data/spec/fixtures/report.txt +3 -0
- data/spec/sales_report_parser_spec.rb +20 -0
- metadata +15 -7
- data/README.rdoc +0 -0
data/Gemfile.lock
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2012 Francis Chong.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# itunes_ingestion
|
2
|
+
|
3
|
+
A Ruby client library for fetching and downloading iTunes Connect sales report.
|
4
|
+
|
5
|
+
## A note about versions
|
6
|
+
|
7
|
+
Versions *0.3.x* is a breaking change, please update code that based on pre 0.3.x versions.
|
8
|
+
|
9
|
+
## Getting started
|
10
|
+
|
11
|
+
To fetch report, use following code:
|
12
|
+
|
13
|
+
require "itunes_ingestion"
|
14
|
+
|
15
|
+
fetcher = ITunesIngestion::Fetcher.new("username", "password", "vadnumber")
|
16
|
+
report_data = fetcher.fetch("20120202")
|
17
|
+
|
18
|
+
To parse fetched report, use following code:
|
19
|
+
|
20
|
+
require "itunes_ingestion"
|
21
|
+
|
22
|
+
report = ITunesIngestion::SalesReportParser.parse(report_data)
|
23
|
+
|
24
|
+
## Copyright
|
25
|
+
|
26
|
+
Copyright (c) 2012 Francis Chong. See LICENSE for details.
|
27
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/itunes_ingestion.rb
CHANGED
@@ -1,89 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
class AutoIngestion
|
4
|
-
attr_reader :response
|
5
|
-
|
6
|
-
BASE_URL = "https://reportingitc.apple.com/autoingestion.tft?"
|
1
|
+
module ITunesIngestion
|
2
|
+
class ITunesConnectError < RuntimeError; end
|
7
3
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
REPORT_SUMMARY = "Summary"
|
13
|
-
REPORT_OPT_IN = "Opt-In"
|
14
|
-
|
15
|
-
PRODUCT_TYPE_IDENTIFIER = {
|
16
|
-
"1" => "Free or Paid Apps, iPhone and iPod Touch",
|
17
|
-
"7" => "Updates, iPhone and iPod Touch",
|
18
|
-
"IA1" => "In Apps Purchase",
|
19
|
-
"IA9" => "In Apps Subscription",
|
20
|
-
"IAY" => "Auto-Renewable Subscription",
|
21
|
-
"1F" => "Free or Paid Apps (Universal)",
|
22
|
-
"7F" => "Updates (Universal)",
|
23
|
-
"1T" => "Free or Paid Apps, iPad",
|
24
|
-
"7T" => "Updates, iPad",
|
25
|
-
"F1" => "Free or Paid Apps, Mac OS",
|
26
|
-
"F7" => "Updates, Mac OS",
|
27
|
-
"FI1" => "In Apps Purchase, Mac OS",
|
28
|
-
"1E" => "Custome iPhone and iPod Touch",
|
29
|
-
"1EP" => "Custome iPad",
|
30
|
-
"1EU" => "Custome Universal"
|
31
|
-
}
|
32
|
-
|
33
|
-
def initialize(username, password, vadnumber)
|
34
|
-
@username = username
|
35
|
-
@password = password
|
36
|
-
@vadnumber = vadnumber
|
37
|
-
end
|
38
|
-
|
39
|
-
def fetch(options={})
|
40
|
-
params = {
|
41
|
-
:USERNAME => @username, :PASSWORD => @password, :VNDNUMBER => @vadnumber
|
42
|
-
}
|
43
|
-
params[:TYPEOFREPORT] = options[:type_of_report] || REPORT_TYPE_SALES
|
44
|
-
params[:DATETYPE] = options[:date_type] || DATE_TYPE_DAILY
|
45
|
-
params[:REPORTTYPE] = options[:report_type] || REPORT_SUMMARY
|
46
|
-
params[:REPORTDATE] = options[:report_date] || (Time.now-60*60*24).strftime("%Y%m%d")
|
47
|
-
|
48
|
-
@response = RestClient.post BASE_URL, params
|
49
|
-
if @response.headers[:"errormsg"]
|
50
|
-
raise @response.headers[:"errormsg"]
|
51
|
-
elsif @response.headers[:"filename"]
|
52
|
-
report = Zlib::GzipReader.new(StringIO.new(@response.body)).read
|
53
|
-
parse_report(report)
|
54
|
-
else
|
55
|
-
raise "no data returned from itunes!"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
def parse_report(report)
|
61
|
-
lines = report.split("\n")
|
62
|
-
header = lines.shift # remove first line
|
63
|
-
lines.collect do |line|
|
64
|
-
provider, country, sku, developer, title, version, product_type_id, units, developer_proceeds, begin_date, end_date, currency, country_code, currency_of_proceeds, apple_id, customer_price, promo_code, parent_id, subscription, period = line.split("\t")
|
65
|
-
{
|
66
|
-
:provider => provider.strip,
|
67
|
-
:country => country.strip,
|
68
|
-
:sku => sku.strip,
|
69
|
-
:developer => developer.strip,
|
70
|
-
:title => title.strip,
|
71
|
-
:version => version.strip,
|
72
|
-
:product_type_id => product_type_id.strip,
|
73
|
-
:units => units.to_i,
|
74
|
-
:developer_proceeds => developer_proceeds.to_f,
|
75
|
-
:begin_date => Date.strptime(begin_date.strip, '%m/%d/%Y'),
|
76
|
-
:end_date => Date.strptime(end_date.strip, '%m/%d/%Y'),
|
77
|
-
:currency => currency.strip,
|
78
|
-
:country_code => country_code.strip,
|
79
|
-
:currency_of_proceeds => currency_of_proceeds.strip,
|
80
|
-
:apple_id => apple_id.to_i,
|
81
|
-
:customer_price => customer_price.to_f,
|
82
|
-
:promo_code => promo_code.strip,
|
83
|
-
:parent_id => parent_id.strip,
|
84
|
-
:subscription => subscription.strip,
|
85
|
-
:period => period
|
86
|
-
}
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
4
|
+
autoload :Fetcher, 'itunes_ingestion/fetcher'
|
5
|
+
autoload :SalesReportParser, 'itunes_ingestion/sales_report_parser'
|
6
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'zlib'
|
3
|
+
|
4
|
+
module ITunesIngestion
|
5
|
+
class Fetcher
|
6
|
+
BASE_URL = "https://reportingitc.apple.com/autoingestion.tft?"
|
7
|
+
|
8
|
+
REPORT_TYPE_SALES = "Sales"
|
9
|
+
DATE_TYPE_DAILY = "Daily"
|
10
|
+
DATE_TYPE_WEEKLY = "Weekly"
|
11
|
+
|
12
|
+
REPORT_SUMMARY = "Summary"
|
13
|
+
REPORT_OPT_IN = "Opt-In"
|
14
|
+
|
15
|
+
# Create new instance of Fetcher
|
16
|
+
#
|
17
|
+
# username - username
|
18
|
+
# password - password
|
19
|
+
# vadnumber - vadnumber
|
20
|
+
def initialize(username, password, vadnumber)
|
21
|
+
@username = username
|
22
|
+
@password = password
|
23
|
+
@vadnumber = vadnumber
|
24
|
+
end
|
25
|
+
|
26
|
+
# Fetch and unzip report from itunes connect
|
27
|
+
#
|
28
|
+
# options - Hash of options:
|
29
|
+
# - :type_of_report can only be REPORT_TYPE_SALES at the moment
|
30
|
+
# - :date_type either DATE_TYPE_DAILY or DATE_TYPE_WEEKLY, default DATE_TYPE_DAILY
|
31
|
+
# - :report_type either REPORT_OPT_IN or REPORT_SUMMARY, default REPORT_SUMMARY
|
32
|
+
# - :report_date date in YYYYMMDD
|
33
|
+
#
|
34
|
+
# Returns text file downloaded and unzipped from iTunes
|
35
|
+
def fetch(options={})
|
36
|
+
params = {
|
37
|
+
:USERNAME => @username, :PASSWORD => @password, :VNDNUMBER => @vadnumber
|
38
|
+
}
|
39
|
+
params[:TYPEOFREPORT] = options[:type_of_report] || REPORT_TYPE_SALES
|
40
|
+
params[:DATETYPE] = options[:date_type] || DATE_TYPE_DAILY
|
41
|
+
params[:REPORTTYPE] = options[:report_type] || REPORT_SUMMARY
|
42
|
+
params[:REPORTDATE] = options[:report_date] || (Time.now-60*60*24).strftime("%Y%m%d")
|
43
|
+
|
44
|
+
response = RestClient.post BASE_URL, params
|
45
|
+
if response.headers[:"errormsg"]
|
46
|
+
raise ITunesConnectError.new response.headers[:"errormsg"]
|
47
|
+
elsif response.headers[:"filename"]
|
48
|
+
Zlib::GzipReader.new(StringIO.new(response.body)).read
|
49
|
+
else
|
50
|
+
raise "no data returned from itunes: #{response.body}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module ITunesIngestion
|
4
|
+
class SalesReportParser
|
5
|
+
PRODUCT_TYPE_IDENTIFIER = {
|
6
|
+
"1" => "Free or Paid Apps, iPhone and iPod Touch",
|
7
|
+
"7" => "Updates, iPhone and iPod Touch",
|
8
|
+
"IA1" => "In Apps Purchase",
|
9
|
+
"IA9" => "In Apps Subscription",
|
10
|
+
"IAY" => "Auto-Renewable Subscription",
|
11
|
+
"1F" => "Free or Paid Apps (Universal)",
|
12
|
+
"7F" => "Updates (Universal)",
|
13
|
+
"1T" => "Free or Paid Apps, iPad",
|
14
|
+
"7T" => "Updates, iPad",
|
15
|
+
"F1" => "Free or Paid Apps, Mac OS",
|
16
|
+
"F7" => "Updates, Mac OS",
|
17
|
+
"FI1" => "In Apps Purchase, Mac OS",
|
18
|
+
"1E" => "Custome iPhone and iPod Touch",
|
19
|
+
"1EP" => "Custome iPad",
|
20
|
+
"1EU" => "Custome Universal"
|
21
|
+
}
|
22
|
+
|
23
|
+
# Parse sales report
|
24
|
+
#
|
25
|
+
# report - text based report form itunesconnect
|
26
|
+
#
|
27
|
+
# Returns array of hash, each hash contains one line of sales report
|
28
|
+
def self.parse(report)
|
29
|
+
lines = report.split("\n")
|
30
|
+
header = lines.shift # remove first line
|
31
|
+
lines.collect do |line|
|
32
|
+
provider, country, sku, developer, title, version, product_type_id, units, developer_proceeds, begin_date, end_date, currency, country_code, currency_of_proceeds, apple_id, customer_price, promo_code, parent_id, subscription, period = line.split("\t")
|
33
|
+
{
|
34
|
+
:provider => provider.strip,
|
35
|
+
:country => country.strip,
|
36
|
+
:sku => sku.strip,
|
37
|
+
:developer => developer.strip,
|
38
|
+
:title => title.strip,
|
39
|
+
:version => version.strip,
|
40
|
+
:product_type_id => product_type_id.strip,
|
41
|
+
:units => units.to_i,
|
42
|
+
:developer_proceeds => developer_proceeds.to_f,
|
43
|
+
:begin_date => Date.strptime(begin_date.strip, '%m/%d/%Y'),
|
44
|
+
:end_date => Date.strptime(end_date.strip, '%m/%d/%Y'),
|
45
|
+
:currency => currency.strip,
|
46
|
+
:country_code => country_code.strip,
|
47
|
+
:currency_of_proceeds => currency_of_proceeds.strip,
|
48
|
+
:apple_id => apple_id.to_i,
|
49
|
+
:customer_price => customer_price.to_f,
|
50
|
+
:promo_code => promo_code.strip,
|
51
|
+
:parent_id => parent_id.strip,
|
52
|
+
:subscription => subscription.strip,
|
53
|
+
:period => period
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,3 @@
|
|
1
|
+
Provider Provider Country SKU Developer Title Version Product Type Identifier Units Developer Proceeds Begin Date End Date Customer Currency Country Code Currency of Proceeds Apple Identifier Customer Price Promo Code Parent Identifier Subscription Period
|
2
|
+
APPLE US UT124500 Your Company App1 1.0.0 10 970 0 02/01/2011 02/01/2011 USD TW USD 10001000 0
|
3
|
+
APPLE US UA124502 Your Company App2 1.2.0 700 7100 0 02/01/2011 02/01/2011 JPY JP JPY 10001001 0
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path("../../lib/itunes_ingestion", __FILE__)
|
2
|
+
|
3
|
+
describe ITunesIngestion::SalesReportParser do
|
4
|
+
let (:data) { open(File.expand_path("../report/report.txt", __FILE__)).read }
|
5
|
+
|
6
|
+
it "parse report" do
|
7
|
+
report = ITunesIngestion::SalesReportParser.parse(data)
|
8
|
+
report.class.should == Array
|
9
|
+
report.length.should == 2
|
10
|
+
|
11
|
+
first_report = report.first
|
12
|
+
first_report[:sku].should == "UT124500"
|
13
|
+
first_report[:product_type_id].should == "10"
|
14
|
+
first_report[:title].should == "App1"
|
15
|
+
first_report[:begin_date].should == Date.new(2011, 2, 1)
|
16
|
+
first_report[:country_code].should == "TW"
|
17
|
+
first_report[:currency].should == "USD"
|
18
|
+
first_report[:currency_of_proceeds].should == "USD"
|
19
|
+
end
|
20
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: itunes_ingestion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-02-02 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|
16
|
-
requirement: &
|
16
|
+
requirement: &70345686376200 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,20 +21,25 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70345686376200
|
25
25
|
description: A simple port of Apple itunes Autoingestion tool to ruby.
|
26
26
|
email: francis@ignition.hk
|
27
27
|
executables: []
|
28
28
|
extensions: []
|
29
|
-
extra_rdoc_files:
|
30
|
-
- README.rdoc
|
29
|
+
extra_rdoc_files: []
|
31
30
|
files:
|
32
31
|
- Gemfile
|
33
32
|
- Gemfile.lock
|
34
|
-
-
|
33
|
+
- LICENSE
|
34
|
+
- README.md
|
35
35
|
- Rakefile
|
36
36
|
- VERSION
|
37
37
|
- lib/itunes_ingestion.rb
|
38
|
+
- lib/itunes_ingestion/fetcher.rb
|
39
|
+
- lib/itunes_ingestion/sales_report_parser.rb
|
40
|
+
- spec/fetcher_spec.rb
|
41
|
+
- spec/fixtures/report.txt
|
42
|
+
- spec/sales_report_parser_spec.rb
|
38
43
|
homepage: http://github.com/siuying/itunes-auto-ingestion
|
39
44
|
licenses: []
|
40
45
|
post_install_message:
|
@@ -59,4 +64,7 @@ rubygems_version: 1.8.10
|
|
59
64
|
signing_key:
|
60
65
|
specification_version: 3
|
61
66
|
summary: A simple port of Apple itunes Autoingestion tool to ruby.
|
62
|
-
test_files:
|
67
|
+
test_files:
|
68
|
+
- spec/fetcher_spec.rb
|
69
|
+
- spec/fixtures/report.txt
|
70
|
+
- spec/sales_report_parser_spec.rb
|
data/README.rdoc
DELETED
File without changes
|