<?php

namespace App\Http\Controllers\Sivir;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Notifications\SendNotificationsController;
use App\Http\Helpers\GenerateCuf;
use App\Http\Helpers\UploadFile;
use App\Jobs\SendRemoteNotificationJob;
use App\Models\Customers\PortfolioCustomers;
use App\Models\ExchangeRate;
use App\Models\LicenseServer;
use App\Models\Sivir\CafcCode;
use App\Models\Sivir\CatalogsSivir;
use App\Models\Sivir\Enterprise;
use App\Models\Sivir\Products;
use App\Models\Sivir\ProductsKardex;
use App\Models\Sivir\ProductsLot;
use App\Models\Sivir\ProductsLotHistory;
use App\Models\Sivir\ProductsStock;
use App\Models\Sivir\ProductsStockHistory;
use App\Models\Sivir\SellPoint;
use App\Models\Sivir\SellPointMovement;
use App\Models\Sivir\Settings;
use App\Models\Sivir\SivirBolivianInvoice;
use App\Models\Sivir\SivirCoupons;
use App\Models\Sivir\SivirCufd;
use App\Models\Sivir\SivirGiftCard;
use App\Models\Sivir\SivirMassMailing;
use App\Models\Sivir\SivirOpticalWorkOrders;
use App\Models\Sivir\SivirPaymentWay;
use App\Models\Sivir\SivirSell;
use App\Models\Sivir\SivirSellAditionalDiscount;
use App\Models\Sivir\SivirSellAttachments;
use App\Models\Sivir\SivirSellInvoice;
use App\Models\Sivir\SivirSellInvoiceMilitary;
use App\Models\Sivir\SivirSellInvoiceStatus;
use App\Models\Sivir\SivirSellNote;
use App\Models\Sivir\SivirSellOrder;
use App\Models\Sivir\SivirSellPaymentWay;
use App\Models\Sivir\SivirSellSold;
use App\Models\Sivir\SivirSellSoldLotUsed;
use App\Models\Sivir\SivirServicePeriodsPaymentsMade;
use App\Models\Sivir\SivirSignificantEvent;
use App\Models\Sivir\SivirSystemBehavior;
use App\Models\Sivir\SoapCuis;
use App\Models\User;
use App\Traits\CurrencyConvertTrait;
use App\Traits\GenerateCufdTrait;
use App\Traits\GenerateGraphicRepresentationTrait;
use App\Traits\GetCashPaymentOnSellTrait;
use App\Traits\MakeForm004Trait;
use App\Traits\MakeForm005Trait;
use App\Traits\MakeForm007Trait;
use App\Traits\MakeInvoiceA4AndA6Trait;
use App\Traits\MakeOrderA4Trait;
use App\Traits\MakeProformaA4Trait;
use App\Traits\MakeWarehouseNoteA4Trait;
use App\Traits\SendNewInvoiceToServerTrait;
use App\Traits\SignSellXmlTrait;
use App\Traits\SoapDataTrait;
use App\Traits\WriteXmlFileInvoiceTrait;
use App\Traits\WriteXsdFileInvoiceTrait;
use Carbon\Carbon;
use Carbon\Exceptions\Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Mtownsend\XmlToArray\XmlToArray;
use Nette\InvalidStateException;
use PharData;
use Symfony\Component\Console\Question\ConfirmationQuestion;

use function PHPSTORM_META\type;

class SivirSellController extends Controller
{

