Paypal standard, articles séparés, problème si pas de retour
Publié: 06 Oct 2010, 11:37
Bonjour,
Etant utilisateur d'OSCommerce, j'ai eu envie d'essayer la version 1.4.8 FR d'OpenCart. J'observe quelques problèmes, que j'ai déjà expérimentés et corrigés avec OSCommerce.
Tout d'abord avec le module Paypal standard intégré, quand on arrive sur le paiement, le panier n'est pas décrit complètement, on a juste un seul article qui représente le total, avec comme nom celui de la boutique. Pas très pratique quand on reçoit un paiement. Ceci n'est pas grave quand le client clique bien sur "retour à la boutique" car la commande est enregistrée correctement et on a le détail.
Par contre, si le client ferme la page et ne revient pas sur la boutique, le paiement est ok, mais la commande n'est pas enregistrée, le panier pas vidé. Dans ce cas là il est utile d'avoir la description complète des articles commandés dans l'email de paypal, pour éviter d'avoir a téléphoner au client pour lui demander ce qu'il a commandé (pas terrible quand même...)
N'ayant pas trouvé d'info à ce sujet sur ce forum, j'en ai par contre trouvé sur celui anglais :
http://forum.opencart.com/viewtopic.php?f=119&t=8568&start=0
on trouve un code du fichier pp_standard.php qui semble fonctionner correctement avec la 1.4.8 (après un bref test de ma part), sur le dernier post de la 2ème page.
il faut aussi télécharger la dernière version du correctif qui se situe un peu plus haut dans la 2ème page, pour avoir le fichier .tpl correspondant.
http://forum.opencart.com/download/file.php?id=2569
Avec cela on résous donc le problème et le panier chez paypal est identique à celui de la boutique, les articles sont séparés.
Par contre pour le 2ème souci, à savoir quand le client ne retourne pas sur la boutique après le paiement, on ne trouve aucune trace de la commande dans l'administration d'OpenCart. Dans ce cas là comment faire? existe-t-il une extension, un module pour enregistrer la commande avant le paiement?
Dans OSCommerce, il y a une contribution "OrderCheck" très pratique : elle enregistre la commande avant paiement, pas dans la section commande normale, mais dans une autre. Cependant la commande est identique à une "vraie", on a le descriptif complet, etc. Comme ça si un client ne reviens pas sur la boutique après paiement, on a le descriptif dans l'email de paypal, on va dans l'admin et on déplace la commande dans la section normale, elle est bien associée au client, on la trouve dans son historique. La seule chose qui reste, c'est le panier du client qui n'est pas vidé, mais ça reste un détail.
http://www.oscommerce.com/community/contributions,1168
Existe-t-il un équivalent pour OpenCart? si ce n'est pas le cas, je pense que ça vaudrait le coup de l'adapter, d'autant plus que paypal n'est pas le seul moyen de paiement ou il y aura le problème quand les clients ne revienne pas sur la boutique. Cela dit c'est une "moitié" de problème si j'ose dire, car quand le client paye avec son compte paypal au lieu d'une CB, une option du compte paypal du marchand permet de rediriger automatiquement le client vers la boutique, au bout de quelques secondes. (il peut néanmoins y avoir le problème si le client n'attend pas et ferme direct la fenêtre...) Mais cette option n'est pas disponible quand le client paye en CB.
Je n'ai pas les connaissances nécessaires en programmation pour l'adapter moi-même, voilà pourquoi je vous fait part de tout ça
Etant utilisateur d'OSCommerce, j'ai eu envie d'essayer la version 1.4.8 FR d'OpenCart. J'observe quelques problèmes, que j'ai déjà expérimentés et corrigés avec OSCommerce.
Tout d'abord avec le module Paypal standard intégré, quand on arrive sur le paiement, le panier n'est pas décrit complètement, on a juste un seul article qui représente le total, avec comme nom celui de la boutique. Pas très pratique quand on reçoit un paiement. Ceci n'est pas grave quand le client clique bien sur "retour à la boutique" car la commande est enregistrée correctement et on a le détail.
Par contre, si le client ferme la page et ne revient pas sur la boutique, le paiement est ok, mais la commande n'est pas enregistrée, le panier pas vidé. Dans ce cas là il est utile d'avoir la description complète des articles commandés dans l'email de paypal, pour éviter d'avoir a téléphoner au client pour lui demander ce qu'il a commandé (pas terrible quand même...)
N'ayant pas trouvé d'info à ce sujet sur ce forum, j'en ai par contre trouvé sur celui anglais :
http://forum.opencart.com/viewtopic.php?f=119&t=8568&start=0
on trouve un code du fichier pp_standard.php qui semble fonctionner correctement avec la 1.4.8 (après un bref test de ma part), sur le dernier post de la 2ème page.
- Code: Tout sélectionner
<?php
class ControllerPaymentPPStandard extends Controller {
///////Q: START ITEMIZED CODE /////////
protected function index() {
$this->data['button_confirm'] = $this->language->get('button_confirm');
$this->data['button_back'] = $this->language->get('button_back');
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']);
// Check for supported currency, otherwise convert to USD.
$supported_currencies = array('AUD','CAD','EUR','GBP','JPY','USD','NZD','CHF','HKD','SGD','SEK','DKK','PLN','NOK','HUF','CZK','ILS','MXN');
if (in_array($order_info['currency'], $supported_currencies)) {
$currency = $order_info['currency'];
} else {
$currency = 'USD';
}
$useItemized = 1; // set to 0 if you don't want itemized
$useItemizedwCoupon = 0; // set to 0 if you don't want itemized when a coupon is in use.
// Get All taxes, shipping fees, and order totals
$total = 0;
$taxes = $this->cart->getTaxes();
$this->load->model('checkout/extension');
$sort_order = array();
$results = $this->model_checkout_extension->getExtensions('total');
if (!isset($this->session->data['shipping_method'])) { $this->session->data['shipping_method']['cost'] = '0.00'; }
foreach ($results as $key => $value) {
$sort_order[$key] = $this->config->get($value['key'] . '_sort_order');
}
array_multisort($sort_order, SORT_ASC, $results);
foreach ($results as $result) {
$this->load->model('total/' . $result['key']);
$this->{'model_total_' . $result['key']}->getTotal($total_data, $total, $taxes);
}
$total = $this->currency->format($total, $currency, FALSE, FALSE);
$this->data['fields'] = array();
$i=1;
if ($useItemized && ($useItemizedwCoupon || !isset($this->session->data['coupon']))) {
$this->data['fields']['cmd'] = '_cart';
$this->data['fields']['upload'] = '1';
$this->data['fields']['shipping_1'] = $this->currency->format($this->session->data['shipping_method']['cost'], $currency, FALSE, FALSE);
$taxtotal = 0;
foreach ($this->cart->getTaxes() as $key => $value) {
$taxtotal += $this->currency->format($value, $currency, FALSE, FALSE);
}
$this->data['fields']['tax']=$taxtotal;
$this->data['fields']['tax_cart']=$taxtotal;
$pp_total = 0;
foreach ($this->cart->getProducts() as $result) {
$price = $this->currency->format($result['price'], $currency, FALSE, FALSE);
$this->data['fields']['item_number_' . $i . '']=$result['model'];
$this->data['fields']['item_name_' . $i . '']=$result['name'];
$this->data['fields']['amount_' . $i . '']=$price;
$this->data['fields']['quantity_' . $i . '']=$result['quantity'];
$this->data['fields']['weight_' . $i . '']=$result['weight'];
$pp_total += ($price * $result['quantity']);
if (!empty($result['option'])) {
$x=0;
foreach ($result['option'] as $res) {
$this->data['fields']['on' . $x . '_' . $i . '']=$res['name'];
$this->data['fields']['os' . $x . '_' . $i . '']=$res['value'];
$x++;
}
}
$i++;
}
// Cumulative total of what Paypal thinks it is
$pp_total += $this->currency->format($this->session->data['shipping_method']['cost'], $currency, FALSE, FALSE);
$pp_total += $taxtotal;
// If Total is more or less than product + shipping + tax. Then there must be an order total
// module like 'low order fee' affecting the price. Take that difference as either
// a discount or an additional handling fee.
if ($pp_total > $total) {
$this->data['fields']['discount_amount_cart'] = ($pp_total - $total);
} else {
$this->data['fields']['shipping_2'] = number_format(($total - $pp_total), 2, '.', '');
}
} else { //non-itemized
$this->data['fields']['cmd'] = '_xclick';
$this->data['fields']['item_name'] = html_entity_decode($this->config->get('config_store'), ENT_QUOTES, 'UTF-8');
$this->data['fields']['amount'] = $this->currency->format($order_info['total'], $currency, FALSE, FALSE);
}
$this->data['fields']['business'] = $this->config->get('pp_standard_email');
$this->data['fields']['currency_code'] = $currency;
$this->data['fields']['first_name'] = html_entity_decode($order_info['payment_firstname'], ENT_QUOTES, 'UTF-8');
$this->data['fields']['last_name'] = html_entity_decode($order_info['payment_lastname'], ENT_QUOTES, 'UTF-8');
$this->data['fields']['address1'] = html_entity_decode($order_info['payment_address_1'], ENT_QUOTES, 'UTF-8');
$this->data['fields']['address2'] = html_entity_decode($order_info['payment_address_2'], ENT_QUOTES, 'UTF-8');
$this->data['fields']['city'] = html_entity_decode($order_info['payment_city'], ENT_QUOTES, 'UTF-8');
$this->data['fields']['zip'] = html_entity_decode($order_info['payment_postcode'], ENT_QUOTES, 'UTF-8');
$this->data['fields']['country'] = $order_info['payment_iso_code_2'];
$this->data['fields']['notify_url'] = HTTPS_SERVER . 'index.php?route=payment/pp_standard/callback';
$this->data['fields']['email'] = $order_info['email'];
$this->data['fields']['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['fields']['lc'] = $order_info['payment_iso_code_2'];
$this->data['fields']['rm'] = '2';
if (!$this->config->get('pp_standard_transaction')) {
$this->data['fields']['paymentaction'] = 'authorization';
} else {
$this->data['fields']['paymentaction'] = 'sale';
}
$this->data['fields']['return'] = HTTPS_SERVER . 'index.php?route=checkout/success';
$this->data['fields']['cancel_return'] = HTTPS_SERVER . 'index.php?route=checkout/payment';
$this->load->library('encryption');
$encryption = new Encryption($this->config->get('config_encryption'));
$this->data['fields']['custom'] = $encryption->encrypt($this->session->data['order_id']);
//bug fix
//$this->data['back'] = HTTPS_SERVER . 'index.php?route=checkout/payment';
if ($this->request->get['route'] != 'checkout/guest_step_3') {
$this->data['back'] = HTTPS_SERVER . 'index.php?route=checkout/payment';
} else {
$this->data['back'] = HTTPS_SERVER . 'index.php?route=checkout/guest_step_2';
}
$this->id = 'payment';
//$this->template = $this->config->get('config_template') . 'payment/pp_standard.tpl';
//Q: pre-1.3.3 Backwards compatibility check
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';
} elseif (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/payment/pp_standard.tpl')) {
$this->template = $this->config->get('config_template') . '/payment/pp_standard.tpl';
} else {
$this->template = 'default/template/payment/pp_standard.tpl';
}
$this->render();
}
///////Q: END ITEMIZED CODE /////////
public function callback() {
$this->load->library('encryption');
$encryption = new Encryption($this->config->get('config_encryption'));
if (isset($this->request->post['custom'])) {
$order_id = $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(stripslashes($value));
$request .= '&' . $key . '=' . urlencode(htmlspecialchars_decode(stripslashes($value), ENT_QUOTES));
}
if (extension_loaded('curl')) {
if (!$this->config->get('pp_standard_test')) {
$ch = curl_init('https://www.paypal.com/cgi-bin/webscr');
} else {
$ch = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr');
}
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
if (strcmp($response, 'VERIFIED') == 0) {
$this->model_checkout_order->confirm($order_id, $this->config->get('pp_standard_order_status_id'));
} else {
$this->model_checkout_order->confirm($order_id, $this->config->get('config_order_status_id'));
mail($this->config->get('config_email'), 'ATTN: Unverified Paypal Order', "Order ID: $order_id needs manual review");
}
curl_close($ch);
} else {
$header = 'POST /cgi-bin/webscr HTTP/1.0' . "\r\n";
$header .= 'Content-Type: application/x-www-form-urlencoded' . "\r\n";
$header .= 'Content-Length: ' . strlen(utf8_decode($request)) . "\r\n\r\n";
$header .= 'Connection: close' ."\r\n\r\n";
if (!$this->config->get('pp_standard_test')) {
$fp = fsockopen('www.paypal.com', 80, $errno, $errstr, 30);
} else {
$fp = fsockopen('www.sandbox.paypal.com', 80, $errno, $errstr, 30);
}
if ($fp) {
fputs($fp, $header . $request);
while (!feof($fp)) {
$response = fgets($fp, 1024);
if (strcmp($response, 'VERIFIED') == 0) {
$this->model_checkout_order->confirm($order_id, $this->config->get('pp_standard_order_status_id'));
} else {
$this->model_checkout_order->confirm($order_id, $this->config->get('config_order_status_id'));
mail($this->config->get('config_email'), 'ATTN: Unverified Paypal Order', "Order ID: $order_id needs manual review");
}
}
fclose($fp);
}
}
} else {
mail($this->config->get('config_email'), 'ATTN: NO PAYPAL IPN ORDER ID', "PAYPAL IPN RETURNED BUT NO MATCHING ORDER ID");
}
}
}
?>
il faut aussi télécharger la dernière version du correctif qui se situe un peu plus haut dans la 2ème page, pour avoir le fichier .tpl correspondant.
http://forum.opencart.com/download/file.php?id=2569
Avec cela on résous donc le problème et le panier chez paypal est identique à celui de la boutique, les articles sont séparés.
Par contre pour le 2ème souci, à savoir quand le client ne retourne pas sur la boutique après le paiement, on ne trouve aucune trace de la commande dans l'administration d'OpenCart. Dans ce cas là comment faire? existe-t-il une extension, un module pour enregistrer la commande avant le paiement?
Dans OSCommerce, il y a une contribution "OrderCheck" très pratique : elle enregistre la commande avant paiement, pas dans la section commande normale, mais dans une autre. Cependant la commande est identique à une "vraie", on a le descriptif complet, etc. Comme ça si un client ne reviens pas sur la boutique après paiement, on a le descriptif dans l'email de paypal, on va dans l'admin et on déplace la commande dans la section normale, elle est bien associée au client, on la trouve dans son historique. La seule chose qui reste, c'est le panier du client qui n'est pas vidé, mais ça reste un détail.
http://www.oscommerce.com/community/contributions,1168
Existe-t-il un équivalent pour OpenCart? si ce n'est pas le cas, je pense que ça vaudrait le coup de l'adapter, d'autant plus que paypal n'est pas le seul moyen de paiement ou il y aura le problème quand les clients ne revienne pas sur la boutique. Cela dit c'est une "moitié" de problème si j'ose dire, car quand le client paye avec son compte paypal au lieu d'une CB, une option du compte paypal du marchand permet de rediriger automatiquement le client vers la boutique, au bout de quelques secondes. (il peut néanmoins y avoir le problème si le client n'attend pas et ferme direct la fenêtre...) Mais cette option n'est pas disponible quand le client paye en CB.
Je n'ai pas les connaissances nécessaires en programmation pour l'adapter moi-même, voilà pourquoi je vous fait part de tout ça