├── app ├── etc │ └── modules │ │ └── Web_Ppfix.xml └── code │ └── local │ └── Web │ └── Ppfix │ ├── sql │ └── web_ppfix_setup │ │ └── mysql4-install-0.1.0.php │ ├── Model │ ├── Config.php │ ├── Source │ │ └── Currency.php │ ├── Observer.php │ ├── Standard.php │ ├── Cart.php │ └── Payment.php │ ├── Block │ └── Checkout │ │ └── Cart │ │ └── Totals.php │ ├── etc │ ├── config.xml │ └── system.xml │ └── Helper │ └── Data.php └── README.md /app/etc/modules/Web_Ppfix.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | local 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/code/local/Web/Ppfix/sql/web_ppfix_setup/mysql4-install-0.1.0.php: -------------------------------------------------------------------------------- 1 | startSetup(); 13 | 14 | 15 | $installer->endSetup(); -------------------------------------------------------------------------------- /app/code/local/Web/Ppfix/Model/Config.php: -------------------------------------------------------------------------------- 1 | _supportedCurrencyCodes = array_merge($this->_supportedCurrencyCodes, Mage::helper('ppfix')->getCurrencyArray()); 12 | } 13 | } -------------------------------------------------------------------------------- /app/code/local/Web/Ppfix/Model/Source/Currency.php: -------------------------------------------------------------------------------- 1 | getSupportedCurrency(); 10 | if (!$this->_options) { 11 | $this->_options = Mage::app()->getLocale()->getOptionCurrencies(); 12 | } 13 | $options = array(); 14 | foreach ($this->_options as $option) { 15 | if (in_array($option['value'], $_supportedCurrencyCodes)) { 16 | $options[] = $option; 17 | } 18 | } 19 | return $options; 20 | } 21 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Paypal-Multi-Currency-Magento 2 | ============================= 3 | 4 | Paypal Multi Currency Magento 5 | 6 | This module is for Magento 1.7+ to Support Paypal payments for not supported currencies by paypal 7 | 8 | After Installation go to System -> Configuration -> Payment Methods -> Paypal Multi Currency 9 | 10 | And configure the module on your choice ! 11 | 12 | Feel free to contact me Meabed.net for inquiries,issues and feedback 13 | 14 | ### Screen Shots 15 | 16 | ####Paypal payment method in Checkout page 17 | 18 | ![Paypal payment method in Checkout page](http://i.imgur.com/LMcHwJw.png) 19 | 20 | ####View Order in Adminpanel [ Payment block ] 21 | 22 | ![View Order in Adminpanel](http://i.imgur.com/O98IUHa.png) 23 | 24 | ####Base currency configuration 25 | 26 | ![Base currency configuration](http://i.imgur.com/pCdRHWB.png) 27 | 28 | ####Paypal payment method configuration 29 | 30 | ![Paypal payment method configuration](http://i.imgur.com/KG6QLTy.png) 31 | 32 | -------------------------------------------------------------------------------- /app/code/local/Web/Ppfix/Block/Checkout/Cart/Totals.php: -------------------------------------------------------------------------------- 1 | getQuote(); 8 | if ($quote->getPayment()->getMethodInstance()->getCode() == 'paypal_standard') { 9 | if (Mage::helper('ppfix')->shouldConvert() && ($quote->getQuoteCurrencyCode() != Mage::helper('ppfix')->getToCurrency())) { 10 | return true; 11 | } else { 12 | return false; 13 | } 14 | } 15 | if ($quote->getBaseCurrencyCode() != $quote->getQuoteCurrencyCode()) { 16 | return true; 17 | } 18 | return false; 19 | } 20 | 21 | public function displayBaseGrandtotal() 22 | { 23 | $firstTotal = reset($this->_totals); 24 | if (Mage::helper('ppfix')->shouldConvert()) { 25 | $total = $firstTotal->getAddress()->getBaseGrandTotal(); 26 | $total = Mage::helper('ppfix')->getExchangeRate($total); 27 | $currency = Mage::getModel('directory/currency')->load(Mage::helper('ppfix')->getToCurrency()); 28 | return $currency->format($total, array(), true); 29 | } 30 | if ($firstTotal) { 31 | $total = $firstTotal->getAddress()->getBaseGrandTotal(); 32 | return Mage::app()->getStore()->getBaseCurrency()->format($total, array(), true); 33 | } 34 | return '-'; 35 | } 36 | } -------------------------------------------------------------------------------- /app/code/local/Web/Ppfix/Model/Observer.php: -------------------------------------------------------------------------------- 1 | getConfig('business_account'); 9 | if ($currentMerchant != $ppMerchant) { 10 | $config = new Mage_Core_Model_Config(); 11 | $config->saveConfig('paypal/general/business_account', $ppMerchant, 'default', 0); 12 | } 13 | 14 | } 15 | 16 | public function setPaymentInfo(Varien_Event_Observer $observer) 17 | { 18 | $order = $observer->getOrder(); 19 | $payment = $order->getPayment(); 20 | $code = $payment->getMethod(); 21 | if (in_array($code, array('paypal_standard'))) { 22 | $payment->setAdditionalInformation('payment_currency', Mage::helper('ppfix')->getToCurrency()); 23 | $payment->setAdditionalInformation('due_amount', Mage::helper('ppfix')->convertAmount($order->getBaseGrandTotal())); 24 | $payment->setAdditionalInformation('exchange_rate', Mage::helper('ppfix')->getCurrentExchangeRate()); 25 | } 26 | $payment->save(); 27 | } 28 | 29 | public function getPaymentInfo(Varien_Event_Observer $observer) 30 | { 31 | $transport = $observer->getTransport(); 32 | $payment = $observer->getPayment(); 33 | if ($payment->getAdditionalInformation('payment_currency')) { 34 | $transport['Payment Currency'] = $payment->getAdditionalInformation('payment_currency'); 35 | } 36 | if ($payment->getAdditionalInformation('due_amount')) { 37 | $transport['Amount Due'] = $payment->getAdditionalInformation('due_amount'); 38 | 39 | } 40 | if ($payment->getAdditionalInformation('exchange_rate')) { 41 | $transport['Exchange Rate'] = $payment->getAdditionalInformation('exchange_rate'); 42 | 43 | } 44 | return; 45 | } 46 | } -------------------------------------------------------------------------------- /app/code/local/Web/Ppfix/Model/Standard.php: -------------------------------------------------------------------------------- 1 | getConfig()->isCurrencyCodeSupported($currencyCode); 9 | if ($result == false) { 10 | $result = strpos(Mage::helper('ppfix')->getConfig('extra_currencies'), Mage::app()->getStore()->getCurrentCurrencyCode()); 11 | } 12 | return $result; 13 | } 14 | 15 | /** 16 | * Return form field array 17 | * 18 | * @return array 19 | */ 20 | public function getStandardCheckoutFormFields() 21 | { 22 | $orderIncrementId = $this->getCheckout()->getLastRealOrderId(); 23 | $order = Mage::getModel('sales/order')->loadByIncrementId($orderIncrementId); 24 | /* @var $api Mage_Paypal_Model_Api_Standard */ 25 | $api = Mage::getModel('paypal/api_standard')->setConfigObject($this->getConfig()); 26 | $api->setOrderId($orderIncrementId) 27 | ->setCurrencyCode(Mage::helper('ppfix')->getToCurrency()) 28 | //->setPaymentAction() 29 | ->setOrder($order) 30 | ->setNotifyUrl(Mage::getUrl('paypal/ipn/')) 31 | ->setReturnUrl(Mage::getUrl('paypal/standard/success')) 32 | ->setCancelUrl(Mage::getUrl('paypal/standard/cancel')); 33 | 34 | // export address 35 | $isOrderVirtual = $order->getIsVirtual(); 36 | $address = $isOrderVirtual ? $order->getBillingAddress() : $order->getShippingAddress(); 37 | if ($isOrderVirtual) { 38 | $api->setNoShipping(true); 39 | } elseif ($address->validate()) { 40 | $api->setAddress($address); 41 | } 42 | 43 | // add cart totals and line items 44 | $api->setPaypalCart(Mage::getModel('paypal/cart', array($order))) 45 | ->setIsLineItemsEnabled($this->_config->lineItemsEnabled); 46 | $api->setCartSummary($this->_getAggregatedCartSummary()); 47 | $api->setLocale($api->getLocaleCode()); 48 | $result = $api->getStandardCheckoutRequest(); 49 | return $result; 50 | } 51 | 52 | private function _getAggregatedCartSummary() 53 | { 54 | if ($this->_config->lineItemsSummary) { 55 | return $this->_config->lineItemsSummary; 56 | } 57 | return Mage::app()->getStore($this->getStore())->getFrontendName(); 58 | } 59 | } -------------------------------------------------------------------------------- /app/code/local/Web/Ppfix/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 0.1.0 6 | 7 | 8 | 9 | 10 | 11 | Web_Ppfix_Model 12 | 13 | 14 | 15 | Web_Ppfix_Model_Cart 16 | Web_Ppfix_Model_Standard 17 | Web_Ppfix_Model_Config 18 | 19 | 20 | 21 | 22 | Web_Ppfix_Model_Payment 23 | 24 | 25 | 26 | 27 | 28 | Web_Ppfix_Block 29 | 30 | 31 | 32 | Web_Ppfix_Block_Checkout_Cart_Totals 33 | 34 | 35 | 36 | 37 | 38 | Web_Ppfix_Helper 39 | 40 | 41 | 42 | 43 | 44 | Web_Ppfix 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Web_Ppfix_Model_Observer 53 | setPaymentInfo 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Web_Ppfix_Model_Observer 65 | getPaymentInfo 66 | 67 | 68 | 69 | 70 | 71 | 72 | Web_Ppfix_Model_Observer 73 | setConfig 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/code/local/Web/Ppfix/Model/Cart.php: -------------------------------------------------------------------------------- 1 | _shouldRender = true; 17 | $amount = Mage::helper('ppfix')->getExchangeRate($amount); 18 | $item = new Varien_Object(array( 19 | 'name' => $name, 20 | 'qty' => $qty, 21 | 'amount' => (float)$amount, 22 | )); 23 | if ($identifier) { 24 | $item->setData('id', $identifier); 25 | } 26 | $this->_items[] = $item; 27 | return $item; 28 | } 29 | 30 | /** 31 | * Check the line items and totals according to PayPal business logic limitations 32 | */ 33 | protected function _validate() 34 | { 35 | $this->_areItemsValid = false; 36 | $this->_areTotalsValid = false; 37 | 38 | //$referenceAmount = $this->_salesEntity->getBaseGrandTotal(); 39 | $referenceAmount = Mage::helper('ppfix')->getExchangeRate($this->_salesEntity->getBaseGrandTotal()); 40 | 41 | $itemsSubtotal = 0; 42 | foreach ($this->_items as $i) { 43 | $itemsSubtotal = $itemsSubtotal + $i['qty'] * $i['amount']; 44 | } 45 | $sum = $itemsSubtotal + $this->_totals[self::TOTAL_TAX]; 46 | if (!$this->_isShippingAsItem) { 47 | $sum += $this->_totals[self::TOTAL_SHIPPING]; 48 | } 49 | if (!$this->_isDiscountAsItem) { 50 | $sum -= $this->_totals[self::TOTAL_DISCOUNT]; 51 | } 52 | /** 53 | * numbers are intentionally converted to strings because of possible comparison error 54 | * see http://php.net/float 55 | */ 56 | // match sum of all the items and totals to the reference amount 57 | if (sprintf('%.4F', $sum) == sprintf('%.4F', $referenceAmount)) { 58 | $this->_areItemsValid = true; 59 | } 60 | 61 | // PayPal requires to have discount less than items subtotal 62 | if (!$this->_isDiscountAsItem) { 63 | $this->_areTotalsValid = round($this->_totals[self::TOTAL_DISCOUNT], 4) < round($itemsSubtotal, 4); 64 | } else { 65 | $this->_areTotalsValid = $itemsSubtotal > 0.00001; 66 | } 67 | $this->_areItemsValid = $this->_areItemsValid && $this->_areTotalsValid; 68 | } 69 | 70 | protected function _render() 71 | { 72 | parent::_render(); 73 | foreach ($this->_totals as $key => $value) { 74 | $this->_totals[$key] = Mage::helper('ppfix')->getExchangeRate($this->_totals[$key]); 75 | } 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /app/code/local/Web/Ppfix/Helper/Data.php: -------------------------------------------------------------------------------- 1 | getStore()->getBaseCurrencyCode(); 8 | } 9 | 10 | public function getCurrencyArray() 11 | { 12 | return explode(',', self::getConfig('extra_currencies')); 13 | } 14 | 15 | public static function getSupportedCurrency() 16 | { 17 | return array('AUD', 'CAD', 'CZK', 'DKK', 'EUR', 'HKD', 'HUF', 'ILS', 'JPY', 'MXN', 18 | 'NOK', 'NZD', 'PLN', 'GBP', 'SGD', 'SEK', 'CHF', 'USD', 'TWD', 'THB'); 19 | } 20 | 21 | public static function shouldConvert() 22 | { 23 | //return self::isActive() && !in_array(Mage::app()->getStore()->getCurrentCurrencyCode(), self::getSupportedCurrency()) && !in_array(self::getBaseCurrency(),self::getSupportedCurrency()); 24 | return self::isActive() && !in_array(self::getBaseCurrency(), self::getSupportedCurrency()); 25 | } 26 | 27 | public static function getConfig($name = '') 28 | { 29 | if ($name) { 30 | return Mage::getStoreConfig('payment/ppfix/' . $name); 31 | } 32 | return; 33 | } 34 | 35 | public static function getToCurrency() 36 | { 37 | $to = self::getConfig('to_currency'); 38 | if (!$to) { 39 | $to = 'USD'; 40 | } 41 | return $to; 42 | } 43 | 44 | public function getCurrentExchangeRate() 45 | { 46 | $auto = self::getConfig('auto_rate'); 47 | if ($auto) { 48 | $current = Mage::app()->getStore()->getCurrentCurrencyCode(); 49 | $to = self::getToCurrency(); 50 | $rate = Mage::getModel('directory/currency')->getCurrencyRates($current, $to); 51 | //var_dump($rate); 52 | if (!empty($rate[$to])) { 53 | $rate = $rate[$to]; 54 | } else { 55 | $rate = 1; 56 | } 57 | } else { 58 | $rate = self::getConfig('rate'); 59 | } 60 | return $rate; 61 | } 62 | 63 | public static function isActive() 64 | { 65 | $state = self::getConfig('active'); 66 | if (!$state) { 67 | return; 68 | } 69 | return $state; 70 | 71 | } 72 | 73 | public function convertAmount($amount = false) 74 | { 75 | return self::getExchangeRate($amount); 76 | } 77 | 78 | public static function getExchangeRate($amount = false) 79 | { 80 | if (!self::shouldConvert()) { 81 | return $amount; 82 | } 83 | if (!$amount) { 84 | return; 85 | } 86 | $auto = self::getConfig('auto_rate'); 87 | if ($auto) { 88 | $current = Mage::app()->getStore()->getCurrentCurrencyCode(); 89 | $base = Mage::app()->getStore()->getBaseCurrencyCode(); 90 | $to = self::getToCurrency(); 91 | //$rate = Mage::getModel('directory/currency')->getCurrencyRates($current, $to); 92 | $rate = Mage::getModel('directory/currency')->getCurrencyRates($base, $to); 93 | //var_dump($rate); 94 | if (!empty($rate[$to])) { 95 | $rate = $rate[$to]; 96 | } else { 97 | $rate = 1; 98 | } 99 | } else { 100 | $rate = self::getConfig('rate'); 101 | } 102 | if ($rate) { 103 | return $amount * $rate; 104 | } 105 | return; 106 | } 107 | 108 | } -------------------------------------------------------------------------------- /app/code/local/Web/Ppfix/Model/Payment.php: -------------------------------------------------------------------------------- 1 | _generateTransactionId(Mage_Sales_Model_Order_Payment_Transaction::TYPE_CAPTURE, 22 | $this->getAuthorizationTransaction() 23 | ); 24 | 25 | $order = $this->getOrder(); 26 | $amount = (float)$amount; 27 | //DD 28 | $currency = Mage::getModel('directory/currency')->load(Mage::helper('ppfix')->getToCurrency()); 29 | Mage::log('Currency:' . $currency->getCurrencyCode()); 30 | Mage::log($currency->getCurrencyCode()); 31 | Mage::log('amount:' . strval($amount)); 32 | Mage::log('grand total:' . strval((float)$order->getBaseGrandTotal())); 33 | if ($currency->getCurrencyCode() != Mage::app()->getStore()->getBaseCurrencyCode()) { 34 | $amount = (float)$order->getBaseGrandTotal(); 35 | } 36 | 37 | //--DD 38 | $invoice = $this->_getInvoiceForTransactionId($this->getTransactionId()); 39 | 40 | // register new capture 41 | if (!$invoice) { 42 | if ($this->_isCaptureFinal($amount)) { 43 | $invoice = $order->prepareInvoice()->register(); 44 | $order->addRelatedObject($invoice); 45 | $this->setCreatedInvoice($invoice); 46 | } else { 47 | if (!$skipFraudDetection) { 48 | $this->setIsFraudDetected(true); 49 | } 50 | $this->_updateTotals(array('base_amount_paid_online' => $amount)); 51 | } 52 | } 53 | 54 | $status = true; 55 | if ($this->getIsTransactionPending()) { 56 | $message = Mage::helper('sales')->__('Capturing amount of %s is pending approval on gateway.', $this->_formatPrice($amount)); 57 | $state = Mage_Sales_Model_Order::STATE_PAYMENT_REVIEW; 58 | if ($this->getIsFraudDetected()) { 59 | $message = Mage::helper('sales')->__('Order is suspended as its capture amount %s is suspected to be fraudulent.', $this->_formatPrice($amount)); 60 | $status = Mage_Sales_Model_Order::STATUS_FRAUD; 61 | } 62 | } else { 63 | $message = Mage::helper('sales')->__('Registered notification about captured amount of %s.', $this->_formatPrice($amount)); 64 | $state = Mage_Sales_Model_Order::STATE_PROCESSING; 65 | if ($this->getIsFraudDetected()) { 66 | $state = Mage_Sales_Model_Order::STATE_PAYMENT_REVIEW; 67 | $message = Mage::helper('sales')->__('Order is suspended as its capture amount %s is suspected to be fraudulent.', $this->_formatPrice($amount)); 68 | $status = Mage_Sales_Model_Order::STATUS_FRAUD; 69 | } 70 | // register capture for an existing invoice 71 | if ($invoice && Mage_Sales_Model_Order_Invoice::STATE_OPEN == $invoice->getState()) { 72 | $invoice->pay(); 73 | $this->_updateTotals(array('base_amount_paid_online' => $amount)); 74 | $order->addRelatedObject($invoice); 75 | } 76 | } 77 | 78 | $transaction = $this->_addTransaction(Mage_Sales_Model_Order_Payment_Transaction::TYPE_CAPTURE, $invoice, true); 79 | $message = $this->_prependMessage($message); 80 | $message = $this->_appendTransactionToMessage($transaction, $message); 81 | $order->setState($state, $status, $message); 82 | return $this; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/code/local/Web/Ppfix/etc/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1000 9 | 1 10 | 1 11 | 0 12 | 13 | 14 | 15 | select 16 | adminhtml/system_config_source_yesno 17 | 0 18 | 1 19 | 1 20 | 1 21 | 22 | 23 | 24 | text 25 | 1 26 | 1 27 | 1 28 | 1 29 | validate-email required-entry 30 | 31 | 32 | 33 | extra currency to support for your store 34 | multiselect 35 | adminhtml/system_config_source_currency 36 | 2 37 | 1 38 | 1 39 | 1 40 | required-entry 41 | 42 | 43 | 44 | The selected currencies will be converted to this currency and this currency will be used in checkout instead. 45 | select 46 | web_ppfix_model_source_currency 47 | 3 48 | 1 49 | 1 50 | 1 51 | required-entry 52 | 53 | 54 | 55 | select 56 | adminhtml/system_config_source_yesno 57 | 4 58 | 1 59 | 1 60 | 1 61 | 62 | 63 | 64 | text 65 | 5 66 | 1 67 | 1 68 | 1 69 | 70 | 0 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | --------------------------------------------------------------------------------