Set up custom invoice numbering
Add this code to site.php file:
Am_Di::getInstance()->hook->add(Am_Event::INVOICE_BEFORE_INSERT, function (Am_Event $event) { $di = Am_Di::getInstance(); $period = date('Y_m'); $counterKey = 'invoice_counter_' . $period;
// Increment the counter atomically so concurrent checkouts get different numbers. $di->db->query( "INSERT INTO ?_store SET name=?, `value`=LAST_INSERT_ID(1), `expires`=NULL ON DUPLICATE KEY UPDATE `value`=LAST_INSERT_ID(CAST(`value` AS UNSIGNED) + 1), `expires`=NULL", $counterKey ); $number = (int)$di->db->selectCell('SELECT LAST_INSERT_ID()');
$invoice = $event->getInvoice(); $invoice->public_id = sprintf('%s_%04d', $period, $number);
$di->logger->debug( '[FIX:custom-invoice-number] Assigned invoice number {public_id}', ['public_id' => $invoice->public_id] );});This example produces numbers such as 2026_08_0001 and starts a new counter
each month. You can change the prefix and formatting, but keep the complete
value within the 64-character public_id limit. The database requires this
value to be unique; if a duplicate is supplied, aMember replaces it with a
randomly generated ID.
The counter is reserved before the invoice is saved, so failed invoice creation can leave gaps in the sequence.
For the widest payment-plugin compatibility, use only letters, numbers, and underscores. In particular, avoid dashes because some payment plugins use them to add or parse transaction suffixes.
Copyright © 2002–2026 www.amember.com. All Rights Reserved.