62 lines
1.9 KiB
Python
62 lines
1.9 KiB
Python
# /home/Autopartes/pos/services/barcode_generator.py
|
|
"""Generate internal barcodes for parts that don't have manufacturer barcodes.
|
|
Format: NX-{tenant_short}-{sequential_number}
|
|
|
|
Uses a PostgreSQL sequence (barcode_seq) per tenant schema to guarantee uniqueness
|
|
under concurrent requests. No MAX+1 race conditions.
|
|
"""
|
|
|
|
|
|
def _ensure_sequence(conn):
|
|
"""Create the barcode sequence if it doesn't exist yet."""
|
|
cur = conn.cursor()
|
|
cur.execute("""
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_class WHERE relkind = 'S' AND relname = 'barcode_seq'
|
|
) THEN
|
|
CREATE SEQUENCE barcode_seq START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
|
END IF;
|
|
END $$;
|
|
""")
|
|
cur.close()
|
|
|
|
|
|
def generate_barcode(conn, tenant_db_name):
|
|
"""Generate the next barcode for this tenant.
|
|
|
|
Format: NX-{tenant_short}-{NNNNNNN}
|
|
Example: NX-REFLOPEZ-0000001
|
|
|
|
Uses a PostgreSQL sequence to guarantee unique sequential numbers even
|
|
under concurrent requests (no race conditions).
|
|
"""
|
|
short = tenant_db_name.replace('tenant_', '').replace('_', '').upper()[:10]
|
|
prefix = f"NX-{short}-"
|
|
|
|
_ensure_sequence(conn)
|
|
|
|
cur = conn.cursor()
|
|
cur.execute("SELECT nextval('barcode_seq')")
|
|
next_num = cur.fetchone()[0]
|
|
cur.close()
|
|
|
|
return f"{prefix}{next_num:07d}"
|
|
|
|
|
|
def generate_barcodes_batch(conn, tenant_db_name, count):
|
|
"""Generate multiple sequential barcodes atomically."""
|
|
short = tenant_db_name.replace('tenant_', '').replace('_', '').upper()[:10]
|
|
prefix = f"NX-{short}-"
|
|
|
|
_ensure_sequence(conn)
|
|
|
|
cur = conn.cursor()
|
|
# setval + generate range atomically via a single call
|
|
cur.execute("SELECT nextval('barcode_seq') FROM generate_series(1, %s)", (count,))
|
|
nums = [r[0] for r in cur.fetchall()]
|
|
cur.close()
|
|
|
|
return [f"{prefix}{n:07d}" for n in nums]
|