4 replies [Last post]
derhasi@drupal.org's picture
Offline
Joined: 01/20/2009
Juice: 3

At DrupalCamp Cologne there was a suggestion on adding an hook_product() that lets us edit a product on product load. So we could solve the VAT/GST calculation on product load.

On a TrainSession back from Cologne to Hannover SteffenR and me worked out some concept. I hope this can help to create a clear structure for future releases.

Some central problems of current ubercart seems to be,
* No flexible prize adjust
* no itemization of prize adjusts
* no logging of current currency, taxes, ... in order ?
* no arranging of different prize adjust possible (e.g. to do tax before discount or discount before tax)

Therefore I think we need to itemize the prizes (sell prize, costs, list prize), e.g. as objects, with one property that collects the adjustments.

(object) $prize
  ->  (str) currency    //current sitewide currency?? (for logging)
  ->  (array) adjustments  //list of nested arrays
        [0] => (array)adjustment 1
        [1] => (array)adjustment 2
        [2] => (array)adjustment 3
        ...
  ->  (obj) sell_prize
        -> sell_prize
        ... possible additional values provides by modules ...
        -> with_taxes
        -> without_taxes
        -> without_discount
        ...
  ->  (obj) list_prize
        ... like sell prize ...
  ->  (obj) costs
        ... like sell prize ...

$prize->sell prize->sell_prize would be the prize customer has to pay. The other components could be used to show adjustments, e.g. on invoice or for further calculation or statistics (shipping costs)

The adjustments and additional components could be processed after calling hook_product to ensure propper logging of information and providing a integrated method for applying changes to prizes.
The adjustments would be applied on sell_prize, costs, list_prize.

Each adjustment could be described by:

[type] =>
* label  // translatable name of adjustment
* option // option as selector for adjustment types: e.g. tax rate
* value  // value that indicates an adjustment on the current prize value

In an hook_product_adjust_info() this adjustment types could be declared with arrays

*type  //e.g. tax, fee, shipping_per_product, discount
*title //human readable, translatable label
*adjust callback //a callback function that acts on the current product

Adjustment could act depending on product costs or list prizes.
E.g. apply sell_prize to be 120% of costs, or to be 90% of list prize for automated prize regulation.

<?php

/**
* @param $product
*   the product object retrieved from hook_product
* @param $type
*   type of adjustment
* @param $option
*   attribute for callback
* @param $value
*   value that indicates adjustment
* @param $back
*   perator for calculationg backwards, if set to true
* @return (array)
*/
function prizesminus1_adjust_callback($product,$type,$option,$value,$back=FALSE){
  ...
  return array(
   
'sell_prize'=>array('sell_prize'=>-1,'without_taxes'=>-1,'with_taxes'=>-1.17),
   
'costs'=>array('costs'=>-1),
  );
}
?>

These adjustment values on the current prize and additional components will be applied after each other, so there will be allways the actual $product with all applied adjustments listed.

The new product_load could look like this:

<?php
function uc_product_load(&$node) {
 
$product = db_fetch_object(db_query('SELECT model, list_price, cost, sell_price, weight, weight_units, length, width, height, length_units, pkg_qty, default_qty, unique_hash, ordering, shippable FROM {uc_products} WHERE vid = %d', $node->vid));
 
module_invoke_all("product",$product);//product by Ref
 
 
$adjustment_infos = module_invoke_all("prize_adjustment_info");
  foreach (
$product->adjustments as $adjustment){
     
$info = $adjustment_infos[$adjustment['type']];
     
$product4val = $product;//ensures product by value
     
$return = call_user_func($info['adjust callback'],$product4val,$adjustment['type'],$adjustment['option'],$adjustment['value']);
      foreach(
$return as $pkey=>$obj){
          foreach (
$obj as $ckey=>$component){
             
$product->$pkey[$ckey] += $component;
          }
      }
  }
  return
$product;
}
?>

By implementing such hook, modules like uc_attribute, uc_fee, uc_discount could easily use this hook to apply prize adjustments per product(!).

Ryan's picture
Offline
Joined: 08/07/2007
Juice: 15422
Re: hook_product for solving VAT/GST & co?

(Just so you don't get discouraged, I have bookmarked this post for review and have been chatting w/ Mike about this since his return from Germany. Will post my thoughts up here as soon as I can. Smiling )

Lyle's picture
Offline
AdministratoreLiTe!
Joined: 08/07/2007
Juice: 6841
Re: hook_product for solving VAT/GST & co?

One of the main ideas kicked around is a kind of hook_product_alter() that gets called during uc_product_load(). This lets modules affect the actual product data that gets attached to the node. Along with this is a rather large change to the Ubercart core to implement a "display price" in addition to the "sell price". The idea is that modules would only add their changes to the display price while the sell price is the value entered in the node form.

To ease the burden of coding, I've turned the definitions around so that the modules are expected to modify the sell_price, and uc_product will preserve the value of the product that is entered in the node form. This is necessary so that the calculations done by other modules aren't affected when the node is updated.

I believe that the only other place that might need the original price is on invoices, so the product value has been given a token: [value]. It is certainly possible for this number to become a line item, as well as other modules' adjustments.

If there's something I've missed, mention it. There is a patch, so play with it some and see what works.

AttachmentSize
display_price.patch 6.2 KB
Lyle's picture
Offline
AdministratoreLiTe!
Joined: 08/07/2007
Juice: 6841
Re: Re: hook_product for solving VAT/GST & co?

I cleaned up the patch a little and put it on drupal.org: http://drupal.org/node/369286. I'll post subsequent patches there, but I guess discussion can continue here as well.

Ryan's picture
Offline
Joined: 08/07/2007
Juice: 15422
Re: Re: Re: hook_product for solving VAT/GST & co?

Curious to know if you took Al's comments in this post into account. Puzzled