Merge branch 'issue-19' into 'develop'
add status on invoices - issue #19 See merge request ldc-web/projets/support-web!53
This commit is contained in:
commit
c155e48d78
22 changed files with 419 additions and 110 deletions
25
app/Enums/Invoices/InvoiceStatusEnum.php
Normal file
25
app/Enums/Invoices/InvoiceStatusEnum.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Invoices;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum InvoiceStatusEnum: int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case opened = 1;
|
||||
case refused = 2;
|
||||
case canceled = 3;
|
||||
case archived = 4;
|
||||
|
||||
/**
|
||||
* Optionnal labels definition.
|
||||
*/
|
||||
private const LABELS = [
|
||||
self::opened->name => "Ouvert (nouveaux ou en cours)",
|
||||
self::refused->name => "Refusé (par le client ou aucune réponse de sa part)",
|
||||
self::canceled->name => "Annulé (supprimé)",
|
||||
self::archived->name => "Archivé (validé et envoyé à la comptabilité)",
|
||||
];
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Invoice;
|
||||
namespace App\Enums\Invoices;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Enums\Invoices\InvoiceStatusEnum;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Invoices\StoreInvoiceRequest;
|
||||
use App\Http\Requests\Bo\Invoices\UpdateInvoiceRequest;
|
||||
|
|
@ -26,6 +27,10 @@ class InvoiceController extends Controller
|
|||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $invoiceModels */
|
||||
$invoiceModels = Invoice::query();
|
||||
$status = intval($request->status);
|
||||
$invoiceModels = $invoiceModels->when($status, function ($query) use ($status) {
|
||||
$query->where('status', $status);
|
||||
});
|
||||
|
||||
/** @var string $search Search field */
|
||||
$search = $request->search;
|
||||
|
|
@ -46,7 +51,7 @@ class InvoiceController extends Controller
|
|||
/** Custom pagination */
|
||||
$invoiceModels = $this->customPaginate($invoiceModels, $request->pagination);
|
||||
|
||||
return view('bo.pages.invoices.index', compact('invoiceModels', 'search', 'searchFields'));
|
||||
return view('bo.pages.invoices.index', compact('invoiceModels', 'search', 'searchFields', 'status'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -79,6 +84,7 @@ class InvoiceController extends Controller
|
|||
'packageModels' => $packageModels,
|
||||
'siteModels' => $siteModels,
|
||||
'companyModels' => $companyModels,
|
||||
'invoiceStatusArray' => $invoice->getInvoiceStatusArray($invoice),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -130,6 +136,7 @@ class InvoiceController extends Controller
|
|||
'packageModels' => $packageModels,
|
||||
'siteModels' => $siteModels,
|
||||
'companyModels' => $companyModels,
|
||||
'invoiceStatusArray' => $invoice->getInvoiceStatusArray($invoice),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -143,12 +150,7 @@ class InvoiceController extends Controller
|
|||
public function update(UpdateInvoiceRequest $request, Invoice $invoice): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $invoice) {
|
||||
if (isset($invoice->signed_date)) {
|
||||
$fields = $request->safe()->only('signed_date', 'sent_client_date', 'sent_accounting_date');
|
||||
} else {
|
||||
$fields = $request->validated();
|
||||
}
|
||||
$invoice->fill($fields);
|
||||
$invoice->fill(($invoice->status->value === InvoiceStatusEnum::opened->value) ? $request->validated() : []);
|
||||
if ($invoice->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.invoices.edit', $invoice)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Invoices;
|
||||
|
||||
use App\Enums\Invoice\TaskTypeEnum;
|
||||
use App\Enums\Invoices\TaskTypeEnum;
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
|
@ -90,7 +90,8 @@ class StoreInvoiceRequest extends FormRequest
|
|||
'invoiced_to_id' => trans('Entité à facturer'),
|
||||
'signed_date' => trans('Date de signature du Devis'),
|
||||
'sent_client_date' => trans('Date d\'envoi du Devis au client'),
|
||||
'sent_accounting_date' => trans('Date d\'envoi du Devis à la compta'),
|
||||
'sent_accounting_date' => trans('Date d\'envoi du Devis à la comptabilité'),
|
||||
'status' => trans('État du devis'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Invoices;
|
||||
|
||||
use App\Enums\Invoices\InvoiceStatusEnum;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
class UpdateInvoiceRequest extends StoreInvoiceRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -12,14 +15,34 @@ class UpdateInvoiceRequest extends StoreInvoiceRequest
|
|||
public function rules()
|
||||
{
|
||||
$rules = [];
|
||||
if (!$this->route('invoice')->signed_date) {
|
||||
$rules = array_merge($rules, parent::rules());
|
||||
}
|
||||
$rules = array_merge($rules, [
|
||||
'signed_date' => 'sometimes|nullable|date',
|
||||
'sent_client_date' => 'sometimes|nullable|date',
|
||||
'sent_accounting_date' => 'sometimes|nullable|date',
|
||||
]);
|
||||
$model = $this->route('invoice');
|
||||
if ($model->status->value === InvoiceStatusEnum::opened->value) {
|
||||
if (!$model->sent_client_date) {
|
||||
$rules = array_merge($rules, parent::rules());
|
||||
}
|
||||
$rules = array_merge($rules, [
|
||||
'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' => [
|
||||
'required',
|
||||
new Enum(InvoiceStatusEnum::class),
|
||||
//phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) use ($model) {
|
||||
if (
|
||||
(intval($value) === InvoiceStatusEnum::archived->value) &&
|
||||
(is_null($model->sent_client_date) ||
|
||||
is_null($model->signed_date) ||
|
||||
is_null($model->sent_accounting_date))
|
||||
) {
|
||||
$fail(__('Le status :status doit être assigné lorsque les 3 dates sont saisies', [
|
||||
'status' => InvoiceStatusEnum::archived->label()
|
||||
]));
|
||||
}
|
||||
},
|
||||
],
|
||||
]);
|
||||
} //end if
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
/**
|
||||
* @property string $name
|
||||
|
|
@ -21,6 +22,15 @@ class Company extends Model
|
|||
'name'
|
||||
];
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = [
|
||||
'value'
|
||||
];
|
||||
|
||||
/**
|
||||
* HasMany Invoices
|
||||
*
|
||||
|
|
@ -30,4 +40,16 @@ class Company extends Model
|
|||
{
|
||||
return $this->hasMany(Invoice::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return value attribute for belongsto search component
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Casts\Attribute
|
||||
*/
|
||||
protected function value(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn () => $this->id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\Invoice\TaskTypeEnum;
|
||||
use App\Enums\Invoices\TaskTypeEnum;
|
||||
use App\Enums\Invoices\InvoiceStatusEnum;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
|
@ -26,6 +27,7 @@ use Mccarlosen\LaravelMpdf\LaravelMpdf;
|
|||
* @property Site $site_id
|
||||
* @property Company $company_id
|
||||
* @property Company $invoiced_to_id
|
||||
* @property InvoiceStatusEnum $status
|
||||
*/
|
||||
class Invoice extends Model
|
||||
{
|
||||
|
|
@ -51,7 +53,8 @@ class Invoice extends Model
|
|||
'sent_accounting_date',
|
||||
'site_id',
|
||||
'company_id',
|
||||
'invoiced_to_id'
|
||||
'invoiced_to_id',
|
||||
'status',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -64,6 +67,7 @@ class Invoice extends Model
|
|||
'signed_date' => 'date',
|
||||
'sent_client_date' => 'date',
|
||||
'sent_accounting_date' => 'date',
|
||||
'status' => InvoiceStatusEnum::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -92,6 +96,7 @@ class Invoice extends Model
|
|||
->reduce(function ($previous, array $task) {
|
||||
return \floatval($task['amount']) + \floatval($previous);
|
||||
});
|
||||
$model->status = InvoiceStatusEnum::opened;
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
$model->total_days = collect($model->tasks)
|
||||
|
|
@ -215,4 +220,36 @@ class Invoice extends Model
|
|||
);
|
||||
return $pdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the invoice status array depending to the dates entered.
|
||||
*
|
||||
* @param \App\Models\Invoice $invoice
|
||||
* @return array
|
||||
*/
|
||||
public static function getInvoiceStatusArray(Invoice $invoice): array
|
||||
{
|
||||
$invoiceStatusArray = [];
|
||||
if ($invoice->signed_date && $invoice->sent_client_date && $invoice->sent_accounting_date) {
|
||||
return array_merge($invoiceStatusArray, [
|
||||
InvoiceStatusEnum::toArray()['opened'],
|
||||
InvoiceStatusEnum::toArray()['archived'],
|
||||
]);
|
||||
}
|
||||
if ($invoice->signed_date) {
|
||||
return array_merge($invoiceStatusArray, [
|
||||
InvoiceStatusEnum::toArray()['opened']
|
||||
]);
|
||||
}
|
||||
if ($invoice->sent_client_date) {
|
||||
return array_merge($invoiceStatusArray, [
|
||||
InvoiceStatusEnum::toArray()['opened'],
|
||||
InvoiceStatusEnum::toArray()['refused'],
|
||||
]);
|
||||
}
|
||||
return array_merge($invoiceStatusArray, [
|
||||
InvoiceStatusEnum::toArray()['opened'],
|
||||
InvoiceStatusEnum::toArray()['canceled'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
/**
|
||||
* @property string $name
|
||||
|
|
@ -22,6 +23,15 @@ class Site extends Model
|
|||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = [
|
||||
'value'
|
||||
];
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
|
|
@ -64,4 +74,16 @@ class Site extends Model
|
|||
{
|
||||
return $this->belongsTo(Project::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return value attribute for belongsto search component
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Casts\Attribute
|
||||
*/
|
||||
protected function value(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn () => $this->id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\Invoice\TaskTypeEnum;
|
||||
use App\Enums\Invoices\TaskTypeEnum;
|
||||
use App\Enums\Invoices\InvoiceStatusEnum;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Package;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
|
@ -16,18 +17,58 @@ class InvoiceFactory extends Factory
|
|||
*/
|
||||
protected $model = Invoice::class;
|
||||
|
||||
/**
|
||||
* A JSON object, each line has to be contructed using these
|
||||
* fields description, days, type Invoice\TaskType, amount.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $tasks = [];
|
||||
|
||||
/**
|
||||
* The total calculated using all tasks.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
protected $total = 0;
|
||||
|
||||
/**
|
||||
* The total days calculated using all tasks.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
protected $totalDays = 0;
|
||||
|
||||
/**
|
||||
* The date of the signing.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $signedDateBoolean = 0;
|
||||
|
||||
/**
|
||||
* The date of the shipping to the client.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $sentClientDateBoolean = 0;
|
||||
|
||||
/**
|
||||
* The date of the shipping to the accounting.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $sentAccountingDateBoolean = 0;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
* @return void
|
||||
*/
|
||||
public function definition()
|
||||
private function customData(): void
|
||||
{
|
||||
\mt_srand();
|
||||
$lines = \mt_rand(2, 9);
|
||||
$tasks = [];
|
||||
$total = 0;
|
||||
$totalDays = 0;
|
||||
$lines = \mt_rand(2, 9);
|
||||
for ($i = 0; $i < $lines; $i++) {
|
||||
$days = 0.125 * $this->faker->numberBetween(1, 4);
|
||||
$type = \collect(TaskTypeEnum::cases())->random();
|
||||
|
|
@ -47,37 +88,54 @@ class InvoiceFactory extends Factory
|
|||
$amount = $days * $this->faker->randomFloat(null, 150, 650);
|
||||
break;
|
||||
}
|
||||
$totalDays += $days;
|
||||
$total += $amount;
|
||||
/** @var \App\Enums\Invoice\TaskTypeEnum */
|
||||
$taskType = \collect(TaskTypeEnum::cases())->random();
|
||||
$tasks[] = \array_merge(Invoice::getTaskStructure(), [
|
||||
$this->totalDays += $days;
|
||||
$this->total += $amount;
|
||||
/** @var \App\Enums\Invoices\TaskTypeEnum */
|
||||
$this->tasks[] = \array_merge(Invoice::getTaskStructure(), [
|
||||
'desc' => $this->faker->words(9, true),
|
||||
'days' => $days,
|
||||
'type' => $taskType->value,
|
||||
'type' => \collect(TaskTypeEnum::cases())->random()->value,
|
||||
'amount' => $amount,
|
||||
'package' => 1
|
||||
]);
|
||||
/** Dates */
|
||||
$this->signedDateBoolean = $this->faker->boolean(25);
|
||||
$this->sentClientDateBoolean = $this->faker->boolean(25);
|
||||
$this->sentAccountingDateBoolean = $this->faker->boolean(25);
|
||||
} //end for
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
$this->customData();
|
||||
return [
|
||||
'firstname' => $this->faker->firstName,
|
||||
'lastname' => $this->faker->lastName,
|
||||
'object' => $this->faker->words(3, true),
|
||||
// * constructed object
|
||||
'tasks' => $tasks,
|
||||
'tasks' => $this->tasks,
|
||||
// * constructed object result
|
||||
'total' => $total,
|
||||
'total' => $this->total,
|
||||
// * constructed object result
|
||||
'total_days' => $totalDays,
|
||||
'total_days' => $this->totalDays,
|
||||
'comment' => $this->faker->text(\rand(20, 40)),
|
||||
'show_days' => $this->faker->boolean(75),
|
||||
'signed_date' => $this->faker->boolean(25) ?
|
||||
'signed_date' =>
|
||||
$this->signedDateBoolean ?
|
||||
$this->faker->dateTimeBetween('-1 year', '+1 year') : null,
|
||||
'sent_client_date' => $this->faker->boolean(25) ?
|
||||
'sent_client_date' =>
|
||||
$this->signedDateBoolean && $this->sentClientDateBoolean ?
|
||||
$this->faker->dateTimeBetween('-1 year', '+1 year') : null,
|
||||
'sent_accounting_date' => $this->faker->boolean(25) ?
|
||||
'sent_accounting_date' =>
|
||||
$this->signedDateBoolean && $this->sentClientDateBoolean && $this->sentAccountingDateBoolean ?
|
||||
$this->faker->dateTimeBetween('-1 year', '+1 year') : null,
|
||||
'status' => $this->signedDateBoolean && $this->sentClientDateBoolean && $this->sentAccountingDateBoolean ?
|
||||
InvoiceStatusEnum::archived : InvoiceStatusEnum::opened,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class CreateInvoicesTable extends Migration
|
|||
$table->text('tasks')
|
||||
->comment(
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
'A JSON object, each line has to be contructed using these fields description, days, type Invoice\TaskTypeEnum, amount'
|
||||
'A JSON object, each line has to be contructed using these fields description, days, type Invoices\TaskTypeEnum, amount'
|
||||
);
|
||||
|
||||
$table->unsignedFloat('total')->comment('The total calculated using all tasks');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use App\Enums\Invoices\InvoiceStatusEnum;
|
||||
use App\Models\Invoice;
|
||||
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->unsignedTinyInteger('status')
|
||||
->default(InvoiceStatusEnum::opened->value)
|
||||
->comment('Status of the invoice.')
|
||||
->after('invoiced_to_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('invoices', function (Blueprint $table) {
|
||||
$table->dropColumn('status');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -28,15 +28,6 @@ export default defineComponent({
|
|||
throw new Error("this component requires json");
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const json = String(this.$attrs.json ?? "{}"),
|
||||
data = JSON.parse(json);
|
||||
this.name = data.name;
|
||||
this.internalText = data.text ? String(data.text) : "";
|
||||
this.internalId = data.id ? data.id : "";
|
||||
this.internalRequired = Boolean(data.required);
|
||||
this.makeSuperBuild();
|
||||
},
|
||||
data(): {
|
||||
name: string;
|
||||
internalText: string;
|
||||
|
|
@ -57,6 +48,15 @@ export default defineComponent({
|
|||
chars: 0,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const json = String(this.$attrs.json ?? "{}"),
|
||||
data = JSON.parse(json);
|
||||
this.name = data.name;
|
||||
this.internalText = data.text ? String(data.text) : "";
|
||||
this.internalId = data.id ? data.id : "";
|
||||
this.internalRequired = Boolean(data.required);
|
||||
this.makeSuperBuild();
|
||||
},
|
||||
watch: {
|
||||
dbtext() {
|
||||
if (this.internalText != this.dbtext) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import {
|
|||
faArrowRightLong,
|
||||
faArrowUp,
|
||||
faBan,
|
||||
faBox,
|
||||
faBoxArchive,
|
||||
faBoxOpen,
|
||||
faChevronLeft,
|
||||
faChevronRight,
|
||||
faClipboard,
|
||||
|
|
@ -43,7 +45,9 @@ import {
|
|||
config.autoReplaceSvg = false;
|
||||
library.add(faTags);
|
||||
library.add(faSquarePlus);
|
||||
library.add(faBox);
|
||||
library.add(faBoxArchive);
|
||||
library.add(faBoxOpen);
|
||||
library.add(faEraser);
|
||||
library.add(faSignHanging);
|
||||
library.add(faDiagramProject);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
@section('content')
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-3">
|
||||
<div class="d-flex flex-row align-items-center">
|
||||
<a href="{{ route('bo.invoices.index') }}"
|
||||
<a href="{{ route('bo.invoices.index', ['status' => \App\Enums\Invoices\InvoiceStatusEnum::opened]) }}"
|
||||
class="btn btn-primary text-decoration-none m-0 me-2"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
@section('content')
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-3">
|
||||
<div class="d-flex flex-row align-items-start">
|
||||
<a href="{{ route('bo.invoices.index') }}"
|
||||
<a href="{{ route('bo.invoices.index', ['status' => \App\Enums\Invoices\InvoiceStatusEnum::opened]) }}"
|
||||
class="btn btn-primary text-decoration-none m-0 me-2"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
title="{{ __('crud.helpers.view_model', ['model' => __('models.classes.invoices')]) }}">
|
||||
<i class="fa-solid fa-eye"></i>
|
||||
</a>
|
||||
@if($invoiceModel->status->value === \App\Enums\Invoices\InvoiceStatusEnum::opened->value)
|
||||
<button id="formSubmitClone"
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
|
|
@ -33,9 +34,11 @@
|
|||
title="{{ __('crud.helpers.save_model', ['model' => __('models.classes.invoices')]) }}">
|
||||
{{ __('crud.actions.save') }}
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if($invoiceModel->status->value === \App\Enums\Invoices\InvoiceStatusEnum::opened->value)
|
||||
<form action="{{ route('bo.invoices.update', $invoiceModel->id) }}" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
|
@ -53,4 +56,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@else
|
||||
@include('bo.pages.invoices.form-inputs')
|
||||
@endif
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -1,41 +1,30 @@
|
|||
<div class="row">
|
||||
{{-- DATES/STATUS --}}
|
||||
@if (request()->routeIs('bo.invoices.edit'))
|
||||
@if($invoiceModel->status !== \App\Enums\Invoices\InvoiceStatusEnum::opened || $invoiceModel->signed_date)
|
||||
<div class="col-12">
|
||||
<div class="alert alert-secondary text-white" role="alert">
|
||||
<strong>
|
||||
@if($invoiceModel->status !== \App\Enums\Invoices\InvoiceStatusEnum::opened)
|
||||
{{ __('Impossible de mettre à jour les informations d\'un devis :status.', ['status' => $invoiceModel->status->label()]) }}
|
||||
@elseif($invoiceModel->signed_date)
|
||||
{{ __('Impossible de mettre à jour les informations d\'un devis déjà signé, seule la section "État" est prise en compte') }}
|
||||
@endif
|
||||
</strong>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
{{-- DATES STATUS --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="row border w-100 h-100 bg-white mx-auto p-3">
|
||||
<legend class="p-0">{{ __('Dates') }}</legend>
|
||||
<legend class="p-0">{{ __('État') }}</legend>
|
||||
<div class="row w-100 mx-auto p-0">
|
||||
@if($invoiceModel->signed_date)
|
||||
<div class="col-12 p-0 pe-md-3">
|
||||
<div class="alert alert-secondary text-white" role="alert">
|
||||
<strong>{{ __('Impossible de mettre à jour les informations d\'un devis déjà signé, seules les dates sont prises en compte !') }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
{{-- SIGNED_DATE --}}
|
||||
<div class="col-12 col-sm-6 col-md-4 p-0 pe-md-3">
|
||||
@if(!$invoiceModel->signed_date)
|
||||
@include('bo.partials.inputs.timestamp-datetime', [
|
||||
'id' => 'invoiceSigneddate',
|
||||
'label' => __('Date d\'envoi du :model', [
|
||||
'model' => __('models.classes.invoices'),
|
||||
]),
|
||||
'name' => 'signed_date',
|
||||
'defaultValue' => false,
|
||||
'required' => true,
|
||||
'model' => $invoiceModel ?? null,
|
||||
'helper' => __('Doît être une date réelle et existante.'),
|
||||
])
|
||||
@else
|
||||
<p class="fw-bold text-center m-0">{{ __('Envoyé le :date', ['date' => $invoiceModel->signed_date]) }}</p>
|
||||
@endif
|
||||
</div>
|
||||
{{-- SENT_CLIENT_DATE --}}
|
||||
<div class="col-12 col-sm-6 col-md-4 p-0 pe-md-3">
|
||||
@if(!$invoiceModel->sent_client_date)
|
||||
@include('bo.partials.inputs.timestamp-datetime', [
|
||||
@if($invoiceModel->status === \App\Enums\Invoices\InvoiceStatusEnum::opened AND !$invoiceModel->sent_client_date )
|
||||
@include('bo.partials.inputs.date', [
|
||||
'id' => 'invoiceSentclientdate',
|
||||
'label' => __('Date de signature du :model (client)', [
|
||||
'label' => __('Date d\'envoi du :model', [
|
||||
'model' => __('models.classes.invoices'),
|
||||
]),
|
||||
'name' => 'sent_client_date',
|
||||
|
|
@ -44,16 +33,38 @@
|
|||
'model' => $invoiceModel ?? null,
|
||||
'helper' => __('Doît être une date réelle et existante.'),
|
||||
])
|
||||
@else
|
||||
<p class="fw-bold text-center m-0">{{ __('Signé le :date (client)', ['date' => $invoiceModel->sent_client_date]) }}</p>
|
||||
@elseif ($invoiceModel->sent_client_date)
|
||||
<p class="fw-bold text-center m-0">
|
||||
{{ __('Envoyé le :date', ['date' => \Carbon\Carbon::parse($invoiceModel->sent_client_date)->format('d/m/Y')]) ?? "xxx" }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
{{-- SIGNED_DATE --}}
|
||||
<div class="col-12 col-sm-6 col-md-4 p-0 pe-md-3">
|
||||
@if($invoiceModel->status === \App\Enums\Invoices\InvoiceStatusEnum::opened AND !$invoiceModel->signed_date)
|
||||
@include('bo.partials.inputs.date', [
|
||||
'id' => 'invoiceSigneddate',
|
||||
'label' => __('Date de signature du :model (client)', [
|
||||
'model' => __('models.classes.invoices'),
|
||||
]),
|
||||
'name' => 'signed_date',
|
||||
'defaultValue' => false,
|
||||
'required' => true,
|
||||
'model' => $invoiceModel ?? null,
|
||||
'helper' => __('Doît être une date réelle et existante.'),
|
||||
])
|
||||
@elseif ($invoiceModel->signed_date)
|
||||
<p class="fw-bold text-center m-0">
|
||||
{{ __('Signé le :date (client)', ['date' => \Carbon\Carbon::parse($invoiceModel->signed_date)->format('d/m/Y') ?? "xxx"]) }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
{{-- SENT_ACCOUNTING_DATE --}}
|
||||
<div class="col-12 col-sm-6 col-md-4 p-0 pe-md-3">
|
||||
@if(!$invoiceModel->sent_accounting_date)
|
||||
@include('bo.partials.inputs.timestamp-datetime', [
|
||||
@if($invoiceModel->status === \App\Enums\Invoices\InvoiceStatusEnum::opened AND !$invoiceModel->sent_accounting_date)
|
||||
@include('bo.partials.inputs.date', [
|
||||
'id' => 'invoiceSentaccountingdate',
|
||||
'label' => __('Date d\'envoi du :model à la compta', [
|
||||
'label' => __('Date d\'envoi du :model à la comptabilité', [
|
||||
'model' => __('models.classes.invoices'),
|
||||
]),
|
||||
'name' => 'sent_accounting_date',
|
||||
|
|
@ -62,17 +73,40 @@
|
|||
'model' => $invoiceModel ?? null,
|
||||
'helper' => __('Doît être une date réelle et existante.'),
|
||||
])
|
||||
@else
|
||||
<p class="fw-bold text-center m-0">{{ __('Envoyé à la compta le :date', ['date' => $invoiceModel->sent_accounting_date]) }}</p>
|
||||
@elseif ($invoiceModel->sent_accounting_date)
|
||||
<p class="fw-bold text-center m-0">
|
||||
{{ __('Envoyé à la comptabilité le :date', ['date' => \Carbon\Carbon::parse($invoiceModel->sent_accounting_date)->format('d/m/Y') ?? "xxx"]) }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
{{-- STATUS --}}
|
||||
@if ($invoiceModel->status === \App\Enums\Invoices\InvoiceStatusEnum::opened)
|
||||
<div class="col-12 col-md-6 p-0 pe-md-3">
|
||||
@include('bo.partials.inputs.tinyint-enum', [
|
||||
'id' => 'invoiceStatus',
|
||||
'label' => __('crud.minicrud.associated', [
|
||||
'entity' => 'État',
|
||||
]),
|
||||
'name' => 'status',
|
||||
'model' => $invoiceModel ?? null,
|
||||
'required' => true,
|
||||
'associatedModels' => $invoiceStatusArray,
|
||||
'helper' => __('crud.minicrud.select', [
|
||||
'entity' => 'État',
|
||||
]),
|
||||
])
|
||||
@else
|
||||
<div class="col-12 p-0 pe-md-3">
|
||||
<p class="fw-bold text-warning text-center m-0 mt-3">{{ $invoiceModel->status->label() }}</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@endif
|
||||
{{-- USER ASSOCIATED --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="row border w-100 h-100 bg-white mx-auto p-3" @if($invoiceModel->signed_date) disabled @endif>
|
||||
<fieldset class="row border w-100 h-100 bg-white mx-auto p-3" @if($invoiceModel->sent_client_date) disabled @endif>
|
||||
<legend class="p-0">{{ __('Informations sur la personne associée') }}</legend>
|
||||
<div class="row w-100 mx-auto p-0">
|
||||
{{-- FIRSTNAME --}}
|
||||
|
|
@ -126,7 +160,7 @@
|
|||
</div>
|
||||
{{-- OBJECT --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="border h-100 bg-white p-3" @if($invoiceModel->signed_date) disabled @endif>
|
||||
<fieldset class="border h-100 bg-white p-3" @if($invoiceModel->sent_client_date) disabled @endif>
|
||||
<legend>{{ Str::ucfirst(__('validation.attributes.object')) }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
|
|
@ -156,7 +190,7 @@
|
|||
</div>
|
||||
{{-- TASKS --}}
|
||||
<div class="col-12 pb-3">
|
||||
<fieldset class="border bg-white h-100 p-3" @if($invoiceModel->signed_date) disabled @endif>
|
||||
<fieldset class="border bg-white h-100 p-3" @if($invoiceModel->sent_client_date) disabled @endif>
|
||||
<legend>{{ __('validation.attributes.tasks') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
|
|
@ -164,7 +198,7 @@
|
|||
$data = [
|
||||
'companies' => $companyModels,
|
||||
'packages' => $packageModels,
|
||||
'taskTypeEnums' => collect(\App\Enums\Invoice\TaskTypeEnum::toArray())->values(),
|
||||
'taskTypeEnums' => collect(\App\Enums\Invoices\TaskTypeEnum::toArray())->values(),
|
||||
'taskRowModel' => $taskRowModel,
|
||||
'tasks' => $invoiceModel->tasks ?? []
|
||||
];
|
||||
|
|
@ -176,10 +210,13 @@
|
|||
</div>
|
||||
{{-- COMMENT --}}
|
||||
<div class="col-12 pb-3">
|
||||
<fieldset class="border bg-white h-100 p-3" @if($invoiceModel->signed_date) disabled @endif>
|
||||
<fieldset class="border bg-white h-100 p-3">
|
||||
<legend>{{ Str::ucfirst(__('validation.attributes.comment')) }}</legend>
|
||||
<div class="row mb-3">
|
||||
<div class="col-12">
|
||||
@if($invoiceModel->sent_client_date)
|
||||
<textarea class="form-control" disabled>{{ $invoiceModel->comment }}</textarea>
|
||||
@else
|
||||
@include('bo.partials.inputs.text-html', [
|
||||
'id' => 'invoiceComment',
|
||||
'label' => __('Commentaire du :model', [
|
||||
|
|
@ -187,18 +224,19 @@
|
|||
]),
|
||||
'name' => 'comment',
|
||||
'model' => $invoiceModel,
|
||||
'required' => true,
|
||||
'required' => false,
|
||||
'helper' => __('crud.minicrud.text_warning', [
|
||||
'number' => 15
|
||||
]),
|
||||
])
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- SITE_ID --}}
|
||||
<div class="col-12 col-md-6 pb-3">
|
||||
<fieldset class="border bg-white h-100 p-3" @if($invoiceModel->signed_date) disabled @endif>
|
||||
<fieldset class="border bg-white h-100 p-3" @if($invoiceModel->sent_client_date) disabled @endif>
|
||||
<legend>{{ Str::singular(trans('models.classes.sites')) }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
|
|
@ -212,7 +250,7 @@
|
|||
'routeName' => 'invoices.json-paginate',
|
||||
'modelRelated' => $siteModels ?? [],
|
||||
'modelSelected' => $invoiceModel->site ?? [],
|
||||
'readonly' => ($invoiceModel->signed_date) ? true : false,
|
||||
'readonly' => ($invoiceModel->sent_client_date) ? true : false,
|
||||
'placeholder' => __('Rechercher une :model', [
|
||||
'model' => Str::singular(trans('models.classes.sites')),
|
||||
]),
|
||||
|
|
@ -227,7 +265,7 @@
|
|||
</div>
|
||||
{{-- COMPANY_ID --}}
|
||||
<div class="col-12 col-md-6 pb-3">
|
||||
<fieldset class="border bg-white h-100 p-3" @if($invoiceModel->signed_date) disabled @endif>
|
||||
<fieldset class="border bg-white h-100 p-3" @if($invoiceModel->sent_client_date) disabled @endif>
|
||||
<legend>{{ Str::singular(trans('models.classes.companies')) }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
|
|
@ -241,7 +279,7 @@
|
|||
'routeName' => 'invoices.json-paginate',
|
||||
'modelRelated' => $companyModels ?? [],
|
||||
'modelSelected' => $invoiceModel->company ?? [],
|
||||
'readonly' => ($invoiceModel->signed_date) ? true : false,
|
||||
'readonly' => ($invoiceModel->sent_client_date) ? true : false,
|
||||
'placeholder' => __('Rechercher une :model', [
|
||||
'model' => Str::singular(trans('models.classes.companies')),
|
||||
]),
|
||||
|
|
@ -268,7 +306,7 @@
|
|||
'routeName' => 'invoices.json-paginate',
|
||||
'modelRelated' => $companyModels ?? [],
|
||||
'modelSelected' => $invoiceModel->companyInvoiced ?? [],
|
||||
'readonly' => ($invoiceModel->signed_date) ? true : false,
|
||||
'readonly' => ($invoiceModel->sent_client_date) ? true : false,
|
||||
'placeholder' => __('Rechercher une :model', [
|
||||
'model' => Str::singular(trans('models.classes.companies')),
|
||||
]),
|
||||
|
|
@ -283,7 +321,7 @@
|
|||
</div>
|
||||
{{-- SHOW DAYS --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="border h-100 bg-white p-3" @if($invoiceModel->signed_date) disabled @endif>
|
||||
<fieldset class="border h-100 bg-white p-3" @if($invoiceModel->sent_client_date) disabled @endif>
|
||||
<legend>{{ __('Visibilité') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
|
|
@ -302,6 +340,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
@if($invoiceModel->status === \App\Enums\Invoices\InvoiceStatusEnum::opened)
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
|
|
@ -315,3 +354,4 @@
|
|||
});
|
||||
</script>
|
||||
@endpush
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -6,13 +6,29 @@
|
|||
@section('content')
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center">
|
||||
@include('breadcrumbs.breadcrumb-body')
|
||||
<a href="{{ route('bo.invoices.create') }}"
|
||||
class="btn btn-primary float-right"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{{ __('crud.helpers.create_model', ['model' => Str::singular(__('models.classes.invoices'))]) }}">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
</a>
|
||||
<form id="invoiceStatus" action="{{ route('bo.invoices.index') }}">
|
||||
<div class="input-group justify-content-end">
|
||||
<select class="form-select w-fit" name="status" id="selectInvoiceStatus">
|
||||
@foreach (\App\Enums\Invoices\InvoiceStatusEnum::toArray() as $invoiceStatusEnum)
|
||||
<option value="{{ $invoiceStatusEnum->value }}" @if($status === $invoiceStatusEnum->value) selected @endif>
|
||||
{{ $invoiceStatusEnum->label }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@push('scripts')
|
||||
<script nonce="{{ $nonce }}">document.getElementById('selectInvoiceStatus').addEventListener('change', function (e) {
|
||||
document.getElementById('invoiceStatus').submit();
|
||||
});</script>
|
||||
@endpush
|
||||
<a href="{{ route('bo.invoices.create') }}"
|
||||
class="btn btn-primary float-right"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{{ __('crud.helpers.create_model', ['model' => Str::singular(__('models.classes.invoices'))]) }}">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@include('bo.modules.search-bar')
|
||||
<table class="table table-hover">
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
@section('content')
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-3">
|
||||
<div class="d-flex flex-row align-items-start">
|
||||
<a href="{{ route('bo.invoices.index') }}"
|
||||
<a href="{{ route('bo.invoices.index', ['status' => \App\Enums\Invoices\InvoiceStatusEnum::opened]) }}"
|
||||
class="btn btn-primary text-decoration-none m-0 me-2"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
|
|
|
|||
15
resources/views/bo/partials/inputs/date.blade.php
Normal file
15
resources/views/bo/partials/inputs/date.blade.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<label for="{{ $id }}">
|
||||
<b>{{ $label }}</b>
|
||||
</label>
|
||||
<input id="{{ $id }}"
|
||||
name="{{ $name }}"
|
||||
class="form-control"
|
||||
type="date"
|
||||
data-form-type="date"
|
||||
aria-describedby="{{ "{$id}Help" }}"
|
||||
value="{{ old($name, ((isset($model) and $model->{$name}) ? ($model->{$name}->format('Y-m-d') ?? ($defaultValue ? Carbon\Carbon::today() : '')) : ($defaultValue ? Carbon\Carbon::today() : ''))) }}">
|
||||
@include('modules.input-error', [
|
||||
'inputName' => $name,
|
||||
'helperId' => "{$id}Help",
|
||||
'helper' => $helper
|
||||
])
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
@if (count($breadcrumbs))
|
||||
<ol class="breadcrumb flex-nowrap border-0 w-100 p-0 m-0">
|
||||
<ol class="breadcrumb flex-nowrap border-0 w-fit p-0 m-0">
|
||||
@foreach ($breadcrumbs as $breadcrumb)
|
||||
@if ($breadcrumb->url && !$loop->last)
|
||||
<li class="breadcrumb-item d-flex h2 fw-bold m-0">
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
<a class="dropdown-item @if(Route::is('bo.projects.*'))active @endif" href="{{ route('bo.projects.index') }}">{{ __('models.classes.projects') }}</a>
|
||||
@endcan
|
||||
@can('isAdmin')
|
||||
<a class="dropdown-item @if(Route::is('bo.invoices.*'))active @endif" href="{{ route('bo.invoices.index') }}">{{ __('models.classes.invoices') }}</a>
|
||||
<a class="dropdown-item @if(Route::is('bo.invoices.*'))active @endif" href="{{ route('bo.invoices.index', ['status' => \App\Enums\Invoices\InvoiceStatusEnum::opened]) }}">{{ __('models.classes.invoices') }}</a>
|
||||
@endcan
|
||||
@can('isAdmin')
|
||||
<a class="dropdown-item @if(Route::is('bo.companies.*'))active @endif" href="{{ route('bo.companies.index') }}">{{ __('models.classes.companies') }}</a>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Enums\Invoices\InvoiceStatusEnum;
|
||||
use App\Models\Brand;
|
||||
use App\Models\Company;
|
||||
use App\Models\Dutyhour;
|
||||
|
|
@ -98,7 +99,7 @@ Breadcrumbs::for('bo.companies.edit', function (Generator $trail, Company $compa
|
|||
|
||||
// * INVOICES
|
||||
Breadcrumbs::for('bo.invoices.index', function (Generator $trail) {
|
||||
$trail->push(__('models.classes.invoices'), route('bo.invoices.index'));
|
||||
$trail->push(__('models.classes.invoices'), route('bo.invoices.index', ['status' => InvoiceStatusEnum::opened]));
|
||||
});
|
||||
Breadcrumbs::for('bo.invoices.create', function (Generator $trail) {
|
||||
$trail->parent('bo.invoices.index');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue