Merge branch 'develop' into trunk
This commit is contained in:
commit
52386bbfd4
12 changed files with 162 additions and 63 deletions
|
|
@ -28,11 +28,11 @@ class SiteController extends Controller
|
|||
|
||||
if ($user->isAdmin()) {
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $siteModels */
|
||||
$siteModels = Site::query();
|
||||
$siteModels = Site::query()->with(['invoices', 'tickets']);
|
||||
} else {
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $siteModels */
|
||||
$siteModels = Site::whereHas('users', function (\Illuminate\Database\Eloquent\Builder $query) use ($user) {
|
||||
$query->where('id', $user->id);
|
||||
$query->where('id', $user->id)->with(['invoices', 'tickets']);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -517,9 +517,9 @@ class TicketController extends Controller
|
|||
return back()->with('error', trans('Le ticket que vous avez renseigné ne fait pas partie du même site.'));
|
||||
}
|
||||
|
||||
if (!$ticket->linkedTicket()->where('linked_ticket_id', $linkedTicket->id)->exists()) {
|
||||
$ticket->linkedTicket()->attach($linkedTicket->id);
|
||||
$linkedTicket->linkedTicket()->attach($ticket->id);
|
||||
if (!$ticket->linkedTickets()->where('linked_ticket_id', $linkedTicket->id)->exists()) {
|
||||
$ticket->linkedTickets()->attach($linkedTicket->id);
|
||||
$linkedTicket->linkedTickets()->attach($ticket->id);
|
||||
return back()->with('success', trans('Les tickets ont été liés avec succès.'));
|
||||
}
|
||||
|
||||
|
|
@ -536,8 +536,8 @@ class TicketController extends Controller
|
|||
*/
|
||||
public function unlinkTicket(Ticket $ticket, Ticket $linkedTicket)
|
||||
{
|
||||
$ticket->linkedTicket()->detach($linkedTicket->id);
|
||||
$linkedTicket->linkedTicket()->detach($ticket->id);
|
||||
$ticket->linkedTickets()->detach($linkedTicket->id);
|
||||
$linkedTicket->linkedTickets()->detach($ticket->id);
|
||||
|
||||
return back()->with('warning', trans('Le lien entre les tickets à été supprimé.'));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use Illuminate\Support\Carbon;
|
|||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
use Mccarlosen\LaravelMpdf\LaravelMpdf;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* @property string $ref
|
||||
|
|
@ -32,6 +33,7 @@ use Mccarlosen\LaravelMpdf\LaravelMpdf;
|
|||
class Invoice extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
* The attributes that are fillable.
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ class Site extends Model
|
|||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::deleted(function ($site) {
|
||||
$site->invoices()->delete();
|
||||
$site->tickets()->delete();
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
|
@ -84,7 +88,7 @@ class Site extends Model
|
|||
* HasMany Message relation
|
||||
* The users of type client that would have access to this site tickets
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
* @return \Illuminate\Database\Eloquent\Relations\belongsToMany
|
||||
*/
|
||||
public function users()
|
||||
{
|
||||
|
|
@ -101,6 +105,16 @@ class Site extends Model
|
|||
return $this->hasMany(Ticket::class, 'site_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* HasMany Invoices relation
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function invoices()
|
||||
{
|
||||
return $this->hasMany(Invoice::class, 'site_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* BelongsTo Brand relation
|
||||
*
|
||||
|
|
|
|||
|
|
@ -16,12 +16,14 @@ use App\Models\Ticket\TicketType;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Ticket extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
* The attributes that are fillable.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('invoices', function (Blueprint $table) {
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('invoices', function (Blueprint $table) {
|
||||
$table->dropColumn('deleted_at');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('tickets', function (Blueprint $table) {
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('tickets', function (Blueprint $table) {
|
||||
$table->dropColumn('deleted_at');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -5,9 +5,8 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
/**
|
||||
* Popup delete item.
|
||||
*/
|
||||
const elements = document.getElementsByClassName(
|
||||
"confirmDeleteTS"
|
||||
) as HTMLCollectionOf<Element>;
|
||||
const elements = document.getElementsByClassName("confirmDeleteTS") as HTMLCollectionOf<Element>;
|
||||
|
||||
for (const element of elements) {
|
||||
element.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
|
|
@ -17,15 +16,33 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
"confirmDoneJS can only be executed on an exising form"
|
||||
);
|
||||
}
|
||||
|
||||
const event = e as SubmitEvent;
|
||||
let submitter: HTMLButtonElement | null = null;
|
||||
|
||||
if (event.submitter) {
|
||||
submitter = event.submitter as HTMLButtonElement;
|
||||
} else {
|
||||
submitter = document.activeElement as HTMLButtonElement;
|
||||
}
|
||||
|
||||
const tickets_number = submitter?.dataset.tickets ?? "0";
|
||||
const invoices_number = submitter?.dataset.invoices ?? "0";
|
||||
|
||||
const message = `Toutes les données vont être perdues.
|
||||
<br>Tickets concernés : ${tickets_number}
|
||||
Devis concernées : ${invoices_number}`;
|
||||
|
||||
sweetalert.methods.confirm(
|
||||
"Êtes-vous sûr ?",
|
||||
"Toutes les données vont être perdu",
|
||||
message,
|
||||
el as HTMLFormElement,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function (response: SweetAlertResult<any>) {
|
||||
(el as HTMLFormElement).submit();
|
||||
},
|
||||
{ icon: "warning" }
|
||||
{ icon: "warning" },
|
||||
true
|
||||
);
|
||||
return false;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ export default {
|
|||
text: string = "",
|
||||
self: Object,
|
||||
after: (response: SweetAlertResult<any>) => void = () => {},
|
||||
options: SweetAlertOptions = {}
|
||||
options: SweetAlertOptions = {},
|
||||
html: Boolean = false
|
||||
) {
|
||||
if (!self) {
|
||||
throw Error("self is needed to set \"this\" on callback");
|
||||
|
|
@ -19,10 +20,12 @@ export default {
|
|||
if (!after) {
|
||||
throw Error("callback is needed when using confirm");
|
||||
}
|
||||
|
||||
const icon = options.icon ?? "warning";
|
||||
Swal.fire({
|
||||
|
||||
// define options to fire
|
||||
const saOptions = {
|
||||
title: title,
|
||||
text: text,
|
||||
color: getComputedStyle(document.body).getPropertyValue("--bs-body-color"),
|
||||
icon: icon,
|
||||
showCancelButton: true,
|
||||
|
|
@ -40,7 +43,18 @@ export default {
|
|||
},
|
||||
buttonsStyling: false,
|
||||
background: getComputedStyle(document.body).getPropertyValue("--bs-body-bg"),
|
||||
}).then((result) => {
|
||||
};
|
||||
|
||||
// Enable HTML content interpretation in the modal options
|
||||
let message = {};
|
||||
if (html) {
|
||||
message = {html: text};
|
||||
} else {
|
||||
message = { text: text };
|
||||
}
|
||||
const fullOptions = {...saOptions, ...message};
|
||||
|
||||
Swal.fire(fullOptions).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
if (after) {
|
||||
after.apply(self, [result]);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@
|
|||
<td class="text-center align-middle"><span class="badge bg-info">{{ $invoiceModel->sent_client_date }}</span></td>
|
||||
<td class="text-center align-middle"><span class="badge bg-info">{{ $invoiceModel->signed_date }}</span></td>
|
||||
<td class="text-center align-middle"><span class="badge bg-info">{{ $invoiceModel->sent_accounting_date }}</span></td>
|
||||
<td class="text-center align-middle">{{ $invoiceModel->site->name }}</td>
|
||||
<td class="text-center align-middle">
|
||||
{{ $invoiceModel->site->name }}
|
||||
<td class="text-center align-middle"><span class="badge bg-info">{{ $invoiceModel->updated_at }}</span></td>
|
||||
<td class="text-end align-middle">
|
||||
<div class="btn-group">
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@
|
|||
@method('DELETE')
|
||||
<button type="submit"
|
||||
class="btn btn-sm btn-danger"
|
||||
data-tickets="{{ $siteModel->tickets()->count() }}"
|
||||
data-invoices="{{ $siteModel->invoices()->count() }}"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{{ __('crud.actions.delete') }}">
|
||||
|
|
|
|||
|
|
@ -18,10 +18,11 @@
|
|||
</h1>
|
||||
@if (session('tickets.pr'))
|
||||
@php
|
||||
$projectManager = \App\Models\Site::query()->find(session('tickets.pr'))->projectManager;
|
||||
$site = \App\Models\Site::query()->find(session('tickets.pr'));
|
||||
$projectManager = $site ? $site->projectManager : false;
|
||||
@endphp
|
||||
@if($projectManager)
|
||||
<h2>{{ __("Chef de projet") }} : {{ $projectManager->name }}</h2>
|
||||
@if ($projectManager)
|
||||
<h2>{{ __('Chef de projet') }} : {{ $projectManager->name }}</h2>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
|
|
@ -76,8 +77,7 @@
|
|||
{{-- All types --}}
|
||||
<div class="col">
|
||||
<div class="input-group">
|
||||
<label class="input-group-text" for="selectType"><i
|
||||
class="fa-solid fa-ticket"></i></label>
|
||||
<label class="input-group-text" for="selectType"><i class="fa-solid fa-ticket"></i></label>
|
||||
<select class="form-select" id="selectType">
|
||||
<option value="-1">{{ __('Tous les types') }}</option>
|
||||
@foreach ($types as $type)
|
||||
|
|
@ -100,8 +100,7 @@
|
|||
{{-- All status --}}
|
||||
<div class="col">
|
||||
<div class="input-group">
|
||||
<label class="input-group-text" for="selectStatus"><i
|
||||
class="fa-solid fa-sign-hanging"></i></label>
|
||||
<label class="input-group-text" for="selectStatus"><i class="fa-solid fa-sign-hanging"></i></label>
|
||||
<select class="form-select" id="selectStatus">
|
||||
<option value="-1">{{ __('Tous les statuts') }}</option>
|
||||
@foreach ($status as $statut)
|
||||
|
|
@ -125,8 +124,7 @@
|
|||
@can('assignTickets', App\Models\Ticket::class)
|
||||
<div class="col">
|
||||
<div class="input-group">
|
||||
<label class="input-group-text" for="selectAssign"><i
|
||||
class="fa-solid fa-hat-wizard"></i></label>
|
||||
<label class="input-group-text" for="selectAssign"><i class="fa-solid fa-hat-wizard"></i></label>
|
||||
<select class="form-select" id="selectAssign">
|
||||
<option value="-1">{{ __("Sans filtre d'assignation") }}</option>
|
||||
@foreach (\App\Models\User::adminUsers() as $user)
|
||||
|
|
@ -149,8 +147,7 @@
|
|||
@endcan
|
||||
{{-- Search form --}}
|
||||
<div class="col">
|
||||
<form id="searchTicketForm"
|
||||
action="{{ request()->fullUrlWithQuery(['search' => '']) }}">
|
||||
<form id="searchTicketForm" action="{{ request()->fullUrlWithQuery(['search' => '']) }}">
|
||||
<div class="input-group mb-3">
|
||||
<input class="form-control" id="searchTicket" name="search" type="text"
|
||||
value="{{ session()->get('tickets.search') }}"
|
||||
|
|
@ -179,8 +176,7 @@
|
|||
<div class="btn-group float-end">
|
||||
@if (session('tickets.pr') && session('tickets.st') != \App\Enums\Tickets\TicketStatusEnum::archived->value)
|
||||
@if (session('tickets.or'))
|
||||
<a class="btn btn-info float-end"
|
||||
href="{{ route('bo.ticket.index', ['ord' => -1]) }}">
|
||||
<a class="btn btn-info float-end" href="{{ route('bo.ticket.index', ['ord' => -1]) }}">
|
||||
<i
|
||||
class="fa-solid fa-equals"></i> {{ __('see_mode', ['mode' => __('validation.custom.default')]) }}
|
||||
</a>
|
||||
|
|
@ -209,7 +205,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="overflow-scroll w-100">
|
||||
<div class="w-100 overflow-scroll">
|
||||
<table class="table-hover table">
|
||||
<thead>
|
||||
@php
|
||||
|
|
@ -245,16 +241,13 @@
|
|||
@endphp
|
||||
@include('bo.modules.table-col-sorter', [
|
||||
'cols' => $cols,
|
||||
'ignore' => session('tickets.or')
|
||||
? array_keys($cols)
|
||||
: ['id', 'site', 'status', 'tickets'],
|
||||
'ignore' => session('tickets.or') ? array_keys($cols) : ['id', 'site', 'status', 'tickets'],
|
||||
])
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (!count($tickets))
|
||||
<tr>
|
||||
<td class="text-center"
|
||||
colspan="@if (Auth::user()->isAdmin()) 9 @else 6 @endif">
|
||||
<td class="text-center" colspan="@if (Auth::user()->isAdmin()) 9 @else 6 @endif">
|
||||
<h2>{{ __('Aucun ticket') }}</h2>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -267,7 +260,7 @@
|
|||
'routeName' => 'ticket',
|
||||
'model' => $ticket,
|
||||
'models' => $tickets,
|
||||
'value' => ($key + 1) + (($tickets->currentPage() - 1) * $tickets->perPage()),
|
||||
'value' => $key + 1 + ($tickets->currentPage() - 1) * $tickets->perPage(),
|
||||
'noRightsVisible' => false,
|
||||
])
|
||||
@endif
|
||||
|
|
@ -291,16 +284,14 @@
|
|||
'sitename' => $ticket->site->name,
|
||||
]) }}">{{ $ticket->site->name }}</a>
|
||||
@else
|
||||
<span
|
||||
class="text-decoration-underline">{{ $ticket->site->name }}</span>
|
||||
<span class="text-decoration-underline">{{ $ticket->site->name }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
@endif
|
||||
{{-- type --}}
|
||||
<td class="text-center">
|
||||
<span
|
||||
class="badge {{ $ticket->type->class() }}">{{ $ticket->type->label() }}</span>
|
||||
<span class="badge {{ $ticket->type->class() }}">{{ $ticket->type->label() }}</span>
|
||||
</td>
|
||||
{{-- status --}}
|
||||
<td scope="row">
|
||||
|
|
@ -347,13 +338,10 @@
|
|||
$ticket_files = $ticket->getFiles();
|
||||
@endphp
|
||||
@foreach ($ticket_files as $key => $file)
|
||||
@if (
|
||||
$file !== null &&
|
||||
(\App\Lib\Helpers\ToolboxHelper::isImageFile($file) || \App\Lib\Helpers\ToolboxHelper::isPdfFile($file)))
|
||||
@if ($file !== null && (\App\Lib\Helpers\ToolboxHelper::isImageFile($file) || \App\Lib\Helpers\ToolboxHelper::isPdfFile($file)))
|
||||
<a class="glightbox btn btn-outline-dark"
|
||||
data-gallery="gallery{{ $ticket->id }}"
|
||||
href="{{ asset($file) }}" target="_blank"><i
|
||||
class="fa-solid fa-file-image"></i>
|
||||
data-gallery="gallery{{ $ticket->id }}" href="{{ asset($file) }}"
|
||||
target="_blank"><i class="fa-solid fa-file-image"></i>
|
||||
</a>
|
||||
@break
|
||||
@endif
|
||||
|
|
@ -361,8 +349,8 @@
|
|||
{{-- Modal du ticket --}}
|
||||
<!-- Button trigger modal -->
|
||||
<button class="btn btn-outline-info" data-bs-toggle="modal"
|
||||
data-bs-target="#ticket{{ $ticket->id }}Modal"
|
||||
type="button"><i class="fa-solid fa-eye"></i></button>
|
||||
data-bs-target="#ticket{{ $ticket->id }}Modal" type="button"><i
|
||||
class="fa-solid fa-eye"></i></button>
|
||||
<a class="btn btn-outline-success"
|
||||
href="{{ route('bo.ticket.show', $ticket->id) }}"><i
|
||||
class="fa-solid fa-comment"></i></a>
|
||||
|
|
@ -377,10 +365,8 @@
|
|||
action="{{ route('bo.ticket.archive', $ticket) }}">
|
||||
@method('PUT')
|
||||
@csrf
|
||||
<button
|
||||
class="btn btn-outline-danger rounded-0 rounded-end"
|
||||
type="submit"><i
|
||||
class="fa-solid fa-box-archive"></i></button>
|
||||
<button class="btn btn-outline-danger rounded-0 rounded-end"
|
||||
type="submit"><i class="fa-solid fa-box-archive"></i></button>
|
||||
</form>
|
||||
@endif
|
||||
@endcan
|
||||
|
|
@ -388,13 +374,12 @@
|
|||
</div>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="ticket{{ $ticket->id }}Modal"
|
||||
aria-labelledby="ticket{{ $ticket->id }}ModalLabel"
|
||||
aria-hidden="true" tabindex="-1">
|
||||
aria-labelledby="ticket{{ $ticket->id }}ModalLabel" aria-hidden="true"
|
||||
tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"
|
||||
id="ticket{{ $ticket->id }}ModalLabel">
|
||||
<h5 class="modal-title" id="ticket{{ $ticket->id }}ModalLabel">
|
||||
@can('isAdmin')
|
||||
<a href="{{ route('bo.sites.show', $ticket->site) }}"
|
||||
title="{{ __('Voir le site :sitename', [
|
||||
|
|
@ -413,9 +398,8 @@
|
|||
{{ $ticket->type->label() }}
|
||||
</span>
|
||||
</h5>
|
||||
<button class="btn btn-sm btn-primary bg-primary"
|
||||
data-bs-dismiss="modal" type="button"
|
||||
aria-label="Close">
|
||||
<button class="btn btn-sm btn-primary bg-primary" data-bs-dismiss="modal"
|
||||
type="button" aria-label="Close">
|
||||
<i class="fa-solid fa-xmark text-white"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -431,8 +415,7 @@
|
|||
<p>{!! clean(nl2br($ticket->text)) !!}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-sm btn-primary"
|
||||
data-bs-dismiss="modal"
|
||||
<button class="btn btn-sm btn-primary" data-bs-dismiss="modal"
|
||||
type="button">{{ __('Fermer') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue