<?php

$loader = $this->registry->get('load');
$loader->dmodel('marketplace/mktpedido');

final class DModelmercadolivremelipedido extends DModelmarketplacemktpedido
{

  public function getidPedidoFromShipments($ShipmentId)
  {
    $meli_itens = $this->mercadolivre->getShipmentsItems($ShipmentId);

    if (!$meli_itens) {
      throw new Exception($this->mercadolivre->error);
    }

    $meli_orderid = $this->getPropery($meli_itens[0], 'order_id', 0);

    if ($meli_orderid == 0) {
      throw new Exception('Item de pedido não vinculado a nenhuma venda! Contate a futura sistemas!');
    }

    return $meli_orderid;
  }

  //Funcao usada para sincronizar automaticamente os pedidos que estao no Mercado Livre ae ainda nao foram sincronizados
  public function processAPIOrder($tempoLimite = false){
    $this->db->query("DELETE FROM `" . DB_PREFIX . "marketplace_api_call` WHERE tipo_integracao = " . Type_MarketPlace::Tp_Mercadolivre . " AND done = 1");
    $api_orders = $this->db->query("SELECT * FROM `" . DB_PREFIX . "marketplace_api_call` WHERE tipo_integracao = " . Type_MarketPlace::Tp_Mercadolivre . " AND (callType='order' or callType='shipments') and `done` = '0' and attempts < 5 limit 100 ")->rows;

    $retorno = array("fail_order" => 0);
    if ($api_orders) {
      $api_orders_group = array_chunk($api_orders, 50);
      foreach ($api_orders_group as $key => $api_orders) {
        foreach ($api_orders as $api_order) {
          try {
            $this->db->startTransaction();
            $callId = $api_order['callId'];

            $date = new DateTime(date('Y-m-d H:i:s'));
            $orderDate = DateTime::createFromFormat('Y-m-d H:i:s', $api_order['dateTime']);
            $diff = date_diff($date, $orderDate);
            if ($diff->m > 1) {
              throw new Exception("Pedido muito antigo, com mais de 1 mês!");
            }

            if ($api_order['callType'] == 'shipments') {
              $mercaOrderId = $this->getidPedidoFromShipments($callId);
            } else {
              $mercaOrderId = $callId;
            }

            $merca_order = $this->getMktOrder($mercaOrderId, Type_MarketPlace::Tp_Mercadolivre);

            if ($merca_order) {
              $this->updateOpencartOrder($merca_order);
            } else {
              $this->meliOrderV2($mercaOrderId);
            }

            $this->db->query("UPDATE `" . DB_PREFIX . "marketplace_api_call` SET done = '1' WHERE tipo_integracao = " . Type_MarketPlace::Tp_Mercadolivre . " AND callId = '" . $callId . "' and callType='" . $api_order['callType'] . "';");
            $this->db->commit();
          } catch (Exception $e) {
            $this->db->rollback();
            $this->db->query("UPDATE `" . DB_PREFIX . "marketplace_api_call` SET attempts = " . ($api_order['attempts'] + 1) . " WHERE callId = '" . $callId . "'");
            if ((strpos($e->getMessage(), 'invalid_caller_id') !== false) || (strpos($e->getMessage(), 'not_owned_order') !== false)) {
              $this->db->query("DELETE FROM `" . DB_PREFIX . "marketplace_api_call` WHERE tipo_integracao = " . Type_MarketPlace::Tp_Mercadolivre . " AND callId = '" . $callId . "'");
            } else {
              $this->mercadolivre->setErrorML('MERCADOLIVRE Order API Error: ' . $e . " - " . ($callId ?? ""));
              $this->mercadolivre->raiseGlobalErrors();
            }
            $retorno['fail_order']++;
          }
        }

        if (($tempoLimite) && (new DateTime($this->db->dataAtual()) > $tempoLimite)){
          break;
        }
      }
    }
    return $retorno;
  }

  public function SearchProcessAPIOrder($filter_order_id)
  {
    try {
      $this->db->startTransaction();
      if ($filter_order_id) {
        try {

          $merca_order = $this->getMktOrder($filter_order_id, Type_MarketPlace::Tp_Mercadolivre);
          if($merca_order){
            throw new Exception('Pedido já se encontra no sistema');
          }

          $this->meliOrderV2($filter_order_id, true);
          $this->db->query("UPDATE `oc_marketplace_api_call` SET done = '1' WHERE tipo_integracao = " . Type_MarketPlace::Tp_Mercadolivre . " AND callId = '" . $filter_order_id . "'");
        } catch (Exception $e) {
          $this->mercadolivre->setErrorML('MERCADOLIVRE Order API Error: ' . $e);
          throw $e;
        }
      }
      $this->db->commit();
    } catch (Exception $e) {
      $this->db->rollback();
      throw $e;
    }
  }

  public function SearchMissedFeed($topic = "orders_v2")
  {
    $this->load->dmodel('marketplace/marketplace');
    $missedFeed = $this->mercadolivre->getMissedFeed($topic);
    if ($missedFeed && isset($missedFeed->messages)) {
        $missedFeed = array_column($missedFeed->messages, null, 'resource');
        
        $apiCalls = $this->db->query("SELECT callId FROM `" . DB_PREFIX . "marketplace_api_call` WHERE tipo_integracao = " . Type_MarketPlace::Tp_Mercadolivre . " AND callType='" . ($topic == 'orders_v2' ? 'order' : $topic) . "' ORDER BY dateTime DESC limit 1000 ")->rows;
        $apiCalls = $apiCalls ? array_column($apiCalls, 'callId', null) : [];

        foreach($missedFeed as $key => $feed) {
            $callId = null;
            if ($feed->attempts < 5) {
                continue;
            }
            switch ($topic) {
                case Type_CallbackTopic::getNickFromConstValue(Type_CallbackTopic::Tp_Items) :
                  $callId = trim(str_replace('/items/', '', $key));
                  break;
                case Type_CallbackTopic::getNickFromConstValue(Type_CallbackTopic::Tp_Orders) :
                case Type_CallbackTopic::getNickFromConstValue(Type_CallbackTopic::Tp_OrdersV2) :
                    $callId = trim(str_replace('/orders/', '', $key));
                    $merca_order = $this->getMktOrder($callId, Type_MarketPlace::Tp_Mercadolivre);
                    if($merca_order){
                      continue 2;
                    }
                    break;
                case Type_CallbackTopic::getNickFromConstValue(Type_CallbackTopic::Tp_Shipments) :
                    $callId = trim(str_replace('/shipments/', '', $key));
                    break;
                case Type_CallbackTopic::getNickFromConstValue(Type_CallbackTopic::Tp_Questions) :
                    $callId = trim(str_replace('/questions/', '', $key));
                    break;
            }

            if ($callId && !in_array($callId, $apiCalls)) {
              $this->dmodel_marketplace_marketplace->addAPICall(Type_MarketPlace::Tp_Mercadolivre, $callId, ($topic == 'orders_v2' ? 'order' : $topic));
            }
        }
    }
  }

  public function getmercaorder($order_id)
  {
    return $this->db->query("SELECT
				mo.*
			FROM `oc_marketplace_order` mo
			inner join oc_order o on (o.order_id = mo.order_id)
			WHERE mo.order_id = " . (int)$order_id
      . " and o.mkt_integracao_tipo = " . Type_MarketPlace::Tp_Mercadolivre)->row;
  }


  public function getOCStatus($merca_status = array())
  {
    $row = $this->db->query("SELECT * FROM `" . DB_PREFIX . "mercadolivre_status` WHERE merca_status='$merca_status'")->row;
    if ($row) return $row['oc_status'];
    else return '';
  }

  public function getMercaStatus($oc_status)
  {
    $row = $this->db->query("SELECT * FROM `" . DB_PREFIX . "mercadolivre_status` WHERE oc_status='$oc_status'")->row;
    if ($row) return $row['merca_status'];
    else return false;
  }

  private function scapeStrSql($value)
  {
    return "'" . $this->db->escape($value) . "'";
  }


  private function getPropery($dataobj, $dataname, $defaultvalue = '')
  {
    return (is_object($dataobj) && property_exists($dataobj, $dataname)) ? $dataobj->$dataname : $defaultvalue;
  }

  public function getMercadolivreOrderID($order_id)
  {
    $this->load->type('tipocomum');

    $sql = "SELECT
				mo.*
			FROM `oc_marketplace_order` mo
			inner join oc_order o on (o.order_id = mo.order_id)
			WHERE mo.order_id = " . (int)$order_id
      . " and o.mkt_integracao_tipo = " . Type_MarketPlace::Tp_Mercadolivre;


    $result = $this->db->query($sql);
    if ($result->row)
      return Type_DsimDnao::Tp_Sim;
    else
      return Type_DsimDnao::Tp_Nao;
  }


  public function getNfesMl($data = array())
  {

    $this->load->type('tipofuturaserver');
    $sql = "SELECT o.meli_shipping_id, o.id_futura, o.order_id FROM oc_marketplace_order mo"
      . " inner join oc_order o on (mo.order_id = o.order_id)"
      . " WHERE o.status_futuraserver = '" . Type_PedidoStatus::TpPSt_Faturado . "'"
      . " and (o.id_futura is not null)"
      . " and (o.mkt_integracao_tipo = " . Type_MarketPlace::Tp_Mercadolivre . ")"
      . " and (o.meli_shipping_id is not null) and (date(o.date_added) BETWEEN CURDATE() - INTERVAL 30 DAY AND CURDATE())"
      . " and (exists(select nfe.order_id from oc_order_nfe nfe where (o.order_id = nfe.order_id) and (nfe.ml_nf_enviado = " . Type_Enviado::Tp_NaoEnviado . ")))";

    if (!empty($data['order_id'])) {
      $sql .= ' and o.order_id = ' . $data['order_id'];
    }

    $result = $this->db->query($sql);

    if ($result->rows) {
      return $result->rows;
    } else {
      return false;
    }

  }

  public function updateNfeEnviadoMl($order_id)
  {
    $sql = ' update oc_order_nfe set ml_nf_enviado = ' . Type_Enviado::Tp_Enviado . ' where order_id = ?';

    $this->db->executeSql($sql, [$order_id]);
  }

  public function sendNfesML($data = array())
  {
    $this->load->dmodel('checkout/order');
    $this->load->dmodel('setting/task');
    $this->load->type('tipocomum');
    $this->load->dmodel('wsceo/pedido/wsnotafiscal');
    $this->load->dmodel('notafiscal/notafiscal');

    if ($this->config->get('mercadolivre_nfe_status')) {
      $result = $this->getNfesMl($data);

      if ($result) {
          foreach ($result as $row) {
              $this->db->startTransaction();
              try {

                  $nfe = $this->dmodel_notafiscal_notafiscal->getOrderNfe($row['order_id']);

                  if ($nfe) {

                      $retorno = $this->mercadolivre->setNfe($row['meli_shipping_id'], $nfe['xml'], $row['order_id']);

                      $this->saveMarketplaceLog();

                      if (property_exists($retorno, 'error')) {
                          $this->mercadolivre->raiseGlobalErrors();
                      } else {
                          $this->updateNfeEnviadoMl($row['order_id']);
                      }
                      $this->db->commit();
                  } else {
                      $this->db->rollback();
                      return false;
                  }

              } catch (Exception $e) {
                  $this->db->rollback();
                  $this->saveMarketplaceLog();
                  throw $e;
              }
          }
      }

      // Caso não esteja setado o retorno retorna falso, senão da erro na URL e trava a fila pra todos os pedidos
      if (!isset($retorno)){
          return false;
      }

      if (property_exists($retorno, 'error')) {
        $tipoSituacao = TypeMercadoLivre_Situacao::Tp_SituacaoErro;
        $mensagemErro = $this->mercadolivre->TranslateError($retorno->error);
      }else{
        $tipoSituacao = TypeMercadoLivre_Situacao::Tp_SituacaoNotificado;
        $mensagemErro = '';
      }

      $dataStatus = array(
        "order_id" => $data['order_id'],
        "order_history_id" => $data['order_history_id'],
        "mktStatus" => Type_MercadoLivreNfeStatus::Tp_NfeInvoiced,
        "tipo_origem" => TypeMercadoLivre_Origem::Tp_Envio,
        "tipo_situacao" => $tipoSituacao,
        "msg_erro" => $mensagemErro
      );

      if(isset($data['reenvio'])){
        $this->updateMktOrderStatus($dataStatus);
      }else if(!$this->dmodel_marketplace_mktpedido->isVinculedMktOrderStatus($data['order_history_id'])){
        $this->addMktOrderStatus($dataStatus);
      }

      if (property_exists($retorno, 'error')) {
        throw new Exception($retorno->error);
      } else {
        return true;
      }

    } else {
      throw new Exception('Configuração de verificação de envio nota fiscal do mercado livre desabilitada!');
    }

  }

  public function meliOrderV2($mercaOrderId, $syncManual=false)
  {
    $this->load->type('tipocomum');
    $this->load->type('tipomarketplace');
    $this->load->helper('ftr_geral');
    $this->load->dmodel('checkout/order');
    $this->load->dmodel('mercadolivre/meliproduto');

    $pedido = $this->marketplace->getOrder(Type_MarketPlace::Tp_Mercadolivre, $mercaOrderId);

    //Caso retorne false na função, é porque não encontrou pedido...
    if (!$pedido) {
      return true;
    }

    //lógica para barrar pedidos antigos, acabando não gerando lixo para o cliente...
    if ($this->config->get('mercadolivre_data_pedido')) {
      $tz = new DateTimeZone('America/Sao_Paulo');
      $datapedido = new DateTime($pedido->getDateCreated());
      $datapedido->setTimeZone($tz);

      if (!$syncManual){
          $base = DateTime::createFromFormat('d/m/Y H:i:s', $this->config->get('mercadolivre_data_pedido'));
          $base->setTimeZone($tz);
          if ($base > $datapedido) {
              return true;
          }
      }
    }

    $meli_shipping_id = $pedido->getParam('meli_shipping_id');

    if ((!is_null($meli_shipping_id)) || ($pedido->getAddressCombinar())) {

      $this->load->dmodel('marketplace/mktproduto');
      $this->load->dmodel('marketplace/mktprodutomercadolivre');
      $this->load->dmodel('catalog/product');

      $adFieldsOrder        = Array();
      $adFieldsOrderValue   = Array();
      $adjustmentKit        = false;
      $mktCommisions        = Array();

      $adFieldsOrder[] = 'meli_pack_id';
      $adFieldsOrder[] = 'meli_shipping_id';
      $adFieldsOrder[] = 'mercadolivre_shipping_substatus';
      $adFieldsOrder[] = 'shipping_list_cost';
      $adFieldsOrder[] = 'mercadolivre_shipping_status';

      $adFieldsOrderValue[] = $this->scapeStrSql($pedido->getParam('meli_pack_id'));
      $adFieldsOrderValue[] = $this->scapeStrSql($pedido->getParam('meli_shipping_id'));
      $adFieldsOrderValue[] = $this->scapeStrSql($pedido->getParam('mercadolivre_shipping_substatus'));
      $adFieldsOrderValue[] = $this->scapeStrSql($pedido->getParam('shipping_list_cost'));
      $adFieldsOrderValue[] = $this->scapeStrSql($pedido->getParam('mercadolivre_shipping_status'));

      $this->db->startTransaction();
      try {
        $dadosProd = Array();
        $mkt_comission_total = 0;
        foreach ($pedido->getItens() as $product) {
          $mkt_comission = 0;
          $oc_mktproduct = $this->dmodel_marketplace_mktproduto->getMarketPlaceFromMarketId($product->getMktId(), Type_MarketPlace::Tp_Mercadolivre);

          // caso não achou o anuncio, verifica se é produto de catalogo
          if (!$oc_mktproduct){
            $catalogProduct = $this->dmodel_mercadolivre_meliproduto->getMercadolivreAdCatalogByMlAdId($product->getMktId());
            $oc_mktproduct = isset($catalogProduct['marketId']) ? $this->dmodel_marketplace_mktproduto->getMarketPlaceFromMarketId($catalogProduct['marketId'], Type_MarketPlace::Tp_Mercadolivre) : false;
          }

          $product_id = 0;
          $variation_id = '';
          $productDB = null;

          if ($oc_mktproduct && $oc_mktproduct['tipo_produto'] == Type_ProdutoMkt::Tp_MktProd_Grade) {
            //é vinculado com produto grade!! verificando então qual é a variação correta que está ligada ao produto...
            if ($product->getMktVariationId()) {
              $variation_id = $product->getMktVariationId();
              $productItemGrid = $this->dmodel_marketplace_mktproduto->getProductFromVariation($variation_id, Type_MarketPlace::Tp_Mercadolivre);

              if (isset($productItemGrid['product_id'])) {
                $product_id = $productItemGrid['product_id'];
              }
            } else if ($catalogProduct){
              $product_id = $catalogProduct['product_id'];
            }

          } elseif ($oc_mktproduct && ($oc_mktproduct['tipo_produto'] == Type_ProdutoMkt::Tp_MktProd_Normal) && isset($oc_mktproduct['product_key_id'])) {
            $productDB = $this->dmodel_marketplace_mktprodutomercadolivre->getProduct($oc_mktproduct['product_key_id']);
            if ($productDB) {
              $product_id = $productDB['product_id'];
            }
          }


          if ((is_null($productDB)) && ($product_id != 0)) {
            $productDB = $this->dmodel_marketplace_mktprodutomercadolivre->getProduct($product_id);
          }

          if ($this->config->get('mercadolivre_comission_status')) {
            $product_tpanuncio = 'mercadolivre_comission_' . $product->getParam('listing_type_id');

            if (ftr_geral::isIsset($this->config->get($product_tpanuncio)) && ($this->config->get($product_tpanuncio) > 0)) {
              $mkt_comission = (($this->config->get($product_tpanuncio) * $pedido->getTotal()) / 100);
              $mkt_comission_total += $mkt_comission;
            }
          }

          $brinde = $this->getMktBrinde($product_id);
          if ($brinde){
            if ($productDB['product_kit_id']){
                $brinde['product_kit_id']  = $productDB['product_kit_id'];
                $brinde['product_kit_qtd'] = $product->getQuantity();
            }
            $dadosProd[] = $brinde;
            $product->setPrice($product->getPrice()-0.01);
          }

          if (!$productDB) {
            $dadosProd[] = array(
              'product_id' => $product_id,
              'name' => $product->getProductName(),
              'model' => '',
              'quantity' => $product->getQuantity(),
              'price' => $product->getPrice(),
              'total' => $product->getQuantity() * $product->getPrice(),
              'marketId' => $product->getMktId(),
              'mkt_comission' => $mkt_comission,
              'mkt_variation_id' => $variation_id,
              'mktOrderId' => $product->getMktIdOrderItem()
            );
          } else {
            if ($productDB['product_kit_id']){
              $adjustmentKit = true;
              $itens_kit = $this->dmodel_catalog_product->getProductKitItens($productDB['product_kit_id'],$product->getPrice());

              $mktCommisions[] = array( /* Para que seja rateado posteriormente, pois para isso preciso do pedido/pedido item */
                "product_kit_id" => $productDB['product_kit_id'],
                "mkt_comission"  => $mkt_comission
              );

              if (!empty($itens_kit)){
                  foreach ($itens_kit as $item_kit) {
                    $dadosProd[] = array(
                      'product_id'        => $item_kit['product_id'],
                      'name'              => $item_kit['descricao'],
                      'model'             => $item_kit['model'],
                      'quantity'          => $item_kit['quantidade']*$product->getQuantity(),
                      'price'             => $item_kit['price'],
                      'total'             => ($item_kit['price'] * $item_kit['quantidade']) * $product->getQuantity(),
                      'marketId'          => "",
                      'mkt_comission'     => 0,
                      'mkt_variation_id'  => "",
                      'product_kit_id'    => $productDB['product_kit_id'],
                      'product_kit_qtd'   => $product->getQuantity(),
                      'id_futura'         => $item_kit['product_id_futura'],
                      'discount'          => ($item_kit['acerto'])<0 ? ($item_kit['acerto'] *-1)*$product->getQuantity() : 0,
                      'increase'          => ($item_kit['acerto'])>0 ? $item_kit['acerto']*$product->getQuantity() : 0,
                      'mktOrderId'        => $product->getMktIdOrderItem()
                    );
                  }
              } else {
                  $dadosProd[] = array(
                      'product_id' => 0,
                      'name' => $product->getProductName(),
                      'model' => '',
                      'quantity' => $product->getQuantity(),
                      'price' => $product->getPrice(),
                      'total' => $product->getQuantity() * $product->getPrice(),
                      'marketId' => $product->getMktId(),
                      'mkt_comission' => $mkt_comission,
                      'mktOrderId' => $product->getMktIdOrderItem()
                  );
              }
            }else{
              $dadosProd[] = array(
                'product_id' => $product_id,
                'name' => $productDB['name'],
                'model' => $productDB['model'],
                'quantity' => $product->getQuantity(),
                'price' => $product->getPrice(),
                'total' => $product->getQuantity() * $product->getPrice(),
                'marketId' => $product->getMktId(),
                'mkt_comission' => $mkt_comission,
                'mkt_variation_id' => $variation_id,
                'mktOrderId' => $product->getMktIdOrderItem()
              );
            }

          }
        }

        $total_data = array();
        if ($adjustmentKit){
          //Ajuste dos descontos e totais dos produtos caso possua KIT
          $this->language->load('total/descontoacrescimokit');
          $fullSubTotal = array_sum(array_column($dadosProd,'total'));
          $adjustmentKitValue = $pedido->getSubTotal()-$fullSubTotal;
          $pedido->setSubTotal($fullSubTotal);
          if($adjustmentKitValue >= 0){
            $text_kit = $this->language->get('acrescimo_kit');
            $pedido->setAcresKit($adjustmentKitValue);
          }else{
            $text_kit = $this->language->get('desconto_kit');
            $pedido->setDiscountKit($adjustmentKitValue*-1);
          }

          $text_kit = ($adjustmentKitValue > 0) ? $this->language->get('acrescimo_kit') : $this->language->get('desconto_kit');
          $total_data[] = array(
            'code'        => 'descontoacrescimokit',
            'title'       => $text_kit,
            'text'        => $this->currency->format($adjustmentKitValue, $this->currency->getCode()),
            'value'       => (float)$adjustmentKitValue,
            'sort_order'  => $this->config->get('sub_total_sort_order')+1//Exibir o desconto do Kit logo em seguida do subtotal
          );
        }

        $order_id = $this->addOrder($pedido, $mkt_comission_total, Type_MercadoLivreModule::Tp_Payment, Type_MercadoLivreModule::Tp_Shipping, $adFieldsOrder, $adFieldsOrderValue, true);

        foreach ($dadosProd as $prod) {
            if (isset($prod['product_kit_id']) && !isset($prod['brinde_product_id'])) {
                $extraFields = array("product_kit_id","product_kit_qtd","desconto_valor","acrescimo_valor");
                $extraValues = array($prod["product_kit_id"],$prod["product_kit_qtd"],$prod["discount"],$prod["increase"]);
                $order_product_id = null;
                $this->addOrderProduct($order_id, $prod,$extraFields,$extraValues);
            }elseif (isset($prod['brinde_product_id'])){
                $extraFields = array("brinde_product_id","brinde_tipo");
                $extraValues = array($prod["brinde_product_id"],$prod["brinde_tipo"]);
                $order_product_id = null;
                if(isset($prod['product_kit_id'])){
                    $extraFields = array_merge($extraFields,["product_kit_id","product_kit_qtd"]);
                    $extraValues = array_merge($extraValues,[$prod["product_kit_id"],$prod["product_kit_qtd"]]);
                }
                $this->addOrderProduct($order_id, $prod,$extraFields,$extraValues);
            }else{
                $order_product_id = $this->addOrderProduct($order_id, $prod);
            }

            if ( !isset($prod['brinde_tipo']) || (!$prod['brinde_tipo']==Type_ProdutoBrinde::Tp_Brinde) ){
                $mktOrders[$prod['mktOrderId']] = array(
                    "mktOrderId" => $prod['mktOrderId'],
                    "order_product_id" => $order_product_id
                );
            }
        }

        foreach ($mktOrders as $mktOrdersItem){
          $this->addMktOrder(array(
            'order_id'         => (int)$order_id,
            'mktOrderId'       => $mktOrdersItem['mktOrderId'],
            'order_product_id' => $mktOrdersItem['order_product_id'],
            'tipo_integracao'  => Type_MarketPlace::Tp_Mercadolivre,
            'shipping_code'    => $pedido->getParam('meli_shipping_code'),
            'origem_captura'   => $syncManual ? Type_MktOrigemCaptura::Manual : Type_MktOrigemCaptura::Automatica
          ));
        }

        if ($mktCommisions){
          $orderItens = $this->dmodel_checkout_order->getOrderItems($order_id);
          foreach ($mktCommisions as $comission){
            $this->dmodel_checkout_order->updateApportionment($order_id, $comission['mkt_comission'], Type_Apportionment::MktCommission, true,$comission['product_kit_id'],$orderItens);
          }
        }


        $this->language->load('total/sub_total');
        $total_data[] = array(
          'code' => 'sub_total',
          'title' => $this->language->get('heading_title'),
          'text' => $this->currency->format($pedido->getSubTotal(), $this->currency->getCode()),
          'value' => (float)$pedido->getSubTotal(),
          'sort_order' => $this->config->get('sub_total_sort_order')
        );

        $shipping_cost = $pedido->getShippingCost();

        if ($pedido->getTotal() <= 0) {
          $this->mercadolivre->setErrorML("MERCADOLIVRE Order API valor zerado: " . $pedido->getParam('meli_shipping_id'));
          throw new exception('valor total zerado');
        }

        $method_title = ($pedido->getShippingName()) ? $pedido->getShippingName() : $this->getModuleName(Type_MercadoLivreModule::Tp_Shipping, 'shipping');
        if ($shipping_cost <= 0) {
          $method_title .= ' (Grátis)';
        }

        if (!$pedido->getAddressCombinar()) {
          $total_data[] = array(
            'code' => 'shipping',
            'title' => ($method_title) ? $method_title : $pedido->getShippingName(),
            'text' => $this->currency->format((float)$shipping_cost, $this->currency->getCode()),
            'value' => (float)$shipping_cost,
            'sort_order' => $this->config->get('shipping_sort_order')
          );
        }

        $this->language->load('total/total');
        $total_data[] = array(
          'code' => 'total',
          'title' => $this->language->get('heading_title'),
          'text' => $this->currency->format((float)$pedido->getTotal(), $this->currency->getCode()),
          'value' => (float)$pedido->getTotal(),
          'sort_order' => $this->config->get('total_sort_order')
        );

        $this->dmodel_checkout_order->updateApportionmentAll($order_id,
        array(
          Type_Apportionment::Shipping => $shipping_cost,
          Type_Apportionment::Discount => $pedido->getDiscount(),
          Type_Apportionment::Increase => $pedido->getAcres()
        )
      );

        $this->addOrderTotal($order_id, $total_data);

        $commentHistory = (($pedido->hasParam('meli_pack_id')) && (!empty($pedido->getParam('meli_pack_id')))) ? "Mercado livre (Pacote #" . $pedido->getParam('meli_pack_id') . ")" : "Mercado livre (Venda #" . $product->getMktIdOrderItem() . ")";
        $order_status_id = $this->getOCStatus($pedido->getParam('status'));

        $order_history_id = $this->updateOrderHistory($order_id, $order_status_id, $commentHistory);

        if ($order_history_id){
          $data = array(
            "order_id" => $order_id,
            "order_history_id" => $order_history_id,
            "mktStatus" => $pedido->getParam('status'),
            "tipo_origem" => TypeMercadoLivre_Origem::Tp_Recebimento,
            "tipo_situacao" => TypeMercadoLivre_Situacao::Tp_SituacaoRecebido,
          );
          $this->addMktOrderStatus($data);
        }

        $this->saveMarketplaceLog();

        $this->db->commit();
        return $order_id;
      } catch (Exception $e) {
        $this->db->rollback();
        throw new Exception($e->getMessage());
      }
    }
  }

