@@ -266,11 +266,257 @@ public function show(string $id)
266266 /**
267267 * Update the specified resource in storage.
268268 */
269- public function update (Request $ request , string $ id )
270- {
271- //
269+ public function update (Request $ request , $ id )
270+ {
271+ try {
272+ DB ::beginTransaction ();
273+
274+ // Log de la requête entrante
275+ Log::info ('Product update request received ' , ['product_id ' => $ id , 'request_all ' => $ request ->all ()]);
276+
277+ $ user = Auth::guard ('api ' )->user ();
278+ $ shop = Shop::where ('user_id ' , $ user ->id )->first ();
279+
280+ if (!$ shop ) {
281+ throw new \Exception ("Shop not found for the authenticated user. " );
282+ }
283+
284+ $ product = Product::where ('id ' , $ id )->where ('shop_id ' , $ shop ->id )->firstOrFail ();
285+
286+ // Mise à jour des champs de base
287+ $ product ->product_name = $ request ->product_name ;
288+ $ product ->product_description = $ request ->product_description ;
289+ $ product ->type = $ request ->type == 'simple ' ? 0 : 1 ;
290+ $ product ->product_gender = $ request ->product_gender ;
291+ $ product ->whatsapp_number = $ request ->whatsapp_number ;
292+ $ product ->product_residence = $ request ->product_residence ;
293+ // $product->status = 0; // Optionnel : remettre en attente après modification ?
294+
295+ // Gestion du produit simple
296+ if ($ product ->type == 0 ) {
297+ $ product ->product_price = $ request ->product_price ;
298+ $ product ->product_quantity = $ request ->product_quantity ;
299+ }
300+
301+ // Mise à jour de l'image principale si fournie
302+ if ($ request ->hasFile ('product_profile ' )) {
303+ // Supprimer l'ancienne image si nécessaire (optionnel)
304+ // if ($product->product_profile) { Storage::disk('public')->delete($product->product_profile); }
305+ $ product ->product_profile = $ request ->file ('product_profile ' )->store ('product/profile ' , 'public ' );
306+ }
307+
308+ // Gestion des prix de gros globaux (Produit Simple ou Variable Couleur Uniquement)
309+ if ($ request ->is_wholesale == "1 " ) {
310+ $ product ->is_wholesale = true ;
311+ $ product ->is_only_wholesale = ($ request ->is_only_wholesale == "1 " );
312+
313+ if ($ request ->has ('wholesale_prices ' )) {
314+ $ wholesalePricesData = json_decode ($ request ->wholesale_prices , true );
315+ // On supprime les anciens prix de gros globaux pour les remplacer
316+ $ product ->wholesalePrices ()->delete ();
317+
318+ if ($ wholesalePricesData ) {
319+ foreach ($ wholesalePricesData as $ wpData ) {
320+ if ($ wpData ['wholesale_price ' ] != "0 " ){
321+ $ product ->wholesalePrices ()->create ([
322+ 'min_quantity ' => $ wpData ['min_quantity ' ],
323+ 'wholesale_price ' => $ wpData ['wholesale_price ' ],
324+ ]);
325+ }
326+ }
327+ }
328+ }
329+ } else {
330+ $ product ->is_wholesale = false ;
331+ $ product ->is_only_wholesale = false ;
332+ $ product ->wholesalePrices ()->delete ();
333+ }
334+
335+ $ product ->save ();
336+
337+ // Gestion des images du produit (Ajout)
338+ if ($ request ->hasFile ('images ' )) {
339+ foreach ($ request ->file ('images ' ) as $ image ) {
340+ $ imagePath = $ image ->store ('product/images ' , 'public ' );
341+ $ product ->images ()->create (['image_path ' => $ imagePath ]);
342+ }
343+ }
344+
345+ // Gestion de la suppression des images du produit
346+ if ($ request ->filled ('images_to_delete ' )) {
347+ $ imagesToDelete = json_decode ($ request ->images_to_delete , true );
348+ if (is_array ($ imagesToDelete )) {
349+ // Supposons que imagesToDelete contient les IDs des images
350+ // Si ce sont des chemins, il faudra adapter la requête
351+ // $product->images()->whereIn('id', $imagesToDelete)->delete();
352+ // Note: Assurez-vous de supprimer aussi les fichiers physiques si nécessaire
353+ }
272354 }
273355
356+ // Gestion des variations pour produit variable
357+ if ($ product ->type == 1 && $ request ->filled ('variations ' )) {
358+ $ variationsData = json_decode ($ request ->variations , true );
359+ $ processedVariationIds = [];
360+
361+ foreach ($ variationsData as $ variationData ) {
362+ $ isColorAndAttribute = (isset ($ variationData ['sizes ' ]) && is_array ($ variationData ['sizes ' ]) && count ($ variationData ['sizes ' ]) > 0 ) ||
363+ (isset ($ variationData ['shoeSizes ' ]) && is_array ($ variationData ['shoeSizes ' ]) && count ($ variationData ['shoeSizes ' ]) > 0 );
364+
365+ // Mise à jour ou Création de la variation
366+ // On utilise l'ID s'il est présent et valide (non null)
367+ $ variation = null ;
368+ if (isset ($ variationData ['id ' ]) && $ variationData ['id ' ]) {
369+ $ variation = $ product ->variations ()->find ($ variationData ['id ' ]);
370+ }
371+
372+ if ($ variation ) {
373+ // Mise à jour
374+ $ variation ->update ([
375+ 'color_id ' => $ variationData ['color_id ' ],
376+ 'price ' => !$ isColorAndAttribute && isset ($ variationData ['price ' ]) ? $ variationData ['price ' ] : 0 ,
377+ 'quantity ' => !$ isColorAndAttribute && isset ($ variationData ['quantity ' ]) ? $ variationData ['quantity ' ] : null ,
378+ ]);
379+ } else {
380+ // Création
381+ $ variation = $ product ->variations ()->create ([
382+ 'color_id ' => $ variationData ['color_id ' ],
383+ 'price ' => !$ isColorAndAttribute && isset ($ variationData ['price ' ]) ? $ variationData ['price ' ] : 0 ,
384+ 'quantity ' => !$ isColorAndAttribute && isset ($ variationData ['quantity ' ]) ? $ variationData ['quantity ' ] : null ,
385+ ]);
386+ }
387+
388+ $ processedVariationIds [] = $ variation ->id ;
389+ $ variationId = $ variationData ['id ' ] ?? $ variation ->id ; // ID utilisé pour les images (frameId)
390+
391+ // Gestion des images de variation (Ajout)
392+ // Le frontend envoie `variation_images[frameId][index]`
393+ // Si c'est une nouvelle variation, frameId est temporaire, mais le frontend l'utilise pour mapper les fichiers
394+ // Il faut faire attention ici : si le frontend envoie un ID temporaire 'frame-...', il faut le récupérer
395+ $ frameId = $ variationData ['id ' ] ?? null ;
396+ // Note: Dans votre code frontend, vous envoyez `variation_images[frame.id]`.
397+ // Si frame.id est 'frame-...', c'est ce qui est utilisé comme clé.
398+ // Si frame.id est un ID de base de données, c'est ce qui est utilisé.
399+
400+ // On doit itérer sur les fichiers envoyés pour trouver ceux correspondant à cette variation
401+ // Astuce : Le frontend utilise l'ID de la frame (qui peut être temporaire ou réel) comme clé.
402+ // Vous devez probablement passer cet ID temporaire dans le payload JSON des variations pour faire le lien.
403+ // Dans votre code frontend actuel, vous envoyez `id: frame.id.startsWith('frame-') ? null : frame.id`.
404+ // Cela signifie que vous perdez l'ID temporaire dans le JSON 'variations'.
405+ // CORRECTION REQUISE CÔTÉ FRONTEND ou BACKEND :
406+ // Le plus simple est de se fier à l'ordre ou d'envoyer l'ID temporaire dans le JSON.
407+ // MAIS, le frontend envoie `variation_images[frame.id]`.
408+ // Si frame.id est null dans le JSON, on ne peut pas faire le lien facilement si on a plusieurs nouvelles variations.
409+
410+ // Supposons pour l'instant que vous utilisez l'ID réel pour les updates, et que pour les créations ça marche par index ou que vous avez ajusté le frontend.
411+ // Pour ce code, je vais assumer que vous pouvez récupérer les images via une clé.
412+
413+ // Approche robuste : Le frontend devrait envoyer un `temp_id` dans le JSON si `id` est null, et utiliser ce `temp_id` pour les clés de fichiers.
414+ // Avec le code actuel du frontend : `formData.append('variation_images[${frame.id}][${imgIndex}]', img);`
415+ // Si frame.id est 'frame-123', c'est la clé. Mais dans le JSON `variations`, `id` est null.
416+ // Il faudrait modifier le frontend pour envoyer `temp_id` ou `key` dans le JSON.
417+
418+ // Workaround avec le code actuel :
419+ // Si `id` est présent (update), la clé est l'ID.
420+ // Si `id` est null (create), c'est compliqué sans changer le frontend.
421+
422+ // Code générique pour les images (à adapter selon votre logique de clé)
423+ $ imageKey = $ variationData ['id ' ] ?: $ variationData ['temp_id ' ] ?? null ; // Idéalement
424+ if ($ imageKey ) {
425+ $ prefix = "variation_images. {$ imageKey }" ; // Notation dot pour array imbriqué
426+ // Laravel gère les tableaux de fichiers différemment, souvent via $request->file('variation_images')[$key]
427+ $ uploadedImages = $ request ->file ('variation_images ' );
428+ if (isset ($ uploadedImages [$ imageKey ])) {
429+ foreach ($ uploadedImages [$ imageKey ] as $ image ) {
430+ $ imagePath = $ image ->store ('product/variations ' , 'public ' );
431+ $ variation ->images ()->create (['image_path ' => $ imagePath ]);
432+ }
433+ }
434+ }
435+
436+ // Gestion des attributs (Tailles/Pointures)
437+ if ($ isColorAndAttribute ) {
438+ $ processedAttrIds = [];
439+ $ attributesList = array_merge ($ variationData ['sizes ' ] ?? [], $ variationData ['shoeSizes ' ] ?? []);
440+
441+ foreach ($ attributesList as $ attrData ) {
442+ // Update ou Create VariationAttribute
443+ // On cherche par attribute_value_id pour cette variation
444+ $ attrVariation = $ variation ->attributesVariation ()->updateOrCreate (
445+ ['attribute_value_id ' => $ attrData ['id ' ]],
446+ [
447+ 'quantity ' => $ attrData ['quantity ' ],
448+ 'price ' => $ attrData ['price ' ],
449+ ]
450+ );
451+ $ processedAttrIds [] = $ attrVariation ->id ;
452+
453+ // Prix de gros attribut
454+ if (isset ($ attrData ['wholesalePrices ' ]) && is_array ($ attrData ['wholesalePrices ' ])) {
455+ $ attrVariation ->wholesalePrices ()->delete (); // Remplacer
456+ foreach ($ attrData ['wholesalePrices ' ] as $ wpData ) {
457+ $ attrVariation ->wholesalePrices ()->create ([
458+ 'min_quantity ' => $ wpData ['min_quantity ' ],
459+ 'wholesale_price ' => $ wpData ['wholesale_price ' ],
460+ ]);
461+ }
462+ }
463+ }
464+ // Supprimer les attributs qui ne sont plus présents
465+ $ variation ->attributesVariation ()->whereNotIn ('id ' , $ processedAttrIds )->delete ();
466+ }
467+ }
468+
469+ // Supprimer les variations qui ne sont plus dans la liste (si on veut une synchro complète)
470+ // Attention : cela supprimera les variations non renvoyées.
471+ $ product ->variations ()->whereNotIn ('id ' , $ processedVariationIds )->delete ();
472+ }
473+
474+ // Suppression d'images de variation spécifiques
475+ if ($ request ->filled ('variation_images_to_delete ' )) {
476+ $ varImagesToDelete = json_decode ($ request ->variation_images_to_delete , true );
477+ // Structure attendue : { "frameId": [imageId1, imageId2] }
478+ foreach ($ varImagesToDelete as $ frameId => $ imageIds ) {
479+ // Trouver la variation (soit par frameId si c'est l'ID réel, sinon ignorer car nouvelle variation n'a pas d'images à supprimer)
480+ // Si frameId est un ID numérique
481+ if (is_numeric ($ frameId )) {
482+ $ variation = $ product ->variations ()->find ($ frameId );
483+ if ($ variation ) {
484+ // $variation->images()->whereIn('id', $imageIds)->delete();
485+ }
486+ }
487+ }
488+ }
489+
490+ // Synchronisation des catégories
491+ $ categories = [];
492+ if ($ request ->has ('categories ' ) && is_array ($ request ->categories )) {
493+ $ categories = array_merge ($ categories , array_map ('intval ' , $ request ->categories ));
494+ }
495+ if ($ request ->has ('sub_categories ' ) && is_array ($ request ->sub_categories )) {
496+ $ categories = array_merge ($ categories , array_map ('intval ' , $ request ->sub_categories ));
497+ }
498+ $ product ->categories ()->sync ($ categories );
499+
500+
501+ DB ::commit ();
502+ Log::info ('Product update transaction committed ' , ['product_id ' => $ product ->id ]);
503+
504+ return response ()->json (['message ' => "Product updated successfully " ], 200 );
505+
506+ } catch (\Exception $ e ) {
507+ DB ::rollBack ();
508+ Log::error ('Product update failed ' , [
509+ 'error ' => $ e ->getMessage (),
510+ 'trace ' => $ e ->getTraceAsString ()
511+ ]);
512+ return response ()->json ([
513+ 'success ' => false ,
514+ 'message ' => 'Something went wrong ' ,
515+ 'error ' => $ e ->getMessage ()
516+ ], 500 );
517+ }
518+ }
519+
274520 /**
275521 * Remove the specified resource from storage.
276522 */
@@ -298,4 +544,8 @@ public function getEditProduct($url){
298544 $ product =Product::where ('product_url ' ,$ url )->first ();
299545 return response ()->json (new ProductEditResource ($ product ));
300546 }
547+
548+
301549 }
550+
551+
0 commit comments