- Aggiunte viste complete per ripartizioni-spesa: create, edit, show - Aggiunte viste complete per piani-rateizzazione: index, create, edit, show - Aggiunte viste complete per rate: index, create, edit, show - Interfacce responsive con Bootstrap 5 e componenti interattivi - Tabelle DataTables con filtri avanzati e ricerca - Form validation completa con Select2 e date picker - Grafici Chart.js per statistiche e monitoraggio - Funzionalità AJAX per calcoli automatici e aggiornamenti - Design mobile-first con sidebar navigation aggiornata - Tutte le viste pronte per integrazione con controller esistenti
456 lines
21 KiB
PHP
456 lines
21 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('title', 'Dettaglio Piano di Rateizzazione')
|
|
|
|
@section('content')
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="card-title">Dettaglio Piano di Rateizzazione</h3>
|
|
<div class="card-tools">
|
|
@can('update', $piano)
|
|
<a href="{{ route('admin.piani-rateizzazione.edit', $piano->id) }}" class="btn btn-primary btn-sm">
|
|
<i class="fas fa-edit"></i> Modifica
|
|
</a>
|
|
@endcan
|
|
<a href="{{ route('admin.piani-rateizzazione.index') }}" class="btn btn-default btn-sm">
|
|
<i class="fas fa-arrow-left"></i> Torna all'elenco
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="info-box">
|
|
<span class="info-box-icon bg-primary"><i class="fas fa-calendar-alt"></i></span>
|
|
<div class="info-box-content">
|
|
<span class="info-box-text">Denominazione</span>
|
|
<span class="info-box-number">{{ $piano->denominazione }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="info-box">
|
|
<span class="info-box-icon bg-info"><i class="fas fa-receipt"></i></span>
|
|
<div class="info-box-content">
|
|
<span class="info-box-text">Ripartizione Spesa</span>
|
|
<span class="info-box-number">
|
|
<a href="{{ route('admin.ripartizioni-spesa.show', $piano->ripartizione->id) }}" class="text-info">
|
|
{{ $piano->ripartizione->voceSpesa->codice }}
|
|
</a>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="info-box">
|
|
<span class="info-box-icon bg-success"><i class="fas fa-list-ol"></i></span>
|
|
<div class="info-box-content">
|
|
<span class="info-box-text">Numero Rate</span>
|
|
<span class="info-box-number">{{ $piano->numero_rate }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3">
|
|
<div class="info-box">
|
|
<span class="info-box-icon bg-warning"><i class="fas fa-euro-sign"></i></span>
|
|
<div class="info-box-content">
|
|
<span class="info-box-text">Importo Totale</span>
|
|
<span class="info-box-number">€ {{ number_format($piano->importo_totale, 2, ',', '.') }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3">
|
|
<div class="info-box">
|
|
<span class="info-box-icon bg-secondary"><i class="fas fa-clock"></i></span>
|
|
<div class="info-box-content">
|
|
<span class="info-box-text">Tipo Scadenza</span>
|
|
<span class="info-box-number">{{ ucfirst($piano->tipo_scadenza) }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3">
|
|
<div class="info-box">
|
|
<span class="info-box-icon bg-{{ $piano->stato == 'attivo' ? 'success' : ($piano->stato == 'completato' ? 'primary' : ($piano->stato == 'sospeso' ? 'warning' : 'secondary')) }}">
|
|
<i class="fas fa-{{ $piano->stato == 'attivo' ? 'play' : ($piano->stato == 'completato' ? 'check' : ($piano->stato == 'sospeso' ? 'pause' : 'stop')) }}"></i>
|
|
</span>
|
|
<div class="info-box-content">
|
|
<span class="info-box-text">Stato</span>
|
|
<span class="info-box-number">{{ ucfirst($piano->stato) }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label>Data Inizio</label>
|
|
<p class="form-control-plaintext">{{ $piano->data_inizio->format('d/m/Y') }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label>Data Fine</label>
|
|
<p class="form-control-plaintext">{{ $piano->data_fine ? $piano->data_fine->format('d/m/Y') : 'Non definita' }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label>Stabile</label>
|
|
<p class="form-control-plaintext">{{ $piano->ripartizione->stabile->denominazione }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label>Tasso Interesse</label>
|
|
<p class="form-control-plaintext">{{ $piano->tasso_interesse ?? 0 }}%</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label>Spese Gestione</label>
|
|
<p class="form-control-plaintext">€ {{ number_format($piano->spese_gestione ?? 0, 2, ',', '.') }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@if($piano->note)
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="form-group">
|
|
<label>Note</label>
|
|
<p class="form-control-plaintext">{{ $piano->note }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="form-group">
|
|
<label>Audit</label>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<tr>
|
|
<th>Creato il:</th>
|
|
<td>{{ $piano->created_at->format('d/m/Y H:i:s') }}</td>
|
|
</tr>
|
|
<tr>
|
|
<th>Ultima modifica:</th>
|
|
<td>{{ $piano->updated_at->format('d/m/Y H:i:s') }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Rate -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="card-title">Rate del Piano</h3>
|
|
<div class="card-tools">
|
|
@if($piano->stato == 'bozza')
|
|
<button type="button" class="btn btn-success btn-sm" id="btn-genera-rate">
|
|
<i class="fas fa-cogs"></i> Genera Rate
|
|
</button>
|
|
@endif
|
|
<button type="button" class="btn btn-info btn-sm" data-toggle="modal" data-target="#modal-statistiche">
|
|
<i class="fas fa-chart-bar"></i> Statistiche
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
@if($piano->rate->count() > 0)
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered table-striped" id="rate-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Numero</th>
|
|
<th>Data Scadenza</th>
|
|
<th>Importo</th>
|
|
<th>Interessi</th>
|
|
<th>Spese</th>
|
|
<th>Totale</th>
|
|
<th>Stato</th>
|
|
<th>Data Pagamento</th>
|
|
<th>Importo Pagato</th>
|
|
<th>Note</th>
|
|
<th>Azioni</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($piano->rate as $rata)
|
|
<tr class="{{ $rata->data_scadenza->isPast() && $rata->stato != 'pagata' ? 'table-danger' : '' }}">
|
|
<td>{{ $rata->numero_rata }}</td>
|
|
<td>{{ $rata->data_scadenza->format('d/m/Y') }}</td>
|
|
<td>€ {{ number_format($rata->importo, 2, ',', '.') }}</td>
|
|
<td>€ {{ number_format($rata->importo_interessi, 2, ',', '.') }}</td>
|
|
<td>€ {{ number_format($rata->importo_spese, 2, ',', '.') }}</td>
|
|
<td><strong>€ {{ number_format($rata->importo_totale, 2, ',', '.') }}</strong></td>
|
|
<td>
|
|
<span class="badge badge-{{ $rata->stato == 'pagata' ? 'success' : ($rata->stato == 'scaduta' ? 'danger' : 'warning') }}">
|
|
{{ ucfirst($rata->stato) }}
|
|
</span>
|
|
</td>
|
|
<td>{{ $rata->data_pagamento ? $rata->data_pagamento->format('d/m/Y') : '-' }}</td>
|
|
<td>€ {{ number_format($rata->importo_pagato, 2, ',', '.') }}</td>
|
|
<td>{{ $rata->note ?? '-' }}</td>
|
|
<td>
|
|
<div class="btn-group">
|
|
<a href="{{ route('admin.rate.show', $rata->id) }}" class="btn btn-sm btn-info">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
<a href="{{ route('admin.rate.edit', $rata->id) }}" class="btn btn-sm btn-primary">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
@if($rata->stato != 'pagata')
|
|
<button type="button" class="btn btn-sm btn-success" onclick="marcaPagata({{ $rata->id }})">
|
|
<i class="fas fa-check"></i>
|
|
</button>
|
|
@endif
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
<tfoot>
|
|
<tr class="table-info">
|
|
<th>Totale</th>
|
|
<th>-</th>
|
|
<th>€ {{ number_format($piano->rate->sum('importo'), 2, ',', '.') }}</th>
|
|
<th>€ {{ number_format($piano->rate->sum('importo_interessi'), 2, ',', '.') }}</th>
|
|
<th>€ {{ number_format($piano->rate->sum('importo_spese'), 2, ',', '.') }}</th>
|
|
<th>€ {{ number_format($piano->rate->sum('importo_totale'), 2, ',', '.') }}</th>
|
|
<th>-</th>
|
|
<th>-</th>
|
|
<th>€ {{ number_format($piano->rate->sum('importo_pagato'), 2, ',', '.') }}</th>
|
|
<th colspan="2">-</th>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
@else
|
|
<div class="alert alert-info">
|
|
<i class="fas fa-info-circle"></i> Nessuna rata trovata per questo piano.
|
|
@if($piano->stato == 'bozza')
|
|
Clicca su "Genera Rate" per creare le rate automaticamente.
|
|
@endif
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Progress Bar -->
|
|
@if($piano->rate->count() > 0)
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="card-title">Progresso Pagamenti</h3>
|
|
</div>
|
|
<div class="card-body">
|
|
@php
|
|
$ratePagate = $piano->rate->where('stato', 'pagata')->count();
|
|
$totalRate = $piano->rate->count();
|
|
$percentuale = $totalRate > 0 ? ($ratePagate / $totalRate) * 100 : 0;
|
|
@endphp
|
|
<div class="progress mb-3">
|
|
<div class="progress-bar bg-success" role="progressbar" style="width: {{ $percentuale }}%" aria-valuenow="{{ $percentuale }}" aria-valuemin="0" aria-valuemax="100">
|
|
{{ round($percentuale, 1) }}%
|
|
</div>
|
|
</div>
|
|
<p class="text-muted">Rate pagate: {{ $ratePagate }} su {{ $totalRate }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<!-- Modal Statistiche -->
|
|
<div class="modal fade" id="modal-statistiche" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-lg" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">Statistiche Piano di Rateizzazione</h4>
|
|
<button type="button" class="close" data-dismiss="modal">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<canvas id="chart-stati-rate"></canvas>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<canvas id="chart-importi-rate"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('scripts')
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Initialize DataTable
|
|
$('#rate-table').DataTable({
|
|
responsive: true,
|
|
lengthChange: false,
|
|
autoWidth: false,
|
|
order: [[0, 'asc']],
|
|
language: {
|
|
url: '//cdn.datatables.net/plug-ins/1.10.25/i18n/Italian.json'
|
|
}
|
|
});
|
|
|
|
// Genera rate
|
|
$('#btn-genera-rate').click(function() {
|
|
if (confirm('Sei sicuro di voler generare le rate? Eventuali rate esistenti verranno sovrascritte.')) {
|
|
$.ajax({
|
|
url: '{{ route("admin.piani-rateizzazione.genera-rate", $piano->id) }}',
|
|
type: 'POST',
|
|
data: {
|
|
_token: '{{ csrf_token() }}'
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Errore nella generazione delle rate: ' + response.message);
|
|
}
|
|
},
|
|
error: function() {
|
|
alert('Errore nella generazione delle rate');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Charts for modal
|
|
$('#modal-statistiche').on('shown.bs.modal', function() {
|
|
// Chart Stati Rate
|
|
var ctxStati = document.getElementById('chart-stati-rate').getContext('2d');
|
|
new Chart(ctxStati, {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: ['Da Pagare', 'Pagate', 'Scadute'],
|
|
datasets: [{
|
|
data: [
|
|
{{ $piano->rate->where('stato', 'da_pagare')->count() }},
|
|
{{ $piano->rate->where('stato', 'pagata')->count() }},
|
|
{{ $piano->rate->where('stato', 'scaduta')->count() }}
|
|
],
|
|
backgroundColor: ['#ffc107', '#28a745', '#dc3545']
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: {
|
|
title: {
|
|
display: true,
|
|
text: 'Stati Rate'
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Chart Importi Rate
|
|
var ctxImporti = document.getElementById('chart-importi-rate').getContext('2d');
|
|
new Chart(ctxImporti, {
|
|
type: 'line',
|
|
data: {
|
|
labels: [
|
|
@foreach($piano->rate as $rata)
|
|
'{{ $rata->numero_rata }}',
|
|
@endforeach
|
|
],
|
|
datasets: [{
|
|
label: 'Importo Totale (€)',
|
|
data: [
|
|
@foreach($piano->rate as $rata)
|
|
{{ $rata->importo_totale }},
|
|
@endforeach
|
|
],
|
|
borderColor: '#007bff',
|
|
backgroundColor: 'rgba(0, 123, 255, 0.1)',
|
|
fill: true
|
|
}, {
|
|
label: 'Importo Pagato (€)',
|
|
data: [
|
|
@foreach($piano->rate as $rata)
|
|
{{ $rata->importo_pagato }},
|
|
@endforeach
|
|
],
|
|
borderColor: '#28a745',
|
|
backgroundColor: 'rgba(40, 167, 69, 0.1)',
|
|
fill: true
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: {
|
|
title: {
|
|
display: true,
|
|
text: 'Andamento Pagamenti'
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
function marcaPagata(id) {
|
|
if (confirm('Sei sicuro di voler marcare questa rata come pagata?')) {
|
|
$.ajax({
|
|
url: '{{ route("admin.rate.marca-pagata", ":id") }}'.replace(':id', id),
|
|
type: 'POST',
|
|
data: {
|
|
_token: '{{ csrf_token() }}'
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Errore: ' + response.message);
|
|
}
|
|
},
|
|
error: function() {
|
|
alert('Errore nella marcatura del pagamento');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
</script>
|
|
@endsection
|