Bu dökümanda havale veya EFT ödemelerinin otomatik olarak eticaret sistemindeki ilgili siparişin ödemesi olarak işlenmesi için gerekli kurulum adımları anlatılmıştır.
Kullanılan eticaret sistemi osCommerce 2.2rc2a ‘ dır.
Ödeme bildirim örneği olarak Garanti Bankasının bildirim örneği kullanılmıştır.
Sunucu olarak VPS (sanal sunucu) sunucuda CentOS işletim sistemi kullanılmıştır.
havale.php programı PHP5 veya üstü versiyonlarda çalışmaktadır.
Amacımız banka tarafından gönderilen gelen ödeme hatırlatma epostasını alıp işleyerek ait olduğu siparişin durumunu eticaret sisteminde ödeme alındı olarak güncellemek ve müşteriye eposta ile bildirmek.
Kısaca bir kişi banka havalesi kullanarak verdiği siparişinin ödemesini yaptığında mağazaya ödeme bildirimi yapmasına gerek kalmadan beklemede olan siparişini ödeme yapıldığı anda otomatik olarak işleme koyuyoruz ve müşteriye bildiriyoruz.
Havale IPN (Havale Anında Ödeme Bildirimi ve Havale Otomatik Ödeme Bildirimi. IPN: Instant Payment Notification) sisteminin çalışması için havale açıklamasına sipariş numarası girilmesi zorunludur.
Havale açıklaması olarak 2 farklı format belirledik (havale.php dosyasından alternatif formatlar belirlenebilir.) Bunun dışındaki kullanımda otomatik sipariş güncellemesi çalışmaz.
Örneğin sipariş numarası 123 ise açıklama olarak aşağıdaki örnek formatlardan biri kullanılmalıdır. [tırnak işaretleri kullanmadan]
“123″
veya (tırnak işaretleri kullanmadan)
“123 nolu sipariş için”
veya (tırnak işaretleri kullanmadan)
“123 nolu siparişin ödemesi”
şeklinde sipariş numarası en başta olacak şekilde kullanılmalıdır.
Plesk CentOS VPS sunucularında test edilmiştir. Havale IPN sistemini kurmak için VPS sunucusuna ait (veya özel sunucu) root kullanıcısı erişimi olmalıdır. Komut girmek için dahili plesk içindeki SSH programı veya PuTTY programı kullanılabilir.
1- /var/qmail/mailnames/alanadi.com klasörüne git
cd /var/qmail/mailnames/alanadi.com
2- vi ile .qmail-havale adlı bir dosya aç ve “| php -q /var/www/vhosts/alanadi.com/httpdocs/havale.php” satırını ekle (tırnak işaretleri olmadan. havale@alanadi.com için .qmail-havale dosya adı olmalı)
vi .qmail-havale
3- havale.php dosyası 755, .qmail-havale dosyası 644 chmod olmalı
chmod 644 /var/qmail/mailnames/alanadi.com/.qmail-havale
4- Plesk panelde havale@alanadi.com eposta hesabı açma!
5- havale.php dosyasını sistem PHP olarak tanıması için dosyanın en üstüne #!/usr/bin/php ifadesini ekle
6- son olarak qmail programını yeniden başlatıyoruz
/etc/init.d/qmail restart
Mağaza sahibinin Garanti online bankacılık sisteminde yapması gerekenler ve email yönlendirme (Diğer bankaların internet şubesinde karşılık gelen ödeme hatırlatma tanımlama işlemlerini yapınız).
1-Garanti bankası online bankacılık menüsündeki hatırlatma bölümünden gelen havale eft yi seçip bir eposta adresi gir (gmail olabilir)
2- Yukarıda tanımlanan gmail adresine gmail.com’dan giriş yapıp eposta ayarlarından üst kısımda bulunan “(settings)” i tıkla
3- “Forwarding and POP/IMAP” sekmesindeki “Forward a copy of incoming mail to” de belirtilen alana yukarıda tanımlanan havale@alanadi.com adresini forward adresi olarak tanımla.
Son 3 adımda gelen havalelerin bir kopyasını gmail hesabınada göndermiş oluyoruz. Sunucuda olabilecek sorunlardan dolayı işlenemeyen espostalar yedektekilerden takip edilebilir.
Not: Yukarıdaki havale@alanadi.com ve ornekepostaadresi@gmail.com adreslerini başkası ile paylaşmamanız önerilir.
havale.php dosyası aşağıdadır (#!/usr/bin/php satırı dahil)
#!/usr/bin/php
<?php
/*
havale.php versiyon 1.0
Hazırlayan : OSIcommerce
Lisans: GPL v3
Gelen havale ödeme hatırlatma epostalarını işleyip osCommerce sistemi sipariş durumunu güncellemek için hazırlanmış dosyadır.
Havale IPN olarak adlandırılan bu otomarik bildirim sistemi detaylı kurulum açıklaması için kurulum dosyasını okuyunuz.
*/
/* Veritabanı bağlantıları için gerekli bilgileri includes/configure.php dosyasından alıyoruz */
define('DB_SERVER', 'localhost');
define('DB_SERVER_USERNAME', 'dbkullanciadi');
define('DB_SERVER_PASSWORD', 'sifre');
define('DB_DATABASE', 'veritabani');
define('USE_PCONNECT', 'false');
@setlocale(LC_TIME, 'tr_TR.UTF-8');
define('DATE_FORMAT_LONG', '%d %B %Y, %A'); // this is used for strftime()
/* Programda kullanacağımız fonksiyonlar */
function tep_db_connect($server = DB_SERVER, $username = DB_SERVER_USERNAME, $password = DB_SERVER_PASSWORD, $database = DB_DATABASE, $link = 'db_link') {
global $$link;
$$link = mysql_connect($server, $username, $password);
if ($$link) mysql_select_db($database);
return $$link;
}
function tep_db_close($link = 'db_link') {
global $$link;
return mysql_close($$link);
}
function tep_db_error($query, $errno, $error) {
die('<font color="#000000"><b>' . $errno . ' - ' . $error . '
' . $query . '
<small><font color="#ff0000">[TEP STOP]</font></small>
</b></font>');
}
function tep_db_query($query, $link = 'db_link') {
global $$link;
$result = mysql_query($query, $$link) or tep_db_error($query, mysql_errno(), mysql_error());
return $result;
}
function tep_db_perform($table, $data, $action = 'insert', $parameters = '', $link = 'db_link') {
reset($data);
if ($action == 'insert') {
$query = 'insert into ' . $table . ' (';
while (list($columns, ) = each($data)) {
$query .= $columns . ', ';
}
$query = substr($query, 0, -2) . ') values (';
reset($data);
while (list(, $value) = each($data)) {
switch ((string)$value) {
case 'now()':
$query .= 'now(), ';
break;
case 'null':
$query .= 'null, ';
break;
default:
$query .= '\'' . tep_db_input($value) . '\', ';
break;
}
}
$query = substr($query, 0, -2) . ')';
} elseif ($action == 'update') {
$query = 'update ' . $table . ' set ';
while (list($columns, $value) = each($data)) {
switch ((string)$value) {
case 'now()':
$query .= $columns . ' = now(), ';
break;
case 'null':
$query .= $columns .= ' = null, ';
break;
default:
$query .= $columns . ' = \'' . tep_db_input($value) . '\', ';
break;
}
}
$query = substr($query, 0, -2) . ' where ' . $parameters;
}
return tep_db_query($query, $link);
}
function tep_db_fetch_array($db_query) {
return mysql_fetch_array($db_query, MYSQL_ASSOC);
}
function tep_db_num_rows($db_query) {
return mysql_num_rows($db_query);
}
function tep_db_data_seek($db_query, $row_number) {
return mysql_data_seek($db_query, $row_number);
}
function tep_db_insert_id($link = 'db_link') {
global $$link;
return mysql_insert_id($$link);
}
function tep_db_free_result($db_query) {
return mysql_free_result($db_query);
}
function tep_db_fetch_fields($db_query) {
return mysql_fetch_field($db_query);
}
function tep_db_output($string) {
return htmlspecialchars($string);
}
function tep_db_input($string, $link = 'db_link') {
global $$link;
if (function_exists('mysql_real_escape_string')) {
return mysql_real_escape_string($string, $$link);
} elseif (function_exists('mysql_escape_string')) {
return mysql_escape_string($string);
}
return addslashes($string);
}
function tep_db_prepare_input($string) {
if (is_string($string)) {
return trim(tep_sanitize_string(stripslashes($string)));
} elseif (is_array($string)) {
reset($string);
while (list($key, $value) = each($string)) {
$string[$key] = tep_db_prepare_input($value);
}
return $string;
} else {
return $string;
}
}
function tep_sanitize_string($string) {
$string = ereg_replace(' +', ' ', trim($string));
return preg_replace("/[<>]/", '_', $string);
}
function tep_not_null($value) {
if (is_array($value)) {
if (sizeof($value) > 0) {
return true;
} else {
return false;
}
} else {
if (($value != '') && (strtolower($value) != 'null') && (strlen(trim($value)) > 0)) {
return true;
} else {
return false;
}
}
}
function tep_date_long($raw_date) {
if ( ($raw_date == '0000-00-00 00:00:00') || ($raw_date == '') ) return false;
$year = (int)substr($raw_date, 0, 4);
$month = (int)substr($raw_date, 5, 2);
$day = (int)substr($raw_date, 8, 2);
$hour = (int)substr($raw_date, 11, 2);
$minute = (int)substr($raw_date, 14, 2);
$second = (int)substr($raw_date, 17, 2);
return strftime(DATE_FORMAT_LONG, mktime($hour,$minute,$second,$month,$day,$year));
}
/* Programda kullanacağımız fonksiyonlar - SON */
tep_db_connect() or die('Unable to connect to database server!');
// read from stdin
$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd)) {
$email .= fread($fd, 1024);
}
fclose($fd);
// handle email
$lines = explode("\n", $email);
// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;
for ($i=0; $i<count($lines); $i++) {
if ($splittingheaders) {
// this is a header
$headers .= $lines[$i]."\n";
// look out for special headers
if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) {
$subject = $matches[1];
}
if (preg_match("/^From: (.*)/", $lines[$i], $matches)) {
$from = $matches[1];
}
} else {
// not a header, but message
$message .= $lines[$i]."\n";
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$splittingheaders = false;
}
}
$html = new DOMDocument();
$html->loadHTML(
$message);
//gelen bildirim gövde örneği HTML (Garanti Bankasının ödeme hatırlatma eposta şablonu örnek verilmiştir.)
/*
<span>Sayın <span>MEHMET ALA</span>,</span><p style="line-height:20px"><span><span>AHMET YALÇIN</span> tarafından, <span>Garanti Bankası</span> - <span>KARAKÖY</span> Şubesi'nden <span>123 nolu sipariş için</span> açıklamasıyla gelen <span> 145,00</span> <span>TL</span> havale/EFT, <span>METRO/MECİDİYEKÖY</span> Şubesi'ndeki <span> 678xxx</span> numaralı hesabınıza (IBAN: <span>TR56 0006 xxxx xxxx xxxx xxxx xx</span>) yatırılmıştır. Şu anki bakiyeniz <span> 150</span> <span>TL</span>'dir.</span>
html içinde planları xPath kullanarak çekiyoruz.
spanlar sırası ile şu şekilde (10 aralık 2009 itibari ile Garanti bankasının gelen ödeme hatırlatma epostasına göre)
span 1 : Gönderici Adı Soyadı
span 2 : Gelen Ödeme Banka Adı
span 3 : Gelen Ödeme Şubesi
span 4 : Gelen Ödeme Açıklaması
span 5 : Gelen Ödeme Tutarı
span 6 : Gelen Ödeme Para Birimi
span 7 : Ödemenin Alındığı Hesap Şube Adı
span 8 : Ödemenin Alındığı Hesap Numarası
span 9 : Ödemenin Alındığı Hesabın IBAN Numarası
span 10 : Ödemenin Alındığı Hesabın Bakiyesi
span 11 : Ödemenin Alındığı Hesabın Bakiye Para Birimi
*/
/* HTML bildirim epostası içinde XPath kullanarak gerekli alanları çekmek için sorgulama yapıyoruz. (XPath PHP5 ve sonraki versiyonlarda bulunur.) */
$xpath = new DOMXPath( $html );
$span1 = trim($xpath
->query( "//span[1][@class='param']")
->item(0)->nodeValue
);
$span2 = trim($xpath
->query( "//span[2][@class='param']")
->item(0)->nodeValue
);
$span3 = trim($xpath
->query( "//span[3][@class='param']")
->item(0)->nodeValue
);
$span4 = trim($xpath
->query( "//span[4][@class='param']")
->item(0)->nodeValue
);
$span5 = trim($xpath
->query( "//span[5][@class='param']")
->item(0)->nodeValue
);
$span6 = trim($xpath
->query( "//span[6][@class='param']")
->item(0)->nodeValue
);
$span7 = trim($xpath
->query( "//span[7][@class='param']")
->item(0)->nodeValue
);
$span8 = trim($xpath
->query( "//span[8][@class='param']")
->item(0)->nodeValue
);
$span9 = trim($xpath
->query( "//span[9][@class='param']")
->item(0)->nodeValue
);
$span10 = trim($xpath
->query( "//span[10][@class='param']")
->item(0)->nodeValue
);
$span11 = trim($xpath
->query( "//span[11][@class='param']")
->item(0)->nodeValue
);
// Sipariş nosunu $oID değişkenine atıyoruz.
$oID = tep_db_prepare_input($span4);
//osCommerce ' te 2 işleme alındı sipariş durumunun kodudur.
$status = tep_db_prepare_input('2');
$aciklama = 'Sipariş numarası '. $span4.' olan siparişiniz için '.$span2.' '.$span3.' şubesindeki hesaptan '.$span5.$span6.' tutarındaki havale-EFT işlemi yapılmıştır. Ödemeniz sipariş durumunuza kaydedilmiştir.';
$comments = tep_db_prepare_input($aciklama);
$order_updated = false;
$check_status_query = tep_db_query("select customers_name, customers_email_address, orders_status, date_purchased from orders where orders_id = '" . (int)$oID . "'");
$check_status = tep_db_fetch_array($check_status_query);
/* osCommerce sistemindeki sipariş durum güncellemesi */
// sipariş numarası alındı ise (havale açıklamasınde sadece sipariş nosu veya açıklamanın en başında sipariş nosu varsa)
if ( $check_status['orders_status'] !='') {
tep_db_query("update orders set orders_status = '" . tep_db_input($status) . "', last_modified = now() where orders_id = '" . (int)$oID . "'");
$customer_notified = '0';
$notify_comments = '';
$notify_comments = $comments . "\n\n";
$order_link ='Sipariş faturasına http://alanadi.com/account_history_info.php?order_id='.$oID.' adresinden ulaşabilirsiniz. Sipariş tarihi:'. tep_date_long($check_status['date_purchased']);
$header = 'MIME-Version: 1.0' . "\n" . 'Content-type: text/plain; charset=UTF-8'
. "\n" . 'From: Yourname <' . $from . ">\n";
/* Müşteriye ödemenin alındığı notu ile durum güncellemesini bildiriyoruz */
mail($check_status['customers_email_address'], 'Ödemeniz Alındı-alanadi.com', 'Sayın '.$check_status['customers_name'].' , '. $aciklama.' '.$order_link , $header);
$customer_notified = '1';
tep_db_query("insert into orders_status_history (orders_id, orders_status_id, date_added, customer_notified, comments) values ('" . (int)$oID . "', '" . tep_db_input($status) . "', now(), '" . tep_db_input($customer_notified) . "', '" . tep_db_input($comments) . "')");
$order_updated = true;
}
/* osCommerce sistemindeki sipariş durum güncellemesi - SON */
if ($order_updated == true) {
$siparis_guncellendimi = 'Sipariş Güncellendi';
} else {
$siparis_guncellendimi = 'Sipariş Güncellenemedi';
}
$header = 'MIME-Version: 1.0' . "\n" . 'Content-type: text/plain; charset=UTF-8'
. "\n" . 'From: Yourname <' . $from . ">\n";
mail('magaza.sahibi@gmail.com', 'Havale/EFT Geldi!', $span1.' '.$span2.' '.$span3.' '.$span4.' '.$span5.' '.$span6.' '.$span7.' '.$span8.' '.$span9.' '.$span10.' '.$span11.' '.$siparis_guncellendimi, $header);
?>