    use SoapDataTrait,
        CurrencyConvertTrait,
        GenerateCufdTrait,
        GenerateGraphicRepresentationTrait,
        MakeInvoiceA4AndA6Trait,
        SignSellXmlTrait,
        GetCashPaymentOnSellTrait,
        MakeWarehouseNoteA4Trait,
        MakeProformaA4Trait,
        MakeOrderA4Trait,
        WriteXmlFileInvoiceTrait,
        WriteXsdFileInvoiceTrait,
        SendNewInvoiceToServerTrait,
        MakeForm007Trait,
        MakeForm005Trait,
        MakeForm004Trait;

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallsellbyusers(Request $request)
    {
        // Recibimos el usuario
        $user = $request->by_users;
        // Buscamos el reporte
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'F')->where('users_sid', $user)
            ->where('date_movement', $request->date_movement)
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(
                            [
                                'person'
                            ]
                        );
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'note',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'firstinvoicestatus',
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Devolvemos el reporte encontrado
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'length'    =>      count($response)
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallsellbyid(Request $request)
    {
        // Verificamos si puede ver de todos o propio
        $own = isset($request->own) ? $request->own : false;
        // Obtenemos
        $sivirSellInvoice = new SivirSellInvoice();
        // Recibimos el usuario
        $id = $request->id;
        // Buscamos el reporte
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'F')
            ->when($own, function ($q) {
                $q->where('users_sid', $this->getusersid());
            })
            ->whereIn('id', function ($q) use ($sivirSellInvoice, $id) {
                $q->select('sell_id')->from($sivirSellInvoice->getTableName())
                    ->where('id', $id)
                    ->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('status', 'A')->get();
            })
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(
                            [
                                'person'
                            ]
                        );
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'firstinvoicestatus',
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Devolvemos el reporte encontrado
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'length'    =>      count($response)
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallsellbyfilter(Request $request)
    {
        // Recibimos el metodo de pago requerido
        $payment_type = $request->payment_type;
        // Verificamos si pide por todos
        if ($payment_type == '*') {
            // Ahora buscamos las ventas segun los parametros
            $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
                ->where('sended', 'F')
                ->where('date_movement', $request->date_movement)
                ->with(
                    [
                        'user' => function ($q) {
                            $q->with(['person']);
                        },
                        'branch',
                        'sellpoint',
                        'customer',
                        'currency',
                        'invoice' => function ($q) {
                            $q->with(
                                [
                                    'firstinvoicestatus',
                                    'user',
                                    'branch',
                                    'tipofactura',
                                    'invoicecancelled',
                                    'sellpoint',
                                    'invoicestatus' => function ($q) {
                                        $q->orderBy('created_at', 'DESC')->first();
                                    }
                                ]
                            );
                        }
                    ]
                )
                ->orderBy('created_at', 'DESC')->get();
        } else {
            // Buscamos todas las posibles coincidencias
            $paymentWay = SivirPaymentWay::select('payment_id')->where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('payments_related', 'LIKE', '%' . $payment_type . '%')->get();
            // Ahora buscamos las ventas segun los parametros
            $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
                ->where('status', 'A')
                ->where('sended', 'F')
                ->where('date_movement', $request->date_movement)
                ->whereIn('payment_type', $paymentWay)
                ->with(
                    [
                        'user' => function ($q) {
                            $q->with(['person']);
                        },
                        'branch',
                        'sellpoint',
                        'customer',
                        'currency',
                        'invoice' => function ($q) {
                            $q->with(
                                [
                                    'firstinvoicestatus',
                                    'user',
                                    'branch',
                                    'tipofactura',
                                    'invoicecancelled',
                                    'sellpoint',
                                    'invoicestatus' => function ($q) {
                                        $q->orderBy('created_at', 'DESC')->first();
                                    }
                                ]
                            );
                        }
                    ]
                )
                ->orderBy('created_at', 'DESC')->get();
        }
        // Devolvemos el reporte encontrado
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'length'    =>      count($response)
            ],
            200
        );
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function getalldataforreports()
    {
        $currency_exchange_rate = array();
        // Obtenemos todas las licencias
        $branches       = $this->getcachedlicenseserver();
        // Obtenemos los puntos de venta
        $sellpoint      = $this->getcachedsellpointsnolimitnocufd();
        // las formas de pago
        $payment        = $this->getcachedpaymentswaynomultiple();
        // Formas de pago
        $payments       = $this->getcachedcatalogsbycode('PAYMENT');
        // Obtenemos las monedas con el pais
        $currency       = $this->getcachedcurrency();
        // Obtenemos la moneda del dolar
        $dollarCurrency = $this->getcacheddollar();
        // Obtenemos los datos de configuracion
        $configuration  = $this->getcachedfirstonesetting();
        // Los usuarios
        $users          = $this->getcachedusers();
        // El codigo clasificador
        $codigoClasificador = $dollarCurrency->codigoClasificador;
        // Ahora obtenemos los tipos de cambio
        foreach ($currency as $currency_data) {
            // Ahora recorremos los tipos de cambio
            foreach ($currency_data['exchanges'] as $exchanges) {
                // Buscamos el tipo de cambio
                if (isset($exchanges['global_currency_id'])) {
                    // The currency exchange
                    $currency_exchange_rate[] = (object) array(
                        'id'        =>  $exchanges['global_currency_id'],
                        'exchange'  =>  $exchanges['exchange']
                    );
                }
            }
        }
        // Retornamos la informacion encontrada
        return response()->json(
            [
                'status'            =>      'success',
                'branches'          =>      $branches,
                'sellpoint'         =>      $sellpoint,
                'currency'          =>      $currency,
                'payment'           =>      $payment,
                'payments'          =>      $payments,
                'dollar'            =>      $codigoClasificador,
                'configuration'     =>      $configuration,
                'exchange_rate'     =>      $currency_exchange_rate,
                'users'             =>      $users,
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function updateinvoicestatusverified(Request $request)
    {
        // La factura
        $invoice            = $request->invoice;
        $codigoRecepcion    = $request->codigoRecepcion;
        // Buscamos informacion de la factura
        SivirSellInvoiceStatus::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('invoice_id', $invoice)->delete();
        // Ahora que hemos eliminado los estados previos ingresamos un nuevo estado
        $status = [
            'relative'                  =>  Str::uuid()->toString(),
            'users_sid'                 =>  $this->getusersid(),
            'global_branch_office_id'   =>  $this->getbranchoffice(),
            'invoice_id'                =>  $invoice,
            'codigoDescripcion'         =>  'VALIDADA',
            'codigoEstado'              =>  908,
            'codigoRecepcion'           =>  $codigoRecepcion,
            'codigo'                    =>  null,
            'descripcion'               =>  null,
            'attempts'                  =>  1,
            'timeout'                   =>  0,
            'sended'                    =>  1,
            'status'                    =>  'A',
            'created_at'                =>  date("Y-m-d H:i:s"),
            'updated_at'                =>  null
        ];
        // Ahora registramos el nuevo estado
        $info = SivirSellInvoiceStatus::create($status);
        // Verificamos si la notificación 'validated_invoice' está activa
        $notificationsController = new SivirNotificationsController();
        // Verificamos
        $isNotificationEnabled = $notificationsController->checkFlagActive(
            $this->getbranchoffice(),
            'validated_invoice'
        );

        if ($isNotificationEnabled) {

            // Obtenemos informacion de la factura
            $invoice = SivirSellInvoice::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('id', $invoice)->with(['sell'])->first();

            // Buscamos el código de la moneda seleccionada
            $currencyCode = 'BOB'; // Valor por defecto

            foreach ($this->getcachedcurrency() as $currency) {
                if ($currency['codigoClasificador'] == $invoice['sell']['currency_id']) {
                    $currencyCode = $currency['code'];
                    break;
                }
            }
            // Obtenemos la forma de pago
            $allpayments = CatalogsSivir::where('value', $invoice['sell']['payment_type'])->where('catalog_code', 'PAYMENT')->where('global_branch_office_id', $this->getbranchoffice())->first();
            // Obtenemos la empresa
            $branches = LicenseServer::where('status', 'A')->where('license', $this->getbranchoffice())->with(['branchessivir'])->first();
            // Asignamos las variables
            $enterprise = $branches['branchessivir']['enterprise'];
            $branch = $branches['branchessivir']['branch_office'];
            // Ante titulo
            $prevTitle = "Empresa: {$enterprise}, Sucursal: {$branch} \n";
            // Creamos el título y mensaje
            $titulo = $prevTitle . "Se ha emitido y validado la factura ({$invoice['id']}) en línea.";
            $monto = number_format($invoice['sell']['total'], 2, ".", "");
            $mensaje = "Factura en línea: ({$invoice['id']}) - emitida al cliente: {$invoice['sell']['customer_full_name']} por un monto total de: {$monto} - ({$currencyCode}). Usuario: {$this->getusersemail()}, forma de pago: {$allpayments->label}";
            // Enviamos la notificación usando Job asincrónico
            SendRemoteNotificationJob::dispatch(
                $this->getbranchoffice(),
                $this->getusersid(),
                $titulo,
                $mensaje
            );
        }
        // Devolvemos
        return response()->json(
            [
                'status'    =>  'success',
                'message'   =>  $info
            ],
            200
        );
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function checkinvoicenotsendedorfail()
    {
        $invoiceStatus = new SivirSellInvoiceStatus();
        // La fecha de hoy
        $today = date("Y-m-d");
        // Verificamos las facturas no enviadas unicamente del dia de hoy
        $allInvoicesOfflineNotSended = SivirSellInvoice::where('status', 'A')
            ->where('estado', 'V')
            ->where('tipo_emision', 2)
            ->where('created_at', 'like', $today . "%")
            ->whereNotIn('id', function ($q) use ($invoiceStatus, $today) {
                $q->select('invoice_id')->from($invoiceStatus->getTableName())
                    ->where('status', 'A')->where('created_at', 'like', $today . "%")->get();
            })
            ->count();
        // Ahora todas las facturas enviadas que esten como rechazadas
        $allInvoicesOnlineRejected = SivirSellInvoice::where('status', 'A')
            ->where('tipo_emision', 1)
            ->where('estado', 'V')
            ->where('created_at', 'like', $today . "%")
            ->whereIn('id', function ($q) use ($invoiceStatus, $today) {
                $q->select('invoice_id')->from($invoiceStatus->getTableName())
                    ->where('codigoEstado', '<>', 908)
                    ->where('status', 'A')->where('created_at', 'like', $today . "%")->get();
            })
            ->count();
        // Ya que tenemos las facturas, ahora necesitamos enviarlas y notificarlas
        $notification = new SendNotificationsController();
        // Obtenemos datos de la empresa
        $enterprise = $this->getcachedenterprise();
        // Creamos el mensaje
        $message = 'La empresa, ' . $enterprise->fullname . ' tiene ' . $allInvoicesOfflineNotSended . ' facturas fuera de linea sin enviar.
        Tambien tiene ' . $allInvoicesOnlineRejected . ' facturas en linea que fueron rechazadas por impuestos nacionales.';
        // Nueva direccion
        $newAddressee = '59176108443';
        // Verificamos si hay facturas, en caso de no que no, no manda ninguna notificacion
        if ($allInvoicesOfflineNotSended > 0 || $allInvoicesOnlineRejected > 0) {
            // Ahora vemos las facturas no enviadas y las notificamos al usuario
            $info = $notification->sendnotification($message, $newAddressee);
        } else {
            $info = 'Sin facturas que notificar';
        }
        // Devolvemos lo encontrado
        return response()->json(
            [
                'status'    =>  'success',
                'info'      =>  $info,
                'ns'        =>  $allInvoicesOfflineNotSended,
                'ai'        =>  $allInvoicesOnlineRejected
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getresumebydates(Request $request)
    {
        $validInvoices = [];
        $validAndObservedInvoices = [];
        $observedInvoices = [];
        $rejected = [];
        $notSended = [];
        $notSendedDivided = [];
        $validDivided = [];
        $rejectedDivided = [];
        $cancelled = [];
        $cancelledDivided = [];
        // Obtenemos las fechas
        $since = Carbon::parse($request->since)->format("Y-m-d");
        $until = Carbon::parse($request->until)->format("Y-m-d");
        // El reporte
        $response = SivirSellInvoice::where('global_branch_office_id', $this->getbranchoffice())
            ->whereRaw('created_at between ? and ?', [$since . " 00:00:00", $until . " 23:59:59"])
            ->with(
                [
                    'sell',
                    'invoicestatus'
                ]
            )->orderBy('id', 'ASC')->get();
        // Solo validas
        foreach ($response as $data) {
            if ($data['tipo_emision'] == 2 && !isset($data['invoicestatus'][0])) {
                $notSended[] = $data;
            }
            if ($data['tipo_emision'] == 2 && isset($data['invoicestatus'][0]) && $data['invoicestatus'][0]['codigoEstado'] == "902") {
                $notSended[] = $data;
            }
            if ($data['tipo_emision'] == 1 && isset($data['invoicestatus'][0]) && $data['invoicestatus'][0]['codigoEstado'] == "902") {
                $notSended[] = $data;
            }
            if (isset($data['invoicestatus'][0])) {
                // Las mixtas
                if ($data['invoicestatus'][0]['codigoEstado'] == "908" || $data['invoicestatus'][0]['codigoEstado'] == "904") {
                    $validAndObservedInvoices[] = $data;
                }
                // Las unicas
                if ($data['invoicestatus'][0]['codigoEstado'] == "908") {
                    $validInvoices[] = $data;
                } elseif ($data['invoicestatus'][0]['codigoEstado'] == "904") {
                    $observedInvoices[] = $data;
                } else {
                    $rejected[] = $data;
                }
            }
        }
        $c = 0;
        // Dividido en 5
        for ($j = 1; $j <= count($response); $j++) {
            if ($response[$j - 1]['estado'] == 'V') {
                $validDivided[$c][] = $response[$j - 1]['id'];
            } else {
                $cancelledDivided[$c][] = $response[$j - 1]['id'];
            }
            if ($j % 5 == 0) $c++;
        }
        $c = 0;
        // Dividido en 5
        for ($j = 1; $j <= count($notSended); $j++) {
            $notSendedDivided[$c][] = $notSended[$j - 1]['id'];
            if ($j % 5 == 0) $c++;
        }
        // Devolvemos el reporte encontrado
        return response()->json(
            [
                'status'    =>      'success',
                'since'     =>      $since,
                'until'     =>      $until,
                'message'   =>      $response,
                'length'    =>      count($response),
                'valid'     =>      $validInvoices,
                'rejected'  =>      $rejected,
                'observed'  =>      $observedInvoices,
                'all'       =>      $validAndObservedInvoices,
                'notsended' =>      $notSended,
                'valdiv'    =>      $validDivided,
                'candiv'    =>      array_values($cancelledDivided),
                'rejdiv'    =>      $rejectedDivided,
                'nsdiv'     =>      array_values($notSendedDivided)
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getsellivabookbyrange(Request $request)
    {
        $sellnote = new SivirSellNote();
        // Obtenemos las fechas
        $since = Carbon::parse($request->since)->format("Y-m-d");
        $until = Carbon::parse($request->until)->format("Y-m-d");
        // Las ventas
        $response = SivirSell::where('sended', 'F')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->whereRaw('created_at between ? and ?', [$since . " 00:00:00", $until . " 23:59:59"])
            ->whereNotIn('id', function ($q) use ($sellnote) {
                $q->select('sell_id')->from($sellnote->getTableName())
                    ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())->get();
            })
            ->with(
                [
                    'currency',
                    'sellpaymentway' => function ($q) {
                        $q->with(
                            [
                                'payment'
                            ]
                        );
                    },
                    'sellpoint',
                    'documenttype',
                    'invoice'   => function ($q) {
                        $q->with(['firstinvoicestatus']);
                    },
                    'user' => function ($q) {
                        $q->with(
                            [
                                'person'
                            ]
                        );
                    }
                ]
            )->orderBy('created_at', 'DESC')->get();
        // Devolvemos el reporte encontrado
        return response()->json(
            [
                'status'    =>      'success',
                'since'     =>      $since,
                'until'     =>      $until,
                'message'   =>      $response,
                'length'    =>      count($response)
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function reportbyproductanddaterange(Request $request)
    {
        $sell = new SivirSell();
        $product_id = $request->relative;
        // Obtenemos las fechas
        $since = Carbon::parse($request->since)->format("Y-m-d");
        $until = Carbon::parse($request->until)->format("Y-m-d");
        // Informacion del producto
        $product = Products::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('relative', $product_id)->get()->first();
        // Vendidos por producto
        $response = SivirSellSold::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('product_id', $product_id)
            ->whereIn('sell_id', function ($query) use ($since, $until, $sell) {
                $query->select('id')->from($sell->getTableName())
                    ->whereRaw('created_at between ? and ?', [$since . " 00:00:00", $until . " 23:59:59"])
                    ->where('status', 'A')->where('sended', 'F')
                    ->where('global_branch_office_id', $this->getbranchoffice());
            })->with(
                [
                    'sell' => function ($q) use ($since, $until) {
                        $q->with(
                            [
                                'currency',
                                'sellpaymentway' => function ($q) {
                                    $q->with(
                                        [
                                            'payment'
                                        ]
                                    );
                                },
                                'sellpoint',
                                'invoice'   => function ($q) {
                                    $q->with(['firstinvoicestatus']);
                                }
                            ]
                        );
                    },
                    'product' => function ($q) {
                        $q->with(
                            [
                                'getlot' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                                'lots' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                                'lotsgreaterthanzero' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                            ]
                        );
                    },
                    'user' => function ($q) {
                        $q->with(
                            [
                                'person'
                            ]
                        );
                    }
                ]
            )->orderBy('created_at', 'DESC')->get();
        // Devolvemos el reporte encontrado
        return response()->json(
            [
                'status'    =>      'success',
                'since'     =>      $since,
                'until'     =>      $until,
                'message'   =>      $response,
                'length'    =>      count($response),
                'product'   =>      $product
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function reportbycustomeranddaterange(Request $request)
    {
        $sell = new SivirSell();
        $customerId = $request->relative;
        // Obtenemos las fechas
        $since = Carbon::parse($request->since)->format("Y-m-d");
        $until = Carbon::parse($request->until)->format("Y-m-d");
        // Vendidos por producto
        $response = SivirSellSold::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->whereIn('sell_id', function ($query) use ($since, $until, $sell, $customerId) {
                $query->select('id')->from($sell->getTableName())
                    ->whereRaw('created_at between ? and ?', [$since . " 00:00:00", $until . " 23:59:59"])
                    ->where('customer_id', $customerId)
                    ->where('status', 'A')->where('sended', 'F')
                    ->where('global_branch_office_id', $this->getbranchoffice());
            })->with(
                [
                    'sell' => function ($q) use ($since, $until) {
                        $q->with(
                            [
                                'currency',
                                'sellpaymentway' => function ($q) {
                                    $q->with(
                                        [
                                            'payment'
                                        ]
                                    );
                                },
                                'sellpoint',
                                'invoice'   => function ($q) {
                                    $q->with(['firstinvoicestatus']);
                                }
                            ]
                        );
                    },
                    'product' => function ($q) {
                        $q->with(
                            [
                                'getlot' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                                'lots' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                                'lotsgreaterthanzero' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                            ]
                        );
                    },
                    'user' => function ($q) {
                        $q->with(
                            [
                                'person'
                            ]
                        );
                    }
                ]
            )->orderBy('created_at', 'DESC')->get();
        // Devolvemos el reporte encontrado
        return response()->json(
            [
                'status'    =>      'success',
                'since'     =>      $since,
                'until'     =>      $until,
                'message'   =>      $response,
                'length'    =>      count($response)
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getsellformatbyrange(Request $request)
    {
        $showMilitaryData = false;
        // Verificamos el ENV
        if (config('app.show_military_data') && config('app.show_military_data') == true) {
            $showMilitaryData = true;
        }
        // Iniciamos la venta
        $sell = new SivirSell();
        // Obtenemos las fechas
        $since = Carbon::parse($request->since)->format("Y-m-d");
        $until = Carbon::parse($request->until)->format("Y-m-d");
        // Los productos vendidos
        $response = SivirSellSold::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('provisional', null)
            ->whereIn('sell_id', function ($query) use ($since, $until, $sell) {
                $query->select('id')->from($sell->getTableName())
                    ->whereRaw('created_at between ? and ?', [$since . " 00:00:00", $until . " 23:59:59"])
                    ->where('status', 'A')->where('sended', 'F')
                    ->where('global_branch_office_id', $this->getbranchoffice());
            })
            ->with(
                [
                    'sell' => function ($q) use ($since, $until, $showMilitaryData) {
                        //$q->whereRaw('created_at between ? and ?', [$since . " 00:00:00", $until . " 23:59:59"])
                        $q->with(
                            [
                                'currency',
                                'sellpaymentway' => function ($q) {
                                    $q->with(
                                        [
                                            'payment'
                                        ]
                                    );
                                },
                                'sellpoint',
                                'invoice'   => function ($q) {
                                    $q->with(['firstinvoicestatus']);
                                }
                            ]
                        )->when($showMilitaryData, function ($query) {
                            $query->with(
                                [
                                    'military' => function ($q) {
                                        $q->with(
                                            [
                                                'fuerza',
                                                'departamentoactual',
                                            ]
                                        );
                                    }
                                ]
                            );
                        });
                    },
                    'product' => function ($q) {
                        $q->with(
                            [
                                'brand',
                                'category',
                                'getlot' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                                'lots' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                                'lotsgreaterthanzero' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                            ]
                        );
                    },
                    'user' => function ($q) {
                        $q->with(
                            [
                                'person'
                            ]
                        );
                    }
                ]
            )->orderBy('created_at', 'DESC')->get();
        // Verificamos el condicionante
        if ($showMilitaryData) {
            // Devolvemos todos los grados
            $grados = CatalogsSivir::where('status', 'A')
                ->where('catalog_code', 'MILITARY')
                ->where('catalog_code_dep', 'MILITARY')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->orderBy('value', 'ASC')
                ->get();
        } else {
            // Grados vacios
            $grados = [];
        }
        // Devolvemos el reporte encontrado
        return response()->json(
            [
                'status'    =>      'success',
                'since'     =>      $since,
                'until'     =>      $until,
                'message'   =>      $response,
                'grados'    =>      $grados,
                'smd'       =>      $showMilitaryData,
                'length'    =>      count($response)
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallprofitbydaterange(Request $request)
    {
        // Las notas de venta
        $sellnote = new SivirSellNote();
        // Verificamos la solicitud del usuario
        $secure = isset($request->secure) ? $request->secure : 2;
        // Obtenemos las fechas
        $since = Carbon::parse($request->since)->format("Y-m-d");
        $until = Carbon::parse($request->until)->format("Y-m-d");
        // Instanciamos las ventas
        $sivirSell = new SivirSell();
        // Los productos vendidos
        $response = SivirSellSold::where('status', 'A')
            ->when($request->branch != '*', function ($q) use ($request) {
                $q->where('global_branch_office_id', $request->branch);
            })
            ->whereRaw('created_at between ? and ?', [$since . " 00:00:00", $until . " 23:59:59"])
            ->where('provisional', null)
            ->when($secure == 1, function ($q) use ($sellnote, $request) {
                $q->whereNotIn('sell_id', function ($q) use ($sellnote, $request) {
                    $q->select('sell_id')->from($sellnote->getTableName())->where('estado', '<>', 'C')
                        ->when($request->branch != '*', function ($q) use ($request) {
                            $q->where('global_branch_office_id', $request->branch);
                        });
                });
            })
            ->whereIn('sell_id', function ($q) use ($sivirSell, $request) {
                $q->select('id')->from($sivirSell->getTableName())
                    ->where('status', 'A')->where('sended', 'F')
                    ->when($request->branch != '*', function ($q) use ($request) {
                        $q->where('global_branch_office_id', $request->branch);
                    })->get();
            })
            ->with(
                [
                    'sell' => function ($q) use ($secure, $sellnote, $request) {
                        $q->with(
                            [
                                'currency',
                                'sellpoint',
                                'invoice'   => function ($q) {
                                    $q->with(['firstinvoicestatus']);
                                }
                            ]
                        );
                    },
                    'product' => function ($q) {
                        $q->with(
                            [
                                'lots' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                                'lotsgreaterthanzero' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                            ]
                        );
                    },
                    'user' => function ($q) {
                        $q->with(
                            [
                                'person'
                            ]
                        );
                    }
                ]
            )->orderBy('created_at', 'DESC')->get();

        foreach ($response as $item) {
            // Manually fetch the lot used for THIS specific product in the sale
            // This ensures we get the correct lot cost even if multiple products are in the same sale
            $lotUsed = SivirSellSoldLotUsed::where('sell_id', $item->sell_id)
                ->where('product_id', $item->product_id)
                ->where('global_branch_office_id', $item->global_branch_office_id)
                ->with(['getlot' => function ($q) {
                    $q->with('currency');
                }])
                ->first();

            // Manually set the relation on the model
            $item->setRelation('sellsoldlotused', $lotUsed);
        }

        // Devolvemos el reporte encontrado
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'length'    =>      count($response),
                'dates'     =>      Carbon::parse($since)->format("d/m/Y") . ' : ' . Carbon::parse($until)->format("d/m/Y")
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallprofitbydate(Request $request)
    {
        // Las notas de venta
        $sellnote = new SivirSellNote();
        // Verificamos la solicitud del usuario
        $secure = isset($request->secure) ? $request->secure : 2;
        // Instanciamos las ventas
        $sivirSell = new SivirSell();
        // La fecha
        $date_movement = isset($request->date_movement) ? Carbon::parse($request->date_movement)->format('Y-m-d') : date("Y-m-d");

        // Los productos vendidos
        $response = SivirSellSold::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->whereDate('created_at', $date_movement)
            ->where('provisional', null)
            ->when($secure == 1, function ($q) use ($sellnote) {
                $q->whereNotIn('sell_id', function ($q) use ($sellnote) {
                    $q->select('sell_id')->from($sellnote->getTableName())->where('estado', '<>', 'C')
                        ->where('global_branch_office_id', $this->getbranchoffice());
                });
            })
            ->whereIn('sell_id', function ($q) use ($sivirSell) {
                $q->select('id')->from($sivirSell->getTableName())
                    ->where('status', 'A')->where('sended', 'F')
                    ->where('global_branch_office_id', $this->getbranchoffice());
            })
            ->with(
                [
                    'sell' => function ($q) {
                        $q->with(
                            [
                                'currency',
                                'sellpoint',
                                'invoice'   => function ($q) {
                                    $q->with(['firstinvoicestatus']);
                                }
                            ]
                        );
                    },
                    'product' => function ($q) {
                        $q->with(
                            [
                                'lots' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                                'lotsgreaterthanzero' => function ($q) {
                                    $q->with(
                                        [
                                            'currency'
                                        ]
                                    );
                                },
                            ]
                        );
                    },
                    'user' => function ($q) {
                        $q->with(
                            [
                                'person'
                            ]
                        );
                    }
                ]
            )->orderBy('created_at', 'DESC')->get();

        foreach ($response as $item) {
            // Manually fetch the lot used for THIS specific product in the sale
            // This ensures we get the correct lot cost even if multiple products are in the same sale
            $lotUsed = SivirSellSoldLotUsed::where('sell_id', $item->sell_id)
                ->where('product_id', $item->product_id)
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->with(['getlot' => function ($q) {
                    $q->with('currency');
                }])
                ->first();

            // Manually set the relation on the model
            $item->setRelation('sellsoldlotused', $lotUsed);
        }

        // Devolvemos el reporte encontrado
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'length'    =>      count($response),
                'date'      =>      $date_movement
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallsellbypage(Request $request)
    {
        // Obtenemos el reporte
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'F')
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->paginate($request->pagination);
        // Retornamos
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * Vemos el reporte por rango de fechas y datos del cliente
     *
     * @param Request $request
     * @return void
     */
    public function getallsellsbycustomerdaterange(Request $request)
    {
        // Verificamos si puede ver de todos o propio
        $own = isset($request->own) ? $request->own : false;
        // Informacion del cliente
        $customer = $request->customer;
        // Las notas de venta
        $sellnote = new SivirSellNote();
        // Verificamos la solicitud del usuario
        $secure = isset($request->secure) ? $request->secure : 2;
        $paymentWay = null;
        // Obtenemos las fechas
        $since = Carbon::parse($request->since)->format("Y-m-d");
        $until = Carbon::parse($request->until)->format("Y-m-d");
        // Buscamos todas las posibles coincidencias
        if ($request->payment != '*') {
            $paymentWay = SivirPaymentWay::select('payment_id')->where('status', 'A')
                ->when($request->branch != '*', function ($q) use ($request) {
                    $q->where('global_branch_office_id', $request->branch);
                })
                ->where('payments_related', 'LIKE', '%' . $request->payment . '%')->get();
        }
        // Obtenemos el reporte
        $response = SivirSell::where('sended', 'F')
            ->where('customer_id', $customer)
            ->when($request->branch != '*', function ($q) use ($request) {
                $q->where('global_branch_office_id', $request->branch);
            })
            ->when($request->sellpoint != '*', function ($q) use ($request) {
                $q->where('sellpoint_id', $request->sellpoint);
            })
            ->when($request->payment != '*', function ($q) use ($paymentWay) {
                $q->whereIn('payment_type', $paymentWay);
            })
            ->when($own, function ($q) {
                $q->where('users_sid', $this->getusersid());
            })
            ->when($request->users != '*', function ($q) use ($request) {
                $q->where('users_sid', $request->users);
            })
            ->when($secure == 1, function ($q) use ($sellnote) {
                $q->whereNotIn('id', function ($q) use ($sellnote) {
                    $q->select('sell_id')->from($sellnote->getTableName())->where('estado', '<>', 'C')
                        ->where('global_branch_office_id', $this->getbranchoffice());
                });
            })
            ->whereRaw('created_at between ? and ?', [$since . " 00:00:00", $until . " 23:59:59"])
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'note',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'firstinvoicestatus',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Retornamos la informacion
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallsellbydaterange(Request $request)
    {
        // Verificamos si puede ver de todos o propio
        $own = isset($request->own) ? $request->own : false;
        // Las notas de venta
        $sellnote = new SivirSellNote();
        $newinvoicestatus = new SivirSellInvoiceStatus();
        $sellinvoice = new SivirSellInvoice();
        // Verificamos la solicitud del usuario
        $secure = isset($request->secure) ? $request->secure : 2;
        $paymentWay = null;
        // Obtenemos las fechas
        $since = Carbon::parse($request->since)->format("Y-m-d");
        $until = Carbon::parse($request->until)->format("Y-m-d");
        // Verificamos el estado de la factura
        $invoicestatus = $request->invoicestatus ?? null;
        // Buscamos todas las posibles coincidencias
        if ($request->payment != '*') {
            $paymentWay = SivirPaymentWay::select('payment_id')->where('status', 'A')
                ->when($request->branch != '*', function ($q) use ($request) {
                    $q->where('global_branch_office_id', $request->branch);
                })
                ->where('payments_related', 'LIKE', '%' . $request->payment . '%')->get();
        }
        // Obtenemos el reporte
        $response = SivirSell::where('sended', 'F')
            ->when($request->branch != '*', function ($q) use ($request) {
                $q->where('global_branch_office_id', $request->branch);
            })
            ->when($request->sellpoint != '*', function ($q) use ($request) {
                $q->where('sellpoint_id', $request->sellpoint);
            })
            ->when($request->payment != '*', function ($q) use ($paymentWay) {
                $q->whereIn('payment_type', $paymentWay);
            })
            ->when($own, function ($q) {
                $q->where('users_sid', $this->getusersid());
            })
            ->when($request->users != '*', function ($q) use ($request) {
                $q->where('users_sid', $request->users);
            })
            ->when($secure == 1, function ($q) use ($sellnote) {
                $q->whereNotIn('id', function ($q) use ($sellnote) {
                    $q->select('sell_id')->from($sellnote->getTableName())->where('estado', '<>', 'C')
                        ->where('global_branch_office_id', $this->getbranchoffice());
                });
            })
            ->when($invoicestatus == 'V', function ($query) use ($newinvoicestatus, $request, $sellinvoice) {
                $query->whereIn('id', function ($query) use ($request, $sellinvoice, $newinvoicestatus) {
                    $query->select('sell_id')->from($sellinvoice->getTableName())
                        ->when($request->branch != '*', function ($q) use ($request) {
                            $q->where('global_branch_office_id', $request->branch);
                        })->where('estado', 'V')->whereIn('id', function ($query) use ($newinvoicestatus, $request) {
                            $query->select('invoice_id')->from($newinvoicestatus->getTableName())->where('status', 'A')
                                ->when($request->branch != '*', function ($q) use ($request) {
                                    $q->where('global_branch_office_id', $request->branch);
                                })->where('codigoEstado', 908);
                        });
                });
            })
            ->when($invoicestatus == 'O', function ($query) use ($newinvoicestatus, $request, $sellinvoice) {
                $query->whereIn('id', function ($query) use ($request, $sellinvoice, $newinvoicestatus) {
                    $query->select('sell_id')->from($sellinvoice->getTableName())
                        ->when($request->branch != '*', function ($q) use ($request) {
                            $q->where('global_branch_office_id', $request->branch);
                        })->where('estado', 'V')->whereIn('id', function ($query) use ($newinvoicestatus, $request) {
                            $query->select('invoice_id')->from($newinvoicestatus->getTableName())->where('status', 'A')
                                ->when($request->branch != '*', function ($q) use ($request) {
                                    $q->where('global_branch_office_id', $request->branch);
                                })->where('codigoEstado', 904);
                        });
                });
            })
            ->when($invoicestatus == 'R', function ($query) use ($newinvoicestatus, $request, $sellinvoice) {
                $query->whereIn('id', function ($query) use ($request, $sellinvoice, $newinvoicestatus) {
                    $query->select('sell_id')->from($sellinvoice->getTableName())
                        ->when($request->branch != '*', function ($q) use ($request) {
                            $q->where('global_branch_office_id', $request->branch);
                        })->where('estado', 'V')->whereIn('id', function ($query) use ($newinvoicestatus, $request) {
                            $query->select('invoice_id')->from($newinvoicestatus->getTableName())->where('status', 'A')
                                ->when($request->branch != '*', function ($q) use ($request) {
                                    $q->where('global_branch_office_id', $request->branch);
                                })->where('codigoEstado', 902);
                        });
                });
            })
            ->when($invoicestatus == 'VNS', function ($query) use ($newinvoicestatus, $request, $sellinvoice) {
                $query->whereIn('id', function ($query) use ($request, $sellinvoice, $newinvoicestatus) {
                    $query->select('sell_id')->from($sellinvoice->getTableName())
                        ->when($request->branch != '*', function ($q) use ($request) {
                            $q->where('global_branch_office_id', $request->branch);
                        })->where('estado', 'V')->whereNotIn('id', function ($query) use ($newinvoicestatus, $request) {
                            $query->select('invoice_id')->from($newinvoicestatus->getTableName())->where('status', 'A')
                                ->when($request->branch != '*', function ($q) use ($request) {
                                    $q->where('global_branch_office_id', $request->branch);
                                });
                        });
                });
            })
            ->when($invoicestatus == 'A', function ($query) use ($sellinvoice, $request) {
                $query->whereIn('id', function ($query) use ($request, $sellinvoice) {
                    $query->select('sell_id')->from($sellinvoice->getTableName())
                        ->when($request->branch != '*', function ($q) use ($request) {
                            $q->where('global_branch_office_id', $request->branch);
                        })->where('estado', 'A');
                });
            })
            ->whereRaw('created_at between ? and ?', [$since . " 00:00:00", $until . " 23:59:59"])
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'note',
                    'products',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'firstinvoicestatus',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Retornamos la informacion
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallsellbycustomeranddaterange(Request $request)
    {
        // Verificamos el cliente
        if (isset($request->customer_id)) {
            // Obtenemos el cliente
            $customerRelative = $request->customer_id;
            // Verificamos si puede ver de todos o propio
            $own = isset($request->own) ? $request->own : false;
            // Las notas de venta
            $sellnote = new SivirSellNote();
            // Verificamos la solicitud del usuario
            $secure = isset($request->secure) ? $request->secure : 2;
            $paymentWay = null;
            // Obtenemos las fechas
            $since = Carbon::parse($request->since)->format("Y-m-d");
            $until = Carbon::parse($request->until)->format("Y-m-d");
            // Obtenemos el reporte
            $response = SivirSell::where('sended', 'F')
                ->where('customer_id', $customerRelative)
                ->when($own, function ($q) {
                    $q->where('users_sid', $this->getusersid());
                })
                ->when($secure == 1, function ($q) use ($sellnote) {
                    $q->whereNotIn('id', function ($q) use ($sellnote) {
                        $q->select('sell_id')->from($sellnote->getTableName())->where('estado', '<>', 'C')
                            ->where('global_branch_office_id', $this->getbranchoffice());
                    });
                })
                ->whereRaw('created_at between ? and ?', [$since . " 00:00:00", $until . " 23:59:59"])
                ->with(
                    [
                        'user' => function ($q) {
                            $q->with(['person']);
                        },
                        'branch',
                        'sellpoint',
                        'customer',
                        'currency',
                        'note',
                        'invoice' => function ($q) {
                            $q->with(
                                [
                                    'user',
                                    'branch',
                                    'tipofactura',
                                    'invoicecancelled',
                                    'sellpoint',
                                    'firstinvoicestatus',
                                    'invoicestatus' => function ($q) {
                                        $q->orderBy('created_at', 'DESC')->first();
                                    }
                                ]
                            );
                        }
                    ]
                )
                ->orderBy('created_at', 'DESC')->get();
            // Retornamos la informacion
            return response()->json(
                [
                    'status'    =>      'success',
                    'message'   =>      $response
                ],
                200
            );
        } else {
            // Retornamos error por falta de cliente
            return response()->json(
                [
                    'status'    =>  'fail',
                    'message'   =>  'Debe elegir un cliente'
                ],
                400
            );
        }
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallsellbytoday(Request $request)
    {
        // Verificamos si puede ver de todos o propio
        $own = isset($request->own) ? $request->own : false;
        // La fecha por defecto
        $today = date("Y-m-d");
        // Las notas de venta
        $sellnote = new SivirSellNote();
        // Verificamos la solicitud del usuario
        $secure = isset($request->secure) ? $request->secure : 2;
        // Obtenemos el reporte
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'F')
            ->where('date_movement', $today)
            ->when($own, function ($q) {
                $q->where('users_sid', $this->getusersid());
            })
            ->when($secure == 1, function ($q) use ($sellnote) {
                $q->whereNotIn('id', function ($q) use ($sellnote) {
                    $q->select('sell_id')->from($sellnote->getTableName())->where('estado', '<>', 'C')
                        ->where('global_branch_office_id', $this->getbranchoffice());
                });
            })
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch.branchessivir',
                    'sellpoint',
                    'customer',
                    'currency',
                    'note',
                    'products',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'firstinvoicestatus',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Retornamos la informacion
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallproformasbytoday()
    {
        $today = date("Y-m-d");
        // Obtenemos el reporte
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'P')
            ->where('date_movement', $today)
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency'
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Retornamos la informacion
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return bool|\Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function steponeinvoicenumber(Request $request)
    {
        // Recibimos la factura
        $invoice = $request->id;
        // El codigo del motivo del Evento
        $codigoMotivoEvento     = isset($request->reason) ? $request->reason : 2;
        // La descripcion
        $descripcion            = $this->returnmotivo($codigoMotivoEvento);
        // Obtenemos el dato de la sucursal a utilizar
        $branchOffice           = $this->getbranchoffice();
        // The invoice status
        $status = 2;
        // The sell invoice status
        $invoiceStatus = new SivirSellInvoiceStatus();
        $massMailing = new SivirMassMailing();
        // Ahora procedemos a procesar el evento significativo
        // Verificamos si existen facturas fuera de linea
        $offlineInvoices = SivirSellInvoice::where('status', 'A')->where('estado', 'V')
            ->where('global_branch_office_id', $branchOffice)
            ->where('id', $invoice)->where('tipo_emision', $status) // Offline
            ->when($codigoMotivoEvento <= 3, function ($query) {
                $query->whereNull('cafc');
            })
            ->when($codigoMotivoEvento > 3, function ($query) {
                $query->whereNotNull('cafc');
            })
            ->whereNotIn('id', function ($q) use ($massMailing) {
                $q->select('invoices')->from($massMailing->getTableName())
                    ->where('status', 'A')->get();
            })
            ->whereNotIn('id', function ($q) use ($invoiceStatus) {
                $q->select('invoice_id')->from($invoiceStatus->getTableName())->where('status', 'A')->get();
            })
            ->with(
                [
                    'sellpoint' => function ($q) {
                        $q->with(['cufd']);
                    }
                ]
            );
        // Verificamos si exsite o no
        if ($offlineInvoices->exists()) {
            // Obtenemos las facturas
            $invoicesFinded = $offlineInvoices->orderBy('created_at', 'ASC')->get();
            // Obtenemos el comportamiento del sistema
            $systemBehavior = SivirSystemBehavior::where('status', 'A')
                ->where('global_branch_office_id', $branchOffice)
                ->get()->first();
            // Asignamos los valores devueltos a las variables correspondientes
            // Informacion obtenida del comportamiento del sistema
            $token = $systemBehavior->token;
            // Obtenemos el CUIS utilizando el punto de venta
            $cuis = $this->getCUISBySellpointCode($invoicesFinded[0]['sellpoint']['codigo_punto_venta'], $branchOffice);
            // Comprobamos que exista un cuis valido
            if ($cuis == false) {
                return false;
            }
            // Intentamos el ping
            if ($this->tryping($token)) {
                // Recorremos las facturas encontradas
                foreach ($invoicesFinded as $data) {
                    $invoices[] = $data['id'];
                    // Recorremos las facturas para conocer la hora de inicio y hora final
                    $initialTimeSeconds = Carbon::parse($data['created_at'])->subSeconds(2)->format("H:i:s");
                    // The initial time with milli seconds
                    $initialTimeWithMilliseconds = Carbon::parse($data['created_at'])->format("Y-m-d") . 'T' . $initialTimeSeconds . '.' . substr(intval(microtime(true) * 1000), -3);
                    // The final seconds
                    $finalTimeSeconds = Carbon::parse($data['created_at'])->addSeconds(2)->format("H:i:s");
                    //  The final time with milliseconds
                    $finalTimeWithMilliseconds = Carbon::parse($data['created_at'])->format("Y-m-d") . 'T' . $finalTimeSeconds . '.' . substr(intval(microtime(true) * 1000), -3);
                }
                // Ahora que ya tenemos la fecha hora inicial, y la fecha hora final procedemos a crear el evento significativo
                // Obtenemos el usuario
                $users_sid      = $this->getusersid();
                // La factura encontrada
                $fechaYHoraDeLaFactura = $invoicesFinded[0]['created_at'];
                // Ahora obtenemos el CUFD que estaba vigente mas cercano a esta fecha
                $cufdEncontrado = $this->getlastvalidcufdarounddate($fechaYHoraDeLaFactura, $invoicesFinded[0]['sellpoint_id']);
                // The last CUFD
                $cufdEvento     = $cufdEncontrado->codigo_cufd;
                // Ahora registramos el evento significativo
                $codigoPuntoVenta = $invoicesFinded[0]['sellpoint']['codigo_punto_venta'];
                // Ahora creamos el evento significativo falso
                $elEventoSignificativo  = $this->createsignificantevent($codigoPuntoVenta, $codigoMotivoEvento, $cufdEvento, $descripcion, $initialTimeWithMilliseconds, $finalTimeWithMilliseconds, $users_sid, $branchOffice);
                // Verificamos que no haya fallado
                if ($elEventoSignificativo[0] != false) {
                    // Retornamos la informacion
                    return response()->json(
                        [
                            'status'    =>      'success',
                            'message'   =>      $elEventoSignificativo[0],
                            'cod'       =>      $codigoMotivoEvento,
                            'motivo'    =>      $descripcion
                        ],
                        200
                    );
                } else {
                    // Retornamos la informacion
                    return response()->json(
                        [
                            'status'    =>      'fail',
                            'message'   =>      $elEventoSignificativo[1]
                        ],
                        409
                    );
                }
            }
        } else {
            // Retornamos la informacion
            return response()->json(
                [
                    'status'    =>      'fail',
                    'message'   =>      'El numero de la factura elegida no se puede enviar'
                ],
                409
            );
        }
    }

    /**
     * @param Request $request
     * @return bool|\Illuminate\Http\JsonResponse
     * @throws \SoapFault
     */
    public function sendsteptwo(Request $request)
    {
        // Obtenemos el evento significativo
        $elEventoSignificativo = $request->evento;
        // El evento masivo
        $massMailing = new SivirMassMailing();
        // Buscamos el ID del evento significativo
        $eventos = SivirSignificantEvent::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('codigoRecepcionEventoSignificativo', $elEventoSignificativo)
            ->whereNotIn('id', function ($q) use ($massMailing) {
                $q->select('event_number')->from($massMailing->getTableName())
                    ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice());
            })
            ->orderBy('created_at', 'DESC');
        // Verificamos que exista al menos un evento siginificativo
        if ($eventos->exists()) {
            // Obtenemos el evento
            $eventoSignificativoRegistrado = $eventos->get()->first();
            // Tenemos el ID del evento significativo
            $idDelEventoSignificativo = $eventoSignificativoRegistrado->id;
            // Obtenemos los puntos de venta que este con un CUFD activo
            $sellpointsOpenedAndValid = SellPoint::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('codigo_punto_venta', '<>', null)
                ->with(['cufd'])
                ->orderBy('created_at', 'ASC')->get();
            // Verificamos si existe al menos 1 punto de venta
            if ($sellpointsOpenedAndValid->count() > 0) {
                // Recorremos todos los puntos de venta encontrados
                foreach ($sellpointsOpenedAndValid as $dataSellPointsValid) {
                    // Datos
                    $users_sid      = $this->getusersid();
                    $branch         = $this->getbranchoffice();
                    // The last CUFD
                    $cufdEvento         = $dataSellPointsValid['cufd']['codigo_cufd'];
                    // Ahora registramos el evento significativo
                    $codigoPuntoVenta   = $dataSellPointsValid['codigo_punto_venta'];
                    // Obtenemos las facturas
                    $sivirCufd          = new SivirCufd();
                    $significant_event  = new SivirSignificantEvent();
                    $invoiceStatus      = new SivirSellInvoiceStatus();
                    $massMailing        = new SivirMassMailing();
                    // Las fechas
                    $fechaHoraInicioEvento  = $eventoSignificativoRegistrado->fechaHoraInicioEvento;
                    $fechaHoraFinEvento     = $eventoSignificativoRegistrado->fechaHoraFinEvento;
                    // Ahora buscamos todas las facturas
                    $pendingInvoices = SivirSellInvoice::where('status', 'A')
                        ->where('global_branch_office_id', $this->getbranchoffice())
                        ->where('tipo_emision', 2)
                        ->where('sellpoint_id', $dataSellPointsValid['relative'])
                        ->whereRaw('created_at between ? and ?', [$fechaHoraInicioEvento, $fechaHoraFinEvento])
                        ->whereIn('sellpoint_id', function ($query) use ($sivirCufd, $significant_event, $idDelEventoSignificativo) {
                            $query->select('sellpoint_id')->from($sivirCufd->getTableName())->where('status', 'A')
                                ->whereIn('codigo_cufd', function ($q) use ($significant_event, $idDelEventoSignificativo) {
                                    $q->select('cufdEvento')->from($significant_event->getTableName())
                                        ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                                        ->where('id', $idDelEventoSignificativo);
                                });
                        })
                        ->whereNotIn('id', function ($query) use ($invoiceStatus) {
                            $query->select('invoice_id')->from($invoiceStatus->getTableName())
                                ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice());
                        })
                        ->whereNotIn('id', function ($query) use ($massMailing) {
                            $query->select('invoices')->from($massMailing->getTableName())
                                ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice());
                        })
                        ->orderBy('created_at', 'ASC');
                    // Verificamos que existan facturas
                    if ($pendingInvoices->exists()) {
                        // Obtenemos la data
                        $allInvoices = $pendingInvoices->get();
                        // Recorremos las facturas
                        foreach ($allInvoices as $data) {
                            $invoices[] = $data['id'];
                        }
                        // Obtenemos informacion de la facturacion
                        $bolivianInvoice    = $this->getbolivianinvoice();
                        // Obtenemos informacion sobre el sistema
                        $systemBehavior     = $this->getsystembehavior();
                        // Asignamos los valores devueltos a las variables correspondientes
                        // Informacion obtenida del comportamiento del sistema
                        $codigoAmbiente     = $systemBehavior->codigo_ambiente;
                        $token              = $systemBehavior->token;
                        $codigoSistema      = $systemBehavior->codigo_sistema;
                        // Informacion obtenida de la facturacion boliviana
                        $codigoModalidad    = $bolivianInvoice['codigo_modalidad'];
                        $codigoSucursal     = $bolivianInvoice['codigo_sucursal'];
                        $nit                = $bolivianInvoice['nit'];
                        $codigoDocumentoSector = $allInvoices[0]['tipo_factura_id']; // Here!
                        // Obtenemos informacion de zofra
                        $zofra = $allInvoices[0]['zofra'];
                        // Verificamos zofra
                        $tipo_factura = $this->gettipofactura($codigoDocumentoSector);
                        // Creamos la variable donde iran los XML
                        $xml_file = array();
                        // La URL
                        $url = null;
                        // Ahora recorremos las facturas
                        foreach ($allInvoices as $data) {
                            // La carpeta
                            $storagePath = $this->getstoragefolderinvoice('FOLDER', $codigoSucursal, $data['id'], $codigoModalidad, $codigoDocumentoSector);
                            // El archivo XML
                            $xmlFile = $this->getstoragefolderinvoice('FILE', $codigoSucursal, $data['id'], $codigoModalidad, $codigoDocumentoSector);
                            // El archivo completo
                            $completeFile = $storagePath . $xmlFile;
                            // Ahora obtenemos el XML mediante la funcion correcta
                            if (file_exists($completeFile)) {
                                // XML FILE
                                $xml = $this->getxmlfile($completeFile);
                            } else {
                                sleep(1);
                                // XML FILE
                                $xml = $this->getxmlfile($completeFile);
                            }
                            // Many tries
                            while (!$this->checkxmlfile($xml)) {
                                sleep(1);
                                // XML FILE
                                $xml = $this->getxmlfile($completeFile);
                            }
                            // Si existe entonces lo asignamos
                            $xml_file[] = $xml;
                        }
                        // La url
                        $url = $this->geturltosend($codigoAmbiente, $codigoModalidad, $codigoDocumentoSector, $zofra);
                        // Ahora obtenemos el cafc code
                        $cafcResponse   = CafcCode::where('status', 'A')
                            ->where('global_branch_office_id', $this->getbranchoffice())
                            ->where('tipo_factura_id', $codigoDocumentoSector)
                            ->where('codigo_modalidad', $codigoModalidad)
                            ->orderBy('created_at', 'DESC')->get()->first();
                        // Obtenemos el CUIS
                        $cuis   = $this->getCUISBySellpointCode($dataSellPointsValid['codigo_punto_venta'], $this->getbranchoffice());
                        // Comprobamos que exista un cuis valido
                        if ($cuis == false) {
                            return false;
                        }
                        // Ahora tenemos el CAFC Code
                        $cafc_code = $cafcResponse->cafc_code;
                        // Registramos los parametros que vamos a enviar
                        $params = [
                            'codigoAmbiente'          =>  $codigoAmbiente,
                            'codigoPuntoVenta'        =>  $codigoPuntoVenta,
                            'codigoSistema'           =>  $codigoSistema,
                            'codigoSucursal'          =>  $codigoSucursal,
                            'nit'                     =>  $nit,
                            'codigoDocumentoSector'   =>  $codigoDocumentoSector,
                            'codigoEmision'           =>  2,
                            'codigoModalidad'         =>  $codigoModalidad,
                            'cufd'                    =>  $eventoSignificativoRegistrado->cufdEvento,
                            'cuis'                    =>  $cuis,
                            'tipoFacturaDocumento'    =>  $tipo_factura,
                            'invoices'                =>  $xml_file,
                            'url'                     =>  $url,
                            'codigoMotivo'            =>  $eventoSignificativoRegistrado->codigoMotivoEvento
                        ];
                        // Ahora intentamos la recepcion de facturas
                        $dataServicioFacturacion = $this->recepcionPaqueteFactura($params, $params['invoices'], $eventoSignificativoRegistrado->codigoRecepcionEventoSignificativo, $cafc_code, $token);
                        // Verificamos si salio bien
                        if ($dataServicioFacturacion->RespuestaServicioFacturacion->transaccion) {
                            // La fecha/hora actual
                            $ahora = date("Y-m-d H:i:s");
                            // Guardamos el envio masivo de las facturas
                            SivirMassMailing::create(
                                [
                                    'users_sid'                     =>      $users_sid,
                                    'global_branch_office_id'       =>      $branch,
                                    'event_number'                  =>      $idDelEventoSignificativo,
                                    'invoices'                      =>      implode(",", $invoices),
                                    'codigo_punto_venta'            =>      $codigoPuntoVenta,
                                    'zofra'                         =>      $zofra,
                                    'tipo_emision'                  =>      2,
                                    'codigoDescripcion'             =>      $dataServicioFacturacion->RespuestaServicioFacturacion->codigoDescripcion,
                                    'codigoEstado'                  =>      $dataServicioFacturacion->RespuestaServicioFacturacion->codigoEstado,
                                    'codigoRecepcion'               =>      $dataServicioFacturacion->RespuestaServicioFacturacion->codigoRecepcion,
                                    'status'                        =>      'A',
                                    'created_at'                    =>      $ahora
                                ]
                            );
                            return response()->json(
                                [
                                    'status'    =>  'success',
                                    'message'   =>  implode(",", $invoices),
                                    'event'     =>  $idDelEventoSignificativo
                                ],
                                200
                            );
                        } else {
                            return response()->json(
                                [
                                    'status'    =>      'fail',
                                    'message'   =>      'no conseguimos confirmar los paquetes pendientes',
                                ],
                                409
                            );
                        }
                    }
                }
            } else {
                return response()->json(
                    [
                        'status'    =>  'success'
                    ],
                    200
                );
            }
        } else {
            return response()->json(
                [
                    'status'    =>  'success'
                ],
                200
            );
        }
    }

    /**
     * Procesamos el paso uno con todas las facturas encontradas
     *
     * @param Request $request
     * @return void
     */
    public function processstepone(Request $request)
    {
        // The configuration data
        // El codigo del motivo del Evento
        $codigoMotivoEvento     = $request->reason ?? 2;
        // La descripcion
        $descripcion            = $this->returnmotivo($codigoMotivoEvento);
        // Obtenemos el dato de la sucursal a utilizar
        $branchOffice           = $this->getbranchoffice();
        // The invoice status
        $status = 2;
        // Obtenemos los puntos de venta que este con un CUFD activo
        $sellpointsOpenedAndValid = SellPoint::where('status', 'A')
            ->where('global_branch_office_id', $branchOffice)
            ->where('codigo_punto_venta', '<>', null)
            ->with(['cufd'])
            ->orderBy('created_at', 'ASC')->get();
        // Verificamos si existe al menos 1 punto de venta
        if ($sellpointsOpenedAndValid->count() > 0) {
            // The sell invoice status
            $invoiceStatus = new SivirSellInvoiceStatus();
            $massMailing = new SivirMassMailing();
            // Recorremos todos los puntos de venta encontrados
            foreach ($sellpointsOpenedAndValid as $dataSellPointsValid) {
                // Verificamos si existen facturas fuera de linea
                $offlineInvoices = SivirSellInvoice::where('status', 'A')->where('estado', 'V')
                    ->where('global_branch_office_id', $branchOffice)
                    ->where('sellpoint_id', $dataSellPointsValid['relative'])
                    ->where('created_at', 'like', date("Y-m-d") . '%')
                    ->where('tipo_emision', $status) // Offline
                    ->when($codigoMotivoEvento <= 3, function ($query) {
                        $query->whereNull('cafc');
                    })
                    ->when($codigoMotivoEvento > 3, function ($query) {
                        $query->whereNotNull('cafc');
                    })
                    ->whereNotIn('id', function ($q) use ($massMailing) {
                        $q->select('invoices')->from($massMailing->getTableName())
                            ->where('status', 'A')->where('created_at', 'like', date("Y-m-d") . '%')->get();
                    })
                    ->whereNotIn('id', function ($q) use ($invoiceStatus) {
                        $q->select('invoice_id')->from($invoiceStatus->getTableName())->where('status', 'A')->get();
                    });
                // Verificamos si exsite o no
                if ($offlineInvoices->exists()) {
                    // Obtenemos el comportamiento del sistema
                    $systemBehavior = SivirSystemBehavior::where('status', 'A')
                        ->where('global_branch_office_id', $branchOffice)
                        ->get()->first();
                    // Asignamos los valores devueltos a las variables correspondientes
                    // Informacion obtenida del comportamiento del sistema
                    $token              = $systemBehavior->token;
                    // Obtenemos el CUIS utilizando el punto de venta
                    $cuis               = $this->getCUISBySellpointCode($dataSellPointsValid['codigo_punto_venta'], $branchOffice);
                    // Comprobamos que exista un cuis valido
                    if ($cuis == false) {
                        return false;
                    }
                    // Intentamos el ping
                    if ($this->tryping($token)) {
                        // Obtenemos las facturas
                        $invoicesFinded = $offlineInvoices->orderBy('created_at', 'ASC')->get();
                        // Iniciamos el contador para saber cual es la primer factura
                        $invoicesCounter = 1;
                        // Verifcamos la cantidad
                        if ($invoicesFinded->count() == 1) {
                            // Recorremos las facturas encontradas
                            foreach ($invoicesFinded as $data) {
                                $invoices[] = $data['id'];
                                // Recorremos las facturas para conocer la hora de inicio y hora final
                                $initialTimeSeconds = Carbon::parse($data['created_at'])->subSeconds(2)->format("H:i:s");
                                // The initial time with milli seconds
                                $initialTimeWithMilliseconds = Carbon::parse($data['created_at'])->format("Y-m-d") . 'T' . $initialTimeSeconds . '.' . substr(intval(microtime(true) * 1000), -3);
                                // The final seconds
                                $finalTimeSeconds = Carbon::parse($data['created_at'])->addSeconds(2)->format("H:i:s");
                                //  The final time with milliseconds
                                $finalTimeWithMilliseconds = Carbon::parse($data['created_at'])->format("Y-m-d") . 'T' . $finalTimeSeconds . '.' . substr(intval(microtime(true) * 1000), -3);
                            }
                        } else {
                            // Recorremos las facturas encontradas
                            foreach ($invoicesFinded as $data) {
                                // Registramos las facturas
                                $invoices[] = $data['id'];
                                // Recorremos
                                if ($invoicesCounter == 1) {
                                    // Recorremos las facturas para conocer la hora de inicio y hora final
                                    $initialTimeSeconds = Carbon::parse($data['created_at'])->subSeconds(2)->format("H:i:s");
                                    // The initial time with milli seconds
                                    $initialTimeWithMilliseconds = Carbon::parse($data['created_at'])->format("Y-m-d") . 'T' . $initialTimeSeconds . '.' . substr(intval(microtime(true) * 1000), -3);
                                } else {
                                    // The final seconds
                                    $finalTimeSeconds = Carbon::parse($data['created_at'])->addSeconds(2)->format("H:i:s");
                                    //  The final time with milliseconds
                                    $finalTimeWithMilliseconds = Carbon::parse($data['created_at'])->format("Y-m-d") . 'T' . $finalTimeSeconds . '.' . substr(intval(microtime(true) * 1000), -3);
                                }
                                // Incrementamos el contador de facturas
                                $invoicesCounter++;
                            }
                        }
                        // Ahora que ya tenemos la fecha hora inicial, y la fecha hora final procedemos a crear el evento significativo
                        // Obtenemos el usuario
                        $users_sid      = $this->getusersid();
                        // Ahora obtenemos el CUFD que estaba vigente mas cercano a esta fecha
                        $cufdEncontrado = $this->getlastvalidcufdarounddate($invoicesFinded[0]['created_at'], $invoicesFinded[0]['sellpoint_id']);
                        // The last CUFD
                        $cufdEvento     = $cufdEncontrado->codigo_cufd;
                        // Ahora registramos el evento significativo
                        $codigoPuntoVenta = $dataSellPointsValid['codigo_punto_venta'];
                        // Ahora creamos el evento significativo falso
                        $elEventoSignificativo  = $this->createsignificantevent($codigoPuntoVenta, $codigoMotivoEvento, $cufdEvento, $descripcion, $initialTimeWithMilliseconds, $finalTimeWithMilliseconds, $users_sid, $branchOffice);
                        // Verificamos que no haya fallado
                        if ($elEventoSignificativo[0] != false) {
                            // Retornamos la informacion
                            return response()->json(
                                [
                                    'status'    =>      'success',
                                    'message'   =>      $elEventoSignificativo[0]
                                ],
                                200
                            );
                        } else {
                            // Retornamos la informacion
                            return response()->json(
                                [
                                    'status'    =>      'fail',
                                    'message'   =>      $elEventoSignificativo[1]
                                ],
                                409
                            );
                        }
                    } else {
                        // Retornamos la informacion
                        return response()->json(
                            [
                                'status'    =>      'fail',
                                'message'   =>      'No hay conección con impuestos nacionales'
                            ],
                            409
                        );
                    }
                } else {
                    // Retornamos la informacion
                    return response()->json(
                        [
                            'status'    =>      'fail',
                            'message'   =>      'No hay facturas disponibles para envio'
                        ],
                        409
                    );
                }
            }
        }
    }

    /**
     * Encontramos el primer CUFD valido anterior a la fecha y hora enviadas
     */
    private function getlastvalidcufdarounddate($fechayhora, $sellpoint)
    {
        // Tenemos la fecha y hora ahora debemos obtener los cufd
        $CufdEncontrado = SivirCufd::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('sellpoint_id', $sellpoint)
            ->where('created_at', '<=', $fechayhora)->orderBy('created_at', 'DESC')->first();
        // Ahora retornamos
        return $CufdEncontrado;
    }

    /**
     * @param $codigoPuntoVenta
     * @param $codigoMotivoEvento
     * @param $cufdEvento
     * @param $descripcion
     * @param $fechaHoraInicioEvento
     * @param $fechaHoraFinEvento
     * @param $users_sid
     * @param $branchOffice
     * @return bool|mixed
     * @throws \Exception
     */
    private function createsignificantevent($codigoPuntoVenta, $codigoMotivoEvento, $cufdEvento, $descripcion, $fechaHoraInicioEvento, $fechaHoraFinEvento, $users_sid, $branchOffice)
    {
        // Obtenemos informacion de la facturacion
        $bolivianInvoice    = $this->getbolivianinvoice();
        // Obtenemos informacion sobre el sistema
        $systemBehavior     = $this->getsystembehavior();
        // Asignamos los valores devueltos a las variables correspondientes
        // Informacion obtenida del comportamiento del sistema
        $codigoAmbiente     = $systemBehavior->codigo_ambiente;
        $token              = $systemBehavior->token;
        $codigoSistema      = $systemBehavior->codigo_sistema;
        // Informacion obtenida de la facturacion boliviana
        $codigoModalidad    = $bolivianInvoice['codigo_modalidad'];
        $codigoSucursal     = $bolivianInvoice['codigo_sucursal'];
        $nit                = $bolivianInvoice['nit'];
        // Obtenemos el CUIS utilizando el punto de venta
        $cuis               = $this->getCUISBySellpointCode($codigoPuntoVenta, $branchOffice);
        // Comprobamos que exista un cuis valido
        if ($cuis == false) {
            // Entonces si no hay generamos un CUIS
            $obtenerCuis = $this->createCUIS($codigoAmbiente, $codigoModalidad, $codigoPuntoVenta, $codigoSistema, $codigoSucursal, $nit, $token);
            // Obtenemos unicamente el cuis
            $cuis = XmlToArray::convert($obtenerCuis->body())['soap:Body']['ns2:cuisResponse']['RespuestaCuis']['codigo'];
        }
        // Obtenemos el ID del punto de venta segun su codigo de punto de venta
        $puntoDeVentaResponse = SellPoint::where('status', 'A')->where('codigo_punto_venta', $codigoPuntoVenta)->get()->first();
        // el ID del punto de venta
        $idPuntoDeVenta = $puntoDeVentaResponse->relative;
        // Buscamos el ultimo CUFD del punto de venta
        $responseCufd = SivirCufd::where('status', 'A')
            ->where('sellpoint_id', $idPuntoDeVenta)
            ->with(['sellpoint'])
            ->orderBy('created_at', 'DESC')->get()->first();
        // Ahora guardamos el CUFD en una variable
        $cufd                   = $responseCufd->codigo_cufd; // El ultimo CUFD registrado
        // Obtenemos el evento significativo de la funcion privada
        $eventoSignificativo = $this->generateregistersignificactiveevent(
            $codigoAmbiente,
            $codigoMotivoEvento,
            $codigoPuntoVenta,
            $codigoSistema,
            $codigoSucursal,
            $cufd,
            $cufdEvento,
            $cuis,
            $descripcion,
            $fechaHoraFinEvento,
            $fechaHoraInicioEvento,
            $nit,
            $token
        );
        // Ingresamos a los datos de las unidades de medida
        // La data
        if (config('app.proxy.enabled')) {
            $codigoEventoSignificativoTransaccion = XmlToArray::convert($eventoSignificativo)['soap:Body']['ns2:registroEventoSignificativoResponse']['RespuestaListaEventos']['transaccion'];
        } else {
            $codigoEventoSignificativoTransaccion = XmlToArray::convert($eventoSignificativo->body())['soap:Body']['ns2:registroEventoSignificativoResponse']['RespuestaListaEventos']['transaccion'];
        }
        // Convertimos a booleano
        $codigoEventoSignificativoTransaccion = $codigoEventoSignificativoTransaccion == "false" ? false : true;
        // Comparamos si recibimos un mensaje positivo o negativo
        if ($codigoEventoSignificativoTransaccion) {
            // Obtenemos toda la informacion del evento
            if (config('app.proxy.enabled')) {
                $codigoRecepcionEventoSignificativo = XmlToArray::convert($eventoSignificativo)['soap:Body']['ns2:registroEventoSignificativoResponse']['RespuestaListaEventos']['codigoRecepcionEventoSignificativo'];
            } else {
                $codigoRecepcionEventoSignificativo = XmlToArray::convert($eventoSignificativo->body())['soap:Body']['ns2:registroEventoSignificativoResponse']['RespuestaListaEventos']['codigoRecepcionEventoSignificativo'];
            }
            // Ahora guardamos el evendo significativo en su tabla correspondiente
            SivirSignificantEvent::create(
                [
                    'users_sid'                             =>      $users_sid,
                    'global_branch_office_id'               =>      $branchOffice,
                    'cufd'                                  =>      $cufd,
                    'cufdEvento'                            =>      $cufdEvento,
                    'codigoMotivoEvento'                    =>      $codigoMotivoEvento,
                    'descripcion'                           =>      $descripcion,
                    'fechaHoraInicioEvento'                 =>      $fechaHoraInicioEvento,
                    'fechaHoraFinEvento'                    =>      $fechaHoraFinEvento,
                    'codigoRecepcionEventoSignificativo'    =>      $codigoRecepcionEventoSignificativo,
                    'status'                                =>      'A',
                    'created_at'                            =>      date("Y-m-d H:i:s")
                ]
            );
            // Devolvemos los valores
            return [$codigoRecepcionEventoSignificativo];
        }
        // La data
        if (config('app.proxy.enabled')) {
            return
                [
                    false,
                    XmlToArray::convert($eventoSignificativo)['soap:Body']['ns2:registroEventoSignificativoResponse']['RespuestaListaEventos']['mensajesList']['codigo']
                ];
        } else {
            return
                [
                    false,
                    XmlToArray::convert($eventoSignificativo->body())['soap:Body']['ns2:registroEventoSignificativoResponse']['RespuestaListaEventos']['mensajesList']['codigo']
                ];
        }
    }

    /**
     * @param $codigoAmbiente
     * @param $codigoModalidad
     * @param $codigoPuntoVenta
     * @param $codigoSistema
     * @param $codigoSucursal
     * @param $nit
     * @param $token
     * @return \Illuminate\Http\Client\Response
     * @throws \Exception
     */
    private function createCUIS($codigoAmbiente, $codigoModalidad, $codigoPuntoVenta, $codigoSistema, $codigoSucursal, $nit, $token)
    {
        // Definimos la URL segun el codigo ambiente
        $url = $codigoAmbiente == 1 ? 'https://siatrest.impuestos.gob.bo/v2/FacturacionCodigos' : 'https://pilotosiatservicios.impuestos.gob.bo/v2/FacturacionCodigos';
        return Http::withHeaders([
            "Content-Type"  => "text/xml;charset=utf-8",
            "apikey"        => 'TokenApi ' . $token
        ])->timeout(15)->withoutVerifying()->send(
            "POST",
            $url,
            [
                "body" => '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:siat="https://siat.impuestos.gob.bo/">
                   <soapenv:Header/>
                   <soapenv:Body>
                      <siat:cuis>
                        <SolicitudCuis>
                          <codigoAmbiente>' . $codigoAmbiente . '</codigoAmbiente>
                          <codigoModalidad>' . $codigoModalidad . '</codigoModalidad>
                          <!--Optional:-->
                          <codigoPuntoVenta>' . $codigoPuntoVenta . '</codigoPuntoVenta>
                          <codigoSistema>' . $codigoSistema . '</codigoSistema>
                          <codigoSucursal>' . $codigoSucursal . '</codigoSucursal>
                          <nit>' . $nit . '</nit>
                        </SolicitudCuis>
                      </siat:cuis>
                   </soapenv:Body>
                </soapenv:Envelope>'
            ]
        );
    }

    /**
     * @param $codigoAmbiente
     * @param $codigoMotivoEvento
     * @param $codigoPuntoVenta
     * @param $codigoSistema
     * @param $codigoSucursal
     * @param $cufd
     * @param $cufdEvento
     * @param $cuis
     * @param $descripcion
     * @param $fechaHoraFinEvento
     * @param $fechaHoraInicioEvento
     * @param $nit
     * @param $token
     * @return \Illuminate\Http\Client\Response
     * @throws \Exception
     */
    private function generateregistersignificactiveevent($codigoAmbiente, $codigoMotivoEvento, $codigoPuntoVenta, $codigoSistema, $codigoSucursal, $cufd, $cufdEvento, $cuis, $descripcion, $fechaHoraFinEvento, $fechaHoraInicioEvento, $nit, $token)
    {
        // Definimos la URL segun el codigo ambiente
        $url = $codigoAmbiente == 1 ? 'https://siatrest.impuestos.gob.bo/v2/FacturacionOperaciones' : 'https://pilotosiatservicios.impuestos.gob.bo/v2/FacturacionOperaciones';
        // Obtenemos la opcion de la URL en proxy o no
        $proxy = $this->isthereaproxy('generateregistersignificactiveevent');
        // Verificamos si habia o no proxy
        if ($proxy != false) {
            // Obtenemos el proxy URL
            $proxyUrl = $proxy;
            // El token
            $token = 'TokenApi ' . $token;
            // Y ahora el cuerpo
            $body = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:siat="https://siat.impuestos.gob.bo/">
               <soapenv:Header/>
                   <soapenv:Body>
                      <siat:registroEventoSignificativo>
                        <SolicitudEventoSignificativo>
                          <codigoAmbiente>' . $codigoAmbiente . '</codigoAmbiente>
                          <codigoMotivoEvento>' . $codigoMotivoEvento . '</codigoMotivoEvento>
                          <!--Optional:-->
                          <codigoPuntoVenta>' . $codigoPuntoVenta . '</codigoPuntoVenta>
                          <codigoSistema>' . $codigoSistema . '</codigoSistema>
                          <codigoSucursal>' . $codigoSucursal . '</codigoSucursal>
                          <cufd>' . $cufd . '</cufd>
                          <cufdEvento>' . $cufdEvento . '</cufdEvento>
                          <cuis>' . $cuis . '</cuis>
                          <descripcion>' . $descripcion . '</descripcion>
                          <fechaHoraFinEvento>' . $fechaHoraFinEvento . '</fechaHoraFinEvento>
                          <fechaHoraInicioEvento>' . $fechaHoraInicioEvento . '</fechaHoraInicioEvento>
                          <nit>' . $nit . '</nit>
                        </SolicitudEventoSignificativo>
                      </siat:registroEventoSignificativo>
                   </soapenv:Body>
                </soapenv:Envelope>';
            // Ahora intentamos la conexion
            $response = Http::withHeaders([
                "Content-Type" => "application/json",
            ])->timeout(30)->withoutVerifying()->post($proxyUrl, [
                'url' => $url,
                'token' => $token,
                'body' => $body,
            ]);
            // Retornamos
            return json_decode($response->body())->body;
        } else {
            // Creamos el punto de venta con la informacion que se nos envia
            return Http::withHeaders([
                "Content-Type" => "text/xml;charset=utf-8",
                "apikey" => 'TokenApi ' . $token
            ])->timeout(30)->withoutVerifying()->send(
                "POST",
                $url,
                [
                    "body" => '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:siat="https://siat.impuestos.gob.bo/">
                       <soapenv:Header/>
                       <soapenv:Body>
                          <siat:registroEventoSignificativo>
                            <SolicitudEventoSignificativo>
                              <codigoAmbiente>' . $codigoAmbiente . '</codigoAmbiente>
                              <codigoMotivoEvento>' . $codigoMotivoEvento . '</codigoMotivoEvento>
                              <!--Optional:-->
                              <codigoPuntoVenta>' . $codigoPuntoVenta . '</codigoPuntoVenta>
                              <codigoSistema>' . $codigoSistema . '</codigoSistema>
                              <codigoSucursal>' . $codigoSucursal . '</codigoSucursal>
                              <cufd>' . $cufd . '</cufd>
                              <cufdEvento>' . $cufdEvento . '</cufdEvento>
                              <cuis>' . $cuis . '</cuis>
                              <descripcion>' . $descripcion . '</descripcion>
                              <fechaHoraFinEvento>' . $fechaHoraFinEvento . '</fechaHoraFinEvento>
                              <fechaHoraInicioEvento>' . $fechaHoraInicioEvento . '</fechaHoraInicioEvento>
                              <nit>' . $nit . '</nit>
                            </SolicitudEventoSignificativo>
                          </siat:registroEventoSignificativo>
                       </soapenv:Body>
                    </soapenv:Envelope>'
                ]
            );
        }
    }

    /**
     * @param $sellpointcode
     * @param $branchoffice
     * @return bool
     */
    private function getCUISBySellPointCode($sellpointcode, $branchoffice)
    {
        // Obtenemos la fecha y la hora, y le incrementamos 10 minutos para darle
        // oportunidad al usuario de que haga su transaccion sin errores
        $hora_actual_mas_10_minutos = Carbon::now()->addMinutes(10)->format("Y-m-d H:i:s");
        // Obtenemos el codigo del CUIS de la tabla
        // Pero primero debemos confirmar que el codigo del punto de venta
        // corresponde a un punto de venta
        $obtenerCuis = SoapCuis::where('status', 'A')
            ->where('global_branch_office_id', $branchoffice)
            ->where('cuis_expiration_datetime', '>', $hora_actual_mas_10_minutos)
            ->where('codigo_punto_venta', $sellpointcode)
            ->orderBy('created_at', 'DESC')->get()->first();
        // Devolvemos el CUIS, caso contrario devolvemos false
        return (isset($obtenerCuis->cuis)) ? $obtenerCuis->cuis : false;
    }

    /**
     * @return bool|\Illuminate\Http\JsonResponse
     * @throws \SoapFault
     */
    public function processsteptwo()
    {
        // El evento masivo
        $massMailing = new SivirMassMailing();
        // Buscamos el ID del evento significativo
        $eventos = SivirSignificantEvent::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->whereNotIn('id', function ($q) use ($massMailing) {
                $q->select('event_number')->from($massMailing->getTableName())
                    ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice());
            })
            ->orderBy('created_at', 'DESC');
        // Verificamos que exista al menos un evento siginificativo
        if ($eventos->exists()) {
            // Obtenemos el evento
            $eventoSignificativoRegistrado = $eventos->get()->first();
            // Tenemos el ID del evento significativo
            $idDelEventoSignificativo = $eventoSignificativoRegistrado->id;
            // Ahora verificamos todos los puntos de venta abiertos en esta sucursal
            $cufd = new SivirCufd();
            // La hora actual mas 10 minutos
            $hora_actual_mas_10_minutos = Carbon::now()->addMinutes(10)->format("Y-m-d H:i:s");
            // Obtenemos los puntos de venta que este con un CUFD activo
            $sellpointsOpenedAndValid = SellPoint::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('codigo_punto_venta', '<>', null)
                //                ->whereIn('relative', function($query)use($cufd, $hora_actual_mas_10_minutos){
                //                    $query->select('sellpoint_id')
                //                    ->from($cufd->getTableName())
                //                    ->where('fecha_vigencia', '>', $hora_actual_mas_10_minutos)
                //                    ->where('status', 'A');
                //                })
                ->with(['cufd'])
                ->orderBy('created_at', 'ASC')->get();
            // Verificamos si existe al menos 1 punto de venta
            if ($sellpointsOpenedAndValid->count() > 0) {
                // Recorremos todos los puntos de venta encontrados
                foreach ($sellpointsOpenedAndValid as $dataSellPointsValid) {
                    // Datos
                    $users_sid      = $this->getusersid();
                    $branch         = $this->getbranchoffice();
                    // The last CUFD
                    $cufdEvento         = $dataSellPointsValid['cufd']['codigo_cufd'];
                    // Ahora registramos el evento significativo
                    $codigoPuntoVenta   = $dataSellPointsValid['codigo_punto_venta'];
                    // Obtenemos las facturas
                    $sivirCufd          = new SivirCufd();
                    $significant_event  = new SivirSignificantEvent();
                    $invoiceStatus      = new SivirSellInvoiceStatus();
                    $massMailing        = new SivirMassMailing();
                    // Las fechas
                    $fechaHoraInicioEvento  = $eventoSignificativoRegistrado->fechaHoraInicioEvento;
                    $fechaHoraFinEvento     = $eventoSignificativoRegistrado->fechaHoraFinEvento;
                    // Ahora buscamos todas las facturas
                    $pendingInvoices = SivirSellInvoice::where('status', 'A')
                        ->where('global_branch_office_id', $this->getbranchoffice())
                        ->where('tipo_emision', 2)
                        ->where('sellpoint_id', $dataSellPointsValid['relative'])
                        ->whereRaw('created_at between ? and ?', [$fechaHoraInicioEvento, $fechaHoraFinEvento])
                        ->whereIn('sellpoint_id', function ($query) use ($sivirCufd, $significant_event, $idDelEventoSignificativo) {
                            $query->select('sellpoint_id')->from($sivirCufd->getTableName())->where('status', 'A')
                                ->whereIn('codigo_cufd', function ($q) use ($significant_event, $idDelEventoSignificativo) {
                                    $q->select('cufdEvento')->from($significant_event->getTableName())
                                        ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                                        ->where('id', $idDelEventoSignificativo);
                                });
                        })
                        ->whereNotIn('id', function ($query) use ($invoiceStatus) {
                            $query->select('invoice_id')->from($invoiceStatus->getTableName())
                                ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice());
                        })
                        ->whereNotIn('id', function ($query) use ($massMailing) {
                            $query->select('invoices')->from($massMailing->getTableName())
                                ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice());
                        })
                        ->orderBy('created_at', 'ASC');
                    // Verificamos que existan facturas
                    if ($pendingInvoices->exists()) {
                        // Obtenemos la data
                        $allInvoices = $pendingInvoices->get();
                        // Recorremos las facturas
                        foreach ($allInvoices as $data) {
                            $invoices[] = $data['id'];
                        }
                        // Obtenemos informacion de la facturacion
                        $bolivianInvoice    = $this->getbolivianinvoice();
                        // Obtenemos informacion sobre el sistema
                        $systemBehavior     = $this->getsystembehavior();
                        // Asignamos los valores devueltos a las variables correspondientes
                        // Informacion obtenida del comportamiento del sistema
                        $codigoAmbiente     = $systemBehavior->codigo_ambiente;
                        $token              = $systemBehavior->token;
                        $codigoSistema      = $systemBehavior->codigo_sistema;
                        // Informacion obtenida de la facturacion boliviana
                        $codigoModalidad    = $bolivianInvoice['codigo_modalidad'];
                        $codigoSucursal     = $bolivianInvoice['codigo_sucursal'];
                        $nit                = $bolivianInvoice['nit'];
                        $codigoDocumentoSector = $allInvoices[0]['tipo_factura_id']; // Here!
                        // Obtenemos informacion de zofra
                        $zofra = $allInvoices[0]['zofra'];
                        // Verificamos zofra
                        $tipo_factura = $this->gettipofactura($codigoDocumentoSector);
                        // Creamos la variable donde iran los XML
                        $xml_file = array();
                        // La URL
                        $url = null;
                        // Ahora recorremos las facturas
                        foreach ($allInvoices as $data) {
                            // La carpeta
                            $storagePath = $this->getstoragefolderinvoice('FOLDER', $codigoSucursal, $data['id'], $codigoModalidad, $codigoDocumentoSector);
                            // El archivo XML
                            $xmlFile = $this->getstoragefolderinvoice('FILE', $codigoSucursal, $data['id'], $codigoModalidad, $codigoDocumentoSector);
                            // El archivo completo
                            $completeFile = $storagePath . $xmlFile;
                            // Ahora obtenemos el XML mediante la funcion correcta
                            if (file_exists($completeFile)) {
                                // XML FILE
                                $xml = $this->getxmlfile($completeFile);
                            } else {
                                sleep(1);
                                // XML FILE
                                $xml = $this->getxmlfile($completeFile);
                            }
                            // Many tries
                            while (!$this->checkxmlfile($xml)) {
                                sleep(1);
                                // XML FILE
                                $xml = $this->getxmlfile($completeFile);
                            }
                            // Si existe entonces lo asignamos
                            $xml_file[] = $xml;
                        }
                        // La url
                        $url = $this->geturltosend($codigoAmbiente, $codigoModalidad, $codigoDocumentoSector, $zofra);
                        // Ahora obtenemos el cafc code
                        $cafcResponse   = CafcCode::where('status', 'A')
                            ->where('global_branch_office_id', $this->getbranchoffice())
                            ->where('tipo_factura_id', $codigoDocumentoSector)
                            ->where('codigo_modalidad', $codigoModalidad)
                            ->orderBy('created_at', 'DESC')->get()->first();
                        // Obtenemos el CUIS
                        $cuis   = $this->getCUISBySellpointCode($dataSellPointsValid['codigo_punto_venta'], $this->getbranchoffice());
                        // Comprobamos que exista un cuis valido
                        if ($cuis == false) {
                            return false;
                        }
                        // Ahora tenemos el CAFC Code
                        $cafc_code = $cafcResponse->cafc_code;
                        // Registramos los parametros que vamos a enviar
                        $params = [
                            'codigoAmbiente'          =>  $codigoAmbiente,
                            'codigoPuntoVenta'        =>  $codigoPuntoVenta,
                            'codigoSistema'           =>  $codigoSistema,
                            'codigoSucursal'          =>  $codigoSucursal,
                            'nit'                     =>  $nit,
                            'codigoDocumentoSector'   =>  $codigoDocumentoSector,
                            'codigoEmision'           =>  2,
                            'codigoModalidad'         =>  $codigoModalidad,
                            'cufd'                    =>  $eventoSignificativoRegistrado->cufdEvento,
                            'cuis'                    =>  $cuis,
                            'tipoFacturaDocumento'    =>  $tipo_factura,
                            'invoices'                =>  $xml_file,
                            'url'                     =>  $url,
                            'codigoMotivo'            =>  $eventoSignificativoRegistrado->codigoMotivoEvento
                        ];
                        // Ahora intentamos la recepcion de facturas
                        $dataServicioFacturacion = $this->recepcionPaqueteFactura($params, $params['invoices'], $eventoSignificativoRegistrado->codigoRecepcionEventoSignificativo, $cafc_code, $token);
                        // Verificamos si salio bien
                        if ($dataServicioFacturacion->RespuestaServicioFacturacion->transaccion) {
                            // La fecha/hora actual
                            $ahora = date("Y-m-d H:i:s");
                            // Guardamos el envio masivo de las facturas
                            SivirMassMailing::create(
                                [
                                    'users_sid'                     =>      $users_sid,
                                    'global_branch_office_id'       =>      $branch,
                                    'event_number'                  =>      $idDelEventoSignificativo,
                                    'invoices'                      =>      implode(",", $invoices),
                                    'codigo_punto_venta'            =>      $codigoPuntoVenta,
                                    'zofra'                         =>      $zofra,
                                    'tipo_emision'                  =>      2,
                                    'codigoDescripcion'             =>      $dataServicioFacturacion->RespuestaServicioFacturacion->codigoDescripcion,
                                    'codigoEstado'                  =>      $dataServicioFacturacion->RespuestaServicioFacturacion->codigoEstado,
                                    'codigoRecepcion'               =>      $dataServicioFacturacion->RespuestaServicioFacturacion->codigoRecepcion,
                                    'status'                        =>      'A',
                                    'created_at'                    =>      $ahora
                                ]
                            );
                            return response()->json(
                                [
                                    'status'    =>  'success',
                                    'event'     =>  $idDelEventoSignificativo
                                ],
                                200
                            );
                        } else {
                            return response()->json(
                                [
                                    'status'    =>      'fail',
                                    'message'   =>      'no conseguimos confirmar los paquetes pendientes',
                                ],
                                409
                            );
                        }
                    }
                }
            } else {
                return response()->json(
                    [
                        'status'    =>  'success'
                    ],
                    200
                );
            }
        } else {
            return response()->json(
                [
                    'status'    =>  'success'
                ],
                200
            );
        }
    }
    /**
     * @param $path
     * @return string
     */
    private function getxmlfile($path)
    {
        // Vamos a usarlo de manera aleatoria
        $aleatorio = rand(1, 2);
        // Y dependiendo de eso usaremos un metodo u otro
        if ($aleatorio == 1) {
            try {
                return \Illuminate\Support\Facades\File::get($path);
            } catch (\Exception $e) {
                sleep(1);
                $this->getxmlfile($path);
            }
        } else {
            try {
                return file_get_contents($path);
            } catch (\Exception $e) {
                sleep(1);
                $this->getxmlfile($path);
            }
        }
    }

    /**
     * @param $xml
     * @return bool
     */
    private function checkxmlfile($xml)
    {
        if (isset($xml)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * @param $params
     * @param $facturas
     * @param $cod_evento
     * @param $cafc
     * @param $token
     * @return mixed|string
     * @throws \SoapFault
     */
    public function recepcionPaqueteFactura($params, $facturas, $cod_evento, $cafc, $token)
    {
        $no_facturas    = count($facturas);
        $codigo_evento  = $cod_evento;

        $package_tmp    = storage_path('app/tar/paq_' . time() . '.tar');

        try {
            $package        = new PharData($package_tmp);
        } catch (Exception $exception) {
            return $exception->getMessage();
        }

        foreach ($facturas as $i => $factura) {
            $package->addFromString(sprintf("invoice-%d.xml", $i), $factura);
        }

        try {
            $gzfile         = gzencode(file_get_contents($package_tmp), 6, FORCE_GZIP);
            $hash_file      = hash('sha256', $gzfile, !true);
        } catch (Exception $exception) {
            return $exception->getMessage();
        }

        // Codificar el archivo comprimido en base64
        $gzfile_base64 = base64_encode($gzfile);

        // Obtenemos la opcion de la URL en proxy o no
        $proxy = $this->isthereaproxys('recepcionPaqueteFactura');

        // Verificamos si habia o no proxy
        if ($proxy != false) {
            $request_params =
                [
                    "SolicitudServicioRecepcionPaquete" =>
                    [
                        "codigoAmbiente"            => $params['codigoAmbiente'],
                        "codigoDocumentoSector"     => $params['codigoDocumentoSector'],
                        "codigoEmision"             => $params['codigoEmision'],
                        "codigoModalidad"           => $params['codigoModalidad'],
                        "codigoPuntoVenta"          => $params['codigoPuntoVenta'],
                        "codigoSistema"             => $params['codigoSistema'],
                        "codigoSucursal"            => $params['codigoSucursal'],
                        "cufd"                      => $params['cufd'],
                        "cuis"                      => $params['cuis'],
                        "nit"                       => $params['nit'],
                        "tipoFacturaDocumento"      => $params['tipoFacturaDocumento'],
                        "archivo"                   => $gzfile_base64,
                        "fechaEnvio"                => date('Y-m-d\TH:i:s.v', time()),
                        "codigoEvento"              => $codigo_evento,
                        "hashArchivo"               => $hash_file,
                        "cafc"                      => $cafc,
                        "cantidadFacturas"          => $no_facturas
                    ]
                ];
            // Enviamos
            $toSend = [
                'url'   => $params['url'],
                'token' => $token,
                'body'  => json_encode($request_params),
            ];
            // Ahora intentamos la conexion
            $response = Http::withHeaders([
                "Content-Type" => "application/json",
            ])->timeout(60)->withoutVerifying()->post($proxy, $toSend);
            // Retornamos la respuesta
            return json_decode($response->body())->body;
        } else {
            $request_params =
                [
                    "SolicitudServicioRecepcionPaquete" =>
                    [
                        "codigoAmbiente"            => $params['codigoAmbiente'],
                        "codigoDocumentoSector"     => $params['codigoDocumentoSector'],
                        "codigoEmision"             => $params['codigoEmision'],
                        "codigoModalidad"           => $params['codigoModalidad'],
                        "codigoPuntoVenta"          => $params['codigoPuntoVenta'],
                        "codigoSistema"             => $params['codigoSistema'],
                        "codigoSucursal"            => $params['codigoSucursal'],
                        "cufd"                      => $params['cufd'],
                        "cuis"                      => $params['cuis'],
                        "nit"                       => $params['nit'],
                        "tipoFacturaDocumento"      => $params['tipoFacturaDocumento'],
                        "archivo"                   => $gzfile,
                        "fechaEnvio"                => date('Y-m-d\TH:i:s.v', time()),
                        "codigoEvento"              => $codigo_evento,
                        "hashArchivo"               => $hash_file,
                        "cafc"                      => $cafc,
                        "cantidadFacturas"          => $no_facturas
                    ]
                ];
            // Retornamos la informacion
            return $this->callSoap($params['url'], "RecepcionPaqueteFactura", $request_params, $token);
        }
    }

    /**
     * @param string $service
     * @return bool|string
     */
    private function isthereaproxys($service = 'recepcionPaqueteFactura')
    {
        if (config('app.proxy.enabled')) {
            switch ($service) {
                default:
                    $api = 'sipproxy';
                    break;
            }
            return env('PROXY_URL') . $api;
        } else {
            return false;
        }
    }

    /**
     * @param string $url
     * @param string $function
     * @param mixed $request_params
     * @param string $token
     * @return mixed
     * @throws \SoapFault
     * @throws \Exception
     */
    private function callSoap($url, $function, $request_params = null, $token)
    {
        // Crea un único contexto de stream para las cabeceras y la configuración SSL
        $context = stream_context_create([
            'http' => [
                'header' => "User-Agent: PHP-SOAP/5.5.11\r\n" .
                    sprintf("apikey: TokenApi %s", $token)
            ],
            'ssl' => [
                'verify_peer'       => false,
                'verify_peer_name'  => false,
                'allow_self_signed' => true
            ]
        ]);

        try {
            $client = new \SoapClient($url, [
                'trace' => 1,
                'stream_context' => $context
            ]);

            return $client->__soapCall($function, [$request_params]);
        } catch (\SoapFault $ex) {
            throw $ex;
        } catch (\Exception $ex) {
            throw $ex;
        }
    }

    /**
     * @return bool|\Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function processstepthree(Request $request)
    {
        sleep(3);
        // Obtenemos el evento significativo
        $elIDEventoSignificativo = $request->idevento;
        // Obtenemos la informacion del envio masivo
        $sivirMassMailingPending = SivirMassMailing::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('event_number', $elIDEventoSignificativo)
            //->where('created_at', 'like', date("Y-m-d").'%')
            ->where('codigoEstado', 901);
        // Verificamos si existe
        if ($sivirMassMailingPending->exists()) {
            // Obtenemos todos los pendientes
            $sivirMassMailing = $sivirMassMailingPending->get()->first();
            // Obtenemos el codigo de recepcion
            $codigoRecepcion = $sivirMassMailing->codigoRecepcion;
            // Obteniendo los datos basicos para obtener un CUIS
            $codigoPuntoVenta   = $sivirMassMailing->codigo_punto_venta;
            // Obtenemos informacion de la facturacion
            $bolivianInvoice    = $this->getbolivianinvoice();
            // Obtenemos informacion sobre el sistema
            $systemBehavior     = $this->getsystembehavior();
            // Asignamos los valores devueltos a las variables correspondientes
            // Informacion obtenida del comportamiento del sistema
            $codigoAmbiente     = $systemBehavior->codigo_ambiente;
            $token              = $systemBehavior->token;
            $codigoSistema      = $systemBehavior->codigo_sistema;
            // Informacion obtenida de la facturacion boliviana
            $codigoModalidad    = $bolivianInvoice['codigo_modalidad'];
            $codigoSucursal     = $bolivianInvoice['codigo_sucursal'];
            $nit                = $bolivianInvoice['nit'];
            $tipoFacturaDocumento = $bolivianInvoice['tipo_factura_id'];
            // Obtenemos el CUIS utilizando el punto de venta
            $cuis               = $this->getCUISBySellpointCode($codigoPuntoVenta, $this->getbranchoffice());
            // Comprobamos que exista un cuis valido
            if ($cuis == false) {
                return false;
            }
            // La url
            $url = $this->geturltosend($codigoAmbiente, $codigoModalidad, $bolivianInvoice['tipo_factura_id'], $sivirMassMailing->zofra);
            // Tipo de emision
            $codigoEmision            = $sivirMassMailing->tipo_emision; /* 1: Online 2: Offline 3: Masiva  */

            // Obtenemos el punto de venta
            $sellpointRelative = SellPoint::where('status', 'A')->where('codigo_punto_venta', $codigoPuntoVenta)->get()->first();
            // Buscamos el ultimo CUFD del punto de venta
            $responseCufd = SivirCufd::where('status', 'A')
                ->where('sellpoint_id', $sellpointRelative->relative)
                ->orderBy('created_at', 'DESC')->get()->first();
            // Ahora guardamos el CUFD en una variable
            $cufd                   = $responseCufd->codigo_cufd; // El ultimo CUFD registrado
            // Ahora enviamos la solicitud de confirmacion
            $confirmationMassMailing = $this->checkmassmailing($codigoAmbiente, $bolivianInvoice['tipo_factura_id'], $codigoEmision, $codigoModalidad, $codigoPuntoVenta, $codigoSistema, $codigoSucursal, $cufd, $cuis, $nit, $tipoFacturaDocumento, $codigoRecepcion, $token, $url);
            // Convertimos en array la confirmacion recibida
            $confirmacionRecibida = (array)$confirmationMassMailing->RespuestaServicioFacturacion;
            // Verificamos la confirmacion en booleano
            $confirmacionBooleana = ($confirmacionRecibida['transaccion'] == "true") ? true : false;
            // Verificamos si fue o no positiva
            if ($confirmacionBooleana) {
                // Entonces actualizamos el envio masivo utilizado
                SivirMassMailing::where('status', 'A')
                    ->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('id', $sivirMassMailing->id)
                    ->update(
                        [
                            'codigoDescripcion'     =>      $confirmacionRecibida['codigoDescripcion'],
                            'codigoEstado'          =>      $confirmacionRecibida['codigoEstado']
                        ]
                    );
                // Contamos las facturas
                $facturasMassMailing = $sivirMassMailing->invoices;
                // Contamos las facturas
                $lasFacturas = explode(",", $facturasMassMailing);
                // El contador
                $cuantasFacturasSeEnviaron = count($lasFacturas);
                // Verificamos si es mas de 1 factura
                if ($cuantasFacturasSeEnviaron == 1) {
                    // Insertamos la factura en el status
                    SivirSellInvoiceStatus::create(
                        [
                            'relative'                  =>      Str::uuid()->toString(),
                            'users_sid'                 =>      $this->getusersid(),
                            'global_branch_office_id'   =>      $this->getbranchoffice(),
                            'invoice_id'                =>      $lasFacturas[0],
                            'codigoDescripcion'         =>      $confirmacionRecibida['codigoDescripcion'],
                            'codigoEstado'              =>      $confirmacionRecibida['codigoEstado'],
                            'codigoRecepcion'           =>      $confirmacionRecibida['codigoRecepcion'],
                            'codigo'                    =>      null,
                            'descripcion'               =>      isset($confirmacionRecibida['mensajesList']) ? json_encode($confirmacionRecibida['mensajesList']) : null,
                            'attempts'                  =>      1,
                            'timeout'                   =>      false,
                            'sended'                    =>      true,
                            'status'                    =>      'A',
                            'created_at'                =>      date("Y-m-d H:i:s")
                        ]
                    );
                } elseif ($cuantasFacturasSeEnviaron > 1) {
                    // Recorremos todas las facturas encontradas
                    foreach ($lasFacturas as $factura) {
                        // Insertamos la factura en el status
                        SivirSellInvoiceStatus::create(
                            [
                                'relative'                  =>      Str::uuid()->toString(),
                                'users_sid'                 =>      $this->getusersid(),
                                'global_branch_office_id'   =>      $this->getbranchoffice(),
                                'invoice_id'                =>      $factura,
                                'codigoDescripcion'         =>      $confirmacionRecibida['codigoDescripcion'],
                                'codigoEstado'              =>      $confirmacionRecibida['codigoEstado'],
                                'codigoRecepcion'           =>      $confirmacionRecibida['codigoRecepcion'],
                                'codigo'                    =>      null,
                                'descripcion'               =>      isset($confirmacionRecibida['mensajesList']) ? json_encode($confirmacionRecibida['mensajesList']) : null,
                                'attempts'                  =>      1,
                                'timeout'                   =>      false,
                                'sended'                    =>      true,
                                'status'                    =>      'A',
                                'created_at'                =>      date("Y-m-d H:i:s")
                            ]
                        );
                    }
                } else {
                    return response()->json(
                        [
                            'status'    =>  'fail'
                        ],
                        409
                    );
                }
                // Verificamos si la notificación 'validated_invoice' está activa
                $notificationsController = new SivirNotificationsController();
                // Verificamos
                $isNotificationEnabled = $notificationsController->checkFlagActive(
                    $this->getbranchoffice(),
                    'validated_invoice'
                );

                // Si la notificacion esta habilitada
                if ($isNotificationEnabled) {
                    // La factura
                    $invoiceId = $lasFacturas[0];
                    // Obtenemos informacion de la empresa y sucursal
                    $branches = LicenseServer::where('status', 'A')->where('license', $this->getbranchoffice())->with(['branchessivir'])->first();
                    // Asignamos las variables
                    $enterprise = $branches['branchessivir']['enterprise'];
                    $branch = $branches['branchessivir']['branch_office'];
                    // Ante titulo
                    $prevTitle = "Empresa: {$enterprise}, Sucursal: {$branch} \n";
                    // Creamos el título y mensaje
                    $titulo = $prevTitle . "Se ha enviado y validado la factura ({$invoiceId}).";
                    $mensaje = "La factura número ({$invoiceId}) emitida inicialmente fuera de línea, fué enviada y recibida por impuestos nacionales correctamente.";
                    // Enviamos la notificación usando Job asincrónico
                    SendRemoteNotificationJob::dispatch(
                        $this->getbranchoffice(),
                        $this->getusersid(),
                        $titulo,
                        $mensaje
                    );
                }
                // Retornamos la informacion
                return response()->json(
                    [
                        'status'    =>  'success',
                        'message'   =>  (array)$confirmationMassMailing
                    ],
                    200
                );
            } else {
                return response()->json(
                    [
                        'status'    =>  'fail'
                    ],
                    409
                );
            }
        } else {
            // Retornamos la informacion
            return response()->json(
                [
                    'status'    =>      'success',
                ],
                200
            );
        }
    }

    /**
     * @param $codigoAmbiente
     * @param $codigoDocumentoSector
     * @param $codigoEmision
     * @param $codigoModalidad
     * @param $codigoPuntoVenta
     * @param $codigoSistema
     * @param $codigoSucursal
     * @param $cufd
     * @param $cuis
     * @param $nit
     * @param $tipoFacturaDocumento
     * @param $codigoRecepcion
     * @param $token
     * @param $url
     * @return \Illuminate\Http\Client\Response
     * @throws \Exception
     */
    private function checkmassmailing($codigoAmbiente, $codigoDocumentoSector, $codigoEmision, $codigoModalidad, $codigoPuntoVenta, $codigoSistema, $codigoSucursal, $cufd, $cuis, $nit, $tipoFacturaDocumento, $codigoRecepcion, $token, $url)
    {
        // Armamos los parámetros en un array estructurado
        $request_params = [
            "SolicitudServicioValidacionRecepcionPaquete" => [
                "codigoAmbiente"            => $codigoAmbiente,
                "codigoDocumentoSector"     => $codigoDocumentoSector,
                "codigoEmision"             => $codigoEmision,
                "codigoModalidad"           => $codigoModalidad,
                "codigoPuntoVenta"          => $codigoPuntoVenta,
                "codigoSistema"             => $codigoSistema,
                "codigoSucursal"            => $codigoSucursal,
                "cufd"                      => $cufd,
                "cuis"                      => $cuis,
                "nit"                       => $nit,
                "tipoFacturaDocumento"      => $tipoFacturaDocumento,
                "codigoRecepcion"           => $codigoRecepcion
            ]
        ];

        // Llamamos a callSoap con los parámetros estructurados
        return $this->callSoap($url, "validacionRecepcionPaqueteFactura", $request_params, $token);
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallofflinesellbyseason()
    {
        // Invocamos la factura
        $sellInvoice = new SivirSellInvoice();
        $invoiceStatus = new SivirSellInvoiceStatus();
        // Buscamos la informacion
        $today = date("Y-m-d");
        // Verificamos si la fecha corresponde a antes o despues del 9 del mes
        if ($today <= date("Y-m") . "-09") {
            // En este caso obtenemos todas las facturas incluyendo el mes pasado
            $since = Carbon::now()->subMonth()->startOfMonth()->toDateString();
            $until = $today;
        } else {
            // En este caso unicamente obtenemos las facturas de este mes
            $since = Carbon::now()->startOfMonth()->toDateString();
            $until = $today;
        }
        // Obtenemos el reporte
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'F')
            ->whereRaw('date_movement between ? and ?', [$since, $until])
            //->where('date_movement', $today)
            ->whereIn('id', function ($q) use ($sellInvoice, $invoiceStatus) {
                $q->select('sell_id')->from($sellInvoice->getTableName())
                    ->where('tipo_emision', 2)->where('status', 'A')->where('estado', 'V')
                    ->whereNotIn('id', function ($q) use ($invoiceStatus) {
                        $q->select('invoice_id')->from($invoiceStatus->getTableName())
                            ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice());
                    });
            })
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'firstinvoicestatus',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Significant events
        $events = CatalogsSivir::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('catalog_code', 'SIGNIFICATIVEEVENT')->get();
        // Retornamos la informacion
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'since'     =>      $since,
                'until'     =>      $until,
                'reasons'   =>      $events,
                'length'    =>      count($response)
            ],
            200
        );
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallofflinesellbytoday()
    {
        // Invocamos la factura
        $sellInvoice = new SivirSellInvoice();
        $invoiceStatus = new SivirSellInvoiceStatus();
        // Buscamos la informacion
        $today = date("Y-m-d");
        // Obtenemos el reporte
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'F')
            ->where('date_movement', $today)
            ->whereIn('id', function ($q) use ($sellInvoice, $invoiceStatus) {
                $q->select('sell_id')->from($sellInvoice->getTableName())
                    ->where('tipo_emision', 2)->where('status', 'A')->where('estado', 'V')
                    ->whereNotIn('id', function ($q) use ($invoiceStatus) {
                        $q->select('invoice_id')->from($invoiceStatus->getTableName())
                            ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice());
                    });
            })
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'firstinvoicestatus',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Retornamos la informacion
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'date'      =>      $today,
                'length'    =>      count($response)
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallofflinesellbydate(Request $request)
    {
        // Invocamos la factura
        $sellInvoice = new SivirSellInvoice();
        $invoiceStatus = new SivirSellInvoiceStatus();
        // Buscamos la informacion
        $today = date("Y-m-d");
        // Verificamos la fecha de recepcion
        if (isset($request->date)) {
            $today = Carbon::parse($request->date)->format("Y-m-d");
        }
        // Obtenemos el reporte
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'F')
            ->where('date_movement', $today)
            ->whereIn('id', function ($q) use ($sellInvoice, $invoiceStatus) {
                $q->select('sell_id')->from($sellInvoice->getTableName())
                    ->where('tipo_emision', 2)->where('status', 'A')->where('estado', 'V')
                    ->whereNotIn('id', function ($q) use ($invoiceStatus) {
                        $q->select('invoice_id')->from($invoiceStatus->getTableName())
                            ->where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice());
                    });
            })
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'firstinvoicestatus',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Retornamos la informacion
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'date'      =>      $today,
                'length'    =>      count($response)
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getthesellsendedbycashier(Request $request)
    {
        // The sell
        $response = SivirSell::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('relative', $request->relative)
            ->where('sended', 'C')
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'sold' => function ($q) {
                        $q->with(
                            [
                                'product' => function ($q) {
                                    $q->with(
                                        [
                                            'brand',
                                            'stock' => function ($q) {
                                                $q->with(['measurement']);
                                            }
                                        ]
                                    );
                                }
                            ]
                        );
                    },
                    'aditionaldiscount',
                ]
            )
            ->orderBy('created_at', 'DESC')->get()->first();
        // Ahora devolvemos el valor
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getallsellssendedtothiscash(Request $request)
    {
        // The sell
        $response = SivirSell::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('sellpoint_id', $request->sellpoint)
            ->where('sended', 'C')
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'sold' => function ($q) {
                        $q->with(
                            [
                                'product' => function ($q) {
                                    $q->with(
                                        [
                                            'brand',
                                            'stock' => function ($q) {
                                                $q->with(['measurement']);
                                            }
                                        ]
                                    );
                                }
                            ]
                        );
                    },
                    'aditionaldiscount',
                ]
            )
            ->orderBy('created_at', 'DESC')->paginate($request->pagination);
        // Inforacion de la configuracion
        // Obtenemos los datos de configuracion
        $configuration = $this->getcachedfirstonesetting();
        // Me
        $me = $this->getusersid();
        // Ahora devolvemos el valor
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'config'    =>      $configuration,
                'me'        =>      $me
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getthesellnotfinishedbyrelative(Request $request)
    {
        // The sell
        $response = SivirSell::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('relative', $request->relative)
            ->where('sended', 'C')
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'sold' => function ($q) {
                        $q->with(
                            [
                                'product' => function ($q) {
                                    $q->with(
                                        [
                                            'brand',
                                            'stock' => function ($q) {
                                                $q->with(['measurement']);
                                            }
                                        ]
                                    );
                                }
                            ]
                        );
                    },
                    'aditionaldiscount',
                ]
            )
            ->orderBy('created_at', 'DESC')->get()->first();
        // Inforacion de la configuracion
        // Obtenemos los datos de configuracion
        $configuration = Settings::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())->get()->first();
        // Ahora devolvemos el valor
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'config'    =>      $configuration
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getsellbyidnoinvoice(Request $request)
    {
        // The sell
        $response = SivirSell::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('relative', $request->relative)
            ->where('sended', 'C')
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'sellpaymentway',
                    'aditionaldiscount',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get()->first();
        // Ahora devolvemos el valor
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function viewform(Request $request)
    {
        // Verificamos la licencia
        $license = $this->getbranchoffice();
        // Verificamos el formulario
        $formulario = $request->form;
        // Nombre del formulario
        $nombreFormulario = 'formulario00' . $formulario . '.pdf';
        // Informacion de la facturacion
        $bolivianinvoice = $this->getcachedfirstbolivianinvoice();
        // Datos de la empresa
        $enterprise = $this->getcachedenterprise();
        // El numero de la venta
        $sellid     = $request->id;
        // Informacion de la factura
        $invoiceData = SivirSellInvoice::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sell_id', $sellid)->get()->first();
        // Obtenemos la sucursal
        $branch = $invoiceData->codigo_sucursal;
        // Verificamos si el archivo existe
        if (file_exists(getcwd() . '/storage/attachments/notas/' . $license . '/' . $branch . '/' . $sellid . '/' . $nombreFormulario)) {
            $finalFileName = 'notas/' . $license . '/' . $branch . '/' . $sellid . '/' . $nombreFormulario;
        } else {
            $showMilitaryData = false;
            // Verificamos el ENV
            if (config('app.show_military_data') && config('app.show_military_data') == true) {
                $showMilitaryData = true;
            }
            // Obtenemos la informacion de la venta
            $theCompleteSell = SivirSell::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('id', $sellid)
                ->with(
                    [
                        'branch',
                        'sellpoint',
                        'currency',
                        'products' => function ($q) {
                            $q->with(
                                [
                                    'product' => function ($q) {
                                        $q->with(
                                            [
                                                'stock' => function ($q) {
                                                    $q->with(['measurement']);
                                                },
                                                'homologated'
                                            ]
                                        );
                                    }
                                ]
                            );
                        },
                        'sellpaymentway',
                        'aditionaldiscount',
                        'invoice'
                    ]
                )->when($showMilitaryData, function ($query) {
                    $query->with(
                        [
                            'military' => function ($q) {
                                $q->with(
                                    [
                                        'fuerza',
                                        'departamentoactual',
                                    ]
                                );
                            }
                        ]
                    );
                })
                ->orderBy('created_at', 'DESC')->get()->first();
            // Settings
            $settings = $this->getcachedfirstonesetting();
            // Verificamos el numero
            if ($formulario == 7) {
                // Generamos el archivo
                $this->makeform007($sellid, $enterprise, $theCompleteSell, $settings, $bolivianinvoice, $invoiceData->id);
            }
            // Verificamos el numero
            if ($formulario == 5) {
                // Generamos el archivo
                $this->makeform005($sellid, $enterprise, $theCompleteSell, $settings, $bolivianinvoice, $invoiceData->id);
            }
            // Verificamos el numero
            if ($formulario == 4) {
                // Generamos el archivo
                $this->makeform004($sellid, $enterprise, $theCompleteSell, $settings, $bolivianinvoice);
            }
            // Cuando se ha terminado
            $finalFileName = 'notas/' . $license . '/' . $branch . '/' . $sellid . '/' . $nombreFormulario;
        }
        // Ahora devolvemos el valor
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $finalFileName
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function viewnotefile(Request $request)
    {
        // Verificamos la licencia
        $license = $this->getbranchoffice();
        // Ahora el archivo final
        $finalFileName = '';
        // Informacion de la facturacion
        $bolivianinvoice = $this->getcachedfirstbolivianinvoice();
        // Datos de la empresa
        $enterprise = $this->getcachedenterprise();
        // El numero de la venta
        $sellid     = $request->id;
        // Informacion de la factura
        $invoiceData = SivirSellInvoice::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sell_id', $sellid)->get()->first();
        // Obtenemos la sucursal
        $branch = $invoiceData->codigo_sucursal;
        // Verificamos si el archivo existe
        if (file_exists(getcwd() . '/storage/attachments/notas/' . $license . '/' . $branch . '/' . $sellid . '/notaDeAlmacenCompraVenta.pdf')) {
            $finalFileName = 'notas/' . $license . '/' . $branch . '/' . $sellid . '/notaDeAlmacenCompraVenta.pdf';
        } else {
            $showMilitaryData = false;
            // Verificamos el ENV
            if (config('app.show_military_data') && config('app.show_military_data') == true) {
                $showMilitaryData = true;
            }
            // Obtenemos la informacion de la venta
            $theCompleteSell = SivirSell::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('id', $sellid)
                ->with(
                    [
                        'branch',
                        'sellpoint',
                        'currency',
                        'products' => function ($q) {
                            $q->with(
                                [
                                    'product' => function ($q) {
                                        $q->with(
                                            [
                                                'stock' => function ($q) {
                                                    $q->with(['measurement']);
                                                },
                                                'homologated'
                                            ]
                                        );
                                    }
                                ]
                            );
                        },
                        'sellpaymentway',
                        'aditionaldiscount',
                        'invoice'
                    ]
                )->when($showMilitaryData, function ($query) {
                    $query->with(
                        [
                            'military' => function ($q) {
                                $q->with(
                                    [
                                        'fuerza',
                                        'departamentoactual',
                                    ]
                                );
                            }
                        ]
                    );
                })
                ->orderBy('created_at', 'DESC')->get()->first();
            // Settings
            $settings = $this->getcachedfirstonesetting();
            // Generamos el archivo
            $this->generateWarehouseNote($sellid, $enterprise, $theCompleteSell, $settings, $bolivianinvoice, $invoiceData->id);
            // Cuando se ha terminado
            $finalFileName = 'notas/' . $license . '/' . $branch . '/' . $sellid . '/notaDeAlmacenCompraVenta.pdf';
        }
        // Ahora devolvemos el valor
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $finalFileName
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function viewinvoicefile(Request $request)
    {
        // Ahora el archivo final
        $finalFileName = '';
        // Informacion de la facturacion
        $bolivianinvoice = $this->getcachedfirstbolivianinvoice();
        // La modalidad
        $codigoModalidad = $bolivianinvoice['codigo_modalidad'];
        // El numero de la venta
        $sellid     = $request->id;
        // el formato
        $format     = isset($request->pageformat) ? $request->pageformat : 'A4';
        // Informacion de la factura
        $invoiceData = SivirSellInvoice::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sell_id', $sellid)->get()->first();
        // Obtenemos la sucursal
        $branch = $invoiceData->codigo_sucursal;
        // Ahora obtenemos si es zofra o no
        $zofra  = $invoiceData->zofra;
        // El numero de la factura
        $invoiceId = $invoiceData->id;
        // El tipo de la factura
        $tipo_factura_id = $invoiceData->tipo_factura_id;
        // Los archivos
        $completePathA4 = $this->getpublicfolderinvoice('FOLDER', 'A4', $branch, $invoiceId, $codigoModalidad, $tipo_factura_id);
        $completePathA7 = $this->getpublicfolderinvoice('FOLDER', 'A7', $branch, $invoiceId, $codigoModalidad, $tipo_factura_id);
        // Los paths cortos
        $pathA4 = $this->getpublicfolderinvoiceshort('A4', $branch, $invoiceId, $codigoModalidad, $tipo_factura_id);
        $pathA7 = $this->getpublicfolderinvoiceshort('A7', $branch, $invoiceId, $codigoModalidad, $tipo_factura_id);
        // Ahora el archivo
        $fileNameA4 = $this->getpublicfolderinvoice('FILE', 'A4', $branch, $invoiceId, $codigoModalidad, $tipo_factura_id);
        $fileNameA7 = $this->getpublicfolderinvoice('FILE', 'A7', $branch, $invoiceId, $codigoModalidad, $tipo_factura_id);
        // Ahora verificamos si el archivo existe o no
        if ($format == "A4") {
            if (file_exists($completePathA4 . $fileNameA4)) {
                $finalFileName = $pathA4 . $fileNameA4;
            } else {
                // Hacemos el PDF
                $this->makepdf($invoiceId, false, 'A4');
                // Ahora lo retornamos
                $finalFileName = $pathA4 . $fileNameA4;
            }
        }
        if ($format == "A7") {
            if (file_exists($completePathA7 . $fileNameA7)) {
                $finalFileName = $pathA7 . $fileNameA7;
            } else {
                @mkdir($completePathA7, 0755, true);
                // Hacemos el PDF
                $this->makepdf($invoiceId, false, "A7");
                // Ahora lo retornamos
                $finalFileName = $pathA7 . $fileNameA7;
            }
        }
        // Ahora devolvemos el valor
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $finalFileName
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getsellbyid(Request $request)
    {
        // Mostramos los datos militares
        $showMilitaryData = false;
        // Verificamos el ENV
        if (config('app.show_military_data') && config('app.show_military_data') == true) {
            $showMilitaryData = true;
        }
        // Obtenemos la venta
        $sellId = $request->id;
        // The invoice
        $sellInvoice = SivirSellInvoice::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sell_id', $sellId)->get()->first();
        // Obtenemos la fecha hasta
        $timeuntil = Carbon::parse($sellInvoice->created_at)->addMinutes(5)->format("Y-m-d H:i:s");
        // The sell
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $sellId)
            ->where('sended', 'F')
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer' => function ($q) {
                        $q->with(['documenttype']);
                    },
                    'currency',
                    'attachments',
                    'products' => function ($q) {
                        $q->with(
                            [
                                'product' => function ($q) {
                                    $q->with(
                                        [
                                            'homologated',
                                            'stock' => function ($q) {
                                                $q->with(['measurement']);
                                            },
                                        ]
                                    );
                                }
                            ]
                        );
                    },
                    'sellpaymentway' => function ($q) {
                        $q->with(
                            [
                                'payment',
                                'currency'
                            ]
                        );
                    },
                    'aditionaldiscount',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'firstinvoicestatus',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    },
                    'credit'
                ]
            )->when($showMilitaryData, function ($query) {
                $query->with(
                    [
                        'military' => function ($q) {
                            $q->with(
                                [
                                    'fuerza',
                                    'departamentoactual',
                                ]
                            );
                        }
                    ]
                );
            })
            ->orderBy('created_at', 'DESC')->get()->first();
        // De la fecha del movimiento obtendremos unicamente el mes
        $anoDelMesSiguiente = Carbon::parse($response->date_movement)->addMonth()->format("Y");
        $mesSiguiente = Carbon::parse($response->date_movement)->addMonth()->format("m");
        // los 18 meses de la nota de credito debito
        $meses18Siguentes = Carbon::parse($response->date_movement)->addMonths(18)->format("m");
        $ano18Siguentes = Carbon::parse($response->date_movement)->addMonths(18)->format("Y");
        // Armamos la fecha 09 del mes siguiente
        $fecha09DelMesSiguiente = Carbon::parse($anoDelMesSiguiente . "-" . $mesSiguiente . "-09")->format("Y-m-d");
        // Fecha limite de los 18 meses posteriores
        $fecha18mesesPosterior = Carbon::parse($ano18Siguentes . "-" . $mesSiguiente . "-" . date("d"))->format("Y-m-d");
        // Ahora la fecha actual
        $fechaActual = Carbon::parse($response->date_movement)->format("Y-m-d");
        // Ahora incrementaremos el mes
        $daysUntil = Carbon::parse($fechaActual)->diffInDays($fecha09DelMesSiguiente);
        // La fecha exacta 18 meses despues
        $days18MonthsUntil = Carbon::parse($fechaActual)->diffInDays($fecha18mesesPosterior);
        // Ahora devolvemos el valor
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'mes09'     =>      $fecha09DelMesSiguiente,
                'dias'      =>      $daysUntil,
                'm18'       =>      $days18MonthsUntil,
                'm18date'   =>      $fecha18mesesPosterior,
                'timeuntil' =>      $timeuntil,
                'smd'       =>      $showMilitaryData
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getsellbyidfordc(Request $request)
    {
        $sellId = $request->id;
        // The invoice
        $sellInvoice = SivirSellInvoice::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sell_id', $sellId)->get()->first();
        // Obtenemos la fecha hasta
        $timeuntil = Carbon::parse($sellInvoice->created_at)->addMinutes(5)->format("Y-m-d H:i:s");
        // The sell
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $sellId)
            ->where('sended', 'F')
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer' => function ($q) {
                        $q->with(['documenttype']);
                    },
                    'currency',
                    'attachments',
                    'products' => function ($q) {
                        $q->with(
                            [
                                'product' => function ($q) {
                                    $q->with(
                                        [
                                            'user',
                                            'branch',
                                            'category',
                                            'subcategory',
                                            'stock' => function ($q) {
                                                $q->with(['measurement']);
                                            },
                                            'price' => function ($q) {
                                                $q->with(['currency']);
                                            },
                                            'assistants' => function ($q) {
                                                $q->with(
                                                    [
                                                        'assistant'
                                                    ]
                                                );
                                            },
                                            'brand',
                                            'homologated',
                                            'getlot'
                                        ]
                                    );
                                }
                            ]
                        );
                    },
                    'sellpaymentway' => function ($q) {
                        $q->with(
                            [
                                'payment',
                                'currency'
                            ]
                        );
                    },
                    'aditionaldiscount',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'firstinvoicestatus',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    },
                    'credit'
                ]
            )
            ->orderBy('created_at', 'DESC')->get()->first();
        // De la fecha del movimiento obtendremos unicamente el mes
        $anoDelMesSiguiente = Carbon::parse($response->date_movement)->addMonth()->format("Y");
        $mesSiguiente = Carbon::parse($response->date_movement)->addMonth()->format("m");
        // Armamos la fecha 09 del mes siguiente
        $fecha09DelMesSiguiente = Carbon::parse($anoDelMesSiguiente . "-" . $mesSiguiente . "-09")->format("Y-m-d");
        // Ahora la fecha actual
        $fechaActual = Carbon::parse($response->date_movement)->format("Y-m-d");
        // Ahora incrementaremos el mes
        $daysUntil = Carbon::parse($fechaActual)->diffInDays($fecha09DelMesSiguiente);
        // Ahora devolvemos el valor
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response,
                'mes09'     =>      $fecha09DelMesSiguiente,
                'dias'      =>      $daysUntil,
                'timeuntil' =>      $timeuntil
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getsellbycustomerid(Request $request)
    {
        $response = SivirSell::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('customer_id', $request->customer_id)
            ->with(['user', 'branch', 'sellpoint', 'customer', 'currency', 'invoice'])
            ->orderBy('created_at', 'DESC')->get()->first();
        // Retornamos
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function registersell(Request $request)
    {
        $sell = new SivirSell();
        $request->merge(
            [
                'relative'                  =>  Str::uuid()->toString(),
                'id'                        =>  $sell->next(),
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice()
            ]
        );
        $response = SivirSell::create($request->all());
        // Retornamos
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function updatesell(Request $request)
    {
        $request->merge(
            [
                'users_sid'                 =>  $this->getusersid(),
                'updated_at'                =>  date("Y-m-d H:i:s"),
                'global_branch_office_id'   =>  $this->getbranchoffice()
            ]
        );
        $response = SivirSell::where('relative', $request->relative)->update($request->all());
        // Retornamos
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function logicaldeletesell(Request $request)
    {
        $response = SivirSell::where('id', $request->id)
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->update(array('status' => 'X'));
        // Retornamos
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function deletesell(Request $request)
    {
        $response = SivirSell::where('id', $request->id)
            ->where('global_branch_office_id', $this->getbranchoffice())->delete();
        // Retornamos
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function searchdatasell(Request $request)
    {
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'F')
            ->where(function ($query) use ($request) {
                $query->orWhere('id', 'LIKE', '%' . $request->search . '%')
                    ->orWhere(function ($query) use ($request) {
                        $query->orWhere(function ($query) use ($request) {
                            $query->orWhere('customer_full_name', 'LIKE', '%' . $request->search . '%');
                        })
                            ->orWhere(function ($query) use ($request) {
                                $query->orWhere('customer_nit', 'LIKE', '%' . $request->search . '%');
                            })
                            ->orWhere(function ($query) use ($request) {
                                $query->orWhere('customer_email', 'LIKE', '%' . $request->search . '%');
                            });
                    });
            })
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Retornamos
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function searchdatasellbydate(Request $request)
    {
        // Verificamos si puede ver de todos o propio
        $own = isset($request->own) ? $request->own : false;
        // Las notas de venta
        $sellnote = new SivirSellNote();
        // Verificamos la solicitud del usuario
        $secure = isset($request->secure) ? $request->secure : 2;
        // Ahora obtenemos el reporte
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'F')
            ->where('date_movement', $request->search)
            ->when($own, function ($q) {
                $q->where('users_sid', $this->getusersid());
            })
            ->when($secure == 1, function ($q) use ($sellnote) {
                $q->whereNotIn('id', function ($q) use ($sellnote) {
                    $q->select('sell_id')->from($sellnote->getTableName())->where('estado', '<>', 'C')
                        ->where('global_branch_office_id', $this->getbranchoffice());
                });
            })
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch.branchessivir',
                    'sellpoint',
                    'customer',
                    'currency',
                    'note',
                    'products',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'firstinvoicestatus',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Retornamos la informacion
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function searchproformabydate(Request $request)
    {
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'P')
            ->where('date_movement', $request->search)
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency'
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Retornamos
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function searchdataofflinesellbydate(Request $request)
    {
        // Invocamos la factura
        $sellInvoice = new SivirSellInvoice();
        // Buscamos la informacion
        $response = SivirSell::where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'F')
            ->where('date_movement', $request->search)
            ->whereIn('id', function ($q) use ($sellInvoice) {
                $q->select('sell_id')->from($sellInvoice->getTableName())
                    ->where('tipo_emision', 2)->where('status', 'A')->where('estado', 'V');
            })
            ->with(
                [
                    'user' => function ($q) {
                        $q->with(['person']);
                    },
                    'branch',
                    'sellpoint',
                    'customer',
                    'currency',
                    'invoice' => function ($q) {
                        $q->with(
                            [
                                'firstinvoicestatus',
                                'user',
                                'branch',
                                'tipofactura',
                                'invoicecancelled',
                                'sellpoint',
                                'invoicestatus' => function ($q) {
                                    $q->orderBy('created_at', 'DESC')->first();
                                }
                            ]
                        );
                    }
                ]
            )
            ->orderBy('created_at', 'DESC')->get();
        // Retornamos
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function verifycuf()
    {
        $cuf = new GenerateCuf();
        $response = $cuf->createCuf(52, 51, 1, '51E69BFF8746D74', 0);
        // Retornamos
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $response
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function sendreportbyemail(Request $request)
    {
        // Recibimos la informacion
        $title = $request->title;
        $body = $request->body;
        $to = $request->emails;
        $tosend = $request->url;
        // Ahora enviamos el correo para reserva
        $data = Http::post(
            $tosend,
            [
                'title'         =>  $title,
                'body'          =>  '<h3>' . $title . '<h3><br>' . $body,
                'to'            =>  $to
            ]
        );
        // Ahora devolvemos el dato
        return response()->json(
            [
                'status'    =>  'success',
                'data'      =>  $data
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function sendinvoicebyemail(Request $request)
    {
        $format = $request->pageformat;
        // Recibimos el id de la factura
        $invoiceId = $request->id;
        // la url de envio
        $toSend = $request->url;
        // Obtenemos informacion de la factura
        $invoiceData = SivirSellInvoice::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $invoiceId)
            ->with(
                [
                    'sell'
                ]
            )
            ->get()->first();
        // Ahora tenemos la informacion de la venta y de la factura
        $enterpriseData     = $this->getcachedenterprise();
        // Ahora obtenemos el comportamiento del sistema
        $systemBehavior     = $this->getcachedfirstsystembehavior();
        // Recabamos los datos de la factura
        $bolivianInvoice    = $this->getcachedfirstbolivianinvoice();
        // Hacemos la URL
        $url = $systemBehavior->qr_url . 'nit=' . $bolivianInvoice->nit . '&cuf=' . $invoiceData['cuf'] . '&numero=' . $invoiceId . '&t=' . $systemBehavior->codigo_ambiente;
        // Verificamos el tipo de pagina que requiere
        // Ahora que tenemos los datos enviamos la factura por correo electronico
        $data = $this->sendEmailToServer(
            $invoiceData['relative'],
            $invoiceData['created_at'],
            $invoiceData['sell']['customer_email'],
            $invoiceId,
            $invoiceData['codigo_sucursal'],
            $invoiceData['zofra'],
            $invoiceData['cuf'],
            $enterpriseData->fullname,
            $url,
            $format,
            $toSend,
            $invoiceData['tipo_factura_id']
        );
        // Ahora devolvemos un positivo
        return response()->json(
            [
                'status'    =>  'success',
                'data'      =>  $data
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function sendinvoicebywhatsapp(Request $request)
    {
        $format = $request->pageformat;
        // Recibimos el id de la factura
        $invoiceId = $request->id;
        // la url de envio
        $toSend = $request->url;
        // Obtenemos informacion de la factura
        $invoiceData = SivirSellInvoice::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $invoiceId)
            ->with(
                [
                    'sell' => function ($q) {
                        $q->with(['customer']);
                    }
                ]
            )
            ->get()->first();
        // Ahora tenemos la informacion de la venta y de la factura
        $enterpriseData     = $this->getcachedenterprise();
        // Verificamos el tipo de pagina que requiere
        // Ahora que tenemos los datos enviamos la factura por correo electronico
        $data = $this->sendWhatsappToServer(
            $invoiceData['relative'],
            $invoiceData['created_at'],
            $invoiceData['sell']['customer']['phones'],
            $invoiceId,
            $invoiceData['codigo_sucursal'],
            $invoiceData['zofra'],
            $invoiceData['cuf'],
            $enterpriseData->fullname,
            $format,
            $toSend,
            $invoiceData['tipo_factura_id']
        );
        // Ahora devolvemos un positivo
        return response()->json(
            [
                'status'    =>  'success',
                'data'      =>  $data
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function sendtocashier(Request $request)
    {
        // El numero de la venta siguiente
        $nextSell           = new SivirSell();
        // Venta por Excepcion
        $porExcepcion   = $request->codigoExcepcion;
        // Adicionamos la información basica para cualquier registro
        $request->merge(
            [
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice()
            ]
        );
        // Primero vemos la informacion del cliente (CLIENTES)
        // Si el relative del customer es nulo entonces no existe el cliente
        // si el cliente no existe debemos registrarlo
        if ($request->customerrelative == null) {
            // Verificamos si este caso especial ya se ha registrado
            if (PortfolioCustomers::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                ->where('document_number', $request->document_number)->where('first_name', $request->fullname)->exists()
            ) {
                // Obtenemos la informacion ya registrada del cliente
                $portfolioCustomers = PortfolioCustomers::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('document_number', $request->document_number)->where('first_name', $request->fullname)->get()->first();
                // Adicionamos a las variables el relative del cliente
                $request->merge(['customerrelative' => $portfolioCustomers->relative]);
            } else {
                // Verificamos el codigo del cliente
                if ($request->document_number == "99002") {
                    $customer_type_id = 3;
                } elseif ($request->document_number == "99003") {
                    $customer_type_id = 4;
                } else {
                    $customer_type_id = 1;
                }
                // Relative solo para el cliente
                $customer_relative = Str::uuid()->toString();
                // En caso de no existir registramos el nuevo cliente
                // que para este unico caso es Sin nombre y nit 0
                PortfolioCustomers::create(array(
                    'relative'                  =>      $customer_relative,
                    'users_sid'                 =>      $request->users_sid,
                    'global_branch_office_id'   =>      $request->global_branch_office_id,
                    'customer_type_id'          =>      $customer_type_id,
                    'code'                      =>      0,
                    'first_name'                =>      $request->fullname,
                    'middle_name'               =>      null,
                    'last_name'                 =>      null,
                    'country_id'                =>      27, // Magic number for Bolivia
                    'document_type'             =>      $request->document_type,
                    'document_number'           =>      $request->document_number,
                    'customer_complemento'      =>      $request->complemento,
                    'email'                     =>      $request->email,
                    'social_media'              =>      null,
                    'phones'                    =>      isset($request->phones) ? $request->phones : null,
                    'address'                   =>      null,
                    'references'                =>      isset($request->references) ? $request->references : null,
                    'photo'                     =>      null,
                    'status'                    =>      'A',
                    'created_at'                =>      date("Y-m-d H:i:s")
                ));
                // Adicionamos a las variables el relative del cliente
                $request->merge(['customerrelative' => $customer_relative]);
            }
        } else {
            // Actualizamos la informacion del cliente
            PortfolioCustomers::where('relative', $request->customerrelative)
                ->update(
                    [
                        'phones'    =>  isset($request->phones) ? $request->phones : null,
                        'email'     =>  isset($request->email) ? $request->email : null,
                        'references' =>  isset($request->references) ? $request->references : null
                    ]
                );
        }
        // CANTIDADES
        // Verificamos si los productos tienen cantidades disponibles
        $checkStock = $this->checkStockAvailable($request->products);
        // Si el retorno es falso, la operacion termina
        if (!$checkStock) {
            // Si la cantidad que hay en stock es inferior a la necesaria
            // entonces devolvemos un mensaje de cantidad insuficiente
            return response()->json(
                [
                    'status'    =>      'fail',
                    'message'   =>      'Los productos no tienen cantidades suficiente en stock',
                ],
                429
            );
        }
        // La cantidad en stock es superior o igual a la cantidad requerida (VENTA)
        // Como sabemos que el stock no va a fallarnos, entonces iniciamos con la venta
        // Primero actualizamos la informacion del producto en sell sold en caso de que
        // se haya modificado los precios debido al tipo de cambio y la moneda
        $sell_relative = Str::uuid()->toString();
        // Registramos la nueva venta
        $newSell = SivirSell::create(array(
            'relative'                  =>      $sell_relative,
            'id'                        =>      $nextSell->next(),
            'users_sid'                 =>      $request->users_sid,
            'global_branch_office_id'   =>      $request->global_branch_office_id,
            'sellpoint_id'              =>      $request->sellpoint,
            'payment_type'              =>      $request->payment,
            'payment_detail'            =>      $request->payment_detail,
            'customer_id'               =>      $request->customerrelative,
            'document_type'             =>      $request->document_type,
            'customer_full_name'        =>      $request->fullname,
            'customer_nit'              =>      $request->document_number,
            'customer_complemento'      =>      $request->complemento,
            'customer_email'            =>      $request->email,
            'discount_all_products'     =>      number_format($request->totaldiscount, 2, ".", ""),
            'descuentoAdicional'        =>      number_format($request->descuentoAdicional, 2, ".", ""),
            'discount_total'            =>      number_format($request->totaldiscount + $request->descuentoAdicional, 2, ".", ""),
            'total'                     =>      number_format($request->total, 2, ".", ""),
            'currency_id'               =>      $request->currency,
            'exchange_used'             =>      $request->exchange,
            'codigoExcepcion'           =>      $porExcepcion,
            'medical_prescription_detail' => (isset($request->medical_prescription_detail)) ? $request->medical_prescription_detail : null,
            'sended'                    =>      'C',
            'date_movement'             =>      date("Y-m-d"),
            'status'                    =>      'A',
            'created_at'                =>      date("Y-m-d H:i:s")
        ));
        // Obtenemos el ID de la nueva venta
        $sell_id = $newSell->id;
        // Verificamos que cada producto tenga suficiente en su inventario (PRODUCTOS)
        // Para poder realizar una bajada de sus cantidades
        // Recorremos los productos encontrados y obtenemos cada producto
        foreach ($request->products as $data) {
            // Actualizamos la informacion del producto adicionado a la compra
            // Y modificamos el precio de venta, la cantidad, el total y el descuento
            // Adicionalmente quitamos el valor de provisional a nulo para que esto
            // no nos salga en otra venta del mismo usuario
            SivirSellSold::where('provisional', $request->provisional)
                ->where('product_id', $data['product_id'])->where('global_branch_office_id', $this->getbranchoffice())
                ->where('status', 'A')->update(
                    array(
                        'users_sid'     => $this->getusersid(),
                        'sell_id'       => $sell_id,
                        'price'         => number_format($data['price'], 2, ".", ""),
                        'quantity'      => $data['quantity'],
                        'total_price'   => number_format($data['total_price'], 2, ".", ""),
                        'discount'      => number_format($data['discount'], 2, ".", ""),
                        'provisional'   => null
                    )
                );
            // Actualizamos la forma de pago de provisional, y la integramos con la
            // nueva venta generada
            SivirSellPaymentWay::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('provisional', $request->provisional)
                ->update(
                    [
                        'users_sid'     =>      $this->getusersid(),
                        'sell_id'       =>      $sell_id,
                        'provisional'   =>      null,
                        'updated_at'    =>      date("Y-m-d H:i:s")
                    ]
                );
            // Ahora actualizamos el descuento adicional
            if (SivirSellAditionalDiscount::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('provisional', $request->provisional)
                ->exists()
            ) {
                // Actualizamos el descuento adicional
                SivirSellAditionalDiscount::where('status', 'A')
                    ->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('provisional', $request->provisional)
                    ->update(
                        [
                            'users_sid'     =>      $this->getusersid(),
                            'sell_id'       =>      $sell_id,
                            'provisional'   =>      null,
                            'updated_at'    =>      date("Y-m-d H:i:s")
                        ]
                    );
            }
        }
        // Tenemos que restar los saldos de las GIFT-CARD y los CUPONES
        $this->updategiftcardandcoupons($sell_id);
        // Finalizado el procedimiento debemos devolver la informacion obtenida
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $request->all(),
                'sell'      =>      $sell_relative
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function finishthesell(Request $request)
    {
        // Inicializamos variables en nulo
        $nombreEstudiante = null;
        $periodoFacturado = null;
        // El numero de la factura siguiente
        $nextSellInvoice    = new SivirSellInvoice();
        // Verificamos si es una factura CAFC
        $cafc = null;
        // Si el valor es enviado
        if (isset($request->cafc)) {
            $cafc = $request->cafc;
            // The invoice date time and milliseconds
            $milliseconds = rand(100, 999);
            $datetimev = Carbon::parse($request->datetimev)->format("Y-m-d H:i:s");
        } else {
            // The invoice date time and milliseconds
            $milliseconds = rand(100, 999);
            $datetimev = date("Y-m-d H:i:s");
        }
        // Venta por Excepcion
        $porExcepcion   = $request->codigoExcepcion;
        // Adicionamos la información basica para cualquier registro
        $request->merge(
            [
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice()
            ]
        );
        // Obtenemos la informacion de la orden de production de optica si existe
        $optical_work_order_id = isset($request->optical_work_order_id) ? $request->optical_work_order_id : null;
        // La venta en uuid
        $sellRelative = $request->relative;
        // Informacion de la venta
        $sellInfo = SivirSell::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
            ->where('relative', $sellRelative)->get()->first();
        // la moneda de la venta
        $currency = $sellInfo->currency_id;
        // Recogemos el ID de la venta
        $sell_id = $sellInfo->id;
        // El punto de venta
        $sellPointID = $sellInfo->sellpoint_id;
        // Guardamos el tipo de emision
        $tipoEmision = $request->tipoEmision;
        // Obtenemos informacion de la facturacion
        $bolivianInvoice    = $this->getbolivianinvoice();
        // Informacion obtenida de la facturacion boliviana
        $codigoModalidad    = $bolivianInvoice['codigo_modalidad'];
        $tipo_factura_id    = $request->tipo_factura_id;
        // Informacion del punto de venta
        $sellPoint = SellPoint::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
            ->where('relative', $sellPointID)->with(['cufd'])->get()->first();
        // El almacen permitido
        $warehouse = $sellPoint->warehouses_allowed;
        // Obtenemos el ultimo CUFD valido segun fecha y hora
        $lastValidCufd = $this->getlastvalidcufdarounddate($datetimev, $sellPointID);
        // Ahora obtenemos el CUFD para esta venta
        $cufd = $lastValidCufd->codigo_cufd;
        // Informacion que hemos obtenido de la misma venta
        $codigoControl = $lastValidCufd->codigo_control;
        // Toda la venta
        $products = SivirSellSold::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
            ->where('sell_id', $sell_id)->get(); //HERE
        // CANTIDADES
        // Verificamos si los productos tienen cantidades disponibles
        $checkStock = $this->checkStockAvailable($products);
        // Si el retorno es falso, la operacion termina
        if (!$checkStock) {
            // Si la cantidad que hay en stock es inferior a la necesaria
            // entonces devolvemos un mensaje de cantidad insuficiente
            return response()->json(
                [
                    'status'    =>      'fail',
                    'message'   =>      'Los productos no tienen cantidades suficiente en stock',
                ],
                429
            );
        }
        // Primero vemos la informacion del cliente (CLIENTES)
        // Si el relative del customer es nulo entonces no existe el cliente
        // si el cliente no existe debemos registrarlo
        if ($request->customerrelative == null) {
            // Verificamos si este caso especial ya se ha registrado
            if (PortfolioCustomers::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                ->where('document_number', $request->document_number)->where('first_name', $request->fullname)->exists()
            ) {
                // Obtenemos la informacion ya registrada del cliente
                $portfolioCustomers = PortfolioCustomers::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('document_number', $request->document_number)->where('first_name', $request->fullname)->get()->first();
                // Adicionamos a las variables el relative del cliente
                $request->merge(['customerrelative' => $portfolioCustomers->relative]);
                // Actualizamos la informacion del cliente
                PortfolioCustomers::where('relative', $portfolioCustomers->relative)
                    ->update(
                        [
                            'phones'    =>  isset($request->phones) ? $request->phones : null,
                            'email'     =>  isset($request->email) ? $request->email : null,
                            'references' =>  isset($request->references) ? $request->references : null
                        ]
                    );
            } else {
                // Verificamos el codigo del cliente
                if ($request->document_number == "99002") {
                    $customer_type_id = 3;
                } elseif ($request->document_number == "99003") {
                    $customer_type_id = 4;
                } else {
                    $customer_type_id = 1;
                }
                // Relative solo para el cliente
                $customer_relative = Str::uuid()->toString();
                // En caso de no existir registramos el nuevo cliente
                // que para este unico caso es Sin nombre y nit 0
                PortfolioCustomers::create(array(
                    'relative'                  =>      $customer_relative,
                    'users_sid'                 =>      $request->users_sid,
                    'global_branch_office_id'   =>      $request->global_branch_office_id,
                    'customer_type_id'          =>      $customer_type_id,
                    'code'                      =>      0,
                    'first_name'                =>      $request->fullname,
                    'middle_name'               =>      null,
                    'last_name'                 =>      null,
                    'country_id'                =>      27, // Magic number for Bolivia
                    'document_type'             =>      $request->document_type,
                    'document_number'           =>      $request->document_number,
                    'customer_complemento'      =>      $request->complemento,
                    'email'                     =>      $request->email,
                    'social_media'              =>      null,
                    'phones'                    =>      isset($request->phones) ? $request->phones : null,
                    'address'                   =>      null,
                    'references'                =>      isset($request->references) ? $request->references : null,
                    'photo'                     =>      null,
                    'status'                    =>      'A',
                    'created_at'                =>      date("Y-m-d H:i:s")
                ));
                // Adicionamos a las variables el relative del cliente
                $request->merge(['customerrelative' => $customer_relative]);
            }
        } else {
            // Actualizamos la informacion del cliente
            PortfolioCustomers::where('relative', $request->customerrelative)
                ->update(
                    [
                        'phones'    =>  isset($request->phones) ? $request->phones : null,
                        'email'     =>  isset($request->email) ? $request->email : null,
                        'references' =>  isset($request->references) ? $request->references : null
                    ]
                );
        }
        // Ahora actualizamos la venta de Caja a Finalizada
        SivirSell::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
            ->where('relative', $sellRelative)->update(
                [
                    'optical_work_order_id' =>  $optical_work_order_id,
                    'payment_type'          =>  $request->payment,
                    'payment_detail'        =>  $request->payment_detail,
                    'customer_id'           =>  $request->customerrelative,
                    'document_type'         =>  $request->document_type,
                    'customer_full_name'    =>  $request->fullname,
                    'customer_nit'          =>  $request->document_number,
                    'customer_complemento'  =>  $request->complemento,
                    'customer_email'        =>  $request->email,
                    'discount_all_products' =>  number_format($request->totaldiscount, 2, ".", ""),
                    'descuentoAdicional'    =>  number_format($request->descuentoAdicional, 2, ".", ""),
                    'discount_total'        =>  number_format($request->totaldiscount + $request->descuentoAdicional, 2, ".", ""),
                    'total'                 =>  number_format($request->total, 2, ".", ""),
                    'currency_id'           =>  $currency,
                    'exchange_used'         =>  $request->exchange,
                    'codigoExcepcion'       =>  $porExcepcion,
                    'sended'                =>  'F',
                    'created_at'            =>  date("Y-m-d H:i:s"),
                    'updated_at'            =>  date("Y-m-d H:i:s")
                ]
            );
        // Obtenemos la informacion de configuracion
        $configuration = $this->getcachedfirstonesetting();
        // Ya actualizamos la venta
        // Verificamos que cada producto tenga suficiente en su inventario (PRODUCTOS)
        // Para poder realizar una bajada de sus cantidades
        // Recorremos los productos encontrados y obtenemos cada producto
        foreach ($products as $data) {
            // Una vez que hemos actualizado la informacion nos ocupamos
            // del movimiento del producto como el kardex, el stock y el historial
            // Realizamos el metodo que tenemos en el POST
            $this->makeTheMethod($data['product_id'], $data['quantity'], $sell_id, $data['price'], $currency, $configuration->inventory_method, $warehouse);
        }
        // Obtenemos la informacion necesaria del sistema para ingresar una factura
        $obtenerCuis = SoapCuis::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('cuis_expiration_datetime', '>', date("Y-m-d H:i:s"))
            ->where('sell_point_id', $sellPointID)
            ->orderBy('created_at', 'DESC')->get()->first();
        // Verificamos el tipo de la factura
        if ($tipo_factura_id == 11 || $tipo_factura_id == 46 || $tipo_factura_id == 2 || $tipo_factura_id == 42) {
            if ($tipo_factura_id == 2 || $tipo_factura_id == 42) {
                $periodoFacturado = isset($request->periodoFacturado) ? $request->periodoFacturado : null;
            }
            if ($tipo_factura_id == 11 || $tipo_factura_id == 46) {
                $nombreEstudiante = isset($request->nombreEstudiante) ? $request->nombreEstudiante : null;
                $periodoFacturado = isset($request->periodoFacturado) ? $request->periodoFacturado : null;
            }
        } else {
            $nombreEstudiante = null;
            $periodoFacturado = null;
        }
        // Telecomunicaciones y telecomunicaciones ZF 22 y 49
        if ($tipo_factura_id == 22 || $tipo_factura_id == 49) {
            $nitConjunto = isset($request->nitConjunto) ? $request->nitConjunto : null;
        } else {
            $nitConjunto = null;
        }
        // Hoteles y hospedaje
        if ($tipo_factura_id == 6 || $tipo_factura_id == 16) {
            $hospedaje = isset($request->hospedaje) ? $request->hospedaje : null;
        } else {
            $hospedaje = null;
        }
        // Hospitales y clinicas
        if ($tipo_factura_id == 17 || $tipo_factura_id == 50) {
            $modalidadServicio = isset($request->modalidadServicio) ? $request->modalidadServicio : null;
        } else {
            $modalidadServicio = null;
        }
        // Buscamos obtener el cuis con los datos obtenidos
        $cuis = $obtenerCuis->cuis;
        // Verificamos los documentos adjuntos
        if (isset($request->attachments)) {
            // Subimos el o los archivos
            $this->uploadandsaveattachments($request->attachments, $sell_id);
        }
        // Tenemos que restar los saldos de las GIFT-CARD y los CUPONES
        $this->updategiftcardandcoupons($sell_id);
        // Condicion de zofra
        $zofraSave = $this->getzofraornot($request->tipo_factura_id);
        // Ahora emitimos la factura para la venta realizada
        $array_invoice = [
            'relative'                  =>      Str::uuid()->toString(),
            'id'                        =>      $nextSellInvoice->next(),
            'users_sid'                 =>      $this->getusersid(),
            'global_branch_office_id'   =>      $this->getbranchoffice(),
            'sell_id'                   =>      $sell_id,
            'sellpoint_id'              =>      $sellPointID,
            'payment_type'              =>      $sellInfo->payment_type,
            'payment_detail'            =>      null,
            'cuis'                      =>      $cuis,
            'cufd'                      =>      $cufd,
            'cafc'                      =>      $cafc,
            'codigo_control'            =>      $codigoControl,
            'cuf'                       =>      null,
            'legend'                    =>      $bolivianInvoice['leyenda'],
            'law'                       =>      $bolivianInvoice['ley']['label'],
            'zofra'                     =>      $zofraSave,
            'nitConjunto'               =>      $nitConjunto,
            'modalidadServicio'         =>      $modalidadServicio,
            'numeroParteRecepcion'      =>      $configuration->numeroParteRecepcion,
            'nombreEstudiante'          =>      null,
            'periodoFacturado'          =>      null,
            'tipo_factura_id'           =>      $bolivianInvoice['tipo_factura_id'],
            'tipo_emision'              =>      $tipoEmision,
            'codigo_sucursal'           =>      $bolivianInvoice['codigo_sucursal'],
            'hospedaje'                 =>      $hospedaje,
            'estado'                    =>      'V',
            'status'                    =>      'A',
            'created_at'                =>      $datetimev,
            'milliseconds'              =>      $milliseconds
        ];
        // Registramos la nueva factura
        $invoice = SivirSellInvoice::create($array_invoice);
        // Obtenemos el codigo del punto de venta
        $sellInvoice = SivirSellInvoice::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $invoice->id)->with(['sellpoint'])->get()->first();
        // Solicitamos toda la informacion para generar el cufd
        $dataForCufd = $this->getalldataforcufd($sellInvoice, $tipoEmision);
        // Corremos la funcion que genera el CUF
        $cuf = $this->generateCufd($dataForCufd);
        // Actualizamos la factura
        SivirSellInvoice::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $invoice->id)->update(array('cuf' => $cuf));
        // Obtenemos unicamente el movimiento en efectivo
        $cashTotal = $this->getcashpaymentonsell($sell_id);
        // Si optical_work_order_id existe, se debe descontar el down_payment
        if ($optical_work_order_id != null) {
            // Obtenemos la informacion 
            $optical = SivirOpticalWorkOrders::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('relative', $optical_work_order_id)->first();
            // Obtenemos el down payment
            $down_payment = $optical->down_payment;
            // Descontamos del total
            if ($down_payment > 0) {
                $cashTotal = $cashTotal - $down_payment;
            }
        }
        // Ahora realizamos el movimiento de monto en la caja
        $array_sellpoint_movement = [
            'relative'                  =>      Str::uuid()->toString(),
            'users_sid'                 =>      $request->users_sid,
            'global_branch_office_id'   =>      $request->global_branch_office_id,
            'sellpoint_id'              =>      $request->sellpoint,
            'date_movement'             =>      date("Y-m-d"),
            'type'                      =>      'I',
            'amount'                    =>      number_format($cashTotal, 2, ".", ""),
            'currency_id'               =>      $currency,
            'reason'                    =>      'V:' . $sell_id,
            'status'                    =>      'A',
            'created_at'                =>      date("Y-m-d H:i:s")
        ];
        // Registramos el movimiento de cajas
        // No necesitamos obtener información de lo registrado
        SellPointMovement::create($array_sellpoint_movement);
        // Ahora vemos los pagos posteriores
        $this->getpaymentpendingonsell($sell_id, $request->sellpoint, 6);
        // Creamos el archivo XML
        $fileGenerated = $this->createthexmlfilefrominvoice($invoice->id, $porExcepcion, $bolivianInvoice['codigo_sucursal'], false, $codigoModalidad, $tipo_factura_id);
        // Verificamos si la notificación 'validated_invoice' está activa
        $notificationsController = new SivirNotificationsController();
        // Verificamos
        $isNotificationEnabled = $notificationsController->checkFlagActive(
            $this->getbranchoffice(),
            'validated_invoice'
        );

        if ($isNotificationEnabled) {

            // Buscamos el código de la moneda seleccionada
            $currencyCode = 'BOB'; // Valor por defecto

            foreach ($this->getcachedcurrency() as $cachedCurrency) {
                if ($cachedCurrency['codigoClasificador'] == $currency) {
                    $currencyCode = $cachedCurrency['code'];
                    break;
                }
            }
            // Obtenemos la forma de pago
            $allpayments = CatalogsSivir::where('value', $request->payment)->where('catalog_code', 'PAYMENT')->where('global_branch_office_id', $this->getbranchoffice())->first();
            // Obtenemos la empresa
            $branches = LicenseServer::where('status', 'A')->where('license', $this->getbranchoffice())->with(['branchessivir'])->first();
            // Asignamos las variables
            $enterprise = $branches['branchessivir']['enterprise'];
            $branch = $branches['branchessivir']['branch_office'];
            // Ante titulo
            $prevTitle = "Empresa: {$enterprise}, Sucursal: {$branch} \n";
            // Creamos el título y mensaje
            $titulo = $prevTitle . "Se ha emitido la factura ({$invoice->id}) fuera de línea.";
            $monto = number_format($request->total, 2, ".", "");
            // Tipo de emision de la factura
            if ($tipoEmision == 2) {
                $mensaje = "Factura fuera de línea: ({$invoice->id}) - emitida al cliente: {$request->fullname} por un monto total de: {$monto} - ({$currencyCode}). Usuario: {$this->getusersemail()}, forma de pago: {$allpayments->label}";
            } else {
                $mensaje = "Factura en línea: ({$invoice->id}) - emitida al cliente: {$request->fullname} por un monto total de: {$monto} - ({$currencyCode}). Usuario: {$this->getusersemail()}, forma de pago: {$allpayments->label}";
            }

            // Enviamos la notificación usando Job asincrónico
            SendRemoteNotificationJob::dispatch(
                $this->getbranchoffice(),
                $this->getusersid(),
                $titulo,
                $mensaje
            );
        }
        // Finalizado el procedimiento debemos devolver la informacion obtenida
        return response()->json(
            [
                'status'    =>      'success',
                'invoice'   =>      $invoice->id,
                'sell'      =>      $sell_id,
                'bi'        =>      $bolivianInvoice,
                'cm'        =>      $codigoModalidad,
                'file'      =>      $fileGenerated
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function makeorder(Request $request)
    {
        // El numero de la venta siguiente
        $nextSell           = new SivirSell();
        // Obtenemos la nota de venta
        $nextSellOrder       = new SivirSellOrder();
        // Adicionamos la información basica para cualquier registro
        $request->merge(
            [
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice()
            ]
        );
        // Venta por Excepcion
        $porExcepcion   = $request->codigoExcepcion;
        // Primero vemos la informacion del cliente (CLIENTES)
        // Si el relative del customer es nulo entonces no existe el cliente
        // si el cliente no existe debemos registrarlo
        if ($request->customerrelative == null) {
            // Verificamos si este caso especial ya se ha registrado
            if (PortfolioCustomers::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                ->where('document_number', $request->document_number)->where('first_name', $request->fullname)->exists()
            ) {
                // Obtenemos la informacion ya registrada del cliente
                $portfolioCustomers = PortfolioCustomers::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('document_number', $request->document_number)->where('first_name', $request->fullname)->get()->first();
                // Adicionamos a las variables el relative del cliente
                $request->merge(['customerrelative' => $portfolioCustomers->relative]);
            } else {
                // Verificamos el codigo del cliente
                if ($request->document_number == "99002") {
                    $customer_type_id = 3;
                } elseif ($request->document_number == "99003") {
                    $customer_type_id = 4;
                } else {
                    $customer_type_id = 1;
                }
                // Relative solo para el cliente
                $customer_relative = Str::uuid()->toString();
                // En caso de no existir registramos el nuevo cliente
                // que para este unico caso es Sin nombre y nit 0
                PortfolioCustomers::create(array(
                    'relative'                  =>      $customer_relative,
                    'users_sid'                 =>      $request->users_sid,
                    'global_branch_office_id'   =>      $request->global_branch_office_id,
                    'customer_type_id'          =>      $customer_type_id,
                    'code'                      =>      0,
                    'first_name'                =>      $request->fullname,
                    'middle_name'               =>      null,
                    'last_name'                 =>      null,
                    'country_id'                =>      27, // Magic number for Bolivia
                    'document_type'             =>      $request->document_type,
                    'document_number'           =>      $request->document_number,
                    'customer_complemento'      =>      $request->complemento,
                    'email'                     =>      $request->email,
                    'social_media'              =>      null,
                    'phones'                    =>      isset($request->phones) ? $request->phones : null,
                    'address'                   =>      null,
                    'references'                =>      isset($request->references) ? $request->references : null,
                    'photo'                     =>      null,
                    'status'                    =>      'A',
                    'created_at'                =>      date("Y-m-d H:i:s")
                ));
                // Adicionamos a las variables el relative del cliente
                $request->merge(['customerrelative' => $customer_relative]);
            }
        }
        // La cantidad en stock es superior o igual a la cantidad requerida (VENTA)
        // Como sabemos que el stock no va a fallarnos, entonces iniciamos con la venta
        // Primero actualizamos la informacion del producto en sell sold en caso de que
        // se haya modificado los precios debido al tipo de cambio y la moneda
        $sell_relative = Str::uuid()->toString();
        // Registramos la nueva venta
        $newSell = SivirSell::create(array(
            'relative'                  =>      $sell_relative,
            'id'                        =>      $nextSell->next(),
            'users_sid'                 =>      $request->users_sid,
            'global_branch_office_id'   =>      $request->global_branch_office_id,
            'sellpoint_id'              =>      $request->sellpoint,
            'payment_type'              =>      $request->payment,
            'payment_detail'            =>      $request->payment_detail,
            'customer_id'               =>      $request->customerrelative,
            'document_type'             =>      $request->document_type,
            'customer_full_name'        =>      $request->fullname,
            'customer_nit'              =>      $request->document_number,
            'customer_complemento'      =>      $request->complemento,
            'customer_email'            =>      $request->email,
            'discount_all_products'     =>      number_format($request->totaldiscount, 2, ".", ""),
            'descuentoAdicional'        =>      number_format($request->descuentoAdicional, 2, ".", ""),
            'discount_total'            =>      number_format($request->totaldiscount + $request->descuentoAdicional, 2, ".", ""),
            'total'                     =>      number_format($request->total, 2, ".", ""),
            'currency_id'               =>      $request->currency,
            'exchange_used'             =>      $request->exchange,
            'codigoExcepcion'           =>      $porExcepcion,
            'sended'                    =>      'O',
            'date_movement'             =>      date("Y-m-d"),
            'status'                    =>      'A',
            'created_at'                =>      date("Y-m-d H:i:s")
        ));
        // Obtenemos el ID de la nueva venta
        $sell_id = $newSell->id;
        // Verificamos que cada producto tenga suficiente en su inventario (PRODUCTOS)
        // Para poder realizar una bajada de sus cantidades
        // Recorremos los productos encontrados y obtenemos cada producto
        foreach ($request->products as $data) {
            // Actualizamos la informacion del producto adicionado a la compra
            // Y modificamos el precio de venta, la cantidad, el total y el descuento
            // Adicionalmente quitamos el valor de provisional a nulo para que esto
            // no nos salga en otra venta del mismo usuario
            SivirSellSold::where('provisional', $request->provisional)
                ->where('product_id', $data['product_id'])->where('global_branch_office_id', $this->getbranchoffice())
                ->where('status', 'A')->update(
                    array(
                        'users_sid'         => $this->getusersid(),
                        'sell_id'           => $sell_id,
                        'provisional'       => null
                    )
                );
        }
        // Ahora obtenemos toda la informacion de la factura
        $bolivianInvoice = $this->getcachedfirstbolivianinvoice();
        // Ahora emitimos la nota de salida para la venta realizada
        $array_sell_order = [
            'relative'                  =>      Str::uuid()->toString(),
            'id'                        =>      $nextSellOrder->next(),
            'users_sid'                 =>      $request->users_sid,
            'global_branch_office_id'   =>      $request->global_branch_office_id,
            'sell_id'                   =>      $sell_id,
            'sellpoint_id'              =>      $request->sellpoint,
            'payment_type'              =>      $request->payment,
            'zofra'                     =>      $request->zofra,
            'codigo_sucursal'           =>      $bolivianInvoice->codigo_sucursal,
            'deliverydate'              =>      $request->deliverydate,
            'deliveryaddress'           =>      $request->deliveryaddress,
            'deliveryobs'               =>      $request->deliveryobs,
            'deliverycoordinates'       =>      $request->deliverycoordinates,
            'estado'                    =>      'V',
            'status'                    =>      'A',
            'created_at'                =>      date("Y-m-d H:i:s"),
            'updated_at'                =>      null
        ];
        // Registramos la nueva nota de salida
        SivirSellOrder::create($array_sell_order);
        // Obtenemos la informacion de la empresa
        $enterprise = $this->getcachedenterprise();
        // Obtenemos la informacion de la venta
        $theCompleteSell = SivirSell::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $sell_id)
            ->with(
                [
                    'branch',
                    'sellpoint',
                    'currency',
                    'products' => function ($q) {
                        $q->with(
                            [
                                'product' => function ($q) {
                                    $q->with(
                                        [
                                            'stock' => function ($q) {
                                                $q->with(['measurement']);
                                            },
                                            'homologated'
                                        ]
                                    );
                                }
                            ]
                        );
                    },
                    'order',
                    'aditionaldiscount'
                ]
            )
            ->orderBy('created_at', 'DESC')->get()->first();
        // Ahora obtenemos los datos de configuracion
        $configuration = Settings::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->with(['currency'])->get()->first();
        // Ahora generamos el PDF
        // Ahora debemos genera el archivo de la proforma en la ubicacion publica
        $this->generateOrder($enterprise, $theCompleteSell, $configuration, $bolivianInvoice);

        // Verificamos si la notificación 'sales_order' está activa
        $notificationsController = new SivirNotificationsController();
        // Verificamos
        $isNotificationEnabled = $notificationsController->checkFlagActive(
            $this->getbranchoffice(),
            'sales_order'
        );

        if ($isNotificationEnabled) {

            // Buscamos el código de la moneda seleccionada
            $currencyCode = 'BOB'; // Valor por defecto

            foreach ($this->getcachedcurrency() as $cachedCurrency) {
                if ($cachedCurrency['codigoClasificador'] == $request->currency) {
                    $currencyCode = $cachedCurrency['code'];
                    break;
                }
            }
            // Obtenemos la empresa
            $branches = LicenseServer::where('status', 'A')->where('license', $this->getbranchoffice())->with(['branchessivir'])->first();
            // Asignamos las variables
            $enterprise = $branches['branchessivir']['enterprise'];
            $branch = $branches['branchessivir']['branch_office'];
            // Ante titulo
            $prevTitle = "Empresa: {$enterprise}, Sucursal: {$branch} \n";
            // Creamos el título y mensaje
            $titulo = $prevTitle . "Se ha registrado una nueva orden de venta ({$array_sell_order['id']}).";
            $monto = number_format($request->total, 2, ".", "");
            $mensaje = "Orden de venta: ({$array_sell_order['id']}) - registrada al cliente: {$request->fullname} por un monto total de: {$monto} - ({$currencyCode}). Usuario: {$this->getusersemail()}";

            // Enviamos la notificación usando Job asincrónico
            SendRemoteNotificationJob::dispatch(
                $this->getbranchoffice(),
                $this->getusersid(),
                $titulo,
                $mensaje
            );
        }

        // Finalizado el procedimiento debemos devolver la informacion obtenida
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $request->all(),
                'sell'      =>      $sell_id
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function makeexternalorder(Request $request)
    {
        // Encontramos el punto de venta
        $sellPoint = SellPoint::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('could_close', 'Y')
            ->first();

        // Validamos si existe el punto de venta
        if (!$sellPoint) {
            return response()->json([
                'status' => 'error',
                'message' => 'No active SellPoint found capable of closing acts.'
            ], 404);
        }

        // Configuración
        $configuration = $this->getcachedfirstonesetting();
        $currencyId = $configuration ? $configuration->currency_id : 1;

        // Datos del Request
        $customer = $request->input('Customer');
        $products = $request->input('Products');

        // Calcular Total
        $total = 0;
        foreach ($products as $prod) {
            $total += $prod['price'] * $prod['quantity'];
        }

        // Crear una nueva venta
        $nextSell = new SivirSell();
        $sell_relative = Str::uuid()->toString();
        $newSell = SivirSell::create([
            'relative'                  => $sell_relative,
            'id'                        => $nextSell->next(),
            'users_sid'                 => $this->getusersid(),
            'global_branch_office_id'   => $this->getbranchoffice(),
            'sellpoint_id'              => $sellPoint->relative,
            'optical_work_order_id'     => null,
            'payment_type'              => 1, // Asumido 1 por defecto basado en SellOrder
            'payment_detail'            => null,
            'customer_id'               => $customer['customer_id'],
            'document_type'             => $customer['document_type'],
            'customer_full_name'        => $customer['customer_full_name'],
            'customer_nit'              => $customer['customer_nit'],
            'customer_complemento'      => $customer['customer_complemento'],
            'customer_email'            => $customer['customer_email'],
            'discount_all_products'     => 0,
            'descuentoAdicional'        => 0,
            'discount_total'            => 0,
            'total'                     => number_format($total, 2, ".", ""),
            'currency_id'               => $currencyId,
            'exchange_used'             => json_encode(ExchangeRate::getLatestExchangeRates()),
            'codigoExcepcion'           => 0,
            'medical_prescription_detail' => null,
            'sended'                    => 'O',
            'date_movement'             => date("Y-m-d"),
            'status'                    => 'A',
            'created_at'                => date("Y-m-d H:i:s")
        ]);

        $sell_id = $newSell->id;

        // Crear productos vendidos
        foreach ($products as $prod) {
            SivirSellSold::create([
                'relative'                  => Str::uuid()->toString(),
                'users_sid'                 => $this->getusersid(),
                'global_branch_office_id'   => $this->getbranchoffice(),
                'provisional'               => null,
                'sell_id'                   => $sell_id,
                'product_id'                => $prod['product_id'],
                'product_code'              => $prod['product_code'],
                'product_fullname'          => $prod['product_fullname'],
                'hospital_clinicas'         => null,
                'price'                     => number_format($prod['price'], 2, ".", ""),
                'quantity'                  => $prod['quantity'],
                'total_price'               => number_format($prod['price'] * $prod['quantity'], 2, ".", ""),
                'discount'                  => 0,
                'numeroSerie'               => null,
                'numeroImei'                => null,
                'detalleHuespedes'          => null,
                'hospedajeIngresoYSalida'   => null,
                'status'                    => 'A',
                'created_at'                => date("Y-m-d H:i:s")
            ]);
        }

        // Crear nota de venta (SellOrder)
        $nextSellOrder = new SivirSellOrder();
        $order_id = $nextSellOrder->next();
        SivirSellOrder::create([
            'relative'                  => Str::uuid()->toString(),
            'id'                        => $order_id,
            'users_sid'                 => $this->getusersid(),
            'global_branch_office_id'   => $this->getbranchoffice(),
            'sell_id'                   => $sell_id,
            'sellpoint_id'              => $sellPoint->relative,
            'payment_type'              => 1,
            'zofra'                     => 'N',
            'codigo_sucursal'           => 0,
            'deliverydate'              => $customer['deliverydate'],
            'deliveryaddress'           => $customer['deliveryaddress'],
            'deliveryobs'               => $customer['deliveryobs'],
            'deliverycoordinates'       => $customer['deliverycoordinates'],
            'deliver_status'            => 'P', // Pendiente por defecto
            'estado'                    => 'V',
            'status'                    => 'A',
            'created_at'                => date("Y-m-d H:i:s"),
            'updated_at'                => null
        ]);

        // Verificamos si la notificación 'sales_order' está activa
        $notificationsController = new SivirNotificationsController();
        // Verificamos
        $isNotificationEnabled = $notificationsController->checkFlagActive(
            $this->getbranchoffice(),
            'sales_order'
        );

        if ($isNotificationEnabled) {

            // Buscamos el código de la moneda seleccionada
            $currencyCode = 'BOB'; // Valor por defecto

            foreach ($this->getcachedcurrency() as $cachedCurrency) {
                if ($cachedCurrency['codigoClasificador'] == $currencyId) {
                    $currencyCode = $cachedCurrency['code'];
                    break;
                }
            }

            // Obtenemos la empresa
            $branches = LicenseServer::where('status', 'A')->where('license', $this->getbranchoffice())->with(['branchessivir'])->first();
            // Asignamos las variables
            $enterprise = $branches['branchessivir']['enterprise'];
            $branch = $branches['branchessivir']['branch_office'];
            // Ante titulo
            $prevTitle = "Empresa: {$enterprise}, Sucursal: {$branch} \n";
            // Creamos el título y mensaje
            $titulo = $prevTitle . "Se ha registrado una nueva orden de venta externa ({$order_id}).";
            $monto = number_format($total, 2, ".", "");
            $mensaje = "Orden de venta externa: ({$order_id}) - registrada al cliente: {$customer['customer_full_name']} por un monto total de: {$monto} - ({$currencyCode}). Usuario: {$this->getusersemail()}";

            // Enviamos la notificación usando Job asincrónico
            SendRemoteNotificationJob::dispatch(
                $this->getbranchoffice(),
                $this->getusersid(),
                $titulo,
                $mensaje
            );
        }

        return response()->json([
            'status'    => 'success',
            'sell'      => $sell_id,
            'message'   => 'External order created successfully'
        ], 200);
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function makeproforma(Request $request)
    {
        // El numero de la venta siguiente
        $nextSell           = new SivirSell();
        // Adicionamos la información basica para cualquier registro
        $request->merge(
            [
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice()
            ]
        );
        // Venta por Excepcion
        $porExcepcion   = $request->codigoExcepcion;
        // Primero vemos la informacion del cliente (CLIENTES)
        // Si el relative del customer es nulo entonces no existe el cliente
        // si el cliente no existe debemos registrarlo
        if ($request->customerrelative == null) {
            // Verificamos si este caso especial ya se ha registrado
            if (PortfolioCustomers::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                ->where('document_number', $request->document_number)->where('first_name', $request->fullname)->exists()
            ) {
                // Obtenemos la informacion ya registrada del cliente
                $portfolioCustomers = PortfolioCustomers::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('document_number', $request->document_number)->where('first_name', $request->fullname)->get()->first();
                // Adicionamos a las variables el relative del cliente
                $request->merge(['customerrelative' => $portfolioCustomers->relative]);
            } else {
                // Verificamos el codigo del cliente
                if ($request->document_number == "99002") {
                    $customer_type_id = 3;
                } elseif ($request->document_number == "99003") {
                    $customer_type_id = 4;
                } else {
                    $customer_type_id = 1;
                }
                // Relative solo para el cliente
                $customer_relative = Str::uuid()->toString();
                // En caso de no existir registramos el nuevo cliente
                // que para este unico caso es Sin nombre y nit 0
                PortfolioCustomers::create(array(
                    'relative'                  =>      $customer_relative,
                    'users_sid'                 =>      $request->users_sid,
                    'global_branch_office_id'   =>      $request->global_branch_office_id,
                    'customer_type_id'          =>      $customer_type_id,
                    'code'                      =>      0,
                    'first_name'                =>      $request->fullname,
                    'middle_name'               =>      null,
                    'last_name'                 =>      null,
                    'country_id'                =>      27, // Magic number for Bolivia
                    'document_type'             =>      $request->document_type,
                    'document_number'           =>      $request->document_number,
                    'customer_complemento'      =>      $request->complemento,
                    'email'                     =>      $request->email,
                    'social_media'              =>      null,
                    'phones'                    =>      isset($request->phones) ? $request->phones : null,
                    'address'                   =>      null,
                    'references'                =>      isset($request->references) ? $request->references : null,
                    'photo'                     =>      null,
                    'status'                    =>      'A',
                    'created_at'                =>      date("Y-m-d H:i:s")
                ));
                // Adicionamos a las variables el relative del cliente
                $request->merge(['customerrelative' => $customer_relative]);
            }
        }
        // La cantidad en stock es superior o igual a la cantidad requerida (VENTA)
        // Como sabemos que el stock no va a fallarnos, entonces iniciamos con la venta
        // Primero actualizamos la informacion del producto en sell sold en caso de que
        // se haya modificado los precios debido al tipo de cambio y la moneda
        $sell_relative = Str::uuid()->toString();
        // Registramos la nueva venta
        $newSell = SivirSell::create(array(
            'relative'                  =>      $sell_relative,
            'id'                        =>      $nextSell->next(),
            'users_sid'                 =>      $request->users_sid,
            'global_branch_office_id'   =>      $request->global_branch_office_id,
            'sellpoint_id'              =>      $request->sellpoint,
            'payment_type'              =>      $request->payment,
            'payment_detail'            =>      $request->payment_detail,
            'customer_id'               =>      $request->customerrelative,
            'document_type'             =>      $request->document_type,
            'customer_full_name'        =>      $request->fullname,
            'customer_nit'              =>      $request->document_number,
            'customer_complemento'      =>      $request->complemento,
            'customer_email'            =>      $request->email,
            'discount_all_products'     =>      number_format($request->totaldiscount, 2, ".", ""),
            'descuentoAdicional'        =>      number_format($request->descuentoAdicional, 2, ".", ""),
            'discount_total'            =>      number_format($request->totaldiscount + $request->descuentoAdicional, 2, ".", ""),
            'total'                     =>      number_format($request->total, 2, ".", ""),
            'currency_id'               =>      $request->currency,
            'exchange_used'             =>      $request->exchange,
            'codigoExcepcion'           =>      $porExcepcion,
            'sended'                    =>      'P',
            'date_movement'             =>      date("Y-m-d"),
            'status'                    =>      'A',
            'created_at'                =>      date("Y-m-d H:i:s")
        ));
        // Obtenemos el ID de la nueva venta
        $sell_id = $newSell->id;
        // Verificamos que cada producto tenga suficiente en su inventario (PRODUCTOS)
        // Para poder realizar una bajada de sus cantidades
        // Recorremos los productos encontrados y obtenemos cada producto
        foreach ($request->products as $data) {
            // Actualizamos la informacion del producto adicionado a la compra
            // Y modificamos el precio de venta, la cantidad, el total y el descuento
            // Adicionalmente quitamos el valor de provisional a nulo para que esto
            // no nos salga en otra venta del mismo usuario
            SivirSellSold::where('provisional', $request->provisional)
                ->where('product_id', $data['product_id'])->where('global_branch_office_id', $this->getbranchoffice())
                ->where('status', 'A')->update(
                    array(
                        'users_sid' => $this->getusersid(),
                        'sell_id' => $sell_id,
                        'price' => number_format($data['price'], 2, ".", ""),
                        'quantity' => $data['quantity'],
                        'total_price' => number_format($data['total_price'], 2, ".", ""),
                        'discount' => number_format($data['discount'], 2, ".", ""),
                        'provisional' => null
                    )
                );
        }
        // Obtenemos la informacion de la empresa
        $enterprise = $this->getcachedenterprise();
        // Obtenemos la informacion de la venta
        $theCompleteSell = SivirSell::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $sell_id)
            ->with(
                [
                    'branch',
                    'sellpoint',
                    'currency',
                    'products' => function ($q) {
                        $q->with(
                            [
                                'product' => function ($q) {
                                    $q->with(
                                        [
                                            'stock' => function ($q) {
                                                $q->with(['measurement']);
                                            },
                                            'homologated'
                                        ]
                                    );
                                }
                            ]
                        );
                    },
                    'sellpaymentway',
                    'aditionaldiscount'
                ]
            )
            ->orderBy('created_at', 'DESC')->get()->first();
        // Ahora obtenemos los datos de configuracion
        $configuration = Settings::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->with(['currency'])->get()->first();
        // Ahora obtenemos toda la informacion de la factura
        $bolivianInvoice = $this->getcachedfirstbolivianinvoice();
        // Ahora generamos el PDF
        // Ahora debemos genera el archivo de la proforma en la ubicacion publica
        $this->generateProforma($sell_id, $enterprise, $theCompleteSell, $configuration, $bolivianInvoice);

        // Verificamos si la notificación 'proforma' está activa
        $notificationsController = new SivirNotificationsController();
        // Verificamos
        $isNotificationEnabled = $notificationsController->checkFlagActive(
            $this->getbranchoffice(),
            'proforma'
        );

        if ($isNotificationEnabled) {

            // Buscamos el código de la moneda seleccionada
            $currencyCode = 'BOB'; // Valor por defecto

            foreach ($this->getcachedcurrency() as $currency) {
                if ($currency['codigoClasificador'] == $request->currency) {
                    $currencyCode = $currency['code'];
                    break;
                }
            }

            // Obtenemos la forma de pago
            $allpayments = CatalogsSivir::where('value', $request->payment)->where('catalog_code', 'PAYMENT')->where('global_branch_office_id', $this->getbranchoffice())->first();
            // Obtenemos la empresa
            $branches = LicenseServer::where('status', 'A')->where('license', $this->getbranchoffice())->with(['branchessivir'])->first();
            // Asignamos las variables
            $enterprise = $branches['branchessivir']['enterprise'];
            $branch = $branches['branchessivir']['branch_office'];
            // Ante titulo
            $prevTitle = "Empresa: {$enterprise}, Sucursal: {$branch} \n";
            // Creamos el título y mensaje
            $titulo = $prevTitle . "Se ha registrado una nueva proforma ({$sell_id}).";
            $monto = number_format($request->total, 2, ".", "");
            $mensaje = "Proforma: ({$sell_id}) - registrada al cliente: {$request->fullname} por un monto total de: {$monto} - ({$currencyCode}). Usuario: {$this->getusersemail()}, forma de pago: " . ($allpayments ? $allpayments->label : 'N/A');

            // Enviamos la notificación usando Job asincrónico
            SendRemoteNotificationJob::dispatch(
                $this->getbranchoffice(),
                $this->getusersid(),
                $titulo,
                $mensaje
            );
        }

        // Finalizado el procedimiento debemos devolver la informacion obtenida
        return response()->json(
            [
                'status'    =>      'success',
                'message'   =>      $request->all(),
                'sell'      =>      $sell_id
            ],
            200
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function redooffline(Request $request)
    {
        // Verificamos la licencia
        $license = $this->getbranchoffice();
        // Recibimos la factura
        $invoiceId  = $request->invoice_id;
        $invoice    = $request->invoice_id;
        // Ahora buscaoms la venta que tiene la factura
        $sell = SivirSellInvoice::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $invoiceId)->with(['sellpoint', 'sell']);
        // Verificamos si la venta existe
        if ($sell->exists()) {
            // Obtenemos la venta encontrada
            $sellIdData = $sell->get()->first();
            // Obtenemos zofra
            $zofra = $sellIdData['zofra'];
            // Con el ID de la venta actualizamos la informacion
            SivirSell::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('id', $sellIdData['sell_id'])
                ->update(array(
                    'codigoExcepcion'   =>  1,
                    'created_at'        =>  date("Y-m-d H:i:s"),
                    'updated_at'        =>  date("Y-m-d H:i:s"),
                    'users_sid'         =>  $this->getusersid()
                ));
            // Ahora actualizamos la factura
            $sell->update(array(
                'cafc'              =>  null,
                'tipo_emision'      =>  2,
                'created_at'        =>  date("Y-m-d H:i:s"),
                'updated_at'        =>  date("Y-m-d H:i:s"),
                'users_sid'         =>  $this->getusersid()
            ));
            // Dormimos
            sleep(1);
            // Volvemos a obtener informacion de la factura
            $sellInvoice = SivirSellInvoice::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('id', $invoiceId)->with(['sellpoint'])->get()->first();
            // Solicitamos toda la informacion para generar el cufd
            $dataForCufd = $this->getalldataforcufd($sellInvoice, 2);
            // Corremos la funcion que genera el CUF
            $cuf = $this->generateCufd($dataForCufd);
            // Ahora actualizamos el cuf
            $sell->update(array(
                'cuf'               =>  $cuf,
                'updated_at'        =>  date("Y-m-d H:i:s"),
            ));
            // Obtenemos informacion de la facturacion
            $bolivianInvoice = $this->getcachedfirstbolivianinvoice();
            // Eliminamos el estado de la factura
            SivirSellInvoiceStatus::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('invoice_id', $invoiceId)->delete();
            // Informacion obtenida de la facturacion boliviana
            $codigoModalidad    = $bolivianInvoice['codigo_modalidad'];
            $tipo_factura_id    = $sellInvoice['tipo_factura_id'];
            $codigo_sucursal    = $bolivianInvoice['codigo_sucursal'];
            // Si es factura zofra o no
            if ($zofra == "Y") {
                //=========================
                // Creando el archivo .xml
                //=========================
                // Creamos el directorio de la sucursal
                Storage::disk('invoicezofra')->makeDirectory($license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoice);
                // Obtenemos el path completo
                $storagePath = storage_path('app/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoice . '/');
                // Verificamos la modalidad para darle nombre al archivo
                if ($codigoModalidad == 1) {
                    // Si es una factura de compra venta en zona franca
                    if ($tipo_factura_id == 5) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaZonaFrancaNS.xml';
                        $xml = $storagePath . 'facturaElectronicaZonaFranca.xml';
                        $xsd = $storagePath . 'facturaElectronicaZonaFranca.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaZonaFranca.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaZonaFranca.pdf';
                    }
                    // Factura de tipo hospedaje turistico
                    if ($tipo_factura_id == 6) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaServicioTuristicoHospedajeNS.xml';
                        $xml = $storagePath . 'facturaElectronicaServicioTuristicoHospedaje.xml';
                        $xsd = $storagePath . 'facturaElectronicaServicioTuristicoHospedaje.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaServicioTuristicoHospedaje.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaServicioTuristicoHospedaje.pdf';
                    }
                    // Si es una factura tasa cero
                    if ($tipo_factura_id == 8) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaTasaCeroNS.xml';
                        $xml = $storagePath . 'facturaElectronicaTasaCero.xml';
                        $xsd = $storagePath . 'facturaElectronicaTasaCero.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaTasaCero.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaTasaCero.pdf';
                    }
                    // Si es una factura dutty free
                    if ($tipo_factura_id == 10) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaDuttyFreeNS.xml';
                        $xml = $storagePath . 'facturaElectronicaDuttyFree.xml';
                        $xsd = $storagePath . 'facturaElectronicaDuttyFree.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaDuttyFree.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaDuttyFree.pdf';
                    }
                    // Verificamos sector alquileres
                    if ($tipo_factura_id == 42) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaAlquilerZFNS.xml';
                        $xml = $storagePath . 'facturaElectronicaAlquilerZF.xml';
                        $xsd = $storagePath . 'facturaElectronicaAlquilerZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaAlquilerZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaAlquilerZF.pdf';
                    }
                    // Verificamos sector educativo
                    if ($tipo_factura_id == 46) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaSectorEducativoZFNS.xml';
                        $xml = $storagePath . 'facturaElectronicaSectorEducativoZF.xml';
                        $xsd = $storagePath . 'facturaElectronicaSectorEducativoZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaSectorEducativoZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaSectorEducativoZF.pdf';
                    }
                    // Verificamos sector telecomunicaciones
                    if ($tipo_factura_id == 49) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaTelecomunicacionZFNS.xml';
                        $xml = $storagePath . 'facturaElectronicaTelecomunicacionZF.xml';
                        $xsd = $storagePath . 'facturaElectronicaTelecomunicacionZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaTelecomunicacionZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaTelecomunicacionZF.pdf';
                    }
                    // Hospitales y clinicas ZF
                    if ($tipo_factura_id == 50) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaTelecomunicacionZFNS.xml';
                        $xml = $storagePath . 'facturaElectronicaTelecomunicacionZF.xml';
                        $xsd = $storagePath . 'facturaElectronicaTelecomunicacionZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaTelecomunicacionZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaTelecomunicacionZF.pdf';
                    }
                }
                if ($codigoModalidad == 2) {
                    // Si es una factura de compra venta en zona franca
                    if ($tipo_factura_id == 5) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaZonaFrancaNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaZonaFranca.xml';
                        $xsd = $storagePath . 'facturaComputarizadaZonaFranca.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaZonaFranca.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaZonaFranca.pdf';
                    }
                    // Factura de tipo hospedaje turistico
                    if ($tipo_factura_id == 6) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaServicioTuristicoHospedajeNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaServicioTuristicoHospedaje.xml';
                        $xsd = $storagePath . 'facturaComputarizadaServicioTuristicoHospedaje.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaServicioTuristicoHospedaje.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaServicioTuristicoHospedaje.pdf';
                    }
                    // Si es una factura tasa cero
                    if ($tipo_factura_id == 8) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaTasaCeroNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaTasaCero.xml';
                        $xsd = $storagePath . 'facturaComputarizadaTasaCero.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaTasaCero.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaTasaCero.pdf';
                    }
                    // Si es una factura dutty free
                    if ($tipo_factura_id == 10) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaDuttyFreeNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaDuttyFree.xml';
                        $xsd = $storagePath . 'facturaComputarizadaDuttyFree.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaDuttyFree.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaDuttyFree.pdf';
                    }
                    // Verificamos sector alquileres
                    if ($tipo_factura_id == 42) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaAlquilerZFNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaAlquilerZF.xml';
                        $xsd = $storagePath . 'facturaComputarizadaAlquilerZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaAlquilerZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaAlquilerZF.pdf';
                    }
                    // Verificamos sector educativo
                    if ($tipo_factura_id == 46) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaSectorEducativoZFNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaSectorEducativoZF.xml';
                        $xsd = $storagePath . 'facturaComputarizadaSectorEducativoZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaSectorEducativoZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaSectorEducativoZF.pdf';
                    }
                    // Verificamos sector telecomunicaciones
                    if ($tipo_factura_id == 49) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaTelecomunicacionZFNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaTelecomunicacionZF.xml';
                        $xsd = $storagePath . 'facturaComputarizadaTelecomunicacionZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaTelecomunicacionZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaTelecomunicacionZF.pdf';
                    }
                    // Hospitales y clinicas ZF
                    if ($tipo_factura_id == 50) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaTelecomunicacionZFNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaTelecomunicacionZF.xml';
                        $xsd = $storagePath . 'facturaComputarizadaTelecomunicacionZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaTelecomunicacionZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaTelecomunicacionZF.pdf';
                    }
                }
            } else {
                //=========================
                // Creando el archivo .xml
                //=========================
                // Creamos el directorio de la sucursal
                Storage::disk('invoiceregular')->makeDirectory($codigo_sucursal . DIRECTORY_SEPARATOR . $invoice);
                // Obtenemos el path completo
                $storagePath = storage_path('app/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoice . '/');
                // Verificamos la modalidad para darle nombre al archivo
                if ($codigoModalidad == 1) {
                    // Si es una factura de compra venta en zona franca
                    if ($tipo_factura_id == 1) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaCompraVentaNS.xml';
                        $xml = $storagePath . 'facturaElectronicaCompraVenta.xml';
                        $xsd = $storagePath . 'facturaElectronicaCompraVenta.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaCompraVenta.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaCompraVenta.pdf';
                    }
                    // Verificamos sector alquileres de bienes inmuebles
                    if ($tipo_factura_id == 2) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaAlquilerBienInmuebleNS.xml';
                        $xml = $storagePath . 'facturaElectronicaAlquilerBienInmueble.xml';
                        $xsd = $storagePath . 'facturaElectronicaAlquilerBienInmueble.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaAlquilerBienInmueble.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaAlquilerBienInmueble.pdf';
                    }
                    // Verificamos sector educativo
                    if ($tipo_factura_id == 11) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaSectorEducativoNS.xml';
                        $xml = $storagePath . 'facturaElectronicaSectorEducativo.xml';
                        $xsd = $storagePath . 'facturaElectronicaSectorEducativo.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaSectorEducativo.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaSectorEducativo.pdf';
                    }
                    // Verificamos sector hospedaje turistico
                    if ($tipo_factura_id == 16) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaHotelNS.xml';
                        $xml = $storagePath . 'facturaElectronicaHotel.xml';
                        $xsd = $storagePath . 'facturaElectronicaHotel.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaHotel.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaHotel.pdf';
                    }
                    // Verificamos sector hospitales y clinicas
                    if ($tipo_factura_id == 17) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaHospitalClinicaNS.xml';
                        $xml = $storagePath . 'facturaElectronicaHospitalClinica.xml';
                        $xsd = $storagePath . 'facturaElectronicaHospitalClinica.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaHospitalClinica.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaHospitalClinica.pdf';
                    }
                    // Verificamos sector telecomunicaciones
                    if ($tipo_factura_id == 22) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaTelecomunicacionNS.xml';
                        $xml = $storagePath . 'facturaElectronicaTelecomunicacion.xml';
                        $xsd = $storagePath . 'facturaElectronicaTelecomunicacion.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaTelecomunicacion.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaTelecomunicacion.pdf';
                    }
                    // Verificamos sector bonificaciones
                    if ($tipo_factura_id == 35) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaCompraVentaBonNS.xml';
                        $xml = $storagePath . 'facturaElectronicaCompraVentaBon.xml';
                        $xsd = $storagePath . 'facturaElectronicaCompraVentaBon.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaCompraVentaBon.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaCompraVentaBon.pdf';
                    }
                }
                if ($codigoModalidad == 2) {
                    // Si es una factura de compra venta en zona franca
                    if ($tipo_factura_id == 1) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaCompraVentaNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaCompraVenta.xml';
                        $xsd = $storagePath . 'facturaComputarizadaCompraVenta.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaCompraVenta.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaCompraVenta.pdf';
                    }
                    // Verificamos sector alquileres de bienes inmuebles
                    if ($tipo_factura_id == 2) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaAlquilerBienInmuebleNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaAlquilerBienInmueble.xml';
                        $xsd = $storagePath . 'facturaComputarizadaAlquilerBienInmueble.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaAlquilerBienInmueble.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaAlquilerBienInmueble.pdf';
                    }
                    // Verificamos sector educativo
                    if ($tipo_factura_id == 11) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaSectorEducativoNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaSectorEducativo.xml';
                        $xsd = $storagePath . 'facturaComputarizadaSectorEducativo.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaSectorEducativo.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaSectorEducativo.pdf';
                    }
                    // Verificamos sector hospedaje turistico
                    if ($tipo_factura_id == 16) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaHotelNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaHotel.xml';
                        $xsd = $storagePath . 'facturaComputarizadaHotel.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaHotel.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaHotel.pdf';
                    }
                    // Verificamos sector hospitales y clinicas
                    if ($tipo_factura_id == 17) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaHospitalClinicaNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaHospitalClinica.xml';
                        $xsd = $storagePath . 'facturaComputarizadaHospitalClinica.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaHospitalClinica.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaHospitalClinica.pdf';
                    }
                    // Verificamos sector telecomunicaciones
                    if ($tipo_factura_id == 22) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaTelecomunicacionNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaTelecomunicacion.xml';
                        $xsd = $storagePath . 'facturaComputarizadaTelecomunicacion.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaTelecomunicacion.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaTelecomunicacion.pdf';
                    }
                    // Verificamos sector bonificaciones
                    if ($tipo_factura_id == 35) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaCompraVentaBonNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaCompraVentaBon.xml';
                        $xsd = $storagePath . 'facturaComputarizadaCompraVentaBon.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaCompraVentaBon.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaCompraVentaBon.pdf';
                    }
                }
            }
            // Ahora eliminamos los archivos generados
            // a excepcion de los publicos que no tiene sentido eliminarlos
            // Vemos si es zofra o no, que es lo mas importante
            // Eliminamos los archivos fuente de la factura
            if (is_writable($xmlNS)) {
                unlink($xmlNS);
            }
            if (is_writable($xml)) {
                unlink($xml);
            }
            if (is_writable($xsd)) {
                unlink($xsd);
            }
            if (is_writable($qr)) {
                unlink($qr);
            }
            if (is_writable($publicFileA4)) {
                unlink($publicFileA4);
            }
            if (is_writable($publicFileA7)) {
                @unlink($publicFileA7);
            }
            sleep(2);
            // Ahora rehacemos los archivos XML, XSD, QR y volvemos a firmar
            $this->createthexmlfilefrominvoice($invoiceId, 1, $bolivianInvoice->codigo_sucursal, false, $codigoModalidad, $tipo_factura_id);
            // Verificamos si la notificación 'validated_invoice' está activa
            $notificationsController = new SivirNotificationsController();
            // Verificamos
            $isNotificationEnabled = $notificationsController->checkFlagActive(
                $this->getbranchoffice(),
                'offline_invoice'
            );

            if ($isNotificationEnabled) {

                // Buscamos el código de la moneda seleccionada
                $currencyCode = 'BOB'; // Valor por defecto

                foreach ($this->getcachedcurrency() as $currency) {
                    if ($currency['codigoClasificador'] == $sellIdData['sell']['currency_id']) {
                        $currencyCode = $currency['code'];
                        break;
                    }
                }

                // Obtenemos la forma de pago
                $allpayments = CatalogsSivir::where('value', $sellIdData['sell']['payment_type'])->where('catalog_code', 'PAYMENT')->where('global_branch_office_id', $this->getbranchoffice())->first();
                // Obtenemos la empresa
                $branches = LicenseServer::where('status', 'A')->where('license', $this->getbranchoffice())->with(['branchessivir'])->first();
                // Asignamos las variables
                $enterprise = $branches['branchessivir']['enterprise'];
                $branch = $branches['branchessivir']['branch_office'];
                // Ante titulo
                $prevTitle = "Empresa: {$enterprise}, Sucursal: {$branch} \n";
                // Creamos el título y mensaje
                $titulo = $prevTitle . "Se ha emitido la factura ({$invoiceId}) fuera de línea.";
                $monto = number_format($sellIdData['sell']['total'], 2, ".", "");
                $mensaje = "Factura fuera de línea: ({$invoiceId}) - emitida al cliente: {$sellIdData['sell']['customer_full_name']} por un monto total de: {$monto} - ({$currencyCode}). Usuario: {$this->getusersemail()}, forma de pago: {$allpayments->label}";
                // Enviamos la notificación usando Job asincrónico
                SendRemoteNotificationJob::dispatch(
                    $this->getbranchoffice(),
                    $this->getusersid(),
                    $titulo,
                    $mensaje
                );
            }
            // retornamos la informacion recibida
            return response()->json(
                [
                    'status'    =>  'success',
                    'datacufd'  =>  $dataForCufd,
                    'cuf'       =>  $cuf
                ],
                200
            );
        } else {
            return response()->json(
                [
                    'status'  =>  'fail',
                    'message' =>  'The sell does not exists'
                ],
                409
            );
        }
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function redoinvoiceonline(Request $request)
    {
        // Verificamos la licencia
        $license = $this->getbranchoffice();
        // Recibimos la factura
        $invoiceId  = $request->invoice_id;
        $invoice    = $request->invoice_id;
        // Ahora buscaoms la venta que tiene la factura
        $sell = SivirSellInvoice::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $invoiceId)->with(['sellpoint']);
        // Verificamos si la venta existe
        if ($sell->exists()) {
            // Obtenemos la venta encontrada
            $sellIdData = $sell->get()->first();
            // Obtenemos el ID del sellpoint utilizado
            $sellpointId = $sellIdData->sellpoint_id;
            // Obtenemos el nuevo CUFD
            $cufdData = SivirCufd::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('sellpoint_id', $sellpointId)
                ->orderBy('created_at', 'DESC')->get()->first();
            // The new CUFD
            $newCufd = ($cufdData->codigo_cufd != null) ? $cufdData->codigo_cufd : $cufdData['codigo_cufd'];
            $newCodigoControl = ($cufdData->codigo_control != null) ? $cufdData->codigo_control : $cufdData['codigo_control'];
            // Ahora actualizamos la informacion de la factura
            SivirSellInvoice::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('id', $invoiceId)
                ->update(
                    [
                        'cufd'              =>  $newCufd,
                        'codigo_control'    =>  $newCodigoControl,
                        'created_at'        =>  date("Y-m-d H:i:s"),
                    ]
                );
            // Obtenemos zofra
            $zofra = $sellIdData['zofra'];
            // Con el ID de la venta actualizamos la informacion
            SivirSell::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('id', $sellIdData['sell_id'])
                ->update(array(
                    'codigoExcepcion'   =>  0,
                    'created_at'        =>  date("Y-m-d H:i:s"),
                    'updated_at'        =>  date("Y-m-d H:i:s"),
                    'users_sid'         =>  $this->getusersid()
                ));
            // Ahora actualizamos la factura
            $sell->update(array(
                'cafc'              =>  null,
                'tipo_emision'      =>  1,
                'created_at'        =>  date("Y-m-d H:i:s"),
                'updated_at'        =>  date("Y-m-d H:i:s"),
                'users_sid'         =>  $this->getusersid()
            ));
            // Dormimos
            sleep(1);
            // Volvemos a obtener informacion de la factura
            $sellInvoice = SivirSellInvoice::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('id', $invoiceId)->with(['sellpoint'])->get()->first();
            // Solicitamos toda la informacion para generar el cufd
            $dataForCufd = $this->getalldataforcufd($sellInvoice, 1);
            // Corremos la funcion que genera el CUF
            $cuf = $this->generateCufd($dataForCufd);
            // Ahora actualizamos el cuf
            SivirSellInvoice::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('id', $invoiceId)
                ->update(
                    array(
                        'cuf'               =>  $cuf,
                        'updated_at'        =>  date("Y-m-d H:i:s"),
                    )
                );
            // Obtenemos informacion de la facturacion
            $bolivianInvoice = $this->getcachedfirstbolivianinvoice();
            // Eliminamos el estado de la factura
            SivirSellInvoiceStatus::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('invoice_id', $invoiceId)->delete();
            // Informacion obtenida de la facturacion boliviana
            $codigoModalidad    = $bolivianInvoice['codigo_modalidad'];
            $tipo_factura_id    = $sellInvoice['tipo_factura_id'];
            $codigo_sucursal    = $bolivianInvoice['codigo_sucursal'];
            // Si es factura zofra o no
            if ($zofra == "Y") {
                //=========================
                // Creando el archivo .xml
                //=========================
                // Creamos el directorio de la sucursal
                Storage::disk('invoicezofra')->makeDirectory($codigo_sucursal . DIRECTORY_SEPARATOR . $invoice);
                // Obtenemos el path completo
                $storagePath = storage_path('app/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoice . '/');
                // Verificamos la modalidad para darle nombre al archivo
                if ($codigoModalidad == 1) {
                    // Si es una factura de compra venta en zona franca
                    if ($tipo_factura_id == 5) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaZonaFrancaNS.xml';
                        $xml = $storagePath . 'facturaElectronicaZonaFranca.xml';
                        $xsd = $storagePath . 'facturaElectronicaZonaFranca.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaZonaFranca.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaZonaFranca.pdf';
                    }
                    // Factura de tipo hospedaje turistico
                    if ($tipo_factura_id == 6) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaServicioTuristicoHospedajeNS.xml';
                        $xml = $storagePath . 'facturaElectronicaServicioTuristicoHospedaje.xml';
                        $xsd = $storagePath . 'facturaElectronicaServicioTuristicoHospedaje.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaServicioTuristicoHospedaje.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaServicioTuristicoHospedaje.pdf';
                    }
                    // Si es una factura tasa cero
                    if ($tipo_factura_id == 8) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaTasaCeroNS.xml';
                        $xml = $storagePath . 'facturaElectronicaTasaCero.xml';
                        $xsd = $storagePath . 'facturaElectronicaTasaCero.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaTasaCero.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaTasaCero.pdf';
                    }
                    // Si es una factura dutty free
                    if ($tipo_factura_id == 10) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaDuttyFreeNS.xml';
                        $xml = $storagePath . 'facturaElectronicaDuttyFree.xml';
                        $xsd = $storagePath . 'facturaElectronicaDuttyFree.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaDuttyFree.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaDuttyFree.pdf';
                    }
                    // Verificamos sector alquileres
                    if ($tipo_factura_id == 42) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaAlquilerZFNS.xml';
                        $xml = $storagePath . 'facturaElectronicaAlquilerZF.xml';
                        $xsd = $storagePath . 'facturaElectronicaAlquilerZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaAlquilerZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaAlquilerZF.pdf';
                    }
                    // Verificamos sector educativo
                    if ($tipo_factura_id == 46) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaSectorEducativoZFNS.xml';
                        $xml = $storagePath . 'facturaElectronicaSectorEducativoZF.xml';
                        $xsd = $storagePath . 'facturaElectronicaSectorEducativoZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaSectorEducativoZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaSectorEducativoZF.pdf';
                    }
                    // Verificamos sector telecomunicaciones
                    if ($tipo_factura_id == 49) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaTelecomunicacionZFNS.xml';
                        $xml = $storagePath . 'facturaElectronicaTelecomunicacionZF.xml';
                        $xsd = $storagePath . 'facturaElectronicaTelecomunicacionZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaTelecomunicacionZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaTelecomunicacionZF.pdf';
                    }
                    // Hospitales y clinicas ZF
                    if ($tipo_factura_id == 50) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaTelecomunicacionZFNS.xml';
                        $xml = $storagePath . 'facturaElectronicaTelecomunicacionZF.xml';
                        $xsd = $storagePath . 'facturaElectronicaTelecomunicacionZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaTelecomunicacionZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaTelecomunicacionZF.pdf';
                    }
                }
                if ($codigoModalidad == 2) {
                    // Si es una factura de compra venta en zona franca
                    if ($tipo_factura_id == 5) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaZonaFrancaNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaZonaFranca.xml';
                        $xsd = $storagePath . 'facturaComputarizadaZonaFranca.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaZonaFranca.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaZonaFranca.pdf';
                    }
                    // Factura de tipo hospedaje turistico
                    if ($tipo_factura_id == 6) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaServicioTuristicoHospedajeNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaServicioTuristicoHospedaje.xml';
                        $xsd = $storagePath . 'facturaComputarizadaServicioTuristicoHospedaje.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaServicioTuristicoHospedaje.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaServicioTuristicoHospedaje.pdf';
                    }
                    // Si es una factura tasa cero
                    if ($tipo_factura_id == 8) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaTasaCeroNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaTasaCero.xml';
                        $xsd = $storagePath . 'facturaComputarizadaTasaCero.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaTasaCero.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaTasaCero.pdf';
                    }
                    // Si es una factura dutty free
                    if ($tipo_factura_id == 10) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaDuttyFreeNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaDuttyFree.xml';
                        $xsd = $storagePath . 'facturaComputarizadaDuttyFree.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaDuttyFree.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaDuttyFree.pdf';
                    }
                    // Verificamos sector alquileres
                    if ($tipo_factura_id == 42) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaAlquilerZFNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaAlquilerZF.xml';
                        $xsd = $storagePath . 'facturaComputarizadaAlquilerZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaAlquilerZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaAlquilerZF.pdf';
                    }
                    // Verificamos sector educativo
                    if ($tipo_factura_id == 46) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaSectorEducativoZFNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaSectorEducativoZF.xml';
                        $xsd = $storagePath . 'facturaComputarizadaSectorEducativoZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaSectorEducativoZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaSectorEducativoZF.pdf';
                    }
                    // Verificamos sector telecomunicaciones
                    if ($tipo_factura_id == 49) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaTelecomunicacionZFNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaTelecomunicacionZF.xml';
                        $xsd = $storagePath . 'facturaComputarizadaTelecomunicacionZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaTelecomunicacionZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaTelecomunicacionZF.pdf';
                    }
                    // Hospitales y clinicas ZF
                    if ($tipo_factura_id == 50) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaTelecomunicacionZFNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaTelecomunicacionZF.xml';
                        $xsd = $storagePath . 'facturaComputarizadaTelecomunicacionZF.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaTelecomunicacionZF.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaTelecomunicacionZF.pdf';
                    }
                }
            } else {
                //=========================
                // Creando el archivo .xml
                //=========================
                // Creamos el directorio de la sucursal
                Storage::disk('invoiceregular')->makeDirectory($codigo_sucursal . DIRECTORY_SEPARATOR . $invoice);
                // Obtenemos el path completo
                $storagePath = storage_path('app/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoice . '/');
                // Verificamos la modalidad para darle nombre al archivo
                if ($codigoModalidad == 1) {
                    // Si es una factura de compra venta en zona franca
                    if ($tipo_factura_id == 1) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaCompraVentaNS.xml';
                        $xml = $storagePath . 'facturaElectronicaCompraVenta.xml';
                        $xsd = $storagePath . 'facturaElectronicaCompraVenta.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaCompraVenta.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaCompraVenta.pdf';
                    }
                    // Verificamos sector alquileres de bienes inmuebles
                    if ($tipo_factura_id == 2) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaAlquilerBienInmuebleNS.xml';
                        $xml = $storagePath . 'facturaElectronicaAlquilerBienInmueble.xml';
                        $xsd = $storagePath . 'facturaElectronicaAlquilerBienInmueble.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaAlquilerBienInmueble.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaAlquilerBienInmueble.pdf';
                    }
                    // Verificamos sector educativo
                    if ($tipo_factura_id == 11) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaSectorEducativoNS.xml';
                        $xml = $storagePath . 'facturaElectronicaSectorEducativo.xml';
                        $xsd = $storagePath . 'facturaElectronicaSectorEducativo.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaSectorEducativo.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaSectorEducativo.pdf';
                    }
                    // Verificamos sector hospedaje turistico
                    if ($tipo_factura_id == 16) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaHotelNS.xml';
                        $xml = $storagePath . 'facturaElectronicaHotel.xml';
                        $xsd = $storagePath . 'facturaElectronicaHotel.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaHotel.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaHotel.pdf';
                    }
                    // Verificamos sector hospitales y clinicas
                    if ($tipo_factura_id == 17) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaHospitalClinicaNS.xml';
                        $xml = $storagePath . 'facturaElectronicaHospitalClinica.xml';
                        $xsd = $storagePath . 'facturaElectronicaHospitalClinica.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaHospitalClinica.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaHospitalClinica.pdf';
                    }
                    // Verificamos sector telecomunicaciones
                    if ($tipo_factura_id == 22) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaTelecomunicacionNS.xml';
                        $xml = $storagePath . 'facturaElectronicaTelecomunicacion.xml';
                        $xsd = $storagePath . 'facturaElectronicaTelecomunicacion.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaTelecomunicacion.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaTelecomunicacion.pdf';
                    }
                    // Verificamos sector bonificaciones
                    if ($tipo_factura_id == 35) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaElectronicaCompraVentaBonNS.xml';
                        $xml = $storagePath . 'facturaElectronicaCompraVentaBon.xml';
                        $xsd = $storagePath . 'facturaElectronicaCompraVentaBon.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaElectronicaCompraVentaBon.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaElectronicaCompraVentaBon.pdf';
                    }
                }
                if ($codigoModalidad == 2) {
                    // Si es una factura de compra venta en zona franca
                    if ($tipo_factura_id == 1) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaCompraVentaNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaCompraVenta.xml';
                        $xsd = $storagePath . 'facturaComputarizadaCompraVenta.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaCompraVenta.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaCompraVenta.pdf';
                    }
                    // Verificamos sector alquileres de bienes inmuebles
                    if ($tipo_factura_id == 2) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaAlquilerBienInmuebleNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaAlquilerBienInmueble.xml';
                        $xsd = $storagePath . 'facturaComputarizadaAlquilerBienInmueble.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaAlquilerBienInmueble.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaAlquilerBienInmueble.pdf';
                    }
                    // Verificamos sector educativo
                    if ($tipo_factura_id == 11) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaSectorEducativoNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaSectorEducativo.xml';
                        $xsd = $storagePath . 'facturaComputarizadaSectorEducativo.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaSectorEducativo.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaSectorEducativo.pdf';
                    }
                    // Verificamos sector hospedaje turistico
                    if ($tipo_factura_id == 16) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaHotelNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaHotel.xml';
                        $xsd = $storagePath . 'facturaComputarizadaHotel.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaHotel.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaHotel.pdf';
                    }
                    // Verificamos sector hospitales y clinicas
                    if ($tipo_factura_id == 17) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaHospitalClinicaNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaHospitalClinica.xml';
                        $xsd = $storagePath . 'facturaComputarizadaHospitalClinica.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaHospitalClinica.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaHospitalClinica.pdf';
                    }
                    // Verificamos sector telecomunicaciones
                    if ($tipo_factura_id == 22) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaTelecomunicacionNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaTelecomunicacion.xml';
                        $xsd = $storagePath . 'facturaComputarizadaTelecomunicacion.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaTelecomunicacion.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaTelecomunicacion.pdf';
                    }
                    // Verificamos sector bonificaciones
                    if ($tipo_factura_id == 35) {
                        // Obtenemos el path completo de los archivos fuente
                        $xmlNS = $storagePath . 'facturaComputarizadaCompraVentaBonNS.xml';
                        $xml = $storagePath . 'facturaComputarizadaCompraVentaBon.xml';
                        $xsd = $storagePath . 'facturaComputarizadaCompraVentaBon.xsd';
                        $qr = $storagePath . 'qr.png';
                        // Obtenemos el path de los PDF
                        $publicFileA4 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A4/facturaComputarizadaCompraVentaBon.pdf';
                        $publicFileA7 = '/storage/attachments/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoiceId . '/A7/facturaComputarizadaCompraVentaBon.pdf';
                    }
                }
            }
            // Ahora eliminamos los archivos generados
            // a excepcion de los publicos que no tiene sentido eliminarlos
            // Vemos si es zofra o no, que es lo mas importante
            // Eliminamos los archivos fuente de la factura
            if (is_writable($xmlNS)) {
                unlink($xmlNS);
            }
            if (is_writable($xml)) {
                unlink($xml);
            }
            if (is_writable($xsd)) {
                unlink($xsd);
            }
            if (is_writable($qr)) {
                unlink($qr);
            }
            if (is_writable($publicFileA4)) {
                unlink($publicFileA4);
            }
            if (is_writable($publicFileA7)) {
                @unlink($publicFileA7);
            }
            // Duerme 2 segundos
            sleep(2);
            // Ahora rehacemos los archivos XML, XSD, QR y volvemos a firmar
            $this->createthexmlfilefrominvoice($invoiceId, 0, $bolivianInvoice->codigo_sucursal, false, $codigoModalidad, $tipo_factura_id);
            // retornamos la informacion recibida
            return response()->json(
                [
                    'status'    =>  'success',
                    'datacufd'  =>  $dataForCufd,
                    'cuf'       =>  $cuf
                ],
                200
            );
        } else {
            return response()->json(
                [
                    'status'  =>  'fail',
                    'message' =>  'The sell does not exists'
                ],
                409
            );
        }
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function registeropticalworkorderproducts(Request $request)
    {
        // Recibimos las variables
        $provisional = $request->provisional;
        $frame_product_id = $request->frame_product_id;
        $product_id = $request->product_id;
        $product_code = $request->code;
        $product_fullname = $request->fullname;
        $price = $request->price;
        $quantity = $request->quantity;
        $currency_id = $request->currency_id;

        if ($quantity <= 0) {
            return response()->json(
                [
                    'status'  =>  'fail',
                    'message' =>  'quantity_must_be_greater_than_zero'
                ],
                409
            );
        }
        $discount = 0;
        $total = $price * $quantity;
        $numeroSerie = $frame_product_id;
        $users_sid = $this->getusersid();
        $global_branch_office_id = $this->getbranchoffice();
        $sell_id = null;
        // Ahora registramos en sivir sell sold
        try {
            $newSold = SivirSellSold::create([
                'relative'                  => Str::uuid()->toString(),
                'users_sid'                 => $users_sid,
                'global_branch_office_id'   => $global_branch_office_id,
                'provisional'               => $provisional,
                'sell_id'                   => $sell_id,
                'product_id'                => $product_id,
                'product_code'              => $product_code,
                'product_fullname'          => $product_fullname,
                'price'                     => $price,
                'quantity'                  => $quantity,
                'total_price'               => $total,
                'discount'                  => $discount,
                'numeroSerie'               => $numeroSerie,
                'status'                    => 'A',
                'created_at'                => date("Y-m-d H:i:s")
            ]);

            // Register Payment Way Logic
            // Calculate total for this provisional
            $totalSum = SivirSellSold::where('provisional', $provisional)
                ->where('global_branch_office_id', $global_branch_office_id)
                ->where('status', 'A')
                ->sum('total_price');

            // Check if payment way exists
            $existingPaymentWay = SivirSellPaymentWay::where('provisional', $provisional)
                ->where('global_branch_office_id', $global_branch_office_id)
                ->where('status', 'A')
                ->first();

            if ($existingPaymentWay) {
                $existingPaymentWay->update([
                    'ammount' => $totalSum,
                    'users_sid' => $users_sid,
                    'currency_id' => $currency_id ?? 1, // Default or request currency
                    'updated_at' => date("Y-m-d H:i:s")
                ]);
            } else {
                SivirSellPaymentWay::create([
                    'users_sid'                 =>  $users_sid,
                    'global_branch_office_id'   =>  $global_branch_office_id,
                    'sell_id'                   =>  null,
                    'provisional'               =>  $provisional,
                    'payment_id'                =>  1, // Default Cash
                    'payment_data'              =>  null,
                    'payment_date'              =>  null,
                    'ammount'                   =>  $totalSum,
                    'currency_id'               =>  $currency_id ?? 1,
                    'status'                    =>  'A',
                    'created_at'                =>  date("Y-m-d H:i:s")
                ]);
            }

            return response()->json(
                [
                    'status'    =>  'success',
                    'message'   =>  $newSold
                ],
                200
            );
        } catch (\Exception $e) {
            return response()->json(
                [
                    'status'  =>  'fail',
                    'message' =>  'Error saving sell sold: ' . $e->getMessage()
                ],
                500
            );
        }
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function makesell(Request $request)
    {
        // Inicializamos variables en nulo
        $nombreEstudiante = null;
        $periodoFacturado = null;
        $external = null;
        // El numero de la factura siguiente
        $nextSellInvoice    = new SivirSellInvoice();
        // El numero de la venta siguiente
        $nextSell           = new SivirSell();
        // Verificamos si es una factura CAFC
        $cafc = null;
        // Si el valor es enviado
        if (isset($request->cafc)) {
            $cafc = $request->cafc;
            // The invoice date time and milliseconds
            $milliseconds = rand(100, 999);
            $datetimev = Carbon::parse($request->datetimev)->format("Y-m-d H:i:s");
        } else {
            // The invoice date time and milliseconds
            $milliseconds = rand(100, 999);
            $datetimev = date("Y-m-d H:i:s");
        }
        // Venta por Excepcion
        $porExcepcion   = $request->codigoExcepcion;
        // Adicionamos la información basica para cualquier registro
        $request->merge(
            [
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice()
            ]
        );
        // Obtenemos la informacion de la orden de production de optica si existe
        $optical_work_order_id = isset($request->optical_work_order_id) ? $request->optical_work_order_id : null;
        // Obtenemos informacion de la facturacion
        $bolivianInvoice = SivirBolivianInvoice::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())->first();
        // Informacion obtenida de la facturacion boliviana
        $codigoModalidad    = $bolivianInvoice['codigo_modalidad'];
        $tipo_factura_id    = $request->tipo_factura_id;
        // Guardamos el tipo de emision
        $tipoEmision        = $request->tipoEmision;
        // El nit conjunto si hubiera
        $nitConjunto = isset($request->nitConjunto) ? $request->nitConjunto : null;
        // Primero vemos la informacion del cliente (CLIENTES)
        // Si el relative del customer es nulo entonces no existe el cliente
        // si el cliente no existe debemos registrarlo
        if ($request->customerrelative == null) {
            // Verificamos si este caso especial ya se ha registrado
            if (PortfolioCustomers::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                ->where('document_number', $request->document_number)->where('first_name', $request->fullname)->exists()
            ) {
                // Obtenemos la informacion ya registrada del cliente
                $portfolioCustomers = PortfolioCustomers::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('document_number', $request->document_number)->where('first_name', $request->fullname)->get()->first();
                // Adicionamos a las variables el relative del cliente
                $request->merge(['customerrelative' => $portfolioCustomers->relative]);
                // Actualizamos la informacion del cliente
                PortfolioCustomers::where('relative', $portfolioCustomers->relative)
                    ->update(
                        [
                            'phones'        =>  isset($request->phones) ? $request->phones : null,
                            'email'         =>  isset($request->email) ? $request->email : null,
                            'references'    =>  isset($request->references) ? $request->references : null,
                        ]
                    );
            } else {
                // Verificamos el codigo del cliente
                if ($request->document_number == "99002") {
                    $customer_type_id = 3;
                } elseif ($request->document_number == "99003") {
                    $customer_type_id = 4;
                } else {
                    $customer_type_id = 1;
                }
                // Relative solo para el cliente
                $customer_relative = Str::uuid()->toString();
                // En caso de no existir registramos el nuevo cliente
                // que para este unico caso es Sin nombre y nit 0
                PortfolioCustomers::create(array(
                    'relative'                  =>      $customer_relative,
                    'users_sid'                 =>      $request->users_sid,
                    'global_branch_office_id'   =>      $request->global_branch_office_id,
                    'customer_type_id'          =>      $customer_type_id,
                    'code'                      =>      0,
                    'first_name'                =>      $request->fullname,
                    'middle_name'               =>      null,
                    'last_name'                 =>      null,
                    'country_id'                =>      27, // Magic number for Bolivia
                    'document_type'             =>      $request->document_type,
                    'document_number'           =>      $request->document_number,
                    'customer_complemento'      =>      $request->complemento,
                    'email'                     =>      $request->email,
                    'social_media'              =>      null,
                    'phones'                    =>      isset($request->phones) ? $request->phones : null,
                    'address'                   =>      null,
                    'references'                =>      isset($request->references) ? $request->references : null,
                    'photo'                     =>      null,
                    'status'                    =>      'A',
                    'created_at'                =>      date("Y-m-d H:i:s")
                ));
                // Adicionamos a las variables el relative del cliente
                $request->merge(['customerrelative' => $customer_relative]);
            }
        } else {
            // Actualizamos la informacion del cliente
            PortfolioCustomers::where('relative', $request->customerrelative)
                ->update(
                    [
                        'phones'        =>  isset($request->phones) ? $request->phones : null,
                        'email'         =>  isset($request->email) ? $request->email : null,
                        'references'    =>  isset($request->references) ? $request->references : null,
                    ]
                );
        }
        // CANTIDADES
        // Verificamos si los productos tienen cantidades disponibles
        $checkStock = $this->checkStockAvailable($request->products);
        // Si el retorno es falso, la operacion termina
        if (!$checkStock) {
            // Si la cantidad que hay en stock es inferior a la necesaria
            // entonces devolvemos un mensaje de cantidad insuficiente
            return response()->json(
                [
                    'status'    =>      'fail',
                    'message'   =>      'Los productos no tienen cantidades suficiente en stock',
                ],
                429
            );
        }
        // La cantidad en stock es superior o igual a la cantidad requerida (VENTA)
        // Como sabemos que el stock no va a fallarnos, entonces iniciamos con la venta
        // Primero actualizamos la informacion del producto en sell sold en caso de que
        // se haya modificado los precios debido al tipo de cambio y la moneda
        $sell_relative = Str::uuid()->toString();
        // Registramos la nueva venta
        $newSell = SivirSell::create(array(
            'relative'                  =>      $sell_relative,
            'id'                        =>      $nextSell->next(),
            'users_sid'                 =>      $request->users_sid,
            'global_branch_office_id'   =>      $request->global_branch_office_id,
            'optical_work_order_id'     =>      $optical_work_order_id,
            'sellpoint_id'              =>      $request->sellpoint,
            'payment_type'              =>      $request->payment,
            'payment_detail'            =>      $request->payment_detail,
            'customer_id'               =>      $request->customerrelative,
            'document_type'             =>      $request->document_type,
            'customer_full_name'        =>      $request->fullname,
            'customer_nit'              =>      $request->document_number,
            'customer_complemento'      =>      $request->complemento,
            'customer_email'            =>      $request->email,
            'discount_all_products'     =>      number_format($request->totaldiscount, 2, ".", ""),
            'descuentoAdicional'        =>      number_format($request->descuentoAdicional, 2, ".", ""),
            'discount_total'            =>      number_format($request->totaldiscount + $request->descuentoAdicional, 2, ".", ""),
            'total'                     =>      number_format($request->total, 2, ".", ""),
            'currency_id'               =>      $request->currency,
            'exchange_used'             =>      $request->exchange,
            'codigoExcepcion'           =>      $porExcepcion,
            'medical_prescription_detail' => (isset($request->medical_prescription_detail)) ? $request->medical_prescription_detail : null,
            'sended'                    =>      'F',
            'date_movement'             =>      Carbon::parse($datetimev)->format("Y-m-d"),
            'status'                    =>      'A',
            'created_at'                =>      $datetimev
        ));
        // Informacion del punto de venta
        $sellPoint = SellPoint::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
            ->where('relative', $request->sellpoint)->get()->first();
        // El almacen permitido
        $warehouse = $sellPoint->warehouses_allowed;
        // Obtenemos el ID de la nueva venta
        $sell_id = $newSell->id;
        // Variaciones en caso de ser hotel o servicio hotelero
        if ($tipo_factura_id == 6 || $tipo_factura_id == 16) {
            // Verificamos que cada producto tenga suficiente en su inventario (PRODUCTOS)
            // Para poder realizar una bajada de sus cantidades
            // Recorremos los productos encontrados y obtenemos cada producto
            foreach ($request->products as $data) {
                // Actualizamos la informacion del producto adicionado a la compra
                // Y modificamos el precio de venta, la cantidad, el total y el descuento
                // Adicionalmente quitamos el valor de provisional a nulo para que esto
                // no nos salga en otra venta del mismo usuario
                SivirSellSold::where('provisional', $request->provisional)
                    ->where('product_id', $data['product_id'])->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('status', 'A')->update(
                        array(
                            'users_sid'     =>      $this->getusersid(),
                            'sell_id'       =>      $sell_id,
                            'provisional'   =>      null
                        )
                    );
                // Actualizamos la forma de pago de provisional, y la integramos con la
                // nueva venta generada
                SivirSellPaymentWay::where('status', 'A')
                    ->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('provisional', $request->provisional)
                    ->update(
                        [
                            'users_sid'     =>      $this->getusersid(),
                            'sell_id'       =>      $sell_id,
                            'provisional'   =>      null,
                            'updated_at'    =>      date("Y-m-d H:i:s")
                        ]
                    );
                // Ahora actualizamos el descuento adicional
                if (SivirSellAditionalDiscount::where('status', 'A')
                    ->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('provisional', $request->provisional)
                    ->exists()
                ) {
                    // Actualizamos el descuento adicional
                    SivirSellAditionalDiscount::where('status', 'A')
                        ->where('global_branch_office_id', $this->getbranchoffice())
                        ->where('provisional', $request->provisional)
                        ->update(
                            [
                                'users_sid'     =>      $this->getusersid(),
                                'sell_id'       =>      $sell_id,
                                'provisional'   =>      null,
                                'updated_at'    =>      date("Y-m-d H:i:s")
                            ]
                        );
                }
                // Una vez que hemos actualizado la informacion nos ocupamos
                // del movimiento del producto como el kardex, el stock y el historial
                if ($request->inventorymethod != null) {
                    // Realizamos el metodo que tenemos en el POST
                    $this->makeTheMethod($data['product_id'], $data['quantity'], $sell_id, $data['price'], $request->currency, $request->inventorymethod, $warehouse);
                } else {
                    // Si no tenemos el metodo efectivo
                    return response()->json(
                        [
                            'status'    =>      'fail',
                            'message'   =>      'No encontramos el metodo correcto',
                        ],
                        429
                    );
                }
            }
        } else {
            // Verificamos que cada producto tenga suficiente en su inventario (PRODUCTOS)
            // Para poder realizar una bajada de sus cantidades
            // Recorremos los productos encontrados y obtenemos cada producto
            foreach ($request->products as $data) {
                // Actualizamos la informacion del producto adicionado a la compra
                // Y modificamos el precio de venta, la cantidad, el total y el descuento
                // Adicionalmente quitamos el valor de provisional a nulo para que esto
                // no nos salga en otra venta del mismo usuario
                SivirSellSold::where('provisional', $request->provisional)
                    ->where('product_id', $data['product_id'])->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('status', 'A')->update(
                        array(
                            'users_sid'     =>      $this->getusersid(),
                            'sell_id'       =>      $sell_id,
                            'price'         =>      $data['price'],
                            'quantity'      =>      $data['quantity'],
                            'total_price'   =>      number_format($data['total_price'], 2, ".", ""),
                            'discount'      =>      number_format($data['discount'], 2, ".", ""),
                            'provisional'   =>      null
                        )
                    );
                // Actualizamos la forma de pago de provisional, y la integramos con la
                // nueva venta generada
                SivirSellPaymentWay::where('status', 'A')
                    ->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('provisional', $request->provisional)
                    ->update(
                        [
                            'users_sid'     =>      $this->getusersid(),
                            'sell_id'       =>      $sell_id,
                            'provisional'   =>      null,
                            'updated_at'    =>      date("Y-m-d H:i:s")
                        ]
                    );
                // Ahora actualizamos el descuento adicional
                if (SivirSellAditionalDiscount::where('status', 'A')
                    ->where('global_branch_office_id', $this->getbranchoffice())
                    ->where('provisional', $request->provisional)
                    ->exists()
                ) {
                    // Actualizamos el descuento adicional
                    SivirSellAditionalDiscount::where('status', 'A')
                        ->where('global_branch_office_id', $this->getbranchoffice())
                        ->where('provisional', $request->provisional)
                        ->update(
                            [
                                'users_sid'     =>      $this->getusersid(),
                                'sell_id'       =>      $sell_id,
                                'provisional'   =>      null,
                                'updated_at'    =>      date("Y-m-d H:i:s")
                            ]
                        );
                }
                // Una vez que hemos actualizado la informacion nos ocupamos
                // del movimiento del producto como el kardex, el stock y el historial
                if ($request->inventorymethod != null) {
                    // Realizamos el metodo que tenemos en el POST
                    $this->makeTheMethod($data['product_id'], $data['quantity'], $sell_id, $data['price'], $request->currency, $request->inventorymethod, $warehouse);
                } else {
                    // Si no tenemos el metodo efectivo
                    return response()->json(
                        [
                            'status'    =>      'fail',
                            'message'   =>      'No encontramos el metodo correcto',
                        ],
                        429
                    );
                }
            }
        }
        // Verificamos los documentos adjuntos
        if (isset($request->attachments)) {
            // Subimos el o los archivos
            $this->uploadandsaveattachments($request->attachments, $sell_id);
        }
        // Tenemos que restar los saldos de las GIFT-CARD y los CUPONES
        $this->updategiftcardandcoupons($sell_id);
        // Obtenemos la informacion necesaria del sistema para ingresar una factura
        $obtenerCuis = SoapCuis::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('cuis_expiration_datetime', '>', date("Y-m-d H:i:s"))
            ->where('sell_point_id', $request->sellpoint)
            ->orderBy('created_at', 'DESC')->get()->first();
        // Buscamos obtener el cuis con los datos obtenidos
        $cuis = $obtenerCuis->cuis;
        // Obtenemos el ultimo CUFD valido segun fecha y hora
        $lastValidCufd = $this->getlastvalidcufdarounddate($datetimev, $request->sellpoint);
        // Ahora obtenemos el CUFD para esta venta
        $cufd = $lastValidCufd->codigo_cufd;
        // Informacion que hemos obtenido de la misma venta
        $codigoControl = $lastValidCufd->codigo_control;
        // Verificamos el tipo de la factura
        if ($tipo_factura_id == 11 || $tipo_factura_id == 46 || $tipo_factura_id == 2 || $tipo_factura_id == 42) {
            if ($tipo_factura_id == 2 || $tipo_factura_id == 42) {
                $periodoFacturado = isset($request->periodoFacturado) ? $request->periodoFacturado : null;
            }
            if ($tipo_factura_id == 11 || $tipo_factura_id == 46) {
                $nombreEstudiante = isset($request->nombreEstudiante) ? $request->nombreEstudiante : null;
                $periodoFacturado = isset($request->periodoFacturado) ? $request->periodoFacturado : null;
                $external = isset($request->external) ? $request->external : null;
            }
        } else {
            // Verificamos si esta permitido los alumnos
            if (config('app.show_student_data') && config('app.show_student_data') == true) {
                $nombreEstudiante = isset($request->nombreEstudiante) ? $request->nombreEstudiante : null;
            } else {
                $nombreEstudiante = null;
            }
            $periodoFacturado = null;
        }
        // Telecomunicaciones y telecomunicaciones ZF 22 y 49
        if ($tipo_factura_id == 22 || $tipo_factura_id == 49) {
            $nitConjunto = isset($request->nitConjunto) ? $request->nitConjunto : null;
        } else {
            $nitConjunto = null;
        }
        // Hoteles y hospedaje
        if ($tipo_factura_id == 6 || $tipo_factura_id == 16) {
            $hospedaje = isset($request->hospedaje) ? $request->hospedaje : null;
        } else {
            $hospedaje = null;
        }
        // Hospitales y clinicas
        if ($tipo_factura_id == 17 || $tipo_factura_id == 50) {
            $modalidadServicio = isset($request->modalidadServicio) ? $request->modalidadServicio : null;
        } else {
            $modalidadServicio = null;
        }
        // Verificamos zona militar
        if (config('app.show_military_data') && config('app.show_military_data') == true) {
            // Como es true debemos actualizar el dato como venta
            SivirSellInvoiceMilitary::where('provisional', $request->provisional)
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('status', 'A')->update(
                    array(
                        'users_sid'     =>      $this->getusersid(),
                        'sell_id'       =>      $sell_id,
                        'provisional'   =>      null
                    )
                );
        }
        // Condicion de zofra
        $zofraSave = $this->getzofraornot($request->tipo_factura_id);
        // Ahora emitimos la factura para la venta realizada
        $array_invoice = [
            'relative'                  =>      Str::uuid()->toString(),
            'id'                        =>      $nextSellInvoice->next(),
            'users_sid'                 =>      $request->users_sid,
            'global_branch_office_id'   =>      $request->global_branch_office_id,
            'sell_id'                   =>      $sell_id,
            'sellpoint_id'              =>      $request->sellpoint,
            'payment_type'              =>      $request->payment,
            'payment_detail'            =>      $request->payment_detail,
            'cuis'                      =>      $cuis,
            'cufd'                      =>      $cufd,
            'cafc'                      =>      $cafc,
            'codigo_control'            =>      $codigoControl,
            'cuf'                       =>      null,
            'legend'                    =>      $bolivianInvoice['leyenda'],
            'law'                       =>      $bolivianInvoice['ley'],
            'zofra'                     =>      $zofraSave,
            'nitConjunto'               =>      $nitConjunto,
            'modalidadServicio'         =>      $modalidadServicio,
            'numeroParteRecepcion'      =>      $request->numeroParteRecepcion,
            'nombreEstudiante'          =>      $nombreEstudiante,
            'periodoFacturado'          =>      $periodoFacturado,
            'external'                  =>      $external,
            'tipo_factura_id'           =>      $request->tipo_factura_id,
            'tipo_emision'              =>      $tipoEmision,
            'codigo_sucursal'           =>      $bolivianInvoice['codigo_sucursal'],
            'hospedaje'                 =>      $hospedaje,
            'estado'                    =>      'V',
            'status'                    =>      'A',
            'created_at'                =>      $datetimev,
            'milliseconds'              =>      $milliseconds
        ];
        // Registramos la nueva factura
        $invoice = SivirSellInvoice::create($array_invoice);
        // Obtenemos el codigo del punto de venta
        $sellInvoice = SivirSellInvoice::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $invoice->id)->with(['sellpoint'])->get()->first();
        // Solicitamos toda la informacion para generar el cufd
        $dataForCufd = $this->getalldataforcufd($sellInvoice, $tipoEmision);
        // Corremos la funcion que genera el CUF
        $cuf = $this->generateCufd($dataForCufd);
        // Actualizamos la factura
        SivirSellInvoice::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $invoice->id)->update(array('cuf' => $cuf));
        // Obtenemos unicamente el movimiento en efectivo
        $cashTotal = $this->getcashpaymentonsell($sell_id);
        // Si optical_work_order_id existe, se debe descontar el down_payment
        if ($optical_work_order_id != null) {
            // Obtenemos la informacion 
            $optical = SivirOpticalWorkOrders::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('relative', $optical_work_order_id)->first();
            // Obtenemos el down payment
            $down_payment = $optical->down_payment;
            // Descontamos del total
            if ($down_payment > 0) {
                $cashTotal = $cashTotal - $down_payment;
            }
        }
        // Ahora realizamos el movimiento de monto en la caja
        $array_sellpoint_movement = [
            'relative'                  =>      Str::uuid()->toString(),
            'users_sid'                 =>      $request->users_sid,
            'global_branch_office_id'   =>      $request->global_branch_office_id,
            'sellpoint_id'              =>      $request->sellpoint,
            'date_movement'             =>      date("Y-m-d"),
            'type'                      =>      'I',
            'amount'                    =>      number_format($cashTotal, 2, ".", ""),
            'currency_id'               =>      $request->currency,
            'reason'                    =>      'V:' . $sell_id,
            'status'                    =>      'A',
            'created_at'                =>      date("Y-m-d H:i:s")
        ];
        // Confirmamos los posibles servicios existentes
        SivirServicePeriodsPaymentsMade::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('provisional', $request->provisional)
            ->update(
                [
                    'sell_id'       =>  $sell_id,
                    'provisional'   =>  NULL
                ]
            );
        // Registramos el movimiento de cajas
        // No necesitamos obtener información de lo registrado
        SellPointMovement::create($array_sellpoint_movement);
        // Ahora vemos los pagos posteriores
        $this->getpaymentpendingonsell($sell_id, $request->sellpoint, 6);
        // Creamos el archivo XML
        $fileGenerated = $this->createthexmlfilefrominvoice($invoice->id, $porExcepcion, $bolivianInvoice['codigo_sucursal'], false, $codigoModalidad, $tipo_factura_id);
        // Verificamos si la factura fue emitida fuera de línea
        if ($tipoEmision == 2) {
            // Verificamos si la notificación 'validated_invoice' está activa
            $notificationsController = new SivirNotificationsController();
            // Verificamos
            $isNotificationEnabled = $notificationsController->checkFlagActive(
                $this->getbranchoffice(),
                'offline_invoice'
            );

            if ($isNotificationEnabled) {

                // Buscamos el código de la moneda seleccionada
                $currencyCode = 'BOB'; // Valor por defecto

                foreach ($this->getcachedcurrency() as $currency) {
                    if ($currency['codigoClasificador'] == $request->currency) {
                        $currencyCode = $currency['code'];
                        break;
                    }
                }

                // Obtenemos la forma de pago
                $allpayments = CatalogsSivir::where('value', $request->payment)->where('catalog_code', 'PAYMENT')->where('global_branch_office_id', $this->getbranchoffice())->first();
                // Obtenemos la empresa
                $branches = LicenseServer::where('status', 'A')->where('license', $this->getbranchoffice())->with(['branchessivir'])->first();
                // Asignamos las variables
                $enterprise = $branches['branchessivir']['enterprise'];
                $branch = $branches['branchessivir']['branch_office'];
                // Ante titulo
                $prevTitle = "Empresa: {$enterprise}, Sucursal: {$branch} \n";
                // Creamos el título y mensaje
                $titulo = $prevTitle . "Se ha emitido la factura ({$invoice->id}) fuera de línea.";
                $monto = number_format($request->total, 2, ".", "");
                $mensaje = "Factura fuera de línea: ({$invoice->id}) - emitida al cliente: {$request->fullname} por un monto total de: {$monto} - ({$currencyCode}). Usuario: {$this->getusersemail()}, forma de pago: {$allpayments->label}";

                // Enviamos la notificación usando Job asincrónico
                SendRemoteNotificationJob::dispatch(
                    $this->getbranchoffice(),
                    $this->getusersid(),
                    $titulo,
                    $mensaje
                );
            }
        }
        // Finalizado el procedimiento debemos devolver la informacion obtenida
        return response()->json(
            [
                'status'    =>      'success',
                'invoice'   =>      $invoice->id,
                'sell'      =>      $sell_id,
                'bi'        =>      $bolivianInvoice,
                'cm'        =>      $codigoModalidad,
                'file'      =>      $fileGenerated
            ],
            200
        );
    }

    /**
     * @param $attachments
     * @param $sell_id
     * @return bool
     */
    public function uploadandsaveattachments($attachments, $sell_id)
    {
        // Subimos la imagen
        $files = UploadFile::uploadFile($attachments, [], 'storage/attachments/', '0775');
        // Ahora guardamos los archivos
        SivirSellAttachments::create(
            [
                'relative'                  =>      Str::uuid()->toString(),
                'users_sid'                 =>      $this->getusersid(),
                'global_branch_office_id'   =>      $this->getbranchoffice(),
                'sell_id'                   =>      $sell_id,
                'attachments'               =>      $files,
                'status'                    =>      'A',
                'created_at'                =>      date("Y-m-d H:i:s"),
                'updated_at'                =>      null
            ]
        );
        // Retornamos verdadero
        return true;
    }

    /**
     * @param $sell_id
     * @param int $gift
     * @param int $vales
     * @return bool
     */
    private function updategiftcardandcoupons($sell_id, $gift = 27, $vales = 4)
    {
        // Verificamos si en las formas de pago existe la GIFT-CARD
        if (SivirSellPaymentWay::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('sell_id', $sell_id)
            ->where('payment_id', $gift)->exists()
        ) {
            // Obtenemos el primero
            $pw = SivirSellPaymentWay::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('sell_id', $sell_id)
                ->where('payment_id', $gift)
                ->get()->first();
            // El codigo del gift-card
            $giftCardCode = $pw->payment_data;
            $giftCardAmount = $pw->ammount;
            // Entonces le bajamos el balance
            SivirGiftCard::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('gc_serial', $giftCardCode)
                ->decrement('balance', $giftCardAmount);
            // Retornamos positivo
            return true;
        }
        // Verificamos si en las formas de pago existe los cupones
        if (SivirSellPaymentWay::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('sell_id', $sell_id)
            ->where('payment_id', $vales)->exists()
        ) {
            // Obtenemos el primero
            $pw = SivirSellPaymentWay::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('sell_id', $sell_id)
                ->where('payment_id', $vales)
                ->get()->first();
            // El codigo del gift-card
            $couponCode = $pw->id;
            $couponAmount = $pw->ammount;
            // Entonces le bajamos el balance
            SivirCoupons::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('id', $couponCode)
                ->decrement('amount', $couponAmount);
            // Actualizamos su estado
            SivirCoupons::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('id', $couponCode)
                ->update(
                    [
                        'users_sid'         =>  $this->getusersid(),
                        'coupon_status'     =>  'U',
                        'updated_at'        =>  date("Y-m-d H:i:s")
                    ]
                );
            return true;
        }
        return true;
    }

    /**
     * @param $invoice
     * @param int $tipoEmision
     * @return array
     */
    private function getalldataforcufd($invoice, $tipoEmision = 1)
    {
        // Factura compra/venta zofra
        $codigoDocumentoSector  = $invoice['tipo_factura_id'];
        // El tipo de factura
        $tipo_factura           = $this->gettipofactura($codigoDocumentoSector);       /* 1:factura con dcf. 2:factura sin dcf. 3:Documento ajuste. */
        // Fecha emision
        $emision                = $tipoEmision;       /* 1: Online 2: Offline 3: Masiva  */
        // Obtenemos informacion de la facturacion
        $bolivianInvoice        = $this->getbolivianinvoice();
        // Informacion obtenida de la facturacion boliviana
        $codigoModalidad        = $bolivianInvoice['codigo_modalidad'];
        $codigoSucursal         = $bolivianInvoice['codigo_sucursal'];
        $nit                    = $bolivianInvoice['nit'];
        // Ahora retornamos la data
        return [
            'nit_emisor'              =>  (string)$nit,
            'fecha_hora'              =>  (string)$invoice['created_at'] . "." . $invoice['milliseconds'],
            'sucursal'                =>  (string)$codigoSucursal,
            'modalidad'               =>  (string)$codigoModalidad,
            'tipo_emision'            =>  (string)$emision,
            'tipo_factura'            =>  (string)$tipo_factura,
            'tipo_documento_sector'   =>  (string)$codigoDocumentoSector,
            'num_factura'             =>  (string)$invoice['id'],
            'punto_venta'             =>  (string)$invoice['sellpoint']['codigo_punto_venta'],
            'cod_control'             =>  (string)$invoice['codigo_control'],
        ];
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getsellsold(Request $request)
    {
        $request->merge(
            [
                "email"     => "ohkmalganis@gmail.com",
                "password"  => base64_decode("TWEhOWFuMXM="),
            ]
        );
        // Las credenciales
        $credentials = request(['email', 'password']);
        // Verificamos el branch
        $branch = isset($request->branch) ? $request->branch : '69abe0de-7812-41bd-9124-6a7238aee7d1';
        // El correo
        $email = $request->email;
        // El Auth
        User::where('email', $email)->update(array('global_branch_office_id' =>  $branch));
        // Hacemos el auth
        auth()->attempt($credentials);
        // Obtenemos
        $productsSoldInformation    =   SivirSellSold::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('sell_id', 5110)
            ->with(
                [
                    'product' => function ($q) {
                        $q->with(
                            [
                                'stock' => function ($q) {
                                    $q->with(['measurement']);
                                },
                                'homologated' => function ($q) {
                                    $q->with(['sincode']);
                                },
                                'price',
                                'category'
                            ]
                        );
                    },
                    'sell'
                ]
            )
            ->get();
        return response()->json(
            [
                'status'    =>  'success',
                'data'      =>  $productsSoldInformation,
                'br'        =>  $this->getbranchoffice()
            ],
            200
        );
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function makeatryforcufd()
    {
        $data = [
            'nit_emisor'              =>  (string)'4807414019',
            'fecha_hora'              =>  (string)'2022-10-19 13:59:27.240',
            'sucursal'                =>  (string)0,
            'modalidad'               =>  (string)2,
            'tipo_emision'            =>  (string)1,
            'tipo_factura'            =>  (string)1,
            'tipo_documento_sector'   =>  (string)1,
            'num_factura'             =>  (string)147,
            'punto_venta'             =>  (string)0,
            'cod_control'             =>  (string)'6E129A14E8E6D74',
        ];
        return response()->json(
            $this->generateCufd($data),
            200
        );
    }

    /**
     * @param $invoice
     * @param bool $porExcepcion
     * @param int $codigo_sucursal
     * @param bool $whn
     * @param int $codigoModalidad
     * @param int $tipo_factura_id
     * @param bool $pdf
     * @return string
     */
    public function createthexmlfilefrominvoice($invoice, $porExcepcion = false, $codigo_sucursal = 0, $whn = true, $codigoModalidad = 1, $tipo_factura_id = 1, $pdf = true)
    {
        // Verificamos la licencia
        $license = $this->getbranchoffice();
        $completeFile = "";
        // Obtenemos informacion de la factura
        $invoiceInformation = SivirSellInvoice::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $invoice)->with(['sellpoint'])->get()->first();
        // El archivo
        $filenameNS = '';
        // Si es factura zofra o no
        if ($invoiceInformation['zofra'] == "Y") {
            //=========================
            // Creando el archivo .xml
            //=========================
            // Creamos el directorio de la sucursal
            Storage::disk('invoicezofra')->makeDirectory($license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoice);
            // Obtenemos el path completo
            $storagePath = storage_path('app/facturas/zofra/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoice . '/');
            // Verificamos la modalidad para darle nombre al archivo
            if ($codigoModalidad == 1) {
                // Si es una factura de compra venta en zona franca
                if ($tipo_factura_id == 5) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaZonaFrancaNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaZonaFrancaNS.xml';
                }
                // Factura Servicios Turístico y Hospedaje
                if ($tipo_factura_id == 6) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaServicioTuristicoHospedajeNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaServicioTuristicoHospedajeNS.xml';
                }
                // Si es una factura de tasa cero
                if ($tipo_factura_id == 8) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaTasaCeroNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaTasaCeroNS.xml';
                }
                // Si es una factura dutty free
                if ($tipo_factura_id == 10) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaDuttyFreeNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaDuttyFreeNS.xml';
                }
                // Verificamos sector alquileres
                if ($tipo_factura_id == 42) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaAlquilerZFNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaAlquilerZFNS.xml';
                }
                // Verificamos sector educativo
                if ($tipo_factura_id == 46) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaSectorEducativoZFNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaSectorEducativoZFNS.xml';
                }
                // Verificamos sector telecomunicaciones
                if ($tipo_factura_id == 49) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaTelecomunicacionZFNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaTelecomunicacionZFNS.xml';
                }
                // Verificamos sector hospitales y clinicas
                if ($tipo_factura_id == 50) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaHospitalClinicaZFNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaHospitalClinicaZFNS.xml';
                }
            }
            if ($codigoModalidad == 2) {
                // Si es una factura de compra venta en zona franca
                if ($tipo_factura_id == 5) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaZonaFrancaNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaZonaFrancaNS.xml';
                }
                // Factura Servicios Turístico y Hospedaje
                if ($tipo_factura_id == 6) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaServicioTuristicoHospedajeNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaServicioTuristicoHospedajeNS.xml';
                }
                // Si es una factura de tasa cero
                if ($tipo_factura_id == 8) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaTasaCeroNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaTasaCeroNS.xml';
                }
                // Si es una factura dutty free
                if ($tipo_factura_id == 10) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaDuttyFreeNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaDuttyFreeNS.xml';
                }
                // Verificamos sector alquileres
                if ($tipo_factura_id == 42) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaAlquilerZFNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaAlquilerZFNS.xml';
                }
                // Verificamos sector educativo
                if ($tipo_factura_id == 46) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaSectorEducativoZFNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaSectorEducativoZFNS.xml';
                }
                // Verificamos sector telecomunicaciones
                if ($tipo_factura_id == 49) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaTelecomunicacionZFNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaTelecomunicacionZFNS.xml';
                }
                // Verificamos sector hospitales y clinicas
                if ($tipo_factura_id == 50) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaHospitalClinicaZFNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaHospitalClinicaZFNS.xml';
                }
            }
            // Creamos el archivo con los permisos de escritura
            $FD = fopen($completeFile, "w+");
            // Actualizamos los permisos
            chmod($completeFile, 0775);
            // Escribimos el archivo
            $this->writexmlfile($FD, $invoice, $porExcepcion, $codigoModalidad);
            // Cerramos el archivo
            fclose($FD);
            // Escribimos el PDF
            if ($pdf) $this->makepdf($invoice, false);
        } else {
            //=========================
            // Creando el archivo .xml
            //=========================
            // Creamos el directorio de la sucursal
            Storage::disk('invoiceregular')->makeDirectory($license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoice);
            // Obtenemos el path completo
            $storagePath = storage_path('app/facturas/regular/' . $license . DIRECTORY_SEPARATOR . $codigo_sucursal . DIRECTORY_SEPARATOR . $invoice . '/');
            // Verificamos la modalidad para darle nombre al archivo
            if ($codigoModalidad == 1) {
                // Si es una factura de compra venta en zona franca
                if ($tipo_factura_id == 1) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaCompraVentaNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaCompraVentaNS.xml';
                }
                // Verificamos sector alquileres de bienes inmuebles
                if ($tipo_factura_id == 2) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaAlquilerBienInmuebleNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaAlquilerBienInmuebleNS.xml';
                }
                // Verificamos sector educativo
                if ($tipo_factura_id == 11) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaSectorEducativoNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaSectorEducativoNS.xml';
                }
                // Verificamos Factura de Hoteles
                if ($tipo_factura_id == 16) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaHotelNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaHotelNS.xml';
                }
                // Verificamos sector hospitales y clinicas
                if ($tipo_factura_id == 17) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaHospitalClinicaNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaHospitalClinicaNS.xml';
                }
                // Verificamos sector telecomunicaciones
                if ($tipo_factura_id == 22) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaTelecomunicacionNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaTelecomunicacionNS.xml';
                }
                // Verificamos sector bonificaciones
                if ($tipo_factura_id == 35) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaElectronicaCompraVentaBonNS.xml';
                    $completeFile = $storagePath . 'facturaElectronicaCompraVentaBonNS.xml';
                }
            }
            if ($codigoModalidad == 2) {
                // Si es una factura de compra venta en zona franca
                if ($tipo_factura_id == 1) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaCompraVentaNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaCompraVentaNS.xml';
                }
                // Verificamos sector alquileres de bienes inmuebles
                if ($tipo_factura_id == 2) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaAlquilerBienInmuebleNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaAlquilerBienInmuebleNS.xml';
                }
                // Verificamos sector educativo
                if ($tipo_factura_id == 11) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaSectorEducativoNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaSectorEducativoNS.xml';
                }
                // Verificamos Factura de Hoteles
                if ($tipo_factura_id == 16) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaHotelNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaHotelNS.xml';
                }
                // Verificamos sector hospitales y clinicas
                if ($tipo_factura_id == 17) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaHospitalClinicaNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaHospitalClinicaNS.xml';
                }
                // Verificamos sector comunicaciones
                if ($tipo_factura_id == 22) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaTelecomunicacionNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaTelecomunicacionNS.xml';
                }
                // Verificamos sector bonificaciones
                if ($tipo_factura_id == 35) {
                    // La ruta y el nombre del archivo
                    $filenameNS = 'facturaComputarizadaCompraVentaBonNS.xml';
                    $completeFile = $storagePath . 'facturaComputarizadaCompraVentaBonNS.xml';
                }
            }
            // Creamos el archivo con los permisos de escritura
            $FD = fopen($completeFile, "w+");
            // Actualizamos los permisos
            chmod($completeFile, 0775);
            // Escribimos el archivo
            $this->writexmlfile($FD, $invoice, $porExcepcion, $codigoModalidad);
            // Cerramos el archivo
            fclose($FD);
            // Escribimos el PDF
            if ($pdf) $this->makepdf($invoice, false);
        }
        if ($codigoModalidad == 1) {
            // Obtenemos el comportamiento del sistema
            $systemBehavior = $this->getsystembehavior();
            // Ahora firmamos el archivo XML
            $this->signxmlfile($invoiceInformation['zofra'], $invoice, $codigo_sucursal, $systemBehavior->privatekey, $systemBehavior->publickey, $filenameNS, str_replace("NS", "", $filenameNS), $this->getbranchoffice());
        }
        if ($codigoModalidad == 2) {
            // Renombramos el archivo
            $this->renamexmlfile($invoiceInformation['zofra'], $invoice, $codigo_sucursal, $filenameNS, str_replace("NS", "", $filenameNS), $this->getbranchoffice());
        }
        // Ahora retornamos los datos
        return $completeFile;
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function deleteemptysell(Request $request)
    {
        // Recibimos la venta
        $sellId = $request->sellid;
        // Ahora verificamos que realmente no tenga items
        if (SivirSellSold::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
            ->where('sell_id', $sellId)->exists()
        ) {
            // La venta tiene productos, no podemos eliminarla
            return response()->json(
                [
                    'status'    =>  'false',
                    'message'   =>  'No podemos eliminar la venta porque aun tiene productos'
                ],
                409
            );
        } else {
            // Como no tiene productos ahora procedemos a eliminar la venta
            SivirSell::where('status', 'A')
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('sended', 'C')->where('id', $sellId)->delete();
            // Ahora retornamos un mensaje de finalizado
            return response()->json(
                [
                    'status'    =>  'success'
                ],
                200
            );
        }
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function finishtheproforma(Request $request)
    {
        // Recibimos la venta
        $sellId = $request->id;
        // Adicionamos la información basica para cualquier registro
        $request->merge(
            [
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice()
            ]
        );
        // Ahora actualizamos la venta
        SivirSell::where('status', 'A')->where('global_branch_office_id', $this->getbranchoffice())
            ->where('sended', 'C')->where('id', $sellId)->update(
                [
                    'sended'                    =>      'P',
                    'date_movement'             =>      date("Y-m-d"),
                    'updated_at'                =>      date("Y-m-d H:i:s")
                ]
            );
        // Obtenemos la informacion de la empresa
        $enterprise = $this->getcachedenterprise();
        // Obtenemos la informacion de la venta
        $theCompleteSell = SivirSell::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $sellId)
            ->with(
                [
                    'branch',
                    'sellpoint',
                    'currency',
                    'products' => function ($q) {
                        $q->with(
                            [
                                'product' => function ($q) {
                                    $q->with(
                                        [
                                            'stock' => function ($q) {
                                                $q->with(['measurement']);
                                            },
                                            'homologated'
                                        ]
                                    );
                                }
                            ]
                        );
                    },
                    'sellpaymentway',
                    'aditionaldiscount'
                ]
            )
            ->orderBy('created_at', 'DESC')->get()->first();
        // Ahora obtenemos los datos de configuracion
        $configuration = Settings::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->with(['currency'])->get()->first();
        // Ahora obtenemos toda la informacion de la factura
        $bolivianInvoice = $this->getcachedfirstbolivianinvoice();
        // Ahora generamos el PDF
        // Ahora debemos genera el archivo de la proforma en la ubicacion publica
        $this->generateProforma($sellId, $enterprise, $theCompleteSell, $configuration, $bolivianInvoice);
        // Retornamos la informacion
        return response()->json(
            [
                'status'    =>      'success',
                'sell'      =>      $sellId
            ],
            200
        );
    }

    /**
     * @param $invoice
     * @param string $format
     * @param bool $whn
     */
    private function makepdf($invoice, $whn = true, $format = 'A4')
    {
        // El numero de la factura
        $invoiceId = $invoice;
        // Obtenemos la informacion de la empresa
        $enterprise = Enterprise::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->get()->first();
        // Obtenemos informacion directamente de la factura
        $invoiceInformation = SivirSellInvoice::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $invoice)->get()->first();
        // El numero de la venta
        $sellId = $invoiceInformation->sell_id;
        // Obtenemos la informacion de la venta
        $theCompleteSell = SivirSell::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('id', $sellId)
            ->with(
                [
                    'customer',
                    'branch',
                    'sellpoint',
                    'currency',
                    'products' => function ($q) {
                        $q->with(
                            [
                                'product' => function ($q) {
                                    $q->with(
                                        [
                                            'stock' => function ($q) {
                                                $q->with(['measurement']);
                                            },
                                            'homologated'
                                        ]
                                    );
                                }
                            ]
                        );
                    },
                    'sellpaymentway',
                    'aditionaldiscount',
                    'invoice'
                ]
            )
            ->orderBy('created_at', 'DESC')->get()->first();
        // Ahora obtenemos los datos de configuracion
        $configuration = Settings::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->with(['currency'])->get()->first();
        // Ahora obtenemos el comportamiento del sistema (No hace falta)
        $systemBehavior = $this->getcachedfirstsystembehavior();
        // Ahora obtenemos toda la informacion de la factura
        $bolivianInvoice = $this->getcachedfirstbolivianinvoice();
        // Verificamos el formato
        if ($format == 'A4') {
            // Ahora en el segundo formato
            $this->generateA4Pdf($invoiceId, $enterprise, $theCompleteSell, $configuration, $systemBehavior, $bolivianInvoice, $invoiceInformation->zofra);
        } else {
            // El formato A7
            $this->generateA7Pdf($invoiceId, $enterprise, $theCompleteSell, $configuration, $systemBehavior, $bolivianInvoice, $invoiceInformation->zofra);
        }
        // Ahora generamos el documento de salida
        if ($whn) {
            $this->generateWarehouseNote($sellId, $enterprise, $theCompleteSell, $configuration, $bolivianInvoice, $invoiceId);
        }
    }

    /**
     * @return mixed
     */
    private function getsystembehavior()
    {
        // Ahora obtenemos el comportamiento del sistema (No hace falta)
        return SivirSystemBehavior::where('status', 'A')
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->get()->first();
    }

    /**
     * @param $rate
     * @param $currency
     * @return bool
     */
    private function findtheexchangerate($rate, $currency)
    {
        if (is_array($rate)) {
            foreach ($rate as $data) {
                if ($data->id == $currency) {
                    return $data->exchange;
                }
            }
        } else {
            return false;
        }
        return false;
    }

    /**
     * @param $products
     * @return bool
     */
    private function checkStockAvailable($products)
    {
        // Recorremos los productos para verificar las cantidades
        foreach ($products as $data) {
            // Obtenemos el stock actual del producto
            $products_stock = ProductsStock::where('product_id', $data['product_id'])
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->with(['product'])
                ->where('status', 'A')->get()->first();
            // Debemos verificar la informacion
            if ($products_stock['product']['product_kind'] == 'PCV0') {
                return true;
            } else {
                // Verificamos si existe la cantidad que queremos
                if ($products_stock['quantity'] < $data['quantity']) {
                    // Si la cantidad que hay en stock es inferior a la necesaria
                    // entonces devolvemos un mensaje de cantidad insuficiente
                    return false;
                }
            }
        }
        // Si esta bien, devolvemos un positivo
        return true;
    }

    /**
     * @param $product_id
     * @param $quantity
     * @param $sellid
     * @param $price
     * @param $currency
     * @param string $method
     * @param string $warehouse
     * @return bool
     */
    private function makeTheMethod($product_id, $quantity, $sellid, $price, $currency, $method = "UEPS", $warehouse)
    {
        // Ultimos en entrar, primeros en salir
        // Primero obtenemos todos los lotes del producto
        // unicamente los lotes que tengan mas de 1 producto en cantidad
        if ($method == "UEPS") {
            $lotes = ProductsLot::where('status', 'A')->where('product_id', $product_id)
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->when($warehouse != '*', function ($query) use ($warehouse) {
                    $query->where('warehouse_id', $warehouse);
                })
                ->where('quantity', '>', '0')->orderBy('created_at', 'ASC')->get();
        }
        // Primeros en entrar, primeros en salir
        elseif ($method == "PEPS") {
            $lotes = ProductsLot::where('status', 'A')->where('product_id', $product_id)
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->when($warehouse != '*', function ($query) use ($warehouse) {
                    $query->where('warehouse_id', $warehouse);
                })
                ->where('quantity', '>', '0')->orderBy('created_at', 'DESC')->get();
        }
        // Primeros en entrar, primeros en perecer
        elseif ($method == "PEPP") {
            $lotes = ProductsLot::where('status', 'A')->where('product_id', $product_id)
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->when($warehouse != '*', function ($query) use ($warehouse) {
                    $query->where('warehouse_id', $warehouse);
                })
                ->where('quantity', '>', '0')->orderBy('expiration_date', 'DESC')->get();
        }
        // Ultimos en entrar primeros en perecer
        else {
            $lotes = ProductsLot::where('status', 'A')->where('product_id', $product_id)
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->when($warehouse != '*', function ($query) use ($warehouse) {
                    $query->where('warehouse_id', $warehouse);
                })
                ->where('quantity', '>', '0')->orderBy('expiration_date', 'ASC')->get();
        }
        // La cantidad original
        $originalQ = $quantity;
        // Si unicamente existe 1 lote activo, descontamos facilmente
        if ($lotes->count() == 1) {
            // Debemos disminuir la cantidad del lote
            // como tambien del historico del lote
            $productsLot = ProductsLot::where('product_id', $product_id)
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->when($warehouse != '*', function ($query) use ($warehouse) {
                    $query->where('warehouse_id', $warehouse);
                })
                ->where('relative', $lotes[0]['relative']);
            // Realizamos el decremento
            $productsLot->decrement('quantity', $quantity);
            // Obtenemos el nuevo stock
            $lot_product = $productsLot->get()->first();
            // Ahora guardamos el lote utilizado en el historico
            $array_sell_sold_lot_used = [
                'relative'                  =>  Str::uuid()->toString(),
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice(),
                'sell_id'                   =>  $sellid,
                'product_id'                =>  $product_id,
                'product_lot_id'            =>  $lot_product->relative,
                'lot'                       =>  $lot_product->lot,
                'quantity'                  =>  $quantity,
                'status'                    =>  'A',
                'created_at'                =>  date("Y-m-d H:i:s")
            ];
            // Ahora registramos la informacion
            SivirSellSoldLotUsed::create($array_sell_sold_lot_used);
            // Ahora ingresamos el lote en su historico
            // Primero creamos la variable con todos los datos
            $array_lot_history = [
                'relative'                  =>  Str::uuid()->toString(),
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice(),
                'product_id'                =>  $product_id,
                'lot'                       =>  $lot_product->lot,
                'warehouse_id'              =>  $lot_product->warehouse_id,
                'physical_location'         =>  $lot_product->physical_location,
                'measurement_id'            =>  $lot_product->measurement_id,
                'initial_quantity'          =>  $lot_product->initial_quantity,
                'quantity'                  =>  $lot_product->quantity,
                'unit_cost'                 =>  $lot_product->unit_cost,
                'currency_id'               =>  $lot_product->currency_id,
                'total_price'               =>  number_format($lot_product->unit_cost * $lot_product->quantity, 2, ".", ""),
                'expiration_date'           =>  $lot_product->expiration_date,
                'status'                    =>  'A',
                'created_at'                =>  date("Y-m-d H:i:s")
            ];
            // Registramos el historico del lote
            ProductsLotHistory::create($array_lot_history);
            // Ahora debemos actualizar el stock del producto
            $product_stock = ProductsStock::where('product_id', $product_id)
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('status', 'A');
            // Realizamos el decremento
            $product_stock->decrement('quantity', $quantity);
            // Obtenemos los datos del stock para ingresarlos al historico
            $stock_product = $product_stock->get()->first();
            // Y ahora debemos ingresar el historico del stock
            $array_stock_history = [
                'relative'                  =>  Str::uuid()->toString(),
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice(),
                'product_id'                =>  $product_id,
                'quantity'                  =>  $stock_product->quantity,
                'measurement_id'            =>  $stock_product->measurement_id,
                'price'                     =>  $price,
                'currency_id'               =>  $currency,
                'status'                    =>  'A',
                'created_at'                =>  date("Y-m-d H:i:s")
            ];
            // Realizamos el ingreso para el stock history
            ProductsStockHistory::create($array_stock_history);
            // Realizamos el kardex
            // Contatenamos la descripcion con la venta
            $detail = 'V:' . $sellid;
            // Llamamos a la funcion de kardex
            $this->makeKardex($product_id, $quantity, $stock_product->measurement_id, $detail, 'E', $lot_product->relative, $lot_product->warehouse_id);
        } elseif ($lotes->count() > 1) {
            // Los lotes los tenemos ordenados de manera ascendente
            // osea que primero nos va a mostrar el lote mas antiguo
            // Debemos recorrer los lotes e ir sacando la cantidad necesaria
            foreach ($lotes as $data) {
                // Ahora debemos verificar si la cantidad que existe
                // en el lote es suficiente para satisfacer el requerimiento
                if ($data['quantity'] >= $quantity) {
                    // Debemos disminuir la cantidad del lote correspondiente
                    // y asignamos la cantidad nueva
                    $this->discountLot($product_id, $quantity, $data['relative'], $sellid, true, $data['lot'], $data['relative']);
                    // Entonces rompemos el ciclo, ya no nos hace falta
                    // Ahora hacemos el historial y el kardex
                    $this->stockhistoryandkardex($product_id, $quantity, $price, $currency, $sellid, $data['relative'], $data['warehouse_id']);
                    // seguir recorriendo los lotes
                    break;
                } else {
                    // Debemos disminuir la cantidad del lote correspondiente
                    // y asignamos la cantidad nueva
                    $newQuantity = $this->discountLot($product_id, $quantity, $data['relative'], $sellid, false, $data['lot'], $data['relative']);
                    // Reasignamos el valor
                    $quantity = $newQuantity;
                    // Ahora hacemos el historial y el kardex
                    $this->stockhistoryandkardex($product_id, $quantity - $newQuantity, $price, $currency, $sellid, $data['relative'], $data['warehouse_id']);
                }
            }
        } else {
            return false;
        }
        return true;
    }

    /**
     * @param $product_id
     * @param $quantity
     * @param $price
     * @param $currency
     * @param $sellid
     */
    private function stockhistoryandkardex($product_id, $quantity, $price, $currency, $sellid, $lot_id = null, $warehouse_id = null)
    {
        // Ahora debemos actualizar el stock del producto
        $product_stock = ProductsStock::where('product_id', $product_id)
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('status', 'A');
        // Realizamos el decremento
        $product_stock->decrement('quantity', $quantity);
        // Obtenemos los datos del stock para ingresarlos al historico
        $stock_product = $product_stock->get()->first();
        // Y ahora debemos ingresar el historico del stock
        $array_stock_history = [
            'relative'                  =>  Str::uuid()->toString(),
            'users_sid'                 =>  $this->getusersid(),
            'global_branch_office_id'   =>  $this->getbranchoffice(),
            'product_id'                =>  $product_id,
            'quantity'                  =>  $stock_product->quantity,
            'measurement_id'            =>  $stock_product->measurement_id,
            'price'                     =>  $price,
            'currency_id'               =>  $currency,
            'status'                    =>  'A',
            'created_at'                =>  date("Y-m-d H:i:s")
        ];
        // Realizamos el ingreso para el stock history
        ProductsStockHistory::create($array_stock_history);
        // Realizamos el kardex
        // Contatenamos la descripcion con la venta
        $detail = 'V:' . $sellid;
        // Llamamos a la funcion de kardex
        $this->makeKardex($product_id, $quantity, $stock_product->measurement_id, $detail, 'E', $lot_id, $warehouse_id);
    }

    /**
     * @param $product_id
     * @param $quantity
     * @param $relative
     * @param $sellId
     * @param $oneItsEnough
     * @param $product_lot_id
     * @param $product_lot
     * @return mixed
     */
    private function discountLot($product_id, $quantity, $relative, $sellId, $oneItsEnough, $product_lot, $product_lot_id)
    {
        $qq = $quantity;
        // Obtenemos el lote y la cantidad previa
        $previousLotQiantity = ProductsLot::where('product_id', $product_id)
            ->where('global_branch_office_id', $this->getbranchoffice())
            ->where('relative', $relative)->get()->first();
        // Guardamos en una variable
        $previousQuantity = $previousLotQiantity->quantity;
        // Verificamos si con un lote nos vale
        if ($oneItsEnough) {
            // Debemos disminuir la cantidad del lote correspondiente
            ProductsLot::where('product_id', $product_id)
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('relative', $relative)->decrement('quantity', $quantity);
            // Ahora guardamos el lote utilizado en el historico
            $array_sell_sold_lot_used = [
                'relative'                  =>  Str::uuid()->toString(),
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice(),
                'sell_id'                   =>  $sellId,
                'product_id'                =>  $product_id,
                'product_lot_id'            =>  $relative,
                'lot'                       =>  $product_lot,
                'quantity'                  =>  $quantity,
                'status'                    =>  'A',
                'created_at'                =>  date("Y-m-d H:i:s")
            ];
            // Ahora registramos la informacion
            SivirSellSoldLotUsed::create($array_sell_sold_lot_used);
            // Ajustamos la nueva cantidad
            $quantity = 0;
        } else {
            // Debemos disminuir la cantidad del lote correspondiente
            ProductsLot::where('product_id', $product_id)
                ->where('global_branch_office_id', $this->getbranchoffice())
                ->where('relative', $relative)->decrement('quantity', $previousQuantity);
            // Ahora guardamos el lote utilizado en el historico
            $array_sell_sold_lot_used = [
                'relative'                  =>  Str::uuid()->toString(),
                'users_sid'                 =>  $this->getusersid(),
                'global_branch_office_id'   =>  $this->getbranchoffice(),
                'sell_id'                   =>  $sellId,
                'product_id'                =>  $product_id,
                'product_lot_id'            =>  $relative,
                'lot'                       =>  $product_lot,
                'quantity'                  =>  $previousQuantity,
                'status'                    =>  'A',
                'created_at'                =>  date("Y-m-d H:i:s")
            ];
            // Ahora registramos la informacion
            SivirSellSoldLotUsed::create($array_sell_sold_lot_used);
            // Ajustamos la nueva cantidad, tomando en cuenta que no fue suficiente
            // con el lote anterior
            $quantity = $quantity - $previousQuantity;
        }
        // Y ahora ingresamos el historico de los lotes
        $array_lot_history = [
            'relative'                  =>  Str::uuid()->toString(),
            'users_sid'                 =>  $this->getusersid(),
            'global_branch_office_id'   =>  $this->getbranchoffice(),
            'product_id'                =>  $product_id,
            'lot'                       =>  $previousLotQiantity->lot,
            'warehouse_id'              =>  $previousLotQiantity->warehouse_id,
            'measurement_id'            =>  $previousLotQiantity->measurement_id,
            'initial_quantity'          =>  $previousLotQiantity->initial_quantity,
            'quantity'                  =>  $previousLotQiantity->quantity,
            'unit_cost'                 =>  $previousLotQiantity->unit_cost,
            'currency_id'               =>  $previousLotQiantity->currency_id,
            'total_price'               =>  $previousLotQiantity->total_price,
            'expiration_date'           =>  $previousLotQiantity->expiration_date,
            'status'                    =>  'A',
            'created_at'                =>  date("Y-m-d H:i:s")
        ];
        // Registramos el historico del lote
        ProductsLotHistory::create($array_lot_history);
        // Retornamos la nueva cantidad
        return $quantity;
    }

    /**
     * Actualizar el kardex del producto
     * @param $product_id
     * @param $quantity
     * @param $measurement_id
     * @param $detail
     * @param $iet
     * @param $lot_id
     * @param $warehouse_id
     */
    private function makeKardex($product_id, $quantity, $measurement_id, $detail, $iet = 'E', $lot_id = null, $warehouse_id = null)
    {
        Log::info('Lot id: ' . $lot_id . ' - Almacen: ' . $warehouse_id);
        // Creamos el array para el ingreso del kardex
        $array_kardex = [
            'relative'                  =>  Str::uuid()->toString(),
            'users_sid'                 =>  $this->getusersid(),
            'global_branch_office_id'   =>  $this->getbranchoffice(),
            'product_id'                =>  $product_id,
            'iet'                       =>  $iet,
            'warehouse_id'              =>  $warehouse_id,
            'product_lot_id'            =>  $lot_id,
            'quantity'                  =>  $quantity,
            'measurement_id'            =>  $measurement_id,
            'detail'                    =>  $detail,
            'status'                    =>  'A',
            'created_at'                =>  date("Y-m-d H:i:s")
        ];
        return ProductsKardex::create($array_kardex);
    }

    /**
     * @param $token
     * @return bool
     * @throws \Exception
     */
    private function tryping($token)
    {
        // Obtenemos la opcion de la URL en proxy o no
        $proxy = $this->isthereaproxy();
        // Verificamos si habia o no proxy
        if ($proxy != false) {
            // Obtenemos el proxy URL
            $proxyUrl = $proxy;
            // El token
            $token = 'TokenApi ' . $token;
            // La URL de envio
            $url = 'https://siatrest.impuestos.gob.bo/v2/ServicioFacturacionElectronica?wsdl';
            // Y ahora el cuerpo
            $body = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:siat="https://siat.impuestos.gob.bo/">
                <soapenv:Header/>
                <soapenv:Body>
                    <siat:verificarComunicacion/>
                </soapenv:Body>
             </soapenv:Envelope>';
            // Ahora intentamos la conexion
            try {
                $response = Http::withHeaders([
                    "Content-Type" => "application/json",
                ])->timeout(30)->withoutVerifying()->post($proxyUrl, [
                    'url' => $url,
                    'token' => $token,
                    'body' => $body,
                ]);
                // Tenemos la respuesta
                $array = XmlToArray::convert(json_decode($response->body())->body);
                return ($array['soap:Body']['ns2:verificarComunicacionResponse']['return']['transaccion'] == "true") ? true : false;
            } catch (InvalidStateException $e) {
                Log::error($e->getMessage());
                return false;
            }
        } else {
            // Intentamos la coneccion
            try {
                $response = Http::withHeaders([
                    "Content-Type" => "text/xml;charset=utf-8",
                    "apikey" => 'TokenApi ' . $token
                ])->timeout(30)->withoutVerifying()->send(
                    "POST",
                    "https://siatrest.impuestos.gob.bo/v2/ServicioFacturacionElectronica?wsdl",
                    [
                        "body" => '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:siat="https://siat.impuestos.gob.bo/">
                       <soapenv:Header/>
                       <soapenv:Body>
                          <siat:verificarComunicacion/>
                       </soapenv:Body>
                    </soapenv:Envelope>'
                    ]
                );
                $array = XmlToArray::convert($response->body());
                return ($array['soap:Body']['ns2:verificarComunicacionResponse']['return']['transaccion'] == "true") ? true : false;
            } catch (InvalidStateException $e) {
                Log::error($e->getMessage());
                return false;
            }
        }
    }

    /**
     * @return mixed
     */
    private function getusersid()
    {
        $user = response()->json(auth()->user());
        return $user->original->sid;
    }

    /**
     * Obtenemos el email del usuario
     *
     * @return void
     */
    private function getusersemail()
    {
        $user = response()->json(auth()->user());
        return $user->original->email;
    }

    /**
     * @return mixed
     */
    private function getbranchoffice()
    {
        $user = response()->json(auth()->user());
        return $user->original->global_branch_office_id;
    }
}
