Magento1.7 - Add optional fee over order - magento

How can I add an optional 10% fee over the whole order? I want my customers to be able to choose between no fee or a optional 10% fee (with some advantages for them).
At this moment, I've tried to represent this by enabling "Free shipping" and "Flat rate".
So at System/Configuration/Shipping Methods I've put the following values:
- 'Handling Fee' => '0.10'
- 'Calculate Handling Fee'=>'Percent'
- 'Type' => 'Per order'
As a result, the generated orders have a '10 cents' fee, instead of a percentage over its value.
How does can I represent this with Magento? Should I use Flat rates?
PS: I'm testing it only with back-end, should I face any difference compared with end user?

I have achieved what I was looking for by editing app/code/core/Mage/Shipping/Model/Carrier/Flatrate.php by adding the following method
protected function _getPerorderPrice($cost, $handlingType, $handlingFee){
if ($handlingType == self::HANDLING_TYPE_PERCENT) {
$val = ($cost * $this->_numBoxes * $handlingFee);
return $val;
}
return ($cost * $this->_numBoxes) $handlingFee;
}
and by changing the line 78 to:
$shippingPrice = $request->getPackageValue();
I'm not sure if this will cause any side-effect, so please comment if you identify any :)
At this moment everything seems to be working fine.

Related

Prevent Available stock become minus

It's possible that in Adempiere, Inventory Stock become negative. One of the way to make it become negative is when we put Quantity in Internal Use Inventory more than Available Stock in Warehouse.
Example
Product Info
------------
Product || Qty
Fertilizer || 15
It's shown in Product Info that the current Qty of Fertilizer is 15. Then I make Internal Use Inventory document
Internal Use Inventory
----------------------
Product || Qty
Fertilizer || 25
When I complete it, Quantity will be -10. How can I prevent Internal Use Inventory being completed when Quantity is more than Available Stock so that I can avoid negative stock ?
This is purposely designed functionality of Adempiere. Under some scenarios the Inventory is allowed to become negative because it is felt in those scenarios it is better to allow the process to complete but being negative it highlights a problem that must be addressed. In the case of the Internal Use the user is warned, that the stock will go negative if they proceed.
To change this standard functionality you need to modify the
org.compiere.model.MInventory.completeIt()
But if you change the code directly, it will make it more difficult to keep your version in sync with the base Adempiere or even just applying patches.
The recommended approach would be to add a Model Validator. This is a mechanism that watches the underlying data model and enables additional code/logic to be injected when a specific event occurs.
The event you want is the Document Event TIMING_BEFORE_COMPLETE.
You would create a new model validator as described in the link, register it in Adempiere's Application Dictionary and since you want your code to trigger when Inventory Document Type is executed you would add a method something like this
public String docValidate (PO po, int timing)
{
if (timing == TIMING_BEFORE_COMPLETE) {
if (po.get_TableName().equals(MInventory.Table_Name))
{
// your code to be executed
// it is executed just before any (internal or physical)
// Inventory is Completed
}
}
return null;
} // docValidate
A word of warning; the Internal Use functionality is the same used by Physical Inventory (i.e. a stock count) functionality! They just have different windows in Adempiere. So be sure to test both functionalities after any change is applied. From the core org.compiere.model.MInventory there is a hint as how you might differentiate the two.
//Get Quantity Internal Use
BigDecimal qtyDiff = line.getQtyInternalUse().negate();
//If Quantity Internal Use = Zero Then Physical Inventory Else Internal Use Inventory
if (qtyDiff.signum() == 0)
In order to prevent the stock from being negative you can use two methods
Callout in Code
BeforeSave Method
In order to apply it in Callout you need to create a Callout class and get the current Stock Qty at the locator there and then subtract the qty from entered Qty and if the result is less than 0 , display the error. Apply this on the Qty field and you will get the desired result.
This is slightly better way , as this doesn't needs creating a new class in code altogether and will consume less memory altogether , Search for MInventoryLine class in code and then search for beforesave() in it. Add the same code (getting the stock and then subtracting it from the entered Qty). The Code in beforesave() will be like this
if (your condition here) { log.saveError("Could Not Save - Error", "Qty less than 0"); return false; }
Now I am assuming that you know the basic code to create a Callout and design a condition, If you need any help , let me know.
Adding to the answer of Mr. Colin, please see the below code to restrict the negative inventory from the M_Inventory based transaction. You can consider the same concept in M_Inout and M_Movement Tables also.
for (MInventoryLine line : mInventory.getLines(true))
{
String blockNegativeQty = MSysConfig.getValue("BLOCK_NEGATIVE_QUANTITY_IN_MATERIAL_ISSUE","Y", getAD_Client_ID());
if(blockNegativeQty.equals("Y"))
{
//Always check the on Hand Qty not Qty Book Value. The old Drafted Qty Book Value may be changed alredy.
String sql = "SELECT adempiere.bomqtyonhand(?, ?, ?)";
BigDecimal onhandQty = DB.getSQLValueBD(line.get_TrxName(), sql, line.getM_Product_ID(), mInventory.getM_Warehouse_ID()
, line.getM_Locator_ID());
BigDecimal QtyMove = onhandQty.subtract(line.getQtyInternalUse());
if(QtyMove.compareTo(Env.ZERO) < 0)
{
log.warning("Negative Movement Quantity is restricted. Qty On Hand = " + onhandQty
+ " AND Qty Internal Use = " + line.getQtyInternalUse()
+ ". The Movement Qty is = " + QtyMove);
negativeCount ++;
negativeProducts = negativeProducts + line.getM_Product().getName() + ": " + onhandQty + " ; ";
}
}
}
if(negativeCount > 0)
{
m_processMsg = "Negative Inventory Restricted. "
+ " Restriction has been enabled through the client level system configurator."
+ " Products : " + negativeProducts;
}
return m_processMsg;

