Public paste
Undefined
By: Guest | Date: Feb 25 2015 12:28 | Format: None | Expires: never | Size: 5.13 KB | Hits: 918

  1. # encoding: utf-8
  2.  
  3. class MemberReport
  4.   include ActionView::Helpers::NumberHelper
  5.  
  6.   attr_reader :region_id, :start_date, :end_date,
  7.               :total, :total_members, :total_trials
  8.  
  9.   KEYS = [
  10.     :start,
  11.     :entering, :entering_switching,
  12.     :resigning, :resigning_switching,
  13.     :trend_absolute, :trend_relative,
  14.     :end,
  15.   ]
  16.  
  17.   # - <internal group name>: <array of ContactRole#id>
  18.   CONTACT_ROLES = {
  19.     personal_members: [5],
  20.     company_members: [1],
  21.     company_representatives: [2],
  22.     personal_trial_members: [5],
  23.     company_trial_members: [1],
  24.     company_trial_representatives: [2],
  25.   }
  26.  
  27.   # - <internal group name>: <array of MembershopStateGroup#id>
  28.   MEMBERSHIP_STATE_GROUPS = {
  29.     personal_trial_members: [3],
  30.     company_trial_members: [4],
  31.     company_trial_representatives: [4],
  32.   }
  33.  
  34.   CONTACT_ROLES.keys.each do |group|
  35.     # For all groups, calculation is the same
  36.     define_method \"calc_#{group}\" do
  37.       calc_trend(stats(group))
  38.     end
  39.  
  40.     # For all groups, the results are accessed through an attr_reader
  41.     define_method \"#{group}\" do
  42.       self.instance_variable_get(\"@#{group}\")
  43.     end
  44.   end
  45.  
  46.   def initialize(region_id, start_date=Date.today, end_date=Date.today, calc_on_init=true)
  47.     @region_id = region_id
  48.     @start_date = start_date
  49.     @end_date = end_date
  50.  
  51.     calculcate if calc_on_init
  52.   end
  53.  
  54.   def calculcate
  55.     CONTACT_ROLES.keys.each do |group|
  56.       instance_eval(\"@#{group} = calc_#{group}\")
  57.     end
  58.  
  59.     member_groups = [
  60.       personal_members, company_members, company_representatives
  61.     ]
  62.     trial_groups = [
  63.       personal_trial_members, company_trial_members, company_trial_representatives
  64.     ]
  65.  
  66.     @total = calc_total(member_groups + trial_groups)
  67.     @total_members = calc_total(member_groups)
  68.     @total_trials = calc_total(trial_groups)
  69.  
  70.     self
  71.   end
  72.  
  73.   # Calculations
  74.   def calc_total(groups=[])
  75.     result = {}
  76.  
  77.     groups.each do |group|
  78.       KEYS.each do |key|
  79.         result[key] ||= 0
  80.         result[key] += group[key].to_i
  81.       end
  82.     end
  83.  
  84.     calc_trend(result)
  85.  
  86.     result
  87.   end
  88.  
  89.   def member_count(group, date_from, date_to=nil, type=nil, switching=false)
  90.     return 0 unless group && CONTACT_ROLES[group]
  91.     date_to ||= date_from
  92.  
  93.     contact_ids = ContactAffiliation.main
  94.                     .where(region_id: @region_id)
  95.                     .where(company_id: nil)
  96.                     .between(date_from, date_to)
  97.  
  98.     contact_ids = contact_ids.entering_within(date_from, date_to) if type == :entering
  99.     contact_ids = contact_ids.resigning_within(date_from, date_to) if type == :resigning
  100.     contact_ids = contact_ids.collect(&:contact_id).uniq
  101.  
  102.     if switching
  103.       relevant_date_relation = \'resign_date <=\' if type == :entering
  104.       relevant_date_relation ||= \'entry_date >=\'
  105.  
  106.       contact_ids = ContactAffiliation.main
  107.                       .where(\'region_id != ?\', @region_id)
  108.                       .where(contact_id: contact_ids)
  109.                       .where(
  110.                         \"#{relevant_date_relation} ?\",
  111.                         date_from
  112.                       )
  113.                       .collect(&:contact_id).uniq
  114.     end
  115.  
  116.     contacts_with_roles =
  117.       ContactRoleAffiliation.all
  118.         .where(contact_id: contact_ids)
  119.         .where(contact_role_id: CONTACT_ROLES[group])
  120.         .between(date_from, date_to)
  121.  
  122.     if group.to_s.include?(\'trial\')
  123.       trial_member_count(contacts_with_roles, date_from, date_to)
  124.     else
  125.       contacts_with_roles.count
  126.     end
  127.   end
  128.  
  129.   def trial_member_count(contacts_with_roles, date_from, date_to=nil)
  130.     date_to ||= date_from
  131.     Membership.all
  132.               .between(date_from, date_to)
  133.               .for_contacts(contacts_with_roles.pluck(:id))
  134.               .count
  135.   end
  136.  
  137.   private
  138.  
  139.   # Helpers
  140.   def trend_relative(start_value=0, end_value=0)
  141.     start_value = start_value.to_f
  142.     end_value = end_value.to_f
  143.  
  144.     if start_value == end_value
  145.       \"±0\"
  146.     else
  147.       (
  148.         end_value > start_value ? \'+\' : \'\'
  149.       ) + number_to_percentage( ((end_value / start_value)-1)*100 )
  150.     end
  151.   end
  152.  
  153.   def trend_absolute(start_value=0, end_value=0)
  154.     if start_value == end_value
  155.       \"±0\"
  156.     else
  157.       (
  158.         end_value > start_value ? \'+\' : \'\'
  159.       ) + (end_value - start_value).to_s
  160.     end
  161.   end
  162.  
  163.   def calc_trend(hash={})
  164.     hash[:trend_relative] = trend_relative(hash[:start], hash[:end])
  165.     hash[:trend_absolute] = trend_absolute(hash[:start], hash[:end])
  166.     hash
  167.   end
  168.  
  169.   def stats(group)
  170.     return {} unless group
  171.     {
  172.       start:
  173.         member_count(group, @start_date),
  174.       entering:
  175.         member_count(group, @start_date, @end_date, :entering),
  176.       entering_switching:
  177.         member_count(group, @start_date, @end_date, :entering, true),
  178.       resigning:
  179.         member_count(group, @start_date, @end_date, :resigning),
  180.       resigning_switching:
  181.         member_count(group, @start_date, @end_date, :resigning, true),
  182.       end:
  183.         member_count(group, @end_date),
  184.     }
  185.   end
  186. end