generated from dxw/rails-template
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Model a actual, refund and comment upload row
We've already added the `Import::Csv:Financial` class for handling the financial values from csv, actuals and refunds. This commit adds a representation of the row as we expect it to be supplied in the csv, we perform a set of validations adding to the errors instance variable for use later. Like financial values, we treat 'empty' values such as spaces as nothing rather than included values that users would not see. At this point a valid `Import::ActivityActualRefundComment::Row` still may not result in a record being created as validation occurs later and is collected together for presentation to the user. We are doing more validation than the existing improter does, earlier, we feel like this approach results in a number of benefits including: - the code is more approachable, with as many validation happening as early as possible in one place - performant, we don't have to waste resources during the import if we already know the row is invalid - we can offer more helpful errors than the standard model validation might. As part of this work we are introducing some better name and namespacing for the code that relates to the importing processes. For related models, services and any other we can use: `import::csv:activity_refund_comment` We settled on this as the code relates so many models, including: - Actual Transactions - Refund Transactions - Comments on Activities This model reflects the change to the expectation on users around what values should be included in a csv row once it is in use.
- Loading branch information
Showing
4 changed files
with
851 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
208 changes: 208 additions & 0 deletions
208
app/models/import/csv/activity_actual_refund_comment/row.rb
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
class Import::Csv::ActivityActualRefundComment::Row | ||
attr_reader :errors | ||
|
||
def initialize(csv_row) | ||
@row = csv_row | ||
@errors = {} | ||
@actual = Import::Csv::Financial.new(@row.field("Actual Value")) | ||
@refund = Import::Csv::Financial.new(@row.field("Refund Value")) | ||
end | ||
|
||
def valid? | ||
validate_financial_quarter | ||
validate_financial_year | ||
validate_roda_identifier | ||
validate_receiving_organisation_name | ||
validate_receiving_organisation_type | ||
|
||
if validate_actual && validate_refund | ||
validate_no_actual_and_refund | ||
validate_refund_must_have_comment | ||
end | ||
|
||
@errors.empty? | ||
end | ||
|
||
def invalid? | ||
!valid? | ||
end | ||
|
||
def empty? | ||
return nil unless valid? | ||
|
||
actual_value.zero? && refund_value.zero? && comment.nil? | ||
end | ||
|
||
def actual_value | ||
@actual.decimal_value | ||
end | ||
|
||
def refund_value | ||
@refund.decimal_value | ||
end | ||
|
||
def comment | ||
@row.field("Comment").tap do |comment| | ||
return nil if comment.blank? | ||
end | ||
end | ||
|
||
def roda_identifier | ||
@row.field("Activity RODA Identifier").tap do |identifier| | ||
return nil if identifier.blank? | ||
end | ||
end | ||
|
||
def financial_quarter | ||
@row.field("Financial Quarter").tap do |quarter| | ||
return nil if quarter.blank? | ||
end | ||
end | ||
|
||
def financial_year | ||
@row.field("Financial Year").tap do |year| | ||
return nil if year.blank? | ||
end | ||
end | ||
|
||
def receiving_organisation_name | ||
@row.field("Receiving Organisation Name").tap do |name| | ||
return nil if name.blank? | ||
end | ||
end | ||
|
||
def receiving_organisation_type | ||
@row.field("Receiving Organisation Type").tap do |type| | ||
return nil if type.blank? | ||
end | ||
end | ||
|
||
def receiving_organisation_iati_reference | ||
@row.field("Receiving Organisation IATI Reference").tap do |reference| | ||
return nil if reference.blank? | ||
end | ||
end | ||
|
||
private def original_actual_value | ||
@actual.original_value | ||
end | ||
|
||
private def original_refund_value | ||
@refund.original_value | ||
end | ||
|
||
private def validate_roda_identifier | ||
if roda_identifier.blank? | ||
@errors["Activity RODA Identifier"] = [roda_identifier, I18n.t("import.csv.activity_actual_refund_comment.errors.default.required")] | ||
return false | ||
end | ||
|
||
true | ||
end | ||
|
||
private def validate_financial_quarter | ||
if financial_quarter.blank? | ||
@errors["Financial Quarter"] = [financial_quarter, I18n.t("import.csv.activity_actual_refund_comment.errors.default.required")] | ||
return false | ||
end | ||
|
||
if ["1", "2", "3", "4"].none?(financial_quarter) | ||
@errors["Financial Quarter"] = [financial_quarter, I18n.t("import.csv.activity_actual_refund_comment.errors.financial_quarter")] | ||
return false | ||
end | ||
|
||
true | ||
end | ||
|
||
private def validate_financial_year | ||
if financial_year.blank? | ||
@errors["Financial Year"] = [financial_year, I18n.t("import.csv.activity_actual_refund_comment.errors.default.required")] | ||
return false | ||
end | ||
|
||
begin | ||
FinancialYear.new(financial_year) | ||
rescue ::FinancialYear::InvalidYear | ||
@errors["Financial Year"] = [financial_year, I18n.t("import.csv.activity_actual_refund_comment.errors.financial_year")] | ||
return false | ||
end | ||
|
||
true | ||
end | ||
|
||
private def validate_actual | ||
if actual_value.nil? | ||
@errors["Actual Value"] = [original_actual_value, I18n.t("import.csv.activity_actual_refund_comment.errors.financial_value")] | ||
return false | ||
end | ||
true | ||
end | ||
|
||
private def validate_refund | ||
if refund_value.nil? | ||
@errors["Refund Value"] = [original_refund_value, I18n.t("import.csv.activity_actual_refund_comment.errors.financial_value")] | ||
return false | ||
end | ||
true | ||
end | ||
|
||
private def validate_no_actual_and_refund | ||
if actual_value.positive? && (refund_value.positive? || refund_value.negative?) | ||
@errors["Actual Value"] = [original_actual_value, I18n.t("import.csv.activity_actual_refund_comment.errors.actual_value_with_refund")] | ||
@errors["Refund Value"] = [original_refund_value, I18n.t("import.csv.activity_actual_refund_comment.errors.refund_value_with_actual")] | ||
return false | ||
end | ||
true | ||
end | ||
|
||
private def validate_refund_must_have_comment | ||
if actual_value.zero? && !refund_value.zero? && comment.nil? | ||
@errors["Comment"] = [comment, I18n.t("import.csv.activity_actual_refund_comment.errors.refund_requires_comment")] | ||
return false | ||
end | ||
true | ||
end | ||
|
||
private def validate_receiving_organisation_name | ||
if receiving_organisation_name.blank? && receiving_organisation_type.present? | ||
@errors["Receiving Organisation Name"] = [ | ||
receiving_organisation_name, I18n.t("import.csv.activity_actual_refund_comment.errors.receiving_organisation_name.type") | ||
] | ||
return false | ||
end | ||
|
||
if receiving_organisation_name.blank? && receiving_organisation_iati_reference.present? | ||
@errors["Receiving Organisation Name"] = [ | ||
receiving_organisation_name, I18n.t("import.csv.activity_actual_refund_comment.errors.receiving_organisation_name.reference") | ||
] | ||
return false | ||
end | ||
|
||
true | ||
end | ||
|
||
private def validate_receiving_organisation_type | ||
return true if receiving_organisation_name.blank? && receiving_organisation_type.blank? | ||
|
||
if receiving_organisation_name.present? && receiving_organisation_type.blank? | ||
@errors["Receiving Organisation Type"] = [ | ||
receiving_organisation_type, I18n.t("import.csv.activity_actual_refund_comment.errors.receiving_organisation_type.blank_name") | ||
] | ||
return false | ||
end | ||
|
||
unless value_in_code_list?("organisation_type", receiving_organisation_type) | ||
@errors["Receiving Organisation Type"] = [ | ||
receiving_organisation_type, I18n.t("import.csv.activity_actual_refund_comment.errors.receiving_organisation_type.invalid_code") | ||
] | ||
return false | ||
end | ||
|
||
true | ||
end | ||
|
||
private def value_in_code_list?(code_list, value) | ||
code_list = Codelist.new(type: code_list) | ||
code_list.find_item_by_code(value) ? true : false | ||
end | ||
end |
20 changes: 20 additions & 0 deletions
20
config/locales/import/csv/actiity_actual_refund_comment/errors.en.yml
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
--- | ||
en: | ||
import: | ||
csv: | ||
activity_actual_refund_comment: | ||
errors: | ||
default: | ||
required: Is required | ||
financial_quarter: Must be 1, 2, 3 or 4 | ||
financial_year: Must be a four digit year | ||
financial_value: Must be a financial value | ||
actual_value_with_refund: Actual and refund cannot be reported on the same row | ||
refund_value_with_actual: Refund and actual cannot be reported on the same row | ||
refund_requires_comment: Refund must have a comment | ||
receiving_organisation_name: | ||
type: Cannot be blank when Receiving Organisation Type is present | ||
reference: Cannot be blank when Receiving Organisation IATI reference is present | ||
receiving_organisation_type: | ||
blank_name: Cannot be blank when Receiving Organisation Name is present | ||
invalid_code: Is not a valid receiving organisation type code |
Oops, something went wrong.