# /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]