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/demo.sports-crowd.com/app/Http/Controllers/ShopifyController.php
<?php

namespace App\Http\Controllers;

use App\Erp;
use App\Core\Membership\Application\MembershipService;
use App\Core\Parameter\Application\ParameterService;
use App\Core\Payment\Application\PaymentTransactionService;
use App\Core\Tag\Application\TagService;
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 Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use PHPMailer\PHPMailer\PHPMailer;
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;
use App\ShopifyLog;

class ShopifyController extends Controller implements ERPLogRepository
{
    private $validSync = false;
    private $parameters;
    private $controllerOrder;
    private $utilController;
    private $inventoryController;
    private $paymentTransactionService;
    private $shopifyProducts;
    private $parameterService;

    public function __construct($ERPRepository = null)
    {
        $this->utilController = new UtilController;
        $this->initApiRest();
        $this->controllerOrder = new OrderController;
        $this->inventoryController = new InventoryController;
        $this->paymentTransactionService = new PaymentTransactionService();
        $this->parameterService = new ParameterService();
        $this->shopifyProducts = [];
    }

    //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) {
            $error = [
                'data'                  => $data,
                'currency'              => $currency,
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->utilController->logFile(json_encode($error));
            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) {
            $error = [
                'id'                    => $id,
                'data'                  => $data,
                'currency'              => $currency,
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->utilController->logFile(json_encode($error));
            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) {
            $error = [
                'id'                    => $id,
                'data'                  => $data,
                'currency'              => $currency,
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->utilController->logFile(json_encode($error));
            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) {
            $error = [
                'id'                    => $id,
                'currency'              => $currency,
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->utilController->logFile(json_encode($error));
            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) {
            $error = [
                'product_id'            => $product_id,
                'data'                  => $data,
                'currency'              => $currency,
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->utilController->logFile(json_encode($error));
            return null;
        }
    }

    public function updateVariant($variant_id, $data, $currency)
    {
        try {
            if ($this->validSync && $variant_id && $variant_id != "") {
                $response = $this->httpRequest(
                    'PUT',
                    "variants/" . $variant_id .  ".json",
                    $currency,
                    $data
                );
                return $response;
            }
            return null;
        } catch (Exception $e) {
            $error = [
                'variant_id'            => $variant_id,
                'data'                  => $data,
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->utilController->logFile(json_encode($error));
            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) {
            $error = [
                'variant_id'            => $variant_id,
                'product_id'            => $product_id,
                'currency'              => $currency,
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->utilController->logFile(json_encode($error));
            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) {
            $error = [
                'inventory_item_id'     => $inventory_item_id,
                'quantity_adjustment'   => $quantity_adjustment,
                'location'              => $location,
                'currency'              => $currency,
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->utilController->logFile(json_encode($error));
            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) {
            $error = [
                'value'                 => $value,
                'order'                 => $order,
                'fieldName'             => $fieldName,
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->utilController->logFile(json_encode($error));
            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)
    {
        $order = [];
        try {
            $this->utilController->logFile($request, 'shopify');
            $order = json_decode($request->getContent(), true);
            $previousId = ShopifyLog::onWriteConnection()->find($order['id']);
            if (!$previousId) {
                ShopifyLog::onWriteConnection()->create(['id' => $order['id']]);
                $this->saveData($order);
            }
        } catch (Exception $e) {
            $error = [
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->saveERPLog(json_encode($order), json_encode($error), 'webhooksListener');
        }

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

    private function saveData($order)
    {
        try {
            if (!$order || $order == 'null') {
                return;
            }
            $order = $this->validateOriginOrderNumber($order);
            $this->getShopifyOrderProducts($order);
            if (!$this->controllerOrder->getOrderByReference($order['order_number'])) {
                $user = $this->registerUserFromOrder($order);
                if ($user) {
                    $this->saveShopifyOrderProducts($order);
                    $this->saveOrder($order);
                    $this->createMemberships($order, $user);
                }
            }
            $this->syncERP($order);
        } catch (Exception $e) {
            $error = [
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->saveERPLog(json_encode($order), json_encode($error), '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)
    {
        $response = $this->httpRequest(
            'GET',
            'orders/' . $order['id'] . '/metafields.json',
            $order['currency']
        )['metafields'];

        $jsonDataItem = current(array_filter($response, function ($item) {
            return $item['key'] === 'jsondata';
        }));

        if ($jsonDataItem) {
            return json_decode($jsonDataItem['value']);
        }

        return null;
    }

    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);

        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'],
            'purchase_origin'                   => $this->getOriginShopifyOrder($order),
            'payment_transaction_id'            => $order['reference'] ?? $order['confirmation_number'],
            'status_notification_email_client'  => 'send',
        ));

        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 ($metafields) {
            $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)
    {
        $userController = new UserController();
        $customer = $order['customer'];
        $billingAddress = $order['billing_address'];

        if (!$customer) {
            return null;
        }
        $email = $customer['email'] ?? $order['contact_email'] ?? $order['email'];
        $password = base64_encode(random_bytes(4));
        $tags = $this->getSegmentationByShopifyOrderTags($order);
        $customerDocument = $this->getBuyerDocument($order);

        $userResponse = $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->pluck('id')->toArray(),
            'phone'         => $customer['phone'] ?? $billingAddress['phone'] ?? '1234',
            'document'      => $customerDocument,
            'document_type' => '',
            'direction'     => $billingAddress['address1'] . ',' . $billingAddress['city'] . ',' . $billingAddress['province'] . ',' . $billingAddress['country']
        ]), false);

        if (!$userResponse['r']) {
            return null;
        }

        if (count($tags) > 0) {
            $appStoreUrl = $this->parameterService->appStoreUrl();
            $playStoreUrl = $this->parameterService->playStoreUrl();
            $corporateIdentity = CorporateIdentity::first();
            $segmentationNames = implode(", ", $tags->pluck('name')->toArray());
            $customer['email'] = $email;

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

            $this->sendConfirmationEmail($customer, $segmentationNames, $parameters);
        }
        return $userResponse['d'];
    }

    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) {
            $error = [
                'customer'              => $customer,
                'subject'               => $subject,
                'params'                => $params,
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->utilController->logFile(json_encode($error));
            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)
    {
        $transactionId = json_decode($data)->id;
        ErpLog::updateOrCreate(
            [
                'origin'         => 'shopify',
                'transaction_id' => $transactionId,
                'resolved'       => false
            ],
            [
                'origin'         => 'shopify',
                'action'         => $action,
                'origin_class'   => get_class($this),
                'data'           => $data,
                'transaction_id' => $transactionId,
                'message'        => $message,
            ]
        );
    }

    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;
        }

        $erps = Erp::select('id', 'class')->where('active', true)->get();
        foreach ($erps as $index => $erp) {
            $classPath = $erp->class;
            $ERPRepository = new $classPath($erp->id);

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

            $previousBill = $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, $ERPRepository);
                    break;
                case 'createRC':
                    $this->createRCERP($order, $ERPRepository);
                    break;
                case 'createBill':
                    $this->createBillERP($order, $ERPRepository);
                    break;
                case 'saveData':
                    $this->saveData($order);
                    break;
                default:
                    $this->createThirdClientERP($order, $ERPRepository);
                    break;
            }
        }
    }

    private function createThirdClientERP($order, $ERPRepository)
    {
        $billingAddress = $order['billing_address'];
        $isColombia = $billingAddress['country'] == 'Colombia';

        $metafields = $this->getMetafields($order);
        $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 && $isColombia && !empty($metafields->selectedDepartment) ? $metafields->selectedDepartment : $billingAddress['province'];
        $city               = $metafields && $isColombia && !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 = $ERPRepository->thirdClientValidate($customerDocument);
        $isHED = $this->isHED($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        = $ERPRepository->mapDocumentType($juridicalPerson ? 'nit' : $documentType);
        $third->birthDate           = $birthDate->format('Ymd');
        $third->typeThird           = $typeCustomer;
        $third->gender              = $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     = $isHED ? '105' : null;
        $params->criteria       = $isHED ? '1051' : null;
        $params->currency       = $order['currency'];

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

    public function isHED($order)
    {
        return count($this->getOrderMemberships()) > 0;
    }

    private function createOrderERP($order, $ERPRepository)
    {
        $successTransaction = $this->getSuccessTransaction($order);
        if (!$successTransaction) {
            $this->saveERPLog(json_encode($order), 'La orden no tiene transacciones exitosas', 'createOrder');
            return;
        }
        $response = $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, $ERPRepository);
                return;
            }
        }

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

    private function createRCERP($order, $ERPRepository)
    {
        sleep(60);
        $response = $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 = $ERPRepository->getRC($this->getBuyerDocument($order), isset($siesaOrder->CentroDeOperacion) ? $siesaOrder->CentroDeOperacion : config('erp_siesa.shopOperationCenterId'));
            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, $ERPRepository);
                    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' : 'PYE';
            $parameters->UN = $isHED ? '104' : '102';
            $parameters->price = round($order['total_price']);

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

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

        $response = $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 = $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) {
            $variantResponse = $this->getShopifyVariant(null, null, 1, $product['variant_id'], $order['currency']);

            if (!$variantResponse['r']) {
                continue;
            }

            if ($variantResponse['variantExists']) {
                $variant = $variantResponse['variant'];
                if ($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)
    {
        $variantResponse = $this->getShopifyVariant($item->CodigoDeBarras, null, 1, null, $currency);
        if (!$variantResponse['r']) {
            return;
        }

        if ($variantResponse['variantExists']) {
            $variant = $variantResponse['variant'];
            $dataToUpdate = array(
                "id"    => $variant['id']
            );

            if ($variant['compare_at_price'] > 0) {
                $dataToUpdate['compare_at_price'] = $item->Precio;
            } else {
                $dataToUpdate['price'] = $item->Precio;
            }

            $data_variant =  array(
                "variant"   => $dataToUpdate
            );

            $this->updateVariant($variant['id'], $data_variant, $currency);
            $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",
        );

        $productResponse = $this->getShopifyVariant(null, $item->Referencia, 1, null, $currency);
        if (!$productResponse['r']) {
            return;
        }

        if ($productResponse['variantExists']) {
            $product = $productResponse['variant'];
            $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 array('r' => true, 'variantExists' => true, 'variant' => $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 array('r' => true, 'variantExists' => true, 'variant' => reset($result));
            }

            if (count($variants)) {
                return $this->getShopifyVariant($barcode, $reference, end($variants)['id'], $variantId, $currency);
            }
            return array('r' => true, 'variantExists' => false);
        } catch (Exception $e) {
            $error = [
                'barcode'               => $barcode,
                'reference'             => $reference,
                'sinceId'               => $sinceId,
                'variantId'             => $variantId,
                'currency'              => $currency,
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->utilController->logFile(json_encode($error));
            return array('r' => false);
        }
    }

    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-------------------------------------------------------

    function createMemberships($order, $user)
    {
        $membershipService    = new MembershipService();
        $memberships = $this->getOrderMemberships();

        if (count($memberships) == 0) {
            return false;
        }

        $deliveryPrice = 0;
        foreach ($order['shipping_lines'] as $index => $item) {
            $discount = array_sum(array_column($item['discount_allocations'], 'amount'));
            $deliveryPrice += round($item['price']) - $discount;
        }

        $shopifyPaymentTransaction = $this->getSuccessTransaction($order);
        $log = [
            'order'                     => $order,
            'shopifyProducts'           => $this->shopifyProducts,
            'shopifyPaymentTransaction' => $shopifyPaymentTransaction,
            'user'                      => $user,
            'memberships'               => $memberships
        ];
        $this->utilController->logFile(json_encode($log), 'createMemberships');
        foreach ($memberships as $item) {
            $paymentTransaction = $this->paymentTransactionService->getByPaymentGatewayTxId(
                $shopifyPaymentTransaction['payment_id']
            );

            if ($paymentTransaction) {
                continue;
            }

            $params = new \stdClass();
            $params->membership = $item;
            $params->user = $user;
            $params->startDate = Carbon::parse($order['created_at']);
            $params->deliveryPrice = $deliveryPrice;
            $params->transactionReference = $shopifyPaymentTransaction['payment_id'];

            $membershipService->createConfirmedMembershipSubscription($params);
        }

        return true;
    }

    public function getOrderMemberships()
    {
        $membershipController = new MembershipController();
        $segmentation = $this->getSegmentationByShopifyOrderTags();
        return $membershipController->getBySegmentation($segmentation->pluck('id')->toArray());
    }

    public function productHasMemberships($shopifyProduct)
    {
        $membershipController = new MembershipController();
        $segmentation = $this->getSegmentationByTagNames(explode(', ', $shopifyProduct['tags']));
        $memberships = $membershipController->getBySegmentation($segmentation->pluck('id')->toArray());
        return (count($memberships) > 0);
    }

    private function getShopifyOrderProducts($order)
    {
        $this->shopifyProducts = [];
        foreach ($order['line_items'] as $item) {
            if (!$item['product_id']) {
                continue;
            }
            $this->shopifyProducts[] = $this->getProduct($item['product_id'], $order['currency']);
        }
    }

    private function getSegmentationByShopifyOrderTags()
    {
        $tags = [];
        foreach ($this->shopifyProducts as $shopifyProduct) {
            $tags = array_merge($tags, explode(', ', $shopifyProduct['tags']));
        }

        return $this->getSegmentationByTagNames(array_unique($tags));
    }

    private function getSegmentationByTagNames($tags)
    {
        $tagService = new TagService();
        return $tagService->getByNames($tags);
    }

    private function saveShopifyOrderProducts()
    {
        foreach ($this->shopifyProducts as $shopifyProduct) {
            $this->saveProduct($shopifyProduct);
        }
    }

    public function updateOrdersFromShopify($currency, $lastLoadDate, $sinceId = 1, $orders = [])
    {
        if (is_string($orders)) {
            $orders = json_decode($orders, true);
        }
        $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
        );
        $newOrders = $response["orders"];

        if (count($newOrders) > 0) {
            $orders = array_merge($orders, $newOrders);
            $this->updateOrdersFromShopify($currency, $lastLoadDate, end($orders)['id'], $orders);
        } else {
            if (!count($orders)) {
                $orders = $newOrders;
            }
            foreach ($orders as $order) {
                $orderBD = $this->controllerOrder->getOrderByReference($order['order_number']);
                if ($orderBD && !$orderBD->payment_transaction_id) {
                    $purchaseOrigin = $this->getOriginShopifyOrder($order);
                    $paymentTransactionId = $order['reference'] ?? $order['confirmation_number'];

                    $orderBD->purchase_origin = $purchaseOrigin;
                    $orderBD->payment_transaction_id = $paymentTransactionId;
                    $orderBD->gw_code_transaction = $paymentTransactionId;
                    $orderBD->gw_state = 'CONFIRMED';
                    $orderBD->update();
                    $this->utilController->logFile('Order ' . $order['order_number'] . ' updated');
                }
            }
        }
    }

    private function getOriginShopifyOrder($order)
    {
        $origin = 'OTROS MEDIOS';
        if (!$order['referring_site'] && (str_contains($order['client_details']['user_agent'], 'Android') || str_contains($order['client_details']['user_agent'], 'iPhone'))) {
            $origin = 'APP';
        }
        return $origin;
    }

    public function resyncSystemLogs($days = 30)
    {
        $logs = SystemLog::select(
            'id',
            DB::raw("SUBSTRING_INDEX(data, '\n', -1) AS json")
        )
            ->where('origin', 'shopify')
            ->where('created_at', '>=', Carbon::now()->subDays($days))
            ->get();
        foreach ($logs as $log) {
            $order = [];
            try {
                $order = json_decode($log->json, true);
                $this->saveData($order);
            } catch (Exception $e) {
                $error = [
                    'message'               => $e->getMessage(),
                    'getFile'               => $e->getFile(),
                    'getLine'               => $e->getLine(),
                ];
                $this->saveERPLog(json_encode($order), json_encode($error), 'resyncSystemLogs');
            }
        }

        return response(array('r' => true, 'm' => "Ejecución exitosa resyncSystemLogs, registros: " . count($logs)));
    }

    private function validateOriginOrderNumber($order)
    {
        if ($order['order_status_url'] && str_contains($order['order_status_url'], 'internacional') && $order['order_number'] && !str_contains($order['order_number'], '-I')) {
            $order['order_number'] = $order['order_number'] . '-I';
        }
        return $order;
    }
}