bin/sale in sales-0.0.2 vs bin/sale in sales-0.0.3

- old
+ new

@@ -1,8 +1,8 @@ #!/usr/bin/env ruby -# Sales +# Sales, still wet, not yet dry #make nice colors for terminal strings class String def red; colorize(self, "\e[1m\e[31m"); end def green; colorize(self, "\e[1m\e[32m"); end @@ -34,27 +34,31 @@ get and present a daily summary report for a date #{'sale.rb YYYYMMDD'.green} EGASU +#require all dependent gems require 'rubygems' require 'open-uri' require 'json' require 'date' require 'yaml' +#load the version file V = YAML.load_file(File.join(File.dirname(__FILE__), %w[.. VERSION.yml])) VERSION = "#{V[:major]}.#{V[:minor]}.#{V[:patch]}" #load the iTunes Connect credentials from the sales.yml example_sales_yml_file = File.join(File.dirname(__FILE__), %w[.. sales.yml]) dest_sales_yml_file = "sales.yml" if File.exists? dest_sales_yml_file S = YAML.load_file("sales.yml") - username = S[:username] - password = S[:password] - vendorId = S[:vendorId] + @username = S[:username] + @password = S[:password] + @vendorId = S[:vendorId] + @convertTo = S[:convertTo] + @beVerbose = S[:beVerbose] else puts "Please fill out Your iTunes Connect credentials in the".red + " sales.yml ".green + "file in the same dir where You run 'sale'.".red `cp #{example_sales_yml_file} sales.yml; ls -al` unless File.exists? dest_sales_yml_file abort end @@ -82,90 +86,75 @@ } SALE_IDENTS = ["1", "1F", "1T", "F1"] INAPP_SALE_IDENTS = ["IA1", "IA9", "IAY", "FI1"] UPDATE_IDENTS = ["7", "7F", "7T", "F7"] -#the parser was copied from github, https://github.com/siuying/itunes-auto-ingestion/blob/master/lib/itunes_ingestion/sales_report_parser.rb -class SalesReportParser - # Parse sales report - # - # report - text based report form itunesconnect - # - # Returns array of hash, each hash contains one line of sales report - def self.parse(report) - lines = report.split("\n") - #puts "lines: #{lines}" - header = lines.shift # remove first line - lines.collect do |line| - #puts "line: #{line}" - 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") - p = { - :provider => provider.strip, - :country => country.strip, - :sku => sku.strip, - :developer => developer.strip, - :title => title.strip, - :version => version.strip, - :product_type_id => product_type_id.strip, - :units => units.to_i, - :developer_proceeds => developer_proceeds.to_f, - :begin_date => Date.strptime(begin_date.strip, '%m/%d/%Y'), - :end_date => Date.strptime(end_date.strip, '%m/%d/%Y'), - :currency => currency.strip, - :country_code => country_code.strip, - :currency_of_proceeds => currency_of_proceeds.strip, - :apple_id => apple_id.to_i, - :customer_price => customer_price.to_f, - :promo_code => promo_code.strip, - :parent_id => parent_id.strip, - :subscription => subscription.strip, - :period => period - } - puts "parsing failed".red if p==nil - p - end #lines collect - end #self.parse -end #class +# Parse sales report +# the parser was copied and tweaked from github, https://github.com/siuying/itunes-auto-ingestion/blob/master/lib/itunes_ingestion/sales_report_parser.rb, thanks +# the class was thrown away though, a simple method is so much cleaner in a simple program like this +# +# report - text based report form itunesconnect +# +# Returns array of hash, each hash contains one line of sales report +def parse(report) + lines = report.split("\n") + #puts "lines: #{lines}" + header = lines.shift # remove first line + lines.collect do |line| + #puts "line: #{line}" + 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") + p = { :provider => provider.strip, + :country => country.strip, + :sku => sku.strip, + :developer => developer.strip, + :title => title.strip, + :version => version.strip, + :product_type_id => product_type_id.strip, + :units => units.to_i, + :developer_proceeds => developer_proceeds.to_f, + :begin_date => Date.strptime(begin_date.strip, '%m/%d/%Y'), + :end_date => Date.strptime(end_date.strip, '%m/%d/%Y'), + :currency => currency.strip, + :country_code => country_code.strip, + :currency_of_proceeds => currency_of_proceeds.strip, + :apple_id => apple_id.to_i, + :customer_price => customer_price.to_f, + :promo_code => promo_code.strip, + :parent_id => parent_id.strip, + :subscription => subscription.strip, + :period => period + } + puts "parsing failed".red if p==nil + p + end #lines collect +end #parse -puts "\nSales v#{VERSION}".red + " created by Your Headless Standup Programmer http://kitschmaster.com".dark_blue - -if ARGV[0] == "-h" || ARGV[0] == "help" || ARGV[0] == "h" - - puts USAGE - -elsif ARGV[0] == "daily" || ARGV[0] == "weekly" - #compute alltime stats for daily or weekly reports - - dir_filter = ARGV[0] == "daily" ? "D" : "W" - - alltime_proceeds_per_currency = {} #currency is the key, value is the proceeds - alltime_renewables = 0 - alltime_apps = {} - alltime_payed_units = 0 - alltime_inapp_units = 0 - alltime_free_units = 0 - alltime_updated_units = 0 - reports = Dir["S_#{dir_filter}_*.txt"].uniq.compact - - if reports.empty? +# Computes and presents reports +# +# reports - array of report files to compute +# +# +def compute_and_present(reports) + alltime_proceeds_per_currency = {} #currency is the key, value is the proceeds + alltime_renewables = 0 + alltime_apps = {} + alltime_payed_units = 0 + alltime_inapp_units = 0 + alltime_free_units = 0 + alltime_updated_units = 0 - puts "\nPlease download reports first.".red - puts "sale get:#{ARGV[0].split(':').last}\n".green - - else - first_date = reports[0].split('_').last.split('.').first reports.each do |alltime_filename| - #puts "Processing #{alltime_filename}".green + puts "Processing #{alltime_filename}".green if @beVerbose #get the date from the filename date = alltime_filename.split('_').last.split('.').first #filename example: S_D_80076793_20120706.txt report_data = File.open(alltime_filename, "rb").read - report = SalesReportParser.parse(report_data) + report = parse(report_data) #puts report.class if report #report parsed apps = {} total_payed_units = 0 total_inapp_units = 0 @@ -227,27 +216,27 @@ #add stats alltime_app[:sold_units] += apps_app[:sold_units] alltime_app[:updated_units] += apps_app[:updated_units] end -=begin - #report for date - puts "\n\n______________________________________________________________".blue - puts "Report for #{date}" - puts "\n" + "Product".ljust(40).blue + ": " +"Downloads".green + " / " + "Updates".green - puts "______________________________________________________________".yellow - apps.each do |app_sku,apps_app| - puts "#{apps_app[:title].ljust(40).blue}: #{apps_app[:sold_units].to_s.ljust(10).green} / #{apps_app[:updated_units].to_s.rjust(7).dark_green}" - end - puts "______________________________________________________________".yellow - puts "#{'InApp Purchases'.ljust(40).green}: #{total_inapp_units}" - puts "#{'Payed Downloads'.ljust(40).green}: #{total_payed_units}" - puts "#{'Free Downloads'.ljust(40).dark_green}: #{total_free_units}" - puts "#{'Updates'.ljust(40).dark_green}: #{total_updated_units}" - puts "______________________________________________________________".blue - puts "\n\n" -=end + if @beVerbose && reports.size>1 + #report for date + puts "\n\n______________________________________________________________".blue + puts "Report for #{date}" + puts "\n" + "Product".ljust(40).blue + ": " +"Downloads".green + " / " + "Updates".green + puts "______________________________________________________________".yellow + apps.each do |app_sku,apps_app| + puts "#{apps_app[:title].ljust(40).blue}: #{apps_app[:sold_units].to_s.ljust(10).green} / #{apps_app[:updated_units].to_s.rjust(7).dark_green}" + end + puts "______________________________________________________________".yellow + puts "#{'InApp Purchases'.ljust(40).green}: #{total_inapp_units}" + puts "#{'Payed Downloads'.ljust(40).green}: #{total_payed_units}" + puts "#{'Free Downloads'.ljust(40).dark_green}: #{total_free_units}" + puts "#{'Updates'.ljust(40).dark_green}: #{total_updated_units}" + puts "______________________________________________________________".blue + puts "\n\n" + end #if @beVerbose else puts "null report parsed".red end #if report parsed @@ -256,11 +245,11 @@ #report alltime puts "\n\n______________________________________________________________".blue from = Date.strptime first_date, '%Y%m%d' age = Date.today - from formatted_from = from.strftime("%b %d %Y") - puts "Report for #{ARGV[0]}, from #{formatted_from}, #{age.to_i} days" + puts "Report" + (ARGV[0]? " #{ARGV[0]}":" daily") + ", from #{formatted_from}, #{age.to_i} days" puts "\n" + "Product".ljust(40).blue + ": " +"Downloads".green + " / " + "Updates".green puts "______________________________________________________________".yellow alltime_apps.each do |app_sku, aapp| puts "#{aapp[:title].ljust(40).blue}: #{aapp[:sold_units].to_s.ljust(10).green} / #{aapp[:updated_units].to_s.rjust(7).dark_green}" end @@ -268,115 +257,132 @@ puts "#{'InApp Purchases'.ljust(40).green}: #{alltime_inapp_units}" + ( alltime_renewables > 0.0 ? " / #{alltime_renewables} Auto-Renewed" : "") puts "#{'Payed Downloads'.ljust(40).green}: #{alltime_payed_units}" puts "#{'Free Downloads'.ljust(40).dark_green}: #{alltime_free_units}" puts "#{'Updates'.ljust(40).dark_green}: #{alltime_updated_units}" puts "\n#{'Proceeds'.red}:\n\n" - total_eurs = 0.0 + total_proceeds = 0.0 alltime_proceeds_per_currency.each do |proceed_key, proceed| formatted_sum = proceed > 0.0 ? "#{proceed}".green : "#{proceed}".red if proceed > 0.0 - if proceed_key == "EUR" - total_eurs += proceed + if proceed_key == @convertTo + total_proceeds += proceed puts "#{proceed_key} : #{formatted_sum}" else #convert using google - data = open("http://www.google.com/ig/calculator?q=#{proceed}#{proceed_key}=?EUR").read + data = open("http://www.google.com/ig/calculator?q=#{proceed}#{proceed_key}=?#{@convertTo}").read #fix broken json data.gsub!(/lhs:/, '"lhs":') data.gsub!(/rhs:/, '"rhs":') data.gsub!(/error:/, '"error":') data.gsub!(/icc:/, '"icc":') data.gsub!(Regexp.new("(\\\\x..|\\\\240)"), '') #puts data converted = JSON.parse data converted_proceed = converted["rhs"].split(' ').first.to_f - total_eurs += converted_proceed + total_proceeds += converted_proceed puts "#{proceed_key} : #{formatted_sum} / #{converted['rhs']}" end end end - puts "\n#{'Total'.green}: #{total_eurs} Euros" + puts "\n#{'Total'.green}: #{total_proceeds} #{@convertTo}" puts "______________________________________________________________".blue - puts "\n\n" + puts "\n\n" +end - end #else reports.empty? +#begin to show visible light of this program by displaying its name, version and creator +puts "\nSales v#{VERSION}".red + " created by Your Headless Standup Programmer http://kitschmaster.com".dark_blue if @beVerbose + +if ARGV[0] == "-h" || ARGV[0] == "help" || ARGV[0] == "h" + #----------------------------------------------------------------------------------------------------------------------------- + #show help + puts USAGE + #----------------------------------------------------------------------------------------------------------------------------- +elsif ARGV[0] == "daily" || ARGV[0] == "weekly" + #----------------------------------------------------------------------------------------------------------------------------- + #compute alltime stats for daily or weekly reports + #collect the report files + dir_filter = ARGV[0] == "daily" ? "D" : "W" #the daily or the weekly files + reports = Dir["S_#{dir_filter}_*.txt"].uniq.compact + if reports.empty? + #no reports + puts "\nPlease download reports first.".red + puts "sale get:#{ARGV[0].split(':').last}\n".green + else + #compute and present the collected reports + compute_and_present(reports) + end + #----------------------------------------------------------------------------------------------------------------------------- elsif ARGV[0] == "get:daily" - + #----------------------------------------------------------------------------------------------------------------------------- # Daily reports are available only for past 14 days, please enter a date within past 14 days. - - first_date = Date.today - + first_date = Date.today (1..14).each do |i| - date = (first_date - i).to_s.gsub('-', '') puts "\nGetting Daily Sales Report for #{date}\n" - - filename = "S_D_#{vendorId}_#{date}.txt" + filename = "S_D_#{@vendorId}_#{date}.txt" unless File.exists? filename #download unless there already is a file #call the java program and fetch the file - e = `java -cp #{classpath} Autoingestion #{username} #{password} #{vendorId} Sales Daily Summary #{date}` + e = `java -cp #{classpath} Autoingestion #{@username} #{@password} #{@vendorId} Sales Daily Summary #{date}` report_file = e.split("\n").first if File.exists? report_file f = `gzip -df #{report_file}` else puts "#{e}\n".red end end - - end # 91.each - + end # 1..14.each + #----------------------------------------------------------------------------------------------------------------------------- elsif ARGV[0] == "get:weekly" - + #----------------------------------------------------------------------------------------------------------------------------- # Weekly reports are available only for past 13 weeks, please enter a weekend date within past 13 weeks. - first_date = Date.today (1..13).each do |i| #13 weeks date = (first_date - i*7) day_increment = (0 - date.cwday) % 7 day_increment = 7 if day_increment == 0 next_sunday = date + day_increment formatted_date = next_sunday.to_s.gsub('-', '') puts "\nGetting Weekly Sales Report for #{formatted_date}\n" - filename = "S_W_#{vendorId}_#{formatted_date}.txt" + filename = "S_W_#{@vendorId}_#{formatted_date}.txt" unless File.exists? filename #download unless there already is a file #call the java program and fetch the file - e = `java -cp #{classpath} Autoingestion #{username} #{password} #{vendorId} Sales Weekly Summary #{formatted_date}` + e = `java -cp #{classpath} Autoingestion #{@username} #{@password} #{@vendorId} Sales Weekly Summary #{formatted_date}` report_file = e.split("\n").first if File.exists? report_file f = `gzip -df #{report_file}` else puts "#{e}\n".red end end - end # 13.each - + end # 1..13.each + #----------------------------------------------------------------------------------------------------------------------------- else + #----------------------------------------------------------------------------------------------------------------------------- # no argument or date in format YYYYMMDD #get sales report for date - @date = ARGV[0] date = (Date.today - 1).to_s.gsub('-', '') date = @date if ARGV[0] puts "\nDaily Sales Report for #{date}\n" - - filename = "S_D_#{vendorId}_#{date}.txt" + filename = "S_D_#{@vendorId}_#{date}.txt" unless File.exists? filename #download unless there already is a file #call the java program and fetch the file - e = `java -cp #{classpath} Autoingestion #{username} #{password} #{vendorId} Sales Daily Summary #{date}` + e = `java -cp #{classpath} Autoingestion #{@username} #{@password} #{@vendorId} Sales Daily Summary #{date}` report_file = e.split("\n").first if File.exists? report_file f = `gzip -df #{report_file}` else puts "#{e}\n".red end end - + compute_and_present([filename]) +=begin if File.exists? filename #only if there is data #calculate totals report_data = File.open(filename, "rb").read - report = SalesReportParser.parse(report_data) + report = parse(report_data) apps = {} total_payed_units = 0 total_inapp_units = 0 total_free_units = 0 total_updated_units = 0 @@ -416,6 +422,8 @@ puts "#{'Payed Downloads'.ljust(40).green}: #{total_payed_units}" puts "#{'Free Downloads'.ljust(40).dark_green}: #{total_free_units}" puts "#{'Updates'.ljust(40).dark_green}: #{total_updated_units}" puts "\n" end +=end + #----------------------------------------------------------------------------------------------------------------------------- end \ No newline at end of file