Fórum OpenCart Brasil

Por um e-commerce livre, confiável e profissional

#10880
Para quem está com problemas de fazer os produtos voltarem ao estoque após um pedido ser cancelado na versão 1.5.1.3, a solução pode ser mais simples do que parece. Já existe um código escrito para resolver este problema, porém, ele está dentro de uma condição ainda não definida nas configurações do sistema. Entretanto, é possível desativar essa condição para que o código seja executado e, assim que o pedido é removido os produtos retornam ao estoque.

O código que repõe o estoque é executado somente quando o pedido é removido (deletado) e não quando é adicionado a opção "Cancelado" no status do pedido.

Segue a solução:

1. edite o arquivo /admin/model/sale/order.php e procure por:
public function deleteOrder($order_id) {

2. comente o if adicionando duas barras na frente das linhas abaixo:
if ($this->config->get('config_stock_subtract')) {
}
... desta forma:
// if ($this->config->get('config_stock_subtract')) {
// }

3. ficará assim:
Código: Selecionar todos
	public function deleteOrder($order_id) {
		//if ($this->config->get('config_stock_subtract')) {
			$order_query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "order` WHERE order_status_id > '0' AND order_id = '" . (int)$order_id . "'");

			if ($order_query->num_rows) {
				$product_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_product WHERE order_id = '" . (int)$order_id . "'");

				foreach($product_query->rows as $product) {
					$this->db->query("UPDATE `" . DB_PREFIX . "product` SET quantity = (quantity + " . (int)$product['quantity'] . ") WHERE product_id = '" . (int)$product['product_id'] . "'");

					$option_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_option WHERE order_id = '" . (int)$order_id . "' AND order_product_id = '" . (int)$product['order_product_id'] . "'");

					foreach ($option_query->rows as $option) {
						$this->db->query("UPDATE " . DB_PREFIX . "product_option_value SET quantity = (quantity + " . (int)$product['quantity'] . ") WHERE product_option_value_id = '" . (int)$option['product_option_value_id'] . "' AND subtract = '1'");
					}
				}
			}
		//}

		$this->db->query("DELETE FROM `" . DB_PREFIX . "order` WHERE order_id = '" . (int)$order_id . "'");
      	$this->db->query("DELETE FROM " . DB_PREFIX . "order_history WHERE order_id = '" . (int)$order_id . "'");
      	$this->db->query("DELETE FROM " . DB_PREFIX . "order_product WHERE order_id = '" . (int)$order_id . "'");
      	$this->db->query("DELETE FROM " . DB_PREFIX . "order_option WHERE order_id = '" . (int)$order_id . "'");
	  	$this->db->query("DELETE FROM " . DB_PREFIX . "order_download WHERE order_id = '" . (int)$order_id . "'");
      	$this->db->query("DELETE FROM " . DB_PREFIX . "order_total WHERE order_id = '" . (int)$order_id . "'");
		$this->db->query("DELETE FROM " . DB_PREFIX . "customer_transaction WHERE order_id = '" . (int)$order_id . "'");
		$this->db->query("DELETE FROM " . DB_PREFIX . "customer_reward WHERE order_id = '" . (int)$order_id . "'");
		$this->db->query("DELETE FROM " . DB_PREFIX . "affiliate_transaction WHERE order_id = '" . (int)$order_id . "'");
		$this->db->query("DELETE FROM " . DB_PREFIX . "coupon_history WHERE order_id = '" . (int)$order_id . "'");
	}
Espero ter ajudado.
#12338
Retirar essa checagem funciona, mas o ideal é verificar se o produto havia sido inicialmente removido do estoque (os produtos possuem uma opção "subtrair do estoque?").

