Frappe allows automatically naming documents. One of the autoname options is ‘Naming Series’ as follows -
naming_series option is used, a numerical sequence number is maintained in
tabSeries table against each series key. e.g SO-, SINV-, PO- etc.
Every time a new document is created,
getseries function in
naming.py is called to get the next sequence number to be used for the document. The function is as follows -
def getseries(key, digits, doctype=''): # series created ? current = frappe.db.sql("select `current` from `tabSeries` where name=%s for update", (key,)) if current and current is not None: current = current # yes, update it frappe.db.sql("update tabSeries set current = current+1 where name=%s", (key,)) current = cint(current) + 1 else: # no, create it frappe.db.sql("insert into tabSeries (name, current) values (%s, 1)", (key,)) current = 1 return ('%0'+str(digits)+'d') % current
The above function locks a row in
tabSeries table for update and increments its value by 1. The row remains locked until the entire operation of saving the document is completed. This essentially means we cannot create multiple documents of same type concurrently.
What If, we do following -
At the server start, reserve lets say 100 sequence numbers and allocate the same from memory to new documents getting created. Reserve 100 more when we run out of sequences. We dont have to lock a row in
tabSeries for each document and can essentially create multiple documents concurrently.
e.g. consider current naming series values for Sales Order doctype
tabSeries name current SO- 123
At server startup we reserve 100 sequence numebrs and update the value as follows -
tabSeries name current SO- 223
and in the
get_series method, keep on returning the value from memory keeping track of last issued value.
We can handle error scenarios like server restart etc by resetting the value at startup based on the last document created of any type.