Created
October 31, 2011 13:56
-
-
Save stereosupersonic/1327545 to your computer and use it in GitHub Desktop.
analytics_stub
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# analytics/app/support/report_invoker.rb | |
class ReportInvoker | |
def self.build_reports(dir) | |
new(dir).build_reports | |
end | |
attr_reader :dir | |
def initialize(dir) | |
@dir = dir | |
end | |
def build_reports | |
current_generation = start_next_generation | |
Dir["#{dir}/*.rb"].each do |report_file| | |
# TODO add logging here | |
system "bundle exec rails runner 'ReportBuilder.build(\"#{report_file}\", #{current_generation})'" | |
end | |
finish_current_generation current_generation | |
clear_old_generations current_generation-2 | |
end | |
private | |
# TODO this method should be put into a global module of some kind | |
# it is also needed for read out | |
def read_current_generation | |
# read the current generation from the analytics_generations table | |
end | |
def start_new_generation | |
current_generation = read_current_generation | |
# write entry into analytics_generations table for current_generation+1 | |
end | |
def finish_current_generation(new_generation) | |
# write the new_generation value to analytics_generations | |
end | |
def clear_old_generations(last_generation) | |
# find all databases with name analytics_data_#{i} where i <= last_generation | |
# and delete them | |
end | |
end | |
### in Rakefile | |
task :build_reports do | |
require "path to report invoker" | |
ReportInvoker.build_reports File.join(File.dirname(__FILE__), "app", "reports") | |
end | |
# analytics/app/support/report_builder.rb | |
require "base_report" | |
class ReportBuilder | |
def self.build(report_file, generation) | |
new(report_file, generation).build | |
end | |
def initialize(report_file, generation) | |
@report_class = find_report_class | |
@connection = open_connection generation | |
end | |
def build | |
# pull in the report context, | |
# ie boot up the Rails environment for the report class | |
@report_class.load_application | |
# create the report instance | |
@report_instance = @report_class.new self | |
# determine the headers in all the available locales for this report | |
# these should not depend on the actual data | |
@report_instance.determine_headers | |
# now we're ready to rock and roll | |
@report_instance.calculate | |
end | |
def set(table, id, value) | |
# write value in to table for the row with id | |
end | |
def append(table, value) | |
# append value to the table, generating a new row with a new id | |
end | |
private | |
def find_report_class(report_file) | |
# load the report ruby file | |
require report_file | |
# deduce the report class name from the file name | |
# list_negotiations_report.rb => ListNegotiationsReport | |
File.basename(report_file).classify.constantize | |
end | |
def open_connection(generation) | |
# open mongo_db connection to table analytics_data_#{generation} | |
end | |
end | |
# analytics/app/support/report_reader.rb | |
class ReportReader | |
end | |
# analytics/app/support/base_report.rb | |
class BaseReport | |
def self.define_context(app) | |
class << self | |
define_method :context do | |
app | |
end | |
define_method :load_application do | |
analytics_root = File.join(File.dirname(__FILE__), "..", "..") | |
if File.exist? File.join(analytics_root, "app/support/#{app}_support.rb") | |
require File.join(analytics_root, "app/support/#{app}_support") | |
if Object.const_defined? "#{app}_support".classify | |
include "#{app}_support".classify.constantize | |
end | |
end | |
require File.join(analytics_root, "..", app.to_s, "config", "environment") | |
end | |
end | |
end | |
def self.report_name | |
self.to_s.sub("Report", "").underscore | |
end | |
attr_reader :builder | |
def initialize(builder) | |
@builder = builder | |
end | |
def write(line, specific_id=nil) | |
@builder.append build_name(:values, self.class.report_name), line.generic | |
@builder.append build_name(:values, self.class.report_name, specific_id), line.all if specific_id | |
end | |
def set_headers(headers, locale, specific_id=nil) | |
mapping = {} | |
order = [] | |
headers.each do |header| | |
key = headers.keys.first | |
mapping[key] = header[key] | |
order << key | |
end | |
@builder.set build_name(:row_order, self.class.report_name), # table_name | |
build_name(:order, specific_id), # row_id | |
order # value | |
# set, will set the value of row_id in table_name to content | |
@builder.set build_name(:headers, self.class.report_name), # table_name | |
build_name(locale, specific_id), # row_id | |
headers # content of row | |
end | |
private | |
def build_name(*parts) | |
parts.compact.map(&:to_s).join("_") | |
end | |
end | |
# These support module should go into a seperate directory "analytics/app/support" | |
module KatalysatorSupport | |
def add_shop_field_headers(shop, headers) | |
shop.shop_fields.reject(&:hidden?).each do |shop_field| | |
headers << { "shop_field_#{shop_field.id}".to_sym => shop_field.name } | |
end | |
end | |
def add_shop_fields(project, result) | |
project.shop.shop_fields.reject(&:hidden?).each do |shop_field| | |
project_field = project.project_fields.detect { |pf| pf.shop_field_id == shop_field.id } | |
result << { "shop_field_#{shop_field.id}".to_sym => project_field.value } if project_field | |
end | |
end | |
def shop_categories(shop) | |
Service.statistics_categories_for_shop(shop) | |
end | |
end | |
# example for one report class | |
# analytics/app/reports/booked_offer_acceptance_report.rb | |
class BookedOfferAcceptancesReport < BaseReport | |
GENERIC_HEADERS = [:service_provider_name, :service_provider_id, :service_provider_city, :service_provider_country, :service_provider_chain, :service_provider_pp, | |
:project_number, :negotiation_status, :project_title, :project_start_date, :project_end_date, :offer_acceptance_date, :project_create_date, :project_creator, | |
:project_creator_group, :project_creator_company_name, :project_invoice_address_name, :project_manager, :project_manager_group, :offer_total_currency, | |
:offer_total_with_tax, :offer_savings, :offer_lost_savings, :offer_won_savings, :tender_splitting, :commission_rate_conference, :commission_rate_lodging] | |
define_context :katalysator | |
def determine_headers | |
# TODO find all defined locales, see Rails i18n | |
LOCALES.each do |locale| | |
generic = [] | |
# TODO set the right locale | |
GENERIC_HEADERS.each { |h| generic << { h => I18n.t(h, :prefix => "analytics.headers") } } | |
set_header generic, locale | |
Shop.all.each do |shop| | |
specific = generic.dup | |
add_shop_field_headers(shop, specific) | |
# TODO see if this worcs out for the statitics categories | |
shop_categories(shop).each do |category| | |
cat_name = category.underscore | |
specific << { "amount_#{category}" => I18n.t("amount_#{cat_name}", :prefix => "analytics.statistics_categories") } | |
specific << { "total_#{category}" => I18n.t("total_#{cat_name}", :prefix => "analytics.statistics_categories") } | |
set_header specific, locale, "shop_#{shop.id}" | |
end | |
end | |
end | |
end | |
def calculate | |
get_authorized_offers do |offer| | |
# the method should update the exception counter for offer | |
# and log the exception under "offer_#{id}" | |
exception_logged "offer", offer.id do | |
shop = offer.shop | |
write build_line(offer), "shop_#{shop.id}" | |
end | |
end | |
end | |
private | |
def build_line(offer) | |
service_provider = find_service_provider(o.negotiation.service_provider_id,o.shop) | |
build_offer(offer, service_provider).tap do |result| | |
result.specific do |line| | |
# add shop specific fields | |
add_shop_fields offer.project, line | |
# add shop specific service category aggregations | |
shop_categories(offer.shop).each do |category| | |
if category == "Sonstiges" | |
# all services which are not categorized will be summarized in Sonstiges | |
line["amount_#{category}"] = format_number(offer.calculator.amount_for_statistics_category(cat)+offer.calculator.amount_for_statistics_category("")) | |
line["total_#{category}"] = display_price(offer.calculator.with_tax_total_for_statistics_category(cat)+offer.calculator.with_tax_total_for_statistics_category("")) | |
else | |
line["amount_#{category}"] = format_number(offer.calculator.amount_for_statistics_category(cat)) | |
line["total_#{category}"] = display_price(offer.calculator.with_tax_total_for_statistics_category(cat)) | |
end | |
end | |
end | |
end | |
end | |
def build_offer(offer, service_provider) | |
ReportLine.new.tap do |result| | |
result.generic do |l| | |
# TODO move i18n of specific answers to readout phase | |
l[:service_provider_name] = (service_provider.name rescue I18n.t('common.unknown') | |
l[:service_provider_id] = (o.negotiation.service_provider_id rescue I18n.t('common.unknown')) | |
l[:service_provider_city] = (service_provider.city.to_s rescue I18n.t('common.unknown')) | |
l[:service_provider_country] = (service_provider.land.to_s rescue I18n.t('common.unknown')) | |
l[:service_provider_chain] = (service_provider.kette.blank? ? I18n.t('common.unknown') : o.negotiation.service_provider.kette rescue I18n.t('common.unknown')) | |
l[:service_provider_pp] = (service_provider.prio ? I18n.t('common.positive_answer') : I18n.t('common.negative_answer') rescue "") | |
l[:project_number] = o.project.project_number.to_s | |
l[:negotiation_status] = ProjectsHelper.negotiation_status(o.negotiation) | |
l[:project_title] = o.project.title | |
l[:project_start_date] = format_date(o.project.start_date.to_date) | |
l[:project_end_date] = format_date(o.project.end_date.to_date) | |
l[:offer_acceptance_date] = (format_date(o.offer_acceptance.created_at.to_date) rescue "") | |
l[:project_create_date] = format_date(o.project.created_at.to_date) | |
l[:project_creator] = (o.project.creator_full_name rescue I18n.t('common.unknown')) | |
l[:project_creator_group] = o.project.user_group_name(:creator).to_s | |
l[:project_creator_company_name] = (o.project.creator_company_name rescue I18n.t('common.unknown')) | |
l[:project_invoice_address_name] = o.project.invoice_address_name | |
l[:project_manager] = (o.project.manager_full_name rescue I18n.t('common.unknown')) | |
l[:project_manager_group] = o.project.user_group_name(:manager).to_s | |
l[:offer_total_currency] = currency_iso(o.total_with_tax) | |
l[:offer_total_with_tax] = display_price(o.total_with_tax) | |
l[:offer_savings] = (display_price(o.negotiation.has_positive_savings? ? o.negotiation.savings : 0) rescue 'error') | |
l[:offer_lost_savings] = (display_price(o.lost_saving) rescue 'error') | |
l[:offer_won_savings] = (display_price(o.won_saving) rescue 'error') | |
l[:tender_splitting] = o.tender.splitting ? I18n.t('common.positive_answer') : I18n.t('common.negative_answer') | |
l[:commission_rate_conference] = display_percent(o.offer_info.commission_rate_conference) | |
l[:commission_rate_lodging] = display_percent(o.offer_info.commission_rate_lodging | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment