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.