Перейти до вмісту
Пошук в
  • Детальніше...
Шукати результати, які ...
Шукати результати в ...

[Решено {payment callback URL}] Не записываются заказы при онлайн оплате


trololo

Recommended Posts

Доброго времени суток. Поставил OpenCart 1.5.3.1 , установил модуль интеркассы, оплата paypal. Когда оплачиваю товар любым из этих методов, деньги снимаются, поступают на счет который указан, но в админке и в аккаунте не отображается новый заказ. В упор его не вижу, оплачивал разными методами. А при методе оплаты "При доставке" заказ успешно виден в админке и в аккаунте. Как исправить проблему? Заранее благодарен за помощь.

Надіслати
Поділитися на інших сайтах


Данная проблема связана с так называемыми колбэками - обратными вызовами. Дело в том, что все "продвинутые" модули оплаты, который позволяют выполнять онлайн платежи через различные платежные системы меняют статусы заказов по вызову с платежного сервера. Соответственно платежный сервер должен "знать" куда сообщать об успешном платеже, то есть ему нужна ссылка с Вашего сайта, обратившись к которой он может передать данные о платеже. Как правило данные ссылки задаются двумя путями:

1) Платежный модуль формирует их (то есть формирует ссылку) и передает шлюзу при оформлении заказа, отправляя форму

2) Ссылки задаются в личном кабинете платежного шлюза.

Следовательно, когда статус заказа не меняется, то возможны три причины

1) Ссылка платежным модулем сформирована неправильно и/или не передана в данных формы

2) Если используется 2 вариант, то ссылка не указана либо указана, но неверная

3) Ссылки передаются/указаны верные, но при обращении к ним возникают различного рода ошибки (баги в модуле оплаты, неправильная настройка модуля)

В случае с пейпалом еще одна проблема, когда все прежде описанное работает, но сам модуль пейпала использует curl для проверки данных при получении колбэка, а curl при этом не установлен либо не работает в силу настроек хостера.

Поэтому самый простой вариант проверки - проверить все настройки по пунктам и проверить логи шлюза/своего сервера на наличие вызовов и ошибок.

  • +1 3
Надіслати
Поділитися на інших сайтах

  • 2 months later...

Данная проблема связана с так называемыми колбэками - обратными вызовами. Дело в том, что все "продвинутые" модули оплаты, который позволяют выполнять онлайн платежи через различные платежные системы меняют статусы заказов по вызову с платежного сервера. Соответственно платежный сервер должен "знать" куда сообщать об успешном платеже, то есть ему нужна ссылка с Вашего сайта, обратившись к которой он может передать данные о платеже. Как правило данные ссылки задаются двумя путями:

1) Платежный модуль формирует их (то есть формирует ссылку) и передает шлюзу при оформлении заказа, отправляя форму

2) Ссылки задаются в личном кабинете платежного шлюза.

Следовательно, когда статус заказа не меняется, то возможны три причины

1) Ссылка платежным модулем сформирована неправильно и/или не передана в данных формы

2) Если используется 2 вариант, то ссылка не указана либо указана, но неверная

3) Ссылки передаются/указаны верные, но при обращении к ним возникают различного рода ошибки (баги в модуле оплаты, неправильная настройка модуля)

В случае с пейпалом еще одна проблема, когда все прежде описанное работает, но сам модуль пейпала использует curl для проверки данных при получении колбэка, а curl при этом не установлен либо не работает в силу настроек хостера.

Поэтому самый простой вариант проверки - проверить все настройки по пунктам и проверить логи шлюза/своего сервера на наличие вызовов и ошибок.

 

Столкнулся с проблемой в модуле Liqpay. Там используется 1-й вариант - ссылка передается в форме. Точнее две ссылке. result_url - страница на которую вернется клиент и server_url - адрес куда посылает ответ сервер. Так указано в API документации к Liq&Buy 1.2.

 

Так вот, в xml форме server_url был указан как обращение к функции callback() в контроллере liqpay ( $this->url->link('payment/liqpay/callback', '', 'SSL') ).

В этой функции производится проверка подписей мерчанта по заданным правилам, и в случае совпадения вызывается функция confirm из модели checkout/order - создается заказ со статусом указанным в настройках модуля Liqpay после успешной оплаты.

