diff --git a/Gemfile b/Gemfile index b2a07e7c..7074f669 100644 --- a/Gemfile +++ b/Gemfile @@ -45,6 +45,7 @@ gem 'russian_central_bank' gem 'gon' gem 'whenever', require: false gem 'cocoon' +gem 'validates_overlap' group :development, :test do gem 'rspec-rails' diff --git a/Gemfile.lock b/Gemfile.lock index 66fccd8e..4eb7a83c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -359,6 +359,8 @@ GEM raindrops (~> 0.7) uuid (2.3.7) macaddr (~> 1.0) + validates_overlap (0.5.2) + rails (>= 3.0.0) warden (1.2.3) rack (>= 1.0) wasabi (3.5.0) @@ -425,6 +427,7 @@ DEPENDENCIES timecop uglifier (>= 1.3.0) unicorn + validates_overlap whenever BUNDLED WITH diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 86c47a78..1fdf9003 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -5,8 +5,8 @@ # id :integer not null, primary key # organization_id :integer not null # customer_id :integer not null -# starts_at :datetime -# ends_at :datetime not null +# starts_at :date +# ends_at :date not null # currency :string default("USD"), not null # amount_cents :integer default(0), not null # sent_at :datetime @@ -32,11 +32,13 @@ class Invoice < ActiveRecord::Base validates :ends_at, presence: true validates :amount, presence: true validates :currency, presence: true + validates :customer_name, presence: true validates :amount, numericality: { greater_than: 0, less_than_or_equal_to: Dictionaries.money_max } validates :currency, inclusion: { in: Dictionaries.currencies, message: "%{value} is not a valid currency" } + validates :starts_at, :ends_at, overlap: { scope: 'customer_id', message_content: 'overlaps with another Invoice' } scope :ordered, -> { order('created_at DESC') } diff --git a/db/migrate/20150910054909_change_invoice_date_columns.rb b/db/migrate/20150910054909_change_invoice_date_columns.rb new file mode 100644 index 00000000..ee40b6ef --- /dev/null +++ b/db/migrate/20150910054909_change_invoice_date_columns.rb @@ -0,0 +1,6 @@ +class ChangeInvoiceDateColumns < ActiveRecord::Migration + def change + change_column :invoices, :starts_at, :date + change_column :invoices, :ends_at, :date + end +end diff --git a/db/schema.rb b/db/schema.rb index f533d359..6dccc3ce 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150909054901) do +ActiveRecord::Schema.define(version: 20150910054909) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -94,8 +94,8 @@ create_table "invoices", force: :cascade do |t| t.integer "organization_id", null: false t.integer "customer_id", null: false - t.datetime "starts_at" - t.datetime "ends_at", null: false + t.date "starts_at" + t.date "ends_at", null: false t.string "currency", default: "USD", null: false t.integer "amount_cents", default: 0, null: false t.datetime "sent_at" diff --git a/spec/factories.rb b/spec/factories.rb index c048ab86..b012a44d 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -146,6 +146,7 @@ factory :invoice do organization customer + customer_name ends_at { Time.now } currency 'RUB' amount 500 diff --git a/spec/models/invoice_spec.rb b/spec/models/invoice_spec.rb index 0a124392..14fbf35a 100644 --- a/spec/models/invoice_spec.rb +++ b/spec/models/invoice_spec.rb @@ -5,8 +5,8 @@ # id :integer not null, primary key # organization_id :integer not null # customer_id :integer not null -# starts_at :datetime -# ends_at :datetime not null +# starts_at :date +# ends_at :date not null # currency :string default("USD"), not null # amount_cents :integer default(0), not null # sent_at :datetime @@ -28,8 +28,47 @@ it { is_expected.to validate_presence_of(:organization) } it { is_expected.to validate_presence_of(:ends_at) } it { is_expected.to validate_presence_of(:currency) } + it { is_expected.to validate_presence_of(:customer_name) } it { is_expected.to validate_numericality_of(:amount). is_greater_than(0).is_less_than_or_equal_to(Dictionaries.money_max) } it { is_expected.to validate_inclusion_of(:currency).in_array(Dictionaries.currencies) } + + context 'check customer date range overlaping' do + let!(:org) { create :organization } + let!(:customer) { create :customer } + let!(:invoice) { create :invoice, customer_name: customer.name, + organization: org, starts_at: Date.today - 10.days, ends_at: Date.today } + let(:invoice1) { build :invoice, customer_name: customer.name, + organization: org, starts_at: Date.today - 9.days, ends_at: Date.today + 1.days } + let(:invoice2) { build :invoice, customer_name: customer.name, + organization: org, starts_at: Date.today - 11.days, ends_at: Date.today } + let(:invoice3) { build :invoice, customer_name: customer.name, + organization: org, starts_at: Date.today - 9.days, ends_at: Date.today } + let(:invoice4) { build :invoice, customer_name: customer.name, + organization: org, starts_at: Date.today - 11.days, ends_at: Date.today + 1.days } + let(:invoice5) { build :invoice, customer_name: customer.name, + organization: org, starts_at: Date.today + 2.days, ends_at: Date.today + 10.days } + + it 'Show error on starts_at' do + invoice1.valid? + expect(invoice1.errors[:starts_at]).to include('overlaps with another Invoice') + end + it 'Show error on ends_at' do + invoice2.valid? + expect(invoice2.errors[:starts_at]).to include('overlaps with another Invoice') + end + it 'Show errors on starts_at and ends_at' do + invoice3.valid? + expect(invoice3.errors[:starts_at]).to include('overlaps with another Invoice') + end + it 'Show errors on starts_at and ends_at' do + invoice4.valid? + expect(invoice4.errors[:starts_at]).to include('overlaps with another Invoice') + end + it 'Dont show errors on starts_at and ends_at' do + invoice5.valid? + expect(invoice5.errors[:starts_at]).to_not include('overlaps with another Invoice') + end + end end end