Zen Cart Logo
Forums / Bug Reports / attributes + price factor + special price = incorrect totals

attributes + price factor + special price = incorrect totals

Views: 10,112

Results 1 to 20 of 20
28 Feb 2017, 1:48 AM
#1
balihr avatar

balihr

Totally Zenned

Join Date:
Oct 2008
Location:
Croatia
Posts:
1,769
Plugin Contributions:
20

attributes + price factor + special price = incorrect totals

Zen Cart 1.5.5d vanilla install

Option name "Color" and "Size" changed from dropdown to checkbox.

Inserted new product, set "Product Priced by Attributes" to YES. Product price is set to 0.

Going to Attribute Controller. Assigned "Size: Large". Then, new attribute as follows:
Color: Black, price +15, price factor 5, Default Selected YES
Color: Red, price +15, price factor 5, Default Selected YES

[img]https://s6.postimg.org/58m2b2sox/2017_02_28_022857.png[/img]

Frontend is fine, product info page:

[img]https://s6.postimg.org/9j0q6nxs1/2017_02_28_023054.png[/img]

Adding to cart, subtotal is $180 and I go through checkout with $180.

Now, problem.

I go to Price Manager for that product and set a Special Price to 33.33%

[img]https://s6.postimg.org/nqqevbagx/2017_02_28_023324.png[/img]

Product page is fine and I add the item to cart. Subtotal is $120.

[img]https://s6.postimg.org/6eunnm6dd/2017_02_28_023520.png[/img]

I start checkout, get to checkout_payment page and my subtotal is now $170.

[img]https://s6.postimg.org/xdyiirsu9/2017_02_28_023739.png[/img]

What happened, where is that subtotal coming from? It's not the regular price (that would be $180) and it's not the discounted price (that should be $120 as shown on shopping cart page). Shopping cart sidebox is still showing the correct $120. If I go through checkout, I'm charged $170 (tested on a live site with auth.net and PayPal). Any help would be appreciated.
And, yes, price factor is important because in reality, this is a "bundle" where color:red stands for 6 individual items and we want to show the "per item" price, which is in this case $15 ($10 when discounted). What's most confusing is that shopping_cart page is showing the correct subtotal so that part is working fine...

28 Feb 2017, 2:50 AM
#2
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,908
Plugin Contributions:
2

Re: attributes + price factor + special price = incorrect totals

Not easy to test, but what if the two check boxes under the one option name were each applied to a dropdown, does the full setup work? I ask, because until recently, ZC checkbox attributes didn't fair well generally speaking for such calculations/determinations. Grr, I know I didn't say that right, but basically determination of "combinations" or something similar didn't work out well. Curious if it would work at all with another option name type that would allow the selection(s) you are wanting to offer even if offered a different way.

28 Feb 2017, 11:56 AM
#3
balihr avatar

balihr

Totally Zenned

Join Date:
Oct 2008
Location:
Croatia
Posts:
1,769
Plugin Contributions:
20

Re: attributes + price factor + special price = incorrect totals

mc, I'm not sure I follow the idea... But, thing is - it DOES calculate correctly on the shopping_cart page and that's what is confusing me. I'd say the shopping_cart class is doing it properly, but then for some reason the order_total modules mess it up, and I don't get it...

Splitting the checkboxes into separate dropdowns is a very impractical setup, although it might be OK as a temporary solution... I'll test and report back.

28 Feb 2017, 12:11 PM
#4
balihr avatar

balihr

Totally Zenned

Join Date:
Oct 2008
Location:
Croatia
Posts:
1,769
Plugin Contributions:
20

Re: attributes + price factor + special price = incorrect totals

OK, the idea with separating the options into 2 dropdowns made things even worse...

Here's the admin setup:

[img]https://s6.postimg.org/q0j4jt8sh/2017_02_28_130434.png[/img]

Both red and black have price factor 5:

[img]https://s6.postimg.org/gh9fqcla9/2017_02_28_130529.png[/img]

Adding to cart with Black and Red selected, cart shows $100 subtotal.

[img]https://s6.postimg.org/l4fhs48n5/2017_02_28_130652.png[/img]

Going to checkout, subtotal is $0!

[img]https://s6.postimg.org/udho28hj5/2017_02_28_130757.png[/img]

Now, if I remove the special price, price factor doesn't work at all on the dropdowns, it just takes the $15 and cart shows $30, checkout subtotal is OK. :blink:

There's something REALLY weird going on here...

28 Feb 2017, 1:44 PM
#5
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,065
Plugin Contributions:
56

Re: attributes + price factor + special price = incorrect totals

@balihr, I'd previously isolated the issue to the zen_discount_calc function, see here, but have not had a chance to go back and unravel that logic to understand the flow.

1 Mar 2017, 1:50 AM
#6
lankeeyankee avatar

lankeeyankee

Totally Zenned

Join Date:
Jan 2007
Posts:
1,514
Plugin Contributions:
1

Re: attributes + price factor + special price = incorrect totals

After setting up your original scenario I can repeat the bug. And I can confirm it is caused by the price factor and special price combination after changing the item to not have a price factor. I tried this in my old site on my test server which is 1.3.7.1 and get the exact same result so this has been going on for that long.

What I notice is when you apply the special price then look at it in the attributes controller the total/disc amounts are unexpected. With no special it shows correctly $90. With the 33.333% discount it now shows $65/$43.33. It should show $90/$60, or it would if there is no price factor involved. I have never used the price factor feature so I am not familiar with it's logic. So why is it showing this price of $65/$43.33? I get the same thing in the 1.3.7.1 test store, too.

Now, try the original setup but instead of special use salemaker. I get a price of $65 for each attribute and a price of $130 in the cart. It also shows $65 in the attributes controller. But going to checkout I get a total of $180, the original price, so there is no salemaker price applied.

It could be that the $65 special/salemaker prices are derived from the (factor) 5 being calculated at the sale price (5 x $10) and then added to the 1 at regular price. But why there is a $50 discrepancy with special price during checkout is hard for me to figure out.

In looking at the code I see there is a function zen_get_attributes_price_factor in includes/functions/functions_prices but it is only called in the shopping cart class which is probably why the cart is showing the correct price. So it looks like it needs to be added elsewhere, like perhaps the order class? I'm way too rusty with the code and zen cart file tree/structure to offer any advice.

2 Mar 2017, 4:19 PM
#7
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,908
Plugin Contributions:
2

Re: attributes + price factor + special price = incorrect totals

After a little code following and a few failed attempts, I found this to be a solution to the "central" issue described, though still need to identify a solution to the "difference" in price display/change of an attributes applied price... Ie. when looking in the attributes controller and seeing two prices in the Total | Disc column... It appears that when that is so, that the product page doesn't show the proper information to relate back to the actual total that will be seen once the product is added to the cart/displayed in checkout... But that's still somewhat of a separate issue.

So the "fix" is/was to duplicate an action that is in the includes/classes/shopping_cart.php file within the function cart(). Just prior to iterating each of the product a constant is defined:

if (!defined('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL')) define('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL', 1);

This causes the calculations on the shopping cart page to come out correctly as this affects the results of the includes/functions/functions_prices.php file's function zen_get_attributes_price_factor which in turn affects the function zen_get_attributes_price_final in the same file and also the shopping_cart class in multiple locations...

Well, one place in which that function is called is within the shopping_cart class' function attributes_price... Okay, no big deal right? Except, in the order class when generating the order price values, this class function is called to assign the final_price for each product... Thus... In order for the same "calculation" to be performed in the order class as is/was done in the shopping_cart class, a similar assignment of the constant is needed... Now.. The question becomes, should it be entered only in the shopping_cart class (three times: once in the cart function, once in the attributes_price function), should an instance be added to the order class just before the assignment of the total price so that it is defined for the attributes_price calculation as the order class uses the shopping_cart class to generate the values, or should it be applied site wide???

I chose to add it to the attributes_price calculation seeing as other functions call this class/function to perform calculations on the product and therefore it seems to make sense to apply it only there... (Yes in initial testing I did make it a global constant to see what/if anything would change in site operation.) The function is not used on the admin side, and the following store side files use this function in a default install:
includes/classes/shopping_cart.php
includes/classes/order.php
includes/modules/payment/sagepay_zc/SagepayBasket.php (Appears that the below correction will ensure proper pricing there for this setup.)

Now, using a setup similar to what has been described of a product having attributes with a price factor applied I've gone through a normal purchase without any further deductions, a sale (with a few variations of how to apply the sale), a special, combination of the two and while I did see a little oddity in calculating a sale where the new price was identified and the above setup established, it didn't seem directly related to the change (could include/exclude the constant and the result was effectively the same at the product level and responded as expected at the checkout area), but instead either my understanding or the setup... But that seems to also be a different issue.

So anyways, modifying the includes/classes/shopping_cart.php code to include the below highlighted item seemed to "fix" the issue of attributes + price factor + special price coming out to be the incorrect total at checkout.

function attributes_price($products_id) {
 	global $db, $currencies;
 	
	$total_attributes_price = 0;
 	$qty = $this->contents[$products_id]['qty'];
 	
	if (isset($this->contents[$products_id]['attributes'])) { 	
 	if (!defined('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL')) define('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL', 1); // mc12345678 Added to apply the attribute's price factor and price factor offset against the provided special price if a special is present otherwise against the provided price when returning the value from the function zen_get_attributes_price_factor found in includes/functions/functions_prices.php 
	reset($this->contents[$products_id]['attributes']);
 	while (list($option, $value) = each($this->contents[$products_id]['attributes'])) {
 	  $attributes_price = 0;

Perhaps an improved solution would be to include some "flag" on each product such that the use of the specials price for attributes could be applied or not with the input to the function zen_get_attributes_price_factor would have the $price modified for that product such that

if (defined('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL') && ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL == 1) {
  if ($product[$i]['attribute_special_flag']) {
    // do nothing but provide the $normal and $special values
  } else {
    $special = $normal;
  }
} else {
  if ($product[$i]['attribute_special_flag']) {
    $normal = $special;
  } else {
    // do nothing but provide the $normal and $special values
  }
}
zen_get_attributes_price_factor($normal, $special, $attributes_price_factor, $attributes_price_factor_offset);

That way, the individual product could be targeted, of course an alternative is to add a parameter to the function which when provided would allow lookup of that factor "on the spot" rather than having to modify other code to swap/consider the possibility... Whatever, just some thoughts. :)

2 Mar 2017, 4:20 PM
#8
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,908
Plugin Contributions:
2

Re: attributes + price factor + special price = incorrect totals

After a little code following and a few failed attempts, I found this to be a solution to the "central" issue described, though still need to identify a solution to the "difference" in price display/change of an attributes applied price... Ie. when looking in the attributes controller and seeing two prices in the Total | Disc column... It appears that when that is so, that the product page doesn't show the proper information to relate back to the actual total that will be seen once the product is added to the cart/displayed in checkout... But that's still somewhat of a separate issue.

So the "fix" is/was to duplicate an action that is in the includes/classes/shopping_cart.php file within the function cart(). Just prior to iterating each of the product a constant is defined:

if (!defined('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL')) define('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL', 1);

This causes the calculations on the shopping cart page to come out correctly as this affects the results of the includes/functions/functions_prices.php file's function zen_get_attributes_price_factor which in turn affects the function zen_get_attributes_price_final in the same file and also the shopping_cart class in multiple locations...

Well, one place in which that function is called is within the shopping_cart class' function attributes_price... Okay, no big deal right? Except, in the order class when generating the order price values, this class function is called to assign the final_price for each product... Thus... In order for the same "calculation" to be performed in the order class as is/was done in the shopping_cart class, a similar assignment of the constant is needed... Now.. The question becomes, should it be entered only in the shopping_cart class (three times: once in the cart function, once in the attributes_price function), should an instance be added to the order class just before the assignment of the total price so that it is defined for the attributes_price calculation as the order class uses the shopping_cart class to generate the values, or should it be applied site wide???

I chose to add it to the attributes_price calculation seeing as other functions call this class/function to perform calculations on the product and therefore it seems to make sense to apply it only there... (Yes in initial testing I did make it a global constant to see what/if anything would change in site operation.) The function is not used on the admin side, and the following store side files use this function in a default install:
includes/classes/shopping_cart.php
includes/classes/order.php
includes/modules/payment/sagepay_zc/SagepayBasket.php (Appears that the below correction will ensure proper pricing there for this setup.)

Now, using a setup similar to what has been described of a product having attributes with a price factor applied I've gone through a normal purchase without any further deductions, a sale (with a few variations of how to apply the sale), a special, combination of the two and while I did see a little oddity in calculating a sale where the new price was identified and the above setup established, it didn't seem directly related to the change (could include/exclude the constant and the result was effectively the same at the product level and responded as expected at the checkout area), but instead either my understanding or the setup... But that seems to also be a different issue.

So anyways, modifying the includes/classes/shopping_cart.php code to include the below highlighted item seemed to "fix" the issue of attributes + price factor + special price coming out to be the incorrect total at checkout.

function attributes_price($products_id) {
 	global $db, $currencies;
 	
	$total_attributes_price = 0;
 	$qty = $this->contents[$products_id]['qty'];
 	
	if (isset($this->contents[$products_id]['attributes'])) { 	
 	if (!defined('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL')) define('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL', 1); // mc12345678 Added to apply the attribute's price factor and price factor offset against the provided special price if a special is present otherwise against the provided price when returning the value from the function zen_get_attributes_price_factor found in includes/functions/functions_prices.php 
	reset($this->contents[$products_id]['attributes']);
 	while (list($option, $value) = each($this->contents[$products_id]['attributes'])) {
 	  $attributes_price = 0;

Perhaps an improved solution would be to include some "flag" on each product such that the use of the specials price for attributes could be applied or not with the input to the function zen_get_attributes_price_factor would have the $price modified for that product such that

if (defined('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL') && ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL == 1) {
  if ($product[$i]['attribute_special_flag']) {
    // do nothing but provide the $normal and $special values
  } else {
    $special = $normal;
  }
} else {
  if ($product[$i]['attribute_special_flag']) {
    $normal = $special;
  } else {
    // do nothing but provide the $normal and $special values
  }
}
zen_get_attributes_price_factor($normal, $special, $attributes_price_factor, $attributes_price_factor_offset);

That way, the individual product could be targeted, of course an alternative is to add a parameter to the function which when provided would allow lookup of that factor "on the spot" rather than having to modify other code to swap/consider the possibility... Whatever, just some thoughts. :)

2 Mar 2017, 8:58 PM
#9
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,065
Plugin Contributions:
56

Re: attributes + price factor + special price = incorrect totals

@mc12345678, I think that you're "over thinking" the solution. As I'd noted in my previous response, the issue lies in the zen_discount_calc function.

2 Mar 2017, 9:17 PM
#10
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,908
Plugin Contributions:
2

Re: attributes + price factor + special price = incorrect totals

lat9:

@mc12345678, I think that you're "over thinking" the solution. As I'd noted in my previous response, the issue lies in the zen_discount_calc function.

Yet to be seen. Say that because was able to successfully carry the prices from shopping cart to checkout when the constant was set either in whole on the site or just in the identified function when using a special (further the post referenced related to a sale which is a value of 5 as compared to 59 for a special, not saying that either is returning the expected result, but still a different issue).

2 Mar 2017, 10:10 PM
#11
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,908
Plugin Contributions:
2

Re: attributes + price factor + special price = incorrect totals

Did a quick search for the usage of the zen_get_discount_calc function as far as it applies to the shopping_cart it is only used to affect the price of the base attribute value. Elsewhere in the code, other calculations typically are performed before feeding it into the function and it seems that it is those calculations or how the results are used that are causing the visualized issues as seen in the attributes_controller and attributes.

3 Mar 2017, 1:21 PM
#12
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,065
Plugin Contributions:
56

Re: attributes + price factor + special price = incorrect totals

Isn't part of the issue here that the use of the "price factor" in this case is (kind of) confusing the processing?

From "the book":

The Price Factor and Offset pricing mechanism calculates the attribute price [B][I]based on a percentage of the product price[/I][/B].

But the product's price is based on its attributes, so it seems like the final price is kind of chasing its tail. Why not simply define each of those attributes' prices as 65.00?

While the solution provided by mc12345678 generates the expected result, should those results be expected (given the above)?

5 Mar 2017, 4:04 PM
#13
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,908
Plugin Contributions:
2

Re: attributes + price factor + special price = incorrect totals

lat9:

Isn't part of the issue here that the use of the "price factor" in this case is (kind of) confusing the processing?

From "the book":

The Price Factor and Offset pricing mechanism calculates the attribute price [B][I]based on a percentage of the product price[/I][/B].

> 
> But the product's price is based on its attributes, so it seems like the final price is kind of chasing its tail.  Why not simply define each of those attributes' prices as 65.00?
> 
> While the solution provided by mc12345678 generates the expected result, should those results be expected (given the above)?

What does "the book" say about pricing a product by its attributes? It ought to say something regarding the setup as setting the product's price to zero and then providing an amount for the product attribute's price... That would then identify the product's price which falls in line directly with the suggested setup.  Then taking things a step further a price factor/offset could be used as is currently attempted such that (in this case) the attribute is adding 500% to the price of the product to be calculated as the final price of 90 (before the special).  So yes, depending on the desired aspect of display there could be a chase scenario, but everything is pretty independently calculated so that there is no loop, just actions not yet factored into the base code pretty much whenever zen_get_attributes_price_final didn't return the same price as zen_get_discount_calc. 

Found this to work for the above conditions(s) discussed where a special only is applied to a product that is priced by attributes, has a price factor, and the special price is less than or equal to the product price... A salemaker sale still offers different options/visualization at least on the product page but may be okay in the shopping cart and because of the separate ways that specials, sales, and attributes are calculated, without joining those things more together (datawise) there appears to continue to be a need to modify the associated functionality to gain more control.

So in includes/modules/YOUR_TEMPLATE/attributes.php

Find (in v1.5.5 starting at line 62):
          $discount_type = zen_get_products_sale_discount_type((int)$_GET['products_id']);
          $discount_amount = zen_get_discount_calc((int)$_GET['products_id']);

          $zv_display_select_option = 0;
And add the following line that is in color:
          $discount_type = zen_get_products_sale_discount_type((int)$_GET['products_id']);
          $discount_amount = zen_get_discount_calc((int)$_GET['products_id']);
          $products_price_is_priced_by_attributes = zen_get_products_price_is_priced_by_attributes((int)$_GET['products_id']);

          $zv_display_select_option = 0;

Then find (in v1.5.5 was line 114 before adding the above or any other changes):
              if (((CUSTOMERS_APPROVAL == '2' and $_SESSION['customer_id'] == '') or (STORE_STATUS == '1')) or ((CUSTOMERS_APPROVAL_AUTHORIZATION == '1' or CUSTOMERS_APPROVAL_AUTHORIZATION == '2') and $_SESSION['customers_authorization'] == '') or (CUSTOMERS_APPROVAL == '2' and $_SESSION['customers_authorization'] == '2') or (CUSTOMERS_APPROVAL_AUTHORIZATION == '2' and $_SESSION['customers_authorization'] != 0) ) {

                $new_attributes_price = '';
                $new_options_values_price = 0;
                $products_options_display_price = '';
                $price_onetime = '';
              } else {
                // collect price information if it exists
                if ($products_options->fields['attributes_discounted'] == 1) {
                  // apply product discount to attributes if discount is on
                  //              $new_attributes_price = $products_options->fields['options_values_price'];
                  $new_attributes_price = zen_get_attributes_price_final($products_options->fields["products_attributes_id"], 1, '', 'false');
                  $new_attributes_price = zen_get_discount_calc((int)$_GET['products_id'], true, $new_attributes_price);
                } else {
                  // discount is off do not apply
                  $new_attributes_price = $products_options->fields['options_values_price'];
                }

And add the following colored text to support product page display of attributes that are priced by attributes (meaning with 0 price in the product's base price), have a special (not a sale) where the attribute's price is to be discounted, and in particular have a price factor and or a price factor offset that causes a difference of price calculation between two "standard" methods.

              if (((CUSTOMERS_APPROVAL == '2' and $_SESSION['customer_id'] == '') or (STORE_STATUS == '1')) or ((CUSTOMERS_APPROVAL_AUTHORIZATION == '1' or CUSTOMERS_APPROVAL_AUTHORIZATION == '2') and $_SESSION['customers_authorization'] == '') or (CUSTOMERS_APPROVAL == '2' and $_SESSION['customers_authorization'] == '2') or (CUSTOMERS_APPROVAL_AUTHORIZATION == '2' and $_SESSION['customers_authorization'] != 0) ) {

                $new_attributes_price = '';
                $new_options_values_price = 0;
                $products_options_display_price = '';
                $price_onetime = '';
              } else {
                // collect price information if it exists
                if ($products_options->fields['attributes_discounted'] == 1) {
                  // apply product discount to attributes if discount is on
                  //              $new_attributes_price = $products_options->fields['options_values_price'];
                  $new_attributes_price = zen_get_attributes_price_final($products_options->fields["products_attributes_id"], 1, '', 'false');
                  $new_attributes_price = zen_get_discount_calc((int)$_GET['products_id'], true, $new_attributes_price);
                  $new_attributes_final = zen_get_attributes_price_final($products_options->fields["products_attributes_id"], 1, $products_options, 'false');
                  if ($discount_type == 59 && $products_price_is_priced_by_attributes && $new_attributes_price < $new_attributes_final) {
                    // Known condition (59) Special applied, no Sale. Reason an issue: priced by attributes and attribute has price factor.
                    $new_attributes_price = $new_attributes_final - (zen_get_products_base_price((int)$_GET['products_id']) - zen_get_products_special_price((int)$_GET['products_id'], true));
                  }
                } else {
                  // discount is off do not apply
                  $new_attributes_price = $products_options->fields['options_values_price'];
                }

I've had this solution a couple of days, but have been trying to break it.  Certainly if more information were passed into the function zen_get_discount_calc it seems that more could be done to prevent modification like this, but otherwise right now it seems like there are a few "outliers" that need to be uniquely addressed such as this one.
5 Mar 2017, 4:39 PM
#14
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,065
Plugin Contributions:
56

Re: attributes + price factor + special price = incorrect totals

"The Book" discusses identifying that the product is priced by attributes (note that the product's base price doesn't have to be 0.00) and then to use the attributes' settings to identify what each attribute "contributes" to the price.

I've got a test install of ZC1.5.5e and I'll give your suggested changes a try.

For your solution to @balihr's issue, is there any way to provide the proper result without using that constant definition? That's what threw me for a loop initially because it looks more like a band-aid than a programmatic solution.

5 Mar 2017, 5:20 PM
#15
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,065
Plugin Contributions:
56

Re: attributes + price factor + special price = incorrect totals

@mc12345678, which issue does your most recent update address?

I've applied the changes to a just-installed v1.5.5e and ran it by the SaleMaker issue that I reported here, but no joy. Each of the attribute's prices still show $50.00 instead of $25.00 on the product_info page.

5 Mar 2017, 5:58 PM
#16
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,908
Plugin Contributions:
2

Re: attributes + price factor + special price = incorrect totals

lat9:

"The Book" discusses identifying that the product is priced by attributes (note that the product's base price doesn't have to be 0.00) and then to use the attributes' settings to identify what each attribute "contributes" to the price.

I've got a test install of ZC1.5.5e and I'll give your suggested changes a try.

For your solution to @balihr's issue, is there any way to provide the proper result without using that constant definition? That's what threw me for a loop initially because it looks more like a band-aid than a programmatic solution.

So someone, at one point at or before ZC 1.5.0 decided that the calculated price when using the price factor should possibly be based on the provided $special value or perhaps not depending on whether the constant is defined as '1' or not... The reason provided by the blame history was that the constant may already be defined before its use in the shopping_cart class function calculate...

Thing is, that currently the only place in which the constant is defined is during the use of the calculate function of the shopping_cart class.. So, perhaps in say the checkout_payment area, if the shopping_cart class were called and either the calculate function was used or any of the show_total related functions, and then the order class was created, the solution wouldn't involve editing the shopping_cart class to add the constant test in the attributes_price function. This would instead modify the order of operations in order to ensure that an obscure constant was set in advance/outside the need of it really being set and almost "by accident". This would be a real PATCH/BAND-AID as compared to the constant being addressed in the code where it might actually apply. Further such a sequencing/resequencing would not yet assign the constant as might be needed for when other code tried to use the attributes_price function of the shopping_cart class.

Another solution relates back to the function that uses that constant (similar on both store and admin side) in any number of the below suggested ways:
the function zen_get_attributes_price_factor to always use $special if it is non-zero:
seems that there was a historical reason to have it pre-determined to need to be used as such. The other "parts" I was looking at in my previous (accidentally duplicated) post was a way to add a parameter to the function, which when defined/set would override the test within the function and blanketly apply the $special when the $special was non-zero (ie. remove dependency on the constant being defined/set).

Current function starts like:

// return attributes_price_factor 
   function zen_get_attributes_price_factor($price, $special, $factor, $offset) { 
     if (ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL =='1' and $special) {        // calculate from specials_new_products_price 
       $calculated_price = $special * ($factor - $offset); 
     } else { 

No use of the constant:

// return attributes_price_factor 
   function zen_get_attributes_price_factor($price, $special, $factor, $offset) { 
     if (/* ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL =='1' and */$special) {        // calculate from specials_new_products_price 
       $calculated_price = $special * ($factor - $offset); 
     } else { 

Keep the constant but add a parameter that must be set to true in order to calculate the price factored price based off of the provided $special price and the $special price not evaluating to false. This solution requires additional coding to provide/identify where this function should use the price factor/factor offset against the special price (if it exists) or not which likely would require a field off of the product's information page more than anything, or perhaps on the special's page, though that also seems a little buried:

// return attributes_price_factor 
   function zen_get_attributes_price_factor($price, $special, $factor, $offset, $attributes_price_factor_from_special = false) { 
     if ((ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL =='1' || $attributes_price_factor_from_special == true) and $special) {        // calculate from specials_new_products_price 
       $calculated_price = $special * ($factor - $offset); 
     } else { 

Similar, but automatically considers all provided values to use the $special value until told otherwise, which is somewhat like what is happening in the calculate function of the shopping_cart, that until someone adds some software, codes a constant, etc, then the attributes' price_factor will be calculated from the special if there is one, if not then use the $price value.

// return attributes_price_factor 
   function zen_get_attributes_price_factor($price, $special, $factor, $offset, $attributes_price_factor_from_special = true) { 
     if ((ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL =='1' || $attributes_price_factor_from_special == true) and $special) {        // calculate from specials_new_products_price 
       $calculated_price = $special * ($factor - $offset); 
     } else { 

Regarding the priced-by-attributes base price being zero or not, besides a number of postings indicating that other price "adjustments" don't fair well if a price other than zero is entered, found that the shopping_cart class doesn't do well/as might have been expected for this situation if a price is entered on the product page as well as in the attribute's value and a price factor applied... Somewhere in the process the attribute's price doesn't get factored like might be expected or at least differently than when the product's price is zero.

5 Mar 2017, 6:45 PM
#17
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,908
Plugin Contributions:
2

Re: attributes + price factor + special price = incorrect totals

lat9:

@mc12345678, which issue does your most recent update address?

I've applied the changes to a just-installed v1.5.5e and ran it by the SaleMaker issue that I reported here, but no joy. Each of the attribute's prices still show $50.00 instead of $25.00 on the product_info page.
Doesn't address sale_maker issues.

Addresses: product priced-by-attributes, attribute has a price factor and/or price factor offset, has a special applied.

A sale is a completely different animal. The comments in the code indicate that a product that is priced by attribute and the product has a percent sale applied should resolve the final price to use the sale percent off (assuming as pointed out today by torvista that the sale price is updated after the product's price has been entered/modified).

The test(s) added by my above solution evaluate to the two prices being the same, because it seems that the subfunctions never view the resulting calculations associated with the attribute as a "difference" and therefore such evaluation (which was outside the scope of the OP) requires a different solution applied elsewhere.

5 Mar 2017, 7:01 PM
#18
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,065
Plugin Contributions:
56

Re: attributes + price factor + special price = incorrect totals

Yes, that attributes' handling continues to make my head spin!

I'll point out that there's a demo product (id=157) that has a non-zero base price, implying that the functionality was intended ... whether or not it works correctly.

7 Mar 2017, 3:19 AM
#19
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,908
Plugin Contributions:
2

Re: attributes + price factor + special price = incorrect totals

I can't believe that some form of solution has been found. It seems like it was simple to correct and I can't believe that no one has done this before.. Okay, there may be some "tests" or improvements still to be made around the code to protect the user, but... Sum and total, this is the correction(s) that were needed to go from start to finish on processing a product that is or is not priced by attributes where the attributes can be associated with the special OR a sale (OR combination)... I need someone to confirm/disprove aspects of it, but it became all too clear...

Anyways, still need the CONSTANT to support transferring the individual attribute related prices over to the checkout_ related path so:

includes/classes/shopping_cart.php needs to include the below highlighted item which seems to "fix" the issue of at least attributes + price factor + special price coming out to be the incorrect total at checkout.

function attributes_price($products_id) {
     global $db, $currencies;
     
    $total_attributes_price = 0;
     $qty = $this->contents[$products_id]['qty'];
     
    if (isset($this->contents[$products_id]['attributes'])) {     
     if (!defined('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL')) define('ATTRIBUTES_PRICE_FACTOR_FROM_SPECIAL', 1);  // mc12345678 Added to apply the attribute's price factor and price  factor offset against the provided special price if a special is present  otherwise against the provided price when returning the value from the  function zen_get_attributes_price_factor found in  includes/functions/functions_prices.php 
    reset($this->contents[$products_id]['attributes']);
     while (list($option, $value) = each($this->contents[$products_id]['attributes'])) {
       $attributes_price = 0;

Then working from the end of the file up (so line numbers hold true throughout) in includes/functions/functions_prices.php:
Find line 1083:

      $attributes_price_final += $pre_selected->fields["options_values_price"];

and replace with:

//      $attributes_price_final += $pre_selected->fields["options_values_price"];
      $attributes_price_final += zen_get_discount_calc($pre_selected->fields["products_id"], $pre_selected->fields["products_attributes_id"], $pre_selected->fields["options_values_price"] + (zen_get_products_price_is_priced_by_attributes($pre_selected->fields["products_id"]) ? zen_products_lookup($pre_selected->fields["products_id"], 'products_price') : 0));

Then find line 1081:

      $attributes_price_final -= $pre_selected->fields["options_values_price"];

and replace with:

//      $attributes_price_final -= $pre_selected->fields["options_values_price"];
      $attributes_price_final -= zen_get_discount_calc($pre_selected->fields["products_id"], $pre_selected->fields["products_attributes_id"], (zen_get_products_price_is_priced_by_attributes($pre_selected->fields["products_id"]) ? zen_products_lookup($pre_selected->fields["products_id"], 'products_price') : 0) + (zen_get_products_price_is_priced_by_attributes($pre_selected->fields["products_id"]) ? -1 : 1) * $pre_selected->fields["options_values_price"]);

Line 560:

            $calc = ($attributes_amount * $special_price_discount);

replace with:

            $calc = ($attributes_amount * $sale_price_discount);

Line 539:

            if ($special_price_discount != 0) {
              $calc = ($attributes_amount * $special_price_discount);

replace with:

            if ($sale_price_discount != 0) {
              $calc = ($attributes_amount * $sale_price_discount);

At line 501 add/insert the following:

    if ($new_products_price != 0) {
      $sale_price_discount = ($new_sale_price != 0 ? ($new_sale_price/$new_products_price) : 1);
    } else {
      $sale_price_discount = '';
    }

And in includes/modules/YOUR_TEMPLATE/attributes.php (or rather the base install), comment out line 126:

//                      $new_attributes_price = zen_get_discount_calc((int)$_GET['products_id'], true, $new_attributes_price);

And then are some similar changes that can be made to the admin side. I was working on changing the information presented in the admin attributes_controller such that the discount calculated would be displayed, but I've set that aside for the moment...

Committed these changes to a ZC PR

17 Jan 2019, 10:00 PM
#20
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,908
Plugin Contributions:
2

Re: attributes + price factor + special price = incorrect totals

Seems that the following ZC commits/pulls might correct both of the issues described here. The commits/pulls are based on changes made from ZC 1.5.5 to ZC 1.5.6 (and corrections made to the first pull to ZC 1.5.6):
https://github.com/mc12345678/zc-v1-series/commit/ffa8646c177a9c814b8e298a50726016a5fe4b5a
https://github.com/zencart/zencart/pull/1404/files
https://github.com/zencart/zencart/pull/2075/files