feat: add companion2 support, fix UI rendering, and update test data generator

This commit is contained in:
2026-06-22 02:31:08 -04:00
parent 81251fb869
commit ac0dd65efa
10 changed files with 268 additions and 27 deletions

View File

@@ -246,6 +246,7 @@ def init_db():
worker_id INTEGER NOT NULL, worker_id INTEGER NOT NULL,
worker_comision BOOLEAN DEFAULT 1, worker_comision BOOLEAN DEFAULT 1,
companion_id INTEGER, companion_id INTEGER,
companion2_id INTEGER,
modulo_id INTEGER NOT NULL, modulo_id INTEGER NOT NULL,
fecha DATE NOT NULL, fecha DATE NOT NULL,
hora_entrada TEXT NOT NULL, hora_entrada TEXT NOT NULL,
@@ -253,6 +254,7 @@ def init_db():
companion_hora_entrada TEXT, companion_hora_entrada TEXT,
companion_hora_salida TEXT, companion_hora_salida TEXT,
companion_comision BOOLEAN DEFAULT 0, companion_comision BOOLEAN DEFAULT 0,
companion2_comision BOOLEAN DEFAULT 0,
venta_debito INTEGER DEFAULT 0, venta_debito INTEGER DEFAULT 0,
venta_credito INTEGER DEFAULT 0, venta_credito INTEGER DEFAULT 0,
venta_mp INTEGER DEFAULT 0, venta_mp INTEGER DEFAULT 0,
@@ -265,6 +267,7 @@ def init_db():
observaciones TEXT, observaciones TEXT,
FOREIGN KEY (worker_id) REFERENCES workers(id), FOREIGN KEY (worker_id) REFERENCES workers(id),
FOREIGN KEY (companion_id) REFERENCES workers(id), FOREIGN KEY (companion_id) REFERENCES workers(id),
FOREIGN KEY (companion2_id) REFERENCES workers(id),
FOREIGN KEY (modulo_id) REFERENCES modulos(id))''') FOREIGN KEY (modulo_id) REFERENCES modulos(id))''')
c.execute('''CREATE TABLE IF NOT EXISTS rendicion_items c.execute('''CREATE TABLE IF NOT EXISTS rendicion_items
(id INTEGER PRIMARY KEY AUTOINCREMENT, (id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -283,6 +286,13 @@ def init_db():
except sqlite3.OperationalError: except sqlite3.OperationalError:
pass # column already exists pass # column already exists
# Migrate: add companion2 columns
for col in ['companion2_id', 'companion2_comision']:
try:
c.execute(f"ALTER TABLE rendiciones ADD COLUMN {col}")
except sqlite3.OperationalError:
pass
c.execute("SELECT id FROM workers WHERE is_admin = 1") c.execute("SELECT id FROM workers WHERE is_admin = 1")
if not c.fetchone(): if not c.fetchone():
admin_pass = generate_password_hash("admin123") admin_pass = generate_password_hash("admin123")

View File

@@ -122,13 +122,29 @@ def generar_historico_definitivo(dias_atras=180):
companion_id = None companion_id = None
comp_in, comp_out = None, None comp_in, comp_out = None, None
companion_comision = 0 companion_comision = 0
companion2_id = None
companion2_comision = 0
if random.random() < 0.70: if random.random() < 0.70:
posibles_comp = [w for w in todos_los_trabajadores if w != worker_id] posibles_comp = [w for w in workers_modulo if w != worker_id]
if posibles_comp: if posibles_comp:
companion_id = random.choice(posibles_comp) companion_id = random.choice(posibles_comp)
comp_in, comp_out = hora_entrada, hora_salida comp_in, comp_out = hora_entrada, hora_salida
comp_tipo = workers_tipo.get(companion_id, "Part Time") comp_tipo = workers_tipo.get(companion_id, "Part Time")
companion_comision = 1 if comp_tipo == "Full Time" else random.choice([0, 1]) companion_comision = 1 if comp_tipo == "Full Time" else random.choice([0, 1])
# Acompañante 2 (25% probability if companion 1 is present)
if random.random() < 0.25:
posibles_comp2 = [w for w in posibles_comp if w != companion_id]
if posibles_comp2:
companion2_id = random.choice(posibles_comp2)
comp2_tipo = workers_tipo.get(companion2_id, "Part Time")
companion2_comision = 1 if comp2_tipo == "Full Time" else random.choice([0, 1])
# If there is no companion, comision should be disabled (0)
if companion_id is None:
companion_comision = 0
if companion2_id is None:
companion2_comision = 0
num_prods = random.randint(1, 5) num_prods = random.randint(1, 5)
prods_elegidos = random.sample(productos, min(num_prods, len(productos))) prods_elegidos = random.sample(productos, min(num_prods, len(productos)))
@@ -171,16 +187,16 @@ def generar_historico_definitivo(dias_atras=180):
c.execute(''' c.execute('''
INSERT INTO rendiciones INSERT INTO rendiciones
(worker_id, worker_comision, companion_id, modulo_id, fecha, (worker_id, worker_comision, companion_id, companion2_id, modulo_id, fecha,
hora_entrada, hora_salida, companion_hora_entrada, companion_hora_salida, hora_entrada, hora_salida, companion_hora_entrada, companion_hora_salida,
companion_comision, companion_comision, companion2_comision,
venta_debito, venta_credito, venta_mp, venta_efectivo, venta_debito, venta_credito, venta_mp, venta_efectivo,
boletas_debito, boletas_credito, boletas_mp, boletas_efectivo, boletas_debito, boletas_credito, boletas_mp, boletas_efectivo,
gastos, observaciones) gastos, observaciones)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (worker_id, worker_comision, companion_id, modulo_id, fecha_str, ''', (worker_id, worker_comision, companion_id, companion2_id, modulo_id, fecha_str,
hora_entrada, hora_salida, comp_in, comp_out, hora_entrada, hora_salida, comp_in, comp_out,
companion_comision, companion_comision, companion2_comision,
debito, credito, mp, efectivo, debito, credito, mp, efectivo,
b_debito, b_credito, b_mp, b_efectivo, b_debito, b_credito, b_mp, b_efectivo,
gastos, tipo_registro)) gastos, tipo_registro))

View File

@@ -69,6 +69,7 @@ class Rendicion(db.Model):
worker_id = db.Column(db.Integer, db.ForeignKey('workers.id'), nullable=False) worker_id = db.Column(db.Integer, db.ForeignKey('workers.id'), nullable=False)
worker_comision = db.Column(db.Boolean, default=True) worker_comision = db.Column(db.Boolean, default=True)
companion_id = db.Column(db.Integer, db.ForeignKey('workers.id')) companion_id = db.Column(db.Integer, db.ForeignKey('workers.id'))
companion2_id = db.Column(db.Integer, db.ForeignKey('workers.id'))
modulo_id = db.Column(db.Integer, db.ForeignKey('modulos.id'), nullable=False) modulo_id = db.Column(db.Integer, db.ForeignKey('modulos.id'), nullable=False)
fecha = db.Column(db.Date, nullable=False) fecha = db.Column(db.Date, nullable=False)
hora_entrada = db.Column(db.String, nullable=False) hora_entrada = db.Column(db.String, nullable=False)
@@ -76,6 +77,7 @@ class Rendicion(db.Model):
companion_hora_entrada = db.Column(db.String) companion_hora_entrada = db.Column(db.String)
companion_hora_salida = db.Column(db.String) companion_hora_salida = db.Column(db.String)
companion_comision = db.Column(db.Boolean, default=False) companion_comision = db.Column(db.Boolean, default=False)
companion2_comision = db.Column(db.Boolean, default=False)
venta_debito = db.Column(db.Integer, default=0) venta_debito = db.Column(db.Integer, default=0)
venta_credito = db.Column(db.Integer, default=0) venta_credito = db.Column(db.Integer, default=0)
venta_mp = db.Column(db.Integer, default=0) venta_mp = db.Column(db.Integer, default=0)

View File

@@ -2,3 +2,4 @@ Flask==3.1.3
Flask-SQLAlchemy==3.1.1 Flask-SQLAlchemy==3.1.1
Werkzeug==3.1.6 Werkzeug==3.1.6
SQLAlchemy==2.0.45 SQLAlchemy==2.0.45
openpyxl==3.1.5

View File

@@ -1,4 +1,4 @@
from flask import Blueprint, render_template, request, redirect, url_for, flash, session, jsonify from flask import Blueprint, render_template, request, redirect, url_for, flash, session, jsonify, send_file
from werkzeug.security import generate_password_hash from werkzeug.security import generate_password_hash
from sqlalchemy import func, and_ from sqlalchemy import func, and_
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
@@ -489,8 +489,18 @@ def edit_rendicion(id):
if companion_id and worker_id == companion_id: if companion_id and worker_id == companion_id:
flash("Error: No puedes asignarte a ti mismo como acompañante.", "danger") flash("Error: No puedes asignarte a ti mismo como acompañante.", "danger")
return redirect(url_for('admin.admin_rendiciones')) return redirect(url_for('admin.admin_rendiciones'))
companion2_id = request.form.get('companion2_id') or None
if companion2_id and worker_id == companion2_id:
flash("Error: No puedes asignarte a ti mismo como acompañante 2.", "danger")
return redirect(url_for('admin.admin_rendiciones'))
worker_comision = 1 if request.form.get('worker_comision') else 0 worker_comision = 1 if request.form.get('worker_comision') else 0
companion_comision = 1 if request.form.get('companion_comision') else 0 companion_comision = 1 if request.form.get('companion_comision') else 0
companion2_comision = 1 if request.form.get('companion2_comision') else 0
if not companion_id:
companion_comision = 0
if not companion2_id:
companion2_comision = 0
def clean_money(val): def clean_money(val):
if not val: if not val:
@@ -527,8 +537,10 @@ def edit_rendicion(id):
rendicion.worker_id = int(worker_id) rendicion.worker_id = int(worker_id)
rendicion.modulo_id = int(modulo_id) rendicion.modulo_id = int(modulo_id)
rendicion.companion_id = int(companion_id) if companion_id else None rendicion.companion_id = int(companion_id) if companion_id else None
rendicion.companion2_id = int(companion2_id) if companion2_id else None
rendicion.worker_comision = bool(worker_comision) rendicion.worker_comision = bool(worker_comision)
rendicion.companion_comision = bool(companion_comision) rendicion.companion_comision = bool(companion_comision)
rendicion.companion2_comision = bool(companion2_comision)
rendicion.venta_debito = debito rendicion.venta_debito = debito
rendicion.venta_credito = credito rendicion.venta_credito = credito
rendicion.venta_mp = mp rendicion.venta_mp = mp
@@ -653,3 +665,129 @@ def report_modulo_calculo_iva(modulo_id):
workers_list=workers_list, worker_actual=worker_id, workers_list=workers_list, worker_actual=worker_id,
fecha_inicio=fecha_inicio, fecha_fin=fecha_fin, fecha_inicio=fecha_inicio, fecha_fin=fecha_fin,
anios_disponibles=anios_list) anios_disponibles=anios_list)
@admin_bp.route('/reportes/modulo/<int:modulo_id>/exportar_excel')
@admin_required
def report_modulo_exportar_excel(modulo_id):
fecha_inicio, fecha_fin, worker_id = get_report_params()
data = report_service.get_modulo_periodo_data(modulo_id, fecha_inicio, fecha_fin, worker_id)
mod_name, _, _ = report_service.get_modulo_workers_and_anios(modulo_id)
import io
import openpyxl
from openpyxl.styles import Font, Alignment, PatternFill, Border, Side
from openpyxl.utils import get_column_letter
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Detalle Ventas"
thin = Side(style='thin')
border = Border(left=thin, right=thin, top=thin, bottom=thin)
center = Alignment(horizontal='center', vertical='center')
# ── column colors matching web table ──
col_colors = {
2: '198754', # Venta Total → text-success green
3: '0DCAF0', # Comisión → text-info cyan
4: 'DC3545', # Gastos → text-danger red
5: '6C757D', # Crédito → text-muted gray
6: '6C757D', # Débito → text-muted gray
7: '6C757D', # Mercado Pago → text-muted gray
8: '6C757D', # Efectivo/Dep. → text-muted gray
9: 'e5904d', # Red. Crédito → custom orange
10: 'e5904d', # Red. Débito → custom orange
11: 'e5904d', # Red. MP → custom orange
12: '20c997', # REDELCOM Neto → teal
13: 'FFC107', # Efectivo - Gastos → text-warning
14: '0D6EFD', # Venta Total Neto → text-primary blue
}
hdr_fill = PatternFill(start_color="2B303A", end_color="2B303A", fill_type="solid")
ws.merge_cells('A1:O1')
ws['A1'] = f"Resumen Financiero — {mod_name} ({fecha_inicio} a {fecha_fin})"
ws['A1'].font = Font(bold=True, size=14)
headers = ['Día', 'Venta Total', 'Comisión', 'Gastos',
'Crédito', 'Débito', 'Mercado Pago', 'Efectivo/Dep.',
'Red. Crédito', 'Red. Débito', 'Red. MP',
'REDELCOM Neto', 'Efectivo - Gastos', 'Venta Total Neto']
for col, h in enumerate(headers, 1):
cell = ws.cell(row=3, column=col, value=h)
cell.fill = hdr_fill
cell.alignment = center
cell.border = border
font_color = col_colors.get(col, 'FFFFFF')
cell.font = Font(bold=True, color=font_color, size=11)
for row_idx, dia in enumerate(data['dias_en_periodo'], 4):
d = data['data_por_dia'][dia]
vals = [
dia,
d['venta_total'],
d['comision'],
d['gastos'],
d['credito'],
d['debito'],
d['mp'],
d['efectivo'],
d['credito'] * 0.97620,
d['debito'] * 0.98453,
d['mp'] * 0.98691,
d['credito'] * 0.97620 + d['debito'] * 0.98453 + d['mp'] * 0.98691,
d['efectivo'] - d['gastos'],
d['credito'] * 0.97620 + d['debito'] * 0.98453 + d['mp'] * 0.98691 + d['efectivo'] - d['gastos'],
]
for col, v in enumerate(vals, 1):
cell = ws.cell(row=row_idx, column=col, value=v)
cell.border = border
if col == 1:
cell.alignment = center
else:
cell.number_format = '#,##0'
if col in col_colors:
cell.font = Font(color=col_colors[col])
total_row = 4 + len(data['dias_en_periodo'])
totals = data['totales_mes']
total_vals = [
'TOTAL',
totals['venta_total'],
totals['comision'],
totals['gastos'],
totals['credito'],
totals['debito'],
totals['mp'],
totals['efectivo'],
totals['credito'] * 0.97620,
totals['debito'] * 0.98453,
totals['mp'] * 0.98691,
totals['credito'] * 0.97620 + totals['debito'] * 0.98453 + totals['mp'] * 0.98691,
totals['efectivo'] - totals['gastos'],
totals['credito'] * 0.97620 + totals['debito'] * 0.98453 + totals['mp'] * 0.98691 + totals['efectivo'] - totals['gastos'],
]
total_fill = PatternFill(start_color="2B303A", end_color="2B303A", fill_type="solid")
for col, v in enumerate(total_vals, 1):
cell = ws.cell(row=total_row, column=col, value=v)
cell.fill = total_fill
cell.border = border
if col == 1:
cell.alignment = center
cell.font = Font(bold=True, color="FFFFFF", size=11)
else:
cell.number_format = '#,##0'
font_color = col_colors.get(col, 'FFFFFF')
cell.font = Font(bold=True, color=font_color, size=11)
for col in range(1, 16):
ws.column_dimensions[get_column_letter(col)].width = 16
ws.column_dimensions['A'].width = 8
output = io.BytesIO()
wb.save(output)
output.seek(0)
filename = f"reporte_{mod_name}_{fecha_inicio}_{fecha_fin}.xlsx".replace(' ', '_')
return send_file(output, as_attachment=True, download_name=filename,
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')

View File

@@ -31,6 +31,7 @@ def get_filtered_rendiciones(fecha_inicio, fecha_fin, zona_id, modulo_id):
fin = datetime.strptime(fecha_fin, '%Y-%m-%d').date() fin = datetime.strptime(fecha_fin, '%Y-%m-%d').date()
Companion = aliased(Worker) Companion = aliased(Worker)
Companion2 = aliased(Worker)
filters = [ filters = [
Rendicion.fecha >= inicio, Rendicion.fecha >= inicio,
@@ -52,11 +53,14 @@ def get_filtered_rendiciones(fecha_inicio, fecha_fin, zona_id, modulo_id):
Companion.name.label('companion_name'), Companion.name.label('companion_name'),
Rendicion.worker_id, Rendicion.companion_id, Rendicion.modulo_id, Rendicion.worker_id, Rendicion.companion_id, Rendicion.modulo_id,
Rendicion.worker_comision, Rendicion.companion_comision, Rendicion.worker_comision, Rendicion.companion_comision,
Companion2.name.label('companion2_name'),
Rendicion.companion2_id, Rendicion.companion2_comision,
Rendicion.boletas_debito, Rendicion.boletas_credito, Rendicion.boletas_debito, Rendicion.boletas_credito,
Rendicion.boletas_mp, Rendicion.boletas_efectivo, Rendicion.boletas_mp, Rendicion.boletas_efectivo,
).join(Worker, Rendicion.worker_id == Worker.id ).join(Worker, Rendicion.worker_id == Worker.id
).join(Modulo, Rendicion.modulo_id == Modulo.id ).join(Modulo, Rendicion.modulo_id == Modulo.id
).outerjoin(Companion, Rendicion.companion_id == Companion.id ).outerjoin(Companion, Rendicion.companion_id == Companion.id
).outerjoin(Companion2, Rendicion.companion2_id == Companion2.id
).filter(*filters ).filter(*filters
).order_by(Rendicion.fecha.desc(), Rendicion.id.desc()).all() ).order_by(Rendicion.fecha.desc(), Rendicion.id.desc()).all()

View File

@@ -23,6 +23,13 @@ document.addEventListener("DOMContentLoaded", function () {
window.updateComisionToggle(select, `cc_${id}`); window.updateComisionToggle(select, `cc_${id}`);
}; };
window.toggleComp2Div = function (id, select) {
const compDiv = document.getElementById(`comp2_com_div_${id}`);
if (compDiv) compDiv.style.display = select.value ? 'flex' : 'none';
window.updateBadge(select, `badge_comp2_${id}`);
window.updateComisionToggle(select, `cc2_${id}`);
};
window.updateComisionToggle = function (selectElement, toggleId) { window.updateComisionToggle = function (selectElement, toggleId) {
const option = selectElement.options[selectElement.selectedIndex]; const option = selectElement.options[selectElement.selectedIndex];
const tipoJornada = option ? option.getAttribute('data-tipo') : null; const tipoJornada = option ? option.getAttribute('data-tipo') : null;
@@ -99,6 +106,9 @@ document.addEventListener("DOMContentLoaded", function () {
const compSelect = this.querySelector('select[name="companion_id"]'); const compSelect = this.querySelector('select[name="companion_id"]');
if (compSelect && compSelect.value) window.updateBadge(compSelect, `badge_comp_${rid}`); if (compSelect && compSelect.value) window.updateBadge(compSelect, `badge_comp_${rid}`);
const comp2Select = this.querySelector('select[name="companion2_id"]');
if (comp2Select && comp2Select.value) window.updateBadge(comp2Select, `badge_comp2_${rid}`);
}); });
modal.addEventListener('hidden.bs.modal', function () { modal.addEventListener('hidden.bs.modal', function () {

View File

@@ -80,8 +80,8 @@
<button type="button" class="btn btn-sm btn-danger" data-bs-toggle="modal" data-bs-target="#deleteRendicion{{ r[0] }}" title="Eliminar Rendición"><i class="bi bi-trash"></i></button> <button type="button" class="btn btn-sm btn-danger" data-bs-toggle="modal" data-bs-target="#deleteRendicion{{ r[0] }}" title="Eliminar Rendición"><i class="bi bi-trash"></i></button>
</div> </div>
{{ rendicion_detail_modal(r, r[20], r[21], r[22]) }} {{ rendicion_detail_modal(r, r[23], r[24], r[25]) }}
{{ edit_rendicion_modal(r, r[20], workers, modulos) }} {{ edit_rendicion_modal(r, r[23], workers, modulos) }}
{{ confirm_modal( {{ confirm_modal(
id='deleteRendicion' ~ r[0], id='deleteRendicion' ~ r[0],

View File

@@ -42,10 +42,10 @@
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<div class="card bg-warning text-dark shadow-sm h-100 border-0"> <div class="card bg-primary text-white shadow-sm h-100 border-0">
<div class="card-body"> <div class="card-body">
<div class="text-uppercase small mb-1 opacity-75">Días Trabajados</div> <div class="text-uppercase small mb-1 opacity-75">Venta Total Neto</div>
<h3 class="card-title mb-0">{{ dias_activos }} <span class="fs-6 fw-normal">/ 31</span></h3> <h3 class="card-title mb-0">${{ "{:,.0f}".format(totales_mes.credito * 0.97620 + totales_mes.debito * 0.98453 + totales_mes.mp * 0.98691 + totales_mes.efectivo - totales_mes.gastos).replace(',', '.') }}</h3>
</div> </div>
</div> </div>
</div> </div>
@@ -63,9 +63,9 @@
<div class="card-header border-0 bg-transparent d-flex justify-content-between align-items-center pb-0"> <div class="card-header border-0 bg-transparent d-flex justify-content-between align-items-center pb-0">
<span class="fw-bold text-muted text-uppercase"><i class="bi bi-calendar3 me-1"></i> Desglose Diario</span> <span class="fw-bold text-muted text-uppercase"><i class="bi bi-calendar3 me-1"></i> Desglose Diario</span>
<button class="btn btn-success btn-sm shadow-sm" onclick="alert('Próximamente: Esto descargará un Excel con el detalle de todos los productos vendidos por día.')"> <a class="btn btn-success btn-sm shadow-sm" href="{{ url_for('admin.report_modulo_exportar_excel', modulo_id=modulo_id, fecha_inicio=fecha_inicio, fecha_fin=fecha_fin, worker_id=worker_actual) }}">
<i class="bi bi-file-earmark-excel-fill me-1"></i> Exportar Detalle Completo (.xlsx) <i class="bi bi-file-earmark-excel-fill me-1"></i> Exportar Detalle Completo (.xlsx)
</button> </a>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="table-responsive"> <div class="table-responsive">
@@ -77,12 +77,20 @@
<th class="py-2 text-info" rowspan="2">COMISIÓN</th> <th class="py-2 text-info" rowspan="2">COMISIÓN</th>
<th class="py-2 text-danger" rowspan="2">GASTOS</th> <th class="py-2 text-danger" rowspan="2">GASTOS</th>
<th class="py-1 border-bottom-0" colspan="4">MEDIOS DE PAGO</th> <th class="py-1 border-bottom-0" colspan="4">MEDIOS DE PAGO</th>
<th class="py-1 border-bottom-0" colspan="3">COMISIÓN REDELCOM</th>
<th class="py-1 border-bottom-0" colspan="3">TOTALES NETOS</th>
</tr> </tr>
<tr> <tr>
<th class="py-1 text-muted">Crédito</th> <th class="py-1 text-muted">Crédito</th>
<th class="py-1 text-muted">Débito</th> <th class="py-1 text-muted">Débito</th>
<th class="py-1 text-muted">Mercado Pago</th> <th class="py-1 text-muted">Mercado Pago</th>
<th class="py-1 text-muted">Efectivo/Dep.</th> <th class="py-1 text-muted">Efectivo/Dep.</th>
<th class="py-1" style="color:#e5904d">Crédito (-2.38%)</th>
<th class="py-1" style="color:#e5904d">Débito (-1.547%)</th>
<th class="py-1" style="color:#e5904d">MP (-1.309%)</th>
<th class="py-1" style="color:#20c997">REDELCOM Neto</th>
<th class="py-1 text-warning">Efectivo - Gastos</th>
<th class="py-1 text-primary fw-bold">Venta Total Neto</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -105,6 +113,17 @@
<td class="align-middle numeric-cell text-muted">{{ ("$" ~ "{:,.0f}".format(d.debito).replace(',', '.')) if d.debito > 0 else "-" }}</td> <td class="align-middle numeric-cell text-muted">{{ ("$" ~ "{:,.0f}".format(d.debito).replace(',', '.')) if d.debito > 0 else "-" }}</td>
<td class="align-middle numeric-cell text-muted">{{ ("$" ~ "{:,.0f}".format(d.mp).replace(',', '.')) if d.mp > 0 else "-" }}</td> <td class="align-middle numeric-cell text-muted">{{ ("$" ~ "{:,.0f}".format(d.mp).replace(',', '.')) if d.mp > 0 else "-" }}</td>
<td class="align-middle numeric-cell text-muted">{{ ("$" ~ "{:,.0f}".format(d.efectivo).replace(',', '.')) if d.efectivo > 0 else "-" }}</td> <td class="align-middle numeric-cell text-muted">{{ ("$" ~ "{:,.0f}".format(d.efectivo).replace(',', '.')) if d.efectivo > 0 else "-" }}</td>
{% set red_credito = d.credito * 0.97620 %}
{% set red_debito = d.debito * 0.98453 %}
{% set red_mp = d.mp * 0.98691 %}
{% set redelcom_neto = red_credito + red_debito + red_mp %}
{% set efectivo_menos_gastos = d.efectivo - d.gastos %}
<td class="align-middle numeric-cell" style="color:#e5904d">{{ ("$" ~ "{:,.0f}".format(red_credito).replace(',', '.')) if red_credito > 0 else "-" }}</td>
<td class="align-middle numeric-cell" style="color:#e5904d">{{ ("$" ~ "{:,.0f}".format(red_debito).replace(',', '.')) if red_debito > 0 else "-" }}</td>
<td class="align-middle numeric-cell" style="color:#e5904d">{{ ("$" ~ "{:,.0f}".format(red_mp).replace(',', '.')) if red_mp > 0 else "-" }}</td>
<td class="align-middle numeric-cell" style="color:#20c997">{{ ("$" ~ "{:,.0f}".format(redelcom_neto).replace(',', '.')) if redelcom_neto > 0 else "-" }}</td>
<td class="align-middle numeric-cell text-warning fw-bold">{{ ("$" ~ "{:,.0f}".format(efectivo_menos_gastos).replace(',', '.')) if efectivo_menos_gastos != 0 else "-" }}</td>
<td class="align-middle numeric-cell text-primary fw-bold">{{ ("$" ~ "{:,.0f}".format(redelcom_neto + efectivo_menos_gastos).replace(',', '.')) if (redelcom_neto + efectivo_menos_gastos) != 0 else "-" }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@@ -125,6 +144,14 @@
<td class="align-middle numeric-cell py-2">${{ "{:,.0f}".format(totales_mes.debito).replace(',', '.') }}</td> <td class="align-middle numeric-cell py-2">${{ "{:,.0f}".format(totales_mes.debito).replace(',', '.') }}</td>
<td class="align-middle numeric-cell py-2">${{ "{:,.0f}".format(totales_mes.mp).replace(',', '.') }}</td> <td class="align-middle numeric-cell py-2">${{ "{:,.0f}".format(totales_mes.mp).replace(',', '.') }}</td>
<td class="align-middle numeric-cell py-2">${{ "{:,.0f}".format(totales_mes.efectivo).replace(',', '.') }}</td> <td class="align-middle numeric-cell py-2">${{ "{:,.0f}".format(totales_mes.efectivo).replace(',', '.') }}</td>
<td class="align-middle numeric-cell py-2" style="color:#e5904d">${{ "{:,.0f}".format(totales_mes.credito * 0.97620).replace(',', '.') }}</td>
<td class="align-middle numeric-cell py-2" style="color:#e5904d">${{ "{:,.0f}".format(totales_mes.debito * 0.98453).replace(',', '.') }}</td>
<td class="align-middle numeric-cell py-2" style="color:#e5904d">${{ "{:,.0f}".format(totales_mes.mp * 0.98691).replace(',', '.') }}</td>
{% set t_redelcom = totales_mes.credito * 0.97620 + totales_mes.debito * 0.98453 + totales_mes.mp * 0.98691 %}
{% set t_efectivo_menos = totales_mes.efectivo - totales_mes.gastos %}
<td class="align-middle numeric-cell py-2" style="color:#20c997">${{ "{:,.0f}".format(t_redelcom).replace(',', '.') }}</td>
<td class="align-middle numeric-cell py-2 text-warning">${{ "{:,.0f}".format(t_efectivo_menos).replace(',', '.') }}</td>
<td class="align-middle numeric-cell py-2 text-primary fw-bold">${{ "{:,.0f}".format(t_redelcom + t_efectivo_menos).replace(',', '.') }}</td>
</tr> </tr>
</tfoot> </tfoot>
</table> </table>

View File

@@ -328,7 +328,7 @@
<dd class="col-sm-7">{{ rendicion[2] }} <dd class="col-sm-7">{{ rendicion[2] }}
{% if session.get('is_admin') %} {% if session.get('is_admin') %}
<span class="badge {% if rendicion[14] %}bg-success{% else %}bg-secondary{% endif %} ms-1" style="font-size: 0.65em;"> <span class="badge {% if rendicion[14] %}bg-success{% else %}bg-secondary{% endif %} ms-1" style="font-size: 0.65em;">
{% if rendicion[14] %}$ Si Recibe Comision{% else %}$ No Recibe Comision{% endif %} {% if rendicion[14] %}Si Recibe Comision{% else %}No Recibe Comision{% endif %}
</span> </span>
{% endif %} {% endif %}
</dd> </dd>
@@ -339,7 +339,21 @@
{{ rendicion[10] }} {{ rendicion[10] }}
{% if session.get('is_admin') %} {% if session.get('is_admin') %}
<span class="badge {% if rendicion[15] %}bg-success{% else %}bg-secondary{% endif %} ms-1" style="font-size: 0.65em;"> <span class="badge {% if rendicion[15] %}bg-success{% else %}bg-secondary{% endif %} ms-1" style="font-size: 0.65em;">
{% if rendicion[15] %}$ Si Recibe Comision{% else %}$ No Recibe Comision{% endif %} {% if rendicion[15] %}Si Recibe Comision{% else %}No Recibe Comision{% endif %}
</span>
{% endif %}
{% else %}
<span class="text-muted italic small">Sin acompañante</span>
{% endif %}
</dd>
<dt class="col-sm-5 text-muted">Acompañante 2</dt>
<dd class="col-sm-7">
{% if rendicion[16] %}
{{ rendicion[16] }}
{% if session.get('is_admin') %}
<span class="badge {% if rendicion[18] %}bg-success{% else %}bg-secondary{% endif %} ms-1" style="font-size: 0.65em;">
{% if rendicion[18] %}Si Recibe Comision{% else %}No Recibe Comision{% endif %}
</span> </span>
{% endif %} {% endif %}
{% else %} {% else %}
@@ -352,19 +366,19 @@
</dl> </dl>
<hr> <hr>
<div class="d-flex justify-content-between mb-2"> <div class="d-flex justify-content-between mb-2">
<span class="text-muted">Débito <small>(x{{ rendicion[16] }})</small>:</span> <span class="text-muted">Débito <small>(x{{ rendicion[19] or 0 }})</small>:</span>
<span>${{ "{:,.0f}".format(rendicion[4] or 0).replace(',', '.') }}</span> <span>${{ "{:,.0f}".format(rendicion[4] or 0).replace(',', '.') }}</span>
</div> </div>
<div class="d-flex justify-content-between mb-2"> <div class="d-flex justify-content-between mb-2">
<span class="text-muted">Crédito <small>(x{{ rendicion[17] }})</small>:</span> <span class="text-muted">Crédito <small>(x{{ rendicion[20] or 0 }})</small>:</span>
<span>${{ "{:,.0f}".format(rendicion[5] or 0).replace(',', '.') }}</span> <span>${{ "{:,.0f}".format(rendicion[5] or 0).replace(',', '.') }}</span>
</div> </div>
<div class="d-flex justify-content-between mb-2"> <div class="d-flex justify-content-between mb-2">
<span class="text-muted">Mercado Pago <small>(x{{ rendicion[18] }})</small>:</span> <span class="text-muted">Mercado Pago <small>(x{{ rendicion[21] or 0 }})</small>:</span>
<span>${{ "{:,.0f}".format(rendicion[6] or 0).replace(',', '.') }}</span> <span>${{ "{:,.0f}".format(rendicion[6] or 0).replace(',', '.') }}</span>
</div> </div>
<div class="d-flex justify-content-between mb-2"> <div class="d-flex justify-content-between mb-2">
<span class="text-muted">Efectivo <small>(x{{ rendicion[19] }})</small>:</span> <span class="text-muted">Efectivo <small>(x{{ rendicion[22] or 0 }})</small>:</span>
<span>${{ "{:,.0f}".format(rendicion[7] or 0).replace(',', '.') }}</span> <span>${{ "{:,.0f}".format(rendicion[7] or 0).replace(',', '.') }}</span>
</div> </div>
@@ -451,7 +465,7 @@
<tr> <tr>
<td colspan="3" class="text-end fw-bold">Total Calculado por Sistema:</td> <td colspan="3" class="text-end fw-bold">Total Calculado por Sistema:</td>
<td class="text-end fw-bold fs-6 text-primary" id="sys_total_{{ rendicion[0] }}"> <td class="text-end fw-bold fs-6 text-primary" id="sys_total_{{ rendicion[0] }}">
${{ "{:,.0f}".format(rendicion[21] or 0).replace(',', '.') }} ${{ "{:,.0f}".format(rendicion[24] or 0).replace(',', '.') }}
</td> </td>
</tr> </tr>
</tfoot> </tfoot>
@@ -484,7 +498,7 @@
<div id="badge_worker_{{ rendicion[0] }}"></div> <div id="badge_worker_{{ rendicion[0] }}"></div>
<div class="form-check m-0"> <div class="form-check m-0">
<input class="form-check-input" type="checkbox" name="worker_comision" id="wc_{{ rendicion[0] }}" {% if rendicion[14] %}checked{% endif %}> <input class="form-check-input" type="checkbox" name="worker_comision" id="wc_{{ rendicion[0] }}" {% if rendicion[14] %}checked{% endif %}>
<label class="form-check-label text-warning small fw-bold" for="wc_{{ rendicion[0] }}">Recibe Comisión</label> <label class="form-check-label text-success small fw-bold" for="wc_{{ rendicion[0] }}">Recibe Comisión</label>
</div> </div>
</div> </div>
</div> </div>
@@ -503,7 +517,26 @@
<div id="badge_comp_{{ rendicion[0] }}"></div> <div id="badge_comp_{{ rendicion[0] }}"></div>
<div class="form-check m-0"> <div class="form-check m-0">
<input class="form-check-input" type="checkbox" name="companion_comision" id="cc_{{ rendicion[0] }}" {% if rendicion[15] %}checked{% endif %}> <input class="form-check-input" type="checkbox" name="companion_comision" id="cc_{{ rendicion[0] }}" {% if rendicion[15] %}checked{% endif %}>
<label class="form-check-label text-warning small fw-bold" for="cc_{{ rendicion[0] }}">Recibe Comisión</label> <label class="form-check-label text-success small fw-bold" for="cc_{{ rendicion[0] }}">Recibe Comisión</label>
</div>
</div>
</div>
<div class="mb-2 border-top pt-2">
<label class="small text-muted mb-0">Acompañante 2</label>
<select class="form-select form-select-sm" name="companion2_id" onchange="toggleComp2Div({{ rendicion[0] }}, this)">
<option value="" data-tipo="">Sin acompañante</option>
{% for w in workers %}
{% if w[3] == rendicion[13] %}
<option value="{{ w[0] }}" data-tipo="{{ w[2] }}" {% if w[0] == rendicion[17] %}selected{% endif %}>{{ w[1] }}</option>
{% endif %}
{% endfor %}
</select>
<div class="d-flex justify-content-between align-items-center mt-1" id="comp2_com_div_{{ rendicion[0] }}" {% if not rendicion[17] %}style="display:none;"{% endif %}>
<div id="badge_comp2_{{ rendicion[0] }}"></div>
<div class="form-check m-0">
<input class="form-check-input" type="checkbox" name="companion2_comision" id="cc2_{{ rendicion[0] }}" {% if rendicion[18] %}checked{% endif %}>
<label class="form-check-label text-success small fw-bold" for="cc2_{{ rendicion[0] }}">Recibe Comisión</label>
</div> </div>
</div> </div>
</div> </div>
@@ -514,7 +547,7 @@
<input type="text" class="form-control form-control-sm text-end money-input mb-1" id="edit_debito_{{ rendicion[0] }}" name="venta_debito" value="{{ '{:,.0f}'.format(rendicion[4] or 0).replace(',', '.') }}" oninput="calcTotalEdit({{ rendicion[0] }})"> <input type="text" class="form-control form-control-sm text-end money-input mb-1" id="edit_debito_{{ rendicion[0] }}" name="venta_debito" value="{{ '{:,.0f}'.format(rendicion[4] or 0).replace(',', '.') }}" oninput="calcTotalEdit({{ rendicion[0] }})">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<span class="input-group-text bg-body-tertiary text-muted" style="font-size: 0.7em;">Boletas</span> <span class="input-group-text bg-body-tertiary text-muted" style="font-size: 0.7em;">Boletas</span>
<input type="number" class="form-control text-center bg-body text-body border-secondary" name="boletas_debito" value="{{ rendicion[16] or 0 }}"> <input type="number" class="form-control text-center bg-body text-body border-secondary" name="boletas_debito" value="{{ rendicion[19] or 0 }}">
</div> </div>
</div> </div>
<div class="col-6"> <div class="col-6">
@@ -522,7 +555,7 @@
<input type="text" class="form-control form-control-sm text-end money-input mb-1" id="edit_credito_{{ rendicion[0] }}" name="venta_credito" value="{{ '{:,.0f}'.format(rendicion[5] or 0).replace(',', '.') }}" oninput="calcTotalEdit({{ rendicion[0] }})"> <input type="text" class="form-control form-control-sm text-end money-input mb-1" id="edit_credito_{{ rendicion[0] }}" name="venta_credito" value="{{ '{:,.0f}'.format(rendicion[5] or 0).replace(',', '.') }}" oninput="calcTotalEdit({{ rendicion[0] }})">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<span class="input-group-text bg-body-tertiary text-muted" style="font-size: 0.7em;">Boletas</span> <span class="input-group-text bg-body-tertiary text-muted" style="font-size: 0.7em;">Boletas</span>
<input type="number" class="form-control text-center bg-body text-body border-secondary" name="boletas_credito" value="{{ rendicion[17] or 0 }}"> <input type="number" class="form-control text-center bg-body text-body border-secondary" name="boletas_credito" value="{{ rendicion[20] or 0 }}">
</div> </div>
</div> </div>
<div class="col-6"> <div class="col-6">
@@ -530,7 +563,7 @@
<input type="text" class="form-control form-control-sm text-end money-input mb-1" id="edit_mp_{{ rendicion[0] }}" name="venta_mp" value="{{ '{:,.0f}'.format(rendicion[6] or 0).replace(',', '.') }}" oninput="calcTotalEdit({{ rendicion[0] }})"> <input type="text" class="form-control form-control-sm text-end money-input mb-1" id="edit_mp_{{ rendicion[0] }}" name="venta_mp" value="{{ '{:,.0f}'.format(rendicion[6] or 0).replace(',', '.') }}" oninput="calcTotalEdit({{ rendicion[0] }})">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<span class="input-group-text bg-body-tertiary text-muted" style="font-size: 0.7em;">Boletas</span> <span class="input-group-text bg-body-tertiary text-muted" style="font-size: 0.7em;">Boletas</span>
<input type="number" class="form-control text-center bg-body text-body border-secondary" name="boletas_mp" value="{{ rendicion[18] or 0 }}"> <input type="number" class="form-control text-center bg-body text-body border-secondary" name="boletas_mp" value="{{ rendicion[21] or 0 }}">
</div> </div>
</div> </div>
<div class="col-6"> <div class="col-6">
@@ -538,7 +571,7 @@
<input type="text" class="form-control form-control-sm text-end money-input mb-1" id="edit_efectivo_{{ rendicion[0] }}" name="venta_efectivo" value="{{ '{:,.0f}'.format(rendicion[7] or 0).replace(',', '.') }}" oninput="calcTotalEdit({{ rendicion[0] }})"> <input type="text" class="form-control form-control-sm text-end money-input mb-1" id="edit_efectivo_{{ rendicion[0] }}" name="venta_efectivo" value="{{ '{:,.0f}'.format(rendicion[7] or 0).replace(',', '.') }}" oninput="calcTotalEdit({{ rendicion[0] }})">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<span class="input-group-text bg-body-tertiary text-muted" style="font-size: 0.7em;">Boletas</span> <span class="input-group-text bg-body-tertiary text-muted" style="font-size: 0.7em;">Boletas</span>
<input type="number" class="form-control text-center bg-body text-body border-secondary" name="boletas_efectivo" value="{{ rendicion[19] or 0 }}"> <input type="number" class="form-control text-center bg-body text-body border-secondary" name="boletas_efectivo" value="{{ rendicion[22] or 0 }}">
</div> </div>
</div> </div>
</div> </div>