Magento - Get Discount Type in Cart

I need to be able to get the discount type applied in the cart.
I can get the discount amount like so:
$cart = Mage::getModel('checkout/cart')->getQuote();
$totals = $cart->getTotals();
$discount = $totals["discount"]->getValue();
How can i check what type of discount it is - whether it is a percentage or fixed amount off?
Take a look at applied_rule_ids in sales_flat_quote and sales_flat_quote_item
You could try something like
//if the item has not had a rule applied to it skip it
if($item->getAppliedRuleIds() == '')continue;
/*
* I cant remember in the database they might be comma separated or space if multiple rules were applied
* the getAppliedRuleIds() function is the one you want
*/
foreach(explode(",",$item->getAppliedRuleIds()) as $ruleID){
//Load the rule object
$rule = Mage::getModel('catalogrule/rule')->load($ruleID);
// Throw out some information like the rule name what product it was applied to
echo "<p>".$item->getSku()." had rule ".$rule->getName()."(".$item->getAppliedRuleIds().") applied </p>";
}
See Magento - get price rules from order

Magento: Multiple Currency Conversion on Custom Options Prices

I have several websites using different currencies on each store view. The base currency (default) is set to GBP.
If I add a fixed price to a custom option the currency is converted according to store currency which is fine.
The problem starts when I want to update other values afterwards as it keeps converting the price.
For example, Let’s say I have a product on Store View 1 with a custom option that adds 100 GBP for a blue color option.
The same product will appear on Store View 2 with a custom option that adds 120 EUR for a blue color option, according to the correct currency conversion.
If I change any value on Store View 2, for example, changing the name of the product or adding an image, a change that doesn’t involve the price or the custom options, and than I save the change, it will continue to convert the price of the custom option.
If it was 120 EUR it will refer to it as if it is a new value of 120 GBP and convert it to 143.5 EUR and so on.
If I’ll click save again it will convert it again to 171.5 EUR and so on.
This happens because Magento refers to the custom options added price as a new value that needs to be converted.
Any idea how can I solve this as every time I change a value of a product it changes the custom options price?
I know that this is quite old question, but this bug still occurs (even in Magento 1.9) so maybe my answer will help somebody.
You have to overwrite Mage_Catalog_Model_Resource_Product_Option_Value class.
First add this method:
protected function checkIfPriceHasNotBeenChanged($object, $storeId)
{
$newPrice = (float)sprintf('%F', $object->getPrice());
$priceTable = $this->getTable('catalog/product_option_type_price');
$select = $this->_getReadAdapter()->select()
->from($priceTable, 'price')
->where('option_type_id = ?', (int)$object->getId())
->where('store_id = ?', $storeId);
$oldPrice = $this->_getReadAdapter()->fetchOne($select);
return $newPrice == $oldPrice;
}
Then use it in _saveValuePrices method:
if ($object->getStoreId() != '0' && $scope == Mage_Core_Model_Store::PRICE_SCOPE_WEBSITE
&& !$object->getData('scope', 'price')) {
$baseCurrency = Mage::app()->getBaseCurrencyCode();
$storeIds = Mage::app()->getStore($object->getStoreId())
->getWebsite()
->getStoreIds();
if (is_array($storeIds)) {
foreach ($storeIds as $storeId) {
if ($priceType == 'fixed') {
if ($this->checkIfPriceHasNotBeenChanged($object, $storeId)) {
continue;
}
(...)

Magento & Paypal tax rounding issue

I have some rounding issues with Paypal and Magento 1.7.0.2 - All prices on the site include tax and the tax is worked out at 20% (VAT).
I will go to checkout and everything is correct:
I will then click on place order, and Paypal will be like this, which is incorrect because the grand total is now 1p less. This appears to be cause by how the tax is rounded.
In some cases, it works ok, but in others the tax is rounded incorrectly. I have tried making changes to the tax calculation method calcTaxAmount() in app/code/core/Mage/Tax/Model/Calculation.php
I added this to the calcTaxAmount method which seemed to fix it, but it cause the prices on the product page to then be incorrect (1p less).
$amount = $this->roundUp($amount);
I'm pretty certain this is a bug, but I'm out of ideas. If anyone has come across this before and has a solution I'd be happy to hear it. Any help much appreciated.
EDIT: Here are my tax settings in Magento
I think I've found the solution to this issue plaguing the community.
If your prices include tax, the tax calculation is wrong.
Here's the fix - In Mage_Tax_Model_Calculation::calcTaxAmount():
change the condition:
if ($priceIncludeTax)...
to:
if ( ! $priceIncludeTax ) ...
So the condition looks like:
if ( ! $priceIncludeTax ) {
$amount = $price*(1-1/(1+$taxRate));
} else {
$amount = $price*$taxRate;
}
For details, check out my comments: http://www.magentocommerce.com/boards/viewthread/247201/P45/
Remember not to modify the core files - create a copy in local
I "fixed" this today for i client but not really happy with the solution. But it works.
It is better if you copy this file to your local folder:
app/code/core/Mage/Paypal/Model/Api/Nvp.php
I added this code (Only for the express checkout) on line 606 so it look like this.
$request['SHIPPINGAMT'] = ($request['AMT'] - ($request['TAXAMT'] + $request['ITEMAMT']));
$response = $this->call(self::SET_EXPRESS_CHECKOUT, $request);
$this->_importFromResponse($this->_setExpressCheckoutResponse, $response);
And you need to turn of Transfer Cart Line Items in the paypal moule in the backend
If somebody knows a better solution then just overwriting the shippingcost let me know
This problem has been plaguing me (and by looks of it the magento community for ages), thanks to ShopWorks push in the right direction (inclusive of his code snippet, thanks mate! However it would bug out if going back to the cart from express checkout, added a check in to prevent this.) of the $request parameters I came up with the following fix (/hack):
On line 606 of Nvp.php place the following:
$totalValue = $request['TAXAMT'] + $request['ITEMAMT'];
$finalValue = $totalValue - $request['AMT'];
if($request['SHIPPINGAMT'] > 0) {
$request['SHIPPINGAMT'] = ($request['AMT'] - ($request['TAXAMT'] + $request['ITEMAMT']));
$totalValue = $request['TAXAMT'] + $request['ITEMAMT'] + $request['SHIPPINGAMT'];
$finalValue = $totalValue - $request['AMT'];
}
if($request['AMT'] != $totalValue) {
if($totalValue > $request['AMT']) {
$request['TAXAMT'] = $request['TAXAMT'] - $finalValue;
} elseif($totalValue < $request['AMT']) {
$request['TAXAMT'] = $request['TAXAMT'] + $finalValue;
} else {
$request['AMT'] = $request['TAXAMT'] + $request['ITEMAMT'];
}
}
Additionally, the following needs to be also placed within the call() function (line 938 of Nvp.php):
$totalValue = $request['TAXAMT'] + $request['ITEMAMT'] + $request['SHIPPINGAMT'];
$finalValue = $totalValue - $request['AMT'];
if($request['AMT'] != $totalValue) {
if($totalValue > $request['AMT']) {
if($finalValue > 0) {
// its preferable that we change the tax amount over the grand total amount
$request['TAXAMT'] = $request['TAXAMT'] - $finalValue;
} else {
$request['AMT'] = $totalValue;
}
} elseif($totalValue < $request['AMT']) {
if($finalValue > 0) {
// its preferable that we change the tax amount over the grand total amount
$request['TAXAMT'] = $request['TAXAMT'] + $finalValue;
} else {
$request['AMT'] = $totalValue;
}
} else {
$request['AMT'] = $totalValue;
}
}
This is a hack, and treat it as such. My colleague is currently testing it but seems to be OK for the moment, it is also helpful to set the tax calculation method by unit price (our accountants are happy with this arrangement, but this is for the UK, i'm not sure if other countries will frown upon that particular tax calculation method).
The reason I am manipulating the $request['AMT'] is because occasionally the calculation of the $finalValue variable would produce a -0.9999 repeating integer which is of no use to anyone, my maths sucks so if anyone wants to improve upon this, please do so!
As always don't overwrite the nvp.php in the core directory, create a seperate rewrite module or do this in app/local/mage. First option preferably! :-)
There is a "bug" on Paypal in magento module (at least on my Magento 1.8.0);
It resides in the Mage_Paypal_Model_Cart class.
To validate that the amounts are correct, the method _validate() on line 381 sums up all items prices from the order, adds shipping fees and taxes, and compares the result with the total value of the order (got from order method getBaseGrandTotal())
But sometimes, there is a 0.009999999999999999 difference between the amounts (it must come from different roundings methods, I don't know); so the items are not valid and the method getItems() from line 146 returns false.
In my case this resulted in customers paying a different amount and a "fraud suspicion" flag on their orders.
I fixed it by changing the comparison method (line 404) from :
if (sprintf('%.4F', $sum) == sprintf('%.4F', $referenceAmount)) {
$this->_areItemsValid = true;
}
to
$diff = abs(sprintf('%.4F', $sum) - sprintf('%.4F', $referenceAmount));
if ($diff < 0.01) {
$this->_areItemsValid = true;
}
I still hope that there will not be diffs of more than 0.009999999 in the future...
Hope this helps.
I'm using CE1.7.0.2 and have been stuck on this problem for days, tried several solutions, and finally landed on Adam Hall's fix/hack. The ideal looks reasonable to me, so I applied it on my site and everything went well until this morning, I realized that the adjustment on tax amount doesn't work for our situation.
We're in California and selling stuff all over the states, customers in California will be charged for sales tax while others outside will not. So when tax amount is zero and have to subtract the difference, it will generate a negative tax amount which obviously will be rejected by paypal. So when subtracting difference from tax amount, I added a conditional statement
if ($request['TAXAMT'] > 0) {
$request['TAXAMT'] = $request['TAXAMT'] - $finalValue;
} else {
$request['SHIPPINGAMT'] = $request['SHIPPINGAMT'] - $finalValue;
}
If tax amount is zero, I will adjust shipping amount instead of tax amount. (Sure if both tax and shipping are free, this will not work, but I don't think that will happen in real business.) Hope this could help those who have the same problem as us.
i just changed transfer cart line items to "NO", without the above code change.. and it worked.
Magento 1.9.0.1
just FYI - test if it works for you.
Dmytro

Best way to integrate values into enum (dictionary), then calculating based on user selection in form

Any guidance or pointing me to an example would be much appreciated (I can't formulate a good search term on the Googleplex).
I have a model using enums that i define in a dictionary and then render on the view with #Html.RadioButtonFor, etc.
Here is an example of my model:
public PaymentPlanList PaymentPlan { get; set; }
public enum PaymentPlanList
{
PaymentPlan_One,
PaymentPlan_Two,
}
public class PaymentPlanDictionary
{
public static readonly Dictionary<PaymentPlanList, string> paymentplanDictionary = new Dictionary<PaymentPlanList, string>
{
{ PaymentPlanList.PaymentPlan_One, "One full payment in advance (receive the lowest price)." },
{ PaymentPlanList.PaymentPlan_Two, "Two payments: first payment of 50% due up front, the balance of 50% due within 30 days (increases fee by $100)." },
};
static string ConvertPaymentPlan(PaymentPlanList paymentplanlist)
{
string name;
return (paymentplanDictionary.TryGetValue(paymentplanlist, out name))
? name : paymentplanlist.ToString();
}
static void Main()
{
Console.WriteLine(ConvertPaymentPlan(PaymentPlanList.PaymentPlan_One));
Console.WriteLine(ConvertPaymentPlan(PaymentPlanList.PaymentPlan_Two));
}
}
And, for completeness, this is my view related to the above:
<p>
#Html.RadioButtonFor(m => m.PaymentPlan, "PaymentPlan_One")
One full payment in advance (receive the lowest price).
</p>
<p>
#Html.RadioButtonFor(m => m.PaymentPlan, "PaymentPlan_Two")
Two payments: first payment 50% due up front, the balance of 50% due within 30 days (increases fee by $100).
</p>
This is a quote system I have users fill out. For this particular service, say I charge $1,000.00. This is the base price. Based on user input, this price will be changed, and I want to show that to the user. So, if the user selects the first option, the price remains unchanged. If the user selects the second option, the fee is increased by $100.00.
This changes exponentially, since there are more inputs that affect the price (if selected).
Ultimately, based on the user inputs, I need to calculate the total. I am rendering a view which will display the total. I was thinking of using some #{} blocks and if/else if statements to either a) show nothing if what was selected does not increase the total, or b) showing the additional amount (e.g., $100.00), and then later showing a total.
Something like (EDITING here for clarity):
Base service: $1,000.00
Addon service1: $100.00 (only if user selects "PaymentPlan_Two" for two payments of 50% each (from the PaymentPlanList enum), otherwise hidden (and no addition of the $100.00) if user selects "PaymentPan_One" and pays in full)
Addon service2: $0.00 (this is hidden and a $0.00 or no value since the user did not select anything from a separate enum, but the value of $100.00 would be added if selected, which would make the Total $1,200.00 if it were selected; ALTERNATIVELY, how could I handle if there were 3 or more items in the list? E.g., Choice_One is $0.00, Choice_Two is $100.00 and Choice_Three is $200.00)
TOTAL: $1,100.00
Thanks for any help.
let's see if I understand your requirements correctly:
The application needs to add prices to a base price, depending on
selection of Addon services.
These selections are from a Dictionary, which is based on an Enum
Therefore we're looking to store the price against the Enum to keep the data associations in one place.
It is possible to store a single value against an Enum:
public enum PaymentPlanList
{
PaymentPlan_One = 100,
PaymentPlan_Two = 200,
}
However, I don't think this would be flexible enough for our needs - Enums only allow integers, and are commonly used this way in bitwise operations (where the values are multiples of 2).
I think a better solution here might be to use a Model-View-View-Model (MVVM) which can contain the logic about which services are available, how much they cost, and which services are valid in combination with other services.
There's an ticket pricing example (which sounds similar in concept to the domain here) on the Knockout.js home page that re-calculates a travel ticket price on the client web-page based on a user selection.

Resources