  protected function updateOpencartOrder($orderData)
  {
    $this->mercadolivre->getAccess();

    $this->load->dmodel('checkout/order');
    $this->load->dmodel('notafiscal/notafiscal');

    $stopSync = $this->db->query("select meli_stopSync FROM `" . DB_PREFIX . "order` where order_id = " . (int)$orderData['order_id'])->row['meli_stopSync'];

    if (!$stopSync) {
      $result = $this->db->query("SELECT"
        . " feedback,"
        . " mktOrderId"
        . " FROM `" . DB_PREFIX . "marketplace_order` "
        . " WHERE `order_id` = '" . (int)$orderData['order_id'] . "'")->row;

      $melipedido   = $this->mercadolivre->getmeliOrder($result['mktOrderId']);
      $mktOrderData = $this->mercadolivre->getOrder($result['mktOrderId']);

      if ($melipedido) {
          //Status e Envio
          $statusPedido = $this->getPropery($melipedido, 'status', false);
          $idEnvio = $this->getPropery($melipedido->shipping, 'id', false);
          $packId = $this->getPropery($melipedido, 'pack_id', false);

          if ($idEnvio) {
              $melienvio = $this->mercadolivre->getShipments($idEnvio);
              $statusEnvio = $this->getPropery($melienvio, 'status', false);
          } else if ($packId) {
              $pack = $this->mercadolivre->getShipmentsByPackId($packId);
              if (isset($pack->shipment) && isset($pack->shipment->id) && !is_null($pack->shipment->id)){
                  $idEnvio = $pack->shipment->id;
                  $melienvio = $this->mercadolivre->getShipments($idEnvio);
                  $statusEnvio = $this->getPropery($melienvio, 'status', false);
              }     
          } else {
              $statusEnvio = false;
          }

          // Atualiza Pedido e Endereços caso o endereço tenha sido alterado
          if(isset($melipedido->shipping) && !is_null($melipedido->shipping->id) && isset($melienvio->destination->shipping_address) && $melienvio->destination->shipping_address->zip_code){
              if ($this->orderAddressIsDifferent($orderData, $mktOrderData)){
                  $this->updateOrderAddress($orderData, $mktOrderData);
              }
          }

        if($statusEnvio){
          switch ($statusEnvio) {
            case Type_MercadoLivreEnvioStatus::Tp_Delivered :
              ($result['feedback'] != Type_Status::Tp_Habilitado) ? $statusPedido = Type_MercadoLivreEnvioStatus::Tp_Delivered : $statusEnvio;
            break;
            case Type_MercadoLivreEnvioStatus::Tp_Shipped :
              $statusPedido = Type_MercadoLivreEnvioStatus::Tp_ReadyToShip;
            break;
          }
        }

        if ($statusPedido && !$this->existsMktOrderStatus($orderData['order_id'],$statusPedido)){
          $order_history_id = $this->setOrderOcStatus($statusPedido, $melipedido->id, $orderData['order_id']);
          if ($statusEnvio == Type_MercadoLivreEnvioStatus::Tp_ReadyToShip){
            $this->load->dmodel('tracking/tracking');
            $dataOrder = array(
              'order_id' => $orderData['order_id'],
              'tracking_code' => $melienvio->tracking_number,
            );
            $this->dmodel_tracking_tracking->addTrackingOrderShipping($dataOrder);
          }
          if ($order_history_id){
            $data = array(
              "order_id" => $orderData['order_id'],
              "order_history_id" => $order_history_id,
              "mktStatus" => $statusPedido,
              "tipo_origem" => TypeMercadoLivre_Origem::Tp_Recebimento,
              "tipo_situacao" => TypeMercadoLivre_Situacao::Tp_SituacaoRecebido,
              "mktStatus_envio" => $statusEnvio
            );
            $this->addMktOrderStatus($data);
          }

          $this->saveMarketplaceLog();
        }
      }
    }
  }

  public function getShippingAddressDifferent($customer_id, $address_data){
    $retorno = $this->db->query("
      select address_id from " . DB_PREFIX . "address
      where customer_id = " . $this->db->escape($customer_id) . "
      and address_1 = " . $this->db->escape($address_data['address_1']) . "
      and address_2 = " . $this->db->escape($address_data['address_2']) . "
      and numero = " . $this->db->escape($address_data['numero']) . "
      and complemento = " . $this->db->escape($address_data['complemento']) . "
      and city = " . $this->db->escape($address_data['city']) . "
      and postcode = " . $this->db->escape($address_data['postcode']) . "
      and country_id = " . $this->db->escape($address_data['dadosPais']['country_id']) . "
      and zone_id = " . $this->db->escape($address_data['state_zone_id']) . "
      and tipo_logradouro = " . $this->db->escape($address_data['tipo_logradouro']) . "
      and logradouro = " . $this->db->escape($address_data['logradouro']) . "
      and codigo_municipio = " . $this->db->escape($address_data['codigo_municipio'])
    );

    if ($retorno->num_rows > 0){
      return $retorno->row['address_id'];
    } else {
      return false;
    }
  }

  public function orderAddressIsDifferent($orderInfo, MktPedido $order){
    $orderAddress = $this->getOrderAddress($order);

    $retorno = $this->db->query("
      select order_id from `" . DB_PREFIX . "order`
      where order_id = " . $this->db->escape($orderInfo['order_id']) . "

      and payment_address_1 = '" . $this->db->escape($orderAddress['billing']['address_1']) . "'
      and payment_address_2 = '" . $this->db->escape($orderAddress['billing']['address_2']) . "'
      and payment_numero = " . $this->db->escape($orderAddress['billing']['numero']) . "
      and payment_complemento = '" . $this->db->escape($orderAddress['billing']['complemento']) . "'
      and payment_city = '" . $this->db->escape($orderAddress['billing']['city']) . "'
      and payment_postcode = " . $this->db->escape($orderAddress['billing']['postcode']) . "
      and payment_country_id = " . $this->db->escape($orderAddress['billing']['dadosPais']['country_id']) . "
      and payment_zone_id = " . $this->db->escape($orderAddress['billing']['state_zone_id']) . "
      and payment_tipo_logradouro = '" . $this->db->escape($orderAddress['billing']['tipo_logradouro']) . "'
      and payment_logradouro = '" . $this->db->escape($orderAddress['billing']['logradouro']) . "'

      and shipping_address_1 = '" . $this->db->escape($orderAddress['shipping']['address_1']) . "'
      and shipping_address_2 = '" . $this->db->escape($orderAddress['shipping']['address_2']) . "'
      and shipping_numero = " . $this->db->escape($orderAddress['shipping']['numero']) . "
      and shipping_complemento = '" . $this->db->escape($orderAddress['shipping']['complemento']) . "'
      and shipping_city = '" . $this->db->escape($orderAddress['shipping']['city']) . "'
      and shipping_postcode = " . $this->db->escape($orderAddress['shipping']['postcode']) . "
      and shipping_country_id = " . $this->db->escape($orderAddress['shipping']['dadosPais']['country_id']) . "
      and shipping_zone_id = " . $this->db->escape($orderAddress['shipping']['state_zone_id']) . "
      and shipping_tipo_logradouro = '" . $this->db->escape($orderAddress['shipping']['tipo_logradouro']) . "'
      and shipping_logradouro = '" . $this->db->escape($orderAddress['shipping']['logradouro']) . "'"
    );

    return $retorno->num_rows == 0;
  }

