📜 ⬆️ ⬇️

Connecting Facebook Credits for online stores

Hi, Habr. Not so long ago we wrote a module that connects 1C-Bitrix stores to the social network Facebook. I want to share my experience, as well as the features of setting up reception of Facebook Credits in your store - it does not matter what CMS it is implemented on. Rushed!


History reference


Facebook Credits is the local currency of the social networking site Facebook, which first appeared in 2009, and became the only allowed one, according to the rules of Facebook, since June 1 of this year. For a long time, it was impossible to connect a Russian bank for the withdrawal of earned loans - Russia was simply not in the list of countries for connecting Facebook Credits.

The only possible ways to withdraw earned loans were either withdrawal via PayPal (there is no legal, white or fluffy way out of PayPal to Russia at the moment ), or opening an account in a foreign bank. However, on June 27, Russia appeared in the form of connecting payments, although it is not yet on the official list . But we really hope and are ready :-)
')

We connect payments to the application


We will proceed from the fact that you already have a working application for Facebook, and your task is to connect the acceptance of credits. So, go to the settings of your application.
and click "Edit". Go to the section "On Facebook" -> Credits. Follow the link to register a new company . Carefully fill in the fields on your organization. The most interesting tab is the third one. This is a bank account setup.


Immediately a few tips. The form podglyuchivaet a few, and if you fill it in incorrectly, it erases some of the fields. Therefore, I recommend not to click on the “OK” button, but to click “Open in a separate window” - so even in case of errors, you will not have to interrupt the data again. Fill in all fields in English. Enter the SWIFT field without spaces.


After registering an organization, you can add it to receive credits in your application.

On a note


According to the rules of Facebook, you can sell only virtual goods for Facebook Credits. Personally, I would be interested to know whether the sale of QR codes is a virtual commodity (if, for example, you can go to the movies by this QR code or order a pizza :-)).
Facebook commission is 30% (this is a lot, but less than, for example, in Odnoklassniki). In general, there are nuances that need to be taken into account when planning a business strategy for sales in social networks.

The overall scheme of Facebook Credits


So, let's see what happens in your application at the moment when the user decides to pay for something and clicks on the cherished button.


Your application using the JavaScript call Facebook Api creates a payment dialog for the goods:
FB.init({appId: <?=$facebookAppID?>, status: true, cookie: true}); function placeOrder() { //    var obj = { method: 'pay', order_info: {"order_id": "<?=$orderId?>"}, purchase_type: 'item' }; FB.ui(obj, callback); } var callback = function(data) { if (data['order_id']) { $("#payment").hide(); $("#result-success").show(); } else if ((data['error_code']) && (data['error_message'].indexOf("User canceled", 0) == -1)) { $("#payment").hide(); $("#result-failure").show(); } else if ((data['error_code']) && (data['error_message'].indexOf("User canceled", 0) != -1)) { $("#result-cancel").show(); } else { $("#result-failure").show(); } }; 



Facebook sends a request to the server side of your application for order details:

As you have noticed, Facebook assumes that a user can buy only one product per transaction. But nothing prevents you from forming the entire contents of the basket in the form of goods.

Client callback will be called immediately after the payment window is closed. In it, you must process the error / cancellation code, if any, or congratulate the user on a successful purchase.

We accept the order


As soon as the user confirms the payment, a second request is sent to your server to change the status of the order. If everything is ok, your task is to implement an order handler. For example, send the owner of the store a notification about the order, or set the status “paid” in the database.

 <?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php"); if (!CModule::IncludeModule("sale") || !CModule::IncludeModule("iblock")) { echo(" -  !"); require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/epilog_after.php"); die(); } //    $frontendPath = COption::GetOptionString("sibirix.freshshop", "frontend"); $catalogIblockId = COption::GetOptionString("sibirix.freshshop", "catalogIblockId"); $fbcExchange = COption::GetOptionString("sibirix.freshshop", "exchange"); $api_key = COption::GetOptionString("sibirix.freshshop", "facebook_appid"); $secret = COption::GetOptionString("sibirix.freshshop", "facebook_appsecret"); require_once('facebook.php'); // prepare the return data array $data = array('content' => array()); $request = parse_signed_request($_REQUEST['signed_request'], $secret); if ($request == null) { // handle an unauthenticated request here die("empty request\n"); } //    order_id     float         (      ,    FB).    $payloadData = explode('.', $_REQUEST['signed_request'], 2); $payloadData = base64_url_decode($payloadData[1]); preg_match('/\"order_id\"\:([0-9]*)/', $payloadData, $matches); $stringOrderId = $matches[1]; $payload = $request['credits']; // retrieve all params passed in $func = $_REQUEST['method']; $order_info = json_decode($payload['order_info']); if (!empty($order_info) && isset($order_info->order_id)) { $orderId = (int)$order_info->order_id; } if (empty($orderId)) { //   ( ),     order_id  .      order_id $orderRes = CSaleOrder::GetList(array(), array("COMMENTS" => $stringOrderId, "PAYED" => "N"), false, false, array("*")); $orderData = $orderRes->GetNext(); $orderId = $orderData['ID']; } else { //       $orderData = CSaleOrder::GetByID($orderId); } $basketRes = CSaleBasket::GetList(array(), array( "LID" => SITE_ID, "ORDER_ID" => $orderId), false, false, array("*")); $basket = array(); $description = array(); $itemIds = array(); while ($item = $basketRes->GetNext()) { $basket[] = $item; $description[] = iconv(SITE_CHARSET, "UTF-8", $item['~NAME']) . " - " . number_format($item['QUANTITY'], 0) . "."; if (!empty($item['PRODUCT_ID'])) $itemIds[] = $item['PRODUCT_ID']; } if (count($itemIds)) { $res = CIBlockElement::GetList(array(), array("IBLOCK_ID" => $catalogIblockId, "ID" => $itemIds), false, false, array("DETAIL_PICTURE", "PREVIEW_PICTURE")); while ($item = $res->GetNext()) { if (!empty($item['DETAIL_PICTURE'])) { $pictureId = $item['DETAIL_PICTURE']; break; } if (!empty($item['PREVIEW_PICTURE'])) { $pictureId = $item['PREVIEW_PICTURE']; break; } } } if (isset($pictureId)) { $uploadDir = "/" . COption::GetOptionString("main", "upload_dir", "upload") . "/"; $resFile = CFile::GetList(array(), array("ID" => $pictureId)); $ifile = $resFile->Fetch(); $picture = $ifile; $picture['SRC'] = $uploadDir . $ifile["SUBDIR"] . "/" . $ifile['FILE_NAME']; } $picture = CFacebookShop::getThumbImage($picture, CFacebookShop::PRODUCT_PREVIEW_IMG, SITE_TEMPLATE_PATH.'/images'); if ($orderData['PAYED'] == "Y") { //     $data['content']['status'] = 'settled'; } elseif ($func == 'payments_status_update') { // FB  ,     $status = $payload['status']; // write your logic here, determine the state you wanna move to if ($status == 'placed') { $next_state = 'settled'; $data['content']['status'] = $next_state; //   $ret = CSaleOrder::PayOrder($orderId, "Y"); } // compose returning data array_change_key_case $data['content']['order_id'] = $orderId; } else if ($func == 'payments_get_items') { // FB      $item['title'] = ' №' . $orderId . "    " . COption::GetOptionString("main", "site_name"); $item['price'] = ceil($orderData['PRICE'] / $fbcExchange); $item['description'] = implode(", ", $description); $item['image_url'] = "http://" . COption::GetOptionString("main", "server_name") . $picture; $item['product_url'] = "http://" . COption::GetOptionString("main", "server_name") . $picture; $item['order_id'] = $orderId; CSaleOrder::Update($orderId, array("COMMENTS" => $stringOrderId)); $data['content'] = array($item); } // required by api_fetch_response() $data['method'] = $func; // send data back echo json_encode($data); // you can find the following functions and more details // on http://developers.facebook.com/docs/authentication/canvas function parse_signed_request($signed_request, $secret) { list($encoded_sig, $payload) = explode('.', $signed_request, 2); $sig = base64_url_decode($encoded_sig); $data = json_decode(base64_url_decode($payload), true); if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') { error_log('Unknown algorithm. Expected HMAC-SHA256'); return null; } // check signature $expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true); if ($sig !== $expected_sig) { error_log('Bad Signed JSON signature!'); return null; } return $data; } function base64_url_decode($input) { return base64_decode(strtr($input, '-_', '+/')); } require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_after.php");?> 


We register payment system




We wrote the payment specifically for orders through 1C-Bitrix, so it remains a trifle: to register the payment system in the list of 1C-Bitrix payment systems when installing the module:

 //    Facebook Credits function InstallPaysystem() { if (!CModule::IncludeModule("sale") || !CModule::IncludeModule("catalog")) { throw new Exception("Can't include sale and catalog modules"); } $paysystemRes = CSalePaySystem::GetList(array(), array("NAME" => "Facebook Credits")); $paysystem = $paysystemRes->GetNext(); if (!empty($paysystem)) { //  ,   ID COption::SetOptionString($this->MODULE_ID, "paysystemId", $paysystem['ID']); return true; } else { $paysystemId = CSalePaySystem::Add(array( "LID" => SITE_ID, "CURRENCY" => CCurrency::GetBaseCurrency(), "NAME" => "Facebook Credits", "ACTIVE" => "N", "DESCRIPTION" => GetMessage("SHOPBOOK_INSTALL_FBC_DESCR") )); COption::SetOptionString($this->MODULE_ID, "paysystemId", $paysystem['ID']); } return true; } 


Voila! Our store is ready to receive virtual money from Facebook Credits, ct.d.

Source: https://habr.com/ru/post/125718/


All Articles