When placing pro-rated upgrade order that also has a recurring discount, the calculated price is incorrect. The formula being used is:
Old Product/Service
Price Per Day * Number of days until next due date = Amount Credited
New Product/Service
Price Per Day * Number of days until next due date = Amount Debited
Total Payable Today = Amount Debited - Amount Credited
Discounted Upgrade Price = Total Payable Today - Discount
This is fine for a one-off discount on the upgrade itself, but is incorrect for a pro-rated upgrade on the service where the discount should be applied to the Amount Debited. An older thread discussed the issue.
These values can be overridden when the user selects the product to upgrade to using the OrderProductUpgradeOverride hook. Here's an example of the variables passed to it:
Array
(
[oldproductid] => 159
[oldproductname] => Old product
[newproductid] => 161
[newproductname] => New Product
[daysuntilrenewal] => 25
[totaldays] => 31
[newproductbillingcycle] => monthly
[price] => 6.52
[discount] => 1.63
[promoqualifies] => 1
)
price is the Total Payable Today from above. There's not much to go on here, but in our situation we have no absolute value discounts (just percentages). We can use the price and discount to get the discount percentage and from that calculate what the price and discount should be:
Discount Rate = discount / price
New Price = price / (1 + Discount Rate)
New Discount = New Price * Discount
This is far from perfect, price and discount have already been rounded, so any value derived from them will have a margin of error. Here's the hook code:
function myAddon_OrderProductUpgradeOverride ($vars) {
$return = array();
if ($vars['price'] == 0) {
$discRate = 0;
} else {
$discRate = $vars['discount'] / $vars['price'];
}
$return['price'] = round( $vars['price'] / ($discRate + 1) , 2);
$return['discount'] = round( $return['price'] * $discRate, 2);
logModuleCall('myAddon', 'OrderProductUpgradeOverride', '', $vars, $return, array());
return $return;
}
add_hook('OrderProductUpgradeOverride', 1, 'myAddon_OrderProductUpgradeOverride');
If anyone can spot any problems or offer any improvements to the above, I'd be happy to hear them. I can get the new product information using the newproductid but no way to get the correct currency value. If the customer is ordering the upgrade we can get their currency, but if an admin orders it from within WHMCS it's not possible.
If the hook passed the promotion code and the price for the full payment period, the calculation could be more robust.