Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions app/controllers/concerns/importable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ def import_csv
data = File.read(params[:file].path, encoding: "BOM|UTF-8")
csv = CSV.parse(data, headers: true)
if csv.count.positive? && csv.first.headers.all? { |header| !header.nil? }
errors = resource_model.import_csv(csv, current_organization.id)
if errors.empty?
results = resource_model.import_csv(csv, current_organization.id)
if results[:errors].empty?
flash[:notice] = "#{resource_model_humanized} were imported successfully!"
else
flash[:error] = "The following #{resource_model_humanized} did not import successfully:\n#{errors.join("\n")}"
flash[:error] = "The following #{resource_model_humanized} did not import successfully:\n#{results[:errors].join("\n")}"
end

if results[:warnings].present?
flash[:alert] = "The following #{resource_model_humanized} imported with warnings:\n#{results[:warnings].join("\n")}"
end
else
flash[:error] = "Check headers in file!"
Expand Down
3 changes: 2 additions & 1 deletion app/models/concerns/provideable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ def self.import_csv(csv, organization)

loc.save!
end
[]

{errors: [], warnings: []}
end

def self.csv_export_headers
Expand Down
4 changes: 3 additions & 1 deletion app/models/donation_site.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class DonationSite < ApplicationRecord

def self.import_csv(csv, organization)
errors = []

csv.each_with_index do |row, index|
loc = DonationSite.new(row.to_hash)
loc.organization_id = organization
Expand All @@ -47,7 +48,8 @@ def self.import_csv(csv, organization)
errors << "Row #{index + 2}, #{row.to_hash["name"]} - #{loc.errors.full_messages.join(", ")}"
end
end
errors

{errors: errors, warnings: []}
end

def self.csv_export_headers
Expand Down
31 changes: 26 additions & 5 deletions app/models/partner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class Partner < ApplicationRecord
validate :correct_document_mime_type

before_save { email&.downcase! }
before_create :default_send_reminders_to_false, if: :send_reminders_nil?
before_update :invite_new_partner, if: :should_invite_because_email_changed?

scope :alphabetized, -> { order(:name) }
Expand Down Expand Up @@ -104,18 +105,30 @@ def approvable?
# better to extract this outside of the model
def self.import_csv(csv, organization_id)
errors = []
warnings = []
organization = Organization.find(organization_id)

csv.each do |row|
hash_rows = Hash[row.to_hash.map { |k, v| [k.downcase, v] }]

svc = PartnerCreateService.new(organization: organization, partner_attrs: hash_rows)
svc.call
if svc.errors.present?
errors << "#{svc.partner.name}: #{svc.partner.errors.full_messages.to_sentence}"
partner_create_service = PartnerCreateService.new(organization: organization, partner_attrs: hash_rows)
partner_create_service.call

if partner_create_service.errors.present?
formatted_errors = partner_create_service.errors.map do |error|
"#{error.attribute.to_s.humanize} #{error.message.downcase}"
end
errors << "#{partner_create_service.partner.name}: #{formatted_errors.to_sentence}"

elsif partner_create_service.warnings.present?
formatted_warnings = partner_create_service.warnings.map do |warning|
"#{warning.attribute.to_s.humanize} #{warning.message.downcase}"
end
warnings << "#{partner_create_service.partner.name}: #{formatted_warnings.to_sentence}"
end
end
errors

{errors: errors, warnings: warnings}
end

def partials_to_show
Expand Down Expand Up @@ -166,6 +179,14 @@ def correct_document_mime_type
end
end

def default_send_reminders_to_false
self.send_reminders = false
end

def send_reminders_nil?
send_reminders.nil?
end

def invite_new_partner
UserInviteService.invite(email: email, roles: [Role::PARTNER], resource: self)
end
Expand Down
3 changes: 2 additions & 1 deletion app/models/storage_location.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ def self.import_csv(csv, organization)
loc.organization_id = organization
loc.save!
end
[]

{errors: [], warnings: []}
end

# NOTE: We should generalize this elsewhere -- Importable concern?
Expand Down
24 changes: 24 additions & 0 deletions app/services/partner_create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ def initialize(organization:, partner_attrs:)
end

def call
process_default_storage_location

@partner = organization.partners.build(partner_attrs)

if @partner.valid?
Expand Down Expand Up @@ -37,5 +39,27 @@ def call

private

def process_default_storage_location
return unless partner_attrs.has_key?("default_storage_location")

if partner_attrs["default_storage_location"].blank?
partner_attrs.delete("default_storage_location")
else
default_storage_location_name = partner_attrs["default_storage_location"]&.titlecase
default_storage_location_id = StorageLocation.find_by(
name: default_storage_location_name,
organization: organization.id
)&.id

if default_storage_location_id.nil?
add_warning(:default_storage_location,
"is not a storage location for this partner's organization")
end

partner_attrs.delete("default_storage_location")
partner_attrs["default_storage_location_id"] = default_storage_location_id
end
end

