Skip to content

Commit

Permalink
refactor RentNumberValidator
Browse files Browse the repository at this point in the history
  • Loading branch information
SepsiLaszlo committed Sep 30, 2022
1 parent 2d5d4e3 commit 3d8d8cf
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 45 deletions.
4 changes: 4 additions & 0 deletions app/models/rent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,9 @@ def self.users_filter(params, id)
def item
Item.unscoped { super }
end

def days
(self.begin.to_date.. self.end.to_date).to_a
end
end

61 changes: 40 additions & 21 deletions app/validators/rent_number_validator.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,43 @@
# Validators are instantiated once, instance variables persist between validations, might cause bugs
class RentNumberValidator < ActiveModel::Validator
def validate(record)
#Rent.where("begin < ? && end > ?", record.end, record.begin).where.not(state: :unprocessed).sum(:number)
return if record.number.nil? || record.begin.nil? || record.end.nil?
sum = 0
rents = Rent.all
rents.each do |rent|
sum += rent.number if(rent.begin < record.end && rent.end > record.begin && rent.state != "unprocessed")
end
if sum+record.number > record.item.number
record.errors.add :base, "Erre az időpontra sajnos nincs elég a kívánt eszközből."
record.errors.add :base, "A megadott napokra elérhető eszközök száma:"
day = record.begin.to_date
while(day <= record.end.to_date)
sum = 0
rents.each do |rent|
sum += rent.number if(rent.begin.to_date <= day && rent.end.to_date >= day && rent.state != "unprocessed")
end
record.errors.add :base, day.to_s + ": " + (record.item.number - sum).to_s + " darab"
day += 1
end
end
def validate(record)
item = record.item
active_rents = active_rents(record)
rent_days = rent_days(active_rents)
rents_by_item = rents_by_item(rent_days, active_rents)

record.days.each do |day|
rent_number_for_day = rents_by_item.dig(day, item) || 0
if rent_number_for_day + record.number > item.number
available_item_number = item.number = rent_number_for_day
record.errors.add :base, "A kiválasztott napon(#{day}) csak #{available_item_number} darab #{item.name} elérhető."
end
end
end

private

# hash[rent_day][item] = sum taken out amount item (per day, per item)
def rents_by_item(rent_days, active_rents)
result = {}
rent_days.each do |rent_date|
result[rent_date] = {} if result[rent_date].nil?
active_rents.each do |active_rent|
result[rent_date][active_rent.item] = 0 if result[rent_date][active_rent.item].nil?
result[rent_date][active_rent.item] += active_rent.number
end
end
result
end

def rent_days(active_rents)
active_rents.map(&:days).flatten.uniq.sort
end

def active_rents(record)
Rent.includes(:item)
.where(state: [:approved, :taken])
.where.not('rents.end <= :begin or :end <= rents.begin',
{ begin: record.begin, end: record.end })
end
end
72 changes: 48 additions & 24 deletions spec/models/rent_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

RSpec.describe Rent, type: :model do
let(:user) { create(:user) }
let(:item) { create(:item) }
let(:item) { create(:item, number: 10) }
let(:pre_existing_rent) do
Rent.create!(state: :approved, item: item, user: user,
begin: DateTime.new(2022, 1, 10),
Expand All @@ -13,7 +13,7 @@
Rent.new(state: :approved, item: item, user: user,
begin: begin_date,
end: end_date,
number: 5)
number: rent_number)
end

subject do
Expand All @@ -29,34 +29,58 @@
Timecop.return
end

context 'when the rent starts before the pre existing rent' do
let(:begin_date) { DateTime.new(2022, 1, 5) }
context 'and ends before the current rent' do
let(:end_date) { DateTime.new(2022, 1, 9) }
it { expect(subject).to be_valid }
context 'when the rent number equals to all available item number' do
let(:rent_number) { 10 }
context 'when the rent starts before the pre existing rent' do
let(:begin_date) { DateTime.new(2022, 1, 5) }
context 'and ends before the current rent' do
let(:end_date) { DateTime.new(2022, 1, 9) }
it { expect(subject).to be_valid }
end
context 'and ends on the current rent beginning date' do
let(:end_date) { DateTime.new(2022, 1, 10) }
it { expect(subject).to be_valid }
end
context 'and ends after the current_rent is take' do
let(:end_date) { DateTime.new(2022, 1, 11) }
it {
expect(subject).not_to be_valid
}
end
end
context 'and ends on the current rent beginning date' do
let(:end_date) { DateTime.new(2022, 1, 10) }
it { expect(subject).to be_valid }

context 'when the rent ends after the pre existing rent' do
let(:end_date) { DateTime.new(2022, 1, 20) }
context 'and begins before the current rent is back' do
let(:begin_date) { DateTime.new(2022, 1, 14) }
it { expect(subject).not_to be_valid }
end
context 'and begins whe the current rent is back' do
let(:begin_date) { DateTime.new(2022, 1, 15) }
it { expect(subject).to be_valid }
end
context 'and begins after the current rent is back' do
let(:begin_date) { DateTime.new(2022, 1, 16) }
it { expect(subject).to be_valid }
end
end
context 'and ends after the current_rent is take' do
let(:end_date) { DateTime.new(2022, 1, 11) }
context 'and begins and ends during the current rent' do
let(:begin_date) { DateTime.new(2022, 1, 11) }
let(:end_date) { DateTime.new(2022, 1, 14) }
it { expect(subject).not_to be_valid }
end
end

context 'when the rent ends after the pre existing rent' do
let(:end_date) { DateTime.new(2022, 1, 20) }
context 'and begins before the current rent is back' do
let(:begin_date) { DateTime.new(2022, 1, 14) }
context 'and begins and ends at the same time as the current rent' do
let(:begin_date) { DateTime.new(2022, 1, 10) }
let(:end_date) { DateTime.new(2022, 1, 15) }
it { expect(subject).not_to be_valid }
end
context 'and begins whe the current rent is back' do
let(:begin_date) { DateTime.new(2022, 1, 15) }
it { expect(subject).to be_valid }
end
context 'and begins after the current rent is back' do
let(:begin_date) { DateTime.new(2022, 1, 16) }
end

context 'when the rent number is less then all available item number' do
let(:rent_number) { 1 }
context 'and begins and ends at the same time as the current rent' do
let(:begin_date) { DateTime.new(2022, 1, 10) }
let(:end_date) { DateTime.new(2022, 1, 15) }
it { expect(subject).to be_valid }
end
end
Expand Down

0 comments on commit 3d8d8cf

Please sign in to comment.