HEX
Server: Apache/2.4.41 (Ubuntu)
System: Linux ip-172-31-42-149 5.15.0-1084-aws #91~20.04.1-Ubuntu SMP Fri May 2 07:00:04 UTC 2025 aarch64
User: ubuntu (1000)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/vhost/disk-apps/comfama.sports-crowd.com/app/Http/Controllers/ShopifyController.php
<?php

namespace App\Http\Controllers;

use Exception;
use App\ErpLog;
use App\Product;
use App\Parameter;
use App\SystemLog;
use Carbon\Carbon;
use App\ErpParameter;
use App\ProductAttribute;
use App\CorporateIdentity;
use Slince\Shopify\Client;
use App\IntegrationProvider;
use App\Services\ErpService;
use Illuminate\Http\Request;
use PHPMailer\PHPMailer\PHPMailer;
use App\Repositories\ERPRepository;
use Illuminate\Support\Facades\Auth;
use App\Repositories\ERPLogRepository;
use App\Http\Controllers\UserController;
use Slince\Shopify\PrivateAppCredential;
use App\Http\Controllers\OrderController;
use App\Http\Controllers\BrandsController;
use App\Http\Controllers\AddressController;
use App\Http\Controllers\ProductController;
use App\Http\Controllers\CategoryController;
use App\Http\Controllers\AttributeController;

class ShopifyController extends Controller implements ERPLogRepository
{
    private $validSync = false;
    private $parameters;
    public ERPRepository $ERPRepository;
    private $controllerOrder;
    private $utilController;
    private $inventoryController;
    private $ERPPrefix = 'AS';

    public function __construct($ERPRepository = null)
    {
        $this->utilController = new UtilController;
        $this->initApiRest();
        $this->controllerOrder = new OrderController;
        $this->inventoryController = new InventoryController;

        if ($ERPRepository != null) {
            $this->ERPRepository = $ERPRepository;
        } else {
            $defaultErp = config('erp.default');
            $erp = config("erp.{$defaultErp}.class");
            $this->ERPRepository = new $erp;
        }
    }

    //Mostrar tienda embebida en un iframe
    public function showExternalShop()
    {
        $collections = $this->httpRequest('GET', 'custom_collections.json', 'COP')['custom_collections'];
        $corporateIdentity = CorporateIdentity::first();
        return view('shopify.collections', compact('collections', 'corporateIdentity'));
    }

    public function showExternalShopProducts($collectionId)
    {
        return view('shopify.shop', compact('collectionId'));
    }

    public function initApiRest()
    {
        $this->parameters = Parameter::select('sync_shopify', 'sucursal_products')->find(1);
        if ($this->parameters && $this->parameters->sync_shopify) {
            $this->validSync = true;
        }
    }

    public function getIntegrationProvider($currency)
    {
        return IntegrationProvider::where([['ecommerce_type_id', 3], ['active', true], ['currency', $currency]])->first();
    }

    // produtcs
    public function createProduct($data, $currency)
    {
        try {
            if ($this->validSync) {
                return $this->httpRequest('POST', "products.json", $currency, $data)['product'];
            }
            return null;
        } catch (\Exception $e) {
            dump($e->getMessage(), $data, 'createProduct');
            return null;
        }
    }

    public function updateProduct($id, $data, $currency)
    {
        try {
            if ($this->validSync && $id && $id != "") {
                $this->httpRequest('PUT', "products/" . $id . ".json", $currency, $data);
            }
        } catch (\Exception $e) {
            return null;
        }
    }

    public function addImageProduct($id, $data, $currency)
    {
        try {
            if ($this->validSync && $id && $id != "") {
                $integrationProvider = $this->getIntegrationProvider($currency);
                $credential = new PrivateAppCredential(
                    $integrationProvider->key_public,
                    $integrationProvider->password,
                    $integrationProvider->key_private
                );

                $shopify = new Client(
                    $credential,
                    $integrationProvider->endpoint,
                    [
                        'metaCacheDir'  => './tmp',
                        'apiVersion'      => '2023-04',
                    ],
                );

                $shopify->getProductImageManager()->create($id, $data);
            }
        } catch (\Exception $e) {
            return null;
        }
    }

    public function deleteProduct($id, $currency)
    {
        try {
            if ($this->validSync && $id && $id != "") {
                $integrationProvider = $this->getIntegrationProvider($currency);
                $credential = new PrivateAppCredential(
                    $integrationProvider->key_public,
                    $integrationProvider->password,
                    $integrationProvider->key_private
                );

                $shopify = new Client(
                    $credential,
                    $integrationProvider->endpoint,
                    [
                        'metaCacheDir'  => './tmp',
                        'apiVersion'      => '2023-04',
                    ],
                );
                $shopify->delete('products/' . $id);
            }
        } catch (\Exception $e) {
            return null;
        }
    }

    // Variant
    public function createVariant($product_id, $data, $currency)
    {
        try {
            if ($this->validSync && $product_id && $product_id != "") {
                $response = $this->httpRequest('POST', "products/" . $product_id . "/variants.json", $currency, $data);
                return $response['variant'];
            }
            return null;
        } catch (\Exception $e) {
            dump($e->getMessage(), $product_id, 'createVariant');
            return null;
        }
    }

    public function updateVariant($variant_id, $data)
    {
        try {
            if ($this->validSync && $variant_id && $variant_id != "") {
                $client = new \GuzzleHttp\Client();
                $client->put($this->baseUrl . "variants/" . $variant_id . ".json", [
                    \GuzzleHttp\RequestOptions::JSON      => $data,
                    'headers' => [
                        'X-Shopify-Access-Token' => $this->integration->password
                    ]
                ]);
            }
        } catch (\Exception $e) {
            return null;
        }
    }

    public function deleteVariant($variant_id, $product_id, $currency)
    {
        try {
            if ($this->validSync && $variant_id && $variant_id != "" && $product_id && $product_id != "") {

                $integrationProvider = $this->getIntegrationProvider($currency);
                $credential = new PrivateAppCredential(
                    $integrationProvider->key_public,
                    $integrationProvider->password,
                    $integrationProvider->key_private
                );

                $shopify = new Client(
                    $credential,
                    $integrationProvider->endpoint,
                    [
                        'metaCacheDir'  => './tmp',
                        'apiVersion'      => '2023-04',
                    ],
                );
                $shopify->getProductVariantManager()->remove($product_id, $variant_id);
            }
        } catch (\Exception $e) {
            return null;
        }
    }

    public function updateInventoryLevel($inventory_item_id, $quantity_adjustment, $location, $currency)
    {
        try {
            if ($this->validSync && $inventory_item_id && $inventory_item_id != "") {
                $locations = $this->httpRequest('GET', 'locations.json', $currency)['locations'];
                $locations = array_filter($locations, function ($item) use ($location) {
                    return $item['name'] == $location;
                }, ARRAY_FILTER_USE_BOTH);

                $data = [
                    "location_id" => end($locations)['id'],
                    "inventory_item_id" => $inventory_item_id,
                    "available" => intval($quantity_adjustment),
                ];

                $this->httpRequest('POST', "inventory_levels/set.json", $currency, $data);
            }
        } catch (\Exception $e) {
            return null;
        }
    }

    private function updateShopifyMetafield($value, $order, $fieldName)
    {
        try {
            $data = array(
                "metafield" => array(
                    "value"             => $value,
                    "owner_id"          => $order['id'],
                    "namespace"         => "checkoutcustomizer",
                    "key"               => $fieldName,
                    "owner_resource"    => "order",
                    "type"              => "single_line_text_field",
                )
            );

            $this->httpRequest('POST', "orders/" . $order['id'] . "/metafields.json", $order['currency'], $data);
        } catch (\Exception $e) {
            return null;
        }
    }


    public function newRequest($data)
    {
        return new Request($data);
    }

    public function sync()
    {
        if ($this->validSync) {
            $loadDate = Carbon::now();
            $integrationProviders = IntegrationProvider::where([['ecommerce_type_id', 3], ['active', true]])->get();
            foreach ($integrationProviders as $integrationProvider) {
                $this->getOrdersFromShopify($integrationProvider->currency, $integrationProvider->last_load_date);
                $integrationProvider->last_load_date = $loadDate;
                $integrationProvider->update();
                $this->syncInventoryERP($integrationProvider->currency);
            }
        }
    }

    //---------------------------------------------------weebhook-------------------------------------------------------
    public function webhooksListener(Request $request)
    {
        try {
            $order = json_decode($request->getContent(), true);
            $previousWebhook = SystemLog::select('id')->where('data', 'like', '%:' . $order['id'] . '%')->first();
            if (!$previousWebhook) {
                $utilController = new UtilController();
                $utilController->logFile($request, 'shopify');
                $this->saveData($order);
            }
        } catch (Exception $e) {
            $this->saveERPLog(json_encode($order), $e->getMessage(), 'webhooksListener');
        }

        return response(array('r' => true, 'm' => "Recibido", 'd' => null));
    }

    private function saveData($order)
    {
        try {
            if (!$this->controllerOrder->getOrderByReference($order['order_number'])) {
                $confirmUser = $this->registerUserFromOrder($order);
                if ($confirmUser) $this->saveOrder($order);
            }

            $this->syncERP($order);
        } catch (Exception $e) {
            $this->saveERPLog(json_encode($order), $e->getMessage(), 'saveData');
        }
    }

    private function httpRequest($method, $endpoint, $currency, $data = null)
    {
        $integrationProviders = $this->getIntegrationProvider($currency);
        $client = new \GuzzleHttp\Client();
        $url = 'https://' . $integrationProviders->endpoint . '/admin/api/2023-04/';
        $body = [
            'headers' => ['X-Shopify-Access-Token' => $integrationProviders->password]
        ];

        switch ($method) {
            case 'GET':
                $response = $client->get($url . $endpoint, $body);
                break;
            case 'POST':
                $body = array_merge($body, [\GuzzleHttp\RequestOptions::JSON => $data]);
                $response = $client->post($url . $endpoint, $body);
                break;
            case 'PUT':
                $body = array_merge($body, [\GuzzleHttp\RequestOptions::JSON => $data]);
                $response = $client->put($url . $endpoint, $body);
                break;
        }

        return json_decode($response->getBody()->getContents(), true);
    }

    public function getProduct($productId, $currency)
    {
        return $this->httpRequest('GET', 'products/' . $productId . '.json', $currency)['product'];
    }

    private function getMetafields($order)
    {
        return $this->httpRequest('GET', 'orders/' . $order['id'] . '/metafields.json', $order['currency'])['metafields'];
    }

    public function getSuccessTransaction($order)
    {
        $transactions = $this->httpRequest(
            'GET',
            'orders/' . $order['id'] . '/transactions.json',
            $order['currency']
        )['transactions'];

        $successTransactions = array_filter($transactions, function ($item) {
            return $item['status'] == 'success';
        }, ARRAY_FILTER_USE_BOTH);

        // $successTransactions = $transactions;

        if (count($successTransactions)) {
            return end($successTransactions);
        }

        return null;
    }

    public function getOrdersFromShopify($currency, $lastLoadDate, $sinceId = 1)
    {
        $date = Carbon::parse($lastLoadDate)->toIso8601String();
        $filters = $lastLoadDate ? '&updated_at_min=' . $date : '';
        $filters .= '&since_id=' . $sinceId;

        $response = $this->httpRequest(
            'GET',
            'orders.json?status=any&financial_status=paid&limit=250' . $filters,
            $currency
        );
        $orders =  $response["orders"];
        foreach ($orders as $order) {
            $this->saveData($order);
        }

        if (count($orders) > 0) {
            $this->getOrdersFromShopify($currency, $lastLoadDate, end($orders)['id']);
        }
    }

    private function saveOrder($order)
    {
        $request_params = new Request([]);
        $controllerAddress = new AddressController();
        $controllerUser = new UserController($request_params);
        $address_id = null;

        $customer = $order['customer'];
        $billingAddress = $order['billing_address'];
        $shippingAddress = $order['shipping_address'] ?? $billingAddress;
        $document = $this->getBuyerDocument($order);

        if (!$customer || !$customer['email']) {
            return;
        }

        $user = $controllerUser->searchUser(
            $document,
            $customer['email'],
            $customer['first_name'],
            $customer['last_name'],
            $order['phone']
        );

        if ($user) {
            $user_id = $user->id;
            if ($shippingAddress) {
                $address = $controllerAddress->searchAddressByAddress($shippingAddress['address1'], $user_id);
                if ($address) {
                    $address_id = $address;
                }
            }
        }

        if ($shippingAddress) {
            $city_id = $controllerAddress->searchCityByName($shippingAddress['city']);
        }
        $products = [];
        foreach ($order['line_items'] as $key => $product) {
            $current_product = Product::where('reference_shopify_id', $product['product_id'])->first();
            if ($current_product) {
                $valuesAttributes = [];
                $product_atribute = ProductAttribute::where([['product_id', $current_product->id], ['reference_shopify_id', $product['variant_id']]])
                    ->with('attribute')
                    ->first();

                if ($product_atribute) {
                    $arrayAttribute = array(
                        'attribute'         => $product_atribute->attribute->toArray(),
                        'attribute_id'      => $product_atribute->attribute->id,
                        'available_units'   => $product_atribute->available_units,
                        'dispatched_units'  => $product_atribute->dispatched_units,
                        'ean'               => $product_atribute->ean,
                        'high'              => $product_atribute->high,
                        'id'                => $product_atribute->id,
                        'length'            => $product_atribute->length,
                        'main_position'     => $product_atribute->main_position,
                        'observation'       => $product_atribute->observation,
                        'packaging'         => $product_atribute->packaging,
                        'pmi'               => $product_atribute->pmi,
                        'price_additional'  => $product_atribute->price_additional,
                        'product_id'        => $product_atribute->product_id,
                        'quantity'          => $product['quantity'],
                        'sku'               => $product_atribute->sku,
                        'stowage_pattern'   => null,
                        'value'             => $product['variant_title'],
                        'weight'            => null,
                        'width'             => null,
                        'created_at'        => null,
                        'updated_at'        => null,
                    );
                    $valuesAttributes[] = $arrayAttribute;
                }
                $newProduct = array(
                    'quantity'                      => $product['quantity'],
                    'max_units_per_order'           => $current_product->max_units_per_order,
                    'price'                         => $product['price'],
                    'priceTotal'                    => $product['price'],
                    'id'                            => $current_product->id,
                    'plu'                           => $current_product->plu,
                    'name'                          => $current_product->name,
                    'priceAfterDiscount'            => null,
                    'priceAfterFlash'               => null,
                    'percentage_discount'           => null,
                    'start_discount'                => null,
                    'limit_discount'                => null,
                    'limit_hour_discount'           => null,
                    'flash_price'                   => null,
                    'start_flash_discount'          => null,
                    'limit_flash_discount'          => null,
                    'limit_hour_flash_discount'     => null,
                    'product_attributes_selected'   => $valuesAttributes
                );
                $products[] = $newProduct;
            }
        }

        $priceDomicile = $order['shipping_lines'];
        if (count($priceDomicile) > 0) {
            $priceDomicile = $priceDomicile[0]['price'];
        } else {
            $priceDomicile = 0;
        }

        $phone = $shippingAddress['phone'];
        $address = $shippingAddress['address1'];
        $data = array('data' => array(
            'first_name'        => $customer ? $customer['first_name'] : null,
            'last_name'         => $customer ? $customer['last_name'] : null,
            'document'          => $document,
            'phone'             => $phone,
            'email'             => $customer ? $customer['email'] : null,
            'order_reference'   => $order['order_number'],
            'sucursal'          => null,
            'products'          => $products,
            'confirmOrder'      => array(
                'observations'      => "",
                'effectivePayment'  => 0,
                'cellphone'         => $phone,
                'wayPay'            => 5,
                'address'           => $address_id,
                'address_new'       => array(
                    'direction' => $shippingAddress['address1'],
                    'district'  => '',
                    'instru'    => $shippingAddress['address2'],
                    'lat'       => '',
                    'lng'       => '',
                ),
            ),
            'dCampana'          => null,
            'dReferred'         => null,
            'dCoupone'          => null,
            'subtotal'          => $order['subtotal_price'],
            'discount'          => $order['total_discounts'],
            'priceDomicile'     => $priceDomicile,
            'total'             => $order['total_price'],
            'productsNotFound'  => null,
            'order_type_id'     => 5,
            'client_id'         => $user_id ?? null,
            'city_id'           => $city_id,
            'delivery_man_id'   => null,
            'job_sync'          => true,
            'code'              => $order['id']
        ));

        if (count($products)) {
            $request = new Request($data);
            $newOrder = $this->controllerOrder->create($request, false);

            if (!is_array($newOrder)) {
                $this->registerLog(
                    $user_id,
                    'Error creando order: ' . json_encode($newOrder->getData()),
                    json_encode($order),
                    "Create",
                    3
                );
                return;
            }
        }
    }