А в result_url была указана страница  $this->url->link('checkout/success', '', 'SSL').

 

В итоге что получалось - создавался заказ с нулевым статусом (по-умолчанию). Тыцаешь на кнопку вернутся в магазин после оплаты ( к слову, создание счета для оплаты в терминале - pay_way - delayed) - высвечивается уведомление, мол ваш заказ № такой-то оформлен, можете смотреть в личном кабинете, ссылка, все дела. Но реально статус заказа не изменялся. Т.е. функция callback вообще не срабатывала. Пробовал убирать проверку сигнатуры, на случай каких-то ошибок - даже без проверки функция не обрабатывалась. Как вывод  -то ли сервер не посылает этот запрос до РЕАЛЬНОЙ оплаты счета через терминал, либо я не знаю в чем причина. В итоге я вопрос решил тем что в result_url вписал ссылку не checkout/success, а payment/liqpay/callback и затем redirect на checkout/success - тогда всё стало обрабатываться корректно после нажатия на сайте LIQPAY кнопки "в магазин" после оформления счета для оплаты в терминале самообслуживания.

 

Конечно в процессе тестов обнаружил еще одну любопытную вещь - что при каждом обновлении страницы checkout либо возврате к предыдущим шагам для изменения способа оплаты, способа доставки либо даже написания комментария - КАЖДЫЙ раз создается новый заказ, а предыдущий будет "валяться" в базе данных как "утерянный". В итоге может оказываться огромнейшее количество дублей брошенных заказов, который клиент реально таки оформил, оплатил и вы его выполнили. А в базе у вас останутся эти самые дубли. 

Т.е. клиент начал оформлять заказ под номером 54 к примеру, а потом или страницу обновил или просто ему понравилось пощелкать "шаги оформления" кнопкой "изменить, ну вот прикольно, типа как скользит вверх-вниз - а в базу пишутся новые заказы и оформит он это всё уже под номером, скажем 70. 

А вы будете выводить себе статистику потом ложную, что из 100 набранных корзин заказы сделало 2 человека, хотя реально может оказаться 20. (условно).

Эта проблема решилась очень легко с помощью бесплатного файла vqmod 

ttp://forum.opencart.com/viewtopic.php?t=9192 - вот ссылка на описание данного бага, кому нужно, можете скачать, установить.

Надіслати
Поділитися на інших сайтах


.....

ttp://forum.opencart.com/viewtopic.php?t=9192 - вот ссылка на описание данного бага, кому нужно, можете скачать, установить.

Сделали правильно с редиректами.

Только единственное уточнение - заказ создается с нулевым статусом, а метод confirm подтверждает этот заказ (переводит в статус больше 0) причем сделает это только в случае, если у заказа статус 0, кстати в этот момент и отсылаются письма о заказе.

По второй части - это не баг, а фича опенкарта, чуть ниже - один из ответов почему так сделано.

У себя в Simple я решил этот момент немного иначе, чем в вкмоде, плюс сделал кое-какую проверку, которой в этом вкмоде нет.

А именно может возникнуть такая ситуация (опять же зависит от реализации модулей оплаты)

Клиент создал заказ из 5 товаров на сумму 5000 рублей, номер заказа 20, затем нажал кнопку подтвердить и ушел на оплату заказа номер 20 на сумму 5000 рублей

В другой вкладке открыл страницу корзины, поменял товары, изменив количество/сумму (например стало 6000), прошел шаги заказа, заказ у него пересохранился под номером 20, но в первом окне у него уже инициирована оплата заказа 20 на 5000, которую он может провести. Соответственно без проверки модулем оплаты суммы заказа и суммы оплаты заказ успешно подтвердится, а если даже не подтвердится, то уже добавит головной боли, так как деньги фактически спишутся.

Ситуация конечно гипотетическая, но не невероятная, и поэтому защиту от дурака исключать не стоит.

И поэтому опенкарт пошел по такому пути.

  • +1 2
Надіслати
Поділитися на інших сайтах

.....

