feat: wip issue 67

This commit is contained in:
Nicolas Demangeat 2024-07-22 11:32:03 +02:00
parent 0874e9202c
commit c23e2289e5
20 changed files with 304 additions and 154 deletions

View file

@ -0,0 +1,49 @@
<?php
namespace App\Enums\Credit;
use App\Traits\Enums\BaseEnum;
enum EstimationTimeEnum: int
{
use BaseEnum;
case halfHour = 0.0625;
case hour = 0.125;
case hourAndHalf = 0.1875;
case twoHours = 0.25;
case twoHoursAndHalf = 0.3125;
case threeHours = 0.375;
case threeHoursAndHalf = 0.4375;
case fourHours = 0.5;
case fourHoursAndHalf = 0.5625;
case fiveHours = 0.625;
case fiveHoursAndHalf = 0.6875;
case sixHours = 0.75;
case sixHoursAndHalf = 0.8125;
case sevenHours = 0.875;
case sevenHoursAndHalf = 0.9375;
case eightHours = 1;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::halfHour->name => "Une demi-heure",
self::hour->name => "Une heure",
self::hourAndHalf->name => "Une heure et demie",
self::twoHours->name => "Deux heures",
self::twoHoursAndHalf->name => "Deux heures et demie",
self::threeHours->name => "Trois heures",
self::twoHoursAndHalf->name => "Trois heures et demie",
self::fourHours->name => "Quatre heures",
self::fourHoursAndHalf->name => "Quatre heures et demie",
self::fiveHours->name => "Cinq heures",
self::fiveHoursAndHalf->name => "Cinq heures et demie",
self::sixHours->name => "Six heures",
self::sixHoursAndHalf->name => "Six heures et demie",
self::sevenHours->name => "Sept heures",
self::sevenHoursAndHalf->name => "Sept heures et demi",
self::eightHours->name => "Huit heures",
];
}

View file

@ -0,0 +1,67 @@
<?php
namespace App\Enums\Tickets;
use App\Traits\Enums\BaseEnum;
enum TicketFileTypeEnum: int
{
use BaseEnum;
case png = '.png';
case jpeg = '.jpeg';
case jpg = '.jpg';
case pdf = '.pdf';
case pptx = '.pptx';
case docx = '.docx';
case xlsx = '.xlsx';
case csv = '.csv';
/**
* Optionnal labels definition
*/
private const LABELS = [
self::png->name => "Fichier png",
self::jpeg->name => "Fichier jpeg",
self::jpg->name => "Fichier jpg",
self::pdf->name => "Fichier pdf",
self::pptx->name => "Fichier pptx",
self::docx->name => "Fichier docx",
self::xlsx->name => "Fichier xlsx",
self::csv->name => "Fichier csv",
];
/**
* Custom added mimes type definition
*/
private const MIMETYPE = [
self::png->name => 'image/png',
self::jpeg->name => 'image/jpeg',
self::jpg->name => 'image/jpeg',
self::pdf->name => 'application/pdf',
self::pptx->name => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
self::docx->name => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
self::xlsx->name => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
self::csv->name => 'text/csv',
];
/**
* Get Class
*
* @return string
*/
public function mimetypes(): string
{
return self::MIMETYPE[$this->name];
}
/**
* Get enum classes
*
* @return array<string>
*/
public static function toMimetypes(): array
{
return self::MIMETYPE;
}
}

View file

@ -9,12 +9,14 @@ enum GitlabUsersEnum: int
use BaseEnum;
// Each user is associated to his ID on gitlab.
case olivier = 11;
case olivier = 11;
case sebastien = 15;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::olivier->name => "Olivier LEGAT",
self::olivier->name => "Olivier LEGAT",
self::sebastien->name => "Sebastien Hattry",
];
}

View file

@ -661,7 +661,7 @@ class TicketController extends Controller
'c-support',
$cLabel
]),
'assignee_id' => GitlabUsersEnum::olivier,
'assignee_id' => GitlabUsersEnum::sebastien,
]);
} catch (\Exception $e) {
\report($e);

View file

@ -3,6 +3,7 @@
namespace App\Http\Requests\Bo;
use App\Enums\MessageTypeEnum;
use App\Enums\Tickets\TicketFileTypeEnum;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Enum;
@ -39,7 +40,7 @@ class CreateMessage extends FormRequest
{
$this->merge([
'subscribe' => $this->subscribe ? true : false,
'type' => $this->is_private ? MessageTypeEnum::private->value : MessageTypeEnum::public->value
'type' => $this->is_private ? MessageTypeEnum::private->value : MessageTypeEnum::public->value
]);
}
@ -53,13 +54,12 @@ class CreateMessage extends FormRequest
/** @var \App\Models\User */
$user = auth()->user();
return [
'subscribe' => 'required|boolean',
'message' => 'required|min:' . ($user->isAdmin() ? '5' : '20'),
'file_message' => 'sometimes|mimes:jpeg,jpg,png,pdf|max:2048',
'type' => [
'required',
new Enum(MessageTypeEnum::class)
]
'subscribe' => 'required|boolean',
'message' => 'required|min:' . ($user->isAdmin() ? '5' : '20'),
'file_message' => ['sometimes', new Enum(TicketFileTypeEnum::class), 'max:2048'],
'file_message2' => ['sometimes', new Enum(TicketFileTypeEnum::class), 'max:2048'],
'file_message3' => ['sometimes', new Enum(TicketFileTypeEnum::class), 'max:2048'],
'type' => ['required', new Enum(MessageTypeEnum::class)]
];
}
}

View file

@ -34,8 +34,8 @@ class CreateEstimateRequest extends FormRequest
return [
'amount' => [
'required', 'numeric', 'gt:0', function ($attribute, $value, $fail) {
if ((\floatval($value) * 1000) % 125 !== 0) {
$fail("$attribute doit être un multiple de 125 (soit 0.125)");
if ((\floatval($value) * 1000) % 62.5 !== 0) {
$fail("$attribute doit être un multiple de 62.5 (soit 0.0625)");
}
}
],

View file

@ -1,37 +0,0 @@
<?php
namespace App\Http\Requests\Bo;
use App\Enums\Planning\TableRowEnum;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Enum;
class EraseCellContentRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return auth()->check() and $this->ajax();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'id' => 'required|exists:week_plannings,id',
'day' => 'required|numeric',
'row' => [
'required',
new Enum(TableRowEnum::class)
],
];
}
}

View file