    public function getBuyerDocument($order)
    {
        $metafields = $this->getMetafields($order);
        if (count($metafields)) {
            $metafields = json_decode($metafields[0]['value']);
            $juridicalPerson    = isset($metafields->selectedTypeCustomer) && $metafields->selectedTypeCustomer == 'persona_juridica';
            if (!empty($metafields->selectedNIT) || !empty($metafields->selectedDocument)) {
                return $juridicalPerson ? $metafields->selectedNIT : $metafields->selectedDocument;
            }
        }

        $customer = $order['customer'];
        $billingAddress = $order['billing_address'];
        $customerDocument = isset($customer['document']) ? $customer['document'] : null;
        if ($billingAddress) {
            $customerDocument = $customerDocument ?? $billingAddress['document'] ?? $billingAddress['company'];
        }
        return $customerDocument;
    }

    private function registerUserFromOrder($order)
    {
        $carnetController = new CarnetController();
        $userController = new UserController();
        $customer = $order['customer'];
        $billingAddress = $order['billing_address'];

        if (!$customer) {
            return;
        }
        $email = $customer['email'] ?? $order['contact_email'] ?? $order['email'];
        $password = base64_encode(random_bytes(4));
        $tags = [];

        foreach ($order['line_items'] as $item) {
            if (!$item['product_id']) {
                continue;
            }

            $shopifyProduct = $this->getProduct($item['product_id'], $order['currency']);
            $this->saveProduct($shopifyProduct);
            foreach (explode(', ', $shopifyProduct['tags']) as $tag) {
                $carnet = $carnetController->getBySegmentation($tag);
                if ($carnet) {
                    array_push($tags, $carnet->tag_id);
                }
            }
        }

        $customerDocument = $this->getBuyerDocument($order);
        $userRespose = $userController->createClient(new Request([
            'first_name'    => $customer['first_name'] ?? $billingAddress['first_name'] ?? 'User',
            'last_name'     => $customer['last_name'] ?? $billingAddress['last_name'],
            'email'         => $email,
            'password'      => $password,
            'tags'          => $tags,
            'phone'         => $customer['phone'] ?? $billingAddress['phone'] ?? '1234',
            'document'      => $customerDocument,
            'document_type' => '',
            'direction'     => $billingAddress['address1'] . ',' . $billingAddress['city'] . ',' . $billingAddress['province'] . ',' . $billingAddress['country']
        ]), false);

        if (count($tags) > 0) {
            $parameters = Parameter::select('android_play_store', 'ios_app_store')->first();
            $corporateIdentity = CorporateIdentity::first();
            $appStoreUrl = 'https://apps.apple.com/us/app/' . $parameters->ios_app_store;
            $playStoreUrl = 'https://play.google.com/store/apps/details?id=' . $parameters->android_play_store;

            $customer['email'] = $email;
            $parameters = [
                'isNewUser' => !isset($userRespose['oldUser']) || !$userRespose['oldUser'],
                'email' => $email,
                'password' => $password,
                'segmentation' => $tag,
                'appStoreUrl' => $appStoreUrl,
                'playStoreUrl' => $playStoreUrl,
                'corporateIdentity' => $corporateIdentity
            ];

            $this->sendConfirmationEmail($customer, $tag, $parameters);
        }
        return true;
    }

    public function sendConfirmationEmail(array $customer, string $subject, array $params = [])
    {
        try {
            $mail = new PHPMailer(true);

            // $mail->SMTPDebug = SMTP::DEBUG_SERVER;      //Enable verbose debug output
            $mail->isSMTP();                               //Send using SMTP
            $mail->Host       = env('MAIL_HOST_HED');      //Set the SMTP server to send through
            $mail->SMTPAuth   = true;                      //Enable SMTP authentication
            $mail->Username   = env('MAIL_USERNAME_HED');  //SMTP username
            $mail->Password   = env('MAIL_PASSWORD_HED');  //SMTP password
            $mail->SMTPSecure = env('MAIL_ENCRYPTION');    //Enable implicit TLS encryption
            $mail->Port       = env('MAIL_PORT');

            $mail->setFrom(env('MAIL_USERNAME_HED'), env('MAIL_FROM_NAME'));
            $mail->addAddress($customer['email'], $customer['first_name']);

            $mail->isHTML(true);
            $mail->Subject = $subject;
            $mail->Body    = view('mails.createdUserAndCarnet')->with([
                'isNewUser'     => $parameters['isNewUser'] ?? false,
                'email'         => $customer['email'],
                'password'      => $params['password'] ?? '',
                'segmentation'  => $params['tag'] ?? '',
                'appStoreUrl'   => $params['appStoreUrl'],
                'playStoreUrl'  => $params['playStoreUrl'],
                'corporateIdentity' => $params['corporateIdentity']
            ])->render();

            $mail->send();
        } catch (\Exception $e) {
            echo "Message could not be sent. Mailer Error: " . $e->getMessage();
        }
    }

