Announcement

Collapse
No announcement yet.

Can't get custom discount module to work

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Can't get custom discount module to work

    I'm working on my first Miva module, in general everything is fine, but I can't get the system to call the `DiscountModule_Discount_Items` function. On paper it looks like I'm doing everything correctly, but I must be missing something.

    My goal is for this function to be called whenever the BASK screen is loaded, so I can loop through all items in the basket and apply any necessary discounts. Here's the relevant code, any idea what I might be doing wrong?

    Code:
    <mvFunction name="Module_Description" parameters="module var" standardOutputLevel="">
        .....
        <mvAssign name="l.module:api_ver" value="5.00">
        <mvAssign name="l.module:features" value="discount, system, vis_system, component, data_store">
    </mvFunction>
    
    <mvFunction name="DiscountModule_Capabilities" parameters="module var, capabilities var" standardOutputLevel="">
        <mvEval expr="{'<br><b>DiscountModule_Capabilities function called</b>'}"><br>
        <mvAssign name="l.capabilities:items" value=1>
        <mvAssign name="l.capabilities:basket" value=0>
        <mvAssign name="l.capabilities:tax" value=0>
        <mvAssign name="l.capabilities:shipping" value=0>
        <mvAssign name="l.capabilities:provision_settings" value=0>
    </mvFunction>
    
    <mvFunction name="DiscountModule_Discount_Items" parameters="module var, pricegroup var, discount_state var" standardOutputLevel="">
        <mvEval expr="{'<br><b>DiscountModule_Discount_Items function called</b>'}"><br>
        <mvEval expr="{UpdatePrices()}">
        <mvFunctionReturn value="0">
    </mvFunction>
    None of the output is ever printed to the screen, and the `UpdatePrices` function is never called...


  • Discount modules don't get called every time the basket is displayed. They get called when the basket contents change, or when something else happens that might affect discount status, such as the customer selecting a shipping method (in case there's a free-shipping discount). I think this was done for performance reasons; recalculating the discount state for a shopping session can be a complex operation.

    During my own module testing, I noticed that discount modules get called when you click the Update button to change a quantity on the Basket page. This works even if you didn't actually type a different number in the Quantity box. So that's an easy way to do quick, repetitive tests of a discount module.

    The technique that you described -- updating the discount status whenever the basket contents are displayed -- used to be a pretty common way of handling discounts; I wrote a number of modules that work that way. But those modules used the component feature, running as extensions to the "basket" Item. That was in the days before the discount feature was added to the API.
    Kent Multer
    Magic Metal Productions
    http://TheMagicM.com
    * Web developer/designer
    * E-commerce and Miva
    * Author, The Official Miva Web Scripting Book -- available on-line:
    http://www.amazon.com/exec/obidos/IS...icmetalproducA

    Comment



    • Hi Mike,

      Kent is correct on how / when discounts are re-calculated. In addition, DiscountModule_Discount_Items is only triggered when at least 1 product in the basket is associated with a price group. Hope this helps and allows you easier debugging.

      Let me know if you have anymore questions.
      David Carver
      Miva, Inc. | Software Developer

      Comment


      • Thanks all,

        I seem to still be missing something... I added an item to the cart and clicked update, but the DiscountModule_Discount_Items function still doesn't seem to be called. The item does have price groups assigned, but not under the Price Group's "Qualifying Products" section. I have it assigned under the Product's "Price Groups" section. Not sure if that makes a difference?

        Miva's built-in Price Group (Volume Pricing) is working just fine, showing the updated price for the item depending on the quantity in the cart. So I believe the item is correctly associated with the price group.

        Comment


        • OK I figured out what I was doing wrong. I had to create a new price group for my discount. I was thinking I could have it automatically triggered all the time.

          So now the problem is that the module is updating the price, but the default item price is taking over after my module makes the price change. Here's the relevant code. For debugging purposes, I first pull the price and print it, then change it, then pull and print it again:

          Code:
          <mvComment> <!-- debug: check price --></mvComment>
          <mvAssign name="l.query" value="{ 'SELECT price FROM ' $ g.Store_Table_Prefix $ 'BasketItems WHERE line_id = ?' }">
          <mvOpenView name="Merchant" view="ItemPrice" query="{ l.query }" fields="l.lineID">
          <mvAssign name="l.currentPrice" value="{ItemPrice.d.price}">
          <mvCloseView name="Merchant" view="ItemPrice">
          <mvEval expr="{'<br><b>Current Price: </b>' $ l.currentPrice}"><br>
          
          <mvComment> <!-- change price --></mvComment>
          <mvIf expr="{l.matchingPriceFound AND l.basketItems[l.entryNumber]:price NE l.matchingPrice}">
              <mvQuery name="Merchant"
                  query="{ 'UPDATE ' $ g.Store_Table_Prefix $ 'BasketItems SET price = ? WHERE line_id = ?' }"
                  fields="l.matchingPrice, l.lineID"
              >
              <mvIf expr="{ g.mvQuery_Error }">
                  <mvFunctionReturn value="{ [ g.Module_Library_Utilities ].Error( 'MER-BUT-00015', g.mvQuery_Error ) }">
              </mvIf>
          </mvIf>
          
          <mvComment> <!-- debug: check price --></mvComment>
          <mvAssign name="l.query" value="{ 'SELECT price FROM ' $ g.Store_Table_Prefix $ 'BasketItems WHERE line_id = ?' }">
          <mvOpenView name="Merchant" view="ItemPrice" query="{ l.query }" fields="l.lineID">
          <mvAssign name="l.currentPrice" value="{ItemPrice.d.price}">
          <mvCloseView name="Merchant" view="ItemPrice">
          <mvEval expr="{'<br><b>Modified Price: </b>' $ l.currentPrice}"><br>
          Output at the top of the page is:
          Current Price: 100
          Modified Price: 8
          But the basket still shows the price as 100.

          Comment


          • Mike, you got here too late :^) . Your techniques would have been OK a few years ago, but things changed with the arrival of the discount API. Discount modules can't just change the price in the basket like that. Instead, there's a discount_state variable that is passed to your module; and you need to change the price in that structure.

            If you look at some of the discount modules in the LSK, you can see how it's done. My favorite one to copy-and-paste from is the Specific Sale Price module, since my own projects usually work that way. They need different logic to calculate the actual price, but the rest of the hookup stays about the same.
            Kent Multer
            Magic Metal Productions
            http://TheMagicM.com
            * Web developer/designer
            * E-commerce and Miva
            * Author, The Official Miva Web Scripting Book -- available on-line:
            http://www.amazon.com/exec/obidos/IS...icmetalproducA

            Comment


            • Thanks Kent, I'm sorry but I have a couple more questions if you don't mind...

              In the Specific Sale Price module, at the top of the DiscountModule_Discount_Items() function, the first few lines use variables that don't seem to be defined anywhere:
              l.items
              l.eligibile_products
              l.salepricing
              In my script these variables are both empty, so the foreach loop that tries to iterate through l.items does nothing. How can I define these?

              Comment


              • Maybe you're used to working with programming languages where the function parameters are all read-only: they pass values into the function, but the function can't modify them. In Miva Script, a function parameter can be a reference, instead of just a value; the function body can modify it, and the caller can work with the changed value when the function exits. When you see the keyword "var" in a function's PARAMETERS attribute, that declares it to be a read-write parameter.

                The DiscountState_Eligible_Items() function scans the discount_state variable, and puts a list of eligible BasketItems into your local variable l.items (which might have been better named l.eligible_items). Similarly, DiscountState_Eligible_Products() gets you some info about the products assigned to those BasketItems, and puts it in the variable l.eligible_products. My modules always use those two function calls as shown in the LSK. Then my custom code works with the data retrieved by those two calls to calculate a new price and write it back into l.discount_state.
                Kent Multer
                Magic Metal Productions
                http://TheMagicM.com
                * Web developer/designer
                * E-commerce and Miva
                * Author, The Official Miva Web Scripting Book -- available on-line:
                http://www.amazon.com/exec/obidos/IS...icmetalproducA

                Comment


                • Thanks Kent, I think I understand.. So this line:

                  Code:
                  <mvAssign name="l.item_count" value="{ [ g.Module_Feature_PGR_UT ].DiscountState_Eligible_Items( l.discount_state, l.items ) }">
                  actually defines two variables for us - l.item_count and l.items, right? And in my case, if l.items is empty after that, it means there are no eligible items for one reason or another? Weird because I thought I had the price group set as "All Shoppers" but I'll have to take a closer look.

                  I couldn't find any particularly useful documentation on DiscountState_Eligible_Items except for this page: http://docs.miva.com/api-functions/D...Eligible_Items

                  Comment


                  • Got it! I'd forgotten to go into the Product Page and assign the item to the price group. Once I did that it worked right away.

                    My code is still modifying the basket directly, have to make some changes, but this is a step in the right direction

                    Comment


                    • Hey, good news! And to answer your question, yes, that line of code returns two results at the same time: one in the return value, and another into a "var" function parameter. It takes a little getting used to, but it does let you write tighter code.
                      Kent Multer
                      Magic Metal Productions
                      http://TheMagicM.com
                      * Web developer/designer
                      * E-commerce and Miva
                      * Author, The Official Miva Web Scripting Book -- available on-line:
                      http://www.amazon.com/exec/obidos/IS...icmetalproducA

                      Comment


                      • Thanks again Kent, I understand. Everything is working just about the way I want it too, with the discount being applied correctly, but Miva still shows the old item price. The total is correct, but the price per piece is unchanged. Looking around for a way to change that too

                        Comment

                        Working...
                        X