I had implemented IPN handler (copt paste it from code project) in one of the project for the first time.
The problem in the user can registered to my website with some email address and then while paying he can use some different email address
And the IPN handler request variable give the email address with which it pays. How should i find out which user had paid.
if (strResponse == "VERIFIED")
{
//check the payment_status is Completed
//check that txn_id has not been previously processed
//check that receiver_email is your Primary PayPal email
//check that payment_amount/payment_currency are correct
//process payment
string payerEmail = Request.Form["payer_email"];
string paymentStatus = Request.Form["payment_status"];
string receiverEmail = Request.Form["receiver_email"];
string amount = Request.Form["mc_gross"];
}
Solutions:
Pass some addiditonal may be user id in the payment processing page and assume it will be returned in IPN handler.
Or ask the user to enter the paypal email address before paying. (not feels good)
Any help in this regard is appreciated
I usually POST, within the cart info, a custom field that identifies my local transaction, or my local cart. IPN will send that custom field back to you, so that you can match the transaction with your user. Or you can just pass the USER_ID, and get it back regardless of the transaction.
Send paypal your custom data in your form using this field:
<input type="hidden" name="custom" value="YOUR_CUSTOM_INFO_HERE">
Handle IPN in your callback:
if (strcmp ($res, "VERIFIED") == 0) {
// This is the custom field i posted within the cart form.
$cid = $_POST['custom'];
$txn_id = $_POST['txn_id'];
$cart = load_cart_by_cid($cid);
if (!empty($cart)) {
// Fetch your user from cart and do things with it,
// along with your security checks.
$user = $cart->getUser();
// For example, store the transaction.
TransactionManager::saveTransaction($user, $txn_id);
}
}
Source is php, but i think is verbose enough to be easily translated in java, or c#, or whatever.
Related
Of the three files here- https://github.com/paypal/ipn-code-samples/tree/master/php
I have my Webhook URL set to the stock github version of- PaypalIPN.php (this validates successfully 100% of the time, if I use example_usage.php... Doesn't work. If I use both as Webhooks... Doesn't work).
From the Paypal button side of things I'm able to post my website's active user (call him $MrUser) with this:
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
"custom_id":"<?php echo $MrUser; ?>",
"description":"One hundred Webdollars",
"amount":
{
"currency_code":"USD",
"value":1.99
}
}]
});
},
Here's the SQL I need to run upon successful validation (I change $MrUser to $kitty for clarity's sake):
require 'sqlconfig.php';
$dsn = "mysql:host=$host;dbname=$db;charset=UTF8";
try {
$pdo = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
echo $e->getMessage();
}
$hashedIP = $_SERVER['REMOTE_ADDR'];
$kitty = $_POST['custom']; // Not sure this is working yet, but this should give me $mrUser;
$sql = "INSERT INTO `Insert_upon_Paypal_success` (`date`,`hashedIP`,`username`,`webdollarAMT`) VALUES (now(),:hashedIP,:kitty,'100')";
$statement = $pdo->prepare($sql);
$statement->bindValue(':hashedIP', $hashedIP);
$statement->bindValue(':kitty', $kitty);
$inserted = $statement->execute();
I'm popping this into the PaypalIPN.php file upon validation, but, it doesn't work. Here's how I have it in there:
// Check if PayPal verifies the IPN data, and if so, return true.
if ($res == self::VALID) {
return true;
// i.e. putting all of the SQL above right here.
} else {
return false;
}
I'm guessing I need to put the SQL in a specific place that I'm missing, as per the layout of the PaypalIPN.php file... Please help!!
There is no reason to use IPN with current PayPal Checkout integrations. It is very old technology (20+ years) and should be deprecated soon.
Webhooks are a successor to IPN. However, even they are unnecessary for normal payment processing -- better used only if you need automated notifications of post-checkout exceptions such as refunds or disputes.
For normal PayPal payments, do not use either.
Instead, use the v2/checkout/orders API and make two routes (url paths) on your server, one for 'Create Order' and one for 'Capture Order'. You could use the (recently deprecated) Checkout-PHP-SDK for the routes' API calls to PayPal, or your own HTTPS implementation of first getting an access token and then doing the call with PHP's curl or similar. Both of these routes should return/output only JSON data (no HTML or text). Inside the 2nd route, when the capture API is successful you should verify the amount was correct and store its resulting payment details in your database (particularly purchase_units[0].payments.captures[0].id, which is the PayPal transaction ID) and perform any necessary business logic (such as reserving product or sending an email) immediately before forwarding return JSON to the frontend caller. In the event of an error forward the JSON details of it as well, since the frontend must handle such cases.
Pair those 2 routes with this frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server . (If you need to send any additional data from the client to the server, such as an items array or selected options, add a body parameter to the fetch with a value that is a JSON string or object)
So this is what i did so far and it doesn't work, i will appreciate any help on the matter:
my goal is to post back any webhook event that occur in my paypal sandbox account.
So i have 2 accounts,
one that belongs to the receiver of the money, call it "facilitator",
one that belong to the "buyer",
Now in my account,there is a Sandbox webhooks configuration, so i entered the following:
https://csdieuqkzo.localtunnel.me
goes without saying that this comes from localtunnel.me.
So in my project, i do a simple sale using the api... this is the full create sale process:
$payer = new Payer();
$payer->setPayment_method('paypal');
//dd($payer);
$item = new Item();
$item->setQuantity('1');
$item->setName('benny');
$item->setPrice('7.41');
$item->setCurrency('USD');
$item->setSku('blah');
// //var_dump($item);
$items = new ItemList();
$items->addItem($item);
//var_dump($items);
$amountDetails = new Details();
$amountDetails->setSubtotal('7.41');
$amountDetails->setTax('0.03');
$amountDetails->setShipping('0.03');
$amount = new Amount();
$amount->setCurrency('USD');
$amount->setTotal('7.47');
$amount->setDetails($amountDetails);
$transaction = new Transaction();
$transaction->setAmount($amount);
$transaction->setDescription('This is the payment transaction description.');
$transaction->setItemList($items);
// echo '<pre>';
// print_r($transaction);
$RedirectUrls = new RedirectUrls();
$RedirectUrls ->setReturnUrl('https://csdieuqkzo.localtunnel.me/#/pricing');
$RedirectUrls ->setCancelUrl('https://csdieuqkzo.localtunnel.me/#/');
$payment = new Payment();
$payment->setIntent('sale');
$payment->setPayer($payer);
$payment->setTransactions(array($transaction));
$payment->setRedirectUrls($RedirectUrls);
// echo '<pre>';
// print_r($payment);
// dd();
$response = $payment->create($this->apiContext)->toarray();
Session::put('pay_id',$response['id']);
return Response::json($response);
After this there is a redirect to paypal, approval and when it comes back to my site, it excute with the following:
$payerId = Input::get('payerId');
$payment = Payment::get(Session::get('pay_id'), $this->apiContext);
//return $payerId;
$paymentExecution = new PaymentExecution();
$paymentExecution->setPayer_id($payerId);
$approval = $payment->execute($paymentExecution, $this->apiContext)->toarray();
return Response::json($approval);
Then an object is coming in saying the state of this transaction is approved, super, but i don't see any post to the webhook url i defined earlier...Now how did i test it?
I wrote a simple script to the post method of my root (in laravel):
Route::post('/',function(){
$myfile = fopen("bennyfile.txt", "a") or die("Unable to open file!");
$txt = "\nouterequested";
fwrite($myfile, $txt);
fclose($myfile);
});
Means whenever a post request is coming to the following url (in my case, a post to the root of:https://csdieuqkzo.localtunnel.me
I just want to add a line, that's it...but it doesn't update anything!...
for example if i do a post request from postman to the same place, all is good, but when a sale is approved, or any other action, nothing is happening.
Why?
This is a paypal document which helps you understand how webhooks works.
https://developer.paypal.com/docs/integration/direct/rest-webhooks-overview/
webhooks is http call back mechanism, ideally, you will need a valid url as your webhooks endpoint to test the webhooks notification message posted by PayPal. If you did sale using paypal wallet, you should get PayPal's webhooks notification message in JSON format at your endpoint. webhooks doesn't support direct credit card case yet.
If you want to test your listener script on local, you can use postman tool to post the sample message to your local url and test.
Using "localhost" isn't going to work because when PayPal's servers hits that address they're just hitting themselves. You need to setup DNS to point a domain to a virtual server on your local machine instead so that you can use a fully qualified domain name instead of localhost.
I'm building a book store and I am building the checkout using PayPal Payflow . This is the checkout flow:
Shipping info --> Billing info |verify CC using Paypal| --> Order summary --> Submit |authorize CC using Paypal|
Shipping info: fill out shipping address, nothing special here
Billing info: fill out your billing address + credit card info. Don't save the credit card info since it's against standards, instead just send the CC number, expiration date, and CVV directly to PayPal to verify. PayPal approves.
Order summary: The order sees the summary of his order before he submits the order. He presses submit and another request to PayPal is sent to authorize the funds.
However, the CC info vanishes after #2, so how would I persist that data to #3 so that I can send it to PayPal again?
Can I just use the ORIGID to point to the PNREF ? The documentation says I have to do a full request with the whole params list (including CC info, CVV, exp date, etc).
TRXTYPE=A&TENDER=C&PWD=x1y2z3&PARTNER=PayPal&VENDOR=SuperMerchant&USER=S
uperMerchant&ACCT=5555555555554444&EXPDATE=0308&AMT=123.00&COMMENT1=Seco
nd purchase&COMMENT2=Low risk customer&INVNUM=123456789&STREET=5199
MAPLE&ZIP=94588
Or am I just misunderstanding what authorization means? Isn't authorization actually reserving funds in the user's CC? So that shouldn't be done until the user presses submit order right?
I figured it out.
The documentation here: https://www.paypalobjects.com/webstatic/en_US/developer/docs/pdf/pp_payflowpro_guide.pdf
on page 40 mentions it briefly, but doesn't go into much detail about this checkout flow even though it seems pretty common.
My assumption was right, in that I could just do an address verification request first with all the CC info, and use the PNREF returned. I save the PNREF id in my session and reuse it to submit a request that looks like this:
def authorize_transaction(pnref)
make_request(authorization_data(pnref))
end
def authorization_data(pnref)
{
"TRXTYPE" => "A",
"TENDER" => "C",
"USER" => PAYPAL_API["user"],
"PWD" => PAYPAL_API["pwd"],
"VENDOR" => PAYPAL_API["user"],
"PARTNER" => "Paypal",
"AMT" => purchase.total_price,
"ORIGID" => pnref,
"VERBOSITY" => "HIGH"
}
end
And receive the desired response:
{"RESULT"=>"0", "PNREF"=>"A10A6A9C08E1", "RESPMSG"=>"Approved", "AUTHCODE"=>"752PNI", "AVSADDR"=>"Y", "AVSZIP"=>"Y", "HOSTCODE"=>"A", "PROCAVS"=>"Y", "VISACARDLEVEL"=>"12", "TRANSTIME"=>"2014-01-31 11:53:56", "FIRSTNAME"=>"net", "LASTNAME"=>"theory", "AMT"=>"15.64", "ACCT"=>"1111", "EXPDATE"=>"0115", "CARDTYPE"=>"0", "IAVS"=>"N"}
See above is a picture of new order acknowledgement email of Magento.
On the website we're developing we use Fontis Australia extension (http://www.magentocommerce.com/magento-connect/fontis-australia.html) to implement BPay payment method. The extension works ok, except that on the order acknowledgement email, the Email ref always show 000000.
I try to look at it and see that the ref number generated need the order ID as input to generate the correct ref number.
The extension use this code to get the last order number on payment info block:
$order_id = Mage::getSingleton('checkout/session')->getLastRealOrderId();
I try to use and print the result from other controller, it shows the correct order number. But seems that for the payment info block on email, the order number info can't be retrieved. Actually the same block also called out on the checkout success page, and it shows correctly.
Can somebody suggest other way to get the last order id on payment info block on Magento Email?
In info template you can use $order = $this->getInfo()->getOrder(); to get Mage_Sales_Model_Order object. Then you can get current order id by $order->getData('increment_id').
But with this code, you get error in checkout process, because $this->getInfo() returns other model.
So dirty solution, that works for me without errors, is:
$info = $this->getInfo();
if ($info instanceof Mage_Sales_Model_Order_Payment) {
$order = $info->getOrder();
echo $order->getData('increment_id'));
}
I am using adaptive api to make a chained payment. The code looks
ChainedPay chainedPay = new ChainedPay(numberOfReceivers);
//set values (such as return url, cancel url, ipn url etc for the chainedPay object
....
Receiver primaryReceiver = new Receiver();
// set the receiver's value such as amount etc.
...
chainedPay.setPrimaryReceiver(primaryReceiver);
Receiver rec1 = new Receiver();
//set the second receiver's value
...
chainedPay.addToSecondaryReceivers(rec1);
//Make the request
chainedPay.makeRequest(); like this:
I do get the IPN message back when the payment is approved. But I want to be able to send a value such as a transactionId that exists in my system in the pay request, and have the IPN post it back to me, so I can look up the transaction by its id in my ipn listener, and use that information to deliver digital good to the user. I can't figure out where to set that value in the pay request.
Before using adaptive payment api call, if I want to pass the transaction id to the IPN, I would set it in the item_number field in a field in the form of the buy button and that would get passed through. Is there something similar in the adaptive api?
Thanks,
Tim
Try using the trackingid parameter. I am using the XML version and I pass it as follows
sRequest.Append("</trackingId>");
sRequest.Append(trackingID);
sRequest.Append("</trackingId>"); You may get a property as tracking id in PayRequest class.
I am passing the orderId via the trackingId field in the PayRequest
Ex:
PayRequest payRequest = new PayRequest(requestEnvelope, actionType, cancelUrl, currencyCode, receiverList, returnUrl);
payRequest.ipnNotificationUrl = System.Configuration.ConfigurationManager.AppSettings["PaypalNotifyUrl"];
payRequest.trackingId = orderId.ToString();
Then in the IPN handler, I retrieve it from the Request object.