Created
February 13, 2019 17:55
-
-
Save loicginoux/52eefb5750fd6c5107144bb6279aec93 to your computer and use it in GitHub Desktop.
invoice number generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# generate invoice number in a sequential mode | |
# using redis and redlock gem | |
# ex: | |
# Accounting::InvoiceNumberGenerator::Base.new.lock do |next_number| | |
#. # create your invoice here | |
# end | |
class Accounting::InvoiceNumberGenerator::Base | |
LOCK_TIMEOUT = 10000 | |
FIRST_NUM_SEQUENCE = 100 | |
# pass the new generated invoice number to block | |
def lock(&block) | |
Invoice.transaction do | |
lock_info = lock_manager.lock(lock_name, LOCK_TIMEOUT) | |
if lock_info | |
begin | |
yield(get_next_number) if block_given? | |
ensure | |
lock_manager.unlock(lock_info) | |
end | |
else | |
raise "LockTimeout #{lock_name}" | |
end | |
end | |
end | |
private | |
# Warning: not thread safe | |
def get_next_number | |
"#{yearly_sequence}#{num_sequence}" | |
end | |
def yearly_sequence | |
"#{year}#{type}" | |
end | |
def year | |
Time.now.utc.strftime("%y") | |
end | |
def type | |
'' | |
end | |
def lock_name | |
"lock_#{self.class.to_s.underscore}_invoice_number" | |
end | |
def num_sequence | |
last_invoice = Invoice.where("number LIKE ?", "%#{yearly_sequence}%").order('number').last | |
if last_invoice.nil? | |
FIRST_NUM_SEQUENCE | |
else | |
last_number = last_invoice.number.gsub(yearly_sequence, '').to_i | |
last_number + 1 | |
end | |
end | |
def lock_manager | |
@lock_manager ||= Redlock::Client.new([ENV['REDIS_URL']], { | |
retry_count: 3, | |
retry_delay: 1000, | |
retry_jitter: 50, | |
redis_timeout: 0.1 | |
}) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment