Files
Autoparts-DB/docs/plans/2026-03-02-pos-cuentas-plan.md
consultoria-as 5e6bf788db docs: add design and implementation plans
- SaaS + aftermarket design spec
- SaaS + aftermarket implementation plan (15 tasks)
- Captura partes design
- POS + cuentas design and plan

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 22:25:38 +00:00

25 KiB

POS + Cuentas por Cobrar — Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Add a Point of Sale with credit accounts, invoicing with tax data, and payment tracking to the Nexus Autoparts system.

Architecture: New PostgreSQL tables (customers, invoices, invoice_items, payments) + API endpoints in server.py + two new pages (pos.html, cuentas.html). Prices are cost + configurable margin. Customer balances are maintained via triggers on invoice/payment inserts.

Tech Stack: Flask, PostgreSQL, SQLAlchemy raw SQL via text(), vanilla HTML/CSS/JS (same stack as existing app).


Task 1: Database schema — Create new tables and columns

Files:

  • Modify: /home/Autopartes/dashboard/server.py (no changes yet, just DB)

Step 1: Add cost_usd columns and create POS tables

Run this SQL via Python script:

# /home/Autopartes/setup_pos_tables.py
from sqlalchemy import create_engine, text
import sys
sys.path.insert(0, '.')
from config import DB_URL

engine = create_engine(DB_URL)
with engine.connect() as conn:
    conn.execute(text("""
        -- Add cost columns
        ALTER TABLE parts ADD COLUMN IF NOT EXISTS cost_usd DECIMAL(12,2);
        ALTER TABLE aftermarket_parts ADD COLUMN IF NOT EXISTS cost_usd DECIMAL(12,2);

        -- Customers
        CREATE TABLE IF NOT EXISTS customers (
            id_customer SERIAL PRIMARY KEY,
            name VARCHAR(200) NOT NULL,
            rfc VARCHAR(13),
            business_name VARCHAR(300),
            email VARCHAR(200),
            phone VARCHAR(20),
            address TEXT,
            credit_limit DECIMAL(12,2) DEFAULT 0,
            balance DECIMAL(12,2) DEFAULT 0,
            payment_terms INTEGER DEFAULT 30,
            active BOOLEAN DEFAULT TRUE,
            created_at TIMESTAMP DEFAULT NOW()
        );

        -- Invoices
        CREATE TABLE IF NOT EXISTS invoices (
            id_invoice SERIAL PRIMARY KEY,
            customer_id INTEGER NOT NULL REFERENCES customers(id_customer),
            folio VARCHAR(20) UNIQUE NOT NULL,
            date_issued TIMESTAMP DEFAULT NOW(),
            subtotal DECIMAL(12,2) NOT NULL DEFAULT 0,
            tax_rate DECIMAL(5,4) DEFAULT 0.16,
            tax_amount DECIMAL(12,2) NOT NULL DEFAULT 0,
            total DECIMAL(12,2) NOT NULL DEFAULT 0,
            amount_paid DECIMAL(12,2) DEFAULT 0,
            status VARCHAR(20) DEFAULT 'pending',
            notes TEXT,
            created_at TIMESTAMP DEFAULT NOW()
        );

        -- Invoice items
        CREATE TABLE IF NOT EXISTS invoice_items (
            id_invoice_item SERIAL PRIMARY KEY,
            invoice_id INTEGER NOT NULL REFERENCES invoices(id_invoice) ON DELETE CASCADE,
            part_id INTEGER REFERENCES parts(id_part),
            aftermarket_id INTEGER REFERENCES aftermarket_parts(id_aftermarket_parts),
            description VARCHAR(500) NOT NULL,
            quantity INTEGER DEFAULT 1,
            unit_cost DECIMAL(12,2) DEFAULT 0,
            margin_pct DECIMAL(5,2) DEFAULT 30,
            unit_price DECIMAL(12,2) NOT NULL,
            line_total DECIMAL(12,2) NOT NULL
        );

        -- Payments
        CREATE TABLE IF NOT EXISTS payments (
            id_payment SERIAL PRIMARY KEY,
            customer_id INTEGER NOT NULL REFERENCES customers(id_customer),
            invoice_id INTEGER REFERENCES invoices(id_invoice),
            amount DECIMAL(12,2) NOT NULL,
            payment_method VARCHAR(20) NOT NULL DEFAULT 'efectivo',
            reference VARCHAR(100),
            date_payment TIMESTAMP DEFAULT NOW(),
            notes TEXT,
            created_at TIMESTAMP DEFAULT NOW()
        );

        -- Indexes
        CREATE INDEX IF NOT EXISTS idx_invoices_customer ON invoices(customer_id);
        CREATE INDEX IF NOT EXISTS idx_invoices_status ON invoices(status);
        CREATE INDEX IF NOT EXISTS idx_invoices_folio ON invoices(folio);
        CREATE INDEX IF NOT EXISTS idx_invoice_items_invoice ON invoice_items(invoice_id);
        CREATE INDEX IF NOT EXISTS idx_payments_customer ON payments(customer_id);
        CREATE INDEX IF NOT EXISTS idx_payments_invoice ON payments(invoice_id);

        -- Folio sequence
        CREATE SEQUENCE IF NOT EXISTS invoice_folio_seq START 1;
    """))
    conn.commit()
    print("POS tables created successfully")

Step 2: Run the script

cd /home/Autopartes && python3 setup_pos_tables.py

Step 3: Verify

python3 -c "
from sqlalchemy import create_engine, text
from config import DB_URL
engine = create_engine(DB_URL)
with engine.connect() as conn:
    for t in ['customers','invoices','invoice_items','payments']:
        cols = conn.execute(text(f\"SELECT column_name FROM information_schema.columns WHERE table_name='{t}' ORDER BY ordinal_position\")).fetchall()
        print(f'{t}: {[c[0] for c in cols]}')
"

Step 4: Commit

git add setup_pos_tables.py && git commit -m "feat(pos): add POS database schema"

Task 2: API endpoints — Customers CRUD

Files:

  • Modify: /home/Autopartes/dashboard/server.py — insert before Main Block (line ~2672)

Step 1: Add customer endpoints

Insert these endpoints before the # Main Block comment in server.py:

# ============================================================================
# POS (Point of Sale) Endpoints
# ============================================================================

@app.route('/pos')
def pos_page():
    return send_from_directory('.', 'pos.html')

@app.route('/pos.js')
def pos_js():
    return send_from_directory('.', 'pos.js')

@app.route('/pos.css')
def pos_css():
    return send_from_directory('.', 'pos.css')

@app.route('/cuentas')
def cuentas_page():
    return send_from_directory('.', 'cuentas.html')

@app.route('/cuentas.js')
def cuentas_js():
    return send_from_directory('.', 'cuentas.js')

@app.route('/cuentas.css')
def cuentas_css():
    return send_from_directory('.', 'cuentas.css')


# ---- Customers ----

@app.route('/api/pos/customers')
def api_pos_customers():
    session = Session()
    try:
        search = request.args.get('search', '')
        page = int(request.args.get('page', 1))
        per_page = min(int(request.args.get('per_page', 50)), 100)
        offset = (page - 1) * per_page

        filters = ["active = TRUE"]
        params = {'limit': per_page, 'offset': offset}
        if search:
            filters.append("(name ILIKE :search OR rfc ILIKE :search OR business_name ILIKE :search)")
            params['search'] = f'%{search}%'

        where = ' AND '.join(filters)
        total = session.execute(text(f"SELECT COUNT(*) FROM customers WHERE {where}"), params).scalar()

        rows = session.execute(text(f"""
            SELECT id_customer, name, rfc, business_name, phone, balance, credit_limit, payment_terms
            FROM customers WHERE {where}
            ORDER BY name LIMIT :limit OFFSET :offset
        """), params).mappings().all()
        return jsonify({'data': [dict(r) for r in rows], 'pagination': {
            'page': page, 'per_page': per_page, 'total': total,
            'total_pages': (total + per_page - 1) // per_page
        }})
    finally:
        session.close()


@app.route('/api/pos/customers/<int:customer_id>')
def api_pos_customer_detail(customer_id):
    session = Session()
    try:
        row = session.execute(text(
            "SELECT * FROM customers WHERE id_customer = :id"
        ), {'id': customer_id}).mappings().first()
        if not row:
            return jsonify({'error': 'Cliente no encontrado'}), 404
        return jsonify(dict(row))
    finally:
        session.close()


@app.route('/api/pos/customers', methods=['POST'])
def api_pos_create_customer():
    session = Session()
    try:
        data = request.get_json()
        result = session.execute(text("""
            INSERT INTO customers (name, rfc, business_name, email, phone, address, credit_limit, payment_terms)
            VALUES (:name, :rfc, :business_name, :email, :phone, :address, :credit_limit, :payment_terms)
            RETURNING id_customer
        """), {
            'name': data['name'], 'rfc': data.get('rfc'),
            'business_name': data.get('business_name'),
            'email': data.get('email'), 'phone': data.get('phone'),
            'address': data.get('address'),
            'credit_limit': data.get('credit_limit', 0),
            'payment_terms': data.get('payment_terms', 30)
        })
        new_id = result.scalar()
        session.commit()
        return jsonify({'id': new_id, 'message': 'Cliente creado'})
    except Exception as e:
        session.rollback()
        return jsonify({'error': str(e)}), 500
    finally:
        session.close()


@app.route('/api/pos/customers/<int:customer_id>', methods=['PUT'])
def api_pos_update_customer(customer_id):
    session = Session()
    try:
        data = request.get_json()
        session.execute(text("""
            UPDATE customers SET name = :name, rfc = :rfc, business_name = :business_name,
                   email = :email, phone = :phone, address = :address,
                   credit_limit = :credit_limit, payment_terms = :payment_terms
            WHERE id_customer = :id
        """), {
            'name': data['name'], 'rfc': data.get('rfc'),
            'business_name': data.get('business_name'),
            'email': data.get('email'), 'phone': data.get('phone'),
            'address': data.get('address'),
            'credit_limit': data.get('credit_limit', 0),
            'payment_terms': data.get('payment_terms', 30),
            'id': customer_id
        })
        session.commit()
        return jsonify({'message': 'Cliente actualizado'})
    except Exception as e:
        session.rollback()
        return jsonify({'error': str(e)}), 500
    finally:
        session.close()

Step 2: Verify routes load

cd /home/Autopartes/dashboard && python3 -c "import server; [print(r.rule) for r in server.app.url_map.iter_rules() if 'pos' in r.rule]"

Step 3: Commit

git add dashboard/server.py && git commit -m "feat(pos): add customer CRUD endpoints"

Task 3: API endpoints — Invoices and invoice items

Files:

  • Modify: /home/Autopartes/dashboard/server.py

Step 1: Add invoice endpoints (insert after customer endpoints, before Main Block)

# ---- Invoices ----

@app.route('/api/pos/invoices')
def api_pos_invoices():
    session = Session()
    try:
        customer_id = request.args.get('customer_id', '')
        status = request.args.get('status', '')
        page = int(request.args.get('page', 1))
        per_page = min(int(request.args.get('per_page', 50)), 100)
        offset = (page - 1) * per_page

        filters = ["1=1"]
        params = {'limit': per_page, 'offset': offset}
        if customer_id:
            filters.append("i.customer_id = :customer_id")
            params['customer_id'] = int(customer_id)
        if status:
            filters.append("i.status = :status")
            params['status'] = status

        where = ' AND '.join(filters)
        total = session.execute(text(f"""
            SELECT COUNT(*) FROM invoices i WHERE {where}
        """), params).scalar()

        rows = session.execute(text(f"""
            SELECT i.id_invoice, i.folio, i.date_issued, i.subtotal, i.tax_amount,
                   i.total, i.amount_paid, i.status, c.name AS customer_name, c.rfc
            FROM invoices i
            JOIN customers c ON i.customer_id = c.id_customer
            WHERE {where}
            ORDER BY i.date_issued DESC
            LIMIT :limit OFFSET :offset
        """), params).mappings().all()
        return jsonify({'data': [dict(r) for r in rows], 'pagination': {
            'page': page, 'per_page': per_page, 'total': total,
            'total_pages': (total + per_page - 1) // per_page
        }})
    finally:
        session.close()


@app.route('/api/pos/invoices/<int:invoice_id>')
def api_pos_invoice_detail(invoice_id):
    session = Session()
    try:
        inv = session.execute(text("""
            SELECT i.*, c.name AS customer_name, c.rfc, c.business_name, c.address
            FROM invoices i JOIN customers c ON i.customer_id = c.id_customer
            WHERE i.id_invoice = :id
        """), {'id': invoice_id}).mappings().first()
        if not inv:
            return jsonify({'error': 'Factura no encontrada'}), 404

        items = session.execute(text("""
            SELECT ii.*, p.oem_part_number, ap.part_number AS aftermarket_number
            FROM invoice_items ii
            LEFT JOIN parts p ON ii.part_id = p.id_part
            LEFT JOIN aftermarket_parts ap ON ii.aftermarket_id = ap.id_aftermarket_parts
            WHERE ii.invoice_id = :id
            ORDER BY ii.id_invoice_item
        """), {'id': invoice_id}).mappings().all()

        return jsonify({'invoice': dict(inv), 'items': [dict(it) for it in items]})
    finally:
        session.close()


@app.route('/api/pos/invoices', methods=['POST'])
def api_pos_create_invoice():
    session = Session()
    try:
        data = request.get_json()
        customer_id = data['customer_id']
        items = data['items']  # [{part_id, aftermarket_id, description, quantity, unit_cost, margin_pct, unit_price}]
        tax_rate = data.get('tax_rate', 0.16)
        notes = data.get('notes', '')

        if not items:
            return jsonify({'error': 'La factura debe tener al menos una línea'}), 400

        # Generate folio
        folio_num = session.execute(text("SELECT nextval('invoice_folio_seq')")).scalar()
        folio = f"NX-{folio_num:06d}"

        # Calculate totals
        subtotal = sum(it['quantity'] * it['unit_price'] for it in items)
        tax_amount = round(subtotal * tax_rate, 2)
        total = round(subtotal + tax_amount, 2)

        # Create invoice
        result = session.execute(text("""
            INSERT INTO invoices (customer_id, folio, subtotal, tax_rate, tax_amount, total, notes)
            VALUES (:customer_id, :folio, :subtotal, :tax_rate, :tax_amount, :total, :notes)
            RETURNING id_invoice
        """), {
            'customer_id': customer_id, 'folio': folio,
            'subtotal': subtotal, 'tax_rate': tax_rate,
            'tax_amount': tax_amount, 'total': total, 'notes': notes
        })
        invoice_id = result.scalar()

        # Create items
        for it in items:
            line_total = it['quantity'] * it['unit_price']
            session.execute(text("""
                INSERT INTO invoice_items (invoice_id, part_id, aftermarket_id, description,
                       quantity, unit_cost, margin_pct, unit_price, line_total)
                VALUES (:inv_id, :part_id, :af_id, :desc, :qty, :cost, :margin, :price, :total)
            """), {
                'inv_id': invoice_id,
                'part_id': it.get('part_id'),
                'af_id': it.get('aftermarket_id'),
                'desc': it['description'],
                'qty': it['quantity'],
                'cost': it.get('unit_cost', 0),
                'margin': it.get('margin_pct', 30),
                'price': it['unit_price'],
                'total': line_total
            })

        # Update customer balance
        session.execute(text(
            "UPDATE customers SET balance = balance + :total WHERE id_customer = :id"
        ), {'total': total, 'id': customer_id})

        session.commit()
        return jsonify({'id': invoice_id, 'folio': folio, 'total': total, 'message': 'Factura creada'})
    except Exception as e:
        session.rollback()
        return jsonify({'error': str(e)}), 500
    finally:
        session.close()


@app.route('/api/pos/invoices/<int:invoice_id>/cancel', methods=['PUT'])
def api_pos_cancel_invoice(invoice_id):
    session = Session()
    try:
        inv = session.execute(text(
            "SELECT total, customer_id, status FROM invoices WHERE id_invoice = :id"
        ), {'id': invoice_id}).mappings().first()
        if not inv:
            return jsonify({'error': 'Factura no encontrada'}), 404
        if inv['status'] == 'cancelled':
            return jsonify({'error': 'La factura ya está cancelada'}), 400

        session.execute(text(
            "UPDATE invoices SET status = 'cancelled' WHERE id_invoice = :id"
        ), {'id': invoice_id})

        # Reverse the balance
        session.execute(text(
            "UPDATE customers SET balance = balance - :total WHERE id_customer = :cid"
        ), {'total': inv['total'], 'cid': inv['customer_id']})

        session.commit()
        return jsonify({'message': 'Factura cancelada'})
    except Exception as e:
        session.rollback()
        return jsonify({'error': str(e)}), 500
    finally:
        session.close()

Step 2: Commit

git add dashboard/server.py && git commit -m "feat(pos): add invoice endpoints"

Task 4: API endpoints — Payments and statements

Files:

  • Modify: /home/Autopartes/dashboard/server.py

Step 1: Add payment endpoints (insert after invoice endpoints)

# ---- Payments ----

@app.route('/api/pos/payments', methods=['POST'])
def api_pos_create_payment():
    session = Session()
    try:
        data = request.get_json()
        customer_id = data['customer_id']
        amount = float(data['amount'])
        payment_method = data.get('payment_method', 'efectivo')
        reference = data.get('reference')
        invoice_id = data.get('invoice_id')
        notes = data.get('notes')

        if amount <= 0:
            return jsonify({'error': 'El monto debe ser mayor a 0'}), 400

        result = session.execute(text("""
            INSERT INTO payments (customer_id, invoice_id, amount, payment_method, reference, notes)
            VALUES (:cid, :inv_id, :amount, :method, :ref, :notes)
            RETURNING id_payment
        """), {
            'cid': customer_id, 'inv_id': invoice_id,
            'amount': amount, 'method': payment_method,
            'ref': reference, 'notes': notes
        })
        payment_id = result.scalar()

        # Update customer balance
        session.execute(text(
            "UPDATE customers SET balance = balance - :amount WHERE id_customer = :id"
        ), {'amount': amount, 'id': customer_id})

        # If applied to specific invoice, update its amount_paid and status
        if invoice_id:
            session.execute(text(
                "UPDATE invoices SET amount_paid = amount_paid + :amount WHERE id_invoice = :id"
            ), {'amount': amount, 'id': invoice_id})
            # Update invoice status
            session.execute(text("""
                UPDATE invoices SET status = CASE
                    WHEN amount_paid >= total THEN 'paid'
                    WHEN amount_paid > 0 THEN 'partial'
                    ELSE 'pending'
                END WHERE id_invoice = :id
            """), {'id': invoice_id})

        session.commit()
        return jsonify({'id': payment_id, 'message': 'Pago registrado'})
    except Exception as e:
        session.rollback()
        return jsonify({'error': str(e)}), 500
    finally:
        session.close()


@app.route('/api/pos/customers/<int:customer_id>/statement')
def api_pos_customer_statement(customer_id):
    session = Session()
    try:
        customer = session.execute(text(
            "SELECT * FROM customers WHERE id_customer = :id"
        ), {'id': customer_id}).mappings().first()
        if not customer:
            return jsonify({'error': 'Cliente no encontrado'}), 404

        invoices = session.execute(text("""
            SELECT id_invoice, folio, date_issued, total, amount_paid, status
            FROM invoices WHERE customer_id = :id AND status != 'cancelled'
            ORDER BY date_issued DESC LIMIT 100
        """), {'id': customer_id}).mappings().all()

        payments = session.execute(text("""
            SELECT p.id_payment, p.amount, p.payment_method, p.reference,
                   p.date_payment, p.notes, i.folio AS invoice_folio
            FROM payments p
            LEFT JOIN invoices i ON p.invoice_id = i.id_invoice
            WHERE p.customer_id = :id
            ORDER BY p.date_payment DESC LIMIT 100
        """), {'id': customer_id}).mappings().all()

        return jsonify({
            'customer': dict(customer),
            'invoices': [dict(i) for i in invoices],
            'payments': [dict(p) for p in payments]
        })
    finally:
        session.close()


@app.route('/api/pos/search-parts')
def api_pos_search_parts():
    """Search parts for the POS cart — returns OEM and aftermarket with prices."""
    session = Session()
    try:
        q = request.args.get('q', '')
        if len(q) < 2:
            return jsonify([])

        results = []

        # Search OEM parts
        oem = session.execute(text("""
            SELECT p.id_part, p.oem_part_number, p.name_part, p.name_es,
                   p.cost_usd, pg.name_part_group AS group_name,
                   'oem' AS part_type
            FROM parts p
            JOIN part_groups pg ON p.group_id = pg.id_part_group
            WHERE p.oem_part_number ILIKE :q OR p.name_part ILIKE :q
            ORDER BY p.oem_part_number LIMIT 20
        """), {'q': f'%{q}%'}).mappings().all()
        results.extend([dict(r) for r in oem])

        # Search aftermarket parts
        af = session.execute(text("""
            SELECT ap.id_aftermarket_parts AS id_part, ap.part_number AS oem_part_number,
                   ap.name_aftermarket_parts AS name_part, ap.name_es,
                   COALESCE(ap.cost_usd, ap.price_usd) AS cost_usd,
                   m.name_manufacture AS group_name,
                   'aftermarket' AS part_type
            FROM aftermarket_parts ap
            JOIN manufacturers m ON ap.manufacturer_id = m.id_manufacture
            WHERE ap.part_number ILIKE :q OR ap.name_aftermarket_parts ILIKE :q
            ORDER BY ap.part_number LIMIT 20
        """), {'q': f'%{q}%'}).mappings().all()
        results.extend([dict(r) for r in af])

        return jsonify(results)
    finally:
        session.close()

Step 2: Commit

git add dashboard/server.py && git commit -m "feat(pos): add payment and search endpoints"

Task 5: Frontend — POS page (pos.html + pos.css + pos.js)

Files:

  • Create: /home/Autopartes/dashboard/pos.html
  • Create: /home/Autopartes/dashboard/pos.css
  • Create: /home/Autopartes/dashboard/pos.js

Step 1: Create pos.html

HTML page with:

  • Customer selector (search + create new)
  • Part search bar (searches OEM + aftermarket)
  • Cart table (description, qty, cost, margin%, price, total)
  • Totals section (subtotal, IVA 16%, total)
  • "Facturar" button

Step 2: Create pos.css

Styles for the POS layout: 2-column (left=search+cart, right=customer info + totals).

Step 3: Create pos.js

JavaScript logic:

  • Customer search and selection
  • Part search → add to cart
  • Editable margin per line
  • Auto-calculate prices: unit_price = cost * (1 + margin/100)
  • Totals: subtotal, IVA, total
  • Facturar → POST /api/pos/invoices

Step 4: Commit

git add dashboard/pos.html dashboard/pos.css dashboard/pos.js
git commit -m "feat(pos): add point of sale frontend"

Task 6: Frontend — Cuentas page (cuentas.html + cuentas.css + cuentas.js)

Files:

  • Create: /home/Autopartes/dashboard/cuentas.html
  • Create: /home/Autopartes/dashboard/cuentas.css
  • Create: /home/Autopartes/dashboard/cuentas.js

Step 1: Create cuentas.html

HTML page with:

  • Customer list with balances
  • Customer detail: info card, pending invoices, payment history
  • Payment form: amount, method, reference, apply to invoice
  • Create/edit customer modal

Step 2: Create cuentas.js

JavaScript logic:

  • Load customers with balances
  • Customer detail view with statement
  • Register payment → POST /api/pos/payments
  • Create/edit customer form

Step 3: Commit

git add dashboard/cuentas.html dashboard/cuentas.css dashboard/cuentas.js
git commit -m "feat(pos): add accounts receivable frontend"

Task 7: Navigation + final integration

Files:

  • Modify: /home/Autopartes/dashboard/nav.js

Step 1: Add POS and Cuentas links to nav

Add to the navLinks array and isActive function:

// isActive:
if ((h === '/pos') && (p === '/pos')) return true;
if ((h === '/cuentas') && (p === '/cuentas')) return true;

// navLinks:
{ label: 'POS', href: '/pos' },
{ label: 'Cuentas', href: '/cuentas' },

Step 2: Test full flow

# Start server
nohup python3 /home/Autopartes/dashboard/server.py > /tmp/nexus-server.log 2>&1 &
sleep 2

# Test customer creation
curl -s -X POST http://localhost:5000/api/pos/customers \
  -H "Content-Type: application/json" \
  -d '{"name":"Taller Prueba","rfc":"TAL123456XX0","credit_limit":50000,"payment_terms":30}'

# Test page loads
curl -s -o /dev/null -w "%{http_code}" http://localhost:5000/pos
curl -s -o /dev/null -w "%{http_code}" http://localhost:5000/cuentas

Step 3: Final commit

git add -A && git commit -m "feat(pos): complete POS and accounts system"