File "ProductApiController.php"

Full Path: /home/clickysoft/public_html/jmapi5.clickysoft.net/app/Http/Controllers/Api/V1/Admin/ProductApiController.php
File size: 17.3 KB
MIME-type: text/x-php
Charset: utf-8

<?php

namespace App\Http\Controllers\Api\V1\Admin;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Traits\MediaUploadingTrait;
use App\Http\Requests\Admin\StoreProductRequest;
use App\Http\Requests\Admin\UpdateProductRequest;
use App\Http\Resources\Admin\ProductDetailsResource;
use App\Http\Resources\Admin\ProductResource;
use App\Http\Resources\Admin\ProductResourceWithAttributes;
use App\Http\Resources\Admin\ProductSimple;
use App\Models\OrderItems;
use App\Models\Product;
use App\Models\ProductPrice;
use App\Models\ProductVariation;
use App\Models\ProductVariationCombination;
use App\Models\ProductVariationRange;
use Illuminate\Support\Facades\Gate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\Response;

class ProductApiController extends Controller
{
    use MediaUploadingTrait;

    public function index(Request $request)
    {
        abort_if(Gate::denies('product_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');

        ProductResource::withoutWrapping();
        $products = Product::when($request->filled('category'), function ($query) use ($request){
            $query->whereHas('category', function ($query) use ($request) {
                $query->where('name', 'like', "%{$request->get('category')}%");
                $query->orWhere('id', $request->get('category'));
            });
        })
            ->when($request->filled('name'), function ($query) use ($request){
                $query->where('name', 'like', "%{$request->get('name')}%");
        })
            ->when($request->filled('sku'), function ($query) use ($request){
                $query->where('sku', 'like', "%{$request->get('sku')}%");
        })
            ->when($request->filled('is_draft'), function ($query) use ($request){
                $query->where('is_draft', $request->get('is_draft'));
        })
            ->when($request->filled('product_type'), function ($query) use ($request){
                $query->where('product_type', 'like', "%{$request->get('product_type')}%");
        })
            ->with([
            'category',
            'variations',
            'variations.variation',
            'prices',
            'prices.combinations',
            'prices.priceRanges',
        ])->orderBy('created_at', 'DESC')->paginate(10);

        return ProductResource::collection($products);
    }

    public function getProductsForOrder(Request $request)
    {
        $products = Product::when($request->filled('name'), function ($query) use ($request){
            $query->where('name', 'like', "%{$request->get('name')}%");
        })
            ->when($request->filled('sku'), function ($query) use ($request){
                $query->where('sku', 'like', "%{$request->get('sku')}%");
            });

        $products = $products->orderBy('name')->get();

        ProductSimple::withoutWrapping();
        return ProductSimple::collection($products);
    }

    public function getProductDetails(Product $product)
    {
        return new ProductDetailsResource($product);
    }

    public function change_status(Product $product)
    {
        abort_if(Gate::denies('product_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
        $product->status = !$product->status;
        $product->save();

        return response()
            ->json(['message' => 'Product status updated successfully'], Response::HTTP_OK);
    }

    public function store(StoreProductRequest $request)
    {
        DB::beginTransaction();
        try {
            $product = Product::create([
                'vendor_id' => $request['vendor_id'] ?? null,
                'sku' => $request['sku'],
                'name' => $request['name'],
                'description' => $request['description'],
                'engraving' => $request['engraving'],
                'color_engraving' => $request['color_engraving'],
                'engraving_fee' => $request['engraving_fee'],
                'status' => $request['status'],
                'is_draft' => $request['is_draft'],
                'product_type' => $request['product_type'],
                'category_id' => $request['category_id'],
                'has_variations' => 1,
            ]);

            if ($request->hasFile('featured_image')) {
                $product->addMediaFromRequest('featured_image')
                    ->toMediaCollection('product_featured_image', 'product')->save();
            }

            foreach ($request->file('gallery_images', []) as $file) {
                $product->addMedia($file)->toMediaCollection('gallery_image', 'product');
            }

            $product->handleVariations($request);

            DB::commit();

            return (new ProductResource($product))
                ->response()
                ->setStatusCode(Response::HTTP_CREATED);

        } catch (\Exception $e){
            \Log::channel('db_errors')->info('Product Create Error');
            \Log::channel('db_errors')->info($e->getMessage());
            return response()
                ->json([
                    'message' => "Can not create product.",
                    'errors' => ["error" => ["Unable to create product."]]
                ], Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    public function show(Product $product)
    {
        abort_if(Gate::denies('product_show'), Response::HTTP_FORBIDDEN, '403 Forbidden');
        $product = $product->load([
            'category',
            'variations',
            'variations.variation',
            'prices',
            'prices.combinations',
            'prices.priceRanges',
        ]);
        return new ProductResourceWithAttributes($product);
    }

    public function update(UpdateProductRequest $request, Product $product)
    {
        DB::beginTransaction();
        try {

            $product->update([
                'category_id' => $request['category_id'],
                'vendor_id' => $request['vendor_id'] ?? null,
                'sku' => $request['sku'],
                'name' => $request['name'],
                // 'slug' => $request['slug'],
                'description' => $request['description'],
                'engraving' => $request['engraving'],
                'color_engraving' => $request['color_engraving'],
                'engraving_fee' => $request['engraving_fee'],
                'has_variations' => 1,
                'status' => $request['status'],
                'is_draft' => $request['is_draft'],
                'product_type' => $request['product_type'],
            ]);

            if ($request->hasFile('featured_image')) {
                if (!empty($product->featured_image)) {
                    $product->clearMediaCollection('product_featured_image');
                }
                $product->addMediaFromRequest('featured_image')
                    ->toMediaCollection('product_featured_image', 'product');
                $product->save();
            }

            if ($request->hasFile('gallery_images')){

                foreach ($request->file('gallery_images', []) as $file) {
                    $product->addMedia($file)->toMediaCollection('gallery_image', 'product');
                }
            }

            $product->handleVariations($request);

            $product->save();

            DB::commit();

            return (new ProductResource($product))
                ->response()
                ->setStatusCode(Response::HTTP_CREATED);

        }catch (\Exception $e){
            \Log::channel('db_errors')->info('Product Update Error');
            \Log::channel('db_errors')->info($e->getMessage());
            DB::rollBack();
            return response()
                ->json([
                    'message' => "Can not update product.",
                    'errors' => ["error" => ["Unable to update product."]]
                ], Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    public function destroy(Product $product)
    {
        abort_if(Gate::denies('product_delete'), Response::HTTP_FORBIDDEN, '403 Forbidden');

        try {
            $product->prices()->delete();
            $product->variations()->delete();
            ProductVariationCombination::where('product_id', $product->id)->delete();
            ProductVariationRange::where('product_id', $product->id)->delete();
            $product->delete();
            return response()
                ->json(['message' => 'Product deleted successfully'], Response::HTTP_OK);
        }catch (\Exception $e){
            \Log::channel('db_errors')->info('Record Deletion Error : Product -> '.$product->id);
            \Log::channel('db_errors')->info($e->getMessage());
            return response()
                ->json([
                    'message' => "Record not deleted.",
                    'errors' => ["error" => ["Unable to delete product."]]
                ], Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    public function cloneProduct(Product $product)
    {
        abort_if(Gate::denies('product_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');

        DB::beginTransaction();
        try {
            $cloned_product = $product->replicate();
            $cloned_product->name = $cloned_product->name.' Clone';
            $cloned_product->sku = $cloned_product->sku.'-clone'. time();
            $cloned_product->slug = $cloned_product->slug.'-clone';
            $cloned_product->is_draft = true;
            $cloned_product->created_at = now();
            $cloned_product->updated_at = now();
            $cloned_product->save();

            $this->cloneFeaturedImage($product, $cloned_product);
            $this->duplicateVariations($product, $cloned_product);
            $prices = $this->duplicateProductPrices($product, $cloned_product);
            $variation_prices_ids = $this->duplicateProductVariationPriceRanges($product, $cloned_product, $prices);
            $this->duplicateProductVariationCombinations($product, $cloned_product, $variation_prices_ids);

            DB::commit();

            return (new ProductResource($cloned_product))
                ->response()
                ->setStatusCode(Response::HTTP_CREATED);

        } catch (\Exception $e){
            \Log::channel('db_errors')->info('Product Clone Error');
            \Log::channel('db_errors')->info($e->getMessage(). ' on line : '. $e->getLine());
            return response()
                ->json([
                    'message' => "Can not clone product.",
                    'errors' => ["error" => ["Unable to clone product. (".$e->getMessage().")"]]
                ], Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    public function duplicateVariations($existing_product, $cloned_product)
    {
        $product_variations = ProductVariation::where('product_id', $existing_product->id)->get();

        foreach ($product_variations as $product_variation) {
            $clone_product_variation = $product_variation->replicate();
            $clone_product_variation->product_id = $cloned_product->id;
            $clone_product_variation->created_at = now();
            $clone_product_variation->updated_at = now();
            $clone_product_variation->save();
        }
    }

    public function duplicateProductPrices($existing_product, $cloned_product)
    {
        $product_prices = ProductPrice::where('product_id', $existing_product->id)->get();
        $price_ids = [];

        foreach ($product_prices as $product_price) {
            $clone_product_price = $product_price->replicate();
            $clone_product_price->product_id = $cloned_product->id;
            $clone_product_price->supplier_prod_number = $product_price->supplier_prod_number."-clone";
            $clone_product_price->created_at = now();
            $clone_product_price->updated_at = now();
            $clone_product_price->save();

            if ($product_price->product_sketch != null) {
                $this->cloneSketch($product_price, $clone_product_price);
                $product_price->save();
            }

            $price_ids[$product_price->id] = $clone_product_price->id;
        }

        return $price_ids;
    }

    public function duplicateProductVariationPriceRanges($existing_product, $cloned_product, $prices)
    {
        $product_variation_price_ranges = ProductVariationRange::where('product_id', $existing_product->id)->get();
        $variation_price_ids = [];

        foreach ($product_variation_price_ranges as $key => $product_variation_price_range) {
            $clone_product_variation_price_range = $product_variation_price_range->replicate();
            $clone_product_variation_price_range->product_id = $cloned_product->id;
            $clone_product_variation_price_range->product_price_id = $prices[$product_variation_price_range->product_price_id];
            $clone_product_variation_price_range->created_at = now();
            $clone_product_variation_price_range->updated_at = now();
            $clone_product_variation_price_range->save();

            $variation_price_ids[$product_variation_price_range->product_price_id] = $clone_product_variation_price_range->product_price_id;
        }

        return $variation_price_ids;
    }

    public function duplicateProductVariationCombinations($existing_product, $cloned_product, $variation_price_ids)
    {
        $product_variation_combinations = ProductVariationCombination::where('product_id', $existing_product->id)->get();

        foreach ($product_variation_combinations as $product_variation_combination) {
            $clone_product_variation_combination = $product_variation_combination->replicate();
            $clone_product_variation_combination->product_id = $cloned_product->id;
            $clone_product_variation_combination->product_price_id = $variation_price_ids[$product_variation_combination->product_price_id];
            $clone_product_variation_combination->created_at = now();
            $clone_product_variation_combination->updated_at = now();
            $clone_product_variation_combination->save();
        }
    }

    public function cloneSketch($sourceModel, $destinationModel)
    {

        $sourceModelId = $sourceModel->id; // replace with the actual model ID
        $destinationModelId = $destinationModel->id; // replace with the actual model ID

        // Get the list of files in the source directory
        $files = Storage::disk('variation')->files($sourceModelId);

        // Iterate through the files and copy them to the destination directory
        foreach ($files as $file) {
            // Get the filename without the path
            $filename = pathinfo($file, PATHINFO_BASENAME);

            // Copy the file to the destination directory with the same filename
            Storage::disk('variation')->copy(
                "{$sourceModelId}/{$filename}",
                "{$destinationModelId}/{$filename}"
            );
        }

        $s = explode("/", $sourceModel->product_sketch);

        if(isset($s[1])) {
            $destinationModel->product_sketch = $destinationModel->id."/".$s[1];
            $destinationModel->save();
        }
    }

    public function cloneFeaturedImage($existing_product, $cloned_product)
    {
        $media = $existing_product->media->first();
        $cloned_product->addMediaFromDisk($media->getPathRelativeToRoot(), 'product')
            ->preservingOriginal()
            ->toMediaCollection('product_featured_image', 'product');
    }

    public function deleteProduct(Product $product)
    {

        DB::beginTransaction();
        try {

            $orderItem = OrderItems::where('product_id', $product->id)->first();

            if ($orderItem) {
                return response()
                    ->json([
                        'message' => "Can not delete product.",
                        'errors' => ["error" => ["This product is included in orders."]]
                    ], Response::HTTP_INTERNAL_SERVER_ERROR);
            }

            ProductVariation::where('product_id', $product->id)->delete();
            ProductPrice::where('product_id', $product->id)->delete();
            ProductVariationRange::where('product_id', $product->id)->delete();
            ProductVariationCombination::where('product_id', $product->id)->delete();
            $product->delete();

            DB::commit();

            return response()
                ->json(['message' =>  'Product deleted successfully.'], Response::HTTP_OK);

        } catch (\Exception $e){
            \Log::channel('db_errors')->info('Product Delete Error');
            \Log::channel('db_errors')->info($e->getMessage(). ' on line : '. $e->getLine());
            return response()
                ->json([
                    'message' => "Can not delete product.",
                    'errors' => ["error" => ["Unable to delete product. (".$e->getMessage().")"]]
                ], Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    public function checkCombinationInOrder($priceId)
    {
        $orderItem = OrderItems::where('price_id', $priceId)->first();

        if ($orderItem) {
            return response()
                ->json([
                    'message' => "You cannot delete the combination as it is currently in use in certain orders.",
                    'success' => false,
                ], Response::HTTP_OK);
        } else {
            return response()
                ->json([
                    'message' => "Combination can be removed.",
                    'success' => true,
                ], Response::HTTP_OK);
        }
    }
}