Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fix LoanReport #129

Merged
merged 12 commits into from

2 participants

Oliver Legg James Abley
Oliver Legg

Include Legacy SFLG loans when the modified_by_legacy_id is NULL.

Oliver Legg

Don't merge this in please. Needs some further changes based on feedback from CfE.

Oliver Legg

This is ready now.

This turned into a much bigger re-factor to support filtering by "loan type" instead of a (confusing) combination of loan scheme and loan source.

The responsibility of LoanReport has been split into two. The new LoanReport and the LoanReportPresenter.

LoanReport is just responsible for building the query now, given the criteria. LoanReportPresenter is responsible for parsing the form fields, validating the data & presenting varying interfaces depending on the permissions of the user.

James Abley jabley commented on the diff
app/presenters/loan_report_presenter.rb
((108 lines not shown))
+ end
+
+ private
+ def loan_types_are_allowed
+ if loan_types.present? && loan_types.any? { |type| !ALLOWED_LOAN_TYPES.include?(type) }
+ errors.add(:loan_types, :inclusion)
+ end
+ end
+
+ def loan_states_are_allowed
+ if states.present? && states.any? { |state| !ALLOWED_LOAN_STATES.include?(state) }
+ errors.add(:states, :inclusion)
+ end
+ end
+
+ # See http://stackoverflow.com/questions/8929230/why-is-the-first-element-always-blank-in-my-rails-multi-select
James Abley Owner
jabley added a note

This seems to crop up a lot. Is there a better way of fixing it?

James Abley Owner
jabley added a note

Ah, was it just moved from elsewhere in the codebase?

Oliver Legg
olly added a note

Yeah, just a refactor. We do use something similar in a couple of other places in the codebase. But not enough to abstract out just yet, IMO.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
James Abley jabley commented on the diff
app/reports/loan_report.rb
((101 lines not shown))
- 'loans.guarantee_rate AS loan_guarantee_rate',
- 'loans.premium_rate AS loan_premium_rate',
- 'created_by_user.username AS created_by_username',
- 'modified_by_user.username AS modified_by_username',
- '(SELECT organisation_reference_code FROM lenders WHERE id = loans.lender_id) AS lender_organisation_reference_code',
- '(SELECT recovered_on FROM recoveries WHERE loan_id = loans.id ORDER BY recoveries.id DESC LIMIT 1) AS last_recovery_on',
- '(SELECT SUM(amount_due_to_dti) FROM recoveries WHERE loan_id = loans.id) AS total_recoveries',
- '(SELECT created_at FROM loan_realisations WHERE realised_loan_id = loans.id ORDER BY loan_realisations.id DESC LIMIT 1) AS last_realisation_at',
- '(SELECT SUM(realised_amount) FROM loan_realisations WHERE realised_loan_id = loans.id) AS total_loan_realisations',
- '(SELECT SUM(amount_drawn) FROM loan_modifications WHERE loan_id = loans.id) AS total_amount_drawn',
- '(SELECT SUM(lump_sum_repayment) FROM loan_modifications WHERE loan_id = loans.id) AS total_lump_sum_repayment'
- ].join(',')
- )
+ if loan_types.present?
+ # Tried to use Arel here, but it was segfaulting. Falling back to string
+ # concatination - what web developers do best...
James Abley Owner
jabley added a note

Concatenation like this kills teh kitties.

The Arel code that was segfaulting is presumably what is commented out below? Very odd that what is presumably walking an AST to generate SQL would segfault.

Oliver Legg
olly added a note

It was very weird. It would reliably crash the server process. I didn't investigate any further - I just resorted to something else.

I've actually removed the lines that do the special case for Legacy SFLG loans (due to a conversation with Linda). This shortens it to the following, which is a little nicer (e7013bf).

  type_condition = ->(type) { "(loans.loan_scheme = '#{type.scheme}' AND loans.loan_source = '#{type.source}')" }
  scope = scope.where(loan_types.map(&type_condition).join(' OR '))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
James Abley jabley merged commit 88f369f into from
James Abley jabley deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
15 app/concerns/presenter_formatter_concern.rb
View
@@ -0,0 +1,15 @@
+module PresenterFormatterConcern
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def format(attribute, options)
+ formatter = options.fetch(:with)
+
+ attr_reader attribute
+
+ define_method("#{attribute}=") do |value|
+ instance_variable_set "@#{attribute}", formatter.parse(value)
+ end
+ end
+ end
+end
15 app/controllers/loan_reports_controller.rb
View
@@ -2,11 +2,11 @@ class LoanReportsController < ApplicationController
before_filter :verify_create_permission
def new
- @loan_report = LoanReport.new
+ @loan_report = LoanReportPresenter.new(current_user)
end
def create
- @loan_report = LoanReport.new(loan_report_params)
+ @loan_report = LoanReportPresenter.new(current_user, params[:loan_report])
if @loan_report.valid?
respond_to do |format|
format.html { render 'summary' }
@@ -22,17 +22,6 @@ def create
end
private
-
- # ensure
- # - allowed_lender_ids is included in loan_report params
- # - loan scheme is set to 'E' in loan_report params if current lender can only access EFG loans
- def loan_report_params
- unless current_lender.can_access_all_loan_schemes?
- params[:loan_report].merge!(loan_scheme: Lender::EFG_SCHEME)
- end
- params[:loan_report].merge(allowed_lender_ids: current_user.lender_ids)
- end
-
def verify_create_permission
enforce_create_permission(LoanReport)
end
48 app/helpers/loan_reports_helper.rb
View
@@ -1,31 +1,4 @@
module LoanReportsHelper
-
- LOAN_SOURCE_NAMES = {
- 'New Scheme' => Loan::SFLG_SOURCE,
- 'Legacy Scheme' => Loan::LEGACY_SFLG_SOURCE
- }
-
- LOAN_SCHEME_NAMES = {
- 'SFLG Only' => Loan::SFLG_SCHEME,
- 'EFG Only' => Loan::EFG_SCHEME
- }
-
- def loan_report_source_options
- LOAN_SOURCE_NAMES.to_a
- end
-
- def loan_report_scheme_options
- LOAN_SCHEME_NAMES.to_a
- end
-
- def loan_source_name(sources)
- sources.collect { |source| LOAN_SOURCE_NAMES.invert[source] }.join(', ')
- end
-
- def loan_scheme_name(scheme)
- LOAN_SCHEME_NAMES.invert[scheme]
- end
-
def loan_report_organisation_names(lender_ids)
Lender.find(lender_ids).collect(&:name).join(' / ')
end
@@ -33,25 +6,4 @@ def loan_report_organisation_names(lender_ids)
def loan_report_states(states)
states.is_a?(Array) && states.collect(&:humanize).join(', ')
end
-
- def loan_report_lender_field(form_builder)
- if current_user.lenders.count == 1
- hidden_field_tag 'loan_report[lender_ids][]', current_lender.id
- else
- form_builder.input :lender_ids, as: :select, collection: current_user.lenders.order_by_name, input_html: { class: 'input-xxlarge', multiple: true }
- end
- end
-
- def loan_report_created_by_field(form_builder)
- if current_user.is_a?(LenderUser)
- form_builder.input :created_by_id, as: :select, collection: current_lender.lender_users, prompt: 'All'
- end
- end
-
- def loan_report_scheme_field(form_builder)
- if current_lender.can_access_all_loan_schemes?
- form_builder.input :loan_scheme, as: :select, collection: loan_report_scheme_options, prompt: 'All'
- end
- end
-
end
10 app/models/loan_types.rb
View
@@ -0,0 +1,10 @@
+module LoanTypes
+ class LoanType < Struct.new(:id, :name, :scheme, :source)
+ end
+
+ LEGACY_SFLG = LoanType.new('legacy_sflg', 'Legacy SFLG', Loan::SFLG_SCHEME, Loan::LEGACY_SFLG_SOURCE)
+ NEW_SFLG = LoanType.new('new_sflg', 'New SFLG', Loan::SFLG_SCHEME, Loan::SFLG_SOURCE)
+ EFG = LoanType.new('efg', 'EFG', Loan::EFG_SCHEME, Loan::SFLG_SOURCE)
+
+ ALL = [LEGACY_SFLG, NEW_SFLG, EFG]
+end
137 app/presenters/loan_report_presenter.rb
View
@@ -0,0 +1,137 @@
+require 'active_model/model'
+
+class LoanReportPresenter
+ class Invalid < RuntimeError
+ def initialize(loan_report)
+ @loan_report = loan_report
+ end
+
+ def message
+ "#{super}: #{@loan_report.errors.full_messages.join(', ')}"
+ end
+ end
+
+ include ActiveModel::Model
+ include PresenterFormatterConcern
+
+ def self.model_name
+ ActiveModel::Name.new(self, nil, 'LoanReport')
+ end
+
+ ALLOWED_LOAN_STATES = Loan::States.sort.freeze
+ ALLOWED_LOAN_TYPES = LoanTypes::ALL.freeze
+ LOAN_TYPES_BY_ID = LoanTypes::ALL.index_by(&:id)
+
+ format :facility_letter_start_date, with: QuickDateFormatter
+ format :facility_letter_end_date, with: QuickDateFormatter
+ format :created_at_start_date, with: QuickDateFormatter
+ format :created_at_end_date, with: QuickDateFormatter
+ format :last_modified_start_date, with: QuickDateFormatter
+ format :last_modified_end_date, with: QuickDateFormatter
+
+ validates_presence_of :lender_ids, :loan_types
+ validates_numericality_of :created_by_id, allow_blank: true
+ validate :loan_types_are_allowed
+ validate :loan_states_are_allowed
+
+ def initialize(user, attributes = {})
+ @user = user
+ super(attributes)
+
+ unless has_loan_type_selection?
+ self.loan_types = [LoanTypes::EFG.id]
+ end
+ end
+
+ attr_reader :user
+
+ # Report Accessors
+ def report
+ # We rely on this presenter being valid to goven the correct access to the
+ # LoanReport model. The presenter should be valid before calling #report.
+ raise Invalid.new(self) unless valid?
+
+ LoanReport.new.tap do |report|
+ report.states = self.states
+ report.loan_types = self.loan_types
+ report.lender_ids = filter_lender_ids(self.lender_ids)
+ report.created_by_id = self.created_by_id
+ report.facility_letter_start_date = self.facility_letter_start_date
+ report.facility_letter_end_date = self.facility_letter_end_date
+ report.created_at_start_date = self.created_at_start_date
+ report.created_at_end_date = self.created_at_end_date
+ report.last_modified_start_date = self.last_modified_start_date
+ report.last_modified_end_date = self.last_modified_end_date
+ end
+ end
+
+ def loans
+ report.loans
+ end
+
+ def count
+ report.count
+ end
+
+ # Form Attributes
+ attr_accessor :created_by_id
+ attr_reader :lender_ids, :loan_types, :states
+
+ def allowed_lenders
+ user.lenders
+ end
+
+ def lender_ids=(lender_ids)
+ @lender_ids = filter_blank_multi_select(lender_ids)
+ end
+
+ def loan_types=(type_ids)
+ type_ids = filter_blank_multi_select(type_ids) || []
+ @loan_types = type_ids.map {|id| LOAN_TYPES_BY_ID[id]}.compact
+ end
+
+ def states=(states)
+ @states = filter_blank_multi_select(states)
+ end
+
+ # Permissions
+ def has_lender_selection?
+ !user.lender.is_a?(Lender)
+ end
+
+ def has_loan_type_selection?
+ user.lender.can_access_all_loan_schemes?
+ end
+
+ def has_created_by_selection?
+ user.lender.is_a?(Lender)
+ end
+
+ private
+ def loan_types_are_allowed
+ if loan_types.present? && loan_types.any? { |type| !ALLOWED_LOAN_TYPES.include?(type) }
+ errors.add(:loan_types, :inclusion)
+ end
+ end
+
+ def loan_states_are_allowed
+ if states.present? && states.any? { |state| !ALLOWED_LOAN_STATES.include?(state) }
+ errors.add(:states, :inclusion)
+ end
+ end
+
+ # See http://stackoverflow.com/questions/8929230/why-is-the-first-element-always-blank-in-my-rails-multi-select
James Abley Owner
jabley added a note

This seems to crop up a lot. Is there a better way of fixing it?

James Abley Owner
jabley added a note

Ah, was it just moved from elsewhere in the codebase?

Oliver Legg
olly added a note