ttp://forum.opencart.com/viewtopic.php?t=9192 - вот ссылка на описание данного бага, кому нужно, можете скачать, установить.

....

Ситуация конечно гипотетическая, но не невероятная, и поэтому защиту от дурака исключать не стоит.

И поэтому опенкарт пошел по такому пути.

 

Можете поделиться решением своим?.. Я о этой самой дополнительной проверке?

 

Сам же разобрался - server_url - ответ от сервера приходит тогда, когда на счет поступила оплата. Соответственно самое разумное решение - по возврату клиента (return_url) - подтвердить с помощью confirm заказ и поставить ему статус "ожидание оплаты". А вот для server_url вписать скрипт, который сверяет цифровую подпись и затем присваивает заказу статус оплаченого, после чего клиенту на почту высылается уведомление (если прописать его в вызове функции update). 

Но нужно учесть еще такой момент - клиент мог не нажать кнопку возврата из магазина либо отвлечься, а в это время при оплате с карты например server_url ответ придет раньше, чем вернется клиент по ссылке result_url.

Поэтому для сервера добавил проверку - если статус заказа нулевой - сперва он подтверждается со статусом "ожидание оплаты", отправляется уведомление админу и клиенту, а затем сразу же меняется его статус)

Запутанно может немного написал, но кто вникал в логику работы платежного модуля, думаю поймет :)

Поправьте или подскажите, если чего-то не учёл. Да, еще при ответе сервера, после сверения цифровой подписи проверяется чтобы статус ответа был success.

Надіслати
Поділитися на інших сайтах


  • 1 month later...

а если в платежке можно вписывать url на который нужно переходить после оплаты, не подскажите, какие конкретно адреса туда вписывать:

Вызвать URL после списания средств Вызвать URL после зачисления средств Вызвать URL после отмены списания средств Вызвать URL после отмены зачисления средств
Надіслати
Поділитися на інших сайтах


а если в платежке можно вписывать url на который нужно переходить после оплаты, не подскажите, какие конкретно адреса туда вписывать:

Вызвать URL после списания средств Вызвать URL после зачисления средств Вызвать URL после отмены списания средств Вызвать URL после отмены зачисления средств

Надо смотреть, что в документации модуля оплаты указано, у каждого реализовано по-своему

Надіслати
Поділитися на інших сайтах

  • 2 months later...

Deeman, благодарю Вас! Действительно, в интеркассе следовало прописать пути до страниц. Всё заработало. PayPal проверим позже.

Подробней плиз...

 

Я колдовал с ПайПалом, но ничего не вышло, заказы так и оставались "не видимыми" при успешных транзакциях

Надіслати
Поділитися на інших сайтах


Подробней плиз...

 

Я колдовал с ПайПалом, но ничего не вышло, заказы так и оставались "не видимыми" при успешных транзакциях

а curl установлен и работает? пейпал также использует и его

Надіслати
Поділитися на інших сайтах

а curl установлен и работает? пейпал также использует и его

Да, я как раз думал об этом! 100% curl работает!

Читал даже буржуйские сайты, там что то, как раз писалось про callback, прописывал ссылки и тп, все бестолку :(

Транзакции есть, отображения нет!

Даже в истории заказов в ЛК клиента, нет истории!

 

2 дня потратил, тут писал, но ничего не изменилось :(

 

Но теперь они блокировали мой бизнес счет :) А я собственно на нем и тестил, не знаю на персональном можно, тоже самое делать или нет?

Надіслати
Поділитися на інших сайтах


Да, я как раз думал об этом! 100% curl работает!

Читал даже буржуйские сайты, там что то, как раз писалось про callback, прописывал ссылки и тп, все бестолку :(

Транзакции есть, отображения нет!

Даже в истории заказов в ЛК клиента, нет истории!

 

2 дня потратил, тут писал, но ничего не изменилось :(

 

Но теперь они блокировали мой бизнес счет :) А я собственно на нем и тестил, не знаю на персональном можно, тоже самое делать или нет?

точно не скажу, потому что сам тестировал всегда из-под девелоперского аккаунта

посмотрите логи сервера, вообще приходит ли колбэк после оплаты?

Надіслати
Поділитися на інших сайтах

точно не скажу, потому что сам тестировал всегда из-под девелоперского аккаунта

посмотрите логи сервера, вообще приходит ли колбэк после оплаты?

 

К сожалению в таких нюансах не силен :) Постараюсь поднять логи, если остались.

 

Но, как я сказал все транзакции проходили успешно (те PayPal списывал), после был возврат на страницу "окончания заказа", там где история и тп.

Но при переходе в историю, ее просто не было :) Вот странность то...

 