attr_reader :organization, :partner_attrs
end
9 changes: 8 additions & 1 deletion app/services/service_object_errors_mixin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ def errors
@errors ||= ActiveModel::Errors.new(self)
end

def warnings
@warnings ||= ActiveModel::Errors.new(self)
end

def add_warning(attribute, message)
warnings.add(attribute, message)
end

def read_attribute_for_validation(attr)
send(attr)
end
Expand All @@ -45,4 +53,3 @@ def lookup_ancestors
end
end
end

12 changes: 12 additions & 0 deletions app/views/dashboard/_getting_started_prompt.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,17 @@
<%= button_to "Dismiss", "/manage", method: :patch, params: {organization: { bank_is_set_up: true }}, class: "btn btn-primary" %>
</div>

<%= render(
layout: "shared/csv_import_modal",
locals: {
import_type: "Partners",
csv_template_url: "/partners_template_updated.csv",
csv_import_url: import_csv_partners_path,
},
) do %>
<li>Open the CSV file with Excel or your favourite spreadsheet program.</li>
<li>Delete the sample data and enter your partner agency names and addresses in the appropriate columns.</li>
<li>Save the file as a CSV file.</li>
<% end %>
<% end %>
<% end %>
2 changes: 1 addition & 1 deletion app/views/partners/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
layout: "shared/csv_import_modal",
locals: {
import_type: "Partners",
csv_template_url: "/partners_template.csv",
csv_template_url: "/partners_template_updated.csv",
csv_import_url: import_csv_partners_path
}
) do %>
Expand Down
4 changes: 0 additions & 4 deletions public/partners_template.csv

This file was deleted.

4 changes: 4 additions & 0 deletions public/partners_template_updated.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name,email,default_storage_location,send_reminders,quota,notes
Partner 1,partner1@example.com,"Smithsonian Conservation Center",false,20,"test note 1"
Partner 2,partner2@example.com,"Smithsonian Conservation Center",false,30,"test note 2"
Partner 3,partner3@example.com,"Smithsonian Conservation Center",true,10,"test note 3"
4 changes: 0 additions & 4 deletions spec/fixtures/files/partners.csv

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name,email,default_storage_location,send_reminders,quota,notes
Partner 51,partner51@example.com,,false,50,"great partner"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name,email,send_reminders,quota,notes
Partner 71,partner71@example.com,false,50,"great partner"
3 changes: 3 additions & 0 deletions spec/fixtures/files/partners_missing_send_reminders_field.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name,email,default_storage_location,send_reminders,quota,notes
Partner 51,partner51@example.com,"Smithsonian Conservation Center",,50,"great partner"

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name,email,default_storage_location,quota,notes
Partner 51,partner51@example.com,"Smithsonian Conservation Center",50,"great partner"

42 changes: 21 additions & 21 deletions spec/fixtures/files/partners_with_bom_encoding.csv
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
name,email
Beaverton Police Department,krodriguez@beavertonoregon.gov
Catholic Charities,lcrombie@catholiccharitiesoregon.org
Clackamas Service Center,debramason@cscoregon.org
Healthy Familes of Clackamas County,bkersens@healthyfamiliescc.org
Dollar for Portland,jared@dollorfor.org
Emmanuel Housing Center,shauntemeyers@emmanuelpdx.org
Helensview School,hgandee@mesd.k12.or.us
JOIN,ccarroll@joinpdx.org
Job Corps (PIVOT),zutz.kayla@jobcorps.org
NARA,christman@naranw.org
NW Housing Alternatives,doty@nwhousing.org
Pregnancy Resource Center,debbie@portlandprc.org
Portland Homeless Family Solutions,emma@pdxhfs.org
Raphael House,lvold@raphaelhouse.com
The Rebecca Foundation's Cloth Diaper Closet,portland@clothforall.org
Rose Haven,adeol@rosehaven.org
Self Enhancement Inc.,stephaniep@selfenhancement.org
Teen Parent Services (PPS),lgovan@pps.net
Volunteers of America,cross@voaor.org
Central City Concern,lindsey.ramsey@ccconcern.org
name,email,default_storage_location,send_reminders,quota,notes
Beaverton Police Department,krodriguez@beavertonoregon.gov,"Smithsonian Conservation Center",true,50,"great partner"
Catholic Charities,lcrombie@catholiccharitiesoregon.org,"Smithsonian Conservation Center",true,50,"great partner"
Clackamas Service Center,debramason@cscoregon.org,"Smithsonian Conservation Center",true,50,"great partner"
Healthy Familes of Clackamas County,bkersens@healthyfamiliescc.org,"Smithsonian Conservation Center",true,50,"great partner"
Dollar for Portland,jared@dollorfor.org,"Smithsonian Conservation Center",true,50,"great partner"
Emmanuel Housing Center,shauntemeyers@emmanuelpdx.org,"Smithsonian Conservation Center",true,50,"great partner"
Helensview School,hgandee@mesd.k12.or.us,"Smithsonian Conservation Center",true,50,"great partner"
JOIN,ccarroll@joinpdx.org,"Smithsonian Conservation Center",true,50,"great partner"
Job Corps (PIVOT),zutz.kayla@jobcorps.org,"Smithsonian Conservation Center",true,50,"great partner"
NARA,christman@naranw.org,"Smithsonian Conservation Center",true,50,"great partner"
NW Housing Alternatives,doty@nwhousing.org,"Smithsonian Conservation Center",true,50,"great partner"
Pregnancy Resource Center,debbie@portlandprc.org,"Smithsonian Conservation Center",true,50,"great partner"
Portland Homeless Family Solutions,emma@pdxhfs.org,"Smithsonian Conservation Center",true,50,"great partner"
Raphael House,lvold@raphaelhouse.com,"Smithsonian Conservation Center",true,50,"great partner"
The Rebecca Foundation's Cloth Diaper Closet,portland@clothforall.org,"Smithsonian Conservation Center",true,50,"great partner"
Rose Haven,adeol@rosehaven.org,"Smithsonian Conservation Center",true,50,"great partner"
Self Enhancement Inc.,stephaniep@selfenhancement.org,"Smithsonian Conservation Center",true,50,"great partner"
Teen Parent Services (PPS),lgovan@pps.net,"Smithsonian Conservation Center",true,50,"great partner"
Volunteers of America,cross@voaor.org,"Smithsonian Conservation Center",true,50,"great partner"
Central City Concern,lindsey.ramsey@ccconcern.org,"Smithsonian Conservation Center",true,50,"great partner"
4 changes: 0 additions & 4 deletions spec/fixtures/files/partners_with_duplicates.csv

