Youssef Hassan
@youssef_hassan • 1 months ago
Get a business-level explanation of unfamiliar legacy code, its side effects, the parts that only look removable, and a safe plan for your specific change.
codechangelevel{{code}}{{change}}{{level}}change: Add credit notes. They need their own number sequence with a CN prefix, separate from invoices.
level: Comfortable with PHP 8 and Laravel, never touched raw mysqli code.
code:
```php
function next_invoice_no($db, $branch) {
$y = date('y');
$m = date('n');
$fy = $m < 4 ? ($y - 1) . $y : $y . ($y + 1);
$db->query("LOCK TABLES invoice_seq WRITE");
$r = $db->query("SELECT last_no FROM invoice_seq WHERE branch='$branch' AND fy='$fy'");
$row = $r->fetch_assoc();
if (!$row) {
$n = 1;
$db->query("INSERT INTO invoice_seq (branch, fy, last_no) VALUES ('$branch', '$fy', 1)");
} else {
$n = $row['last_no'] + 1;
$db->query("UPDATE invoice_seq SET last_no=$n WHERE branch='$branch' AND fy='$fy'");
}
$db->query("UNLOCK TABLES");
return strtoupper(substr($branch, 0, 3)) . '/' . $fy . '/' . str_pad($n, 5, '0', STR_PAD_LEFT);
}
```MUM/2627/00042. Numbering restarts at 1 every Indian financial year (April to March), and each branch has its own counter. This is what Indian GST rules expect: a consecutive serial number, unique within the financial year.$fy: in September 2026, $m = 9 gives "26" . 27 = "2627". In February 2027 it gives (27 - 1) . "27" = "2627".invoice_seq table, reads the counter, then either inserts a new row (first invoice of the year for that branch) or updates last_no, and unlocks.LOCK TABLES is not removable. Without it, two invoices created at the same moment read the same last_no and get the same number. Duplicate GST invoice numbers are a compliance problem, not just a bug.date() uses the server's timezone. On a UTC server, an invoice raised at 00:30 IST on 1 April gets last year's $fy.str_pad(..., 5) means 99,999 invoices per branch per year, after which numbers become 6 digits. That's harmless but visible.substr($branch, 0, 3): two branches starting with the same three letters (e.g. "Pune" and "Punjab") share a prefix but not a counter, so numbers can collide on paper.doc_type column ('INV', 'CN') to invoice_seq, default 'INV' for existing rows, and make the unique key (branch, fy, doc_type). Check whether a unique key exists today. The code assumes one but doesn't show it.$type parameter, include it in the SELECT/INSERT/UPDATE WHERE clauses and in the prefix.MUM/CN/2627/00001 is 17. Use MUMCN/2627/00001 (16) or drop a separator.last_no values. After: raise one invoice and one credit note per branch, and confirm the invoice sequence continued unchanged.$branch goes straight into SQL. If it can ever come from user input, that's SQL injection. Use a prepared statement when you touch these lines anyway.