Skip to content

Instantly share code, notes, and snippets.

@ruvaleev
Created February 27, 2020 06:55
Show Gist options
  • Save ruvaleev/e6f6a26840ac6d7e239a14e76aec3a9b to your computer and use it in GitHub Desktop.
Save ruvaleev/e6f6a26840ac6d7e239a14e76aec3a9b to your computer and use it in GitHub Desktop.
Новый экспорт, чтоб память не раздувалась
require 'securerandom'
require 'fileutils'
##
# Родительский класс экспортов.
class BaseExport
attr_reader :objects, :export, :format, :file_name, :errors
EXPORT_DIRECTORY_NAME = 'export_files'.freeze
##
# Инициализация инстанса.
def initialize(objects, export, format = 'xlsx')
@objects = objects
@export = export
@format = format
@file_name = "#{export.id}_#{SecureRandom.urlsafe_base64}"
@errors = []
end
##
# Основная логика формирования отчета.
def call
create_exports_directory
if @format.eql?('xlsx')
xls_export
elsif @format.eql?('csv')
csv_export
end
export.update(file_path: "#{EXPORT_DIRECTORY_NAME}/#{file_name}.#{format}")
self
end
def success?
errors.empty?
end
def failure?
!success?
end
private
#
## Создает папку экспортов, если она отсутствует.
def create_exports_directory
path = "#{Rails.public_path}/#{EXPORT_DIRECTORY_NAME}/"
Dir.mkdir(path) unless File.exist?(path)
end
##
# Путь к файлу.
def file_path
Rails.public_path.join(EXPORT_DIRECTORY_NAME, "#{file_name}.#{format}")
end
##
# Отчет в .xslx
def xls_export
to_xls_export.serialize(file_path)
end
##
# Отчет в .csv
def csv_export
to_csv_export
end
##
# Запись данных в xlsx файл.
def to_xls_export
Axlsx::Package.new do |xlsx_package|
workbook = xlsx_package.workbook
worksheet = workbook.add_worksheet(name: 'Export')
header_style = worksheet.styles.add_style(b: true, alignment: { horizontal: :center, vertical: :center })
basic_style = worksheet.styles.add_style(b: false, alignment: { horizontal: :center, vertical: :center })
worksheet.add_row(export_headers, style: header_style)
objects.each do |instance|
begin
data = export_row(instance.decorate)
types = Array.new(data.count, :string)
worksheet.add_row(data, style: basic_style, types: types)
rescue StandardError => e
errors << "#{instance.id}: #{e.to_s}"
end
end
end
end
##
# Запись данных в csv файл.
def to_csv_export
CSV.open(file_path, 'w') do |csv|
csv << export_headers
objects.each do |instance|
begin
csv << export_row(instance.decorate)
rescue StandardError => e
errors << "#{instance.id}: #{e.to_s}"
end
end
end
end
end
##
# Экспорт заявок.
class ApplicationsManagement::Export < BaseExport
include ExportHelper
# Заголовки файла отчета.
def export_headers # rubocop:disable Metrics/MethodLength
[
'ID',
'Status',
'Borrower',
'Loan sum',
'Approved loan sum',
'Requested loan sum',
'Loan term',
'Gender',
'Date of bir',
'Mobile phone',
'Document number',
'Email',
'Loan type',
'Check status',
'Reason',
'Verificator name',
'Verification mobile phone status',
'Verification mobile phone reason',
'Verification work phone status',
'Verification work phone reason',
'Verification guarantor phone status',
'Verification guarantor phone reason',
'PV comments',
'Mobile phone call comments',
'Work phone call comments',
'Contact person phone call comments',
'TS name',
'TS comments',
'Living postal code',
'Living province',
'Living city',
'Living district',
'Living street',
'Living house number',
'Living apartment number',
'Living home phone',
'Work place',
'Work guarantor full name',
'Work position',
'Work address',
'Work phone',
'Work industry',
'Social status',
'Monly income',
'Bank name',
'Bank account holder',
'Bank account number',
'Bank branch name',
'Bank branch code',
'Bank code',
'IP',
'Browser',
'Number of children',
'Guarantor',
'UUID',
'Have contract',
'repeat sale',
'Number of revisions monly income field',
'Number of revisions document number field',
'Number of revisions mobile phone field',
'Number of revisions work phone field',
'Created at',
'Updated at',
'Action date',
'Staff id',
'Next at',
'Start at',
'End at',
'Iamreal vfv result',
'Iamreal vfv reason',
'Iamreal fb score',
'Iamreal fb significance',
'Iamreal processed at',
'Approval kind',
'KYC'
]
end
##
# Записываемые данные по каждой заявке.
def export_row(application) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
[
application.id,
application.status,
application.display_full_name,
application.display_amount,
application.display_approved_loan_sum,
application.display_requested_loan_sum,
application.display_term_raw,
application.display_gender,
application.display_date_of_birth,
application.mobile_phone,
application.document_number,
application.email,
application.loan_type,
application.check&.status,
application.check&.stop_factors && application&.check&.stop_factors&.map(&:humanize)&.join(', '),
application.display_verificator_name,
application.phones_verification&.calls&.find { |x| x.type.eql?('mobile_phone') }&.status || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('mobile_phone') }&.result&.title || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('work_phone') }&.status || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('work_phone') }&.result&.title || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('guarantor_mobile_phone') }&.status || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('guarantor_mobile_phone') }&.result&.title || 'N/A',
application.comments.map { |c| "#{c.text} (#{c.author.full_name})" }.join(' / '),
application.phones_verification&.calls&.find { |x| x.type.eql?('mobile_phone') }&.comments&.join(' / ') || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('work_phone') }&.comments&.join(' / ') || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('guarantor_mobile_phone') }&.comments&.join(' / ') || 'N/A',
application.telesales_staff_name,
application.telesales_comments,
application.living_postal_code,
application.living_province&.title,
application.living_city&.title,
application.living_district&.title,
application.living_street,
application.living_house_number,
application.living_apartment_number,
application.living_home_phone,
application.work_place,
application.work_guarantor_full_name,
application.work_position,
application.work_address,
application.work_phone,
application.display_working_industry,
application&.occupation&.translations&.select { |x| x.locale.eql?('en') }&.first&.value || '',
application.display_monthly_income,
application.bank_name,
application.bank_account_holder,
application.bank_account_number,
application.bank_branch_name,
application.bank_branch_code,
application.bank_code,
application.ip,
application.browser,
application.number_of_children,
application.guarantor.full_name,
application.uuid,
application.have_contract,
application.repeat_sale,
application.number_of_revisions_monthly_income_field,
application.number_of_revisions_document_number_field,
application.number_of_revisions_mobile_phone_field,
application.number_of_revisions_work_phone_field,
application.created_at,
application.updated_at,
application.action_date,
application.staff_id,
application.next_at,
application.start_at,
application.end_at,
application.iamreal_vfv_result,
application.iamreal_vfv_reason,
application.iamreal_fb_score,
application.iamreal_fb_significance,
application.iamreal_processed_at,
display_approval_kind(application.approval_kind),
application.photo_urls.present? ? 'Yes' : 'No'
]
end
end
##
# Экспорт заявок.
class ApplicationsManagement::NewExport < BaseExport
attr_reader :objects_ids, :export_id, :format, :file_name, :errors
include ExportHelper
# Инициализация инстанса.
def initialize(objects_ids, export_id, format = 'xlsx')
@objects_ids = objects_ids
@export_id = export_id
@format = format
@file_name = "#{export_id}_#{SecureRandom.urlsafe_base64}"
@errors = []
end
##
# Основная логика формирования отчета.
def call
create_exports_directory
if @format.eql?('xlsx')
xls_export
elsif @format.eql?('csv')
csv_export
end
Export.find(export_id).update(file_path: "#{EXPORT_DIRECTORY_NAME}/#{file_name}.#{format}")
self
end
def success?
errors.empty?
end
def failure?
!success?
end
private
#
## Создает папку экспортов, если она отсутствует.
def create_exports_directory
path = "#{Rails.public_path}/#{EXPORT_DIRECTORY_NAME}/"
Dir.mkdir(path) unless File.exist?(path)
end
##
# Отчет в .xslx
def xls_export
to_xls_export.serialize(file_path)
end
##
# Отчет в .csv
def csv_export
to_csv_export
end
##
# Запись данных в xlsx файл.
def to_xls_export
Axlsx::Package.new do |xlsx_package|
workbook = xlsx_package.workbook
worksheet = workbook.add_worksheet(name: 'Export')
header_style = worksheet.styles.add_style(b: true, alignment: { horizontal: :center, vertical: :center })
basic_style = worksheet.styles.add_style(b: false, alignment: { horizontal: :center, vertical: :center })
worksheet.add_row(export_headers, style: header_style)
objects_ids.each do |application_id|
begin
write_row(application_id, worksheet, basic_style)
rescue StandardError => e
errors << "#{application_id}: #{e.to_s}"
end
end
end
end
def write_row(application_id, worksheet, basic_style)
application = Application.find(application_id)
data = export_row(application.decorate)
types = Array.new(data.size, :string)
worksheet.add_row(data, style: basic_style, types: types)
end
##
# Путь к файлу.
def file_path
Rails.public_path.join(EXPORT_DIRECTORY_NAME, "#{file_name}.#{format}")
end
##
# Запись данных в csv файл.
def to_csv_export
CSV.open(file_path, 'w') do |csv|
csv << export_headers
objects.each do |instance|
begin
csv << export_row(instance.decorate)
rescue StandardError => e
errors << "#{instance.id}: #{e.to_s}"
end
end
end
end
# Заголовки файла отчета.
def export_headers # rubocop:disable Metrics/MethodLength
[
'ID',
'Status',
'Borrower',
'Loan sum',
'Approved loan sum',
'Requested loan sum',
'Loan term',
'Gender',
'Date of bir',
'Mobile phone',
'Document number',
'Email',
'Loan type',
'Check status',
'Reason',
'Verificator name',
'Verification mobile phone status',
'Verification mobile phone reason',
'Verification work phone status',
'Verification work phone reason',
'Verification guarantor phone status',
'Verification guarantor phone reason',
'PV comments',
'Mobile phone call comments',
'Work phone call comments',
'Contact person phone call comments',
'TS name',
'TS comments',
'Living postal code',
'Living province',
'Living city',
'Living district',
'Living street',
'Living house number',
'Living apartment number',
'Living home phone',
'Work place',
'Work guarantor full name',
'Work position',
'Work address',
'Work phone',
'Work industry',
'Social status',
'Monly income',
'Bank name',
'Bank account holder',
'Bank account number',
'Bank branch name',
'Bank branch code',
'Bank code',
'IP',
'Browser',
'Number of children',
'Guarantor',
'UUID',
'Have contract',
'repeat sale',
'Number of revisions monly income field',
'Number of revisions document number field',
'Number of revisions mobile phone field',
'Number of revisions work phone field',
'Created at',
'Updated at',
'Action date',
'Staff id',
'Next at',
'Start at',
'End at',
'Iamreal vfv result',
'Iamreal vfv reason',
'Iamreal fb score',
'Iamreal fb significance',
'Iamreal processed at',
'Approval kind',
'KYC'
]
end
##
# Записываемые данные по каждой заявке.
def export_row(application) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
[
application.id,
application.status,
application.display_full_name,
application.display_amount,
application.display_approved_loan_sum,
application.display_requested_loan_sum,
application.display_term_raw,
application.display_gender,
application.display_date_of_birth,
application.mobile_phone,
application.document_number,
application.email,
application.loan_type,
application.check&.status,
application.check&.stop_factors && application&.check&.stop_factors&.map(&:humanize)&.join(', '),
application.display_verificator_name,
application.phones_verification&.calls&.find { |x| x.type.eql?('mobile_phone') }&.status || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('mobile_phone') }&.result&.title || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('work_phone') }&.status || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('work_phone') }&.result&.title || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('guarantor_mobile_phone') }&.status || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('guarantor_mobile_phone') }&.result&.title || 'N/A',
application.comments.map { |c| "#{c.text} (#{c.author.full_name})" }.join(' / '),
application.phones_verification&.calls&.find { |x| x.type.eql?('mobile_phone') }&.comments&.join(' / ') || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('work_phone') }&.comments&.join(' / ') || 'N/A',
application.phones_verification&.calls&.find { |x| x.type.eql?('guarantor_mobile_phone') }&.comments&.join(' / ') || 'N/A',
application.telesales_staff_name,
application.telesales_comments,
application.living_postal_code,
application.living_province&.title,
application.living_city&.title,
application.living_district&.title,
application.living_street,
application.living_house_number,
application.living_apartment_number,
application.living_home_phone,
application.work_place,
application.work_guarantor_full_name,
application.work_position,
application.work_address,
application.work_phone,
application.display_working_industry,
application&.occupation&.translations&.select { |x| x.locale.eql?('en') }&.first&.value || '',
application.display_monthly_income,
application.bank_name,
application.bank_account_holder,
application.bank_account_number,
application.bank_branch_name,
application.bank_branch_code,
application.bank_code,
application.ip,
application.browser,
application.number_of_children,
application.guarantor.full_name,
application.uuid,
application.have_contract,
application.repeat_sale,
application.number_of_revisions_monthly_income_field,
application.number_of_revisions_document_number_field,
application.number_of_revisions_mobile_phone_field,
application.number_of_revisions_work_phone_field,
application.created_at,
application.updated_at,
application.action_date,
application.staff_id,
application.next_at,
application.start_at,
application.end_at,
application.iamreal_vfv_result,
application.iamreal_vfv_reason,
application.iamreal_fb_score,
application.iamreal_fb_significance,
application.iamreal_processed_at,
display_approval_kind(application.approval_kind),
application.photo_urls.present? ? 'Yes' : 'No'
]
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment