Payment with Saferpay, whats the correct Success url? - php

In my online shop, I'm using Saferpay as a Payment Gateway.
When the customer clicks the "Pay" button, his order will be stored in my MySQL table called orders, and the customer will be directly forwarded to the payment page.
I set the ReturnUrls like this:
Fail: to the "fail.php", which has a MySQLl query that will delete the order from the database.
Success: to the "success.php", which has a MySQL query that will change the value of a column (Order_Status) in the table from 0 to 1 and that will make me send him the order.
The problem is :
if the customer clicked the "Pay" button (his order is stored in the DB with the value 0 in the Order_Status column), and if visited the success.php page, then the query on that page will run and set his order Order_Status to 1, and that will make the order appear as its paid for me.
I'm satisfied with the fail.php page, but what's the best way to fix the success.php page so the query inside it will not run unless the customer has completed the payment?
I've tried to store the RedirectUrl I get from Saferpay (this is the link that the customer will be directed to start the payment process) to compare it with the $_SERVER['HTTP_REFERER'] and run the query if $_SERVER['HTTP_REFERER'] == $RedirectUrl, but it didn't work because the payment starts with the $RedirectUrl but the process makes it go through other unique pages before it's directed to the success.php page.
Here is the success.php :
<?php
ob_start();
session_start();
include 'init.php';
$orderId = $_SESSION['OrderId'];
$carts = $_SESSION['carts'];
$RedirectUrl = $_SESSION['RedirectUrl'];
if(isset($orderId) && is_numeric($orderId)){
// changing the Order_Status to 1
$stmtSucess =$con->prepare("UPDATE orders SET Order_Status = 1 WHERE Order_ID = ?");
$stmtSucess->execute(array($orderId));
// changing the status of the Cart Products from 0 to 1 (ordered)
$theOrders1 = explode('::', $carts);
foreach($theOrders1 as $order1){
$stmt1=$con->prepare("UPDATE carts SET Cart_Status = 1 WHERE Cart_ID = ?");
$stmt1->execute(array($order1));
}
if($stmtSucess){
echo lang('THANK_YOU');
}
header('location:profile.php#profile-orders?lang='.$sessionLang);
exit();
}else{
header('location:index.php?lang='.$sessionLang);
exit();
}
ob_end_flush();
?>

Got it, I had to send a request to Saferpay Assert Page with the payment unique information. And I'll get a response in a JSON Object with the result

Related

Prefill CF7 data from the database using a dynamic field

I am trying to create a method through which I can retrieve the data from the database of contacts saved by contact form 7 and pre-fill the fields after the users have previously selected, from a drop-down menu, the PayPal payment method and filled out the form , without then proceeding to the actual payment.
The flow to follow is this:
If the user has chosen to pay with PayPal and filled out the entire form, the "paid" item will be 0 and without making any redirects to the PayPal page
Then, when the user returns to the event card, we will show all the fields filled in previously and the "pay with paypal" button to complete the paypal payment. So the "paid" item will be 1.
So far I have used the following plugins to save the data of the completed forms Advanced CF7 DB and Contact Form CFDB7.
The use of one of these, or someone else, is indifferent to my goal
Here is the code with which so far I am able to populate the dynamic and hidden field [dynamichidden paid ""] when the user selects PayPal but without too much success:
add_action('wpcf7_posted_data', 'course_registration_actions_paypal', 10, 1);
function course_registration_actions_paypal($stato0){
$paypal["paymentmethod"] = '0';
$stato0[“paid”] = '0';
$stato1[“paid”] = '1';
if (isset($paypal[“paymentmethod]) && $stato0[“paid”] === '0') {
return $stato0;
} else {
return $stato1;
}
};
Eventually I managed to get it to work as I wanted, but there remains a redirect problem using the "redirection for contact form 7" plugin.
Always redirect on the first case (paypal) rather than differentiate.
I think the problem is 'wpcf7_posted_data' as without redirects they work fine.
This is my code:
add_action('wpcf7_posted_data','course_registration_actions_persist_payment_status', 10, 1);
function course_registration_actions_persist_payment_status($record){
$current_user = wp_get_current_user();
$userId = get_field('id__pro', 'user_' . $current_user->ID);
$eventId = get_field('id', false);
$records = WPCF7_ContactForm::find([
'ID-Course' => $eventId, // 2
'ID-User' => $userId, // 82994
]);
if ($record['paymentmethod'][0] == 0) {
// Paypal
$record['paymentmethod'] = 0;
// No Paid
$record['paid'] = 0;
} else {
// Bank
$record['paymentmethod'] = 1;
// Paid
$record['paid'] = 1;
}
return $record;
};

Codeigniter Unilevel MLM earning Distribution

I am here to have some help from you.
I am making a Unilevel MLM using Codeigniter
and now I can sucessfully add new member
But the problem is I need to distribute the earnings to other level
after a new member is successfully Added
See pic below:
Distribution of earnings
I need to distribute like the image above.
I hope you can help me with this guys.
Okay, I have a solution for you. The process i used is based on my understanding of the question.
So this is it, first i checked for a registration post, if a post request is made, i use the referral id from the post to fetch the number of registrations tied to that referral id that has not been given awarded the 100 earning. If the count of the result of this query is equal to 4, i loop through all of them and give them the earning of 100 and update their paid status to reflect that they have been paid then i insert the record, else i just insert the record.
So too much text, lets see the code
//this is the controller code
//first check for post of registration
if($_POST){
//kindly do your form validation here
$register = array(
"name" => $this->input->post('name'),
"refid" => $this->input->post('refID')
);
//during post, get the referral id from the post
$refID = $this->input->post('refID');
//before registering, use referral id to get the referred that have not been given earnings yet
$thereffered = $this->referral_m->getReferred($refID);
//check for the number of registration
if(count($thereffered) == 4){
//then get their ids and give them their earnings and update them to paid
foreach($thereffered as $referred){
$earnings = array(
"userID" => $referred->id,
"amount" => 100
);
$paid = array(
"paid" => 1
);
//give earning
$this->referral_m->giveEarning($earnings); //this adds the user id to earning table and give it an amount of 100
$this->referral_m->updateUser($paid, $referred->id); //this updates the user with the paid status
}
//then proceed to register the new record
$this->referral_m->register($register);
}else{
//register the new record
$this->referral_m->register($register);
}
//redirect after registration
redirect();
}else{
//load view here
}
This is how the model looks like
function getReferred($refID){
return $this->db->get_where('referral', array("refid" => $refID, "paid" => '0'))->result();
}
function giveEarning($record){
$this->db->insert('earnings', $record);
}
function register($array){
$this->db->insert('referral', $array);
}
function updateUser($array, $id){
$this->db->where('id', $id);
$this->db->update('referral', $array);
}
From the model, you would discover that i created 2 database tables, I assume you already have those tables created, just use the logic to update your code. If you find any difficulty, kindly comment lets sort it out

Issue with creating an intermediate pending order

I have created a custom payment module and currently it calls validateOrder() after the redirection from the payment website, and this method creates the order, sends email etc. But the issue is if user closed the payment website before it can redirect back to the PrestaShop website the order won't be created in this case. So, I want to create an order(say with "pending" status) before I redirect to the payment website and after redirection from the payment website I can simply mark the same payment as done and send mails etc.
Currently for this I was trying to call validateOrder twice, once in hookdisplayPayment(here I set the status as "pending") and once after redirection. But now after redirection I am getting "The cart cannot be loaded, or an order has already been placed using this cart". I think that's because I can't update the same order twice using the same Card Id.
Note that I want to send the emails only once, once the payment is successful. Currently for this I am using a custom payment status with 'send_email' set to 0.
What's a good workaround for this?
I would like to support versions 1.5+ and 1.6+ if that matters.
A better way to do it than my first answer would be to create a override in your module of function validateOrder.
You will modify:
/** #var Order $order */
$order = new Order();
Into:
/** #var Order $order */
$order = new Order($this->currentOrder);
Then test if is loaded object, skip the part where it sets the order fields. If it's not loaded, set the order fields appropriately with the pending status.
Also test if $this->currentOrder is set where the email is sent, if it's not set skip the email part. If it's set it means the order is pending and you should change the status and send the email.
After you override the function, you can call validateOrder twice, before and after redirection.
You could try something like this:
Before making the redirection you can call once function validateOrder and set status as pending. This will set for your module the variable $this->currentOrder with the id of the pending order.
After redirection don't call again validateOrder, but create your own function to call, eg. validateOrderAfterRedirect in which you check that the payment was made and change the status of the current order. It will be something like this:
// your way of checking that te payment was made
$payment_completed = $this->paymentIsComplete();
if($payment_completed) {
$order = new Order($this->currentOrder);
if(Validate::isLoadedObject($order) && $order->getCurrentOrderState() == [id of pending status]) {
$order->setCurrentState([id of payment accepted status]);
}
}
Create an order with "pending payment" status before the website is redirected to payment system. Once the customer returns the system should just change the payment status to "completed". If the customer closes the payment site, the status will remain "pending" and should be manually updated after checking the payment system.
Many payment gateways provide a mechanism where on completed or failed payment they post data including amount paid and cart ID to a URL you supply to them.
When you process this information using a server-side script at that stage you can validate the order. This should happen before the user is redirected back to your website. Once they are redirected to your site it will already have acknowledged payment in the background.
The reason this method is preferred is that it is the only way to ensure the customer cannot manipulate a URL to make your store think they have paid for an order when in fact no money has changed hands, after which you could end up shipping products for free.
You can do it by adding some like this
$result = $this->validateOrder((int) $cart->id, Configuration::get('PPQ_CREATED_STATUS'), $total, $this->displayName, NULL, array(), (int) $currency->id, false, $customer->secure_key);
in any plays where you need before redirection(where $this is payment module instance)
And after redirection to confirm page I have use wrote this
public function hookPaymentReturn($params)
{
$id_module = (int) Tools::getValue('id_module');
if ($id_module === (int) $this->id) {
$orderHistory = new OrderHistory();
$orderHistory->changeIdOrderState(Configuration::get('PPQ_SUCCESS_STATUS'), $params['objOrder']);
}
}
For mail sending you can configure needed order status
For my case (need work only with paypal, I have change write my own one page checkout module and write my own payment module and befour redirect to paypal I have wrote this
public function hookPayment($params)
{
$customer = &$this->context->customer;
$cart = &$this->context->cart;
$currency = &$this->context->currency;
if (
$customer->isLogged(true) &&
$cart->nbProducts()
) {
$total = (float) $cart->getOrderTotal(true, Cart::BOTH);
$result = $this->validateOrder((int) $cart->id, Configuration::get('PPQ_CREATED_STATUS'), $total, $this->displayName, NULL, array(), (int) $currency->id, false, $customer->secure_key);
if ($result) {
if (!Configuration::get('PPQ_TEST_MODE')) {
$paypal_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=' . Configuration::get('PPQ_PROFILE');
} else {
$paypal_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_xclick&business=' . Configuration::get('PPQ_PROFILE');
}
$order_confirmation_url = $this->context->link->getPageLink('order-confirmation', null, null, array(
'id_cart' => (int) $cart->id,
'id_module' => (int) $this->id,
'id_order' => (int) $this->currentOrder,
'key' => $customer->secure_key,
));
$this->context->smarty->assign(array(
'paypal_url' => $paypal_url,
'order_confirmation_url' => $order_confirmation_url,
'order_id' => (int) $this->currentOrder,
'shop_name' => $this->context->shop->name,
'total_without_shipping' => Tools::convertPriceFull((float) $cart->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING)),
'total_shipping' => Tools::convertPriceFull((float) $cart->getOrderTotal(true, Cart::ONLY_SHIPPING)),
'currency_iso' => Tools::strtoupper($currency->iso_code)
));
return $this->display(__FILE__, 'paypalquick.tpl');
} else {
$this->context->controller->errors[] = $this->l('Can\'t create order. Pleas contact with us');
}
} else {
$this->context->controller->errors[] = $this->l('Problem with loginin or cart empty');
}
}
and tpl
<form id="paypalquick" action="{$paypal_url}" method="post" enctype="multipart/form-data">
<input type="hidden" value="{l s='%s order #%s' sprintf=[$shop_name|escape:'html':'UTF-8', $order_id|intval] mod='paypalquick'}" name="item_name"/>
<input type="hidden" value="{$total_without_shipping}" name="amount"/>
<input type="hidden" value="{$total_shipping}" name="shipping"/>
<input type="hidden" value="{$currency_iso}" name="currency_code"/>
<input type="hidden" value="{$order_confirmation_url}" name="return"/>
<div class="text-center">
<button class="submit">{l s='Go to PayPal for payment' mod='paypalquick'}</button>
</div>
But it was my private cas you can't use it on default but you can see how to make it.
I think we need you to call another hook (that you create) at the time of validation on the site (before leaving that matter) who put a pending status, and keep ValidateOrder hook () to to payment confirmed
Regards,
Arthur

Prestashop - Change order status when payment is validated

When a payment is validated, the order status becomes "Payment validated" ("Paiement accepté" in french). I want to set another status when payment is validated, so the history would show the following :
Current status : My personnal status
History :
My personnal status
Payment validated
To do so, I use the hook actionOrderStatusPostUpdate. This is my code :
public function hookActionOrderStatusPostUpdate($aParams) {
$oOrder = new Order($aParams['id_order']);
if($aParams['newOrderStatus']->id == Configuration::get('PS_OS_PAYMENT')) {
$oOrder->setCurrentState(Configuration::get('XXXXXX_STATUS_WAITING'));
$oOrder->save();
}
}
The Configuration values are correctly defined. This code works, because I see the status changed. But the thing is it changed BEFORE changing to "Payment validated". I don't understand why. The history looks like this :
Current status : Payment validated
History :
Payment validated
My personnal status
What should I do to make My personnal status appear as the last status ?
hookActionOrderStatusPostUpdate hook call is made by changeIdOrderState but the add to order_history table is made after the call of changeIdOrderState like in https://github.com/PrestaShop/PrestaShop/blob/1.6.1.x/controllers/admin/AdminOrdersController.php#L521-L542
You rather need to bind your module on a classic hook like hookActionObjectOrderHistoryAddAfter https://github.com/PrestaShop/PrestaShop/blob/1.6.1.x/classes/ObjectModel.php#L535-L537
public function hookActionObjectOrderHistoryAddAfter($params) {
$orderHistory = $params['object'];
if($orderHistory->id_order_state == Configuration::get('PS_OS_PAYMENT')) {
$oOrder->setCurrentState(Configuration::get('XXXXXX_STATUS_WAITING'));
$oOrder->save();
}
Best Regards
I think this is what you should use to change order status after payment validate those hooks are called when status changing or status changed.
$history = new OrderHistory();
$history->id_order = (int)$id_order;
$history->changeIdOrderState($status_id, (int)$id_order);
$history->addWithemail();
$history->save();
I think it'll work on other hook: actionOrderStatusUpdate

How to mark an order failed programmatically - Magento

I would just like to know what is that one property which when set would mark the order as failed so that failureAction() of app/code/core/Mage/Checkout/controller/OnepageController.php gets called.
I have an Observer.php where in I'm creating invoice for successful payments and for failed payments saving order with pending_payment status and wanting to redirect them to the cart page with an error message at the top.
All this happens fine. Just that for unsuccessful / failed payments, along with saving the order with pending_payment status n redirecting them to cart page with error message, I would also like to retain/save the cart from getting empty.
But to no luck
Observer.php
public function implementOrderStatus($event)
{
$order = $event->getEvent()->getOrder();
if ($this->_getPaymentMethod($order) == 'mypaymentmodule')
{
$quote = Mage::getModel('sales/quote')->load($order->getQuoteId());
if($order->getPayment()->getCcTransId() == NULL)
{
$order->cancel();
$order->setStatus('canceled');
$order->save();
$quote->setIsActive(1)->save();
/*$state = 'pending_payment';
$status = 'pending_payment';
$comment = 'Payment transaction failed due to incorrect AVS/CVD details.';
$isNotified = false;
$order->setState($state,$status,$comment,$isNotified)->save();
$order->setCanSendNewEmailFlag(false);*/
Mage::getSingleton('checkout/session')->addError('Sorry, either of your card information (billing address or card validation digits) dint match. Please try again');
Mage::app()->getFrontController()->getResponse()->setRedirect('checkout/cart/')->sendResponse();
}
else
{
if ($order->canInvoice())
$this->_processOrderStatus($order);
}
}
return $this;
}
But $quote->setIsActive(true)->save() does not seem to be doing the trick. Any help as to how can I save my cart from getting empty after saving the order with 'canceled' status.
You maybe should have a look at ./app/code/core/Mage/Sales/Model/Order.php. There you will find several constants for an order, which may be used to set the state of an order like this:
<?php
// [...] all your code within your custom action or script
//load your order by order_id (or by increment_id, if you like to, here, it's your order id
$order = Mage::getModel('sales/order')->load($your_order_id);
$order->setState(Mage_Sales_Model_Order::STATE_CANCELED); //or whatever distinct order status you'd like
$order->save();
The failureAction in the controiller action does nothing of the sort, if you want to call it manually, you can build it's url using Mage::getUrl()

Categories