Skip to content

Instantly share code, notes, and snippets.

@apneadiving
Last active May 1, 2020 09:50
Show Gist options
  • Save apneadiving/b8009ba7aea9989fc46a to your computer and use it in GitHub Desktop.
Save apneadiving/b8009ba7aea9989fc46a to your computer and use it in GitHub Desktop.
incremental invoice numbers without gap in rails + postgresql
class CreateInvoiceNumbers < ActiveRecord::Migration
def up
create_table :invoice_numbers do |t|
t.integer :year, null: false, unique: true
t.integer :next_number_within_year, null: false, default: 1
end
add_index :invoice_numbers, :year, unique: true
(2016..2045).each do |year|
::InvoiceNumber.create!(year: year)
end
create_table :payment_statements do |t|
t.integer :user_id, null: false
t.integer :payment_request_id, null: false
t.integer :number, null: false
t.integer :year, null: false
t.timestamps
end
add_index :payment_statements, [:year, :number], unique: true
add_index :payment_statements, :payment_request_id, unique: true
execute %{
CREATE OR REPLACE FUNCTION add_invoice_number()
RETURNS trigger AS
$BODY$
DECLARE
new_invoice_number INTEGER;
BEGIN
LOCK TABLE invoice_numbers IN ACCESS EXCLUSIVE MODE;
SELECT invoice_numbers.next_number_within_year
INTO new_invoice_number
FROM invoice_numbers
WHERE invoice_numbers.year = DATE_PART('YEAR', NEW.created_at)
;
NEW.number = new_invoice_number;
NEW.year = DATE_PART('YEAR', NEW.created_at);
UPDATE invoice_numbers
SET next_number_within_year = new_invoice_number + 1
WHERE year = DATE_PART('YEAR', NEW.created_at);
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
}
execute %{
CREATE TRIGGER add_invoice_number_to_statements
BEFORE INSERT
ON payment_statements
FOR EACH ROW
EXECUTE PROCEDURE add_invoice_number();
}
end
def down
drop_table :invoice_numbers
drop_table :payment_statements
execute %{
DROP FUNCTION add_invoice_number();
}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment