From 8badf858a6235ce4385fb8a7da1d5eccfe0561c1 Mon Sep 17 00:00:00 2001 From: Vincent Pochet Date: Thu, 14 Dec 2023 14:56:48 +0100 Subject: [PATCH] fix(invoice): Add missing unique index on invoice organization_sequential ids --- app/models/invoice.rb | 5 ++++- ...ue_index_on_invoice_organization_sequential_id.rb | 12 ++++++++++++ db/schema.rb | 3 ++- spec/factories/invoices.rb | 2 ++ spec/models/invoice_spec.rb | 4 ++-- 5 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20231214133638_add_unique_index_on_invoice_organization_sequential_id.rb diff --git a/app/models/invoice.rb b/app/models/invoice.rb index d2a95c8acdc6..9f218f398653 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -279,7 +279,10 @@ def ensure_organization_sequential_id end def generate_organization_sequential_id - organization_sequence_scope = organization.invoices.where(created_at: Time.now.utc.all_month) + organization_sequence_scope = organization.invoices.where( + "date_trunc('month', created_at)::date = ?", + Time.now.utc.beginning_of_month.to_date, + ) result = Invoice.with_advisory_lock( organization_id, diff --git a/db/migrate/20231214133638_add_unique_index_on_invoice_organization_sequential_id.rb b/db/migrate/20231214133638_add_unique_index_on_invoice_organization_sequential_id.rb new file mode 100644 index 000000000000..0265325c9094 --- /dev/null +++ b/db/migrate/20231214133638_add_unique_index_on_invoice_organization_sequential_id.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class AddUniqueIndexOnInvoiceOrganizationSequentialId < ActiveRecord::Migration[7.0] + disable_ddl_transaction! + + def change + add_index :invoices, + "organization_id, organization_sequential_id, date_trunc('month'::text, created_at)", + name: 'unique_organization_sequential_id', + unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index d37807b7eecf..54fba63f5229 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_12_14_103653) do +ActiveRecord::Schema[7.0].define(version: 2023_12_14_133638) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -527,6 +527,7 @@ t.integer "net_payment_term", default: 0, null: false t.datetime "voided_at" t.integer "organization_sequential_id", default: 0, null: false + t.index "organization_id, organization_sequential_id, date_trunc('month'::text, created_at)", name: "unique_organization_sequential_id", unique: true t.index ["customer_id", "sequential_id"], name: "index_invoices_on_customer_id_and_sequential_id", unique: true t.index ["customer_id"], name: "index_invoices_on_customer_id" t.index ["organization_id"], name: "index_invoices_on_organization_id" diff --git a/spec/factories/invoices.rb b/spec/factories/invoices.rb index c3526fc557e1..63847b5d43a8 100644 --- a/spec/factories/invoices.rb +++ b/spec/factories/invoices.rb @@ -10,6 +10,8 @@ payment_status { 'pending' } currency { 'EUR' } + organization_sequential_id { rand(1_000_000) } + trait :draft do status { :draft } end diff --git a/spec/models/invoice_spec.rb b/spec/models/invoice_spec.rb index afc343e9cde3..310e1a34a0e6 100644 --- a/spec/models/invoice_spec.rb +++ b/spec/models/invoice_spec.rb @@ -11,7 +11,7 @@ describe 'sequential_id' do let(:customer) { create(:customer, organization:) } - let(:invoice) { build(:invoice, customer:, organization:) } + let(:invoice) { build(:invoice, customer:, organization:, organization_sequential_id: nil) } it 'assigns a sequential id and organization sequential id to a new invoice' do invoice.save @@ -98,7 +98,7 @@ let(:organization) { create(:organization, name: 'LAGO') } let(:customer) { create(:customer, organization:) } let(:subscription) { create(:subscription, organization:, customer:) } - let(:invoice) { build(:invoice, customer:, organization:) } + let(:invoice) { build(:invoice, customer:, organization:, organization_sequential_id: nil) } it 'generates the invoice number' do invoice.save