    private function  saveProduct($product)
    {
        $request_params = $this->newRequest([]);
        $brand = new BrandsController($request_params);
        $category = new CategoryController($request_params);
        $product_controller = new ProductController($request_params);
        $productAttribute_controller = new ProductAttributeController($request_params);
        $attribute_controller = new AttributeController($request_params);

        $current_product = Product::where('name', $product['title'])->first();
        // si existe actualizamos si no creamos
        if ($current_product) {
            $current_product->reference_shopify_id = $product['id'];
            $product_id = $current_product->id;
            $current_product->update();

            $this->saveProductImages($product, $current_product->id);
        } else {
            $default_sucursal_id = 2;
            if (Auth::user()) {
                $default_sucursal_id = Auth::user()->userInfo->sucursal_id;
            }
            $sucursal_id = $this->parameters->sucursal_products ? $default_sucursal_id : null;
            $brand_id = null;
            $c_brand = $brand->create($this->newRequest(['name' => $product['vendor']]));
            if ($c_brand) {
                $brand_id = $c_brand["d"]["id"];
            }

            $subcategory_id = null;
            $data_category = [
                'name'        => $product['product_type'],
                'sucursal_id' => $sucursal_id,
                'priority'    => 1,
                'store_type' => 'main'
            ];
            $c_category = $category->create($this->newRequest($data_category), false);
            if ($c_category) {
                $subcategory_id = $c_category["s"];
            }

            $price = 0;
            $available_units = 0;
            foreach ($product['variants'] as $variant) {
                $price = $variant['price'];
                $available_units = $available_units + $variant['inventory_quantity'];
            }

            $product_id = null;
            $data_product = [
                'name' => $product['title'],
                'plu' => $product['handle'],
                'bar_code' => null,
                'price' => $price,
                'available_units' => $available_units,
                'max_units_per_order' => 100,
                'percentage_discount' => null,
                'start_discount' => null,
                'limit_discount' => null,
                'limit_hour_discount' => null,
                'flash_price' => null,
                'start_flash_discount' => null,
                'limit_flash_discount' => null,
                'limit_hour_flash_discount' => null,
                'brand_id' => $brand_id,
                'order' => 1,
                'chkAgeProduct' => false,
                'sucursal_id' => $sucursal_id,
                'sub_categories' => [$subcategory_id],
                'reference_shopify_id' => $product['id'],
                'active' => true,
                'store_type' => 'main'
            ];
            $cproduct = $product_controller->create($this->newRequest($data_product), false);

            if ($cproduct) {
                $product_id = $cproduct["d"]["id"];
                $this->saveProductImages($product, $cproduct['d']['id']);
            }
        }

        foreach ($product['variants'] as $variant) {
            $name_attribute = "Tallas checkbox único";
            foreach ($product['options'] as $options) {
                foreach ($options['values'] as $option) {
                    if ($option == $variant['title']) {
                        $name_attribute = $options['name'];
                        break;
                    }
                }
            }

            $attribute_id = null;
            $data_attribute = [
                "name" => $name_attribute,
                "display_name" => $name_attribute,
                "is_more_one" => false,
                "required" => true,
                "attribute_type_id" => 2,
                "active" => true,
            ];
            $catrribute = $attribute_controller->store($this->newRequest($data_attribute), false);
            if ($catrribute) {
                $attribute_id = $catrribute["d"];
            }

            $data_productAttribute = [
                "product_id" => $product_id,
                "attribute_id" => $attribute_id,
                "value" => $variant['title'],
                "price_additional" => 0,
                "sku" => $variant['sku'],
                "available_units" => $variant['inventory_quantity'],
                "pmi" => 0,
                "packaging" => 0,
                "weight" => 0,
                "ean" => 0,
                "width" => 0,
                "length" => 0,
                "high" => 0,
                "observation" => 0,
                "main_position" => 0,
                "stowage_pattern" => 0,
                "reference_shopify_variation_id" => $variant['inventory_item_id'],
                "reference_shopify_id" => $variant['id'],
            ];

            $productAttribute_controller->store($this->newRequest($data_productAttribute), $product_id, false);
        }
    }

    private function saveProductImages($productShopify, $productId)
    {
        foreach ($productShopify['images'] as $image) {
            $product_controller = new ProductController();
            $product_controller->uploadImageFromUrl($image['src'], $image['id'], $productId);
        }
    }

    public function searchProductVariant($data, $variant)
    {
        $result = array_filter($data, function ($productVariant) use ($variant) {
            return $productVariant['id'] == $variant;
        }, ARRAY_FILTER_USE_BOTH);
        if (count($result)) {
            $result = reset($result);
        }
        return $result;
    }

    public function saveERPLog($data, $message, $action)
    {
        $erpLog                 = new ErpLog();
        $erpLog->origin         = 'shopify';
        $erpLog->action         = $action;
        $erpLog->origin_class   = get_class($this);
        $erpLog->data           = $data;
        $erpLog->message        = $message;
        $erpLog->save();
    }

    public function retrySyncERP($data, $action)
    {
        $this->syncERP(json_decode($data, true), $action);
    }

