I am developing a web application, this application will need to generate receipt number for every confirmed transaction.
What is a good receipt number? I think a receipt number should not be just a running number generated by database, but it should have some meaning beyond just a unique running number.
Here is what I have come up with so far,
Format: EYY-ddd-XXXXXXX
Example output: E13-146-0000001
Where:
E
: It is just a to signify this receipt number was generated by my system. This value is always E
.
YY
: Is the current year the receipt was generated, so in this case it is 13
ddd
: Is the day of the year, 146
is May 26 (in 2013).
XXXXXXX
: Is a 7 digit running number, up to 9,999,999
So my system can generate up to 10 million unique receipt numbers daily until 2099.
What do you think? Is this sensible? Any suggestion is appreciated.
Update
Judging from the comments so far, it looks like there is no specific ‘pattern’ or ‘best practices’ for receipt number. My intention in asking the question is to know whether there is specific best practises in generating the number that I should know about. Looks like I am free to use whatever pattern I feel sensible.
Other requirements
- As short as possible (that is why I didnt go for YYYYMMdd-XXXXXXX)
- Somewhat not to obvious (YYYMMdd is way to obvious).
- Should be fixed length. (Easier to detect if customer entered invalid receipt number)
- Can generate fairly large numbers (10 million a day seems sensible, though I doubt my system will be that popular)
- Can be made into QR code (so staff can scan and verify the number is valid)
- Someone mentions about error detection code like ISBN, seems good but I havent read it yet.
12
Unless encoding the extra information serves some useful purpose you didn’t describe in your question, don’t attempt to build any kind of intelligence into your numbers. It will eventually backfire, often in a way that will make recovery difficult and expensive.
My advice? Use an integer sequence number and be done with it. They’re easy to deal with, and if you’re using them as identifiers in a database, they store compactly and index much more quickly than strings.
As short as possible
If you’re actually doing only 10,000 transactions per day, you’re going to have three unnecessary zeros in every receipt number pretty much forever. That makes your numbers 30% larger than they need to be. More digits increases the odds there will be a communication or keying error. Someone unfamiliar with your scheme won’t know that there should be seven digits in your sequence number and will have to count out a string of leading zeros for the low-numbered receipts — you’ll have a bunch of those daily — and that will consume more time than having them will save.
An integer sequence number won’t get any longer until it runs out of digits in its current size and can grow practically infinitely. Days when you do low volume will delay the addition of digits.
Somewhat not to obvious (YYYMMdd is way to obvious).
Don’t think for a minute that someone wanting to do something nefarious with your receipt numbers isn’t going to look up at his calendar and notice that you’re using the year and Julian day. If the receipt number is your sole method of verifying that someone giving it to you is the customer who received it, you’re going to get hacked hard. Amateurs hack systems, professionals hack people.
Should be fixed length. (Easier to detect if customer entered invalid receipt number)
It’s not really any easier; if the number isn’t in your database, it’s not valid. There’s plenty of potential for someone to enter an invalid number that’s the right length.
Can generate fairly large numbers (10 million a day seems sensible, though I doubt my system will be that popular)
A 64-bit unsigned integer can hold a maximum value of 9,223,372,036,854,775,807. That will give you a billion unique numbers daily for the next 2.5 million years, longer if you’re not doing that kind of volume.
Can be made into QR code (so staff can scan and verify the number is valid)
Using digits only assures that you’ll be able to use any barcode format out there. Linear barcodes scan a lot faster than QR and are readable under much worse conditions. That should be taken into account if there’s a warehouse involved.
3
Without more information it appears reasonable, if not overly complex. No one here can say for sure it will meet your needs, as you have not said what they are.
Whats wrong with a sequential number starting at 0? – You state “you think its not good enough”, what requirement does that not meet?.
What happens after 2099 – whats the requirement, what happens after 9,999,999 transactions in a day – whats the requirement, ‘E’ – what requirement does that meet?
5
I would add a checksum digit. Makes it easier to tell if someone types it out and makes a mistake.
3
Will many systems be generating these numbers at once? If so, then neither your system nor sequential numbers will be sufficient; there will be days when the internet isn’t working, or a bug somewhere results in collisions, and so on. If these things are true, I’d use a GUID (which is “unique enough”). If GUIDs aren’t an option, I’d switch to hex and use a semantic numeric string like this:
EDDDDLLLLNNNNNNNNC
Where E
is your generic “I did this” flag, D
is a hex string representing the year and date in hex, L
is a hex string representing the source location (allowing 65,000 separate POS systems or other sources to use your system without collision), N
is a simple sequence number for that source, and C
is a check digit.
An example:
E3FDF00A2000000D2C
3FDF
represents 16351
, or June 12, 2051. 00A2
represents your POS system. The 000000D2
represents that day’s sequence number, and C
is a check digit (calculated simply as (3FDF + A2 + D2) % F
, which may not be algorithmically perfect).
If you are willing to relax the requirement that it be the same length every time, you can easily make it elastic, so that the above is rendered as:
E3FDF00A2D2C
The first 9 digits are always the same, and the last digit is the check digit, so the remainder is the sequence number. If you are open to having a divider character, you could make it even shorter:
E3FDFA2-D2C
3