Initial commit: Sistema de comisiones y gastos personales
This commit is contained in:
11
resources/css/app.css
Executable file
11
resources/css/app.css
Executable file
@@ -0,0 +1,11 @@
|
||||
@import 'tailwindcss';
|
||||
|
||||
@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';
|
||||
@source '../../storage/framework/views/*.php';
|
||||
@source '../**/*.blade.php';
|
||||
@source '../**/*.js';
|
||||
|
||||
@theme {
|
||||
--font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
||||
'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
}
|
||||
1
resources/js/app.js
Executable file
1
resources/js/app.js
Executable file
@@ -0,0 +1 @@
|
||||
//
|
||||
53
resources/views/auth/login.blade.php
Executable file
53
resources/views/auth/login.blade.php
Executable file
@@ -0,0 +1,53 @@
|
||||
@extends('layouts.guest')
|
||||
|
||||
@section('title', 'Iniciar Sesión')
|
||||
|
||||
@section('content')
|
||||
<div class="auth-card p-4">
|
||||
<h3 class="text-center mb-4">
|
||||
<i class="bi bi-person-circle"></i> Nómina Pegaso
|
||||
</h3>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<ul class="mb-0">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(session('success'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('login') }}">
|
||||
@csrf
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Usuario</label>
|
||||
<input type="text" class="form-control" id="username" name="username"
|
||||
value="{{ old('username') }}" required autofocus>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Contraseña</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="remember" name="remember">
|
||||
<label class="form-check-label" for="remember">Recordarme</label>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary w-100">Iniciar Sesión</button>
|
||||
</form>
|
||||
|
||||
<div class="text-center mt-3">
|
||||
<a href="{{ route('register') }}">¿No tienes cuenta? Regístrate</a>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
84
resources/views/auth/register.blade.php
Executable file
84
resources/views/auth/register.blade.php
Executable file
@@ -0,0 +1,84 @@
|
||||
@extends('layouts.guest')
|
||||
|
||||
@section('title', 'Registrarse')
|
||||
|
||||
@section('content')
|
||||
<div class="auth-card p-4">
|
||||
<h3 class="text-center mb-4">
|
||||
<i class="bi bi-person-plus"></i> Registrarse
|
||||
</h3>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<ul class="mb-0">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('register') }}">
|
||||
@csrf
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Nombre de Usuario</label>
|
||||
<input type="text" class="form-control" id="username" name="username"
|
||||
value="{{ old('username') }}" required>
|
||||
<small class="text-muted">Único - sin espacios ni acentos</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Nombre Completo</label>
|
||||
<input type="text" class="form-control" id="name" name="name"
|
||||
value="{{ old('name') }}" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Correo Electrónico</label>
|
||||
<input type="email" class="form-control" id="email" name="email"
|
||||
value="{{ old('email') }}" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Contraseña</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
<small class="text-muted">Mínimo 8 caracteres</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password_confirmation" class="form-label">Confirmar Contraseña</label>
|
||||
<input type="password" class="form-control" id="password_confirmation"
|
||||
name="password_confirmation" required>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h5 class="mb-3">Configuración de Comisión</h5>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="commission_percentage" class="form-label">Porcentaje de Comisión (%)</label>
|
||||
<input type="number" class="form-control" id="commission_percentage"
|
||||
name="commission_percentage" value="{{ old('commission_percentage', 10) }}"
|
||||
min="0" max="100" step="0.01" required>
|
||||
<small class="text-muted">Porcentaje que recibirás sobre tus ventas</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="monthly_salary" class="form-label">Salario Mensual Base</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="monthly_salary"
|
||||
name="monthly_salary" value="{{ old('monthly_salary', 0) }}"
|
||||
min="0" step="0.01" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-success w-100">Registrarse</button>
|
||||
</form>
|
||||
|
||||
<div class="text-center mt-3">
|
||||
<a href="{{ route('login') }}">¿Ya tienes cuenta? Inicia Sesión</a>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
584
resources/views/calendar/index.blade.php
Executable file
584
resources/views/calendar/index.blade.php
Executable file
@@ -0,0 +1,584 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Calendario')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">
|
||||
<i class="bi bi-calendar3 text-primary"></i> Calendario de Ventas y Gastos
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Selector de mes -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="GET" class="d-flex gap-2 flex-wrap">
|
||||
<select name="year" class="form-select" style="width: auto;" onchange="this.form.submit()">
|
||||
@php($years = range(date('Y'), date('Y') - 5))
|
||||
@foreach($years as $y)
|
||||
<option value="{{ $y }}" {{ $year == $y ? 'selected' : '' }}>{{ $y }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<select name="month" class="form-select" style="width: auto;" onchange="this.form.submit()">
|
||||
<option value="">Todos los meses</option>
|
||||
@foreach(['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'] as $m)
|
||||
<option value="{{ $m }}" {{ request('month') == $m ? 'selected' : '' }}>{{ $m }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 text-end">
|
||||
@if($currentMonth)
|
||||
<span class="badge bg-primary fs-6">
|
||||
<i class="bi bi-calendar"></i> {{ $currentMonth->name }} {{ $currentMonth->year }}
|
||||
</span>
|
||||
<span class="badge bg-{{ $currentMonth->status === 'open' ? 'success' : ($currentMonth->status === 'closed' ? 'warning' : 'info') }}">
|
||||
{{ ucfirst($currentMonth->status) }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($currentMonth)
|
||||
<!-- Resumen del mes -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card primary">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Ventas del Usuario</h6>
|
||||
<h4 class="text-primary">${{ number_format($currentMonth->dailySales()->sum('user_sales'), 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card success">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Ventas del Sistema</h6>
|
||||
<h4 class="text-success">${{ number_format($currentMonth->dailySales()->sum('system_sales'), 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card stat-card warning">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Total Gastos</h6>
|
||||
<h4 class="text-warning">${{ number_format($currentMonth->expenses()->sum('amount'), 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Calendario FullCalendar -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div id="calendar"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Leyenda -->
|
||||
<div class="row mt-3">
|
||||
<div class="col-12">
|
||||
<div class="d-flex gap-3 flex-wrap">
|
||||
<span class="badge bg-light text-dark border p-2">
|
||||
<i class="bi bi-square text-secondary"></i> Sin datos
|
||||
</span>
|
||||
<span class="badge bg-success-subtle text-success border p-2">
|
||||
<i class="bi bi-square text-success"></i> Con ventas
|
||||
</span>
|
||||
<span class="badge bg-danger-subtle text-danger border p-2">
|
||||
<i class="bi bi-square text-danger"></i> Con gastos
|
||||
</span>
|
||||
<span class="badge bg-warning-subtle text-warning border p-2">
|
||||
<i class="bi bi-square text-warning"></i> Con ambos
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="alert alert-info">
|
||||
<h5><i class="bi bi-info-circle"></i> No hay un mes seleccionado</h5>
|
||||
<p>Selecciona un mes del dropdown o crea uno nuevo.</p>
|
||||
<a href="{{ route('months.index') }}" class="btn btn-primary">Ver Meses</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Modal para capturar ventas -->
|
||||
<div class="modal fade" id="dayModal" tabindex="-1" aria-labelledby="dayModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="dayModalLabel">
|
||||
<i class="bi bi-calendar-plus"></i> Capturar Día
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form method="POST" id="dayForm">
|
||||
@csrf
|
||||
<div class="modal-body">
|
||||
<input type="hidden" name="month_id" id="formMonthId" value="{{ $currentMonth->id ?? '' }}">
|
||||
<input type="hidden" name="date" id="modalDate">
|
||||
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i> Fecha: <strong id="modalDateDisplay"></strong>
|
||||
</div>
|
||||
|
||||
<!-- Ventas -->
|
||||
<h6 class="border-bottom pb-2 mb-3">
|
||||
<i class="bi bi-currency-dollar text-success"></i> Ventas
|
||||
</h6>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="user_sales" class="form-label">Ventas del Usuario</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="user_sales" name="user_sales"
|
||||
value="0" step="0.01" min="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="system_sales" class="form-label">Ventas del Sistema</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="system_sales" name="system_sales"
|
||||
value="0" step="0.01" min="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gastos -->
|
||||
<h6 class="border-bottom pb-2 mb-3 mt-4">
|
||||
<i class="bi bi-receipt text-danger"></i> Gastos
|
||||
</h6>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="expense_description" class="form-label">Descripción del Gasto</label>
|
||||
<input type="text" class="form-control" id="expense_description" name="expense_description"
|
||||
placeholder="Opcional">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="expense_amount" class="form-label">Monto del Gasto</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="expense_amount" name="expense_amount"
|
||||
value="0" step="0.01" min="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="expense_type" class="form-label">Quincena del Gasto</label>
|
||||
<select class="form-select" id="expense_type" name="expense_type">
|
||||
<option value="q1">1ra Quincena (1-15)</option>
|
||||
<option value="q2">2da Quincena (16-31)</option>
|
||||
<option value="mensual">Gasto Mensual (se divide en 2)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-save"></i> Guardar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal para ver detalles del día -->
|
||||
<div class="modal fade" id="dayDetailModal" tabindex="-1" aria-labelledby="dayDetailModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-info text-white">
|
||||
<h5 class="modal-title" id="dayDetailModalLabel">
|
||||
<i class="bi bi-eye"></i> Detalles del Día
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="mb-3"><strong>Fecha:</strong> <span id="detailDate"></span></p>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-6">
|
||||
<div class="card bg-light">
|
||||
<div class="card-body text-center">
|
||||
<h6 class="text-muted">Ventas Usuario</h6>
|
||||
<h5 class="text-success" id="detailUserSales">$0.00</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="card bg-light">
|
||||
<div class="card-body text-center">
|
||||
<h6 class="text-muted">Ventas Sistema</h6>
|
||||
<h5 class="text-info" id="detailSystemSales">$0.00</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Gastos del Día</h6>
|
||||
<div id="detailExpenses">
|
||||
<p class="text-muted mb-0">No hay gastos registrados</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
|
||||
<button type="button" class="btn btn-primary" id="editDayBtn">
|
||||
<i class="bi bi-pencil"></i> Editar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Data for calendar events
|
||||
const dailySales = @json($dailySales ?? []);
|
||||
const expenses = @json($expenses ?? []);
|
||||
const year = {{ $year }};
|
||||
const currentMonthId = {{ $currentMonth->id ?? 0 }};
|
||||
|
||||
console.log('Month ID:', currentMonthId);
|
||||
console.log('DailySales raw:', dailySales);
|
||||
console.log('DailySales type:', typeof dailySales);
|
||||
console.log('Expenses:', expenses);
|
||||
|
||||
// Map data to calendar events
|
||||
const events = [];
|
||||
|
||||
// Add sales events - iterate over object values
|
||||
Object.keys(dailySales).forEach(date => {
|
||||
const saleData = dailySales[date];
|
||||
if (saleData && saleData.user_sales > 0) {
|
||||
events.push({
|
||||
title: 'V: $' + parseFloat(saleData.user_sales).toLocaleString(),
|
||||
start: date,
|
||||
className: 'bg-success',
|
||||
extendedProps: {
|
||||
type: 'sale',
|
||||
user_sales: saleData.user_sales,
|
||||
system_sales: saleData.system_sales
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add expense events
|
||||
Object.keys(expenses).forEach(date => {
|
||||
const expData = expenses[date];
|
||||
if (expData && expData.amount > 0) {
|
||||
events.push({
|
||||
title: 'G: $' + parseFloat(expData.amount).toLocaleString(),
|
||||
start: date,
|
||||
className: 'bg-danger',
|
||||
extendedProps: {
|
||||
type: 'expense',
|
||||
amount: expData.amount,
|
||||
description: expData.description
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Events:', events);
|
||||
|
||||
const calendarEl = document.getElementById('calendar');
|
||||
|
||||
// FullCalendar initialization
|
||||
const calendar = new FullCalendar.Calendar(calendarEl, {
|
||||
initialView: 'dayGridMonth',
|
||||
initialDate: year + '-04-01',
|
||||
locale: 'es',
|
||||
headerToolbar: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'dayGridMonth,listMonth'
|
||||
},
|
||||
buttonText: {
|
||||
today: 'Hoy',
|
||||
month: 'Mes',
|
||||
list: 'Lista'
|
||||
},
|
||||
dayMaxEvents: true,
|
||||
eventDisplay: 'block',
|
||||
events: events,
|
||||
dateClick: function(info) {
|
||||
// Verify month exists
|
||||
const monthId = {{ $currentMonth->id ?? 0 }};
|
||||
if (!monthId || monthId === 0) {
|
||||
console.log('No hay mes seleccionado');
|
||||
return;
|
||||
}
|
||||
openDayModal(info.dateStr);
|
||||
},
|
||||
eventClick: function(info) {
|
||||
showDayDetails(info.event.startStr);
|
||||
},
|
||||
eventDidMount: function(info) {
|
||||
// Add custom styling based on data
|
||||
const date = info.event.startStr;
|
||||
if (dailySales[date] && expenses[date]) {
|
||||
info.el.style.background = 'linear-gradient(135deg, #f39c12 0%, #e74c3c 100%)';
|
||||
} else if (dailySales[date]) {
|
||||
info.el.style.background = 'linear-gradient(135deg, #27ae60 0%, #2ecc71 100%)';
|
||||
} else if (expenses[date]) {
|
||||
info.el.style.background = 'linear-gradient(135deg, #e74c3c 0%, #c0392b 100%)';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
calendar.render();
|
||||
|
||||
// Initialize selected date variable
|
||||
window.selectedDate = null;
|
||||
|
||||
// Functions
|
||||
window.openDayModal = function(dateStr) {
|
||||
const modalEl = document.getElementById('dayModal');
|
||||
if (!modalEl) return;
|
||||
|
||||
const modal = new bootstrap.Modal(modalEl);
|
||||
|
||||
const modalDateEl = document.getElementById('modalDate');
|
||||
const modalDateDisplayEl = document.getElementById('modalDateDisplay');
|
||||
|
||||
if (modalDateEl && modalDateDisplayEl) {
|
||||
modalDateEl.value = dateStr;
|
||||
modalDateDisplayEl.textContent = formatDate(dateStr);
|
||||
}
|
||||
|
||||
// Check if there's existing data
|
||||
const userSalesEl = document.getElementById('user_sales');
|
||||
const systemSalesEl = document.getElementById('system_sales');
|
||||
const expenseDescEl = document.getElementById('expense_description');
|
||||
const expenseAmountEl = document.getElementById('expense_amount');
|
||||
|
||||
if (userSalesEl && systemSalesEl) {
|
||||
// Buscar coincidencia parcial
|
||||
let saleData = dailySales[dateStr];
|
||||
if (!saleData) {
|
||||
// Buscar en claves
|
||||
for (const key in dailySales) {
|
||||
if (key.includes(dateStr) || dateStr.includes(key)) {
|
||||
saleData = dailySales[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (saleData) {
|
||||
userSalesEl.value = saleData.user_sales;
|
||||
systemSalesEl.value = saleData.system_sales;
|
||||
} else {
|
||||
userSalesEl.value = 0;
|
||||
systemSalesEl.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (expenseDescEl && expenseAmountEl) {
|
||||
let expData = expenses[dateStr];
|
||||
if (!expData) {
|
||||
for (const key in expenses) {
|
||||
if (key.includes(dateStr) || dateStr.includes(key)) {
|
||||
expData = expenses[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (expData) {
|
||||
expenseDescEl.value = expData.description || '';
|
||||
expenseAmountEl.value = expData.amount;
|
||||
} else {
|
||||
expenseDescEl.value = '';
|
||||
expenseAmountEl.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
modal.show();
|
||||
};
|
||||
|
||||
window.showDayDetails = function(dateStr) {
|
||||
const modal = new bootstrap.Modal(document.getElementById('dayDetailModal'));
|
||||
document.getElementById('detailDate').textContent = formatDate(dateStr);
|
||||
|
||||
// Buscar en todas las claves
|
||||
let foundKey = null;
|
||||
for (const key in dailySales) {
|
||||
if (key.includes(dateStr) || dateStr.includes(key)) {
|
||||
foundKey = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundKey) {
|
||||
// Found
|
||||
document.getElementById('detailUserSales').textContent = '$' + dailySales[foundKey].user_sales.toLocaleString();
|
||||
document.getElementById('detailSystemSales').textContent = '$' + dailySales[foundKey].system_sales.toLocaleString();
|
||||
} else {
|
||||
document.getElementById('detailUserSales').textContent = '$0.00';
|
||||
document.getElementById('detailSystemSales').textContent = '$0.00';
|
||||
}
|
||||
|
||||
if (expenses[dateStr]) {
|
||||
document.getElementById('detailExpenses').innerHTML = `
|
||||
<p class="mb-1"><strong>${expenses[dateStr].description || 'Gasto'}</strong></p>
|
||||
<h5 class="text-danger mb-0">$${expenses[dateStr].amount.toLocaleString()}</h5>
|
||||
`;
|
||||
} else {
|
||||
document.getElementById('detailExpenses').innerHTML = '<p class="text-muted mb-0">No hay gastos registrados</p>';
|
||||
}
|
||||
|
||||
// Set up edit button
|
||||
document.getElementById('editDayBtn').onclick = function() {
|
||||
window.selectedDate = dateStr;
|
||||
modal.hide();
|
||||
setTimeout(() => openDayModal(dateStr), 300);
|
||||
};
|
||||
|
||||
modal.show();
|
||||
};
|
||||
|
||||
function formatDate(dateStr) {
|
||||
if (!dateStr) return 'Sin fecha';
|
||||
const parts = dateStr.split('-');
|
||||
if (parts.length === 3) {
|
||||
const year = parseInt(parts[0]);
|
||||
const month = parseInt(parts[1]) - 1;
|
||||
const day = parseInt(parts[2]);
|
||||
const date = new Date(year, month, day);
|
||||
return date.toLocaleDateString('es-ES', { year: 'numeric', month: 'long', day: 'numeric' });
|
||||
}
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
// Form submission handler
|
||||
document.getElementById('dayForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Get values directly from DOM elements
|
||||
const monthIdEl = document.getElementById('formMonthId');
|
||||
const dateEl = document.getElementById('modalDate');
|
||||
const userSalesEl = document.getElementById('user_sales');
|
||||
const systemSalesEl = document.getElementById('system_sales');
|
||||
const expenseAmountEl = document.getElementById('expense_amount');
|
||||
const expenseDescEl = document.getElementById('expense_description');
|
||||
const expenseTypeEl = document.getElementById('expense_type');
|
||||
|
||||
let monthId = monthIdEl ? monthIdEl.value : '';
|
||||
let date = dateEl ? dateEl.value : '';
|
||||
|
||||
// Use window.selectedDate as fallback
|
||||
if (!date && window.selectedDate) date = window.selectedDate;
|
||||
|
||||
// Try fallback
|
||||
if (!monthId) monthId = '{{ $currentMonth->id ?? 0 }}';
|
||||
|
||||
const userSales = userSalesEl ? (parseFloat(userSalesEl.value) || 0) : 0;
|
||||
const systemSales = systemSalesEl ? (parseFloat(systemSalesEl.value) || 0) : 0;
|
||||
const expenseAmount = expenseAmountEl ? (parseFloat(expenseAmountEl.value) || 0) : 0;
|
||||
const expenseDesc = expenseDescEl ? expenseDescEl.value : '';
|
||||
const expenseType = expenseTypeEl ? expenseTypeEl.value : 'q1';
|
||||
|
||||
// Save data
|
||||
if (!monthId || !date) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {
|
||||
month_id: monthId,
|
||||
date: date,
|
||||
user_sales: userSales,
|
||||
system_sales: systemSales,
|
||||
expense_description: expenseDesc,
|
||||
expense_amount: expenseAmount,
|
||||
expense_type: expenseType
|
||||
};
|
||||
|
||||
// Send data via fetch
|
||||
fetch('{{ route("calendar.day.store") }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
console.error('Error saving:', data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
.fc {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.fc .fc-toolbar-title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.fc .fc-daygrid-day-number {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.fc-event {
|
||||
padding: 2px 4px;
|
||||
font-size: 0.75rem;
|
||||
border-radius: 4px;
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
.fc .fc-col-header-cell-cushion {
|
||||
padding: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.fc-daygrid-day.has-data {
|
||||
background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%);
|
||||
}
|
||||
|
||||
.fc-daygrid-day.has-expense {
|
||||
background: linear-gradient(135deg, #ffebee 0%, #ffcdd2 100%);
|
||||
}
|
||||
|
||||
.fc-daygrid-day.has-both {
|
||||
background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%);
|
||||
}
|
||||
|
||||
.day-cell-clickable {
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.day-cell-clickable:hover {
|
||||
background: #e3f2fd !important;
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
170
resources/views/dashboard/index.blade.php
Executable file
170
resources/views/dashboard/index.blade.php
Executable file
@@ -0,0 +1,170 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Dashboard')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Bienvenido, {{ auth()->user()->name }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($currentMonth)
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-calendar3"></i>
|
||||
Resumen de {{ $currentMonth->name }} {{ $currentMonth->year }}
|
||||
@if($currentMonth->status === 'open')
|
||||
<span class="badge bg-success ms-2">Abierto</span>
|
||||
@elseif($currentMonth->status === 'closed')
|
||||
<span class="badge bg-warning ms-2">Cerrado</span>
|
||||
@else
|
||||
<span class="badge bg-info ms-2">Pagado</span>
|
||||
@endif
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if($data)
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card primary mb-3">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Ventas del Usuario</h6>
|
||||
<h4>${{ number_format($data['total_user_sales'], 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card success mb-3">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Ventas del Sistema</h6>
|
||||
<h4>${{ number_format($data['total_system_sales'], 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card warning mb-3">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Comisión ({{ $data['commission_percentage'] }}%)</h6>
|
||||
<h4>${{ number_format($data['commission_amount'], 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card danger mb-3">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Total a Recibir</h6>
|
||||
<h4>${{ number_format($data['total_earning'], 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-md-6">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Salario Mensual
|
||||
<span class="badge bg-primary rounded-pill">${{ number_format($data['monthly_salary'], 2) }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Gastos del Mes
|
||||
<span class="badge bg-danger rounded-pill">${{ number_format($data['total_expenses'], 2) }}</span>
|
||||
</li>
|
||||
@if($data['has_difference'])
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Diferencia Ventas
|
||||
<span class="badge bg-warning rounded-pill">${{ number_format($data['sales_difference'], 2) }}</span>
|
||||
</li>
|
||||
@endif
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6 text-end">
|
||||
<a href="{{ route('reports.monthly', ['month_id' => $currentMonth->id]) }}" class="btn btn-primary">
|
||||
<i class="bi bi-file-earmark-text"></i> Ver Reporte Mensual
|
||||
</a>
|
||||
<a href="{{ route('reports.biweekly', ['month_id' => $currentMonth->id, 'biweekly' => 1]) }}" class="btn btn-outline-primary">
|
||||
<i class="bi bi-file-earmark-text"></i> Ver Quincena
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="alert alert-info">
|
||||
No hay datos suficientes para calcular el resumen. Agrega ventas y gastos.
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="alert alert-warning">
|
||||
<h5>No hay un mes de trabajo activo</h5>
|
||||
<p>Para comenzar, crea un nuevo mes de trabajo.</p>
|
||||
<a href="{{ route('months.create') }}" class="btn btn-primary">Crear Mes</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Últimos meses -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<h4 class="mb-3">Meses Recientes</h4>
|
||||
</div>
|
||||
@forelse($recentMonths as $month)
|
||||
<div class="col-md-4 col-lg-2 mb-3">
|
||||
<div class="card h-100">
|
||||
<div class="card-body text-center">
|
||||
<h6>{{ $month->name }}</h6>
|
||||
<small class="text-muted">{{ $month->year }}</small>
|
||||
<div class="mt-2">
|
||||
@if($month->status === 'open')
|
||||
<span class="badge bg-success">Abierto</span>
|
||||
@elseif($month->status === 'closed')
|
||||
<span class="badge bg-warning">Cerrado</span>
|
||||
@else
|
||||
<span class="badge bg-info">Pagado</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<a href="{{ route('months.show', $month->id) }}" class="btn btn-sm btn-outline-primary w-100">Ver</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">No hay meses registrados.</div>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
<!-- Acceso rápido -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<h4 class="mb-3">Acceso Rápido</h4>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="{{ route('sales.create') }}" class="btn btn-success w-100 mb-2">
|
||||
<i class="bi bi-plus-circle"></i> Nueva Venta
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="{{ route('expenses.create') }}" class="btn btn-warning w-100 mb-2">
|
||||
<i class="bi bi-plus-circle"></i> Nuevo Gasto
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="{{ route('calendar') }}" class="btn btn-info w-100 mb-2">
|
||||
<i class="bi bi-calendar3"></i> Ver Calendario
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="{{ route('reports.monthly') }}" class="btn btn-secondary w-100 mb-2">
|
||||
<i class="bi bi-graph-up"></i> Ver Reportes
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
63
resources/views/expenses/create.blade.php
Executable file
63
resources/views/expenses/create.blade.php
Executable file
@@ -0,0 +1,63 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Nuevo Gasto')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Nuevo Gasto</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('expenses.store') }}">
|
||||
@csrf
|
||||
<input type="hidden" name="month_id" value="{{ $month->id }}">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">Descripción</label>
|
||||
<input type="text" class="form-control" id="description" name="description"
|
||||
value="{{ old('description') }}" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="amount" class="form-label">Monto</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="amount" name="amount"
|
||||
value="{{ old('amount') }}" step="0.01" min="0.01" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="date" class="form-label">Fecha</label>
|
||||
<input type="date" class="form-control" id="date" name="date"
|
||||
value="{{ old('date', now()->format('Y-m-d')) }}" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="expense_type" class="form-label">Quincena</label>
|
||||
<select class="form-select" id="expense_type" name="expense_type" required>
|
||||
<option value="q1">1ra Quincena (1-15)</option>
|
||||
<option value="q2">2da Quincena (16-31)</option>
|
||||
<option value="mensual">Gasto Mensual (se divide en 2)</option>
|
||||
</select>
|
||||
<small class="text-muted">
|
||||
Selecciona a qué quincena se restará el gasto.
|
||||
Los gastos mensuales se dividen entre 2.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-warning">Guardar Gasto</button>
|
||||
<a href="{{ route('expenses.index', ['month_id' => $month->id]) }}" class="btn btn-secondary">Cancelar</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
59
resources/views/expenses/edit.blade.php
Executable file
59
resources/views/expenses/edit.blade.php
Executable file
@@ -0,0 +1,59 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Editar Gasto')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Editar Gasto</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('expenses.update', $expense->id) }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">Descripción</label>
|
||||
<input type="text" class="form-control" id="description" name="description"
|
||||
value="{{ old('description', $expense->description) }}" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="amount" class="form-label">Monto</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="amount" name="amount"
|
||||
value="{{ old('amount', $expense->amount) }}" step="0.01" min="0.01" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="date" class="form-label">Fecha</label>
|
||||
<input type="date" class="form-control" id="date" name="date"
|
||||
value="{{ old('date', $expense->date->format('Y-m-d')) }}" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="expense_type" class="form-label">Quincena</label>
|
||||
<select class="form-select" id="expense_type" name="expense_type" required>
|
||||
<option value="q1" {{ $expense->expense_type == 'q1' ? 'selected' : '' }}>1ra Quincena (1-15)</option>
|
||||
<option value="q2" {{ $expense->expense_type == 'q2' ? 'selected' : '' }}>2da Quincena (16-31)</option>
|
||||
<option value="mensual" {{ $expense->expense_type == 'mensual' ? 'selected' : '' }}>Gasto Mensual (se divide en 2)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">Actualizar</button>
|
||||
<a href="{{ route('expenses.index', ['month_id' => $expense->month_id]) }}" class="btn btn-secondary">Cancelar</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
99
resources/views/expenses/index.blade.php
Executable file
99
resources/views/expenses/index.blade.php
Executable file
@@ -0,0 +1,99 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Gastos')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Gestión de Gastos</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Selector de mes -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<form method="GET" class="d-flex gap-2">
|
||||
<select name="month_id" class="form-select" onchange="this.form.submit()">
|
||||
<option value="">Todos los meses</option>
|
||||
@foreach($months as $m)
|
||||
<option value="{{ $m->id }}" {{ $month && $month->id == $m->id ? 'selected' : '' }}>
|
||||
{{ $m->name }} {{ $m->year }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<a href="{{ route('expenses.create', ['month_id' => $month?->id]) }}" class="btn btn-warning">
|
||||
<i class="bi bi-plus-circle"></i> Nuevo Gasto
|
||||
</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($month)
|
||||
<!-- Resumen -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Total Gastos del Mes</h6>
|
||||
<h3>${{ number_format($month->expenses()->sum('amount'), 2) }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Lista de gastos -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Fecha</th>
|
||||
<th>Descripción</th>
|
||||
<th>Monto</th>
|
||||
<th>Quincena</th>
|
||||
<th>Mes</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($expenses as $expense)
|
||||
<tr>
|
||||
<td>{{ $expense->date->format('d/m/Y') }}</td>
|
||||
<td>{{ $expense->description }}</td>
|
||||
<td class="text-danger">-${{ number_format($expense->amount, 2) }}</td>
|
||||
<td>
|
||||
@if($expense->expense_type == 'q1')
|
||||
<span class="badge bg-primary">Q1</span>
|
||||
@elseif($expense->expense_type == 'q2')
|
||||
<span class="badge bg-warning">Q2</span>
|
||||
@else
|
||||
<span class="badge bg-info">Mensual</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $expense->month->name }} {{ $expense->month->year }}</td>
|
||||
<td>
|
||||
<a href="{{ route('expenses.edit', $expense->id) }}" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<form method="POST" action="{{ route('expenses.destroy', $expense->id) }}" class="d-inline">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" onclick="return confirm('¿Eliminar este gasto?')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="6" class="text-center text-muted">No hay gastos registrados.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{{ $expenses->links() }}
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
310
resources/views/layouts/app.blade.php
Executable file
310
resources/views/layouts/app.blade.php
Executable file
@@ -0,0 +1,310 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>@yield('title', 'Nómina Pegaso')</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
||||
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@6.1.10/main.min.css' rel='stylesheet' />
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
/* Sidebar Styles */
|
||||
.sidebar {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(180deg, #2c3e50 0%, #1a252f 100%);
|
||||
box-shadow: 2px 0 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.sidebar-brand {
|
||||
padding: 1rem;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.sidebar a {
|
||||
color: rgba(255,255,255,0.8);
|
||||
text-decoration: none;
|
||||
padding: 12px 20px;
|
||||
display: block;
|
||||
border-radius: 8px;
|
||||
margin: 4px 12px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar a:hover {
|
||||
background: rgba(255,255,255,0.1);
|
||||
color: #fff;
|
||||
transform: translateX(5px);
|
||||
}
|
||||
|
||||
.sidebar a.active {
|
||||
background: #3498db;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.sidebar a i {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
/* Card Styles */
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.12);
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
border-left: 4px solid;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.stat-card.primary { border-color: #3498db; }
|
||||
.stat-card.success { border-color: #27ae60; }
|
||||
.stat-card.warning { border-color: #f39c12; }
|
||||
.stat-card.danger { border-color: #e74c3c; }
|
||||
|
||||
/* Calendar Styles */
|
||||
.fc .fc-daygrid-day:hover {
|
||||
background: #f8f9fa;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.fc-event {
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.day-with-sales {
|
||||
background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%) !important;
|
||||
}
|
||||
|
||||
.day-with-expenses {
|
||||
background: linear-gradient(135deg, #f8d7da 0%, #f5c6cb 100%) !important;
|
||||
}
|
||||
|
||||
.day-empty {
|
||||
background: #f8f9fa;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
/* Mobile Styles */
|
||||
@media (max-width: 768px) {
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 280px;
|
||||
z-index: 1050;
|
||||
transition: left 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar.show {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.sidebar-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 1040;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-overlay.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mobile-nav-btn {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-nav-btn {
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
z-index: 1030;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
/* Button Styles */
|
||||
.btn {
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* Form Styles */
|
||||
.form-control, .form-select {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e0e0e0;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.form-control:focus, .form-select:focus {
|
||||
border-color: #3498db;
|
||||
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
|
||||
}
|
||||
|
||||
/* Badge Styles */
|
||||
.badge {
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Toast Styles */
|
||||
.toast-container {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/* Table Styles */
|
||||
.table th {
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
border-bottom: 2px solid #e9ecef;
|
||||
}
|
||||
|
||||
.table-hover tbody tr:hover {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
</style>
|
||||
@stack('styles')
|
||||
</head>
|
||||
<body>
|
||||
@auth
|
||||
<!-- Sidebar Overlay (Mobile) -->
|
||||
<div class="sidebar-overlay" id="sidebarOverlay"></div>
|
||||
|
||||
<!-- Mobile Navigation Button -->
|
||||
<button class="btn btn-primary mobile-nav-btn" id="mobileNavBtn">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar -->
|
||||
<nav class="col-md-2 d-none d-md-block sidebar py-3" id="sidebar">
|
||||
<div class="sidebar-brand text-center mb-4">
|
||||
<h5 class="text-white mb-1">
|
||||
<i class="bi bi-cash-coin"></i> Nómina Pegaso
|
||||
</h5>
|
||||
<small class="text-white-50">{{ auth()->user()->name }}</small>
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<a href="{{ route('dashboard') }}" class="{{ request()->routeIs('dashboard') ? 'active' : '' }}">
|
||||
<i class="bi bi-house-door"></i> Dashboard
|
||||
</a>
|
||||
<a href="{{ route('calendar') }}" class="{{ request()->routeIs('calendar*') ? 'active' : '' }}">
|
||||
<i class="bi bi-calendar3"></i> Calendario
|
||||
</a>
|
||||
<a href="{{ route('sales.index') }}" class="{{ request()->routeIs('sales.*') ? 'active' : '' }}">
|
||||
<i class="bi bi-currency-dollar"></i> Ventas
|
||||
</a>
|
||||
<a href="{{ route('expenses.index') }}" class="{{ request()->routeIs('expenses.*') ? 'active' : '' }}">
|
||||
<i class="bi bi-receipt"></i> Gastos
|
||||
</a>
|
||||
<a href="{{ route('months.index') }}" class="{{ request()->routeIs('months.*') ? 'active' : '' }}">
|
||||
<i class="bi bi-calendar-month"></i> Meses
|
||||
</a>
|
||||
<hr class="border-secondary mx-3">
|
||||
<a href="{{ route('reports.monthly') }}" class="{{ request()->routeIs('reports.*') ? 'active' : '' }}">
|
||||
<i class="bi bi-graph-up"></i> Reportes
|
||||
</a>
|
||||
<a href="{{ route('settings.index') }}" class="{{ request()->routeIs('settings.*') ? 'active' : '' }}">
|
||||
<i class="bi bi-gear"></i> Configuración
|
||||
</a>
|
||||
<a href="{{ route('telegram.verify') }}" class="{{ request()->routeIs('telegram.*') ? 'active' : '' }}">
|
||||
<i class="bi bi-telegram"></i> Telegram
|
||||
</a>
|
||||
<hr class="border-secondary mx-3">
|
||||
<form method="POST" action="{{ route('logout') }}" class="px-3">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-link text-white w-100 text-start p-2">
|
||||
<i class="bi bi-box-arrow-right"></i> Cerrar Sesión
|
||||
</button>
|
||||
</form>
|
||||
</nav>
|
||||
</nav>
|
||||
|
||||
<!-- Main content -->
|
||||
<main class="col-md-10 ms-sm-auto px-4 py-4">
|
||||
<!-- Mobile Header -->
|
||||
<div class="d-md-none mb-4">
|
||||
<div class="card">
|
||||
<div class="card-body d-flex justify-content-between align-items-center">
|
||||
<span class="fw-bold">Nómina Pegaso</span>
|
||||
<button class="btn btn-outline-primary btn-sm" id="mobileNavBtn2">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@yield('content')
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
@yield('content')
|
||||
@endauth
|
||||
|
||||
<!-- Toast Container -->
|
||||
<div class="toast-container">
|
||||
@if(session('success'))
|
||||
<div class="toast show" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-success text-white">
|
||||
<strong class="me-auto"><i class="bi bi-check-circle"></i> Éxito</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast"></button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(session('error'))
|
||||
<div class="toast show" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-danger text-white">
|
||||
<strong class="me-auto"><i class="bi bi-exclamation-circle"></i> Error</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast"></button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.10/index.global.min.js"></script>
|
||||
<script src="{{ asset('js/app.js') }}"></script>
|
||||
|
||||
@stack('scripts')
|
||||
</body>
|
||||
</html>
|
||||
35
resources/views/layouts/guest.blade.php
Executable file
35
resources/views/layouts/guest.blade.php
Executable file
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>@yield('title', 'Nómina Pegaso')</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.auth-card {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
||||
}
|
||||
</style>
|
||||
@stack('styles')
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center align-items-center min-vh-100">
|
||||
<div class="col-md-6 col-lg-5">
|
||||
@yield('content')
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
@stack('scripts')
|
||||
</body>
|
||||
</html>
|
||||
53
resources/views/months/create.blade.php
Executable file
53
resources/views/months/create.blade.php
Executable file
@@ -0,0 +1,53 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Crear Mes')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Crear Nuevo Mes</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('months.store') }}">
|
||||
@csrf
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Nombre del Mes</label>
|
||||
<select class="form-select" id="name" name="name" required>
|
||||
<option value="">Selecciona un mes</option>
|
||||
<option value="Enero">Enero</option>
|
||||
<option value="Febrero">Febrero</option>
|
||||
<option value="Marzo">Marzo</option>
|
||||
<option value="Abril">Abril</option>
|
||||
<option value="Mayo">Mayo</option>
|
||||
<option value="Junio">Junio</option>
|
||||
<option value="Julio">Julio</option>
|
||||
<option value="Agosto">Agosto</option>
|
||||
<option value="Septiembre">Septiembre</option>
|
||||
<option value="Octubre">Octubre</option>
|
||||
<option value="Noviembre">Noviembre</option>
|
||||
<option value="Diciembre">Diciembre</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="year" class="form-label">Año</label>
|
||||
<input type="number" class="form-control" id="year" name="year"
|
||||
value="{{ old('year', now()->year) }}" min="2020" max="2100" required>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-success">Crear Mes</button>
|
||||
<a href="{{ route('months.index') }}" class="btn btn-secondary">Cancelar</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
53
resources/views/months/edit.blade.php
Executable file
53
resources/views/months/edit.blade.php
Executable file
@@ -0,0 +1,53 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Editar Mes')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Editar Mes</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('months.update', $month->id) }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Nombre del Mes</label>
|
||||
<select class="form-select" id="name" name="name" required>
|
||||
@foreach(['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'] as $m)
|
||||
<option value="{{ $m }}" {{ $month->name == $m ? 'selected' : '' }}>{{ $m }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="year" class="form-label">Año</label>
|
||||
<input type="number" class="form-control" id="year" name="year"
|
||||
value="{{ old('year', $month->year) }}" min="2020" max="2100" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="status" class="form-label">Estado</label>
|
||||
<select class="form-select" id="status" name="status" required>
|
||||
<option value="open" {{ $month->status == 'open' ? 'selected' : '' }}>Abierto</option>
|
||||
<option value="closed" {{ $month->status == 'closed' ? 'selected' : '' }}>Cerrado</option>
|
||||
<option value="paid" {{ $month->status == 'paid' ? 'selected' : '' }}>Pagado</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">Actualizar</button>
|
||||
<a href="{{ route('months.show', $month->id) }}" class="btn btn-secondary">Cancelar</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
58
resources/views/months/index.blade.php
Executable file
58
resources/views/months/index.blade.php
Executable file
@@ -0,0 +1,58 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Meses')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Meses de Trabajo</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<a href="{{ route('months.create') }}" class="btn btn-primary">
|
||||
<i class="bi bi-plus-circle"></i> Crear Nuevo Mes
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lista de meses -->
|
||||
<div class="row">
|
||||
@forelse($months as $month)
|
||||
<div class="col-md-4 col-lg-3 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">{{ $month->name }} {{ $month->year }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="mb-1">
|
||||
<strong>Estado:</strong>
|
||||
@if($month->status === 'open')
|
||||
<span class="badge bg-success">Abierto</span>
|
||||
@elseif($month->status === 'closed')
|
||||
<span class="badge bg-warning">Cerrado</span>
|
||||
@else
|
||||
<span class="badge bg-info">Pagado</span>
|
||||
@endif
|
||||
</p>
|
||||
<p class="mb-1"><small class="text-muted">Ventas: ${{ number_format($month->dailySales()->sum('user_sales'), 2) }}</small></p>
|
||||
<p class="mb-0"><small class="text-muted">Gastos: ${{ number_format($month->expenses()->sum('amount'), 2) }}</small></p>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<a href="{{ route('months.show', $month->id) }}" class="btn btn-sm btn-primary">Ver Detalles</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
No hay meses registrados.
|
||||
<a href="{{ route('months.create') }}">Crea tu primer mes</a>
|
||||
</div>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
{{ $months->links() }}
|
||||
@endsection
|
||||
142
resources/views/months/show.blade.php
Executable file
142
resources/views/months/show.blade.php
Executable file
@@ -0,0 +1,142 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Detalles del Mes')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">
|
||||
{{ $month->name }} {{ $month->year }}
|
||||
@if($month->status === 'open')
|
||||
<span class="badge bg-success">Abierto</span>
|
||||
@elseif($month->status === 'closed')
|
||||
<span class="badge bg-warning">Cerrado</span>
|
||||
@else
|
||||
<span class="badge bg-info">Pagado</span>
|
||||
@endif
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Resumen -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card primary">
|
||||
<div class="card-body">
|
||||
<h6>Ventas Usuario</h6>
|
||||
<h4>${{ number_format($month->dailySales()->sum('user_sales'), 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card success">
|
||||
<div class="card-body">
|
||||
<h6>Ventas Sistema</h6>
|
||||
<h4>${{ number_format($month->dailySales()->sum('system_sales'), 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card warning">
|
||||
<div class="card-body">
|
||||
<h6>Total Gastos</h6>
|
||||
<h4>${{ number_format($month->expenses()->sum('amount'), 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card danger">
|
||||
<div class="card-body">
|
||||
<h6>Días Registrados</h6>
|
||||
<h4>{{ $month->dailySales()->count() }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Acciones -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<a href="{{ route('sales.create', ['month_id' => $month->id]) }}" class="btn btn-success">
|
||||
<i class="bi bi-plus-circle"></i> Agregar Venta
|
||||
</a>
|
||||
<a href="{{ route('expenses.create', ['month_id' => $month->id]) }}" class="btn btn-warning">
|
||||
<i class="bi bi-plus-circle"></i> Agregar Gasto
|
||||
</a>
|
||||
<a href="{{ route('reports.monthly', ['month_id' => $month->id]) }}" class="btn btn-info">
|
||||
<i class="bi bi-graph-up"></i> Ver Reporte
|
||||
</a>
|
||||
|
||||
@if($month->status === 'open')
|
||||
<form method="POST" action="{{ route('months.close', $month->id) }}" class="d-inline">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-outline-danger" onclick="return confirm('¿Cerrar este mes?')">
|
||||
<i class="bi bi-lock"></i> Cerrar Mes
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Últimas ventas -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Últimas Ventas</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Fecha</th>
|
||||
<th>Venta Usuario</th>
|
||||
<th>Venta Sistema</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($month->dailySales()->latest()->limit(10)->get() as $sale)
|
||||
<tr>
|
||||
<td>{{ $sale->date->format('d/m/Y') }}</td>
|
||||
<td>${{ number_format($sale->user_sales, 2) }}</td>
|
||||
<td>${{ number_format($sale->system_sales, 2) }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="3" class="text-center">No hay ventas</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Últimos gastos -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Últimos Gastos</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Fecha</th>
|
||||
<th>Descripción</th>
|
||||
<th>Monto</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($month->expenses()->latest()->limit(10)->get() as $expense)
|
||||
<tr>
|
||||
<td>{{ $expense->date->format('d/m/Y') }}</td>
|
||||
<td>{{ $expense->description }}</td>
|
||||
<td class="text-danger">${{ number_format($expense->amount, 2) }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="3" class="text-center">No hay gastos</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="{{ route('months.index') }}" class="btn btn-secondary">Volver a Meses</a>
|
||||
</div>
|
||||
@endsection
|
||||
131
resources/views/reports/biweekly.blade.php
Executable file
131
resources/views/reports/biweekly.blade.php
Executable file
@@ -0,0 +1,131 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Reporte Quincenal')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Reporte Quincenal</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Selector -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-4">
|
||||
<form method="GET" class="d-flex gap-2">
|
||||
<select name="month_id" class="form-select" onchange="this.form.submit()">
|
||||
@foreach($months as $m)
|
||||
<option value="{{ $m->id }}" {{ $month->id == $m->id ? 'selected' : '' }}>
|
||||
{{ $m->name }} {{ $m->year }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<form method="GET" class="d-flex gap-2">
|
||||
<input type="hidden" name="month_id" value="{{ $month->id }}">
|
||||
<select name="biweekly" class="form-select" onchange="this.form.submit()">
|
||||
<option value="1" {{ $biweekly == 1 ? 'selected' : '' }}>1ra Quincena (1-15) - ANTICIPO</option>
|
||||
<option value="2" {{ $biweekly == 2 ? 'selected' : '' }}>2da Quincena (16-31) - LIQUIDACIÓN</option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-4 text-end">
|
||||
<a href="{{ route('reports.monthly', ['month_id' => $month->id]) }}" class="btn btn-outline-primary">Ver Mensual</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($report)
|
||||
<!-- Resumen Quincenal -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card {{ $report['type'] === 'anticipo' ? 'border-success' : 'border-warning' }}">
|
||||
<div class="card-header {{ $report['type'] === 'anticipo' ? 'bg-success' : 'bg-warning' }} text-white">
|
||||
<h5 class="mb-0">{{ $report['period'] }}</h5>
|
||||
<small>{{ $report['description'] }}</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row text-center">
|
||||
@if($report['type'] === 'anticipo')
|
||||
<div class="col-md-4">
|
||||
<h6 class="text-muted">Mitad Sueldo</h6>
|
||||
<h3>${{ number_format($report['biweekly_salary'], 2) }}</h3>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h6 class="text-muted">Comisiones del Mes</h6>
|
||||
<h3 class="text-success">+${{ number_format($report['commission_amount'], 2) }}</h3>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h6 class="text-muted">Total ANTICIPO</h6>
|
||||
<h2 class="text-success">${{ number_format($report['total_earning'], 2) }}</h2>
|
||||
</div>
|
||||
@else
|
||||
<div class="col-md-4">
|
||||
<h6 class="text-muted">Mitad Sueldo</h6>
|
||||
<h3>${{ number_format($report['biweekly_salary'], 2) }}</h3>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h6 class="text-muted">Gastos Q{{ $biweekly }}</h6>
|
||||
<h3 class="text-danger">-${{ number_format($report['expenses_q2'], 2) }}</h3>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h6 class="text-muted">Total LIQUIDACIÓN</h6>
|
||||
<h2 class="{{ $report['total_earning'] >= 0 ? 'text-success' : 'text-danger' }}">${{ number_format($report['total_earning'], 2) }}</h2>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Desglose de gastos -->
|
||||
@if(count($expenses) > 0)
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Gastos de la Quincena</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Fecha</th>
|
||||
<th>Descripción</th>
|
||||
<th>Tipo</th>
|
||||
<th class="text-end">Monto</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($expenses as $expense)
|
||||
<tr>
|
||||
<td>{{ $expense->date->format('d/m/Y') }}</td>
|
||||
<td>{{ $expense->description }}</td>
|
||||
<td>
|
||||
@if($expense->expense_type == 'q1')
|
||||
<span class="badge bg-primary">Q1</span>
|
||||
@elseif($expense->expense_type == 'q2')
|
||||
<span class="badge bg-warning">Q2</span>
|
||||
@else
|
||||
<span class="badge bg-info">Mensual (mitad)</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="text-end text-danger">${{ number_format($expense->expense_type == 'mensual' ? $expense->amount / 2 : $expense->amount, 2) }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@else
|
||||
<div class="alert alert-warning">No hay datos para mostrar.</div>
|
||||
@endif
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<a href="{{ route('dashboard') }}" class="btn btn-secondary">← Volver al Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
199
resources/views/reports/monthly.blade.php
Executable file
199
resources/views/reports/monthly.blade.php
Executable file
@@ -0,0 +1,199 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Reporte Mensual')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Reporte Mensual</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Selector -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<form method="GET" class="d-flex gap-2">
|
||||
<select name="month_id" class="form-select" onchange="this.form.submit()">
|
||||
@foreach($months as $m)
|
||||
<option value="{{ $m->id }}" {{ $month->id == $m->id ? 'selected' : '' }}>
|
||||
{{ $m->name }} {{ $m->year }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<a href="{{ route('reports.biweekly', ['month_id' => $month->id, 'biweekly' => 1]) }}" class="btn btn-outline-primary">Quincenal</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($report)
|
||||
<!-- Resumen General -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">{{ $report['month_name'] }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<h6 class="text-muted">Ventas del Usuario</h6>
|
||||
<h4>${{ number_format($report['total_user_sales'], 2) }}</h4>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h6 class="text-muted">Ventas del Sistema</h6>
|
||||
<h4>${{ number_format($report['total_system_sales'], 2) }}</h4>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h6 class="text-muted">Comisión ({{ $report['commission_percentage'] }}%)</h6>
|
||||
<h4 class="text-success">${{ number_format($report['commission_amount'], 2) }}</h4>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h6 class="text-muted">Total a Recibir</h6>
|
||||
<h4 class="text-primary">${{ number_format($report['total_earning'], 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Detalles -->
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Desglose</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td>Salario Mensual</td>
|
||||
<td class="text-end">${{ number_format($report['monthly_salary'], 2) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Comisión ({{ $report['commission_percentage'] }}%)</td>
|
||||
<td class="text-end text-success">+${{ number_format($report['commission_amount'], 2) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Gastos del Mes</td>
|
||||
<td class="text-end text-danger">-${{ number_format($report['total_expenses'], 2) }}</td>
|
||||
</tr>
|
||||
<tr class="table-light">
|
||||
<td><strong>Total a Recibir</strong></td>
|
||||
<td class="text-end"><strong>${{ number_format($report['total_earning'], 2) }}</strong></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Diferencia de Ventas</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if($report['has_difference'])
|
||||
<div class="alert alert-{{ $report['sales_difference'] > 0 ? 'warning' : 'danger' }}">
|
||||
<strong>Diferencia:</strong> ${{ number_format($report['sales_difference'], 2) }}
|
||||
<br>
|
||||
<small>
|
||||
{{ $report['sales_difference'] > 0 ? 'Ventas del usuario mayores que sistema' : 'Ventas del sistema mayores que usuario' }}
|
||||
</small>
|
||||
</div>
|
||||
@else
|
||||
<div class="alert alert-success">
|
||||
<i class="bi bi-check-circle"></i> Ventas conciliadas (sin diferencia)
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ventas Diarias -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Ventas Diarias</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Fecha</th>
|
||||
<th class="text-end">Venta Usuario</th>
|
||||
<th class="text-end">Venta Sistema</th>
|
||||
<th class="text-end">Diferencia</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($dailySales as $sale)
|
||||
<tr>
|
||||
<td>{{ $sale->date->format('d/m/Y') }}</td>
|
||||
<td class="text-end">${{ number_format($sale->user_sales, 2) }}</td>
|
||||
<td class="text-end">${{ number_format($sale->system_sales, 2) }}</td>
|
||||
<td class="text-end">
|
||||
@php $diff = $sale->user_sales - $sale->system_sales; @endphp
|
||||
@if($diff != 0)
|
||||
<span class="text-{{ $diff > 0 ? 'warning' : 'danger' }}">
|
||||
${{ number_format($diff, 2) }}
|
||||
</span>
|
||||
@else
|
||||
<span class="text-success">-</span>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="4" class="text-center">No hay ventas</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="table-light">
|
||||
<th>Total</th>
|
||||
<th class="text-end">${{ number_format($dailySales->sum('user_sales'), 2) }}</th>
|
||||
<th class="text-end">${{ number_format($dailySales->sum('system_sales'), 2) }}</th>
|
||||
<th class="text-end">${{ number_format($dailySales->sum('user_sales') - $dailySales->sum('system_sales'), 2) }}</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gastos -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Gastos del Mes</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Fecha</th>
|
||||
<th>Descripción</th>
|
||||
<th class="text-end">Monto</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($expenses as $expense)
|
||||
<tr>
|
||||
<td>{{ $expense->date->format('d/m/Y') }}</td>
|
||||
<td>{{ $expense->description }}</td>
|
||||
<td class="text-end text-danger">${{ number_format($expense->amount, 2) }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="3" class="text-center">No hay gastos</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="table-light">
|
||||
<th colspan="2">Total Gastos</th>
|
||||
<th class="text-end">${{ number_format($expenses->sum('amount'), 2) }}</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="alert alert-warning">No hay datos disponibles para este mes.</div>
|
||||
@endif
|
||||
@endsection
|
||||
109
resources/views/reports/yearly.blade.php
Executable file
109
resources/views/reports/yearly.blade.php
Executable file
@@ -0,0 +1,109 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Reporte Anual')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Reporte Anual</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Selector de año -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-4">
|
||||
<form method="GET" class="d-flex gap-2">
|
||||
<select name="year" class="form-select" onchange="this.form.submit()">
|
||||
@foreach($years as $y)
|
||||
<option value="{{ $y }}" {{ $year == $y ? 'selected' : '' }}>{{ $y }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($report)
|
||||
<!-- Resumen Anual -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark text-white">
|
||||
<h5 class="mb-0">Resumen del Año {{ $year }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<h6 class="text-muted">Meses</h6>
|
||||
<h4>{{ $report['months_count'] }}</h4>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<h6 class="text-muted">Ventas Usuario</h6>
|
||||
<h4>${{ number_format($report['total_user_sales'], 0) }}</h4>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<h6 class="text-muted">Ventas Sistema</h6>
|
||||
<h4>${{ number_format($report['total_system_sales'], 0) }}</h4>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<h6 class="text-muted">Total Salario</h6>
|
||||
<h4>${{ number_format($report['total_salary'], 2) }}</h4>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<h6 class="text-muted">Total Comisión</h6>
|
||||
<h4 class="text-success">${{ number_format($report['total_commission'], 2) }}</h4>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<h6 class="text-muted">Total Año</h6>
|
||||
<h4 class="text-primary">${{ number_format($report['total_earning'], 2) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Meses del año -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Detalle por Mes</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Mes</th>
|
||||
<th class="text-end">Ventas Usuario</th>
|
||||
<th class="text-end">Ventas Sistema</th>
|
||||
<th class="text-end">Gastos</th>
|
||||
<th class="text-end">Comisión</th>
|
||||
<th class="text-end">Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($months as $month)
|
||||
@php
|
||||
$userSales = $month->dailySales()->sum('user_sales');
|
||||
$systemSales = $month->dailySales()->sum('system_sales');
|
||||
$expenses = $month->expenses()->sum('amount');
|
||||
$commission = ($systemSales * auth()->user()->commission_percentage) / 100;
|
||||
$total = auth()->user()->monthly_salary + $commission - $expenses;
|
||||
@endphp
|
||||
<tr>
|
||||
<td>{{ $month->name }}</td>
|
||||
<td class="text-end">${{ number_format($userSales, 2) }}</td>
|
||||
<td class="text-end">${{ number_format($systemSales, 2) }}</td>
|
||||
<td class="text-end text-danger">${{ number_format($expenses, 2) }}</td>
|
||||
<td class="text-end text-success">${{ number_format($commission, 2) }}</td>
|
||||
<td class="text-end"><strong>${{ number_format($total, 2) }}</strong></td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="6" class="text-center">No hay meses en este año</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="alert alert-warning">No hay datos disponibles para este año.</div>
|
||||
@endif
|
||||
@endsection
|
||||
54
resources/views/sales/create.blade.php
Executable file
54
resources/views/sales/create.blade.php
Executable file
@@ -0,0 +1,54 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Nueva Venta')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Nueva Venta</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('sales.store') }}">
|
||||
@csrf
|
||||
<input type="hidden" name="month_id" value="{{ $month->id }}">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="date" class="form-label">Fecha</label>
|
||||
<input type="date" class="form-control" id="date" name="date"
|
||||
value="{{ old('date', now()->format('Y-m-d')) }}" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="user_sales" class="form-label">Ventas del Usuario</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="user_sales" name="user_sales"
|
||||
value="{{ old('user_sales') }}" step="0.01" min="0" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="system_sales" class="form-label">Ventas del Sistema (Opcional)</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="system_sales" name="system_sales"
|
||||
value="{{ old('system_sales', 0) }}" step="0.01" min="0">
|
||||
</div>
|
||||
<small class="text-muted">Ventas consolidadas del sistema</small>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-success">Guardar Venta</button>
|
||||
<a href="{{ route('sales.index', ['month_id' => $month->id]) }}" class="btn btn-secondary">Cancelar</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
53
resources/views/sales/edit.blade.php
Executable file
53
resources/views/sales/edit.blade.php
Executable file
@@ -0,0 +1,53 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Editar Venta')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Editar Venta</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('sales.update', $sale->id) }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="date" class="form-label">Fecha</label>
|
||||
<input type="date" class="form-control" id="date" name="date"
|
||||
value="{{ old('date', $sale->date->format('Y-m-d')) }}" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="user_sales" class="form-label">Ventas del Usuario</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="user_sales" name="user_sales"
|
||||
value="{{ old('user_sales', $sale->user_sales) }}" step="0.01" min="0" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="system_sales" class="form-label">Ventas del Sistema</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="system_sales" name="system_sales"
|
||||
value="{{ old('system_sales', $sale->system_sales) }}" step="0.01" min="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">Actualizar</button>
|
||||
<a href="{{ route('sales.index', ['month_id' => $sale->month_id]) }}" class="btn btn-secondary">Cancelar</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
109
resources/views/sales/index.blade.php
Executable file
109
resources/views/sales/index.blade.php
Executable file
@@ -0,0 +1,109 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Ventas')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Gestión de Ventas</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Selector de mes -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<form method="GET" class="d-flex gap-2">
|
||||
<select name="month_id" class="form-select" onchange="this.form.submit()">
|
||||
@foreach($months as $m)
|
||||
<option value="{{ $m->id }}" {{ $month->id == $m->id ? 'selected' : '' }}>
|
||||
{{ $m->name }} {{ $m->year }} ({{ $m->status }})
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<a href="{{ route('sales.create', ['month_id' => $month->id]) }}" class="btn btn-success">
|
||||
<i class="bi bi-plus-circle"></i> Nueva Venta
|
||||
</a>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6 text-end">
|
||||
<div class="btn-group">
|
||||
<a href="{{ route('sales.index', ['month_id' => $month->id]) }}" class="btn btn-outline-secondary">Todas</a>
|
||||
<a href="{{ route('expenses.index', ['month_id' => $month->id]) }}" class="btn btn-outline-warning">Ver Gastos</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Resumen -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Total Ventas Usuario</h6>
|
||||
<h3>${{ number_format($month->dailySales()->sum('user_sales'), 2) }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Total Ventas Sistema</h6>
|
||||
<h3>${{ number_format($month->dailySales()->sum('system_sales'), 2) }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lista de ventas -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Fecha</th>
|
||||
<th>Venta Usuario</th>
|
||||
<th>Venta Sistema</th>
|
||||
<th>Diferencia</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($sales as $sale)
|
||||
<tr>
|
||||
<td>{{ $sale->date->format('d/m/Y') }}</td>
|
||||
<td>${{ number_format($sale->user_sales, 2) }}</td>
|
||||
<td>${{ number_format($sale->system_sales, 2) }}</td>
|
||||
<td>
|
||||
@php $diff = $sale->user_sales - $sale->system_sales; @endphp
|
||||
@if($diff != 0)
|
||||
<span class="badge bg-{{ $diff > 0 ? 'warning' : 'danger' }}">
|
||||
${{ number_format($diff, 2) }}
|
||||
</span>
|
||||
@else
|
||||
<span class="badge bg-success">conciliada</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('sales.edit', $sale->id) }}" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<form method="POST" action="{{ route('sales.destroy', $sale->id) }}" class="d-inline">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" onclick="return confirm('¿Eliminar esta venta?')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="5" class="text-center text-muted">No hay ventas registradas.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{{ $sales->links() }}
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
257
resources/views/settings/index.blade.php
Executable file
257
resources/views/settings/index.blade.php
Executable file
@@ -0,0 +1,257 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Configuración')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">
|
||||
<i class="bi bi-gear text-primary"></i> Configuración
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<!-- Datos Laborales -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-briefcase"></i> Datos Laborales
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('settings.update') }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="fecha_ingreso" class="form-label">Fecha de Ingreso</label>
|
||||
<input type="date" class="form-control" id="fecha_ingreso"
|
||||
name="fecha_ingreso"
|
||||
value="{{ old('fecha_ingreso', auth()->user()->fecha_ingreso?->format('Y-m-d')) }}">
|
||||
<small class="text-muted">Fecha en que started a trabajar en la empresa</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="razon_social" class="form-label">Razón Social</label>
|
||||
<input type="text" class="form-control" id="razon_social"
|
||||
name="razon_social"
|
||||
value="{{ old('razon_social', auth()->user()->razon_social) }}"
|
||||
placeholder="Empresa donde trabajas">
|
||||
<small class="text-muted">Nombre de la empresa o negocio</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="sueldo_integro_diario" class="form-label">Sueldo Íntegro Diario</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="sueldo_integro_diario"
|
||||
name="sueldo_integro_diario"
|
||||
value="{{ old('sueldo_integro_diario', auth()->user()->sueldo_integro_diario) }}"
|
||||
min="0" step="0.01">
|
||||
</div>
|
||||
<small class="text-muted">Salario diario integrado (para calcular vacaciones)</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@php($user = auth()->user())
|
||||
@if($user->fecha_ingreso)
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-calendar-check"></i>
|
||||
<strong>Antigüedad:</strong> {{ $user->fecha_ingreso->diffInYears(now()) }} año(s) y {{ $user->fecha_ingreso->diffInMonths(now()) % 12 }} mes(es)
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-save"></i> Guardar Datos Laborales
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Configuración de Comisión -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-percent"></i> Configuración de Comisión
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('settings.update') }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="commission_percentage" class="form-label">Porcentaje de Comisión (%)</label>
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="commission_percentage"
|
||||
name="commission_percentage"
|
||||
value="{{ old('commission_percentage', auth()->user()->commission_percentage) }}"
|
||||
min="0" max="100" step="0.01" required>
|
||||
<span class="input-group-text">%</span>
|
||||
</div>
|
||||
<small class="text-muted">Porcentaje que recibirás sobre tus ventas</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="monthly_salary" class="form-label">Salario Mensual Base</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="monthly_salary"
|
||||
name="monthly_salary"
|
||||
value="{{ old('monthly_salary', auth()->user()->monthly_salary) }}"
|
||||
min="0" step="0.01" required>
|
||||
</div>
|
||||
<small class="text-muted">Salario base mensual sin comisiones</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i>
|
||||
<strong>Nota:</strong> Estos valores se aplicarán a partir del próximo mes.
|
||||
Los meses actuales mantendrán su configuración original.
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-save"></i> Guardar Cambios
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cambiar Contraseña -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-secondary text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-key"></i> Cambiar Contraseña
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('settings.update') }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="current_password" class="form-label">Contraseña Actual</label>
|
||||
<input type="password" class="form-control" id="current_password"
|
||||
name="current_password">
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Nueva Contraseña</label>
|
||||
<input type="password" class="form-control" id="password"
|
||||
name="password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="password_confirmation" class="form-label">Confirmar Contraseña</label>
|
||||
<input type="password" class="form-control" id="password_confirmation"
|
||||
name="password_confirmation">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<small class="text-muted">Deja los campos de contraseña en blanco si no deseas cambiarlo.</small>
|
||||
|
||||
<div class="mt-3">
|
||||
<button type="submit" class="btn btn-secondary">
|
||||
<i class="bi bi-key-fill"></i> Actualizar Contraseña
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<!-- Información del Usuario -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-dark text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-person"></i> Información del Usuario
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<dl class="row">
|
||||
<dt class="col-sm-4">Nombre:</dt>
|
||||
<dd class="col-sm-8">{{ auth()->user()->name }}</dd>
|
||||
|
||||
<dt class="col-sm-4">Email:</dt>
|
||||
<dd class="col-sm-8">{{ auth()->user()->email }}</dd>
|
||||
|
||||
@if(auth()->user()->razon_social)
|
||||
<dt class="col-sm-4">Empresa:</dt>
|
||||
<dd class="col-sm-8">{{ auth()->user()->razon_social }}</dd>
|
||||
@endif
|
||||
|
||||
@if(auth()->user()->fecha_ingreso)
|
||||
<dt class="col-sm-4">Ingreso:</dt>
|
||||
<dd class="col-sm-8">{{ auth()->user()->fecha_ingreso->format('d/m/Y') }}</dd>
|
||||
@endif
|
||||
|
||||
<dt class="col-sm-4">Comisión:</dt>
|
||||
<dd class="col-sm-8">
|
||||
<span class="badge bg-primary">{{ auth()->user()->commission_percentage }}%</span>
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-4">Salario:</dt>
|
||||
<dd class="col-sm-8">${{ number_format(auth()->user()->monthly_salary, 2) }}</dd>
|
||||
|
||||
<dt class="col-sm-4">Estado:</dt>
|
||||
<dd class="col-sm-8">
|
||||
@if(auth()->user()->is_active)
|
||||
<span class="badge bg-success">Activo</span>
|
||||
@else
|
||||
<span class="badge bg-danger">Inactivo</span>
|
||||
@endif
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ayuda -->
|
||||
<div class="card">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-question-circle"></i> Ayuda
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6>¿Cómo funciona la comisión?</h6>
|
||||
<p class="text-muted small">
|
||||
Tu salario se calcula sumando el salary base más el {{ auth()->user()->commission_percentage }}%
|
||||
de tus ventas del mes.
|
||||
</p>
|
||||
|
||||
<h6 class="mt-3">¿Qué son las ventas del sistema?</h6>
|
||||
<p class="text-muted small">
|
||||
Las ventas del sistema son las ventas consolidadas automáticamente.
|
||||
Si difieren de tus ventas, aparecerán en el reporte.
|
||||
</p>
|
||||
|
||||
<h6 class="mt-3">¿Puedo cambiar estos valores?</h6>
|
||||
<p class="text-muted small">
|
||||
Sí, pero los cambios se aplicarán al siguiente mes.
|
||||
Los meses actuales mantendrán su configuración.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
78
resources/views/telegram/verify.blade.php
Executable file
78
resources/views/telegram/verify.blade.php
Executable file
@@ -0,0 +1,78 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Vincular Telegram')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="mb-4">Vincular Cuenta de Telegram</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@if($telegramAccount->is_verified)
|
||||
<div class="alert alert-success">
|
||||
<h5><i class="bi bi-check-circle"></i> Cuenta Verificada</h5>
|
||||
<p>Tu cuenta de Telegram está vinculada correctamente.</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<strong>Chat ID:</strong> {{ $telegramAccount->chat_id }}
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('telegram.unlink') }}">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-danger" onclick="return confirm('¿Desvincular cuenta de Telegram?')">
|
||||
<i class="bi bi-unlink"></i> Desvincular Cuenta
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
<div class="alert alert-info">
|
||||
<h5><i class="bi bi-info-circle"></i> Vinculación de Telegram</h5>
|
||||
<p>Sigue estos pasos para vincular tu cuenta de Telegram:</p>
|
||||
<ol>
|
||||
<li>Abre Telegram y busca el bot de Nómina Pegaso</li>
|
||||
<li>Envía el código de verificación que aparece abajo</li>
|
||||
<li>Recibirás una confirmación cuando esté vinculado</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-4">
|
||||
<div class="card-body text-center">
|
||||
<h6 class="text-muted">Tu Código de Verificación</h6>
|
||||
<h1 class="display-4 text-primary">{{ $telegramAccount->verification_code }}</h1>
|
||||
<small class="text-muted">Este código expira cuando se genera uno nuevo</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('telegram.regenerate') }}">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-outline-primary">
|
||||
<i class="bi bi-arrow-clockwise"></i> Regenerar Código
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Información</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="small">Al vincular tu cuenta de Telegram podrás:</p>
|
||||
<ul class="small">
|
||||
<li>Recibir notificaciones de tus ventas</li>
|
||||
<li>Consultar tu estado de comisiones</li>
|
||||
<li>Recibir recordatorios de registro</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
225
resources/views/welcome.blade.php
Executable file
225
resources/views/welcome.blade.php
Executable file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user