Last active
August 29, 2015 14:26
-
-
Save JamesDullaghan/9f79e4f07b979312cbfe to your computer and use it in GitHub Desktop.
This file contains hidden or 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
class Booking::ReportGenerator < ReportGenerator | |
# Presenter class overriding superclass method | |
# | |
# @return [Class] | |
# | |
# @api public | |
def presenter_class | |
ReportPresenter | |
end | |
# Column titles method overriding superclass method | |
# | |
# @return [Array<String>] | |
# | |
# @api public | |
def column_titles | |
[ | |
'Cust. Name', | |
'Email', | |
'Phone', | |
'Address', | |
'Location', | |
'Check in', | |
'Check out', | |
'Room', | |
'Pet Name', | |
'Breed', | |
'# Nights', | |
'Source', | |
'Amount' | |
] | |
end | |
# Stat row methods | |
# | |
# @return [Array<Symbols>] | |
# | |
# @api public | |
def stat_row_methods | |
[ | |
:user_full_name, | |
:user_email, | |
:user_phone, | |
:user_full_address, | |
:location_address, | |
:display_check_in, | |
:display_check_out, | |
:room_names, | |
:pets_names, | |
:pets_breeds, | |
:nights, | |
:source, | |
:total_price_with_discount | |
] | |
end | |
# Temporary path for report generation | |
# | |
# @return [String] | |
# | |
# @api public | |
def file_path | |
file_name = business_entity.name.parameterize.underscore | |
"#{Rails.root}/tmp/#{file_name}_#{date.year}_report.xls" | |
end | |
end |
This file contains hidden or 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
# Booking Reports for internal use | |
class Internal::ReportGenerator < ReportGenerator | |
# Internal Report Presenter | |
# | |
# @return [Class] | |
# | |
# @api public | |
def presenter_class | |
InternalReportPresenter | |
end | |
# Column titles for internal booking report | |
# | |
# @return [Array<String>] | |
# | |
# @api public | |
def column_titles | |
[ | |
'Direct Deposit/Check', | |
'Cust. Name', | |
'New/Existing Cust.', | |
'Email', | |
'Phone', | |
'Address', | |
'Facility Booked', | |
'Booking Source', | |
'Check In', | |
'Check Out', | |
'Nights Booked', | |
'Pet Name', | |
'Breed', | |
'Discount Amount', | |
'Amount With Discount Applied', | |
'Amount Before Discount Applied', | |
'Promotion used?', | |
'Promotion Used', | |
'Promotion Type', | |
'Booking Fee', | |
'Total Amount After Fee', | |
'Room(s) type booked' | |
] | |
end | |
# Stat row methods for internal booking report | |
# | |
# @return [Array<Symbols>] | |
# | |
# @api public | |
def stat_row_methods | |
[ | |
:banking?, | |
:user_full_name, | |
:new_customer?, | |
:user_email, | |
:user_phone, | |
:address, | |
:location_name, | |
:booking_source, | |
:display_check_in, | |
:display_check_out, | |
:nights, | |
:pets_names, | |
:pets_breeds, | |
:discount, | |
:total_price, | |
:total_with_discount, | |
:promo_code?, | |
:promotional_code, | |
:promotional_type, | |
:booking_fee, | |
:total_after_fee, | |
:room_names | |
] | |
end | |
# Temporary path for report generation | |
# | |
# @return [String] | |
# | |
# @api public | |
def file_path | |
"#{Rails.root}/tmp/internal_report_#{date.to_s.underscore}.xls" | |
end | |
end |
This file contains hidden or 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
class InternalReportPresenter < BookingPresenter | |
delegate :phone, :email, :full_name, to: :user, prefix: true | |
delegate :names, :breeds, to: :pets, prefix: true | |
OBT_FEE = 0.08 | |
WEB_FEE = 0.12 | |
# Has banking information | |
# | |
# @return [Boolean] | |
# | |
# @api public | |
def banking? | |
business_entity.banking.present?.to_s | |
end | |
# Check in date | |
# | |
# @return [String] | |
# | |
# @api public | |
def display_check_in | |
check_in.strftime('%-m/%-d/%-y') | |
end | |
# Check out date | |
# | |
# @return [String] | |
# | |
# @api public | |
def display_check_out | |
check_out.strftime('%-m/%-d/%-y') | |
end | |
# Does the customer have a booking at an existing facility | |
# | |
# @return [Boolean] | |
# | |
# @api public | |
def new_customer? | |
user_bookings.where(boarding_facility_id: boarding_facility_id).count <= 1 | |
end | |
# Source of the booking | |
# | |
# @return [String] | |
# | |
# @api public | |
def booking_source | |
source == 'widget' || source.nil? ? 'OBT' : 'Web' | |
end | |
# Total booking price with discount amount | |
# | |
# @return [Integer] | |
# | |
# @api public | |
def total_with_discount | |
total_price + discount.to_f | |
end | |
# Promotion code used | |
# | |
# @return [String] | |
# | |
# @api public | |
def promotional_code | |
promo_code ? promo_code.code : '' | |
end | |
# Promotion type used | |
# | |
# @return [String] | |
# | |
# @api public | |
def promotional_type | |
promo_code ? promo_code.discount_type : '' | |
end | |
# Booking fee | |
# | |
# @return [Float] | |
# | |
# @api public | |
def booking_fee | |
total_price * discount_amount | |
end | |
# Total to be payed out to BusinessEntity | |
# | |
# @return [Float] | |
# | |
# @api public | |
def total_after_fee | |
total_price - booking_fee | |
end | |
private | |
# Discount amount from obt or web | |
# | |
# @return [Float] | |
# | |
# @api public | |
def discount_amount | |
online_booking_tool? ? OBT_FEE : WEB_FEE | |
end | |
# is the booking_source OBT | |
# | |
# @return [Boolean] | |
# | |
# @api private | |
def online_booking_tool? | |
booking_source.eql?('OBT') | |
end | |
# Users bookings | |
# | |
# @return [ActiveRecord::Collection] | |
# | |
# @api private | |
def user_bookings | |
user.bookings | |
end | |
end |
This file contains hidden or 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
class Report < ActiveRecord::Base | |
belongs_to :business_entity | |
has_attached_file :file, REPORT_STORAGE | |
do_not_validate_attachment_file_type :file | |
# Generate the booking report for specific business_entity | |
# Used in facility dashboard | |
# | |
# @return [Boolean] | |
# | |
# @api public | |
def self.generate_booking_report(business_entity, year = Date.current.year) | |
find_or_initialize_by(year: year, business_entity_id: business_entity.id). | |
generate_and_record_spreadsheet( | |
Booking::ReportGenerator.new( | |
business_entity: business_entity, | |
bookings: business_entity.bookings | |
) | |
) | |
end | |
# Generate an internal booking report | |
# | |
# @return [Boolean] | |
# | |
# @api public | |
def self.generate_internal_report(bookings, year = Date.current.year) | |
find_or_initialize_by(year: year, business_entity_id: nil). | |
generate_and_record_spreadsheet( | |
Internal::ReportGenerator.new( | |
bookings: bookings | |
) | |
) | |
end | |
# Generate and record the spreadsheet as a report | |
# | |
# @return [Boolean] | |
# | |
# @api private | |
def generate_and_record_spreadsheet(spreadsheet) | |
spreadsheet.generate | |
spreadsheet.record_file | |
self.file = File.open(spreadsheet.file_path) | |
File.delete(spreadsheet.file_path) | |
save | |
self | |
end | |
end |
This file contains hidden or 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
# A spreadsheet is made up of multiple components | |
# | |
# Workbook is the main component | |
# Worksheets are housed within a workbook to generate the tabs in the xls file | |
# Rows are appended to a worksheet by assigning variables to worksheet[x, y] | |
# where [x, y] is the row & column | |
class ReportGenerator | |
extend Memoist | |
attr_reader :bookings, :date, :business_entity | |
def initialize(args) | |
@business_entity = args.fetch(:business_entity) { nil } | |
@bookings = args.fetch(:bookings) | |
@date = Date.current | |
end | |
# Column titles | |
# | |
# @return [String] | |
# | |
# @api public | |
def column_titles | |
raise NotImplementedError, 'define column_titles method in the subclass' | |
end | |
# Stat row methods | |
# | |
# @return [String] | |
# | |
# @api public | |
def stat_row_methods | |
raise NotImplementedError, 'define stat_row_methods method in the subclass' | |
end | |
# File Path for report upload | |
# | |
# @return [String] | |
# | |
# @api public | |
def file_path | |
raise NotImplementedError, 'define file_path method in the subclass' | |
end | |
# Raise not implemented error if presenter class not defined | |
# | |
# @return [String] | |
# | |
# @api public | |
def presenter_class | |
raise NotImplementedError, 'define presenter_class in the subclass' | |
end | |
# Create the worksheet for the report | |
# | |
# @param [month<Integer>] | |
# zero-index | |
# ex.) Date.current.beginning_of_month + 0.month = Jan 1, 2015 | |
# | |
# @return [Integer] | |
# | |
# @api private | |
def worksheet(i) | |
month = start_date + i.months | |
name = "#{month.strftime('%B')} #{month.year}" | |
sheet = workbook.create_worksheet name: name | |
generate_title_row(sheet) | |
bookings.bookings_for_month(month).each_with_index do |booking, index| | |
generate_stat_row( | |
sheet, | |
presenter_class.new(self, booking), | |
index + 2 | |
) | |
end | |
end | |
# Generate spreadsheet for each month of the year | |
# | |
# @return [Integer] | |
# | |
# @api public | |
def generate | |
12.times { |month| worksheet(month) } | |
end | |
# Generate the title row | |
# | |
# @return [] | |
# | |
# @api public | |
def generate_title_row(sheet) | |
sheet[0, 0] = 'Bookings' | |
titles = column_titles | |
titles.delete('Source') unless business_entity && business_entity.widget | |
titles.each_with_index { |title, index| sheet[1, index] = title } | |
end | |
# Generate Stat Row with information from booking | |
# | |
# @return [] | |
# | |
# @api public | |
def generate_stat_row(sheet, booking, row) | |
methods = stat_row_methods | |
methods.delete(:source) unless business_entity && business_entity.widget | |
methods.each_with_index do |method, index| | |
sheet[row, index] = booking.send(method) | |
end | |
end | |
# Record the workbook to the filepath | |
# | |
# @return [] | |
# | |
# @api public | |
def record_file | |
workbook.write file_path | |
end | |
private | |
# Beginning of Year | |
# | |
# @return [Date] | |
# | |
# @api private | |
def start_date | |
date.beginning_of_year | |
end | |
# Build a new spreadsheet | |
# | |
# @return [Spreadsheet::Workbook] | |
# | |
# @api private | |
def workbook | |
Spreadsheet::Workbook.new | |
end | |
memoize :workbook, | |
:start_date | |
end |
This file contains hidden or 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
class ReportPresenter < BookingPresenter | |
delegate :phone, :email, :full_name, to: :user, prefix: true | |
delegate :names, :breeds, to: :pets, prefix: true | |
# Users full address | |
# | |
# @return [String] | |
# | |
# @api public | |
def user_full_address | |
address = "#{user.address1} #{user.address2} #{user.city} #{user.state} #{user.zip}" | |
address.blank? ? 'N/A' : address.strip | |
end | |
# Boarding Facility Address For Reports | |
# | |
# @return [String] | |
# | |
# @api public | |
def location_address | |
"#{location_name} - #{boarding_facility.city_name}" | |
end | |
# Booking total price with discount applied | |
# | |
# @return [String] | |
# | |
# @api public | |
def total_price_with_discount | |
number_to_currency(total_price + discount.to_f, precision: 2) | |
end | |
# display room names | |
# | |
# @return [String] | |
# | |
# @api public | |
def room_names | |
super.join(', ') | |
end | |
def display_check_in | |
check_in.strftime('%-m/%-d/%-y') | |
end | |
def display_check_out | |
check_out.strftime('%-m/%-d/%-y') | |
end | |
end |
This file contains hidden or 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
class Report < ActiveRecord::Base | |
attr_accessible :kennel_id, :year, :file_file_name, :file_content_type, :file_file_size, :file_updated_at | |
belongs_to :kennel | |
# has_attached_file :file, {url: "/system/:class/:id/:filename"} | |
has_attached_file :file, REPORT_STORAGE | |
def generate | |
start_date = Date.parse("#{year}-01-01") | |
end_date = Date.parse("#{year}-12-31") | |
book = Spreadsheet::Workbook.new | |
12.times do |i| | |
month = start_date + i.months | |
sheet = book.create_worksheet name: "#{month.strftime("%B")} #{month.year}" | |
sheet[0,0] = "Bookings" | |
sheet[1,0] = "Cust. Name" | |
sheet[1,1] = "Email" | |
sheet[1,2] = "Phone" | |
sheet[1,3] = "Address" | |
sheet[1,4] = "Location" | |
sheet[1,5] = "Check in" | |
sheet[1,6] = "Check out" | |
sheet[1,7] = "Room" | |
sheet[1,8] = "Pet Name" | |
sheet[1,9] = "Breed" | |
sheet[1,10] = "# Nights" | |
if kennel.widget | |
sheet[1,11] = "Source" | |
sheet[1,12] = "Amount" | |
else | |
sheet[1,11] = "Amount" | |
end | |
row = 2 | |
kennel.bookings.where("created_at >= ? AND created_at <= ?", | |
month.beginning_of_month.beginning_of_day, | |
month.end_of_month.end_of_day).each do |b| | |
user = b.user | |
sheet[row,0] = user.full_name | |
sheet[row,1] = user.email | |
sheet[row,2] = user.phone | |
sheet[row,3] = "#{user.address1} #{user.address2} #{user.city} #{user.state}, #{user.zip}" | |
sheet[row,4] = "#{b.location.name}- #{b.location.city_name}" if b.location | |
sheet[row,5] = b.check_in.strftime("%m/%d/%y") | |
sheet[row,6] = b.check_out.strftime("%m/%d/%y") | |
sheet[row,7] = b.room.name if b.room | |
sheet[row,8] = b.pets.map{|x| x.name}.join(",") if b.pets.any? | |
sheet[row,9] = b.pets.map{|x| x.breed}.join(",") if b.pets.any? | |
sheet[row,10] = b.nights | |
if kennel.widget | |
sheet[row,11] = b.source | |
sheet[row,12] = "$#{b.total_price + b.discount.to_f}" | |
else | |
sheet[row,11] = "$#{b.total_price + b.discount.to_f}" | |
end | |
row += 1 | |
end | |
end | |
file_path = "#{Rails.root}/tmp/#{kennel.name.downcase.gsub(" ", "-").gsub(/[^a-zA-Z\d\s:-]/, '')}_#{year}_report.xls" | |
book.write file_path | |
self.file = File.open(file_path) | |
File.delete(file_path) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment