Auto-number customer and supplier IDs
Epicor gives every customer and supplier an internal number (CustNum, VendorNum) automatically, but
the IDs people see and type (CustID, VendorID) are entered by hand. If you want those to be
sequential numbers, a short pre-processing directive can hand them out. This is a well-known community
pattern; the version here is written to be safe with several users saving at once.
What it does
Section titled “What it does”- Users create a customer and enter
AUTOas the Customer ID (or you default it toAUTO; see below). - On save, the directive replaces
AUTOwith the next number from a counter and increments the counter. - Users can still type a real ID when they need a specific one; the directive leaves those alone.
Before you start
Section titled “Before you start”Create the counter as a user code:
- Open User Codes Maintenance.
- Add a code type
NEXTNUM. - Under it, add a code
CUSTOMERand put the first number to issue (for example100001) in its description.
The directive
Section titled “The directive”Pre-processing on Erp.BO.Customer.Update, Custom Code widget:
var newCustomers = ds.Customer .Where(c => c.RowMod == IceRow.ROWSTATE_ADDED && c.CustID == "AUTO") .ToList();
if (newCustomers.Count == 0) return;
using (var txScope = IceContext.CreateDefaultTransactionScope()){ var counter = Db.UDCodes.With(LockHint.UpdLock).FirstOrDefault(u => u.Company == Session.CompanyID && u.CodeTypeID == "NEXTNUM" && u.CodeID == "CUSTOMER");
int next; if (counter == null || !int.TryParse(counter.CodeDesc, out next)) throw new Ice.BLException("Customer numbering isn't set up. Check user code NEXTNUM / CUSTOMER.");
foreach (var cust in newCustomers) { // skip any number someone has already used by hand while (Db.Customer.Any(c => c.Company == Session.CompanyID && c.CustID == next.ToString())) next++;
cust.CustID = next.ToString(); next++; }
counter.CodeDesc = next.ToString(); Db.Validate(); txScope.Complete();}How it works
Section titled “How it works”- Why
Updateand notGetNewCustomer. Numbers are only taken when a customer is actually saved. Assigning at New would use up a number every time someone started a customer and abandoned it. - Why
UpdLock. Reading the counter with an update lock inside a transaction makes a second user wait until the first has written the new value back. Without it, two saves at the same moment can read the same number. - Why the
Anycheck. If someone typed a numeric ID by hand earlier, the counter could otherwise collide with it. - The counter lives in data, not code, so an administrator can move it (for example to start a new range) without editing the directive.
Variations
Section titled “Variations”- Supplier IDs. Same pattern on
Erp.BO.Vendor.Update, working onds.VendorandVendorID, with a separate counter code such asSUPPLIER. Use separate counters so customers and suppliers don’t share a sequence. - Fixed width. Use
next.ToString("D6")to produce000123-style IDs. Make sure theAnycheck uses the same format. - Default to AUTO. A post-processing directive on
Erp.BO.Customer.GetNewCustomerwith a Set Field ofCustIDon the added row to"AUTO"saves users typing it.