feat: cashier/counter reports, service-order & remission flows, Rached migration utils
Some checks failed
CI / lint-and-test (3.11) (push) Has been cancelled
CI / lint-and-test (3.13) (push) Has been cancelled

- Add "Mis cortes de caja" report for cashiers/counters with sales detail.
- Cash register history scoped to own cuts for non-admin roles; new /register/<id>/sales endpoint.
- Remove dashboard from cashier menu; add Reports to cashier/counter.
- Service orders: assign mechanic, budget field, invoice flag, counter/cashier can add items/remissions, convert to remission.
- Remission notes module (UI, CSS, courier, counter remissions).
- Customer hard-delete and vehicle/customer linkage in workshop.
- POS: always show search results, compact payment grid, credit validation, tier pricing (5%/10%), ticket with customer/folio.
- Inventory: CSV template with sku_secondary, alias import.
- Rached migration scripts and DB migrations.
- Version-bump cached JS/CSS query strings.

Excludes local Rached session tokens/captures (rached_*.json / rached_*.txt).
This commit is contained in:
2026-07-02 12:51:56 +00:00
parent 483498cfcc
commit f42910f4f6
71 changed files with 5388 additions and 626 deletions

View File

@@ -16,7 +16,7 @@
<link rel="shortcut icon" type="image/png" href="/pos/static/pwa/icon-192.png" />
<script src="/pos/static/js/native-bridge.js" defer></script>
<link rel="stylesheet" href="/pos/static/css/pos.css?v=33"></head>
<link rel="stylesheet" href="/pos/static/css/pos.css?v=34"></head>
<body class="pos-shell" id="appBody">
@@ -123,7 +123,6 @@
</div>
</div>
<button class="btn-change-customer" onclick="POS.clearCustomer()" aria-label="Cambiar cliente">Cambiar</button>
<button class="btn-change-customer" onclick="POS.creditSale()" aria-label="Venta a credito" style="margin-left:4px;background:var(--color-primary);color:#fff;border-color:var(--color-primary);">Crédito</button>
</div>
</div>
@@ -199,15 +198,29 @@
</div>
</div>
<!-- Courier selector for counter remission notes -->
<div class="form-field" id="courierSelectField" style="display:none; margin-bottom: 12px;">
<label class="form-label" for="remissionCourier">Repartidor</label>
<select class="form-input" id="remissionCourier">
<option value="">-- Sin repartidor --</option>
</select>
</div>
<!-- COBRAR Button -->
<button class="btn-cobrar" id="btnCobrar" onclick="POS.checkout()" aria-label="Procesar cobro">
<span>COBRAR</span>
</button>
<!-- Counter remission button (shown for counter role when feature enabled) -->
<button class="btn-cobrar" id="btnRemission" onclick="POS.createRemissionNote()" aria-label="Generar nota de remision" style="display:none;background:var(--color-secondary);">
<span>NOTA DE REMISIÓN</span>
</button>
<!-- Secondary Actions -->
<div class="secondary-actions" role="toolbar" aria-label="Acciones secundarias">
<button class="btn-secondary-action" onclick="POS.modifyPrice()" title="Modificar precio">Mod.Precio</button>
<button class="btn-secondary-action" onclick="POS.saveQuotation()" title="Cotizacion (F4)">Cotizar</button>
<button class="btn-secondary-action" id="btnPayRemission" onclick="POS.openPayRemissionModal()" title="Cobrar nota de remision" style="display:none;">Cobrar Nota</button>
<button class="btn-secondary-action" onclick="POS.createLayaway()" title="Apartado (requiere cliente)">Apartado</button>
<button class="btn-secondary-action" onclick="POS.createServiceOrder()" title="Orden de servicio (F7)">Orden Taller</button>
<button class="btn-secondary-action" onclick="POS.showLastSale()" title="Ultima venta (F5)">Ult.Venta</button>
@@ -295,6 +308,15 @@
<button class="pago-tab" data-method="mixto" onclick="POS.selectPaymentMethod('mixto', this)">
Mixto
</button>
<button class="pago-tab" data-method="credito" onclick="POS.selectPaymentMethod('credito', this)">
Crédito
</button>
<button class="pago-tab" data-method="cheque" onclick="POS.selectPaymentMethod('cheque', this)">
Cheque
</button>
<button class="pago-tab" data-method="pendiente" onclick="POS.selectPaymentMethod('pendiente', this)">
Pendiente
</button>
</div>
<!-- TAB: Efectivo -->
@@ -358,6 +380,35 @@
</div>
</div>
<!-- TAB: Crédito -->
<div class="tab-content" id="creditPayment">
<div class="form-group">
<label class="form-label">Venta a crédito</label>
<p style="color:var(--color-text-muted);font-size:var(--text-body-sm);">Se registrará como venta a crédito para el cliente seleccionado y se agregará a su cuenta.</p>
</div>
</div>
<!-- TAB: Cheque -->
<div class="tab-content" id="chequePayment">
<div class="form-group">
<label class="form-label">Monto</label>
<input type="text" class="form-input form-input-lg" id="chequeAmount" readonly />
</div>
<div class="form-group">
<label class="form-label">No. de cheque / referencia</label>
<input type="text" class="form-input" id="chequeRef" placeholder="No. de cheque" />
</div>
<div class="form-hint">Verificar que el cheque sea válido antes de confirmar</div>
</div>
<!-- TAB: Pendiente -->
<div class="tab-content" id="pendingPayment">
<div class="form-group">
<label class="form-label">Pago pendiente</label>
<p style="color:var(--color-text-muted);font-size:var(--text-body-sm);">La venta quedará pendiente de pago. Podrá cobrarse más tarde desde el listado de ventas o notas de remisión.</p>
</div>
</div>
<!-- CFDI Checkbox -->
<div class="cfdi-check">
<input type="checkbox" id="cfdiCheck" />
@@ -373,6 +424,68 @@
</div>
</div>
<!-- ================================================================
PAY REMISSION NOTE MODAL
================================================================ -->
<div class="modal-overlay" id="payRemissionModal">
<div class="modal-pago">
<div class="modal-header">
<h3>Cobrar Nota de Remisión</h3>
<button class="modal-close" onclick="POS.closePayRemissionModal()">&#x2715;</button>
</div>
<div class="form-row" style="padding: 16px; gap: 8px;">
<input class="form-input" type="number" id="payRemissionFolio" placeholder="Folio de la nota (NR-XXXX)" style="flex:1;" />
<button class="btn btn-primary" onclick="POS.searchRemissionToPay()">Buscar</button>
</div>
<div id="payRemissionDetail" style="padding: 0 16px 16px; max-height: 220px; overflow-y: auto;"></div>
<div id="payRemissionActions" style="display:none; padding: 0 16px 16px;">
<div class="form-row" style="gap: 8px; margin-bottom: 8px;">
<select class="form-input" id="payRemissionMethod" onchange="POS.updatePayRemissionMethod()">
<option value="efectivo">Efectivo</option>
<option value="transferencia">Transferencia</option>
<option value="tarjeta">Tarjeta</option>
<option value="mixto">Mixto</option>
</select>
</div>
<div id="payRemissionCash" class="form-row" style="gap: 8px; margin-bottom: 8px;">
<input class="form-input" type="number" id="payRemissionReceived" placeholder="Recibido" step="0.01" />
</div>
<div id="payRemissionRef" class="form-row" style="gap: 8px; margin-bottom: 8px; display:none;">
<input class="form-input" type="text" id="payRemissionReference" placeholder="Referencia" />
</div>
<div id="payRemissionMixed" class="form-row" style="gap: 8px; margin-bottom: 8px; display:none; flex-direction: column;">
<div class="mixed-row" style="display:flex; gap:8px; width:100%;">
<select class="form-input" style="flex:1;">
<option value="efectivo">Efectivo</option>
<option value="transferencia">Transferencia</option>
<option value="tarjeta">Tarjeta</option>
</select>
<input class="form-input mixed-amount" type="number" placeholder="Monto" step="0.01" style="flex:1;" />
<input class="form-input" type="text" placeholder="Referencia" style="flex:1;" />
</div>
<div class="mixed-row" style="display:flex; gap:8px; width:100%;">
<select class="form-input" style="flex:1;">
<option value="efectivo">Efectivo</option>
<option value="transferencia">Transferencia</option>
<option value="tarjeta">Tarjeta</option>
</select>
<input class="form-input mixed-amount" type="number" placeholder="Monto" step="0.01" style="flex:1;" />
<input class="form-input" type="text" placeholder="Referencia" style="flex:1;" />
</div>
</div>
<div class="modal-footer" style="padding:0;">
<button class="btn btn-ghost" onclick="POS.closePayRemissionModal()">Cancelar</button>
<button class="btn btn-primary" id="btnConfirmPayRemission" onclick="POS.confirmPayRemission()">Confirmar Pago</button>
</div>
</div>
<div id="payRemissionResult" style="padding: 0 16px 16px;"></div>
</div>
</div>
<!-- ================================================================
CANCEL SALE CONFIRMATION MODAL
================================================================ -->
@@ -613,14 +726,14 @@
<!-- ================================================================
JAVASCRIPT
================================================================ -->
<script src="/pos/static/js/i18n.js?v=36" defer></script>
<script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/kiosk.js" defer></script>
<script src="/pos/static/js/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/app-init.js?v=2" defer></script>
<script src="/pos/static/js/app-init.js?v=5" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" defer></script>
<script src="/pos/static/js/push.js" defer></script>
<script src="/pos/static/js/printer.js" defer></script>
<script src="/pos/static/js/pos.js?v=33" defer></script>
<script src="/pos/static/js/pos.js?v=41" defer></script>
<script>
// Cancel sale button wiring