    public function syncERP($order, $action = null)
    {
        $erpSync = ErpParameter::where('key', 'shop_sync')->first();

        if (!$erpSync || $erpSync->value == 'false') {
            $this->saveERPLog(json_encode($order), 'Sinc ERP deshabilitada', 'syncERP');
            return;
        }

        if (!$this->controllerOrder->validateSyncWithERPPayment($order['id'])) {
            return;
        }

        $previousBill = $this->ERPRepository->getBill($order['order_number']);
        if ($previousBill['r'] && count($previousBill['d']->detalle->Table)) {
            $this->controllerOrder->confirmSyncERP($order['order_number']);
            return;
        }

        switch ($action) {
            case 'createOrder':
                $this->createOrderERP($order);
                break;
            case 'createRC':
                $this->createRCERP($order);
                break;
            case 'createBill':
                $this->createBillERP($order);
                break;
            case 'saveData':
                $this->saveData($order);
                break;
            default:
                $this->createThirdClientERP($order);
                break;
        }
    }

    private function createThirdClientERP($order)
    {
        $billingAddress = $order['billing_address'];

        $metafieldsResponse = $this->getMetafields($order);
        $metafields         = count($metafieldsResponse) ? json_decode($metafieldsResponse[0]['value']) : null;
        $birthDate          = $metafields ? str_replace('-', '/', $metafields->selectedAge) : Carbon::now();
        $documentType       = $metafields && !empty($metafields->selectedTypeDocument) ? $metafields->selectedTypeDocument : 'O';
        $typeCustomer       = $metafields && isset($metafields->selectedTypeCustomer) ? $metafields->selectedTypeCustomer : 'persona_natural';
        $juridicalPerson    = $typeCustomer == 'persona_juridica';
        $gender             = $metafields ? $metafields->selectedGenero : 'O';
        $establishmentName  = $metafields && isset($metafields->selectedNombreEstablecimiento) ? $metafields->selectedNombreEstablecimiento : null;
        $district           = $metafields && isset($metafields->selectedNeighborhood) ? $metafields->selectedNeighborhood : '';
        $customerDocument   = $this->getBuyerDocument($order);
        $birthDate          = str_contains($birthDate, '/') ? Carbon::createFromFormat('d/m/Y', $birthDate) : Carbon::parse($birthDate);
        $province           = $metafields && !empty($metafields->selectedDepartment) ? $metafields->selectedDepartment : $billingAddress['province'];
        $city               = $metafields && !empty($metafields->selectedCity) ? $metafields->selectedCity : $billingAddress['city'];
        $socialReason       = $metafields && isset($metafields->selectedRazonSocial) ? $metafields->selectedRazonSocial : null;
        $ciiu               = $metafields && isset($metafields->selectedCodigoCIIU) ? $metafields->selectedCodigoCIIU : null;
        $namePersonContact  = $metafields && isset($metafields->selectedPersonaContacto) ? $metafields->selectedPersonaContacto : null;
        $nit                = $metafields && isset($metafields->selectedNIT)  ? $metafields->selectedNIT : null;

        $this->updateShopifyMetafield($birthDate->toDateString(), $order, 'fechadecumpleaos_v1');
        $this->updateShopifyMetafield($customerDocument, $order, 'numerodedocumento_v1');
        $this->updateShopifyMetafield($documentType, $order, 'tipodedocumento_v1');
        $this->updateShopifyMetafield($typeCustomer, $order, 'tipodecomprador_v1');
        $this->updateShopifyMetafield($province, $order, 'departamento_v1');
        $this->updateShopifyMetafield($district, $order, 'barrio_v1');
        $this->updateShopifyMetafield($gender, $order, 'genero_v1');
        $this->updateShopifyMetafield($city, $order, 'ciudad_v1');
        $this->updateShopifyMetafield($establishmentName, $order, 'nombredelestablecimiento_v1');
        $this->updateShopifyMetafield($namePersonContact, $order, 'nombredelapersonadecontacto_v1');
        $this->updateShopifyMetafield($ciiu, $order, 'codigociiu_v1');
        $this->updateShopifyMetafield($nit, $order, 'nit_v1');
        $this->updateShopifyMetafield($socialReason, $order, 'razonsocial_v1');


        $siesaThirdClient = $this->ERPRepository->thirdClientValidate($customerDocument);
        $isHED = $this->isHED($order);
        $hasHED = $this->hasHED($order);
        $isLocal = $order['currency'] == 'COP';

        $params = new \stdClass();
        $third  = new \stdClass();

        $third->document            = $customerDocument;
        $third->firstName           = $billingAddress['first_name'];
        $third->lastName            = $billingAddress['last_name'];
        $third->contact             = $juridicalPerson ? $namePersonContact : $billingAddress['name'];
        $third->phone               = $billingAddress['phone'];
        $third->email               = $order['customer']['email'];
        $third->isNew               = count($siesaThirdClient) == 0;
        $third->documentType        = $this->ERPRepository->mapDocumentType($juridicalPerson ? 'nit' : $documentType);
        $third->birthDate           = $birthDate->format('Ymd');
        $third->typeThird           = $typeCustomer;
        $third->gender              = $this->ERPRepository->mapGender($gender);
        $third->socialReason        = $juridicalPerson ? $socialReason : $billingAddress['name'];
        $third->establishmentName   = $establishmentName;
        $third->ciiu                = $juridicalPerson ? $ciiu : null;

        $params->third          = $third;
        $params->client         = $third;
        $params->address        = $billingAddress['address1'] . ' | ' . $district;
        $params->shortAddress   = $billingAddress['address1'];
        $params->country        = $billingAddress['country'];
        $params->province       = $province;
        $params->city           = $city;
        $params->sucursal       = $isLocal ? '001' : '010';
        $params->price_list     = $isLocal ? '001' : '014';
        $params->typeClient     = $isHED ? 'CHED' : ($isLocal ? 'CTDS' : 'CTTI');
        $params->postal         = substr($billingAddress['zip'], 0, 10);
        $params->hasTaxes       = $isLocal ? '1' : '0';
        $params->createThirdPos = !$isHED;
        $params->idCriteria     = $hasHED ? '105' : null;
        $params->criteria       = $hasHED ? '1051' : null;
        $params->currency       = $order['currency'];

        $response = $this->ERPRepository->createThirdClient($params);
        if (!$response['r']) {
            $this->saveERPLog(json_encode($order), json_encode($response['d']), 'createThirdClient');
            return;
        }
        $this->createOrderERP($order);
    }