This file was deleted.

4 changes: 4 additions & 0 deletions spec/fixtures/files/partners_with_six_fields.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name,email,default_storage_location,send_reminders,quota,notes
Partner 1,partner1@example.com,"Smithsonian Conservation Center",true,50,"great partner"
Partner 2,partner2@example.com,"Smithsonian Conservation Center",true,75,"such a great partner"
Partner 4,partner4@example.com,"Smithsonian Conservation Center",false,80,"really ten out of ten"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name,email,default_storage_location,send_reminders,quota,notes
Partner 1,partner1@example.com,"Smithsonian Conservation Center",true,50,"great partner"
Partner 2,partner2@example.com,"Smithsonian Conservation Center",true,75,"such a great partner"
Partner 3,partner3@example.com,"Smithsonian Conservation Center",true,80,"yay, a partner"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name,email,default_storage_location,send_reminders,quota,notes
Partner 1,partner1@example.com,"SMITHSONIAN CONSERVATION CENTER",true,50,"great partner"
Partner 2,partner2@example.com,"Smithsonian Conservation Center",true,75,"such a great partner"
Partner 4,partner4@example.com,"Smithsonian Conservation Center",false,80,"really ten out of ten"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name,email,default_storage_location,send_reminders,quota,notes
Partner 4,partner4@example.com,"Invalid",false,80,"really ten out of ten"
13 changes: 9 additions & 4 deletions spec/models/donation_site_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
data = File.read(duplicated_name_csv_path, encoding: "BOM|UTF-8")
csv = CSV.parse(data, headers: true)

errors = DonationSite.import_csv(csv, organization.id)
response = DonationSite.import_csv(csv, organization.id)
errors = response[:errors]
expect(errors).not_to be_empty
expect(errors.first).to match(/Row/)
expect(errors.first).to include("Name must be unique within the organization")
Expand All @@ -55,7 +56,8 @@
data = File.read(valid_csv_path, encoding: "BOM|UTF-8")
csv = CSV.parse(data, headers: true)

errors = DonationSite.import_csv(csv, organization.id)
response = DonationSite.import_csv(csv, organization.id)
errors = response[:errors]
expect(errors).to be_empty
expect(DonationSite.count).to eq 1

Expand All @@ -67,7 +69,8 @@
data = File.read(invalid_csv_path, encoding: "BOM|UTF-8")
csv = CSV.parse(data, headers: true)

errors = DonationSite.import_csv(csv, organization.id)
response = DonationSite.import_csv(csv, organization.id)
errors = response[:errors]
expect(errors).not_to be_empty
expect(errors.first).to match(/Row/)
expect(errors.first).to include("can't be blank")
Expand All @@ -79,7 +82,9 @@
import_file_path = Rails.root.join("spec", "fixtures", "files", "donation_sites.csv")
data = File.read(import_file_path, encoding: "BOM|UTF-8")
csv = CSV.parse(data, headers: true)
DonationSite.import_csv(csv, organization.id)
response = DonationSite.import_csv(csv, organization.id)
errors = response[:errors]
expect(errors).to be_empty
expect(DonationSite.count).to eq 1
end
end
Expand Down
Loading