How to create order in magento programmatically with paypal payment method.
We have implemented code for COD method or Check/Money order payment methods, now I need to implement payment, I searched alot but didn't found any answer, is there a proper way for this ?
first of all paypal is payment getaway which need authentication .
but you can try this code
file here : app/code/core/Mage/Paypal/Model/Express.php
function code here :
public function order(Varien_Object $payment, $amount)
{
$this->_placeOrder($payment, $amount);
$payment->setAdditionalInformation($this->_isOrderPaymentActionKey, true);
if ($payment->getIsFraudDetected()) {
return $this;
}
$order = $payment->getOrder();
$orderTransactionId = $payment->getTransactionId();
$api = $this->_callDoAuthorize($amount, $payment, $payment->getTransactionId());
$state = Mage_Sales_Model_Order::STATE_PROCESSING;
$status = true;
$formatedPrice = $order->getBaseCurrency()->formatTxt($amount);
if ($payment->getIsTransactionPending()) {
$message = Mage::helper('paypal')->__('Ordering amount of %s is pending approval on gateway.', $formatedPrice);
$state = Mage_Sales_Model_Order::STATE_PAYMENT_REVIEW;
} else {
$message = Mage::helper('paypal')->__('Ordered amount of %s.', $formatedPrice);
}
$payment->addTransaction(Mage_Sales_Model_Order_Payment_Transaction::TYPE_ORDER, null, false, $message);
$this->_pro->importPaymentInfo($api, $payment);
if ($payment->getIsTransactionPending()) {
$message = Mage::helper('paypal')->__('Authorizing amount of %s is pending approval on gateway.', $formatedPrice);
$state = Mage_Sales_Model_Order::STATE_PAYMENT_REVIEW;
if ($payment->getIsFraudDetected()) {
$status = Mage_Sales_Model_Order::STATUS_FRAUD;
}
} else {
$message = Mage::helper('paypal')->__('Authorized amount of %s.', $formatedPrice);
}
$payment->resetTransactionAdditionalInfo();
$payment->setTransactionId($api->getTransactionId());
$payment->setParentTransactionId($orderTransactionId);
$transaction = $payment->addTransaction(Mage_Sales_Model_Order_Payment_Transaction::TYPE_AUTH, null, false,
$message
);
$order->setState($state, $status);
$payment->setSkipOrderProcessing(true);
return $this;
}
you can customize this code as per you basic requirement
and let me know if you have any issue
Related
Basically, im trying to make a finance section on magento, I have looked into how to place an order as part of the finance submission, everywhere I look uses the code below (Not exact):
$order = Mage::getModel('sales/order');
$store = Mage::app()->getStore();
$website_id = Mage::app()->getWebsite()->getStoreId();
$quote = Mage::getModel('sales/order')->setStoreId($store->getId());
$customer = Mage::getSingleton('customer/session')->getCustomer();
$quote->assignCustomer($customer);
$quote->setSendCconfirmation(1);
$product_ids = array();
$cart = Mage::getModel('checkout/cart')->getQuote();
foreach($cart->getAllVisibleItems() as $item) {
$quote->addProduct($item->getProduct() , $item->getQty());
}
$shipping = $quote->getShippingAddress();
$shipping->setCollectShippingRates(true)->collectShippingRates()->setShippingMethod('flatrate_flatrate')->setPaymentMethod(array(
'method' => 'checkmo'
));
try {
$service = Mage::getModel('sales/service_quote', $quote);
$service->submitAll();
$increment_id = $service->getOrder()->getRealOrderId();
}
catch(Exception $e) {
die($e->getMessage());
}
catch(Mage_Core_Exception $d) {
die($d->getMessage());
}
And for some reason i keep getting this error:
I was loading the customer from session, and not supplying the correct model as an argument , for anyone also looking for this answer;
$customer = Mage::getModel('customer/customer')->loadByEmail(Mage::getSingleton('customer/session')->getCustomer()->getEmail());
I'm currently developing a payment plugin for VirtueMart. I have never used it before. The goal is:
When the user clicks to the confirm order button, he gets redirected to the bank interface (managed it, no work needed)
He then gets redirected back to the webshop with an answer from the bank (also done)
If the transaction is success, the order is stored as confirmed or if the transaction fails, the order is getting cancelled.
What I managed, is marked in the list above. For some reason, the order gets stored twice as pending, once when the user clicks the button, and once when the user gets redirected back to the shop. Also, if the transaction fails, the order is stored twice, also pending. I reused the standard payment plugin given with the VirtueMart aio package. All the above stuff is written in the plgVmConfirmedOrder function. I would post it here:
function plgVmConfirmedOrder ($cart, $order) {
if (!($method = $this->getVmPluginMethod ($order['details']['BT']->virtuemart_paymentmethod_id))) {
return NULL; // Another method was selected, do nothing
}
if (!$this->selectedThisElement ($method->payment_element)) {
return FALSE;
}
VmConfig::loadJLang('com_virtuemart',true);
VmConfig::loadJLang('com_virtuemart_orders', TRUE);
if (!class_exists ('VirtueMartModelOrders')) {
require(VMPATH_ADMIN . DS . 'models' . DS . 'orders.php');
}
$this->getPaymentCurrency($method);
$currency_code_3 = shopFunctions::getCurrencyByID($method->payment_currency, 'currency_code_3');
$email_currency = $this->getEmailCurrency($method);
$totalInPaymentCurrency = vmPSPlugin::getAmountInCurrency($order['details']['BT']->order_total,$method->payment_currency);
$dbValues['payment_name'] = $this->renderPluginName ($method) . '<br />' . $method->payment_info;
$dbValues['order_number'] = $order['details']['BT']->order_number;
$dbValues['virtuemart_paymentmethod_id'] = $order['details']['BT']->virtuemart_paymentmethod_id;
$dbValues['cost_per_transaction'] = $method->cost_per_transaction;
$dbValues['cost_percent_total'] = $method->cost_percent_total;
$dbValues['payment_currency'] = $currency_code_3;
$dbValues['email_currency'] = $email_currency;
$dbValues['payment_order_total'] = $totalInPaymentCurrency['value'];
$dbValues['tax_id'] = $method->tax_id;
$payment_info='';
if (!empty($method->payment_info)) {
$lang = JFactory::getLanguage ();
if ($lang->hasKey ($method->payment_info)) {
$payment_info = vmText::_ ($method->payment_info);
} else {
$payment_info = $method->payment_info;
}
}
if (!class_exists ('VirtueMartModelCurrency')) {
require(VMPATH_ADMIN . DS . 'models' . DS . 'currency.php');
}
$currency = CurrencyDisplay::getInstance ('', $order['details']['BT']->virtuemart_vendor_id);
if(!array_key_exists("fizetesValasz", $_REQUEST)){
$transaction_id = $this->getTransactionID();
$_REQUEST['tranzakcioAzonosito'] = $transaction_id;
$price = $cart->cartPrices['billTotal'];
$_REQUEST['osszeg'] = round($price);
$_REQUEST['devizanem'] = 'HUF';
$_REQUEST['backURL'] = "http://" . $_SERVER['SERVER_NAME'] . '/component/virtuemart/cart/confirm.html?Itemid=' . $_REQUEST['Itemid'];
$_REQUEST['nyelvkod'] = 'hu';
$dbValues['transaction_id'] = $transaction_id;
//this is where I redirect to the bank interface
process();
}
else{
//this is where I get the data about transaction
$transaction_datas = processDirectedToBackUrl(false);
$status_code = $transaction_datas->getStatuszKod();
$dbValues['otp_response'] = $status_code;
$this->storePSPluginInternalData ($dbValues);
$modelOrder = VmModel::getModel ('orders');
switch ($status_code) {
case 'FELDOLGOZVA':
if($transaction_datas->isSuccessful()){
$message = 'Sikeres Tranzakció!';
$new_status = $this->getNewStatus($method);
$order['customer_notified'] = 1;
$order['comments'] = '';
$modelOrder->updateStatusForOneOrder ($order['details']['BT']->virtuemart_order_id, $order, TRUE);
$message = getMessageText(($transaction_datas->getPosValaszkod()));
$cart->emptyCart();
$html = $this->renderByLayout('post_payment_success', array(
'message' =>$message,
'order_number' =>$order['details']['BT']->order_number,
'order_pass' =>$order['details']['BT']->order_pass,
'payment_name' => $dbValues['payment_name'],
'displayTotalInPaymentCurrency' => round($totalInPaymentCurrency['display'])
));
vRequest::setVar ('html', $html);
return TRUE;
}
else{
$new_status = $method->status_cancelled;
$modelOrder->updateStatusForOneOrder($order['details']['BT']->virtuemart_order_id, $order, TRUE);
$message = 'Sajnos a bank visszautasította a tranzakciót.';
$html = $this->renderByLayout('post_payment_failure', array(
'message' => $message
));
vRequest::setVar('html', $html);
return FALSE;
}
break;
case 'VEVOOLDAL_VISSZAVONT':
return FALSE;
break;
case 'VEVOOLDAL_TIMEOUT':
return FALSE;
break;
}
}
return FALSE;
}
Every help is appreciated. Thanks in advance!
So, the problem was the redirect url. There is an action called plgVmOnPaymentResponseReceived(). This is fired when a specific url is called. I only had to rewrite the $_REQUEST parameter for the redirection.
I am writing a custom order handling script for magento. If a new order is picked up by the script through cron it should create an invoice and notify the user and send a comment. I use the SOAP api for this purpose.
This works when sending an email, but how can I make the comment visible to the user on the frontend?
If I manually login to Magento admin, I can add a comment to an order and then check Visible on Frontend.
I would like the comments I add with sales_order_invoice.create and sales_order_shipment.create to be visible to the customer in the Frontend the same way. I know that is not possible with default settings in the backend, but I would like to do that.
If this is really hard to do, I would at least like the comments added with sales_order.addComment to be visible to the customer on the frontend just as when I manually comment and check Visible on Frontend.
Here is my code for the SOAP proxy:
class magentoProxyHandler{
protected $proxy;
protected $session;
function __construct(){
$this->proxy = new SoapClient('http://www.magento.nl/index.php/api/soap/?wsdl');
$this->session = $this->proxy->login('change_order', 'password');
}
function __destruct(){
$this->proxy->endSession($this->session);
}
function addComment($orderId, $status, $comment = '', $notifyCustomer = true){
$orderId = ($orderId > 100000000 ? $orderId : $orderId + 100000000);
$notify = $notifyCustomer ? true : false;
$changeOrder = array('orderIncrementId' => $orderId, 'status' => $status, 'comment'=> $comment, 'notify'=> $notify);
return $this->proxy->call($this->session, 'sales_order.addComment', $changeOrder);
}
function createInvoice($orderId, $status, $comment = 'Invoice ready', $notifyCustomer = true){
$orderId = ($orderId > 100000000 ? $orderId : $orderId + 100000000);
$notify = $notifyCustomer ? true : false;
return $this->proxy->call($this->session, 'sales_order_invoice.create', array($orderId, array(), $comment, true, true));
}
function shipOrder($orderId, $status, $comment = 'Order shipped', $notifyCustomer = true){
$orderId = ($orderId > 100000000 ? $orderId : $orderId + 100000000);
$notify = $notifyCustomer ? true : false;
return $this->proxy->call($this->session, 'sales_order_shipment.create', array($orderId, array(), $comment, true, true));
}
} //end of class
I know I can do some little improvements to this code, this was simply for testing the the soap API.
I learned to code PHP all by just reading guides on the internet and start trying. Stack overflow has been of great help in this journey for all the problems I encountered on my way; I have had a lot and I mean a lot of help by just using the search function on stack overflow in the past. Thanks for that!
Of course I used it again together with big friend Google, but with no luck for the first time. That's why this is my first question here.
I really hope you guys can help me out, thanks in advance!
OK I found out how to do it, had to change a little code:
I coppied /app/code/core/Mage/Sales/Model/Order/Api.php to /app/code/local/Mage/Sales/Model/Order/Api.php
I changed the method addComment:
public function addComment($orderIncrementId, $status, $comment = '', $notify = false, $showOnFront = true)
{
$order = $this->_initOrder($orderIncrementId);
$historyItem = $order->addStatusHistoryComment($comment, $status);
$historyItem->setIsVisibleOnFront($showOnFront);
$historyItem->setIsCustomerNotified($notify)->save();
try {
if ($notify && $comment) {
$oldStore = Mage::getDesign()->getStore();
$oldArea = Mage::getDesign()->getArea();
Mage::getDesign()->setStore($order->getStoreId());
Mage::getDesign()->setArea('frontend');
}
$order->save();
$order->sendOrderUpdateEmail($notify, $comment);
if ($notify && $comment) {
Mage::getDesign()->setStore($oldStore);
Mage::getDesign()->setArea($oldArea);
}
} catch (Mage_Core_Exception $e) {
$this->_fault('status_not_changed', $e->getMessage());
}
return true;
}
And then in my class:
function addComment($orderId, $status, $comment = '', $notifyCustomer = true, $showOnFront = true){
$orderId = ($orderId > 100000000 ? $orderId : $orderId + 100000000);
$notify = $notifyCustomer ? true : false;
$changeOrder = array('orderIncrementId' => $orderId, 'status' => $status, 'comment'=> $comment, 'notify'=> $notify, 'showOnFront' => $showOnFront);
return $this->proxy->call($this->session, 'sales_order.addComment', $changeOrder);
}
Works like a charm!
From what I've seen I can do the same thing in the shipment and invoice api files.
I used paypal php sdk with this :
https://github.com/paypal/merchant-sdk-php/blob/master/samples/RecurringPayments/CreateRecurringPaymentsProfile.php
Express checkout is works well, but use recurring payments have problem : token is invalid.
Line 152 in the sdk, it's said
A timestamped token, the value of which was returned in the response
to the first call to SetExpressCheckout. Call
CreateRecurringPaymentsProfile once for each billing
agreement included in SetExpressCheckout request and use the same
token for each call. Each CreateRecurringPaymentsProfile request
creates a single recurring payments profile.
But i don't understand how to "Call CreateRecurringPaymentsProfile once in SetExpressCheckout", there is my code:
public function createPayToken($returnUrl, $cancelUrl, $payModeData) {
$itemName = $payModeData['name'];
$order = $payModeData['fee'];
// $category = 'Digital';
$category = 'Physical';
$currencyCode = "USD";
$paymentDetails = new PaymentDetailsType();
$itemAmount = new BasicAmountType($currencyCode, $order);
$itemDetails = new PaymentDetailsItemType();
$itemDetails->Name = $itemName;
$itemDetails->Amount = $itemAmount;
$itemDetails->Quantity = 1;
$itemDetails->ItemCategory = $category;
$paymentDetails->OrderTotal = new BasicAmountType($currencyCode, $order);
$paymentDetails->PaymentAction = 'Sale';
$paymentDetails->PaymentDetailsItem[] = $itemDetails;
$setECReqDetails = new SetExpressCheckoutRequestDetailsType();
$setECReqDetails->PaymentDetails[] = $paymentDetails;
$setECReqDetails->ReqConfirmShipping = 0;
$setECReqDetails->NoShipping = 1;
$setECReqDetails->AddressOverride = 0;
$setECReqDetails->CancelURL = $cancelUrl;
$setECReqDetails->ReturnURL = $returnUrl;
$setECReqType = new SetExpressCheckoutRequestType();
$setECReqType->SetExpressCheckoutRequestDetails = $setECReqDetails;
$setECReq = new SetExpressCheckoutReq();
$setECReq->SetExpressCheckoutRequest = $setECReqType;
$paypalService = new PayPalAPIInterfaceServiceService();
try {
$setECResponse = $paypalService->SetExpressCheckout($setECReq);
exit;
} catch (Exception $ex) {
echo $ex;
exit;
}
if(isset($setECResponse)) {
if($setECResponse->Ack =='Success') {
$token = $setECResponse->Token;
return $token;
}
var_dump($setECResponse);
exit;
}
return false;
}
Thank you.
You just need to make sure you're including the billing agreement information in your SetExpressCheckout request. Take a look at this sample of set of API calls to complete a recurring payments profile using Express Checkout.
You'll notice the SEC request includes parameters for L_BILLINGTYPE0 AND L_BILLINGAGREEMENTDESCRIPTION0. You need to make sure you include those, otherwise the token that you get back won't be valid for CreateRecurringPaymentsProfile.
With the help of https://github.com/ph/magento-moneris I have managed to create a Moneris payment gateway in Magento and I am testing it now with Moneris Development site.
I have got a couple of questions where I am confused and don't know how to proceed.
Is there a way I can set 'Authorize only' to 'Authorize and Capture' some where in the code so that the capture is performed at the same time when the order is placed?
Also Is there a way that the invoicing can be done at the same time as the order is placed with the invoice mail sent to the customer n store owner.
Ex: when the 'Place Order' is clicked, the customer's card details are checked and validated. If they are ok, then the payment is captured at the same time in the merchant's account and the invoice emails are sent to the customer and store owner.
If the card details are not right, then show an appropriate message on front end to the customer as well keep that order as pending with appropriate reason for the store owner to see.
The code I have for now is for _authorize n _capture functions. Do they need to be modified or new functions needs to be created.
public function authorize(Varien_Object $payment, $amount)
{
$error = false;
// check for payment
if($amount > 0) {
$payment->setAmount($amount);
// Map magento keys to moneris way
$order = $payment->getOrder();
$billing = $order->getBillingAddress();
$avsTemplate = array('avs_zipcode' => $order->getBillingAddress()->getPostcode(), 'avs_street_number' => $order->getBillingAddress()->getStreet(1),'', 'avs_street_name' => $order->getBillingAddress()->getStreet(2),'');
$mpgAvsInfo = new mpgAvsInfo($avsTemplate);
$cvdTemplate = array('cvd_value' => $payment->getCcCid(),'cvd_indicator' => 1);
$mpgCvdInfo = new mpgCvdInfo($cvdTemplate);
$transaction = $this->_build($payment, self::TRANSACTION_PREAUTH);
$transaction->setAvsInfo($mpgAvsInfo);
$transaction->setCvdInfo($mpgCvdInfo);
$response = $this->_send($transaction);
$payment->setCcApproval($response->getReceiptId())
->setLastTransId($response->getReceiptId())
->setCcTransId($response->getTxnNumber())
->setCcAvsStatus($response->getAuthCode())
->setCcCidStatus($response->getResponseCode());
if($response->getResponseCode() > 0 && $response->getResponseCode() <= self::ERROR_CODE_LIMIT)
{
$payment->setStatus(self::STATUS_APPROVED);
$message = 'AVS Response: ' . Mage::helper('paygate')->__($this->_errors[$response->getAvsResultCode()]);
$message .= '<br>CVD Response: ' . Mage::helper('paygate')->__($this->_errors[$response->getCvdResultCode()]);
Mage::getSingleton('core/session')->addSuccess($message);
}
else if($response->getResponseCode() > self::ERROR_CODE_LIMIT && $response->getResponseCode() < self::ERROR_CODE_UPPER_LIMIT)
{
$error = Mage::helper('paygate')->__($this->_errors[$response->getResponseCode()]);
}
else
{
$error = Mage::helper('paygate')->__('Incomplete transaction.');
}
}
else
{
$error = Mage::helper('paygate')->__('Invalid amount for authorization.');
}
if ($error !== false)
Mage::throwException($error);
return $this;
}
/**
* Capture the authorized transaction for a specific order
* #var Variant_Object $payment
* #var Float $amount
*/
public function capture(Varien_Object $payment, $amount) {
$error = false;
// check for payment
if ($amount <= 0)
{
Mage::throwException(Mage::helper('paygate')->__('Invalid amount for capture.'));
}
if($amount > 0)
{
$payment->setAmount($amount);
// Map magento keys to moneris way
$transaction = $this->_build($payment, self::TRANSACTION_COMPLETION);
$response = $this->_send($transaction);
if($response->getResponseCode() > 0 && $response->getResponseCode() <= self::ERROR_CODE_LIMIT)
{
$payment->setStatus(self::STATUS_SUCCESS);
$message = 'AVS Response: ' . Mage::helper('paygate')->__($this->_errors[$response->getAvsResultCode()]);
$message .= '<br>CVD Response: ' . Mage::helper('paygate')->__($this->_errors[$response->getCvdResultCode()]);
Mage::getSingleton('core/session')->addSuccess($message);
}
else if($response->getResponseCode() > self::ERROR_CODE_LIMIT && $response->getResponseCode() < self::ERROR_CODE_UPPER_LIMIT)
{
$error = Mage::helper('paygate')->__($this->_errors[$response->getResponseCode()]);
}
else
{
$error = Mage::helper('paygate')->__('Incomplete transaction.');
}
}
else
{
$error = Mage::helper('paygate')->__('Invalid amount for capture.');
}
// we've got something bad here.
if ($error !== false)
Mage::throwException($error);
return $this;
}
Feel free to correct me anywhere or suggest a better way of doing what I'm trying to do.
In the end I'm looking forward to build a basic Moneris payment gateway in Magento which authorizes n captures the amount if the card details are right and sends invoice mails to customer n store owner all at the same time at the click of 'place order'.
And if the card details are wrong then show appropriate message to customer and keep it as pending with right reason for pending payment for the store owner to see.