Ну, а в админке находилось, только в "потерянных"

Надіслати
Поділитися на інших сайтах


Короче все тоже, и не знаю, куда копать... Может кто предложит свои файлы от PayPal?

И опишет настройки...

 

Разблокировали мне мой PayPal, стал снова тестить и снова транзакции есть, в заказах нет!

 

Проблема то эта и на буржуйских сайтах обсуждалась, но и там четкого ответа нет.

Надіслати
Поділитися на інших сайтах


по порядку

1) установлен и работает ли курл

2) в логах сервера посмотрите приходят ли колбэки на сервер после оплаты

 

если оба пункта выполняются, то надо будет смотреть дальше

но мне кажется, что не приходят колбэки

Надіслати
Поділитися на інших сайтах

curl - 100% установлен :) Но проверю снова!

 

А почему колбэки не проходят? Вот здесь я дуб дубом!

 

P.S.

А кто-то уже пользуется приемом через PayPal ?

может просто неправильно настроены, вот и не приходят

Надіслати
Поділитися на інших сайтах

может просто неправильно настроены, вот и не приходят

Вот я и пытаюсь понять :) Может кто сбросит файлы тогда?

 

CURL включен (проверил), неужели у других PAYPAL проводится без проблем?

 

По логам не понимаю, какие именно логи? Ошибок то нет, логи самого Апача или внутри магазина? (не вижу ничего)

Надіслати
Поділитися на інших сайтах


Вот я и пытаюсь понять :) Может кто сбросит файлы тогда?

 

CURL включен (проверил), неужели у других PAYPAL проводится без проблем?

 

По логам не понимаю, какие именно логи? Ошибок то нет, логи самого Апача или внутри магазина? (не вижу ничего)

обычно у серверов настроено ведение логов доступа, т.е. какие ссылки (грубо говоря) открывались с вашего сервера, т.е. какие запросы выполнялись к серверу, среди них и надо искать вызовы к модулю пейпала

Надіслати
Поділитися на інших сайтах

  • 2 months later...

Ааааа ну помогите :)))))

 

Убил почти неделю, ну ничего не помогает!!!

 

Все тоже по ПайПал, перелопатил весь инет буржуйский

Деньги снимаются 
Все проходит, а заказ идет в "потерянные"

смотрел логи и тп ну не вижу проблем, curl активен!
с настройками в самом PayPal тоже ковырялся, ничего...

в буржунете тема обсуждается, но решения не работают

Надіслати
Поділитися на інших сайтах


Ааааа ну помогите :)))))

 

Убил почти неделю, ну ничего не помогает!!!

 

Все тоже по ПайПал, перелопатил весь инет буржуйский

Деньги снимаются 

Все проходит, а заказ идет в "потерянные"

смотрел логи и тп ну не вижу проблем, curl активен!

с настройками в самом PayPal тоже ковырялся, ничего...

в буржунете тема обсуждается, но решения не работают

 

Скопируйте сюда код контроллера из (catalog/controller/payment/paypal.php), тогда можно будет попробовать найти проблему, что-то подсказать. Ошибка скорее всего в нем.

Надіслати
Поділитися на інших сайтах


Стандартный модуль PayPal Standart

