I am using PayPal's API to process a payment using SetExpressCheckout method.
$requestParams = array(
'RETURNURL' => 'SUCCESS_PAGE_URL',
'CANCELURL' => 'CANCE_PAGE_URL'
);
$orderParams = array(
'PAYMENTREQUEST_0_AMT' => $price,
'PAYMENTREQUEST_0_SHIPPINGAMT' => '0',
'PAYMENTREQUEST_0_CURRENCYCODE' => 'USD',
'PAYMENTREQUEST_0_ITEMAMT' => $price
);
$item = array(
'L_PAYMENTREQUEST_0_NAME0' => $item_name,
'L_PAYMENTREQUEST_0_DESC0' => $item_description,
'L_PAYMENTREQUEST_0_AMT0' => $price,
'L_PAYMENTREQUEST_0_QTY0' => '1'
);
$paypal = new Paypal();
$response = $paypal -> request('SetExpressCheckout',$requestParams + $orderParams + $item);
It all works great, but even though the description is showing in the PayPal's checkout page, the email receipt that I get is missing the description information.
Does anyone know what how I can get the description to show on the receipt?
Figured it out. When the SetExpressCheckout is done and returns "Success" it gets redirected to PayPal, after which it goes back to your specified RETURNURL. On this RETURNURL page, for DoExpressCheckoutPayment, you need to specify the order details, this is what shows up in the invoice. Here is the code:
// Complete the checkout transaction
$requestParams = array(
'TOKEN' => $_GET['token'],
'PAYMENTACTION' => 'Sale',
'PAYERID' => $_GET['PayerID'],
'PAYMENTREQUEST_0_AMT' => '1', // Same amount as in the original request
'PAYMENTREQUEST_0_CURRENCYCODE' => 'USD' // Same currency as the original request
);
$item = array(
'L_PAYMENTREQUEST_0_NAME0' => $name,
'L_PAYMENTREQUEST_0_DESC0' => $desc, // <-- this is the description
'L_PAYMENTREQUEST_0_AMT0' => $price,
'L_PAYMENTREQUEST_0_QTY0' => '1'
);
$response = $paypal -> request('DoExpressCheckoutPayment',$requestParams + $item);
Related
I'm having troubles with the PayPal callback feature, i can't for the life of me get it to work at all. I have double checked the callback URL path, it's correct. When the user logs into paypal, it always just returns the default shipping rate. I'm just really not sure what i am missing here, if anyone can help out. Also, i have the callback timeout set to 6, though it seems it only takes about 3 - 4 seconds for it to fail and return the default shipping rate.
I've followed the documentation here https://developer.paypal.com/docs/classic/express-checkout/integration-guide/ECInstantUpdateAPI/ and applied it to my website. I've also made sure i am logged into sandbox too.
SetExpressCheckout params:
// SetExpressCheckout
$params = array (
'METHOD' => 'SetExpressCheckout',
'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
'VERSION' => $version, // 124.0
'USER' => $paypal_user,
'PWD' => $paypal_password,
'SIGNATURE' => $signature,
'L_SHIPPINGOPTIONNAME0' => 'Flat',
'L_SHIPPINGOPTIONLABEL0' => 'N/A',
'L_SHIPPINGOPTIONAMOUNT0' => '6.99',
'L_SHIPPINGOPTIONISDEFAULT0' => 'true',
'PAYMENTREQUEST_0_INSURANCEOPTIONSOFFERED' => 'false',
'PAYMENTREQUEST_0_SHIPPINGAMT' => $shipping_default, // 6.99
'PAYMENTREQUEST_0_ITEMAMT' => $cart_total,
'PAYMENTREQUEST_0_AMT' => $cart_total + $shipping_default,
'MAXAMT' => $cart_total + 30, // 30 is the total possible shipping amount
'PAYMENTREQUEST_0_CURRENCYCODE' => $paypal_currency, // AUD
'RETURNURL' => $paypal_return,
'CANCELURL' => $paypal_cancel,
'CALLBACK' => 'HTTP://localhost/moes/php/paypal_callback_php.php',
'CALLBACKTIMEOUT' => 6,
'CALLBACKVERSION' => '61.0',
'ALLOWNOTE' => 1,
'PAYMENTREQUEST_0_INVNUM' => '123' /*$invoice_number*/,
'PAYMENTREQUEST_0_TAXAMT' => $tax, // 0.00
);
// List each product and add to exress check-out array
foreach ($paypal_products as $k => $product){
$params["L_PAYMENTREQUEST_0_NAME$k"] = $product['name'];
$params["L_PAYMENTREQUEST_0_AMT$k"] = number_format($product['price'],2);
$params["L_PAYMENTREQUEST_0_QTY$k"] = $product['qty'];
$params["L_PAYMENTREQUEST_0_NUMBER$k"] = $product['code'];
$params["L_PAYMENTREQUEST_0_DESC$k"] = '1';
/* Optional shipping options to calculate shipping costs on callback
Option weight (L_PAYMENTREQUEST_n_ITEMWEIGHTVALUEm, L_PAYMENTREQUEST_n_ITEMWEITHTUNITm)
Option height (L_PAYMENTREQUEST_n_ITEMHEIGHTVALUEm, L_PAYMENTREQUEST_n_ITEMHEIGHTUNITm)
Option length (L_PAYMENTREQUEST_n_ITEMLENGTHVALUEm, L_PAYMENTREQUEST_n_ITEMLENGTHUNITm)
Option width (L_PAYMENTREQUEST_n_ITEMWIDTHVALUEm, L_PAYMENTREQUEST_n_ITEMWIDTHUNITm)*/
}
Callback script:
<?php
// Populate variables into local variables
$method = $_POST['METHOD'];
$version = $_POST['CALLBACKVERSION'];
$token = $_POST['TOKEN'];
$currencycode = $_POST['CURRENCYCODE'];
$localecode = $_POST['LOCALECODE'];
$street = $_POST['SHIPTOSTREET'];
$street2 = $_POST['SHIPTOSTREET2'];
$city = $_POST['SHIPTOCITY'];
$state = $_POST['SHIPTOSTATE'];
$country = $_POST['SHIPTOCOUNTRY'];
$zip = $_POST['SHIPTOZIP'];
// Setting shipping rate based on country [Test only]
if ($country == "US"){
echo "METHOD=CallbackResponse&OFFERINSURANCEOPTION=false&L_SHIPPINGOPTIONNAME0=FLat&L_SHIPPINGOPTIONLABEL0=N/A&L_SHIPPINGOPTIONAMOUNT0=10.00&L_TAXAMT0=1.00&L_INSURANCEAMOUNT0=9.00&L_SHIPPINGOPTIONISDEFAULT0=true";
} else {
echo "METHOD=CallbackResponse&OFFERINSURANCEOPTION=false&L_SHIPPINGOPTIONNAME0=FLat&L_SHIPPINGOPTIONLABEL0=N/A&L_SHIPPINGOPTIONAMOUNT0=30.00&L_TAXAMT0=1.00&L_INSURANCEAMOUNT0=9.00&L_SHIPPINGOPTIONISDEFAULT0=true";
}
?>
I'm guessing i missing something fundamental here, or i'm going about it completely the wrong way.
The solution to my problem was :
localhost/moes/php/paypal_callback_php.php
Obviously PayPal can't send a HTTP request to 'localhost'. My WAMP server is not configured to be accessible over the internet.
Here are the repo included in my composer:
omnipay &
paypal
In my config/laravel-omnipay.php:
'gateways' => [
'paypal' => [
'driver' => 'PayPal_Rest',
'options' => [
'solutionType' => '',
'landingPage' => '',
'headerImageUrl' => ''
]
]
]
Here is in my Controller:
// omnipay start
$gateway = Omnipay::create('PayPal_Rest');
// Initialise the gateway
$gateway->initialize(array(
'clientId' => 'xxxxxx',
'secret' => 'xxxxxx',
'testMode' => true, // Or false when you are ready for live transactions
));
// Create a credit card object
// DO NOT USE THESE CARD VALUES -- substitute your own
$card = new CreditCard(array(
'firstName' => $request->firstname,
'lastName' => $request->lastname,
'number' => $request->cardnumber,
'expiryMonth' => $month_year[0],
'expiryYear' => $month_year[1],
'cvv' => $request->ccv,
'billingAddress1' => $request->address
/*
'billingCountry' => 'AU',
'billingCity' => 'Scrubby Creek',
'billingPostcode' => '4999',
'billingState' => 'QLD',*/
));
// Do an authorisation transaction on the gateway
$transaction = $gateway->authorize(array(
'amount' => '100',
'currency' => 'USD',
'description' => $eventName->event_title,
'card' => $card,
));
$response = $transaction->send();
if ($response->isSuccessful()) {
echo "Authorize transaction was successful!\n";
// Find the authorization ID
$auth_id = $response->getTransactionReference();
}
I've got this error:
Class 'App\Http\Controllers\CreditCard' not found
Note: If I use RestGateway to replace PayPal_Rest, I get this error instead:
Class '\Omnipay\RestGateway\Gateway' not found
Searching an answer for a long time but didn't find a solution that works for me. So, not entirely sure how to proceed.
You need to have this at the top of your class file:
use Omnipay\Common\CreditCard;
$creditCard = new \Omnipay\Common\CreditCard([...]);
Backslash
Further reading: https://stackoverflow.com/questions/4790020/what-does-a-backslash-do-in-php-5-3#:~:text=%5C%20(backslash)%20is%20the%20namespace,name%20in%20the%20current%20namespace.
The issue is because it will fetch the class from the global namespace - rather than the current namespace.
How are you supposed to get the shipping info back from a Parallel Payment, using PayPal's Adaptive API system? Normally it would just get passed back as payer_country, etc - when the IPN script is requested. However, this doesn't seem to be the case.
Here are the params being passed in when the IPN script is called:
transaction[0].amount
transaction[0].id
verify_sign
transaction[1].receiver
reverse_all_parallel_payments_on_error
transaction[1].pending_reason
transaction[0].pending_reason
transaction[1].id_for_sender_txn
transaction[0].invoiceId
payment_request_date
test_ipn
cancel_url
charset
return_url
transaction[0].status_for_sender_txn
ipn_notification_url
transaction[1].is_primary_receiver
transaction[1].status
transaction_type
transaction[1].amount
transaction[0].status
log_default_shipping_address_in_transaction
transaction[0].receiver
status
transaction[0].id_for_sender_txn
action_type
fees_payer
pay_key
transaction[1].status_for_sender_txn
transaction[0].paymentType
transaction[1].invoiceId
transaction[1].id
sender_email
notify_version
transaction[1].paymentType
transaction[0].is_primary_receiver
If I then do a PaymentDetails API call, I get back stuff like:
$VAR1 = {
'currencyCode' => 'USD',
'responseEnvelope' => {
'correlationId' => '9944330ab9a8c',
'timestamp' => '2014-04-07T06:08:16.094-07:00',
'ack' => 'Success',
'build' => '10273932'
},
'status' => 'COMPLETED',
'senderEmail' => 'andy.aaaa#ultranerds.co.uk',
'cancelUrl' => 'http://somesite.net/paypal/cancel.html',
'paymentInfoList' => {
'paymentInfo' => [
{
'pendingRefund' => 'false',
'receiver' => {
'accountId' => 'NY3AD33DD739C',
'email' => 'andy-xxx#ultranerds.com',
'amount' => '65.00',
'invoiceId' => '1022',
'primary' => 'false',
'paymentType' => 'GOODS'
},
'transactionId' => '8E1114341X895213Y',
'senderTransactionStatus' => 'COMPLETED',
'senderTransactionId' => '5EV71352C33256006',
'transactionStatus' => 'COMPLETED',
'refundedAmount' => '0.00'
},
{
'pendingRefund' => 'false',
'receiver' => {
'accountId' => 'YYP5C69YWCMKE',
'email' => 'andy.yyy#gmail.com',
'amount' => '15.00',
'invoiceId' => '1023',
'primary' => 'false',
'paymentType' => 'GOODS'
},
'transactionId' => '68H86656UP574062X',
'senderTransactionStatus' => 'COMPLETED',
'senderTransactionId' => '2XW88939LK1112523',
'transactionStatus' => 'COMPLETED',
'refundedAmount' => '0.00'
}
]
},
'feesPayer' => 'EACHRECEIVER',
'actionType' => 'CREATE',
'ipnNotificationUrl' => 'http://somesite.net/paypal/test_ipn.cgi',
'sender' => {
'useCredentials' => 'false',
'accountId' => 'B74RBM5F6SLZG',
'email' => 'andy.aaa#ultranerds.co.uk'
},
'returnUrl' => 'http://somesite.net/paypal/success.html',
'payKey' => 'AP-4EK17906VB6613533',
'reverseAllParallelPaymentsOnError' => 'false'
};
As you can see, there is no reference to the delivery address at all. How are you supposed to get that info back?
UPDATE: Mmm ok, so it looks like GetShippingAddresses is what I need - but for some reason its coming back with nothing in when I call it:
{"requestEnvelope":{"errorLanguage":"en_US","detailLevel":"ReturnAll"},"key":"AP-1B1377463N9785350"} /GetShippingAddresses_API_Operation/
...simply returns:
{
'responseEnvelope' => {
'correlationId' => '3a4443aed09c9',
'timestamp' => '2014-04-07T06:40:35.460-07:00',
'ack' => 'Success',
'build' => '10273932'
}
}
I'm a bit baffled as to why its doing that. Any suggestions?
I found a quote here:
http://go.developer.ebay.com/devzone/articles/using-paypals-adaptive-payments-and-google-app-engine-build-online-market-python-part-3
Unfortunately, although this follows the process recommended by
PayPal's documentation, it doesn't work. There's currently a bug in
PayPal's Adaptive Payments implementation. For a traditional payment,
the shipping address is not collected; for embedded payments, the
GetShippingAddresses call does not return the shipping address.
PayPal has acknowledged the bug and indicated that it expects to have
this fixed in April 2011. If you need shipping addresses right now,
the recommendation is to collect them on your site rather than relying
on the PayPal API.
That was from 2011... but is this still the case??
Sorry to bump - but has anyone got any suggestions?
Ok, well I got my answer - but unfortunately its not what I was hoping for:
Yes, unfortunately this feature is only available for embedded payment
flow.
https://developer.paypal.com/webapps/developer/docs/classic/adaptive-payments/ht_ap-embeddedPayment-curl-etc/
If you're using embedded payment flow, then you can retrieve the
address on their PayPal account by passing in
senderOptions.requireShippingAddressSelection = true during
SetPaymentOption API call. You can then retrieve it via
GetShippingAddresses API call.
So it looks like really what I need to do, is ask the user to provide their shipping information BEFORE sending them to paypal, then storing it. Not ideal - but I guess you just have to work with what you got!
I'm trying to set a shipping info (name,address, email, etc) using OmniPay for PayPal Express.
I've tried adding shipping info in options array in purchase($options) object:
$options = array(
// required fields (username, pass, etc)
// .....
'shippingAddress1' => 'Elm Street'
'shippingCity' => 'Elm',
'shippingPostcode' => '1000'
// etc.
);
I also tried passing this info to CreditCard object:
$card = new Omnipay\Common\CreditCard($card_options);
without any success. The code:
$gateway = GatewayFactory::create('PayPal_Express');
$gateway->setUsername(USERNAME);
$gateway->setPassword(PASS);
$gateway->setSignature(SIGNATURE);
$gateway->setTestMode(true);
$card_options = array(
'shippingAddress1' => 'Elm Street',
'shippingCity' => 'Elm',
'shippingPostcode' => '10000',
'shippingState' => '',
'shippingCountry' => 'NEverland',
'shippingPhone' => '123465789',
'company' => '',
'email' => 'shipping#test.com'
);
$card = new Omnipay\Common\CreditCard($card_options);
$response = $gateway->purchase(
array(
'cancelUrl'=>'http://localhost/laravel_paypal/',
'returnUrl'=>'http://localhost/laravel_paypal/public/paypalexpress_confirm',
'amount' => '0.99',
'currency' => 'USD',
'card' => $card
)
)->send();
How to add shipping info to PayPal Express using OmniPay?
BTW, I'm using Laravel with PayPal Sandbox.
This problem has recently been fixed (https://github.com/adrianmacneil/omnipay/pull/140) so it should now be possible to set shipping info properly.
I am faced with a Sugar 6.3 CE installation, trying to create new accounts through rest api.
I am still on the learning curve for a lot of the innards of the CRM, and cannot figure out how to have the email inserted whith the rest of the account info upon creation with a REST call.
I have tried many different field values, and after catching that $email1 was used in some snippet examples I saw on the sugarCRM site. I have not found other mentions in the forums or in the docs yet.
The $parameters array used to configure the usual rest call to create an account in php with REST api looks like this and works fine, except for the $email1:
$parameters = array(
'session' => $session,
'module' => 'Contacts',
'name_value_list' => array(
array('name' => 'first_name', 'value' =>
utf8_encode($contacts["Name"])),
array('name' => 'last_name', 'value' =>
utf8_encode($contacts["GivenName"])),
array('name' => 'phone_work', 'value' =>
utf8_encode($row->PrimaryPhoneAreaCode . ' ' . $row->PrimaryPhone)),
array('name' => 'phone_fax', 'value' =>
utf8_encode($row->PrimaryFaxAreaCode . ' ' . $row->PrimaryFaxNumber)),
array('name' => 'title', 'value' =>
utf8_encode($contacts["Title"])),
/*
* PROBLEM HERE!
*/
array('name' => 'email1', 'value' =>
utf8_encode($row->PrimaryEmail)),
array('name' => 'primary_address_street', 'value' =>
utf8_encode($row->Address1) . ' ' .
utf8_encode($row->Address2)),
array('name' => 'language', 'value' =>
utf8_encode($row->Language)),
array('name' => 'assigned_user_id', 'value' =>
get_rep_id($row->Salesperson1Name, $sugarlink)),
)
);
I would be curious, if someone has the trick. I tried to find to field for emails but it seems to be in separate tables. Any help / tips appreciated.
If you are using REST API the email1 will work for both set en get methods (just tested it).
Did not used the SOAP API as in your example, and suggest to migrate all to REST according to SugarCRM recommendations.
You must add the email into emailadress database first, create contact and set a relationship between both ;-)
$set_entry_parametersEADDR = array(
"session" => $session_id,
//The name of the module from which to retrieve records.
"module_name" => "EmailAddresses",
//Record attributes
"name_value_list" => array(
array('name' => 'email_address', 'value' => $email),
array('name' => 'email_address_caps', 'value' => strtoupper($email)),
array('name' => 'invalid_email' , 'value' => 0),
array('name' => 'opt_out', 'value' => 0),
array('name' => 'date_created' , 'value' => date('Y-m-d H:i:s')),
array('name' => 'date_modified', 'value' => date('Y-m-d H:i:s')),
array('name' => 'deleted' , 'value' => 0),
),
);
$set_entry_resultEmailsAdd = call("set_entry", $set_entry_parametersEADDR, $url);
print_r($set_entry_resultEmailsAdd);
$Email_id = $set_entry_resultEmailsAdd->id;
$set_entry_parameters_contact = array(
//session id
"session" => $session_id,
//The name of the module from which to retrieve records.
"module_name" => "Contacts",
//Record attributes
"name_value_list" => array(
//to update a record, you will nee to pass in a record id as commented below
//array("name" => "id", "value" => "9b170af9-3080-e22b-fbc1-4fea74def88f"),
array("name" => "first_name", "value" => $prof["Prenom"]),
array("name" => "last_name", "value" => $prof["Nom"]),
array("name" => "login_c", "value" => $prof["Login"]),
//array("name" => "email1", "value" => $email),
array("name" => "fonction_c", "value" => "prof")
),
);
$set_entry_result_contact = call("set_entry", $set_entry_parameters_contact, $url);
print_r($set_entry_result_contact);
$contact_id = $set_entry_result_contact->id;
$set_relationship_parameters_email = array(
'session' => $session_id,
'module_name' => 'Contacts',
'module_id' => $contact_id,
'link_field_name' => 'email_addresses',
'related_ids' => $Email_id,
);
$set_relationship_result_email = call("set_relationship", $set_relationship_parameters_email, $url);
print_r($set_relationship_result_email);
Currently I think that not works with REST api but works with SOAP API. Could you try to use email1_set_in_workflow key instead of email1?
It's not a very good solution but perhaps that could unlock you pending a better way to do that in future release