Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Ensure Gap Free and Safe Invoice Number Generation (Legal Issues)

Background and System View

We have implemented a Billing system in a distributed environment. There are 4 terminals that generate around 2 bills per minute per terminal. We use Mysql as backend and C#, winforms as our client tech.

The most important constraint in any billing system is that the invoice number must be sequential. To do that I run a query similar to

In pseudo-code

let x ="SELECT count(*) from Orders where IsInvoiceGenerated=1 and FinancialYear=val

new invoicenum = x + 1;

The Problem Everything was running ok till 411th invoice, after which the system suddenly skipped 2 invoices and generated Invoice 414. We investigated the system state and found that system was not tampered externally and we also inferred that nobody accessed database from workbench. This is a major issue since it also has legal ramifications.

Can you please suggest the best way to ensure that billing number always remains sequential.?

like image 342
Akshay Zadgaonkar Avatar asked Jan 08 '13 13:01

Akshay Zadgaonkar


People also ask

What is a good numbering system for invoices?

Try using sequential numbering, alphanumeric invoice numbers, or professional invoice software to better organize your payment history. Invoice numbers help you quickly assess how much money you're owed, which clients have paid, and the full payment history for a given client.

Do invoices have to be sequentially numbered?

Invoice numbers are a mandatory invoice field. They should be assigned sequentially, meaning that the number of each new invoice increases. Legally, an invoice number sequence should never contain repeats or gaps. It's not recommended to simply number invoices '1', '2', '3', etc.

Why do invoices have to be sequentially numbered?

The only thing to remember when numbering your invoices are to ensure that they are sequential. Assigning invoice numbers chronologically allows you to easily identify every unique transaction – this is especially important as your business grows and you start getting more individual clients to track payments with.


2 Answers

To create a unique number, you should store the current number in a table and then, when you create a new invoice you have to perform the following steps:

  1. Start a transaction
  2. Get the number from the table
  3. Set the number to your invoice
  4. Set number + 1 in the table from before
  5. commit
like image 148
TGlatzer Avatar answered Oct 25 '22 01:10

TGlatzer


Here is a solution I came up with:

CREATE TABLE `inv` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `invNo` int(10) DEFAULT NULL,
  `invName` varchar(100) DEFAULT NULL,
  `cratetedAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE     CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;

and create a new invoice with this query

INSERT INTO `inv` (`invNo`, `invName`) SELECT (SELECT MAX(invNo)+1 FROM `inv` FOR UPDATE) AS `invNo`, 'Invoice 1';

Using SELECT FOR UPDATE will acquire a write lock on the table hence simultaneous insert will be block, where at the same time there will be no restriction on read. So the only bottleneck could be invoice creation which will happen only one at a time, and I think that is acceptable.

Now only concern is what will happen if my server stopped, crashed, network lost or something extraordinary happened and the code doesn't get a chance to finish the transaction, and it could end up with a deadlock.

Frankly I am not sure how to handle this last situation, but I was reading somewhere that we can use MySql wait_timeout property for this but not sure how to use it. However I am using Spring for my server code and using @Transactional timeout property, not sure if that will cover me.

like image 31
Krishnendu Avatar answered Oct 24 '22 23:10

Krishnendu