<?php
class ControllerPaymentPPStandard extends Controller {
	protected function index() {
		$this->language->load('payment/pp_standard');
		
		$this->data['text_testmode'] = $this->language->get('text_testmode');		
    	
		$this->data['button_confirm'] = $this->language->get('button_confirm');

		$this->data['testmode'] = $this->config->get('pp_standard_test');
		
		if (!$this->config->get('pp_standard_test')) {
    		$this->data['action'] = 'https://www.paypal.com/cgi-bin/webscr';
  		} else {
			$this->data['action'] = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
		}

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

		$order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']);

		if ($order_info) {
			$this->data['business'] = $this->config->get('pp_standard_email');
			$this->data['item_name'] = html_entity_decode($this->config->get('config_name'), ENT_QUOTES, 'UTF-8');				
			
			$this->data['products'] = array();
			
			foreach ($this->cart->getProducts() as $product) {
				$option_data = array();
	
				foreach ($product['option'] as $option) {
					if ($option['type'] != 'file') {
						$value = $option['option_value'];	
					} else {
						$filename = $this->encryption->decrypt($option['option_value']);
						
						$value = utf8_substr($filename, 0, utf8_strrpos($filename, '.'));
					}
										
					$option_data[] = array(
						'name'  => $option['name'],
						'value' => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . '..' : $value)
					);
				}
				
				$this->data['products'][] = array(
					'name'     => $product['name'],
					'model'    => $product['model'],
					'price'    => $this->currency->format($product['price'], $order_info['currency_code'], false, false),
					'quantity' => $product['quantity'],
					'option'   => $option_data,
					'weight'   => $product['weight']
				);
			}	
			
			$this->data['discount_amount_cart'] = 0;
			
			$total = $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $order_info['currency_code'], false, false);

			if ($total > 0) {
				$this->data['products'][] = array(
					'name'     => $this->language->get('text_total'),
					'model'    => '',
					'price'    => $total,
					'quantity' => 1,
					'option'   => array(),
					'weight'   => 0
				);	
			} else {
				$this->data['discount_amount_cart'] -= $total;
			}
			
			$this->data['currency_code'] = $order_info['currency_code'];
			$this->data['first_name'] = html_entity_decode($order_info['payment_firstname'], ENT_QUOTES, 'UTF-8');	
			$this->data['last_name'] = html_entity_decode($order_info['payment_lastname'], ENT_QUOTES, 'UTF-8');	
			$this->data['address1'] = html_entity_decode($order_info['payment_address_1'], ENT_QUOTES, 'UTF-8');	
			$this->data['address2'] = html_entity_decode($order_info['payment_address_2'], ENT_QUOTES, 'UTF-8');	
			$this->data['city'] = html_entity_decode($order_info['payment_city'], ENT_QUOTES, 'UTF-8');	
			$this->data['zip'] = html_entity_decode($order_info['payment_postcode'], ENT_QUOTES, 'UTF-8');	
			$this->data['country'] = $order_info['payment_iso_code_2'];
			$this->data['email'] = $order_info['email'];
			$this->data['invoice'] = $this->session->data['order_id'] . ' - ' . html_entity_decode($order_info['payment_firstname'], ENT_QUOTES, 'UTF-8') . ' ' . html_entity_decode($order_info['payment_lastname'], ENT_QUOTES, 'UTF-8');
			$this->data['lc'] = $this->session->data['language'];
			$this->data['return'] = $this->url->link('checkout/success');
			$this->data['notify_url'] = $this->url->link('payment/pp_standard/callback', '', 'SSL');
			$this->data['cancel_return'] = $this->url->link('checkout/checkout', '', 'SSL');
			
			if (!$this->config->get('pp_standard_transaction')) {
				$this->data['paymentaction'] = 'authorization';
			} else {
				$this->data['paymentaction'] = 'sale';
			}
			
			$this->data['custom'] = $this->encryption->encrypt($this->session->data['order_id']);
		
			if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/payment/pp_standard.tpl')) {
				$this->template = $this->config->get('config_template') . '/template/payment/pp_standard.tpl';
			} else {
				$this->template = 'default/template/payment/pp_standard.tpl';
			}
	
			$this->render();
		}
	}
	
	public function callback() {
		if (isset($this->request->post['custom'])) {
			$order_id = $this->encryption->decrypt($this->request->post['custom']);
		} else {
			$order_id = 0;
		}		
		
		$this->load->model('checkout/order');
				
		$order_info = $this->model_checkout_order->getOrder($order_id);
		
		if ($order_info) {
			$request = 'cmd=_notify-validate';
		
			foreach ($this->request->post as $key => $value) {
				$request .= '&' . $key . '=' . urlencode(html_entity_decode($value, ENT_QUOTES, 'UTF-8'));
			}
			
			if (!$this->config->get('pp_standard_test')) {
				$curl = curl_init('https://www.paypal.com/cgi-bin/webscr');
			} else {
				$curl = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr');
			}

			curl_setopt($curl, CURLOPT_POST, true);
			curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
			curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($curl, CURLOPT_HEADER, false);
			curl_setopt($curl, CURLOPT_TIMEOUT, 30);
			curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
					
			$response = curl_exec($curl);
			
			if (!$response) {
				$this->log->write('PP_STANDARD :: CURL failed ' . curl_error($curl) . '(' . curl_errno($curl) . ')');
			}
					
			if ($this->config->get('pp_standard_debug')) {
				$this->log->write('PP_STANDARD :: IPN REQUEST: ' . $request);
				$this->log->write('PP_STANDARD :: IPN RESPONSE: ' . $response);
			}
						
			if ((strcmp($response, 'VERIFIED') == 0 || strcmp($response, 'UNVERIFIED') == 0) && isset($this->request->post['payment_status'])) {
				$order_status_id = $this->config->get('config_order_status_id');
				
				switch($this->request->post['payment_status']) {
					case 'Canceled_Reversal':
						$order_status_id = $this->config->get('pp_standard_canceled_reversal_status_id');
						break;
					case 'Completed':
						if ((strtolower($this->request->post['receiver_email']) == strtolower($this->config->get('pp_standard_email'))) && ((float)$this->request->post['mc_gross'] == $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false))) {
							$order_status_id = $this->config->get('pp_standard_completed_status_id');
						} else {
							$this->log->write('PP_STANDARD :: RECEIVER EMAIL MISMATCH! ' . strtolower($this->request->post['receiver_email']));
						}
						break;
					case 'Denied':
						$order_status_id = $this->config->get('pp_standard_denied_status_id');
						break;
					case 'Expired':
						$order_status_id = $this->config->get('pp_standard_expired_status_id');
						break;
					case 'Failed':
						$order_status_id = $this->config->get('pp_standard_failed_status_id');
						break;
					case 'Pending':
						$order_status_id = $this->config->get('pp_standard_pending_status_id');
						break;
					case 'Processed':
						$order_status_id = $this->config->get('pp_standard_processed_status_id');
						break;
					case 'Refunded':
						$order_status_id = $this->config->get('pp_standard_refunded_status_id');
						break;
					case 'Reversed':
						$order_status_id = $this->config->get('pp_standard_reversed_status_id');
						break;	 
					case 'Voided':
						$order_status_id = $this->config->get('pp_standard_voided_status_id');
						break;								
				}
				
				if (!$order_info['order_status_id']) {
					$this->model_checkout_order->confirm($order_id, $order_status_id);
				} else {
					$this->model_checkout_order->update($order_id, $order_status_id);
				}
			} else {
				$this->model_checkout_order->confirm($order_id, $this->config->get('config_order_status_id'));
			}
			
			curl_close($curl);
		}	
	}
}
?>
Надіслати
Поділитися на інших сайтах


Почитайте статьи:

http://habrahabr.ru/post/137080/
http://habrahabr.ru/post/128198/
 

может на мысль наведет, что у Вас не так настроено.

Так же скажите какие настройки сделали в самом paypal Для работы с интернет-магазином? 
(закладки "мой счет", в меню Профиль-Дополнительные функции, далее меню "мои инструменты продаж")

Надіслати
Поділитися на інших сайтах


Гість
Ця тема закрита для публікації повідомлень.
  • Зараз на сторінці   0 користувачів

    • Ні користувачів, які переглядиють цю сторінку
×
×
  • Створити...

Important Information

На нашому сайті використовуються файли cookie і відбувається обробка деяких персональних даних користувачів, щоб поліпшити користувальницький інтерфейс. Щоб дізнатися для чого і які персональні дані ми обробляємо перейдіть за посиланням . Якщо Ви натиснете «Я даю згоду», це означає, що Ви розумієте і приймаєте всі умови, зазначені в цьому Повідомленні про конфіденційність.