Skip to content

Commit

Permalink
Quarterly numeric answer data exports
Browse files Browse the repository at this point in the history
Splitted some headers of the numeric answer data export table into
year quarters. As required, those are:
- Sum of Disbursements
- Sum of Repayments
- Repayments of Principal
- Repayments of Interest
- Final Principal Balance
- Final Interest Balance

The format of the splitted headers is "<KEY> Q<quarter-number><year>"
  • Loading branch information
Novruu committed Sep 2, 2024
1 parent b8ebbb0 commit 22b07ec
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 6 deletions.
5 changes: 3 additions & 2 deletions app/models/data_export.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ def self.model_name
def process_data
@child_errors = []
data = []
data.concat(header_rows)
quarters = type == "NumericAnswerDataExport" ? quarters_between(start_date, end_date) : nil
data.concat(header_rows(quarters))
scope.find_each do |object|
begin
data << hash_to_row(object_data_as_hash(object))
data << hash_to_row(object_data_as_hash(object, quarters))
rescue => e
Rails.logger.error("Error for loan #{object.id} in data export #{self.name}: #{e}")

Expand Down
4 changes: 2 additions & 2 deletions app/models/enhanced_loan_data_export.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class EnhancedLoanDataExport < StandardLoanDataExport

protected

def object_data_as_hash(loan)
def object_data_as_hash(loan, _)
super.merge(response_hash(loan))
end

Expand Down Expand Up @@ -48,7 +48,7 @@ def q_data_types
["boolean", "text", "number", "percentage", "rating", "currency", "range"]
end

def header_rows
def header_rows(_)
[main_header_row, question_id_row]
end

Expand Down
140 changes: 140 additions & 0 deletions app/models/numeric_answer_data_export.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,149 @@
class NumericAnswerDataExport < EnhancedLoanDataExport

QUARTERLY_KEYS = [
:sum_of_disbursements, :sum_of_repayments, :repayments_of_principal,
:repayments_of_interest, :final_principal_balance, :final_interest_balance
]

def q_data_types
["number", "percentage", "rating", "currency", "range"]
end

def include_numeric_answer_in_export?(str)
true if Float(str) rescue false
end

protected

def object_data_as_hash(loan, quarters)

hash = {
loan_id: loan.id,
name: loan.name,
division: loan.division_name,
division_membership_status: loan.division_membership_status,
cooperative: loan.coop_name,
address: loan.coop_street_address,
city: loan.coop_city,
state: loan.coop_state,
country: loan.coop_country&.name,
postal_code: loan.coop_postal_code,
entity_structure: loan.coop_entity_structure,
naics_code: loan.coop_naics_code,
census_tract_code: loan.coop_census_tract_code,
date_established: loan.coop_date_established,
status: loan.status.to_s,
actual_end_date: loan.actual_end_date,
actual_first_payment_date: loan.actual_first_payment_date,
projected_end_date: loan.projected_end_date,
projected_first_payment_date: loan.projected_first_payment_date,
signing_date: loan.signing_date,
length_months: loan.length_months,
loan_type: loan.loan_type.to_s,
currency: loan.currency&.name,
amount: loan.amount,
rate: loan.rate,
source_of_capital: loan.source_of_capital,
final_repayment_formula: loan.final_repayment_formula,
primary_agent: loan.primary_agent&.name,
secondary_agent: loan.secondary_agent&.name,
num_accounting_warnings: loan.num_sync_issues_by_level(:warning),
num_accounting_errors: loan.num_sync_issues_by_level(:error),
accrued_interest: loan.total_accrued_interest(start_date: start_date, end_date: end_date),
change_in_principal: loan.change_in_principal(start_date: start_date, end_date: end_date),
change_in_interest: loan.change_in_interest(start_date: start_date, end_date: end_date)
}

hash.transform_keys! { |k| I18n.t("standard_loan_data_exports.headers.#{k}") }

for key in QUARTERLY_KEYS do
for quarter in quarters do
hash["#{I18n.t("standard_loan_data_exports.headers.#{key}")} #{quarter[2]}"] = loan.send(key, start_date: quarter[0], end_date: quarter[1])
end
end

hash["#{I18n.t("standard_loan_data_exports.headers.#{:created_at}")}"] = loan.created_at.to_date
hash["#{I18n.t("standard_loan_data_exports.headers.#{:updated_at}")}"] = loan.updated_at.to_date

return hash.merge(response_hash(loan))
end

def header_rows(quarters)
[main_header_row(quarters), question_id_row]
end

def main_header_row(quarters)
headers = StandardLoanDataExport::HEADERS - QUARTERLY_KEYS
updated_at = I18n.t("standard_loan_data_exports.headers.#{headers.pop}")
created_at = I18n.t("standard_loan_data_exports.headers.#{headers.pop}")
headers.map! { |h| I18n.t("standard_loan_data_exports.headers.#{h}") }

for key in QUARTERLY_KEYS do
for quarter in quarters do
headers.push("#{I18n.t("standard_loan_data_exports.headers.#{key}")} #{quarter[2]}")
end
end

headers.push(created_at)
headers.push(updated_at)

@main_headers = headers
@total_headers = headers + questions.map { |q| q.label.to_s }
@quarters = quarters

return @total_headers
end

def question_id_row
row = [I18n.t("standard_loan_data_exports.headers.question_id")]
row[@main_headers.size - 1] = nil
row + questions.map(&:id)
end

def header_symbols
@header_symbols ||= @main_headers + questions.map(&:id)
end

private

def add_quarters_per_key(hash, quarters, key)
for quarter in quarters do
hash["#{key} #{quarter[0]} - #{quarter[1]}".to_sym] = "data"
end
end

def get_quarter(date)
remaining = (date.month - (3 * (date.month / 3.0).ceil)).abs
end_month = date.month + remaining
end_day = Date.civil(date.year, end_month, -1).day

return [
"#{date.year}/#{date.month}/#{date.day}",
"#{date.year}/#{end_month}/#{end_day}",
"Q#{(end_month / 3.0).ceil}#{date.year}",
Date.civil(end_month >= 12 ? date.year + 1 : date.year, end_month >= 12 ? 1 : end_month + 1, 1)
]
end

def quarters_between(date_a, date_b)
if (date_a >= date_b)
Rails.logger.error("Invalid dates")
return
end

quarters = []
next_quarter = date_a

loop do
quarter_start, quarter_end, quarter_name, next_quarter = get_quarter(next_quarter)
quarters = quarters.append([ quarter_start, quarter_end, quarter_name ])

if next_quarter > date_b
break
end
end

quarters[-1][1] = "#{date_b.year}/#{date_b.month}/#{date_b.day}"
return quarters
end
end
4 changes: 2 additions & 2 deletions app/models/standard_loan_data_export.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def scope

private

def object_data_as_hash(loan)
def object_data_as_hash(loan, _)
{
loan_id: loan.id,
name: loan.name,
Expand Down Expand Up @@ -104,7 +104,7 @@ def header_symbols
HEADERS
end

def header_rows
def header_rows(_)
[HEADERS.map { |h| I18n.t("standard_loan_data_exports.headers.#{h}") }]
end
end

0 comments on commit 22b07ec

Please sign in to comment.