    public function isHED($order)
    {
        foreach ($order['line_items'] as $index => $item) {
            $variant = $this->getShopifyVariant(null, null, 1, $item['variant_id'], $order['currency']);
            if (!$variant || $variant['barcode'] != '1104424520023') {
                return false;
            }
        }
        return true;
    }

    public function hasHED($order)
    {
        foreach ($order['line_items'] as $index => $item) {
            $variant = $this->getShopifyVariant(null, null, 1, $item['variant_id'], $order['currency']);
            if ($variant && $variant['barcode'] == '1104424520023') {
                return true;
            }
        }
        return false;
    }

    private function createOrderERP($order)
    {
        $successTransaction = $this->getSuccessTransaction($order);
        if (!$successTransaction) {
            $this->saveERPLog(json_encode($order), 'La orden no tiene transacciones exitosas', 'createOrder');
            return;
        }
        $response = $this->ERPRepository->getOrder($order['order_number']);
        if ($response['r']) {
            $previousOrders = array_filter($response['d']->detalle->Table, function ($siesaOrder) use ($order, $successTransaction) {
                return str_contains($siesaOrder->Notas, $order['checkout_id']) ||
                    str_contains($siesaOrder->Notas, $successTransaction['payment_id']);
            }, ARRAY_FILTER_USE_BOTH);

            if (count($previousOrders)) {
                $this->createRCERP($order);
                return;
            }
        }

        $response = $this->ERPRepository->createOrderShop($order, $this);
        if (!$response['r']) {
            $this->saveERPLog(json_encode($order), json_encode($response['d']), 'createOrder');
            return;
        }
        $this->syncInventoryERPFromOrder($order);
        $this->createRCERP($order);
    }

    private function createRCERP($order)
    {
        $response = $this->ERPRepository->getOrder($order['order_number']);
        if (!$response['r']) {
            $this->saveERPLog(json_encode($order), json_encode($response['d']), 'createRC');
            return;
        }
        $successTransaction = $this->getSuccessTransaction($order);
        $isHED = $this->isHED($order);
        $isLocal = $order['currency'] == 'COP';

        $prefixNote = $isHED ? 'HED - ' : '';
        foreach ($response['d']->detalle->Table as $index => $siesaOrder) {
            $response = $this->ERPRepository->getRC($this->getBuyerDocument($order), $siesaOrder->CentroDeOperacion);
            if ($response['r']) {
                $previousRC = array_filter($response['d']->detalle->Table, function ($item) use ($order) {
                    return str_contains($item->Notas, $order['order_number']);
                }, ARRAY_FILTER_USE_BOTH);

                if (count($previousRC)) {
                    $this->createBillERP($order);
                    continue;
                }
            }

            $parameters = new \stdClass();
            $parameters->paymentDate = Carbon::parse($order['created_at'])->format('Ymd');
            $parameters->idThird = $this->getBuyerDocument($order);
            $parameters->currency = $order['currency'];
            $parameters->siesaOrder = $siesaOrder;
            $parameters->fe = '1104';
            $parameters->note = $prefixNote . 'Número de pedido:' . $order['order_number'] . ' - IDPAGO:' . $successTransaction['payment_id'];
            $parameters->assistant = $isHED ? '28050507' : ($isLocal ? '28050506' : '28050508');
            $parameters->sucursal = $isLocal ? '001' : '010';
            $parameters->paymetMethod = $isLocal ? 'PYV' : 'PYV';
            $parameters->UN = $isHED ? '104' : '102';
            $parameters->price = round($order['total_price']);

            $response = $this->ERPRepository->createRC($parameters);
            if (!$response['r']) {
                $this->saveERPLog(json_encode($order), json_encode($response['d']), 'createRC');
                return;
            }
        }
        $this->createBillERP($order);
    }

    private function createBillERP($order)
    {
        $previousBill = $this->ERPRepository->getBill($order['order_number']);
        if ($previousBill['r'] && count($previousBill['d']->detalle->Table)) {
            return;
        }

        $response = $this->ERPRepository->getOrder($order['order_number']);
        if (!$response['r']) {
            $this->saveERPLog(json_encode($order), json_encode($response['d']), 'createBill');
            return;
        }

        $thirdDocument = $this->getBuyerDocument($order);
        foreach ($response['d']->detalle->Table as $index => $siesaOrder) {
            $parameters = new \stdClass();
            $parameters->siesaOrder = $siesaOrder;
            $parameters->thirdDocument = $thirdDocument;
            $parameters->note = $order['order_number'];
            $parameters->price = $order['total_price'];
            $parameters->typeDocument = $order['currency'] == 'COP' ? 'FE1' : 'FE2';

            $response = $this->ERPRepository->createBill($parameters);
            if (!$response['r']) {
                $this->saveERPLog(json_encode($order), json_encode($response['d']), 'createBill');
                return;
            }
        }
        $this->controllerOrder->confirmSyncERP($order['order_number']);
    }


