diff --git a/app/Enums/Products/CertificationEnum.php b/app/Enums/Products/CertificationEnum.php index 85eb0d0..ff575d7 100644 --- a/app/Enums/Products/CertificationEnum.php +++ b/app/Enums/Products/CertificationEnum.php @@ -12,8 +12,8 @@ enum CertificationEnum: int case labelRouge = 2; case certifiedCQ = 3; case standard = 4; - case freeRange = 5; - case others = 6; + case freeRange = 6; + case others = 5; /** * Custom added functions definition diff --git a/app/Enums/Products/RangeEnum.php b/app/Enums/Products/RangeEnum.php index 5ee737a..0465deb 100644 --- a/app/Enums/Products/RangeEnum.php +++ b/app/Enums/Products/RangeEnum.php @@ -18,9 +18,9 @@ enum RangeEnum: int case rawMeat = 8; case cookedMeats = 9; case farcis = 10; - case plant = 11; - case frozenSpecific = 12; - case others = 13; + case plant = 12; + case frozenSpecific = 13; + case others = 11; /** * Custom added functions definition diff --git a/app/Enums/Products/SourceEnum.php b/app/Enums/Products/SourceEnum.php index 64d0f92..0e57de9 100644 --- a/app/Enums/Products/SourceEnum.php +++ b/app/Enums/Products/SourceEnum.php @@ -8,13 +8,20 @@ enum SourceEnum: int { use BaseEnum; - case catalogArgumentary = 1; - case magazin = 2; - case press = 3; - case showConsumer = 4; - case showCustomer = 5; - case showTrade = 6; - case web = 7; + // * Catalogue argumentaire + case catalogArgumentary = 7; + // * Magasin + case magazin = 1; + // * Presse + case press = 3; + // * Salon Grand Public + case showConsumer = 6; + // * Salon Clients + case showCustomer = 5; + // * Salon Professionnel + case showTrade = 4; + // * Web + case web = 2; /** * Custom added functions definition diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php index 04efddd..e56d63a 100644 --- a/app/Http/Controllers/ProductController.php +++ b/app/Http/Controllers/ProductController.php @@ -13,6 +13,7 @@ use App\Models\Product; use App\Traits\Controllers\HasDocuments; use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; @@ -32,7 +33,7 @@ class ProductController extends Controller $brandsQuery = Brand::query(); /** @var \Illuminate\Database\Eloquent\Builder $productsQuery */ - $productsQuery = Product::query(); + $productsQuery = Product::query()->orderBy('created_at', 'desc'); $this->requestFilters($request, $productsQuery); @@ -58,11 +59,12 @@ class ProductController extends Controller /** * Show the form for creating a new resource. * - * @param App\Models\Product $productModel + * @param App\Models\Product $productModel + * @param Illuminate\Support\Collection $commentModel * @return \Illuminate\Contracts\View\View * phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass */ - public function create(Product $productModel): \Illuminate\Contracts\View\View + public function create(Product $productModel, Collection $commentModel): \Illuminate\Contracts\View\View { //phpcs:enable $brands = Brand::all(); @@ -82,7 +84,8 @@ class ProductController extends Controller 'productsFair', 'productsShop', 'productsCatalog', - 'keywords' + 'keywords', + 'commentModel' )); } @@ -255,7 +258,11 @@ class ProductController extends Controller */ public function duplicate(Product $product) { - return $this->create($product->replicate()); + $duplicatedProduct = $product->replicate(); + foreach ($product->productComments as $comment) { + $duplicatedComments[] = $comment->replicate(); + } + return $this->create($duplicatedProduct, collect($duplicatedComments ?? null)); } /** diff --git a/app/Http/Requests/Products/StoreProductRequest.php b/app/Http/Requests/Products/StoreProductRequest.php index 73d0eb2..d34f771 100644 --- a/app/Http/Requests/Products/StoreProductRequest.php +++ b/app/Http/Requests/Products/StoreProductRequest.php @@ -11,7 +11,7 @@ use App\Enums\Products\RangeEnum; use App\Enums\Products\RayEnum; use App\Enums\Products\SourceEnum; use App\Lib\Helpers\ToolboxHelper; -use App\Traits\Requests\HasDocument; +use App\Traits\Requests\HasDocumentAndPictureList; use App\Traits\Requests\HasPicture; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rules\Enum; @@ -20,7 +20,7 @@ use Illuminate\Validation\ValidationException; class StoreProductRequest extends FormRequest { use HasPicture; - use HasDocument; + use HasDocumentAndPictureList; /** * Determine if the user is authorized to make this request. @@ -63,12 +63,9 @@ class StoreProductRequest extends FormRequest 'name' => 'required|string|min:3|max:255', 'brand_id' => 'required|exists:brands,id', 'source' => [new Enum(SourceEnum::class)], - 'fair' => 'nullable|string|min:3|max:255|required_if:source,' . - SourceEnum::showConsumer->value . ',' . - SourceEnum::showCustomer->value . ',' . - SourceEnum::showTrade->value, - 'shop' => 'nullable|string|min:3|max:255|required_if:source,' . SourceEnum::magazin->value, - 'catalogue' => 'nullable|string|min:3|max:255|required_if:source,' . SourceEnum::catalogArgumentary->value, + 'fair' => 'nullable|string|min:3|max:255', + 'shop' => 'nullable|string|min:3|max:255', + 'catalogue' => 'nullable|string|min:3|max:255', 'gencod' => 'nullable|numeric|min:0', 'picture_alt' => 'required|min:3|max:255', 'picture_title' => 'required|min:3|max:255', @@ -110,7 +107,7 @@ class StoreProductRequest extends FormRequest return \array_merge( $rules, $this->pictureRules('picture', false, 1200, 900, 1200, 900), - $this->documentsRules('docs', false), + $this->documentsRules('docs'), ); } diff --git a/app/Http/Resources/ProductResource.php b/app/Http/Resources/ProductResource.php index 278510d..097ff52 100644 --- a/app/Http/Resources/ProductResource.php +++ b/app/Http/Resources/ProductResource.php @@ -34,6 +34,7 @@ class ProductResource extends JsonResource 'certification' => null, 'origins' => null, 'claims' => null, + 'specified_claim' => null, 'distribution_network' => null, 'ray' => null, 'product_range' => null, @@ -69,7 +70,7 @@ class ProductResource extends JsonResource 'user' => (object)$this->product->user->toArray(), 'brand' => (object)$this->product->brand->toArray(), 'name' => $this->product->name, - 'seen_at' => $this->product->seen_at->isoFormat('DD\/MM\/YYYY \à HH\hmm'), + 'seen_at' => $this->product->seen_at->isoFormat('DD\/MM\/YYYY'), 'source' => $this->product->source->label(), 'fair' => $this->product->fair, 'shop' => $this->product->shop, @@ -80,9 +81,10 @@ class ProductResource extends JsonResource 'picture' => $this->product->picture, 'picture_alt' => $this->product->picture_alt, 'picture_title' => $this->product->picture_title, - 'certification' => \optional($this->product->certification)->label, + 'certification' => \optional($this->product->certification)->label(), 'origins' => $this->product->origins_enum->map(fn (OriginEnum $enum) => $enum->label())->implode(', '), 'claims' => $this->product->claims_enum->map(fn (ClaimEnum $enum) => $enum->label())->implode(', '), + 'specified_claim' => $this->product->specified_claim, 'distribution_network' => $this->product->distribution_network->label(), 'ray' => $this->product->ray->label(), 'product_range' => $this->product->product_range->label(), diff --git a/app/Models/Product.php b/app/Models/Product.php index 6b52924..b339122 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -185,7 +185,9 @@ class Product extends Model { $check = false; foreach ($model->claims as $claimValue) { - $check = (intval($claimValue) === \App\Enums\Products\ClaimEnum::others->value) ? true : false; + if (!$check) { + $check = (intval($claimValue) === \App\Enums\Products\ClaimEnum::others->value) ? true : false; + } } $model->specified_claim = ($check) ? $model->specified_claim : null; } diff --git a/app/Traits/Requests/HasDocument.php b/app/Traits/Requests/HasDocumentAndPictureList.php similarity index 58% rename from app/Traits/Requests/HasDocument.php rename to app/Traits/Requests/HasDocumentAndPictureList.php index 63ea180..f5864ed 100644 --- a/app/Traits/Requests/HasDocument.php +++ b/app/Traits/Requests/HasDocumentAndPictureList.php @@ -4,24 +4,43 @@ namespace App\Traits\Requests; use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Str; -trait HasDocument +trait HasDocumentAndPictureList { + /** + * Autorised mimtypes + * + * @var string[] + */ + private $autorisedMimTypes = [ + 'application/msword', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'image/jpeg', + 'image/png', + 'image/gif', + 'application/pdf', + 'application/vnd.ms-powerpoint', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'text/csv', + 'text/plain', + ]; + /** * Images rules * - * @param string $name - * @param boolean $required + * @param string $name * @return array */ public function documentsRules( - string $name = 'documents', - ?bool $required = null + string $name = 'docs', ): array { return [ - "{$name}" => ($required ? 'required' : 'nullable') . '|array', + "{$name}" => 'present|array', "{$name}.*" => [ - $required ? 'required' : 'nullable', + 'required', function (string $attribute, $value, callable $fail) { return $this->validateDocument($attribute, $value, $fail); } @@ -40,29 +59,32 @@ trait HasDocument */ private function validateDocument(string $attribute, mixed $value, callable $fail) { + // phpcs:enable if (!($useStorage = Storage::exists($value)) and !File::exists($value)) { $fail(trans(":attribute n'existe pas dans le système de fichier")); return; } - if ( - !\in_array($this->getUploadedFileMimeType($value, $useStorage), [ - 'application/pdf' - ]) - ) { - $fail(trans(":attribute doit être une image de type 'application/pdf'")); + if (!\in_array($this->getUploadedFileMimeType($value, $useStorage), $this->autorisedMimTypes)) { + $fail(trans(':attribute doit être un document de type :mimetypes', [ + 'mimetypes' => Str::of($this->autorisedMimTypes)->implode(' ou ') + ])); + } + $maxSize = 6 * 1024 * 1024; + if (File::size($value) > $maxSize) { + $fail(trans(':attribute doit être inférieur à :size Mo', ['size' => $maxSize / (1024 * 1024)])); } } /** - * Merges documents fields with request data. + * Merges docs fields with request data. * * @param string $name * @return void */ - protected function mergeDocuments(string $name = 'documents'): void + protected function mergeDocuments(string $name = 'docs'): void { $documents = $this->{$name}; - $this->merge(['doc' => $this->docs ?? []]); + $this->merge([$name => $this->{$name} ?? []]); $this->merge(["{$name}Validate" => []]); if (is_array($documents)) { foreach ($documents as $key => $documentPath) { diff --git a/app/Traits/Requests/HasPicture.php b/app/Traits/Requests/HasPicture.php index ff664c4..d18ad34 100644 --- a/app/Traits/Requests/HasPicture.php +++ b/app/Traits/Requests/HasPicture.php @@ -138,6 +138,11 @@ trait HasPicture ) { $fail(trans(":attribute doit être une image de type 'image/jpeg,image/jpg,image/png,image/gif'")); } + $filesize = \filesize($fileFullPath); + $maxSize = 6 * 1024 * 1024; + if ($filesize === false || $filesize > $maxSize) { + $fail(trans(':attribute doit être inférieur à :size Mo', ['size' => $maxSize / (1024 * 1024)])); + } if (!($dimensions = \getimagesize($fileFullPath)) or !isset($dimensions[0]) or !isset($dimensions[1])) { $fail(trans(":attribute impossible de valider les dimensions")); } else { diff --git a/database/migrations/2023_12_06_124752_migrate_oci_tables.php b/database/migrations/2023_12_06_124752_migrate_oci_tables.php index be8c442..0fffcd8 100644 --- a/database/migrations/2023_12_06_124752_migrate_oci_tables.php +++ b/database/migrations/2023_12_06_124752_migrate_oci_tables.php @@ -368,9 +368,9 @@ return new class extends Migration } catch (\Exception) { throw new \Error("brand` {$brandName}` not found"); } - $url = $row->URL ? Str::of(url($row->URL))->lower() : null; + $url = $row->URL ? Str::lower(url($row->URL)) : null; $date_saisie = $row->DATE_SAISIE ? $this->tryToParseCarbon($row->DATE_SAISIE, true) : null; - $is_tasted = Str::of($row->DEGUSTER_O_N)->lower() === 'o' ? true : false; + $is_tasted = Str::lower($row->DEGUSTER_O_N) === 'o' ? true : false; $claimList = collect([ $row->ALLEG0, $row->ALLEG1, $row->ALLEG2 ])->filter()->map(fn (string $alleg) => $resolveAllegation($alleg)); @@ -669,7 +669,7 @@ return new class extends Migration $tableComment = "{$tableColumn->name} {$tableColumn->type} {$tableColumn->size}"; switch ($tableColumn->type) { case 'NUMBER': - $table->bigInteger($tableColumn->name) + $table->double($tableColumn->name) ->nullable()->comment($tableComment); break; case 'VARCHAR2': diff --git a/resources/sass/base/_common.scss b/resources/sass/base/_common.scss index 479a389..47ab386 100644 --- a/resources/sass/base/_common.scss +++ b/resources/sass/base/_common.scss @@ -26,3 +26,9 @@ display: block; } } + +.pagination-custom .dropdown-menu { + overflow: auto; + min-width: 5rem; + max-height: 178px; +} diff --git a/resources/ts/components/BelongsToDropdown.vue b/resources/ts/components/BelongsToDropdown.vue index 8accf2a..4d2c912 100644 --- a/resources/ts/components/BelongsToDropdown.vue +++ b/resources/ts/components/BelongsToDropdown.vue @@ -109,18 +109,20 @@ export default defineComponent({ methods: { parseTags(intSelectedItem: number[]): CustomTag[] { const out: CustomTag[] = []; - intSelectedItem.forEach((intItem: number) => { - const selectedItem = this.allItems.find(item => String(item.id) === String(intItem)); - if (!selectedItem) { - console.debug(intItem); - throw new Error(`Could not find enum ${intItem}`); - } - out.push({ - id: String(selectedItem.id), - value: String(selectedItem.id), - text: String(selectedItem[`${this.labelField}`]) - } as LaravelModel as CustomTag); - }); + if (intSelectedItem[0] !== null) { + intSelectedItem.forEach((intItem: number) => { + const selectedItem = this.allItems.find(item => String(item.id) === String(intItem)); + if (!selectedItem) { + console.debug(intItem); + throw new Error(`Could not find enum ${intItem}`); + } + out.push({ + id: String(selectedItem.id), + value: String(selectedItem.id), + text: String(selectedItem[`${this.labelField}`]) + } as LaravelModel as CustomTag); + }); + } return out; }, parseNewlyCreated(newModel: LaravelModel): CustomTag { diff --git a/resources/ts/components/MultipleCommentsComponent.vue b/resources/ts/components/MultipleCommentsComponent.vue index 10d0eb1..f6b085d 100644 --- a/resources/ts/components/MultipleCommentsComponent.vue +++ b/resources/ts/components/MultipleCommentsComponent.vue @@ -38,13 +38,13 @@ type="button" data-bs-toggle="collapse" :data-bs-target="'#comment' + commentIndex" - aria-expanded="false" + :aria-expanded="intModel.length > 0 ? true : false" :aria-controls="'comment' + commentIndex" > {{ __("Commentaire n°" + (commentIndex + 1)) }}
@@ -94,7 +93,6 @@ :name="'aspect[' + commentIndex + ']'" class="form-control" :value="comment?.aspect" - :placeholder="__('Un peu caoutchouteux')" :ariadescribedby="'productcommentAspect' + commentIndex" />
@@ -128,7 +126,6 @@ :name="'taste[' + commentIndex + ']'" class="form-control" :value="comment?.taste" - :placeholder="__('Un peu caoutchouteux')" :ariadescribedby="'productcommentTaste' + commentIndex" />
@@ -162,7 +159,6 @@ :name="'odor[' + commentIndex + ']'" class="form-control" :value="comment?.odor" - :placeholder="__('Un peu caoutchouteux')" :ariadescribedby="'productcommentOdor' + commentIndex" />
@@ -196,7 +192,6 @@ :name="'texture[' + commentIndex + ']'" class="form-control" :value="comment?.texture" - :placeholder="__('Un peu caoutchouteux')" :ariadescribedby="'productCommentTexture' + commentIndex" />
diff --git a/resources/ts/components/MultipleDocumentsInputComponent.vue b/resources/ts/components/MultipleDocumentsInputComponent.vue index f2e0425..ed33fa9 100644 --- a/resources/ts/components/MultipleDocumentsInputComponent.vue +++ b/resources/ts/components/MultipleDocumentsInputComponent.vue @@ -7,11 +7,11 @@