Customize Prestashop Paypal Express Checkout Order Details - php

I am trying to hack the paypal module to change the Order details that are sent via the Express Checkout API.
With PS 1.5.4 and the latest Paypal module, the paypal page looks like this:
Item Name Amount + Tax
Item Description
Item Number
Item Price + Tax
Quantity
...
Item Total Total + Tax
Shipping And Handling Shipping + Tax
Total Total
I would rather have it show prices before tax and then just have a total tax line like this:
Item Name Amount
Item Description
Item Number
Item Price
Quantity
...
Item Total Total
Shipping And Handling Shipping
Total Tax Total Tax
Total Total
I have made modifications to process.php but I must be missing something because I am getting an error with my "hacked" process.php. When I switch it back to default it works fine though.
Here is a link to the original process.php file on the github repo:
https://github.com/PrestaShop/PrestaShop-modules/blob/master/paypal/express_checkout/process.php
The diff of my hacked process.php and the backup of the original:
Comparing files process.php and PROCESS.PHP.BAK
***** process.php
private function setProductsList(&$fields, &$index, &$total) {
...
$fields['L_PAYMENTREQUEST_0_AMT'.$index] = Tools::ps_round($product['price'], $this->decimals);
$fields['L_PAYMENTREQUEST_0_QTY'.$index] = $product['quantity'];
$product_tax = $product['price_wt'] - $product['price'];
$total = $total + (($fields['L_PAYMENTREQUEST_0_AMT'.$index] + $product_tax) * $product['quantity']);
***** PROCESS.PHP.BAK
private function setProductsList(&$fields, &$index, &$total) {
...
$fields['L_PAYMENTREQUEST_0_AMT'.$index] = Tools::ps_round($product['price_wt'], $this->decimals);
$fields['L_PAYMENTREQUEST_0_QTY'.$index] = $product['quantity'];
*****
***** process.php
private function setPaymentValues(&$fields, &$index, &$total, &$taxes){
...
else
$shipping_cost_wt = $this->context->cart->getTotalShippingCost(null, false);
***** PROCESS.PHP.BAK
private function setPaymentValues(&$fields, &$index, &$total, &$taxes){
...
else
$shipping_cost_wt = $this->context->cart->getTotalShippingCost();
*****
***** process.php
private function setPaymentValues(&$fields, &$index, &$total, &$taxes) {
...
$fields['PAYMENTREQUEST_0_AMT'] = $total + $fields['PAYMENTREQUEST_0_SHIPPINGAMT'];
$fields['PAYMENTREQUEST_0_TAXAMT'] = $this->context->cart->getOrderTotal() - $this->context->cart->getOrderTotal(
false);
}
***** PROCESS.PHP.BAK
private function setPaymentValues(&$fields, &$index, &$total, &$taxes) {
...
$fields['PAYMENTREQUEST_0_AMT'] = $total + $fields['PAYMENTREQUEST_0_SHIPPINGAMT'];
}
*****
Here is the error that I get.
Error occurred:
Please try to contact the merchant:
PayPal response:
TIMESTAMP -> 2013-04-04T09:09:42Z
L_ERRORCODE0 -> 10413
L_SHORTMESSAGE0 -> Transaction refused because of an invalid argument. See additional error messages for details.
L_LONGMESSAGE0 -> The totals of the cart item amounts do not match order amounts.
L_SEVERITYCODE0 -> Error
Anyone have any advice.

Add PAYMENTREQUEST_0_ITEMAMT with the sum of the $fields['L_PAYMENTREQUEST_0_AMT'.$index] to your API call.
I met this problem when I started to add shipping cost to PAYMENTREQUEST_0_AMT which is not exactly what is happening to you.
My best advice here is to add PAYMENTREQUEST_0_ITEMAMT whenever the sum of the item costs is different from PAYMENTREQUEST_0_AMT.

Ok,
I finally fixed it. I could write up the specific code fix, but I feel it is too specialized to my situation and this version of prestashop. If someone requests it, I will add it.
The more important part is how I found the bug.
Since the module sends a request and then has to find out from the response if there was an error, var_dump or echo were not possible for debugging.
Instead I wrote a simple custom log file to dump the values to in the process.
I have read that doing so into the apache logs is frowned upon due to potential locking issues.
So TLDR:
Use PHP file functions and log the totals and other vars to a file in the same directory.

Related

Create an Invoice after order is placed

I've create my custom payment module, it works on payment gateway, everything is working fine but I would like to set the order as paid when the return url give back a succes code. So far I've understand that I have to create an invoice for the order to be able to ave it set as paid into Magento panel.
So first of all please tell me if I'm wron until here.
Then I'm trying to create invoice on success.phtml with some codes like:
$invoice = Mage::getModel('sales/service_order', $order->prepareInvoice());
$invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_OFFLINE);
$invoice->register();
$invoice->getOrder()->setCustomerNoteNotify(true);
$invoice->getOrder()->setIsInProcess(true);
$order->addStatusHistoryComment('Automatically INVOICED by Rico.', false);
$transactionSave = Mage::getModel('core/resource_transaction')
->addObject($invoice)
->addObject($invoice->getOrder());
$transactionSave->save();
But it gives me back always a magento error, so probably is not a good idea.
Any help will be appreciated
EDIT
From this http://blog.chapagain.com.np/magento-quick-way-to-create-order-invoice-programmatically/
I've used
$invoiceId = Mage::getModel('sales/order_invoice_api')
->create($_order->getIncrementId(), array());
instead the code above and it seems that the order is paid. But I'm not sure, if is enough.
I suggest you when customer is returning to your site from payment gateway and then it must goes to a magento controller and it an action you need to add your code at there
$order=Mage::getModel('sales/order')->load($orderID);
if($order->canInvoice() and $order->getIncrementId())
{
$items = array();
foreach ($order->getAllItems() as $item) {
$items[$item->getId()] = $item->getQtyOrdered();
}
$invoiceId=Mage::getModel('sales/order_invoice_api')->create($order->getIncrementId(),$items,null,false,true);
Mage::getModel('sales/order_invoice_api')->capture($invoiceId)};
}
See http://www.amitbera.com/programmatically-create-invoice-of-a-new-order-in-magento/

add tracking number only to specific shipping method

hello based on this thread: add tracking number automatically
i have managed to add tracking numbers to orders when button 'ship' is pressed
but the question is can i make somehow check before adding tracking number? cause i want to add tracking number only to specific shipping method (carrier)
how can i do that?
i have tried to add if statement before adding tracking number like this:
public function salesOrderShipmentSaveBefore($observer)
{
$rate = Mage::getSingleton('checkout/session')->getQuote()->getShippingAddress()->getShippingRatesCollection();
$method = $rate->getCarrier();
if ($method == 'mycompany_mycarrier'){
$trackNumber='123456789';
$shipment = $observer->getEvent()->getShipment();
$track = Mage::getModel('sales/order_shipment_track')
->setNumber($trackNumber)
->setCarrierCode('mycompany_mycarrier')
->setTitle('My Carrier');
$shipment->addTrack($track);
}
but when i press ship button error says that i am calling undefined method - Mage_Sales_Model_Resource_Quote_Address_Rate_Collection::getCarrier()
maybe there is other way how can i check that it is my carrier and then add tracking number; cause this code adds tracking number but to all orders, all i want is that it add tracking number to my own created shipping method
any help would be great
// After Order Place event
$iOrderId = Mage::getSingleton('checkout/session')->getLastRealOrderId();
$oOrder = Mage::getModel('sales/order')->loadByIncrementId($iOrderId);
$oOrder->getShippingDescription();
Does the method even exist?
It tells you that you are missing a piece of code.
solved my problem, the Observer.php:
public function salesOrderShipmentSaveBefore($observer)
{
$trackNumber='987654321';
$shipment = $observer->getEvent()->getShipment();
$order = $shipment->getOrder();
$orderIncrementId=$order->getIncrementId();
$oOrder = Mage::getModel('sales/order')->loadByIncrementId($orderIncrementId);
$shipping = $oOrder->getShippingDescription();
if($shipping =='My Carrier - My Method')
{
$track = Mage::getModel('sales/order_shipment_track')
->setNumber($trackNumber)
->setCarrierCode('mycompnay_mycarrier')
->setTitle('My Carrier');
$shipment->addTrack($track);
}
}
now everything works just like i wanted, the tracking number is added to my shipping carrier only.
Thank you Kingshuk Deb, you were right since the begining, i just didnt understood that.

Match the cart item amount and the order amount when calculating taxes

My problem is the following:
I have to include the "taxamt" parameter into my application to calculate the italian "iva", but when i do the order and i call the SetExpressCheckout the application send me back the generic message
Transaction refused because of an invalid argument. See additional error messages for details.
The totals of the cart item amounts do not match order amounts.
This is the input in the SetExpressCheckout.php
$name = $L_NAME0;
$itemamt = $L_AMT0;
$PAYMENTREQUEST_0_TAXAMT = 1.22;
$tax = $PAYMENTREQUEST_0_TAXAMT;
$amt = $L_AMT0*$tax;
$nvpstr="";
$nvpstr="&L_NAME0=".$name."&L_DESC0=".$L_DESC0."&L_AMT0=".$L_AMT0."&L_QTY0=".$L_QTY0."&TAXAMT=".$tax."&AMT=".(string)$amt."&ITEMAMT=".(string)$itemamt."&ReturnUrl=".$returnURL."&CANCELURL=".$cancelURL ."&CURRENCYCODE=".$currencyCodeType."&PAYMENTACTION=".$paymentType."&SOLUTIONTYPE=".$soleStr."&LANDINGPAGE=".$landingStr."&LOCALECODE=".$lang;
Any suggestions?
Thanks a lot

Where does Magento Set a Quote Item's Price?

Whenever you load the cart page in Magento, the following code is run
$cart->init();
$cart->save();
One side effect of this is that the prices for any items in the cart are updated if the price of the product has been updated. This actually updates the entry in sales_flat_quote_item. I'm trying to track down where in code the price is updated on each quote item, and where each quote item is saved.
I know the myrid locations it could be set. I'm hoping someone knows where it actually is set. Magento 1.7x branch specifically, although info from all versions is welcome.
Dug this one up myself. So there's this
#File: app/code/core/Mage/Sales/Model/Quote.php
foreach ($this->getAllAddresses() as $address) {
...
$address->collectTotals();
...
}
which leads to this
#File: app/code/core/Mage/Sales/Model/Quote/Address.php
public function collectTotals()
{
Mage::dispatchEvent($this->_eventPrefix . '_collect_totals_before', array($this->_eventObject => $this));
foreach ($this->getTotalCollector()->getCollectors() as $model) {
$model->collect($this);
}
Mage::dispatchEvent($this->_eventPrefix . '_collect_totals_after', array($this->_eventObject => $this));
return $this;
}
The getTotalCollector object returns a sales/quote_address_total_collector object, which loads a series of collector models from global/sales/quote/totals and calls collect on them. The sub-total collector's collect method ultimately calls this
#File: app/code/core/Mage/Sales/Model/Quote/Address/Total/Subtotal.php
protected function _initItem($address, $item)
{
//...
if ($quoteItem->getParentItem() && $quoteItem->isChildrenCalculated()) {
$finalPrice = $quoteItem->getParentItem()->getProduct()->getPriceModel()->getChildFinalPrice(
$quoteItem->getParentItem()->getProduct(),
$quoteItem->getParentItem()->getQty(),
$quoteItem->getProduct(),
$quoteItem->getQty()
);
$item->setPrice($finalPrice)
->setBaseOriginalPrice($finalPrice);
$item->calcRowTotal();
} else if (!$quoteItem->getParentItem()) {
$finalPrice = $product->getFinalPrice($quoteItem->getQty());
$item->setPrice($finalPrice)
->setBaseOriginalPrice($finalPrice);
$item->calcRowTotal();
$this->_addAmount($item->getRowTotal());
$this->_addBaseAmount($item->getBaseRowTotal());
$address->setTotalQty($address->getTotalQty() + $item->getQty());
}
//...
}
and this is where the quote item gets it's price set/rest.
From a high level, the code that starts the whole process are lines 464 and 465 of Mage_Checkout_Model_Cart :
$this->getQuote()->collectTotals();
$this->getQuote()->save();
The new product price is being set against the quote in Mage_Sales_Model_Quote_Address_Total_Subtotal in the _initItem method. You will see $item->setPrice in the the if / else statement starting at line 104
If you are trying to do custom price changes on products in the cart, rather than extend and modify core classes, I use an observer sales_quote_save_before. It works great if you are trying to customize pricing (especially when I have products that can be custom length).

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