Yeah, just a refactor. We do use something similar in a couple of other places in the codebase. But not enough to abstract out just yet, IMO.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ def filter_blank_multi_select(values)
+ values.is_a?(Array) ? values.reject(&:blank?) : values
+ end
+
+ # User's that can choose a lender are restricted to lender's they can access.
+ # User's that can't choose a lender have it set to their list of lenders.
+ def filter_lender_ids(lender_ids)
+ if has_lender_selection? && lender_ids.present?
+ user.lender_ids & lender_ids.map(&:to_i)
+ else
+ user.lender_ids
+ end
+ end
+end
27 app/reports/base_loan_report.rb
View
@@ -1,27 +0,0 @@
-require 'active_model/model'
-
-class BaseLoanReport
- include ActiveModel::Model
-
- ALLOWED_LOAN_STATES = Loan::States.sort.freeze
-
- def self.date_attribute(*attributes)
- attributes.each do |attribute|
-
- attr_reader attribute
-
- define_method("#{attribute}=") do |value|
- instance_variable_set "@#{attribute}", QuickDateFormatter.parse(value)
- end
-
- end
- end
-
- def count
- @count ||= loans.count
- end
-
- def loans
- raise NotImplementedError, "Define in sub-class"
- end
-end
24 app/reports/loan_audit_report.rb
View
@@ -1,7 +1,25 @@
-class LoanAuditReport < BaseLoanReport
+require 'active_model/model'
+
+class LoanAuditReport
+ include ActiveModel::Model
+
+ ALLOWED_LOAN_STATES = Loan::States.sort.freeze
attr_accessor :state, :lender_id, :event_id
+ # TODO: This could use PresenterFormatterConcern, although it isn't a presenter.
+ def self.date_attribute(*attributes)
+ attributes.each do |attribute|
+
+ attr_reader attribute
+
+ define_method("#{attribute}=") do |value|
+ instance_variable_set "@#{attribute}", QuickDateFormatter.parse(value)
+ end
+
+ end
+ end
+
date_attribute :facility_letter_start_date, :facility_letter_end_date,
:created_at_start_date, :created_at_end_date,
:last_modified_start_date, :last_modified_end_date,
@@ -44,6 +62,10 @@ def loans
scope.order("loans.reference, loan_state_changes.version")
end
+ def count
+ @count ||= loans.count
+ end
+
def event_name
event ? event.name : 'All'
end
178 app/reports/loan_report.rb
View
@@ -1,60 +1,80 @@
-class LoanReport < BaseLoanReport
+class LoanReport
+ attr_accessor :states, :loan_types, :lender_ids, :created_by_id,
+ :facility_letter_start_date, :facility_letter_end_date,
+ :created_at_start_date, :created_at_end_date,
+ :last_modified_start_date, :last_modified_end_date
- class LenderNotAllowed < ArgumentError; end
-
- ALLOWED_LOAN_SOURCES = [ Loan::SFLG_SOURCE, Loan::LEGACY_SFLG_SOURCE ].freeze
-
- ALLOWED_LOAN_SCHEMES = [ Loan::EFG_SCHEME, Loan::SFLG_SCHEME ].freeze
-
- attr_accessor :allowed_lender_ids, :states, :loan_sources, :loan_scheme, :lender_ids, :created_by_id
-
- date_attribute :facility_letter_start_date, :facility_letter_end_date,
- :created_at_start_date, :created_at_end_date,
- :last_modified_start_date, :last_modified_end_date
-
- validates_presence_of :allowed_lender_ids, :lender_ids, :loan_sources
-
- validates_numericality_of :created_by_id, allow_blank: true
-
- validates_inclusion_of :loan_scheme, in: ALLOWED_LOAN_SCHEMES, allow_blank: true
-
- validate :lender_ids_are_allowed
+ def loans
+ loans = scope
+
+ # Loan attributes
+ loans = loans.select('loans.*')
+ loans = loans.select('loans.guarantee_rate AS loan_guarantee_rate')
+ loans = loans.select('loans.premium_rate AS loan_premium_rate')
+
+ # DED Code attributes
+ loans = loans.select('ded_codes.group_description AS ded_code_group_description')
+ loans = loans.select('ded_codes.category_description AS ded_code_category_description')
+ loans = loans.select('ded_codes.code_description AS ded_code_code_description')
+ loans = loans.select('ded_codes.code AS ded_code_code')
+ loans = loans.joins('LEFT JOIN ded_codes ON loans.dti_ded_code = ded_codes.code')
+
+ # Initial Draw attributes
+ loans = loans.select('initial_draw_change.date_of_change AS initial_draw_date')
+ loans = loans.select('initial_draw_change.amount_drawn AS initial_draw_amount')
+ loans = loans.joins('LEFT JOIN loan_modifications AS initial_draw_change ON initial_draw_change.loan_id = loans.id AND initial_draw_change.type = "InitialDrawChange"')
+
+ # Invoice attributes
+ loans = loans.select('invoices.reference AS invoice_reference')
+ loans = loans.joins('LEFT JOIN invoices ON loans.invoice_id = invoices.id')
+
+ # Lending Limit attributes
+ loans = loans.select('lending_limits.name AS lending_limit_name')
+ loans = loans.select('lending_limits.guarantee_rate AS lending_limit_guarantee_rate')
+ loans = loans.select('lending_limits.premium_rate AS lending_limit_premium_rate')
+ loans = loans.joins('LEFT JOIN lending_limits ON loans.lending_limit_id = lending_limits.id')
+
+ # User attributes
+ loans = loans.select('created_by_user.username AS created_by_username')
+ loans = loans.joins('LEFT JOIN users AS created_by_user ON loans.created_by_id = created_by_user.id')
+
+ loans = loans.select('modified_by_user.username AS modified_by_username')
+ loans = loans.joins('LEFT JOIN users AS modified_by_user ON loans.modified_by_id = modified_by_user.id')
+
+ # Sub-Selects
+ loans = loans.select('(SELECT organisation_reference_code FROM lenders WHERE id = loans.lender_id) AS lender_organisation_reference_code')
+ loans = loans.select('(SELECT recovered_on FROM recoveries WHERE loan_id = loans.id ORDER BY recoveries.id DESC LIMIT 1) AS last_recovery_on')
+ loans = loans.select('(SELECT SUM(amount_due_to_dti) FROM recoveries WHERE loan_id = loans.id) AS total_recoveries')
+ loans = loans.select('(SELECT created_at FROM loan_realisations WHERE realised_loan_id = loans.id ORDER BY loan_realisations.id DESC LIMIT 1) AS last_realisation_at')
+ loans = loans.select('(SELECT SUM(realised_amount) FROM loan_realisations WHERE realised_loan_id = loans.id) AS total_loan_realisations')
+ loans = loans.select('(SELECT SUM(amount_drawn) FROM loan_modifications WHERE loan_id = loans.id) AS total_amount_drawn')
+ loans = loans.select('(SELECT SUM(lump_sum_repayment) FROM loan_modifications WHERE loan_id = loans.id) AS total_lump_sum_repayment')
+
+ loans
+ end
- validate :loan_sources_are_allowed
+ def count
+ scope.count
+ end
- validate :loan_states_are_allowed
+ private
+ def scope
+ scope = Loan.scoped
+ scope = scope.where('loans.state IN (?)', states) if states.present?
- def loans
- scope = Loan.select(
- [
- 'ded_codes.group_description AS ded_code_group_description',
- 'ded_codes.category_description AS ded_code_category_description',
- 'ded_codes.code_description AS ded_code_code_description',
- 'ded_codes.code AS ded_code_code',
- 'initial_draw_change.date_of_change AS initial_draw_date',
- 'initial_draw_change.amount_drawn AS initial_draw_amount',
- 'invoices.reference AS invoice_reference',
- 'lending_limits.name AS lending_limit_name',
- 'lending_limits.guarantee_rate AS lending_limit_guarantee_rate',
- 'lending_limits.premium_rate AS lending_limit_premium_rate',
- 'loans.*',
- 'loans.guarantee_rate AS loan_guarantee_rate',
- 'loans.premium_rate AS loan_premium_rate',
- 'created_by_user.username AS created_by_username',
- 'modified_by_user.username AS modified_by_username',
- '(SELECT organisation_reference_code FROM lenders WHERE id = loans.lender_id) AS lender_organisation_reference_code',
- '(SELECT recovered_on FROM recoveries WHERE loan_id = loans.id ORDER BY recoveries.id DESC LIMIT 1) AS last_recovery_on',
- '(SELECT SUM(amount_due_to_dti) FROM recoveries WHERE loan_id = loans.id) AS total_recoveries',
- '(SELECT created_at FROM loan_realisations WHERE realised_loan_id = loans.id ORDER BY loan_realisations.id DESC LIMIT 1) AS last_realisation_at',
- '(SELECT SUM(realised_amount) FROM loan_realisations WHERE realised_loan_id = loans.id) AS total_loan_realisations',
- '(SELECT SUM(amount_drawn) FROM loan_modifications WHERE loan_id = loans.id) AS total_amount_drawn',
- '(SELECT SUM(lump_sum_repayment) FROM loan_modifications WHERE loan_id = loans.id) AS total_lump_sum_repayment'
- ].join(',')
- )
+ if loan_types.present?
+ # Tried to use Arel here, but it was segfaulting. Falling back to string
+ # concatination - what web developers do best...
James Abley Owner
jabley added a note