  protected function setOrderOcStatus($status, $mercaid, $order_id)
  {
    $this->load->dmodel('mercadolivre/meliproduto');
    $order_history_id = false;
    $order_status_id = $this->getOCStatus($status);
    $mercaid = $this->db->query("SELECT
				mo.*
			FROM `oc_marketplace_order` mo
			inner join oc_order o on (o.order_id = mo.order_id)
			WHERE mo.mktOrderId = " . (int)$mercaid
      . " and o.mkt_integracao_tipo = " . Type_MarketPlace::Tp_Mercadolivre)->row;
    $oc_order_info = $this->db->query("SELECT order_status_id FROM `" . DB_PREFIX . "order` WHERE order_id = '" . (int)$mercaid['order_id'] . "'")->row;

    if (!empty($order_status_id)) {
      if ($oc_order_info['order_status_id'] != $order_status_id) {
        try {
          $this->db->query("INSERT INTO " . DB_PREFIX . "order_history SET order_id = '" . (int)$order_id . "', order_status_id = '" . (int)$order_status_id . "', notify = '1', comment = '', date_added = current_timestamp(2)");
          $order_history_id = $this->db->getLastId();
          $this->db->query("UPDATE " . DB_PREFIX . "order SET order_status_id = '" . (int)$order_status_id . "', date_modified = NOW() WHERE order_id = '" . (int)$order_id . "' ");
          $this->load->dmodel('proccess/order_to_situation');
          $this->dmodel_proccess_order_to_situation->updateHistory($order_id, (int)$order_status_id);
        } catch (Exception $e) {
          $this->dmodel_mercadolivre_meliproduto->getError($e->getMessage(), $order_id);
        }
      }
    }
    return $order_history_id;
  }