Eu corrigi a função e otimizei os SELECT, testem aí (essas são só as linhas 130 a 147 da função, as últimas eu não copiei, já que não foram alteradas):
Código: Selecionar todos
	public function deleteOrder($order_id) {
		$order_query = $this->db->query("SELECT order_id FROM `" . DB_PREFIX . "order` WHERE order_status_id > '0' AND order_id = '" . (int)$order_id . "'");
		if ($order_query->num_rows) {
			$product_query = $this->db->query("SELECT product_id,quantity,order_product_id FROM " . DB_PREFIX . "order_product WHERE order_id = '" . (int)$order_id . "'");
			foreach($product_query->rows as $product) {
				$readd_query = $this->db->query("SELECT subtract FROM " . DB_PREFIX . "product WHERE product_id = '" . (int)$product['product_id'] . "'");
				if ($readd_query->num_rows) {
					$readd_value = $readd_query->row['subtract'];
					if ($readd_value) {
						$this->db->query("UPDATE `" . DB_PREFIX . "product` SET quantity = (quantity + " . (int)$product['quantity'] . ") WHERE product_id = '" . (int)$product['product_id'] . "'");
						$option_query = $this->db->query("SELECT product_option_value_id FROM " . DB_PREFIX . "order_option WHERE order_id = '" . (int)$order_id . "' AND order_product_id = '" . (int)$product['order_product_id'] . "'");
						foreach ($option_query->rows as $option) {
							$readd_option_query = $this->db->query("SELECT subtract FROM " . DB_PREFIX . "product_option_value WHERE product_option_value_id = '" . (int)$option['product_option_value_id'] . "'");
							if ($readd_option_query->num_rows) {
								$readd_option_value = $readd_option_query->['subtract'];
								if ($readd_option_value) {
									$this->db->query("UPDATE " . DB_PREFIX . "product_option_value SET quantity = (quantity + " . (int)$product['quantity'] . ") WHERE product_option_value_id = '" . (int)$option['product_option_value_id'] . "' AND subtract = '1'");
								}
							}
						}
					}
				}
			}
		}
-- editado --

o Daniel acabou de atualizar esse arquivo na SVN, é praticamente a minha função re-escrita... ele foi mais inteligente nas cláusulas WHERE. Mas estou sem dormir desde ontem, mereço um desconto! rsrs.

A função completa ficou assim:
Código: Selecionar todos
	public function deleteOrder($order_id) {
		$order_query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "order` WHERE order_status_id > '0' AND order_id = '" . (int)$order_id . "'");

		if ($order_query->num_rows) {
			$product_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_product WHERE order_id = '" . (int)$order_id . "'");

			foreach($product_query->rows as $product) {
				$this->db->query("UPDATE `" . DB_PREFIX . "product` SET quantity = (quantity + " . (int)$product['quantity'] . ") WHERE product_id = '" . (int)$product['product_id'] . "' AND subtract = '1'");

				$option_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_option WHERE order_id = '" . (int)$order_id . "' AND order_product_id = '" . (int)$product['order_product_id'] . "'");

				foreach ($option_query->rows as $option) {
					$this->db->query("UPDATE " . DB_PREFIX . "product_option_value SET quantity = (quantity + " . (int)$product['quantity'] . ") WHERE product_option_value_id = '" . (int)$option['product_option_value_id'] . "' AND subtract = '1'");
				}
			}
		}

		$this->db->query("DELETE FROM `" . DB_PREFIX . "order` WHERE order_id = '" . (int)$order_id . "'");
      	$this->db->query("DELETE FROM " . DB_PREFIX . "order_download WHERE order_id = '" . (int)$order_id . "'");
		$this->db->query("DELETE FROM " . DB_PREFIX . "order_history WHERE order_id = '" . (int)$order_id . "'");
      	$this->db->query("DELETE FROM " . DB_PREFIX . "order_option WHERE order_id = '" . (int)$order_id . "'");
		$this->db->query("DELETE FROM " . DB_PREFIX . "order_product WHERE order_id = '" . (int)$order_id . "'");
      	$this->db->query("DELETE FROM " . DB_PREFIX . "order_total WHERE order_id = '" . (int)$order_id . "'");
		$this->db->query("DELETE FROM " . DB_PREFIX . "customer_transaction WHERE order_id = '" . (int)$order_id . "'");
		$this->db->query("DELETE FROM " . DB_PREFIX . "customer_reward WHERE order_id = '" . (int)$order_id . "'");
		$this->db->query("DELETE FROM " . DB_PREFIX . "affiliate_transaction WHERE order_id = '" . (int)$order_id . "'");
		$this->db->query("DELETE FROM " . DB_PREFIX . "coupon_history WHERE order_id = '" . (int)$order_id . "'");
	}
O mais engraçado foi quando eu perguntei "porque você usa sempre SELECT * FROM se precisa de apenas 1, 2 ou 3 colunas em cada consulta?"...

A resposta foi simplesmente: lazyness (preguiça). :?
#12950
lyon escreveu:Olá pessoal,

Tentei fazer as mudanças informadas no tópico.
Quando eu cancelo o pedido, o produto não volta ao estoque.

Alguém poderia ajudar?

Grato
Só volta quando é DELETADO.

E você seguiu as instruções do meu último CODE? São as alterações oficiais que serão implementadas na 1.5.2.
#12951
Olá Renato,

Fiz todas as alterações mostradas acima.

1º - Comentei a linha do if. Não funcionou e voltei ao normal.
2º - Copiei a parte do código que vc colocou. Não funcionou e voltei ao normal.
3º - Copiei a função inteira e também não funcionou. Ai voltei ao normal.

Até pensei que pudesse ser a forma que estou fechando a venda, mas creio que não.

Fechar venda.

Clique no visualizar o pedido -> histórico -> altero pra cancelado -> adicionar histórico.

É isso neh?... rsss

Abs!
#12998
Pessoal, vejo que tem muita gente batendo a cabeça aí por causa da reposição do produto em estoque.

No início eu disse que é possível fazer os produtos voltarem ao estoque ao excluir o pedido, sim, basta fazer os ajustes que comentei. Vejo que vocês estão tendo a necessidade de reabastecer o estoque somente ao adicionar no histórico do pedido a situação CANCELADO, correto?

Então segue a solução:

1. edite o arquivo /admin/model/sale/order.php

2. procure pelo comentário // Send out any gift voucher mails por volta da linha 490, este comentário fica dentro da function addOrderHistory, então adicione o código abaixo uma linha acima deste comentário:
Código: Selecionar todos
        // Retorna ao estoque se cancelado (verificar a tabela ORDER_STATUS se o item CANCELED é número 7 e mudar na linha abaixo este número se necessário)
		if ((int)$data['order_status_id'] == 7) {
			$order_query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "order` WHERE order_status_id > '0' AND order_id = '" . (int)$order_id . "'");

			if ($order_query->num_rows) {
				$product_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_product WHERE order_id = '" . (int)$order_id . "'");

				foreach($product_query->rows as $product) {
					$this->db->query("UPDATE `" . DB_PREFIX . "product` SET quantity = (quantity + " . (int)$product['quantity'] . ") WHERE product_id = '" . (int)$product['product_id'] . "'");

					$option_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_option WHERE order_id = '" . (int)$order_id . "' AND order_product_id = '" . (int)$product['order_product_id'] . "'");

					foreach ($option_query->rows as $option) {
						$this->db->query("UPDATE " . DB_PREFIX . "product_option_value SET quantity = (quantity + " . (int)$product['quantity'] . ") WHERE product_option_value_id = '" . (int)$option['product_option_value_id'] . "' AND subtract = '1'");
					}
				}
			}
		}
* se precisarem que os produtos retornem ao estoque em outras situações além do CANCELADO, modifique a condição "if" ajustando-a para as suas necessidades

Espero ter ajudado mais uma vez.


*************************************

OBSERVAÇÃO IMPORTANTE: caso utilize este recurso com o módulo da MoIP, cuidado com as mensagens de retorno automático que retornam o status "cancelado", pois, se a MoIP retornar o status de "cancelado" mais de uma vez, é provável que os produtos sejam adicionados várias vezes. Portanto, se isto ocorrer, edite o arquivo retorno_moip.php, no final há o código abaixo:

Código: Selecionar todos
	if (isset($errors)){
	  header("HTTP 200");
	} else {
	  header("HTTP 500");
	}
Então substitua essas linhas por:
Código: Selecionar todos
	  header("HTTP 200");
... até que alguém encontre uma solução melhor. Esta sugestão obtive após a leitura da documentação* disponível no sandbox da MoIP, já que notei que a variável $errors nestas linhas não estava definida em lugar algum, portanto, a resposta para a MoIP era sempre "que houve erro".

* = https://desenvolvedor.moip.com.br/sandb ... nManual.do[/i]
Editado pela última vez por rgtobr em 21 Jan 2012, 13:21, em um total de 1 vez.

Night games. One night, no worries Real Women P[…]

@Manoel Vidal Poderia me ajudar com 2 coisas n[…]

Looking for a partner for an unforgettable night? […]

Vou verificar, Obrigado