Concatenation like this kills teh kitties.

The Arel code that was segfaulting is presumably what is commented out below? Very odd that what is presumably walking an AST to generate SQL would segfault.

Oliver Legg
olly added a note

It was very weird. It would reliably crash the server process. I didn't investigate any further - I just resorted to something else.

I've actually removed the lines that do the special case for Legacy SFLG loans (due to a conversation with Linda). This shortens it to the following, which is a little nicer (e7013bf).

  type_condition = ->(type) { "(loans.loan_scheme = '#{type.scheme}' AND loans.loan_source = '#{type.source}')" }
  scope = scope.where(loan_types.map(&type_condition).join(' OR '))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ #
+ # loans = Loan.arel_table
+ # types_conditions = loan_types.map do |type|
+ # condition = (loans[:loan_scheme].eq(type.scheme).and(loans[:loan_source].eq(type.source)))
+ # condition.to_sql
+ # end
+ type_condition = ->(type) { "(loans.loan_scheme = '#{type.scheme}' AND loans.loan_source = '#{type.source}')" }
+ scope = scope.where(loan_types.map(&type_condition).join(' OR '))
+ end
- scope = scope.where('loans.state IN (?)', states) if states.present?
- scope = scope.where('loans.loan_source IN (?)', loan_sources) if loan_sources.present?
- scope = scope.where('loans.loan_scheme = ?', loan_scheme) if loan_scheme.present?
scope = scope.where('loans.lender_id IN (?)', lender_ids) if lender_ids.present?
scope = scope.where('loans.created_by_id = ?', created_by_id) if created_by_id.present?
scope = scope.where('loans.facility_letter_date >= ?', facility_letter_start_date) if facility_letter_start_date.present?
@@ -64,58 +84,6 @@ def loans
scope = scope.where('loans.last_modified_at >= ?', last_modified_start_date.beginning_of_day) if last_modified_start_date.present?
scope = scope.where('loans.last_modified_at <= ?', last_modified_end_date.end_of_day) if last_modified_end_date.present?
- if loan_sources.include?(Loan::LEGACY_SFLG_SOURCE)
- scope = scope.where("loans.modified_by_legacy_id != 'migration'")
- end
-
- scope.joins(
- 'LEFT JOIN ded_codes ON loans.dti_ded_code = ded_codes.code',
- 'LEFT JOIN invoices ON loans.invoice_id = invoices.id',
- 'LEFT JOIN lending_limits ON loans.lending_limit_id = lending_limits.id',
- 'LEFT JOIN loan_modifications AS initial_draw_change ON initial_draw_change.loan_id = loans.id AND initial_draw_change.type = "InitialDrawChange"',
- 'LEFT JOIN users AS created_by_user ON loans.created_by_id = created_by_user.id',
- 'LEFT JOIN users AS modified_by_user ON loans.modified_by_id = modified_by_user.id',
- )
- end
-
- def loan_sources=(sources)
- @loan_sources = filter_blank_multi_select(sources)
+ scope
end
-
- def states=(states)
- @states = filter_blank_multi_select(states)
- end
-
- def lender_ids=(lender_ids)
- @lender_ids = filter_blank_multi_select(lender_ids)
- end
-
- private
-
- def lender_ids_are_allowed
- return if lender_ids.blank?
-
- disallowed_lender_ids = lender_ids.collect(&:to_i) - allowed_lender_ids.collect(&:to_i)
- unless disallowed_lender_ids.empty?
- raise LoanReport::LenderNotAllowed, "Access to loans for lender(s) with ID #{disallowed_lender_ids.join(',')} is forbidden for this report"
- end
- end
-
- def loan_sources_are_allowed
- if loan_sources.present? && loan_sources.any? { |source| !ALLOWED_LOAN_SOURCES.include?(source) }
- errors.add(:loan_sources, :inclusion)
- end
- end
-
- def loan_states_are_allowed
- if states.present? && states.any? { |state| !ALLOWED_LOAN_STATES.include?(state) }
- errors.add(:states, :inclusion)
- end
- end
-
- # See http://stackoverflow.com/questions/8929230/why-is-the-first-element-always-blank-in-my-rails-multi-select
- def filter_blank_multi_select(values)
- values.is_a?(Array) ? values.reject(&:blank?) : values
- end
-
end
18 app/views/loan_reports/new.html.erb
View
@@ -24,15 +24,21 @@
<%= f.input :last_modified_end_date, as: :quick_date %>
- <%= f.input :states, as: :select, collection: loan_state_options(LoanReport::ALLOWED_LOAN_STATES), input_html: { multiple: true } %>
+ <%= f.input :states, as: :select, collection: loan_state_options(LoanReportPresenter::ALLOWED_LOAN_STATES), input_html: { multiple: true } %>
- <%= loan_report_lender_field(f) %>
+ <% if @loan_report.has_lender_selection? %>
+ <%= f.input :lender_ids, as: :select, collection: @loan_report.allowed_lenders.order_by_name, input_html: { class: 'input-xxlarge', multiple: true } %>
+ <% else %>
+ <%= hidden_field_tag 'loan_report[lender_ids][]', current_lender.id %>
+ <% end %>
- <%= loan_report_created_by_field(f) %>
+ <% if @loan_report.has_created_by_selection? %>
+ <%= f.input :created_by_id, as: :select, collection: current_lender.lender_users, prompt: 'All' %>
+ <% end %>
- <%= f.input :loan_sources, as: :check_boxes, collection: loan_report_source_options %>
-
- <%= loan_report_scheme_field(f) %>
+ <% if @loan_report.has_loan_type_selection? %>
+ <%= f.input :loan_types, as: :check_boxes, collection: LoanTypes::ALL %>
+ <% end %>
<div class="form-actions">
<%= f.button :submit, value: 'Submit', class: 'btn-primary', data: { 'disable-with' => 'Submitting...' } %>
17 app/views/loan_reports/summary.html.erb
View
@@ -61,15 +61,11 @@
<td><%= current_lender.lender_users.find(@loan_report.created_by_id).try(:name) %></td>
</tr>
<% end %>
- <tr>
- <td>Loan type(s)</td>
- <td><%= loan_source_name(@loan_report.loan_sources) %></td>
- </tr>
<% if current_lender.can_access_all_loan_schemes? %>
- <tr>
- <td>Loan scheme</td>
- <td><%= loan_scheme_name(@loan_report.loan_scheme) %></td>
- </tr>
+ <tr>
+ <td>Loan Type(s)</td>
+ <td><%= @loan_report.loan_types.map(&:name).to_sentence %></td>
+ </tr>
<% end %>
</tbody>
</table>
@@ -84,7 +80,6 @@
<%= f.hidden_field :created_at_end_date, value: @loan_report.created_at_end_date.try(:to_s, :screen) %>
<%= f.hidden_field :last_modified_start_date, value: @loan_report.last_modified_start_date.try(:to_s, :screen) %>
<%= f.hidden_field :last_modified_end_date, value: @loan_report.last_modified_end_date.try(:to_s, :screen) %>
- <%= f.hidden_field(:loan_scheme) if current_lender.can_access_all_loan_schemes? %>
<%= f.hidden_field :created_by_id %>
<% @loan_report.states.each do |state| %>
@@ -95,8 +90,8 @@
<%= hidden_field_tag 'loan_report[lender_ids][]', lender_id %>
<% end %>
- <% @loan_report.loan_sources.each do |source| %>
- <%= hidden_field_tag 'loan_report[loan_sources][]', source %>
+ <% @loan_report.loan_types.each do |type| %>
+ <%= hidden_field_tag 'loan_report[loan_types][]', type.id %>
<% end %>
<div class="form-actions">
3  config/locales/simple_form.en.yml
View
@@ -256,8 +256,7 @@ en:
states: Select loan state
lender_ids: What is the name of the lender organisation?
created_by_id: To refine your data extraction select the user who created the data
- loan_sources: What is the Loan Type?
- loan_scheme: Loan scheme
+ loan_types: What is the Loan Type?
loan_audit_report:
facility_letter_start_date: What is the date of Scheme Facility Letter start date for your report?
2  db/schema.rb
View
@@ -203,6 +203,8 @@
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "type"
+ t.integer "old_repayment_duration"
+ t.integer "repayment_duration"
end
add_index "loan_modifications", ["loan_id", "seq"], :name => "index_loan_changes_on_loan_id_and_seq", :unique => true
18 spec/controllers/loan_reports_controller_spec.rb
View
@@ -65,24 +65,6 @@ def dispatch(params = {})
dispatch
response.should be_success
end
-
- it "should raise exception when trying to access loans belonging to a different lender" do
- expect {
- dispatch(lender_ids: [ loan.lender.id, loan2.lender.id ])
- }.to raise_error(LoanReport::LenderNotAllowed)
- end
-
- it "should set loan scheme to 'E' when current user's lender can only access EFG scheme loans" do
- lender.loan_scheme = Lender::EFG_SCHEME
- report = double(LoanReport, 'valid?' => false)
-
- LoanReport.
- should_receive(:new).
- with({ "loan_scheme" => Lender::EFG_SCHEME, "allowed_lender_ids" => [ lender.id ] }).
- and_return(report)
-
- dispatch(loan_scheme: 'S')
- end
end
context 'with cfe user' do
13 spec/exports/loan_report_csv_export_spec.rb
View
@@ -4,8 +4,17 @@
describe LoanReportCsvExport do
describe "#generate" do
let!(:lender) { FactoryGirl.create(:lender, organisation_reference_code: 'ABC123') }
- let(:loan_report) { FactoryGirl.build(:loan_report, lender_ids: [lender.id]) }
- let(:loan_report_csv_export) { LoanReportCsvExport.new(loan_report.loans) }
+ let!(:user) { FactoryGirl.create(:lender_user, lender: lender) }
+
+ let(:loan_report_presenter) { LoanReportPresenter.new(user) }
+
+ before do
+ loan_report_presenter.lender_ids = [lender.id]
+ loan_report_presenter.states = Loan::States
+ loan_report_presenter.loan_types = [LoanTypes::EFG.id]
+ end
+
+ let(:loan_report_csv_export) { LoanReportCsvExport.new(loan_report_presenter.loans) }
let(:csv) { CSV.new(loan_report_csv_export.generate, { headers: :first_row }) }
let(:user1) { FactoryGirl.create(:user, username: 'bobby.t') }
9 spec/factories/loan_report_factory.rb
View
@@ -1,9 +0,0 @@
-FactoryGirl.define do
- factory :loan_report do
- states Loan::States
- loan_sources ["S"]
- loan_scheme "E"
- lender_ids [1]
- allowed_lender_ids [1]
- end
-end
215 spec/presenters/loan_report_presenter_spec.rb
View
@@ -0,0 +1,215 @@
+require 'spec_helper'
+require 'csv'
+
+describe LoanReportPresenter do
+
+ describe "#initialize" do
+ let(:user) { double('user') }
+
+ it "should not allow unsupported attributes" do
+ expect {
+ LoanReportPresenter.new(user, report_attributes(company_registration: '123456C'))
+ }.to raise_error(NoMethodError)
+ end
+ end
+
+ describe "validation" do
+ let(:user) { FactoryGirl.create(:lender_user) }
+ let(:loan_report_presenter) { LoanReportPresenter.new(user, report_attributes) }
+
+ it 'should have a valid factory' do
+ loan_report_presenter.should be_valid
+ end
+
+ it 'should be invalid without an allowed loan state' do
+ loan_report_presenter.states = [ "wrong" ]
+ loan_report_presenter.should_not be_valid
+
+ loan_report_presenter.states = [ Loan::Guaranteed ]
+ loan_report_presenter.should be_valid
+ end
+
+ it 'should be invalid without numeric created by user ID' do
+ loan_report_presenter.created_by_id = 'a'
+ loan_report_presenter.should_not be_valid
+ end
+
+ it 'should be valid with blank created by user ID' do
+ loan_report_presenter.created_by_id = ''
+ loan_report_presenter.should be_valid
+ end
+
+ it 'should be invalid without a loan type' do
+ loan_report_presenter.loan_types = nil
+ loan_report_presenter.should_not be_valid
+
+ loan_report_presenter.loan_types = []
+ loan_report_presenter.should_not be_valid
+ end
+
+ it 'should be invalid without a valid loan type' do
+ loan_report_presenter.loan_types = ["Z"]
+ loan_report_presenter.should_not be_valid
+
+ loan_report_presenter.loan_types = [LoanTypes::LEGACY_SFLG.id]
+ loan_report_presenter.should be_valid
+ end
+
+ it 'should be invalid without lender IDs' do
+ loan_report_presenter.lender_ids = nil
+ loan_report_presenter.should_not be_valid
+ end
+
+ it 'should be invalid without a numeric created by ID' do
+ loan_report_presenter.created_by_id = 'a'
+ loan_report_presenter.should_not be_valid
+ end
+ end
+
+ describe "delegating to report" do
+ let(:user) { FactoryGirl.create(:lender_user) }
+ let(:loan_report) { double('LoanReport') }
+ let(:presenter) { LoanReportPresenter.new(user) }
+ before { presenter.stub!(:report).and_return(loan_report) }
+
+ it "delegates #count" do
+ loan_report.should_receive(:count).and_return(45)
+ presenter.count.should == 45
+ end
+
+ it "delgates #loans" do
+ loans = double('loans')
+ loan_report.should_receive(:loans).and_return(loans)
+ presenter.loans.should == loans
+ end
+ end
+
+ describe "permissions" do
+ let(:presenter) { LoanReportPresenter.new(user) }
+
+ context "with AuditorUser" do
+ let(:user) { FactoryGirl.build(:auditor_user) }
+
+ it "allows lender selection" do
+ presenter.should have_lender_selection
+ end
+
+ it "doesn't allow created by selection" do
+ presenter.should_not have_created_by_selection
+ end
+ end
+
+ context "with CfeUser" do
+ let(:user) { FactoryGirl.build(:cfe_user) }
+
+ it "allows lender selection" do
+ presenter.should have_lender_selection
+ end
+
+ it "allows loan type selection" do
+ presenter.should have_loan_type_selection
+ end
+
+ it "doesn't allow created by selection" do
+ presenter.should_not have_created_by_selection
+ end
+ end
+
+ context "with LenderUser" do
+ let(:user) { FactoryGirl.build(:lender_user) }
+
+ it "doesn't allow lender selection" do
+ presenter.should_not have_lender_selection
+ end
+
+ it "allows created by selection" do
+ presenter.should have_created_by_selection
+ end
+ end
+
+ context "with a users's 'lender' that can access all loan schemes" do
+ let(:lender) { double('lender', :can_access_all_loan_schemes? => true)}
+ let(:user) { FactoryGirl.build(:lender_user) }
+ before { user.stub!(:lender).and_return(lender) }
+
+ it "allows loan type selection" do
+ presenter.should have_loan_type_selection
+ end
+ end
+
+ context "with a user's 'lender' that can't access all loan schemes" do
+ let(:lender) { double('lender', :can_access_all_loan_schemes? => false)}
+ let(:user) { FactoryGirl.build(:lender_user) }
+ before { user.stub!(:lender).and_return(lender) }
+
+ it "doesn't allow loan type selection" do
+ presenter.should_not have_loan_type_selection
+ end
+ end
+ end
+
+ describe "#report" do
+ let(:presenter) { LoanReportPresenter.new(user, report_attributes) }
+
+ context "with a LenderUser" do
+ let(:lender) { FactoryGirl.create(:lender) }
+ let(:user) { FactoryGirl.create(:lender_user, lender: lender) }
+
+ it "sets the report's lender_ids the user's lender_id" do
+ presenter.report.lender_ids.should == [lender.id]
+ end
+ end
+
+ context "with a user who can select lenders" do
+ let!(:lender1) { FactoryGirl.create(:lender) }
+ let!(:lender2) { FactoryGirl.create(:lender) }
+ let!(:lender3) { FactoryGirl.create(:lender) }
+ let(:user) { FactoryGirl.build(:cfe_user) }
+
+ it "sets lender_ids to the selected lender_ids" do
+ presenter.lender_ids = [lender1.id, lender3.id]
+ presenter.report.lender_ids.should == [lender1.id, lender3.id]
+ end
+
+ it "removes any lender_ids that the user can't access" do
+ user.stub!(:lender_ids).and_return([lender1.id, lender2.id])
+
+ presenter.lender_ids = [lender1.id, lender3.id]
+ presenter.report.lender_ids.should == [lender1.id]
+ end
+ end
+
+ context "with a user who can access all loan schemes" do
+ let(:lender) { FactoryGirl.create(:lender, loan_scheme: '') }
+ let(:user) { FactoryGirl.create(:lender_user, lender: lender) }
+ let(:presenter) { LoanReportPresenter.new(user) }
+
+ it "doesn't set loan_types" do
+ presenter.loan_types.should be_nil
+ end
+ end
+
+ context "with a user who can't access all loan schemes" do
+ let(:lender) { FactoryGirl.create(:lender, loan_scheme: 'E') }
+ let(:user) { FactoryGirl.create(:lender_user, lender: lender) }
+ let(:presenter) { LoanReportPresenter.new(user) }
+
+ it "sets the loan_types to EFG" do
+ presenter.loan_types.should == [LoanTypes::EFG]
+ end
+ end
+ end
+
+ private
+
+ def report_attributes(params = {})
+ lender_ids = Lender.count.zero? ? [ 1 ] : Lender.all.collect(&:id)
+
+ {
+ lender_ids: lender_ids,
+ loan_types: [LoanTypes::NEW_SFLG.id, LoanTypes::EFG.id],
+ states: Loan::States,
+ }.merge(params)
+ end
+
+end
243 spec/reports/loan_report_spec.rb
View
@@ -1,283 +1,144 @@
require 'spec_helper'
-require 'csv'
describe LoanReport do
-
- describe "#initialize" do
- it "should not allow unsupported attributes" do
- expect {
- LoanReport.new(report_attributes(company_registration: '123456C'))
- }.to raise_error(NoMethodError)
- end
- end
-
- describe "validation" do
- let(:loan_report) { LoanReport.new(report_attributes) }
-
- it 'should have a valid factory' do
- loan_report.should be_valid
- end
-
- it 'should be invalid without an allowed loan state' do
- loan_report.states = [ "wrong" ]
- loan_report.should_not be_valid
-
- loan_report.states = [ Loan::Guaranteed ]
- loan_report.should be_valid
- end
-
- it 'should be invalid without numeric created by user ID' do
- loan_report.created_by_id = 'a'
- loan_report.should_not be_valid
- end
-
- it 'should be valid with blank created by user ID' do
- loan_report.created_by_id = ''
- loan_report.should be_valid
- end
-
- it 'should be invalid without a loan source' do
- loan_report.loan_sources = nil
- loan_report.should_not be_valid
- end
-
- it 'should be invalid without an allowed loan source' do
- loan_report.loan_sources = ["Z"]
- loan_report.should_not be_valid
-
- loan_report.loan_sources = [ Loan::LEGACY_SFLG_SOURCE ]
- loan_report.should be_valid
- end
-
- it 'should be valid when loan scheme is nil' do
- loan_report.loan_scheme = nil
- loan_report.should be_valid
- end
-
- it 'should be valid with a blank loan scheme' do
- loan_report.loan_scheme = ""
- loan_report.should be_valid
- end
-
- it 'should be invalid without an allowed loan scheme' do
- loan_report.loan_scheme = "Z"
- loan_report.should_not be_valid
-
- loan_report.loan_scheme = Loan::EFG_SCHEME
- loan_report.should be_valid
- end
-
- it 'should be invalid without lender IDs' do
- loan_report.lender_ids = nil
- loan_report.should_not be_valid
- end
-
- it 'should be invalid without a numeric created by ID' do
- loan_report.created_by_id = 'a'
- loan_report.should_not be_valid
- end
-
- it "should raise exception when a specified lender is not allowed" do
- loan1 = FactoryGirl.create(:loan, :eligible)
- loan2 = FactoryGirl.create(:loan, :guaranteed)
-
- loan_report.allowed_lender_ids = [ loan2.lender_id ]
- loan_report.lender_ids = [ loan1.lender_id, loan2.lender_id ]
-
- expect {
- loan_report.valid?
- }.to raise_error(LoanReport::LenderNotAllowed)
- end
- end
-
describe "#count" do
-
let!(:loan1) { FactoryGirl.create(:loan, :eligible) }
-
let!(:loan2) { FactoryGirl.create(:loan, :guaranteed) }
+ let(:loan_report) { LoanReport.new }
- let(:loan_report) { LoanReport.new(report_attributes) }
-
- it "should return the total number of loans matching the report criteria" do
+ it "returns the total number of loans matching the report criteria" do
loan_report.count.should == 2
end
- it "should return the total number of loans with state guaranteed" do
+ it "returns the total number of loans with state guaranteed" do
loan_report.states = [ Loan::Guaranteed ]
loan_report.count.should == 1
end
-
end
describe "#loans" do
-
let!(:loan1) { FactoryGirl.create(:loan) }
-
let!(:loan2) { FactoryGirl.create(:loan) }
+ let(:loan_report) { LoanReport.new }
- let(:loan_report) { LoanReport.new(report_attributes) }
-
- it "should return all loans when matching the default report criteria" do
+ it "returns all loans when matching the default report criteria" do
loan_report.loans.should == [loan1, loan2]
end
- it "should return loans with a specific state" do
+ it "returns loans with a specific state" do
guaranteed_loan = FactoryGirl.create(:loan, :guaranteed)
- loan_report = LoanReport.new(report_attributes(states: [ Loan::Guaranteed ]))
- loan_report.loans.should == [ guaranteed_loan ]
+ loan_report.states = [Loan::Guaranteed]
+ loan_report.loans.should == [guaranteed_loan]
end
- it "should return loans with a specific loan scheme" do
- sflg_loan = FactoryGirl.create(:loan, :sflg)
+ it "returns loans with the Legacy SFLG type" do
+ legacy_sflg_loan = FactoryGirl.create(:loan, :legacy_sflg)
- loan_report = LoanReport.new(report_attributes(loan_scheme: Loan::SFLG_SCHEME))
- loan_report.loans.should == [ sflg_loan ]
+ loan_report.loan_types = [LoanTypes::LEGACY_SFLG]
+ loan_report.loans.should == [legacy_sflg_loan]
end
- it "should return loans with a specific loan source" do
- legacy_sflg_loan = FactoryGirl.create(:loan, loan_source: Loan::LEGACY_SFLG_SOURCE)
+ it "returns loans with the New SFLG type" do
+ sflg_loan = FactoryGirl.create(:loan, :sflg)
- loan_report = LoanReport.new(report_attributes(loan_sources: [ Loan::LEGACY_SFLG_SOURCE ]))
- loan_report.loans.should == [ legacy_sflg_loan ]
+ loan_report.loan_types = [LoanTypes::NEW_SFLG]
+ loan_report.loans.should == [sflg_loan]
end
- it "should return loans with a facility letter date after a specified date" do
+ it "returns loans with a facility letter date after a specified date" do
loan1.update_attribute(:facility_letter_date, 1.day.ago)
loan2.update_attribute(:facility_letter_date, 1.day.from_now)
- loan_report = LoanReport.new(report_attributes(facility_letter_start_date: Date.today.strftime('%d/%m/%Y')))
-
- loan_report.loans.should == [ loan2 ]
+ loan_report.facility_letter_start_date = Date.today
+ loan_report.loans.should == [loan2]
end
- it "should return loans with a facility letter date before a specified date" do
+ it "returns loans with a facility letter date before a specified date" do
loan1.update_attribute(:facility_letter_date, 1.day.ago)
loan2.update_attribute(:facility_letter_date, 1.day.from_now)
- loan_report = LoanReport.new(report_attributes(facility_letter_end_date: Date.today.strftime('%d/%m/%Y')))
-
- loan_report.loans.should == [ loan1 ]
+ loan_report.facility_letter_end_date = Date.today
+ loan_report.loans.should == [loan1]
end
- it "should return loans with a created at date after a specified date" do
+ it "returns loans with a created at date after a specified date" do
loan1.update_attribute(:created_at, 1.day.ago)
loan2.update_attribute(:created_at, 1.day.from_now)
- loan_report = LoanReport.new(report_attributes(created_at_start_date: Date.today.strftime('%d/%m/%Y')))
-
- loan_report.loans.should == [ loan2 ]
+ loan_report.created_at_start_date = Date.today
+ loan_report.loans.should == [loan2]
end
- it "should return loans with a created at date before a specified date" do
+ it "returns loans with a created at date before a specified date" do
loan1.update_attribute(:created_at, 1.day.ago)
loan2.update_attribute(:created_at, 1.day.from_now)
- loan_report = LoanReport.new(report_attributes(created_at_end_date: Date.today.strftime('%d/%m/%Y')))
-
- loan_report.loans.should == [ loan1 ]
+ loan_report.created_at_end_date = Date.today
+ loan_report.loans.should == [loan1]
end
- it "should return loans last modified on the specified start date" do
+ it "returns loans last modified on the specified start date" do
loan1.update_attribute(:last_modified_at, Time.new(2013, 02, 26, 23, 59, 59))
loan2.update_attribute(:last_modified_at, Time.new(2013, 02, 27, 12, 0, 0))
- loan_report = LoanReport.new(report_attributes(last_modified_start_date: '27/02/2013'))
-
- loan_report.loans.should == [ loan2 ]
+ loan_report.last_modified_start_date = Date.new(2013, 2, 27)
+ loan_report.loans.should == [loan2]
end
- it "should return loans last modified after the specified start date" do
+ it "returns loans last modified after the specified start date" do
loan1.update_attribute(:last_modified_at, Time.new(2013, 02, 26, 23, 59, 59))
loan2.update_attribute(:last_modified_at, Time.new(2013, 02, 28, 12, 0, 0))
- loan_report = LoanReport.new(report_attributes(last_modified_start_date: '27/02/2013'))
-
- loan_report.loans.should == [ loan2 ]
+ loan_report.last_modified_start_date = Date.new(2013, 2, 27)
+ loan_report.loans.should == [loan2]
end
- it "should return loans last modified on the specified end date" do
+ it "returns loans last modified on the specified end date" do
loan1.update_attribute(:last_modified_at, Time.new(2013, 02, 27, 12, 0, 0))
loan2.update_attribute(:last_modified_at, Time.new(2013, 02, 28, 0, 0, 0))
- loan_report = LoanReport.new(report_attributes(last_modified_end_date: '27/02/2013'))
-
- loan_report.loans.should == [ loan1 ]
+ loan_report.last_modified_end_date = Date.new(2013, 2, 27)
+ loan_report.loans.should == [loan1]
end
- it "should return loans last modified before the specified end date" do
+ it "returns loans last modified before the specified end date" do
loan1.update_attribute(:last_modified_at, Time.new(2013, 02, 26, 12, 0, 0))
loan2.update_attribute(:last_modified_at, Time.new(2013, 02, 28, 0, 0, 0))
- loan_report = LoanReport.new(report_attributes(last_modified_end_date: '27/02/2013'))
-
- loan_report.loans.should == [ loan1 ]
+ loan_report.last_modified_end_date = Date.new(2013, 2, 27)
+ loan_report.loans.should == [loan1]
end
- it "should return loans belonging to a specific lender" do
- loan_report = LoanReport.new(
- report_attributes(
- allowed_lender_ids: [ loan1.lender_id ],
- lender_ids: [ loan1.lender_id ]
- )
- )
-
- loan_report.loans.should == [ loan1 ]
+ it "returns loans belonging to a specific lender" do
+ loan_report.lender_ids = [loan1.lender_id]
+ loan_report.loans.should == [loan1]
end
context 'with loans created by specific users' do
let(:user1) { FactoryGirl.create(:user) }
let(:user2) { FactoryGirl.create(:user) }
- before(:each) do
+ before do
loan1.update_attribute(:created_by, user1)
loan2.update_attribute(:created_by, user2)
end
- it "should return loans created by a specific user" do
- loan_report = LoanReport.new(report_attributes(created_by_id: user2.id))
- loan_report.loans.should == [ loan2 ]
+ it "returns loans created by a specific user" do
+ loan_report.created_by_id = user2.id
+ loan_report.loans.should == [loan2]
end
- it "should return no loans when specified created by user does not belong to one of the specified lenders" do
- loan_report = LoanReport.new(
- report_attributes(
- allowed_lender_ids: [ loan1.lender_id ],
- lender_ids: [ loan1.lender_id ],
- created_by_id: user2.id
- )
- )
-
+ it "returns no loans when specified created by user does not belong to one of the specified lenders" do
+ loan_report.lender_ids = [loan1.lender_id]
+ loan_report.created_by_id = user2.id
loan_report.loans.should be_empty
end
end
it "should ignore blank values" do
- loan_report = LoanReport.new(report_attributes(facility_letter_start_date: ""))
- loan_report.loans.should == [ loan1, loan2 ]
- end
-
- it "should not include legacy SFLG loans with a legacy modified by id of 'migration'" do
- FactoryGirl.create(:loan, :legacy_sflg, modified_by_legacy_id: 'migration')
-
- loan_report = LoanReport.new(report_attributes(loan_sources: [ Loan::LEGACY_SFLG_SOURCE, Loan::SFLG_SOURCE ]))
-
- loan_report.loans.should == [ loan1, loan2 ]
+ loan_report.facility_letter_start_date = ""
+ loan_report.loans.should == [loan1, loan2]
end
-
- end
-
- private
-
- def report_attributes(params = {})
- allowed_lender_ids = Lender.count.zero? ? [ 1 ] : Lender.all.collect(&:id)
- lender_ids = Lender.count.zero? ? [ 1 ] : Lender.all.collect(&:id)
-
- FactoryGirl.attributes_for(
- :loan_report,
- allowed_lender_ids: allowed_lender_ids,
- lender_ids: lender_ids
- ).merge(params)
end
-
end
6 spec/requests/reports/loan_report_spec.rb
View
@@ -93,9 +93,9 @@
it "should show validation errors" do
click_button "Submit"
- # 2 errors - empty states multi-select, no loan source checkbox checked
+ # 2 errors - empty states multi-select, no loan type selected
page.should have_css('.control-group.select.required.error #loan_report_lender_ids')
- page.should have_css('.control-group.check_boxes.required.error #loan_report_loan_sources_s')
+ page.should have_css('.control-group.check_boxes.required.error .help-inline')
end
end
@@ -126,7 +126,7 @@
def fill_in_valid_details
select 'All states', from: 'loan_report[states][]'
- check :loan_report_loan_sources_s
+ check :loan_report_loan_types_efg
end
def navigate_to_loan_report_form
Something went wrong with that request. Please try again.