  protected function getMessageStatus($status)
  {

    $this->load->helper('ftr_geral');
    $messagemStatus = ftr_geral::isIsset($this->config->get('mercadolivre_automatic_message')) ? array_filter($this->config->get('mercadolivre_automatic_message')) : false;
    $order_status_id = $this->getOCStatus($status);
    return ($messagemStatus) ? $messagemStatus[$order_status_id] : false;

  }

  protected function getToMessage($data = array())
  {

    if ($this->config->get('mercadolivre_automatic_message_status')) {
      $to = array();
      $items = $this->mercadolivre->getShipmentsItems($data['shipmentsid']);

      foreach ($items as $key => $item) {
        $to[] = array(
          'user_id' => $data['user_id'],
          'resource' => 'orders',
          'resource_id' => $item->order_id,
          'site_id' => 'MLB'
        );
      }

      return $to;
    }
    return false;
  }

  public function getOrderTotals($order){
    $this->language->load('total/sub_total');

    $total_data = array();
    $total_data[] = array(
      'code' => 'sub_total',
      'title' => $this->language->get('heading_title'),
      'text' => $this->currency->format($order->getSubTotal(), $this->currency->getCode()),
      'value' => (float)$order->getSubTotal()
    );

    $shipping_cost = $order->getShippingCost();

    if ($order->getTotal() <= 0) {
      $this->mercadolivre->setErrorML("MERCADOLIVRE Order API valor zerado: " . $order->getParam('meli_shipping_id'));
      throw new exception('valor total zerado');
    }

    $method_title = ($order->getShippingName()) ? $order->getShippingName() : $this->getModuleName(Type_MercadoLivreModule::Tp_Shipping, 'shipping');
    if ($shipping_cost <= 0) {
      $method_title .= ' (Grátis)';
    }

    if (!$order->getAddressCombinar()) {
      $total_data[] = array(
        'code' => 'shipping',
        'title' => ($method_title) ? $method_title : $order->getShippingName(),
        'text' => $this->currency->format((float)$shipping_cost, $this->currency->getCode()),
        'value' => (float)$shipping_cost,
      );
    }

    $this->language->load('total/total');
    $total_data[] = array(
      'code' => 'total',
      'title' => $this->language->get('heading_title'),
      'text' => $this->currency->format((float)$order->getTotal(), $this->currency->getCode()),
      'value' => (float)$order->getTotal(),
    );

    return $total_data;
  }

  public function getOrderMktComission($order, $order_id){

    $dadosProd = Array();
    $mkt_comission_total = 0;
    foreach ($order->getItens() as $product) {
      $mkt_comission = 0;
      if ($this->config->get('mercadolivre_comission_status')) {
        $product_tpanuncio = 'mercadolivre_comission_' . $product->getParam('listing_type_id');

        if (ftr_geral::isIsset($this->config->get($product_tpanuncio)) && ($this->config->get($product_tpanuncio) > 0)) {
          $mkt_comission = (($this->config->get($product_tpanuncio) * $order->getTotal()) / 100);
          $mkt_comission_total += $mkt_comission;
        }
      }

      $dadosProd[] = array(
        'product_market_id' => $product->getMktId(),
        'mkt_comission' => $mkt_comission,
      );
    }

    $this->updateOrderProductMktComission($order_id, $dadosProd);

    return $mkt_comission_total;
  }

  public function updateOrderProductMktComission($order_id, $prodData){
     foreach ($prodData as $prod) {
       $this->db->query(
         "UPDATE `oc_order_product` SET"
         . " mkt_comission = " . $this->db->escape($prod['mkt_comission'])
         . " where order_id = " . $this->db->escape($order_id)
         . " and marketId = '" . $this->db->escape($prod['product_market_id']) . "'"
       );
     }
  }

}