Auto naming through Server script - ERPNext

In some ERP customizations, you may want the Item Code to follow a dynamic, logic-based naming series that reflects business parameters like brand, business group, or purchase group.

 · 2 min read

NAMING CONVENTION. Naming convention is really significant… | by Emrullah  DEMİR | Medium

Goals



  1. Automatically generate item_code using logic based on business_group, purchase_group, and brand_code.
  2. Maintain a custom_temp_item_name field to temporarily store the user-entered name.
  3. Ensure item_name does not get overwritten by the new item_code.
  4. Optionally store and manage series tracking outside of the Item table.


 Step 1: Server Script for Custom Naming (Before Insert)



Script Name: Item-auto-name

Trigger: Before Insert

Target Doctype: Item


This script builds a naming series prefix using the first letters of business_group, purchase_group, and full brand_code, then queries the DB to determine the last used code and increments from there.


# Build the prefix
first_letter_business_group = (doc.business_group or "")[:1].upper()
first_letter_purchase_group = (doc.purchase_group or "")[:1].upper()
brand_code = (doc.brand_code or "").upper()

series_digits = 6
series_prefix = f"{first_letter_business_group}{first_letter_purchase_group}{brand_code} "

# Find the last matching item_code
last_item = frappe.db.sql(
   """
   SELECT name FROM `tabItem`
   WHERE name LIKE %s
   ORDER BY LENGTH(name) DESC, name DESC
   LIMIT 1
   """,
   (series_prefix + "%",),
   as_dict=True
)

if last_item:
   last_name = last_item[0]["name"]
   last_number = last_name.replace(series_prefix, "")
   try:
       next_number = int(last_number) + 1
   except ValueError:
       next_number = 1
else:
   next_number = 1

# Assign new item_code
doc.item_code = f"{series_prefix}{str(next_number).zfill(series_digits)}"





Step 2: Client Script to Copy 

item_name

 to Temp Field



ERPNext automatically sets item_name = item_code during the insert process. To preserve what the user originally typed in item_name, we copy it live into a custom field.


Custom Field Required: custom_temp_item_name (Data type)


Client Script: item-copy-item-name-to-temp


frappe.ui.form.on('Item', {
   item_name: function(frm, cdt, cdn) {
       let row = locals[cdt][cdn];
       frappe.model.set_value(cdt, cdn, 'custom_temp_item_name', row.item_name);
   }
});




Step 3: Server Script to Restore Name (Before Validate)


During validation, restore the original item_name from the custom_temp_item_name field.


Script Name: item-before-validate

Trigger: Before Validate


doc.item_name = doc.custom_temp_item_name




Optional Enhancement: Use a Custom DocType to Track Series



Server Scripts do not support frappe.model.naming.set_name_by_naming_series() directly. To decouple naming logic from the Item table and avoid SQL queries, you can manage the series in a separate DocType.



Example Custom DocType: 

Item Series Tracker



Fields:


  1. prefix (Data, unique key)
  2. last_number (Int)



Sample Usage in Server Script:



prefix = f"{first_letter_business_group}{first_letter_purchase_group}{brand_code}"

series_doc = frappe.get_doc('Item Series Tracker', prefix) if frappe.db.exists('Item Series Tracker', prefix) else frappe.get_doc({
   'doctype': 'Item Series Tracker',
   'prefix': prefix,
   'last_number': 0
})

series_doc.last_number += 1
series_doc.save()

doc.item_code = f"{prefix} {str(series_doc.last_number).zfill(series_digits)}"



This approach:


  1. Avoids raw SQL.
  2. Gives you versionable, audit-friendly control over series.
  3. Supports concurrency-safe item code generation.


----------------------------------------


Feature Recommendation: Support Naming Functions in Server Scripts



Problem Statement



Currently, server scripts in Frappe do not support built-in naming utilities like:


  1. frappe.model.naming.make_autoname()
  2. frappe.model.naming.set_name_by_naming_series()



This limitation forces developers to either:


  1. Write raw SQL queries to simulate naming series (which is risky and hard to scale), or
  2. Fall back to custom apps and hooks (e.g., before_insert or autoname in Python), which requires full developer access and a deployment cycle.



However, naming logic is often a business-level decision, not a developer decision.



Why Naming Should Be a Server Script Feature



  1. Business users and consultants often define naming patterns — based on attributes like region, brand, group, or fiscal year — without needing full app-level control.
  2. Server Scripts are designed for low-code/no-code flexibility and should allow complete document initialization — including naming.
  3. This enables faster prototyping, testing, and iteration, especially on hosted Frappe Cloud instances where app installation is restricted.




Suggested Solutions



  1. Allow frappe.model.naming methods in server script , especially:

  2. make_autoname
  3. set_name_by_naming_series




Aysha Mehrin Musthafa

Functional Consultant at ERPGulf

No comments yet

No comments yet. Start a new discussion.

Add Comment