@ -28,7 +28,7 @@ class StoreInvoiceRequest extends FormRequest
protected function prepareForValidation()
{
$this->merge([
'tasks' => request()->tasks ? \collect(json_decode(request()->tasks))
'tasks' => request()->tasks ? \collect(json_decode(request()->tasks))
->map(function ($task) {
return \array_intersect_key((array)$task, Invoice::getTaskStructure());
})->toArray() : [],
@ -44,24 +44,24 @@ class StoreInvoiceRequest extends FormRequest
public function rules()
{
return [
'firstname' => 'required|string|min:3|max:255',
'lastname' => 'required|string|min:3|max:255',
'object' => 'required|string|min:3|max:255',
'tasks' => 'required|array|min:1',
'tasks.*' => 'required|array',
'tasks.*.days' => 'required|numeric',
'firstname' => 'required|string|min:3|max:255',
'lastname' => 'required|string|min:3|max:255',
'object' => 'required|string|min:3|max:255',
'tasks' => 'required|array|min:1',
'tasks.*' => 'required|array',
'tasks.*.days' => 'required|numeric',
'tasks.*.amount' => 'required|numeric',
'tasks.*.desc' => 'required|string|min:10',
'tasks.*.type' => [
'tasks.*.desc' => 'required|string|min:10',
'tasks.*.type' => [
'required', new Enum(TaskTypeEnum::class)
],
'tasks.*.package' => 'required_if:tasks.*.type,' . TaskTypeEnum::package->value .
'|nullable|exists:packages,id',
'comment' => 'sometimes|nullable|string|min:15',
'show_days' => 'required|boolean',
'site_id' => 'required|integer|exists:sites,id',
'company_id' => 'required|integer|exists:companies,id',
'invoiced_to_id' => 'required|integer|exists:companies,id',
'comment' => 'sometimes|nullable|string|min:15',
'show_days' => 'required|boolean',
'site_id' => 'required|integer|exists:sites,id',
'company_id' => 'required|integer|exists:companies,id',
'invoiced_to_id' => 'required|integer|exists:companies,id',
];
}

View file

@ -21,11 +21,11 @@ class UpdateInvoiceRequest extends StoreInvoiceRequest
$rules = array_merge($rules, parent::rules());
}
$rules = array_merge($rules, [
'comment' => 'sometimes|nullable|string|min:15',
'sent_client_date' => 'required_with:signed_date,sent_accounting_date|sometimes|nullable|date',
'signed_date' => 'required_with:sent_accounting_date|sometimes|nullable|date',
'comment' => 'sometimes|nullable|string|min:15',
'sent_client_date' => 'required_with:signed_date,sent_accounting_date|sometimes|nullable|date',
'signed_date' => 'required_with:sent_accounting_date|sometimes|nullable|date',
'sent_accounting_date' => 'sometimes|nullable|date',
'status' => [
'status' => [
'required',
new Enum(InvoiceStatusEnum::class),
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed

View file

@ -1,68 +0,0 @@
<?php
namespace App\Http\Requests\Bo;
use App\Enums\Planning\CellModelEnum;
use App\Enums\Planning\CellTypeEnum;
use App\Enums\Planning\TableRowEnum;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Enum;
class SetCellContentRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
$this->merge([
'model' => $this->model ?? null,
'foreign' => $this->foreign ?? null,
'text' => $this->text ?? ''
]);
return auth()->check() and $this->ajax();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
return [
'id' => 'required|exists:week_plannings,id',
'day' => 'required|numeric',
'row' => [
'required',
new Enum(TableRowEnum::class)
],
'type' => [
'required',
new Enum(CellTypeEnum::class)
],
'CellModelEnum' => \sprintf(
'nullable',
new Enum(CellModelEnum::class)
),
'foreign' => 'required_with:CellModelEnum|nullable|numeric',
'text' => 'required|string|min:5|max:90'
];
}
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes(): array
{
return [
'CellModelEnum' => 'Type d\'élément lié',
'foreign' => 'Élément lié',
'text' => 'Description courte'
];
}
}

View file

@ -96,13 +96,16 @@ class StoreTicket extends FormRequest
}
}
],
'text' => 'required|string|min:40',
'title' => 'required|string|between:3,255',
'file_ticket' => 'mimes:jpeg,jpg,png,pdf|max:2048',
'file_ticket2' => 'mimes:jpeg,jpg,png,pdf|max:2048',
'is_internal' => 'required|boolean',
'labels' => 'sometimes|array',
'labels.*' => [
'text' => 'required|string|min:40',
'title' => 'required|string|between:3,255',
'file_ticket' => 'mimes:pptx,docx,xlsx,csv,jpeg,jpg,png,pdf|max:2048',
'file_ticket2' => 'mimes:pptx,docx,xlsx,csv,jpeg,jpg,png,pdf|max:2048',
'file_ticket3' => 'mimes:pptx,docx,xlsx,csv,jpeg,jpg,png,pdf|max:2048',
'file_ticket4' => 'mimes:pptx,docx,xlsx,csv,jpeg,jpg,png,pdf|max:2048',
'file_ticket5' => 'mimes:pptx,docx,xlsx,csv,jpeg,jpg,png,pdf|max:2048',
'is_internal' => 'required|boolean',
'labels' => 'sometimes|array',
'labels.*' => [
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
'required', 'exists:labels,id', function ($attribute, $value, $fail) use ($user) {
if (!$user->can('assignLabels', Ticket::class)) {

View file

@ -44,9 +44,9 @@ class Ticket extends Model
* @var array
*/
protected $casts = [
'is_internal' => 'bool',
'type' => TicketTypeEnum::class,
'status' => TicketStatusEnum::class,
'is_internal' => 'bool',
'type' => TicketTypeEnum::class,
'status' => TicketStatusEnum::class,
'last_activity' => 'timestamp',
];

View file

@ -70,7 +70,7 @@ class InvoiceFactory extends Factory
\mt_srand();
$lines = \mt_rand(2, 9);
for ($i = 0; $i < $lines; $i++) {
$days = 0.125 * $this->faker->numberBetween(1, 4);
$days = 0.0625 * $this->faker->numberBetween(1, 4);
$type = \collect(TaskTypeEnum::cases())->random();
$amount = 0;
switch ($type) {

View file

@ -0,0 +1,38 @@
<?php
use App\Models\Ticket;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up(): void
{
Schema::table('tickets', function (Blueprint $table) {
$table->string('file3')->after('file2')->comment('Pièce jointes n°3');
$table->string('file4')->after('file3')->comment('Pièce jointes n°4');
$table->string('file5')->after('file4')->comment('Pièce jointes n°5');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down(): void
{
Schema::table('tickets', function (Blueprint $table) {
$table->dropColumn('file3');
$table->dropColumn('file4');
$table->dropColumn('file5');
});
}
};

View file

@ -0,0 +1,36 @@
<?php
use App\Enums\MessageTypeEnum;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class AddMessageType extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('messages', function (Blueprint $table) {
$table->string('file2')->after('file')->comment('Pièce jointes n°2');
$table->string('file3')->after('file2')->comment('Pièce jointes n°3');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('messages', function (Blueprint $table) {
$table->dropColumn('file3');
$table->dropColumn('file4');
});
}
}

2
package-lock.json generated
View file

@ -1,5 +1,5 @@
{
"name": "support-web",
"name": "srcs",
"lockfileVersion": 3,
"requires": true,
"packages": {

View file

@ -82,7 +82,7 @@
v-model="task.days"
@change="updateAmount(index)"
type="number"
step="0.125"
step="0.0625"
>
</td>
<td>

View file

@ -107,7 +107,7 @@
</div>
<h4>Fichier joint 1</h4>
<div class="form-group mb-3">
<input name="file_ticket" type="file" accept="image/png, image/jpeg, image/jpg, .pdf">
<input name="file_ticket" type="file" accept="image/png, image/jpeg, image/jpg, .pdf, .pptx, .docx, .xlsx, .csv">
@if (isset($ticket) and $ticket->file !== null)
<hr>
<div class="text-center">
@ -117,7 +117,7 @@
</div>
<h4>Fichier joint 2</h4>
<div class="form-group">
<input name="file_ticket2" type="file" accept="image/png, image/jpeg, image/jpg, .pdf">
<input name="file_ticket2" type="file" accept="image/png, image/jpeg, image/jpg, .pdf, .pptx, .docx, .xlsx, .csv">
@if (isset($ticket) and $ticket->file2 !== null)
<hr>
<div class="text-center">
@ -125,6 +125,36 @@
</div>
@endif
</div>
<h4>Fichier joint 3</h4>
<div class="form-group">
<input name="file_ticket3" type="file" accept="image/png, image/jpeg, image/jpg, .pdf, .pptx, .docx, .xlsx, .csv">
@if (isset($ticket) and $ticket->file3 !== null)
<hr>
<div class="text-center">
<img class="img-fluid" src="{{ asset($ticket->file3) }}">
</div>
@endif
</div>
<h4>Fichier joint 4</h4>
<div class="form-group">
<input name="file_ticket4" type="file" accept="image/png, image/jpeg, image/jpg, .pdf, .pptx, .docx, .xlsx, .csv">
@if (isset($ticket) and $ticket->file4 !== null)
<hr>
<div class="text-center">
<img class="img-fluid" src="{{ asset($ticket->file4) }}">
</div>
@endif
</div>
<h4>Fichier joint 5</h4>
<div class="form-group">
<input name="file_ticket5" type="file" accept="image/png, image/jpeg, image/jpg, .pdf, .pptx, .docx, .xlsx, .csv">
@if (isset($ticket) and $ticket->file5 !== null)
<hr>
<div class="text-center">
<img class="img-fluid" src="{{ asset($ticket->file5) }}">
</div>
@endif
</div>
@can('changeInternalStatus', App\Model\Ticket::class)
<div class="form-group text-center">
<input id="is_internal" name="is_internal" type="checkbox" @if (old('is_internal', isset($ticket) and $ticket->is_internal)) checked @endif>

View file

@ -121,8 +121,20 @@
</div>
<div class="row mt-4">
<div class="col">
<label for="formFile" class="form-label">{{ __('Joindre un fichier (jpg, png, pdf) 2Mo max') }}</label>
<input class="form-control" type="file" id="formFile" name="file_message" accept="image/jpeg, image/png, image/jpg, .pdf">
<label for="formFile" class="form-label">{{ __('Joindre un fichier 2Mo max') }}</label>
<input class="form-control" type="file" id="formFile" name="file_message" accept="image/png, image/jpeg, image/jpg, .pdf, .pptx, .docx, .xlsx, .csv">
</div>
</div>
<div class="row mt-4">
<div class="col">
<label for="formFile2" class="form-label">{{ __('Joindre un fichier 2Mo max') }}</label>
<input class="form-control" type="file" id="formFile2" name="file_message2" accept="image/png, image/jpeg, image/jpg, .pdf, .pptx, .docx, .xlsx, .csv">
</div>
</div>
<div class="row mt-4">
<div class="col">
<label for="formFile3" class="form-label">{{ __('Joindre un fichier 2Mo max') }}</label>
<input class="form-control" type="file" id="formFile3" name="file_message3" accept="image/png, image/jpeg, image/jpg, .pdf, .pptx, .docx, .xlsx, .csv">
</div>
</div>
<div class="row mt-4">
@ -253,6 +265,24 @@
<a @if(\App\Lib\Helpers\ToolboxHelper::isImageFile($ticket->file2)) class="glightbox" data-gallery="ticket" @endif href="{{ asset($ticket->file2) }}" target="_blank">{{ __('Ouvrir la pièce jointe') }}</a>
</li>
@endif
@if (!is_null($ticket->file3))
<li>
{{ __('Pièce jointe n°3') }} :
<a @if(\App\Lib\Helpers\ToolboxHelper::isImageFile($ticket->file3)) class="glightbox" data-gallery="ticket" @endif href="{{ asset($ticket->file3) }}" target="_blank">{{ __('Ouvrir la pièce jointe') }}</a>
</li>
@endif
@if (!is_null($ticket->file4))
<li>
{{ __('Pièce jointe n°4') }} :
<a @if(\App\Lib\Helpers\ToolboxHelper::isImageFile($ticket->file4)) class="glightbox" data-gallery="ticket" @endif href="{{ asset($ticket->file4) }}" target="_blank">{{ __('Ouvrir la pièce jointe') }}</a>
</li>
@endif
@if (!is_null($ticket->file5))
<li>
{{ __('Pièce jointe n°5') }} :
<a @if(\App\Lib\Helpers\ToolboxHelper::isImageFile($ticket->file5)) class="glightbox" data-gallery="ticket" @endif href="{{ asset($ticket->file5) }}" target="_blank">{{ __('Ouvrir la pièce jointe') }}</a>
</li>
@endif
</ul>
</div>
@endif

View file

@ -1,6 +1,6 @@
<div class="form-group mb-5">
<label for="amount" class="col-form-label text-md-right">{{ __('Montant estimé') }}</label>
<input class="form-control" name="amount" id="amount" type="number" min="0.125" step="0.125" value="{{ old('number', 0.125) }}" aria-describedby="amountHelper"/>
<input class="form-control" name="amount" id="amount" type="number" min="0.0625" step="0.0625" value="{{ old('number', 0.0625) }}" aria-describedby="amountHelper"/>
@include('modules.input-error', [
'inputName' => 'amount', 'helperId' => 'amountHelper' , 'helper' => __('Le montant en homme jour estimé.')
])