Files
Autoparts-DB/pos/services/barcode_generator.py

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]