    private function syncInventoryERPFromOrder($order)
    {
        foreach ($order['line_items'] as $index => $product) {
            $variant = $this->getShopifyVariant(null, null, 1, $product['variant_id'], $order['currency']);
            if ($variant && $variant['barcode']) {

                $integrationProviders = IntegrationProvider::where([['ecommerce_type_id', 3], ['active', true]])->get();
                foreach ($integrationProviders as $integrationProvider) {
                    $this->syncInventoryERP($integrationProvider->currency, $variant['barcode']);
                }
            }
        }
    }

    private function syncInventoryERP($currency, $barcode = null)
    {
        $erpSync = ErpParameter::where('key', 'shop_sync')->first();
        if (!config('erp_siesa.sync_inventory') || !$erpSync || $erpSync->value == 'false') {
            return;
        }

        $priceList = $currency == 'COP' ? '001' : '014';
        $locationNames = ['BDHED','TI108'];

        foreach ($locationNames as $index => $locationName) {
            $siesaInventory = $this->inventoryController->syncInventoryERP(
                $priceList,
                'main',
                true,
                $this,
                $locationName,
                $currency,
                $barcode
            );

            if (!$barcode) {
                $this->syncInventoryWithOutStock(1, $siesaInventory, $locationName, $currency);
            }
        }
    }

    public function syncProductByReference($item, $location, $currency)
    {
        $variant = $this->getShopifyVariant($item->CodigoDeBarras, null, 1, null, $currency);
        if ($variant) {
            $this->updateInventoryFromVariant($variant, $item->Existencias, $location, $currency);
            return;
        }

        $data_variant =  array(
            "option1"               => $item->Talla ?? 'ÚNICA',
            "option2"               => $item->Color ?? 'ÚNICO',
            "price"                 => $item->Precio,
            "barcode"               => $item->CodigoDeBarras,
            "inventory_management"  => "shopify",
        );

        $product = $this->getShopifyVariant(null, $item->Referencia, 1, null, $currency);
        if ($product) {
            $variant = $this->createVariant($product['product_id'], array("variant" => $data_variant), $currency);
            $this->updateInventoryFromVariant($variant, $item->Existencias, $location, $currency);
            return;
        }

        $data_sho = array("product" => array(
            "title" => $item->Descripcion,
            "vendor" => $item->Marca,
            "product_type" => $item->Linea,
            "status"    => "draft",
            "variants" => [
                $data_variant
            ],
            "options" => [
                array(
                    "name" => "Tamaño",
                    "position" => 1
                ),
                array(
                    "name" => "Color",
                    "position" => 2
                ),
            ]
        ));

        $shopifyProduct = $this->createProduct($data_sho, $currency);
        if ($shopifyProduct) {
            $this->updateInventoryFromVariant($shopifyProduct['variants'][0], $item->Existencias, $location, $currency);
        }
    }

    private function updateInventoryFromVariant($variant, $stock, $location, $currency)
    {
        if ($variant) {
            $reference_shopify_variation_id = $variant['inventory_item_id'];
            $this->updateInventoryLevel($reference_shopify_variation_id, $stock, $location, $currency);
        }
    }

    private function getShopifyVariant($barcode, $reference, $sinceId = 1, $variantId = null, $currency)
    {
        try {
            $content = $this->httpRequest(
                'GET',
                'variants' . ($variantId ? '/' . $variantId : '') . '.json?limit=250&since_id=' . $sinceId,
                $currency
            );

            if ($variantId) {
                return $content['variant'];
            }

            $variants = $content["variants"];
            $result = array_filter($variants, function ($productVariant) use ($barcode, $reference) {
                if ($barcode) {
                    return $productVariant['barcode'] == $barcode;
                } else {
                    $productReference = substr($productVariant['barcode'], 0, 5) . substr($productVariant['barcode'], -4);
                    return $productReference == $reference;
                }
            }, ARRAY_FILTER_USE_BOTH);

            if (count($result)) {
                return reset($result);
            }

            if (count($variants)) {
                return $this->getShopifyVariant($barcode, $reference, end($variants)['id'], $variantId, $currency);
            }

            return null;
        } catch (Exception $exception) {
            return null;
        }
    }

    function syncInventoryWithOutStock($sinceId = 1, $siesaInventory, $location, $currency)
    {
        $variants = $this->httpRequest('GET', 'variants.json?limit=250&since_id=' . $sinceId, $currency)["variants"];
        foreach ($variants as $index => $item) {
            if (!$item['barcode']) {
                continue;
            }

            $siesaProducts = array_filter($siesaInventory, function ($productVariant) use ($item) {
                return $productVariant->CodigoDeBarras == $item['barcode'];
            }, ARRAY_FILTER_USE_BOTH);

            if (!count($siesaProducts)) {
                $this->updateInventoryFromVariant($item, 0, $location, $currency);
            }
        }

        if (count($variants)) {
            return $this->syncInventoryWithOutStock(end($variants)['id'], $siesaInventory, $location, $currency);
        }
    }
    //-----------------------------------------------END_weebhook-------------------------------------------------------
}