diff --git a/app/controllers/transfers_controller.rb b/app/controllers/transfers_controller.rb
index e227e16990..e94949a272 100644
--- a/app/controllers/transfers_controller.rb
+++ b/app/controllers/transfers_controller.rb
@@ -11,8 +11,8 @@ def index
.during(helpers.selected_range)
@selected_from = filter_params[:from_location]
@selected_to = filter_params[:to_location]
- @from_storage_locations = Transfer.storage_locations_transferred_from_in(current_organization)
- @to_storage_locations = Transfer.storage_locations_transferred_to_in(current_organization)
+ @from_storage_locations = StorageLocation.with_transfers_from(current_organization)
+ @to_storage_locations = StorageLocation.with_transfers_to(current_organization)
respond_to do |format|
format.html
format.csv { send_data Transfer.generate_csv(@transfers), filename: "Transfers-#{Time.zone.today}.csv" }
diff --git a/app/helpers/date_range_helper.rb b/app/helpers/date_range_helper.rb
index 8d3db3a7a5..cc73af80d8 100644
--- a/app/helpers/date_range_helper.rb
+++ b/app/helpers/date_range_helper.rb
@@ -18,6 +18,10 @@ def date_range_label
"this month"
when "last month"
"last month"
+ when "last 12 months"
+ "last 12 months"
+ when "prior year"
+ "prior year"
else
selected_range_described
end
diff --git a/app/javascript/application.js b/app/javascript/application.js
index c94704d50d..bb8df687e1 100644
--- a/app/javascript/application.js
+++ b/app/javascript/application.js
@@ -99,7 +99,9 @@ $(document).ready(function(){
'This Month': [today.startOf('month').toJSDate(), today.endOf('month').toJSDate()],
'Last Month': [today.minus({'months': 1}).startOf('month').toJSDate(),
today.minus({'month': 1}).endOf('month').toJSDate()],
- 'This Year': [today.startOf('year').toJSDate(), today.endOf('year').toJSDate()]
+ 'Last 12 Months': [today.minus({'months': 12}).plus({'days': 1}).toJSDate(), today.toJSDate()],
+ 'Prior Year': [today.startOf('year').minus({'years': 1}).toJSDate(), today.minus({'year': 1}).endOf('year').toJSDate()],
+ 'This Year': [today.startOf('year').toJSDate(), today.endOf('year').toJSDate()],
}
}
});
diff --git a/app/models/storage_location.rb b/app/models/storage_location.rb
index 6ad65c7fa9..94f2a0a23e 100644
--- a/app/models/storage_location.rb
+++ b/app/models/storage_location.rb
@@ -34,11 +34,11 @@ class StorageLocation < ApplicationRecord
has_many :distributions, dependent: :destroy
has_many :transfers_from, class_name: "Transfer",
inverse_of: :from,
- foreign_key: :id,
+ foreign_key: :from_id,
dependent: :destroy
has_many :transfers_to, class_name: "Transfer",
inverse_of: :to,
- foreign_key: :id,
+ foreign_key: :to_id,
dependent: :destroy
has_many :kit_allocations, dependent: :destroy
@@ -55,6 +55,12 @@ class StorageLocation < ApplicationRecord
scope :alphabetized, -> { order(:name) }
scope :for_csv_export, ->(organization, *) { where(organization: organization) }
scope :active_locations, -> { where(discarded_at: nil) }
+ scope :with_transfers_to, ->(organization) {
+ joins(:transfers_to).where(organization_id: organization.id).distinct.order(:name)
+ }
+ scope :with_transfers_from, ->(organization) {
+ joins(:transfers_from).where(organization_id: organization.id).distinct.order(:name)
+ }
# @param organization [Organization]
# @param inventory [View::Inventory]
diff --git a/app/models/transfer.rb b/app/models/transfer.rb
index 3945ac776f..4237f5fef0 100644
--- a/app/models/transfer.rb
+++ b/app/models/transfer.rb
@@ -29,14 +29,6 @@ class Transfer < ApplicationRecord
}
scope :during, ->(range) { where(created_at: range) }
- def self.storage_locations_transferred_to_in(organization)
- includes(:to).where(organization_id: organization.id).distinct(:to_id).collect(&:to).uniq.sort_by(&:name)
- end
-
- def self.storage_locations_transferred_from_in(organization)
- includes(:from).where(organization_id: organization.id).distinct(:from_id).collect(&:from).uniq.sort_by(&:name)
- end
-
validates :from, :to, :organization, presence: true
validate :storage_locations_belong_to_organization
validate :storage_locations_must_be_different
diff --git a/app/views/partners/profiles/_actions.html.erb b/app/views/partners/profiles/_actions.html.erb
new file mode 100644
index 0000000000..05ef380746
--- /dev/null
+++ b/app/views/partners/profiles/_actions.html.erb
@@ -0,0 +1,31 @@
+<%# locals: (partner:) %>
+
+
diff --git a/app/views/partners/profiles/show.html.erb b/app/views/partners/profiles/show.html.erb
index 225bf4009e..c9e50d1ad9 100644
--- a/app/views/partners/profiles/show.html.erb
+++ b/app/views/partners/profiles/show.html.erb
@@ -22,6 +22,8 @@
+<%= render 'actions', partner: current_partner %>
+
-
+<%= render 'actions', partner: current_partner %>
diff --git a/app/views/users/mailer/invitation_instructions.html.erb b/app/views/users/mailer/invitation_instructions.html.erb
index 7d959b4882..87c7f64cc8 100644
--- a/app/views/users/mailer/invitation_instructions.html.erb
+++ b/app/views/users/mailer/invitation_instructions.html.erb
@@ -374,7 +374,6 @@
<% if @resource.invitation_due_at %>
<%= t("devise.mailer.invitation_instructions.accept_until", due_date: l(@resource.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format')) %>
<% end %>
-
For security reasons these invitations expire. This invitation will expire in 8 hours or if a new password reset is triggered.
If your invitation has an expired message, go <%= link_to "here", new_user_password_url %> and enter your email address to reset your password.
Feel free to ignore this email if you are not interested or if you feel it was sent by mistake.
diff --git a/app/views/users/mailer/reset_password_instructions.html.erb b/app/views/users/mailer/reset_password_instructions.html.erb
index 6656a60751..1352deb8fa 100644
--- a/app/views/users/mailer/reset_password_instructions.html.erb
+++ b/app/views/users/mailer/reset_password_instructions.html.erb
@@ -6,7 +6,7 @@
<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>
-
For security reasons these invitations expire. This invitation will expire in 8 hours or if a new password reset is triggered.
+
For security reasons these invitations expire. This invitation will expire in 6 hours or if a new password reset is triggered.
If your invitation has an expired message, go <%= link_to "here", new_user_password_url %> and enter your email address to reset your password.
If you didn't request this, please ignore this email.
Your password won't change until you access the link above and create a new one.
diff --git a/clock.rb b/clock.rb
index fcf3e803b4..b19137dd1c 100644
--- a/clock.rb
+++ b/clock.rb
@@ -35,6 +35,6 @@ module Clockwork
end
every(1.day, "Send reminder emails", at: "12:00", if: lambda { |_| Rails.env.production? }) do
- ReminderDeadlineJob.perform_now
+ ReminderDeadlineJob.perform_later
end
end
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 3951cd3f08..f18cde16ff 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -120,7 +120,7 @@
# The period the generated invitation token is valid, after
# this period, the invited resource won't be able to accept the invitation.
# When invite_for is 0 (the default), the invitation won't expire.
- # config.invite_for = 2.weeks
+ config.invite_for = 2.weeks
# Number of invitations users can send.
# - If invitation_limit is nil, there is no limit for invitations, users can
diff --git a/config/locales/devise_invitable.en.yml b/config/locales/devise_invitable.en.yml
index 7d5fc7c09c..ba47068d82 100644
--- a/config/locales/devise_invitable.en.yml
+++ b/config/locales/devise_invitable.en.yml
@@ -21,7 +21,7 @@ en:
hello: "Hello %{email}"
someone_invited_you: "Someone has invited you to %{url}, you can accept it through the link below."
accept: "Accept invitation"
- accept_until: "This invitation will be due in %{due_date}."
+ accept_until: "This invitation will expire at %{due_date} GMT or if a new password reset is triggered."
ignore: "If you don't want to accept the invitation, please ignore this email.
\nYour account won't be created until you access the link above and set your password."
time:
formats:
diff --git a/spec/mailers/custom_devise_mailer_spec.rb b/spec/mailers/custom_devise_mailer_spec.rb
index 842c9d7541..4943481cd8 100644
--- a/spec/mailers/custom_devise_mailer_spec.rb
+++ b/spec/mailers/custom_devise_mailer_spec.rb
@@ -34,15 +34,21 @@
end
context "when user is invited" do
- let(:user) { create(:user) }
+ let(:invitation_sent_at) { Time.zone.now }
+ let(:user) { create(:user, invitation_sent_at: invitation_sent_at) }
it "invites to user" do
expect(mail.subject).to eq("Your Human Essentials App Account Approval")
expect(mail.html_part.body).to include("Your request has been approved and you're invited to become an user of the Human Essentials inventory management system!")
end
- it "has invite expiration message" do
- expect(mail.html_part.body).to include("For security reasons these invitations expire. This invitation will expire in 8 hours or if a new password reset is triggered.")
+ it "has invite expiration message and reset instructions" do
+ expect(mail.html_part.body).to include("This invitation will expire at #{user.invitation_due_at.strftime("%B %d, %Y %I:%M %p")} GMT or if a new password reset is triggered.")
+ end
+
+ it "has reset instructions" do
+ expect(mail.html_part.body).to match(%r{
If your invitation has an expired message, go here and enter your email address to reset your password.
})
+ expect(mail.html_part.body).to include("Feel free to ignore this email if you are not interested or if you feel it was sent by mistake.")
end
end
end
diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb
index 236ecd1147..a01a01971e 100644
--- a/spec/mailers/user_mailer_spec.rb
+++ b/spec/mailers/user_mailer_spec.rb
@@ -22,7 +22,7 @@
let(:mail) { ActionMailer::Base.deliveries.last }
it "sends an email with instructions" do
- expect(mail.body.encoded).to include("For security reasons these invitations expire. This invitation will expire in 8 hours or if a new password reset is triggered.")
+ expect(mail.body.encoded).to include("For security reasons these invitations expire. This invitation will expire in 6 hours or if a new password reset is triggered.")
end
end
end
diff --git a/spec/models/storage_location_spec.rb b/spec/models/storage_location_spec.rb
index 332a1eed0b..5ebdb20ba2 100644
--- a/spec/models/storage_location_spec.rb
+++ b/spec/models/storage_location_spec.rb
@@ -52,6 +52,32 @@
expect(results.length).to eq(1)
expect(results.first.discarded_at).to be_nil
end
+
+ it "->with_transfers_to yields storage locations with transfers to an organization" do
+ storage_location1 = create(:storage_location, name: "loc1", organization: organization)
+ storage_location2 = create(:storage_location, name: "loc2", organization: organization)
+ storage_location3 = create(:storage_location, name: "loc3", organization: organization)
+ storage_location4 = create(:storage_location, name: "loc4", organization: create(:organization))
+ storage_location5 = create(:storage_location, name: "loc5", organization: storage_location4.organization)
+ create(:transfer, from: storage_location3, to: storage_location1, organization: organization)
+ create(:transfer, from: storage_location3, to: storage_location2, organization: organization)
+ create(:transfer, from: storage_location5, to: storage_location4, organization: storage_location4.organization)
+
+ expect(StorageLocation.with_transfers_to(organization).to_a).to match_array([storage_location1, storage_location2])
+ end
+
+ it "->with_transfers_from yields storage locations with transfers from an organization" do
+ storage_location1 = create(:storage_location, name: "loc1", organization: organization)
+ storage_location2 = create(:storage_location, name: "loc2", organization: organization)
+ storage_location3 = create(:storage_location, name: "loc3", organization: organization)
+ storage_location4 = create(:storage_location, name: "loc4", organization: create(:organization))
+ storage_location5 = create(:storage_location, name: "loc5", organization: storage_location4.organization)
+ create(:transfer, from: storage_location3, to: storage_location1, organization: organization)
+ create(:transfer, from: storage_location3, to: storage_location2, organization: organization)
+ create(:transfer, from: storage_location5, to: storage_location4, organization: storage_location4.organization)
+
+ expect(StorageLocation.with_transfers_from(organization).to_a).to match_array([storage_location3])
+ end
end
context "Methods >" do
diff --git a/spec/models/transfer_spec.rb b/spec/models/transfer_spec.rb
index 2ca192938d..e3f9d17151 100644
--- a/spec/models/transfer_spec.rb
+++ b/spec/models/transfer_spec.rb
@@ -69,21 +69,6 @@
end
end
- context "Methods >" do
- it "`self.storage_locations_transferred_to` and `..._from` constrains appropriately" do
- storage_location1 = create(:storage_location, name: "loc1", organization: organization)
- storage_location2 = create(:storage_location, name: "loc2", organization: organization)
- storage_location3 = create(:storage_location, name: "loc3", organization: organization)
- storage_location4 = create(:storage_location, name: "loc4", organization: create(:organization))
- storage_location5 = create(:storage_location, name: "loc5", organization: storage_location4.organization)
- create(:transfer, from: storage_location3, to: storage_location1, organization: organization)
- create(:transfer, from: storage_location3, to: storage_location2, organization: organization)
- create(:transfer, from: storage_location5, to: storage_location4, organization: storage_location4.organization)
- expect(Transfer.storage_locations_transferred_to_in(organization).to_a).to match_array([storage_location1, storage_location2])
- expect(Transfer.storage_locations_transferred_from_in(organization).to_a).to match_array([storage_location3])
- end
- end
-
describe "versioning" do
it { is_expected.to be_versioned }
end
diff --git a/spec/system/distributions_by_county_system_spec.rb b/spec/system/distributions_by_county_system_spec.rb
index a9ca7c8de9..82006de4a3 100644
--- a/spec/system/distributions_by_county_system_spec.rb
+++ b/spec/system/distributions_by_county_system_spec.rb
@@ -1,8 +1,8 @@
RSpec.feature "Distributions by County", type: :system do
include_examples "distribution_by_county"
- let(:year) { Time.current.year }
- let(:issued_at_last_year) { Time.current.utc.change(year: year - 1).to_datetime }
+ let(:current_year) { Time.current.year }
+ let(:issued_at_last_year) { Time.current.utc.change(year: current_year - 1).to_datetime }
before do
sign_in(user)
@@ -18,8 +18,9 @@
partner_1.profile.served_areas.each do |served_area|
expect(page).to have_text(served_area.county.name)
end
- expect(page).to have_text("50", count: 4)
- expect(page).to have_text("$525.00", count: 4)
+
+ expect(page).to have_css("table tbody tr td", text: "50", exact_text: true, count: 4)
+ expect(page).to have_css("table tbody tr td", text: "$525.00", exact_text: true, count: 4)
end
it("works for this year") do
@@ -31,8 +32,53 @@
partner_1.profile.served_areas.each do |served_area|
expect(page).to have_text(served_area.county.name)
end
- expect(page).to have_text("25", count: 4)
- expect(page).to have_text("$262.50", count: 4)
+
+ expect(page).to have_css("table tbody tr td", text: "25", exact_text: true, count: 4)
+ expect(page).to have_css("table tbody tr td", text: "$262.50", exact_text: true, count: 4)
+ end
+
+ it("works for prior year") do
+ # Should NOT return distribution issued before previous calendar year
+ last_day_of_two_years_ago = Time.current.utc.change(year: current_year - 2, month: 12, day: 31).to_datetime
+ create(:distribution, :with_items, item: item_1, organization: user.organization, partner: partner_1, issued_at: last_day_of_two_years_ago)
+
+ # Should return distribution issued during previous calendar year
+ one_year_ago = issued_at_last_year
+ create(:distribution, :with_items, item: item_1, organization: user.organization, partner: partner_1, issued_at: one_year_ago)
+
+ # Should NOT return distribution issued after previous calendar year
+ first_day_of_current_year = Time.current.utc.change(year: current_year, month: 1, day: 1).to_datetime
+ create(:distribution, :with_items, item: item_1, organization: user.organization, partner: partner_1, issued_at: first_day_of_current_year)
+
+ visit_distribution_by_county_with_specified_date_range("Prior Year")
+
+ partner_1.profile.served_areas.each do |served_area|
+ expect(page).to have_text(served_area.county.name)
+ end
+ expect(page).to have_css("table tbody tr td", text: "25", exact_text: true, count: 4)
+ expect(page).to have_css("table tbody tr td", text: "$262.50", exact_text: true, count: 4)
+ end
+
+ it("works for last 12 months") do
+ # Should NOT return disitribution issued before 12 months ago
+ one_year_and_one_day_ago = 1.year.ago.prev_day.to_datetime
+ create(:distribution, :with_items, item: item_1, organization: user.organization, partner: partner_1, issued_at: one_year_and_one_day_ago)
+
+ # Should return distribution issued during previous 12 months
+ today = issued_at_present
+ create(:distribution, :with_items, item: item_1, organization: user.organization, partner: partner_1, issued_at: today)
+
+ # Should NOT return distribution issued in the future
+ tomorrow = 1.day.from_now.to_datetime
+ create(:distribution, :with_items, item: item_1, organization: user.organization, partner: partner_1, issued_at: tomorrow)
+
+ visit_distribution_by_county_with_specified_date_range("Last 12 Months")
+
+ partner_1.profile.served_areas.each do |served_area|
+ expect(page).to have_text(served_area.county.name)
+ end
+ expect(page).to have_css("table tbody tr td", text: "25", exact_text: true, count: 4)
+ expect(page).to have_css("table tbody tr td", text: "$262.50", exact_text: true, count: 4)
end
end
diff --git a/spec/system/partners/approval_process_spec.rb b/spec/system/partners/approval_process_spec.rb
index 26d69cbcd4..24b78341f2 100644
--- a/spec/system/partners/approval_process_spec.rb
+++ b/spec/system/partners/approval_process_spec.rb
@@ -28,7 +28,7 @@
before do
click_on 'My Profile'
assert page.has_content? 'Uninvited'
- click_on 'Update Information'
+ all('a', text: 'Update Information').last.click
fill_in 'Other Agency Type', with: 'Lorem'
@@ -41,7 +41,7 @@
click_on 'Update Information'
assert page.has_content? 'Details were successfully updated.'
- find_link(text: 'Submit for Approval').click
+ all('a', text: 'Submit for Approval').last.click
assert page.has_content? 'You have submitted your details for approval.'
assert page.has_content? 'Awaiting Review'
end
@@ -77,7 +77,7 @@
login_as(partner_user)
visit partner_user_root_path
click_on 'My Profile'
- click_on 'Submit for Approval'
+ all('a', text: 'Submit for Approval').last.click
end
it "should render an error message", :aggregate_failures do