VirtueMart Forum

VirtueMart 2 + 3 + 4 => Virtuemart Development and bug reports => Topic started by: bcohen0 on September 02, 2017, 07:12:42 AM

Title: Getting a full product price list for customer, from back end
Post by: bcohen0 on September 02, 2017, 07:12:42 AM
Hello - I need a full price list output capability, for employees to generate for customers. This is a very common need for businesses which maintain accounts, or do quotes for supply. This needs to be accurate as the cart would be, taking into account all markup, discount, specials, etc.

It looked to me like the best way to do this is through the calculationHelper, using the method getProductPrices. However, calculationHelper can only work off the currently logged in user and it can't take an alternate user. It keeps a copy of the instance of itself, which it returns in further queries.  If it were possible to pass in a user and instantiate an independent copy of calculationHelper, then it can be used to generate a price sheet for a particular customer and then released.   To do this, modifications to take a user object (or userid) need to be made in the constructor, the method getInstance, and setShopperGroupIds. Country id also must be set, or the prices will not be preserved by the getProductPrices method.

In an effort not to change the virtuemart code, after testing the above changes, I instead created a php extension of the helper class calculationHelper. It's pretty small, and uses the base class getProductPrices method.  I have to duplicate the whole constructor because it's private in the base class. Anyhow, here is the extension class:


class calculationHelper2 extends calculationHelper
{
   private function __construct($user)
   {

      $this->_db = JFactory::getDBO();
      $this->_app = JFactory::getApplication();
      //$this->_cart =& VirtuemartCart::getCart();
      //We store in UTC and use here of course also UTC
      $jnow = JFactory::getDate();
      $this->_now = $jnow->toSQL();
      $this->_nullDate = $this->_db->getNullDate();

      $this->productVendorId = 1;

      if (!class_exists('CurrencyDisplay')) require(VMPATH_ADMIN . DS . 'helpers' . DS . 'currencydisplay.php');
      $this->_currencyDisplay = CurrencyDisplay::getInstance();
      $this->_debug = false;

      if(!empty($this->_currencyDisplay->_vendorCurrency)){
         $this->vendorCurrency = $this->_currencyDisplay->_vendorCurrency;
         $this->vendorCurrency_code_3 = $this->_currencyDisplay->_vendorCurrency_code_3;
         $this->vendorCurrency_numeric = $this->_currencyDisplay->_vendorCurrency_numeric;
      }


      $this->setShopperGroupIds(0, 1, $user);

      $model = VmModel::getModel('user');
      $model->setId($user->id);
      $virtuemart_userinfo_id_BT = $model->getBTuserinfo_id();

      $dataT = $model->getTable('userinfos');
      $data  = $dataT->load($virtuemart_userinfo_id_BT);
      if (!empty($data->virtuemart_country_id))
         $this->_deliveryCountry = $data->virtuemart_country_id;

      $this->setVendorId($this->productVendorId);

      $this->rules['Marge'] = array();
      $this->rules['Tax']    = array();
      $this->rules['VatTax']    = array();
      $this->rules['DBTax'] = array();
      $this->rules['DATax'] = array();

      //round only with internal digits
      $this->_roundindig = VmConfig::get('roundindig',FALSE);

   }

   protected function setShopperGroupIds($shopperGroupIds=0, $vendorId=1, $customUser=null) {

      if (!empty($shopperGroupIds)) {
         $this->_shopperGroupId = $shopperGroupIds;
      } else {
         $user = $customUser;

         $this->_shopperGroupId = array();
         if (!empty($user->id)) {
            $this->_db->setQuery('SELECT `usgr`.`virtuemart_shoppergroup_id` FROM #__virtuemart_vmuser_shoppergroups as `usgr`
                              JOIN `#__virtuemart_shoppergroups` as `sg` ON (`usgr`.`virtuemart_shoppergroup_id`=`sg`.`virtuemart_shoppergroup_id`)
                              WHERE `usgr`.`virtuemart_user_id`="' . $user->id . '" AND `sg`.`virtuemart_vendor_id`="' . (int) $vendorId . '" ');
            $this->_shopperGroupId = $this->_db->loadColumn();
            if (empty($this->_shopperGroupId)) {

               $this->_db->setQuery('SELECT `virtuemart_shoppergroup_id` FROM #__virtuemart_shoppergroups
                        WHERE `default`="'.($user->guest+1).'" AND `virtuemart_vendor_id`="' . (int) $vendorId . '"');
               $this->_shopperGroupId = $this->_db->loadColumn();
            }
         }
         if(!$this->_shopperGroupId) $this->_shopperGroupId = array();
         $shoppergroupmodel = VmModel::getModel('ShopperGroup');
         $site = JFactory::getApplication ()->isSite ();
         $shoppergroupmodel->appendShopperGroups($this->_shopperGroupId,$user,$site,$vendorId);
      }
   }


   static public function getInstance($user)
   {
      if (!empty($user))
      {
         $customInstance = new calculationHelper2($user);

         return $customInstance;
      }
      else
      {
         return null;
      }

   }
}


I guess I'm not sure what I expect from this post. The above works, but it would be better if Virtuemart could do a customer price list. If it can, and I've just missed it, let me know.

Oh, and I forgot to mention the other drawback of doing it this way, which is that getting the product list ends up going through the very same price calculations using the logged in user, and the existing calculationHelper.  Then afterward, I have to create the new calculationHelper2 with the correct user, and redo all the price calculations. It works, but I hate having to do this twice.


Title: Re: Getting a full product price list for customer, from back end
Post by: GJC Web Design on September 02, 2017, 10:48:01 AM
Is this not what the "Allow Administrators to change the current Shopper" setting is for

When enabled .. if u login the FE as the admin you can choose what user you want the cart to display as -- the prices will all be as if the "user" was logged in

------ oops------- just saw you wanted this from the BE

the http://www.artio.net/faqs/vm-invoice can create new orders as existing customers with all the SG restrictions, shipping etc
Title: Re: Getting a full product price list for customer, from back end
Post by: bcohen0 on September 02, 2017, 12:46:34 PM
That's interesting, I hadn't thought of going for a full-on invoice extension. 

I'm pretty new to Virtuemart 3, and I hadn't tried out front end admin. So when I try to login as super user in the front end I discover that the template I'm using gets an exception. :/    Ah well.
Title: Re: Getting a full product price list for customer, from back end
Post by: GJC Web Design on September 02, 2017, 16:40:15 PM
QuoteSo when I try to login as super user in the front end I discover that the template I'm using gets an exception. :/    Ah well.

Yes.. you have discovered that there are some very badly coded templates out there.... 
You should do this sort of experimentation with the stock templates (Beez or Protostar)
then u know the standard VM template files are being used.. then go kick the template wally
Title: Re: Getting a full product price list for customer, from back end
Post by: Milbo on September 02, 2017, 18:35:56 PM
There is no need to extend the calculationhelper.

The correct way is to enhance the product model or just to add an extra helper. then the shoppergroups (as you did) and a normal getProduct list, plus getProduct with prices, for example. Just a level higher.