Andy Xu's weblog: Commerce Server, .net and more

  • The way to go for Commerce Server pipeline troubleshooting

    This happens from time to time: I received questions from Commerce Server community, asking about what is going wrong in the pipeline?

    (some top questions include: Why my discounts do not apply? Why my basket pipeline can't execute? Why this advertisement shows up instead of the other, the one I want to show?)

    And usually along with the question, the pipeline log file is attached.

    However, the pipeline log file, sometimes, has very limited help. I would like to recommend a much more, way more, powerful troubleshooting tool: XmlTracer, which is avaialble to download in Commerce Server official website.

    It may require some time to get used to this tool, you know, configure it (basically, it requires you to insert the XmlTracer component in the questionable location in the pipeline, save the pipeline, restart the IIS and run a couple of batch files to generate the log). But I can almost promise you that if you are bothered by pipeline, every second you spend learning the tool really worths it.

    Let me know if you have any trouble using this troubleshooting tool. And if you want me to write some examples about how to use it to track down some problems.

  • The search engine FACEOFF

    Still think google has the best search engine in the world? How does it stack against Yahoo!, or the new version MSN search? Try those links out and (most importantly) see what search engine works out best for you. (yeah, it's kind of like the Progressive insurance idea)

     

    http://www.addysanto.com/dualsearch.htm

    http://www.yagoohoogle.com/

     

  • I am back, baby.I am back!

    It has been quite a while since my last blog (almost 8 months, I guess). Between now and then, a team has broken the curse and finally won a championship; an election has finshed with no president change; a cute boy has turned 3-year old (that would be my son); a beautiful lady has quitted MSFT and started her pursue as a law professor, or maybe a lawyer (that would be my wife). 

    And for me, I actually changed to another product team within Microsoft. Now, I am an outsider to Commerce Server. The thing I missed most? some smart, sharp people. As a matter of fact, the "Mr. guru", David Messner, is really one the best, most solid developers I've ever worked with. I still enjoyed the discussion with him about the discount engine algorithm.

    Not surprisingly, I worked with another group of smart folks in the new team (after all, it's Microsoft). But surprisingly, IMO, my new position gives me a better perspecitve to look at Commerce Server. Now I can spend more time looking at .net framework, the SOA, Biztalk and Commerce Server. And I find it interesting to look at Commerce Server product and think about how it fits in the whole picture of MSFT's offering for enterprise software solutions. So I will still focus my blogging on Commerce Server a lot. But meanwhile, adding other stuff I've mentioned above.

    It's nice to be back and let me whether I can keep it up or take another long break before my boy's 4th birthday party.

  • Extend Commerce Server 2002 discount functionality, Part 1 (tiered discount)

    Why needs to extend

     

    Commerce Server 2002 provides a powerful discount engine. It can process basket line item level discount, order level discount, dollar off or percentage off discount and multiple discount interactions (for example, same basket item can be awarded by two or more different discounts). As powerful as it is, the design goal of discount engine is to supply a general useful functional component. So when it comes to each real business scenario, it is possible and necessary for developers to extend the CS2002 discount engine to build their own solutions for special requirements.

     

    After seeing and trying to use variety of discounts in real world, I find there are certain types of discounts which are not rare but requiring customized work on top of Commerce Server 2002. (isn’t that one of the cool things of working in Commerce Server team -- You really get chance to think about some everyday issues from different perspective?) I have my own solutions for those scenarios and I want to share them here to get your thoughts and feedbacks. Hey, your solution is probably different and more importantly, better. In that case, why not also share yours as well?

     

    Extension 1: implementing tiered discount

     

    A typical tiered discount is using the same condition but giving out different award based on different purchase amount. So an real world example would be:

     

    Discount to sell CDs, get 5% off if buying over 10 CDs, get 2% off if buying 5 to 10 CDs, get 1% off if buying less than 5 CDs.

     

    Before we get into my solution, let me mention a little bit about Commerce Server 2002 discount. In Commerce Server 2002, discount is in a fixed format. In you have been using bizdesk or Feature Pack 1 discount manager, you know what I am talking about: Most basically and importantly, a discount has 3 parts: Condition, Award and Offer. A discount may look like:

    Buy some product A,   Get some other product B,   at something ($ or % or free) off

    |ß-----condition-à|  |ß-------- award ------à|  |ß------- offer ----------------à|

     

    Of course, there are other (more advanced) parts of discounts, like eligibility requirements, priority, interaction policies, basket display and for new released feature pack 1, the coupon (promotion) code.

     

    So as you can see, classic commerce server 2002 discount is not an out-of-box solution for tiered discount, which requires the same condition product (CD) but different offer and condition amount.

     

    My solution is to create one discount for each tier and use discount priority to achieve the order the applied discount and finally use interaction policy to make sure only one tier discount is applied.

     

    For example, in the above case (discount to sell CDs), I will create three discounts because of there are three tiers: <5, 5 to 10, >10. Please note since Commerce Server 2002 discount doesn’t take a range (5 to 10) as purchase condition amount, we need to specify the minimal value in the range instead. My three discounts are:

     

    D1: (for tier: over 10)     Buy 11 CDs, get unlimited CDs, at 5% off

    D2: (for tier: 5 to 10)      Buy 5 CDs, get unlimited CDs, at 2% off

    D3: (for tier: less than 5) Buy 1 CD, get unlimited CDs, at 1% off.

     

    You may notice that I put the tier with most purchase amount first. That’s actually the discount priorities we should assign: D1 > D2 > D3 (in bizdesk, the lower the priority number, the higher the priority. So the value is bizdesk in fact should be D1 < D2 < D3). The reason D1 should have higher priority than D2 and D2 should be higher than D3 is because “more exclusive first”. When purchase amount meets D1 condition, it should also meet D2 and D3’s conditions but in that case, we want discount D1 to be applied. Only when D1 or D2 can’t be applied (at this moment, the purchase amount must be less than 5), D3 will be applied.

     

    And relationship between tiers is exclusive – at one time, only one tier discount can be applied. So we need to set higher prioritized discount’s interaction policy to be exclusive: Condition can not be reused as other discounts’ condition or award; award can not be reused as other discounts’ condition or award. Fortunately, those are the default values and we don’t have to modify anything.

     

    One last piece is what we call “disjoint flag”. That is within each discount, we want discount to be applied to condition items as well. For example, shopper adds 12 CDs to his basket, the first 11 CDs will be used as discount D1’s condition and we want the award to be applied not only to the other 1 CD but the condition items, the 11 CDs as well. To accomplish that, in bizdesk, discount definition section, check “Apply offer on both Get and Buy products” box. In feature pack 1 discount manager, discount properties window, check “Allow award to apply to the discount condition items” box.

     

    In feature pack 1, we do add coupon functionality, if it is wanted to add a coupon definition to this tiered discount, it is a good practice to let all discounts for different tiers share the same coupon definition. – It makes a consistent user experience for shoppers.

     

    Drawback of the solution above is extra maintenance cost. Instead of one discount (if Commerce Server 2002 provides an out-of-box solution), we have N discounts (let’s assume N is the number of tiers). It probably doesn’t make sense to remove one or parts of tiers in most cases. So as a developer, you have to ask business manager to treat all of N discounts as a whole – Active/deactive/remove/modify start, end time for all of them. Of course, you can also create some other pieces of customized codes to help the maintenance.

  • Display the applied discounts in shopper's basket in Commerce Server 2002

    Discount basket display field and How to create it

      In commerce server discount engine, if a discount is applied in shopper’s basket, you can retrieve a friendly message of that discount from OrderForm and display it to shopper. The friendly message is what we call the “basket display” field for a discount.

      How to create a basket display? if you are using Commerce Server 2002 bizdesk,  then go to campaign manager module, new discount window, in “Discount Display” section, there is a “Basket display” input for this field. (Please note, the image URL, click URL and Alternate text are for discount targeting, so-called “CSF”. They are nothing to do with OrderForm display).

      If you are using recently shipped Feature pack 1, from Discount Manager UI, there is a new discount wizard. “Basket display” input field is in the “Discount Properties” dialog. Gosh, I wish I know how to insert a picture to the blog post (doubt whether it is feasible). It will save a thousand words.

      Anyway, if you are interested in where exactly the basket display message is store, it is in Campaigns database (if using FP1, it is in Marketing database), order_discount table (mktg_order_discount table for FP1), u_disc_description column (u_disc_basketdisplay column for FP1). Since for both commerce server 2002 and FP1, the basket display are mandatory input, you should not see a null value in that column.

     

    Display correct discount messages in basket

      Now the more interesting topic, from commerce server runtime, how do we display the applied discounts’ messages?  Before Feature pack 1, we need to use both the Content list in OrderForm and discounts_applied Dictionary in each basket line item.

      Data in ContentList in shopper’s OrderForm (orderform._discounts) are actually the discount data copied from runtime discount cache. In you are using commerce server BCL, you can use Microsoft.CommerceServer.Runtime.Orders.DiscountsApplied property. This property is generated by taking the discount ContentList and filtering by all applied discounts in the OrderForm (orderform._winners). In another word, those are data for applied discounts only.

       item.discounts_applied is a Dictionary containing all discounts applied to the specific basket line items. The key for the dictionary is the discount’s campaign item ID and value is the DateTime the discount getting applied.

      In fact, recently we identify an issue in commerce server retail 2002 site (shipped as SDK). This known issue is related to how to display the applied discount messages. I wrote a separate blog for that. That blog article includes the pseudo code to show basket display and the fix to the issue. Check it out if you are interested.

     

    New way to display discounts in Feature pack 1

       In Commerce Server 2002 feature pack 1, we add a new feature to make this work, displaying applied discounts’ messages, a little bit easier. (The old approach still works though).

     

       For each basket line item in OrderForm, we define two SimpleLists. One is for all applied item level discounts, _itemlevel_discounts_applied. The other is for all applied order level discounts, _orderlevel_discounts_applied. Each element (which is a Dictionary) in the SimpleLists is for one specific, individual applied discount. Those two SimpleLists are in Commerce Server 2002 (without FP1) as well. You can refer to one of my previous blog articles for how to retrieve useful discount information from those SimpleLists.

     

       Now FP1 adds one new entry to each element, a.k.a., the Dictionary, of those SimpleLists. The entry’s key is discount_basket_display and the value is the friendly basket display message of the discount.

     

       So instead of going through ContentList and item.discounts_applied, you can use those two SimpleLists to display the discount messages. A sample code looks like (in VB):

     

    Dim currentUserID As New System.Guid(CommerceContext.Current.UserID)

    Dim cart As Microsoft.CommerceServer.Runtime.Orders.Basket

    Dim cartOrderForm As Microsoft.CommerceServer.Runtime.Orders.OrderForm

    Dim cartLineItem As Microsoft.CommerceServer.Runtime.Orders.LineItem

    Dim pipeInfo As Microsoft.CommerceServer.Runtime.Orders.PipelineInfo

    Dim discountAppliedRecords As  Microsoft.CommerceServer.Runtime.ISimpleList

    Dim discountAppliedRecord As  Microsoft.CommerceServer.Runtime.IDictionary

     

    Dim itemDiscountMessage As String

     

    ‘ get the basket

    cart = CommerceContext.Current.OrderSystem.GetBasket(currentUserID)

     

    ‘ get the default OrderForm

    cartOrderForm = cart.OrderForms(“default”)

     

    ‘ Run basket pipeline here, you probably need to extend your own code

    ‘ here, to set UserProfile and TargetingContext profile. And also your

    ‘ own exception handling code

     

    pipeInfo = new PipelineInfo(“basket”)

    cart.RunPipeline(pipeInfo)

     

     

     

    ‘ how to display applied discount messages. This is our focus here

     

    For Each cartLineItem In cartOrderForm.LineItems

     

                itemDiscountMessage = “”

     

    ' retrieve information about all applied item level discounts

    If Not (cartLineItem.Item("_itemlevel_discounts_applied") Is System.DBNull.Value) Then

    discountAppliedRecords = CType(cartLineItem.Item("_itemlevel_discounts_applied"), ISimpleList)

    For Each discountAppliedRecord In discountAppliedRecords

    itemDiscountMessage = itemDiscountMessage + CType(discountAppliedRecord.Value("discount_basket_display"), String) + "<BR>"

    Next

    End If

     

    ' retrieve information about all applied order leve discounts

    If Not (cartLineItem.Item("_orderlevel_discounts_applied") Is System.DBNull.Value) Then

    discountAppliedRecords = CType(cartLineItem.Item("_orderlevel_discounts_applied"), ISimpleList)

    For Each discountAppliedRecord In discountAppliedRecords

    itemDiscountMessage = itemDiscountMessage + CType(discountAppliedRecord.Value("discount_basket_display"), String) + "<BR>"

    Next

    End If

     

    ‘ discount_message entry contains basket displays for all discounts (item level

    ‘ and order level) applied to this basket line item

     

    cartLineItem.Item("_discounts_message") = itemDiscountMessage

    Next

  • A known issue in Commerce Server 2002 SDK: retail 2002 site about applied discount display

    Thanks to one of our commerce server community developers, Ravi, Shankar, we found out an issue in retail 2002 site (shipped as part of Commerce Server 2002). This issue is related to how to display the applied discount in shopping cart page. If you are using Retail 2002, or building your commerce application based on retail 2002, please make sure the problem is fixed on your sites so that shoppers won't get wrong impressions about applied discounts.

     

    The Retail 2002 site's approach to display applied discounts

    In Commerce Server 2002, OrderForm contains a content list, which has information, including discount's basket display message, about every active discount (as a matter of fact, the content list is loaded from runtime discount cache). And after basket pipeline is executed, the applicable discounts will be applied to OrderForm. For each basket line item in OrderForm, we store discount applied information in a Dictionary called (item.)discounts_applied. Each entry in this discounts_applied Dictionary is for each individual discount which is applied to this basket line item. The key of the entry is the campaign item ID (discount is a special type of campaign item) and the value is the DateTime that this discount is being applied.

    So Retail 2002 is using such an algorithm to display applied discounts to each basket line, which I explain below in pseudo-code.

    step                 action

    0    Create a ContentItemCollection containing all applied discounts data from ContentLit (represented by OrderForm.DiscountsApplied in Commerce Server BCL)

    1   For each line item in OrderForm

    2           if (item.discounts_applied is not NULL)

    3                     // item.discounts_applied is a IDictionary

    4                     For each entry in item.discounts_applied

    5                                  Get the key of this entry, let's say X,  which is the campaign item ID.

    6                                  // look for matched discount in ContentItemCollection

    7                                 For each entry in OrderForm.DiscountsApplied (mentioned above)

    8                                          If this entry's campaign item ID equals to X (key of discounts_applied entry)

    9                                                   Output this discount's basket display message

    10                                         End if

    11                                Next

    12                    Next

    13          end if

    14   Next

     

    The issue and the fix

    Unfortunately, Retail 2002 did one thing wrong, in the above pseudocode line 8, it should compare the campaign item ID from content list with campaign item ID from item.discounts_applied Dictionary. But instead of doing that, it uses the campaign ID from the content list.

    The result, it is possible that some discounts applied to a basket line item may not be shown to shoppers and more unlikely (still possible) some discounts applied to other line items, are shown to this line item.  However, to make it clear, it's only related to discount display. Still the correct discounts will be applied and correct price after discounts will be calculated.

    The fix, actually very easy, in controls\transactions\Cart.ascx.vb, there is a funtion defined called

    Sub ApplyDiscountMessagesIntoLineitems(ByRef cartDiscounts As ContentItemCollection)

    If you haven't changed any code in the file, go to line 240 (otherwise, look inside the function, you should find the line faily easy). it needs to be changed from
            If CType(contentItem.Item("campaign_id"), String) = campaignID Then  

    To
           If CType(contentItem.Item("item_id"), String) = campaignID Then  

     

    So now we are using campign item ID instead of campaign ID to do the comparison. Of course, you may find out the variable name is not exactly good -- it uses campaignID here, should be changed to campaignItemID as well. But that should not affect the logic.

     

  • Coupon functionality provided by Commerce Server 2002 Feature Pack 1 (Part 2)

    You can read coupon function Part 1 here.

    Enable coupon functionality in Commerce Server runtime

    Commerce Server uses pipeline infrastructure to orgnize runtime components. Feature pack 1 delivers three new components for coupon functionalities. To enable coupon in runtime, you need to do following modifications:

    • modify basket pipeline (or whatever pipeline in your site having the similar function), add ReservePromoCodes component, make sure to place it before OrderDiscount and OrderLevelDiscountApply components. Add RecordPromoCodes component and place it after OrderDiscount and OrderLevelDiscountApply
    • modify checkout pipeline (or whatever pipeline in your site having the similar function), add RedeemPromoCodes component.
    • change site discount cache configuration to load discount data from Marketing database. Remember, the coupon data, as part of new things introduced by FP1, only reside in marketing database. So unless you change the discount cache loader to load from new marketing database, the coupon function won't work. To do that, you need to update web.config, <caches> section, change discounts cache type to “MarketingDiscounts” 

    Of course, it is necessary to make some changes in your site codes as well (basically to get the shoppers input of coupon codes and add those values to OrderForm). For a detailed sample, you can refer to up-to-date commerce server documentation shipped with FP1, inside Developer's Guide -> Developer Concepts and Tasks -> Marketing System -> Promotion Codes -> Implementing Promotion Codes 

     

    Coupon reservation

    When a shopper uses a coupon, under the hook, the coupon code goes through an input -> validated (and discount applied) -> Redeemed (when basket is checked out) process. However, when the coupon code's available usage limit is under a certain threshold, the validated coupon will be reserved and the coupon will get into a reserved status before the redemption.

    What is available usage limit? In part 1 I discussed the usage limit for coupon code.  Actually, in the marketing system, we definition another two counters in addtion to usage limit. One is coupon's usedcount. It starts from zero. Whenever a coupon is redeemed during checkout, the usedcount will increase by one. The other counter is reserve count. It starts from zero also and only when a coupon gets into reserved mode, the reserved count increases by one. The available usage limit = usage limit - (usedcount + reserve count). And under no circumstance, the available usage limit should be below zero. Otherwise, the coupon will be overused. 

    When available usage limit is under a configured threshold -- the threshold is defined as one property in marketing resource. Open commerce server manager, expand marketing resource and you can find a property for “Promocode reservation threshold“ and the default value is 100. So for a specific coupon code, when there are less than 100 (or whatever threshold value you set) times it can be used, each specific shopper input will get a reservation.  This will prevent concurrency scenario which will overuse the coupon (imagine 101 users come in, all input the valid public coupon and all the inputs get validated and redeemed -- the usedcount will be bigger than the usage limt).

    Oh, one last thing about the counters (you probably already figured it out): when a coupon code is changed from reserved mode to redeemed mode, the counters are changed: reserved count decreases by one (it is not reserved any longer) and usedcount increases by one (it is redeemed).

     

    Cancel expired coupon reservation task

    Let's say, a coupon is entering reservation mode (available usage limit < threshold). Now a shopper inputs the coupon and gets a reservation. This will actually takes away a future usage of this coupon. So we have to, after a certian condition, release this reservation. For example, shopper enters the coupon but doesn't check out and he/she leaves lthe shopping cart for there forever -- the commerce server 2002 FP1 provides you a way to cancel the coupon reservation, if it has been idled over a specific period of time.

    Like the reservation threshold introduced above, the reservation expiration time is also part of marketing resource. Expand the marketing resource, you can find a property named “Promocode reservation expiration time“. The default vaue is 30 minutes.

    The tool to release reservation is a program called ExpirePromoCodeReservation.exe, under <commerce_server_root_directory>\FP1\. The best practice is to configure a windows scheduled task to run this program to automate the process. Details about how to configure is in Commerce Server FP1 documentation, under “Administering your site“ topic.

    One last thing about this ExpirePromoCodeReservation.exe program. It accesses marketing database to cancel the reservation. So from security standpoint, it is good practice to grant only the minimal required permission to the identity running this program. That is, the mktg_promoCodeExpirationTask_role, which is pre-defined in marketing database.

     

    Retrieve coupon information from OrderForm

    In a previous blog post,  I talked about how to retrieve the useful information about discount applied record. Same approach can be used to parse OrderForm and get coupon status.

    • OrderForm.promo_codes

                 A SimpleList of string, this is intended to keep the input coupon codes (site code should set this SimpleList)

    • OrderForm.promo_user_identity

                A string other than OrderForm.user_id to validate user identification for restricted coupon (which is introduced in part 1)

    • OrderForm.promo_code_info

                This is the majority information of coupons after running the basket pipeline. It is a SimpleList and each element is a Dictionary, containing information about each coupon. They are:

             name                                 type                  description

         promo_code                         string                 the coupon code

         promo_code_defintion_id     int                     promo code definition ID

         dt_promo_code_lookup       datetime            The timestamp when coupon was validated and/or reserved

         promo_code_reserved         bool                  whether the coupon is reserved or not

         promo_applied                    bool                  only when coupon is redeemed, it is true

         promo_code_status              int                     0 = OK (valid and/or reserved if reservation starts)

                                                                              1 = Invalid coupon code

                                                                              2 = coupon code's usage limit is reached

                                                                              3 = coupon is valid but related discount is expired

                                                                              4 = for restricted coupon, identity mismatch

    • (item)._itemlevel_discounts_applied and (item)._orderlevel_discount_applied.

             I introduced those two SimpleLists in previous blog about discount applied records. Now, with the coupon components, we add two more keys to each element (which is a Dictionary) in the SimpleLists. They are:

          name                            type        description

          promocode_defn_id     int           if using coupon makes the discount applied, this is the coupon definition ID

          promo_code               string        if using coupon makes the discount applied, this is the coupon code

     

  • Coupon (Promotion code) functionality provided by Commerce Server 2002 Feature Pack 1

    Coupons in Commerce Server history (or the lack of it)

    One major piece added in Commerce Server 2002 FP1 is Coupon/Promotion Code functionality in marketing system. Before FP1, you can only use so-called "automatically applied discount", meaning as long as shopper's basket contains item(s) or order meeting the discount condition and can be taken price off the awarded item(s), the discount will (automatically) be applied.

    In real world, online business usually requires another level of validation of the discounts -- a "secret" code which needs to be input correctly to allow the discount to be applied. Like I said, before FP1, Commerce Server doesn't provide out-of-box solution. Quite often we've seen developers extend the campaign system one way or the other to implement coupon function. Most popular way seems to take advantages of targeting context to set the user input coupon code and use bizdesk to create discount eligibility requirement to specific coupon residing in the targeting context. The drawback of this solution: when the coupon code is per user base, (meaning different shopper knows different code and more than one code are valid for same discount.) It is a headache, or maybe even impossible thing to manage using eliglibility requirement.

    Three coupon types

    To help you to choose the correct coupon function in FP1, I need to introduce the three type of coupons first.

    Public coupon, the scenario is, basically, the coupon is known in public. In another word, all shoppers coming to the site share the same code to get the discount. The number of coupon code is 1.

    Private coupon, the scenaio is that the online business generates many coupon codes and sends them to targeted users respectively. The target users, knowing their codes, can forward the codes to their friends and their friends can use their codes as well. So from the marketing system point of view, many coupon codes point to same discount but using each code doesn't require an identity check in runtime.

    Restricted coupon, similar to private coupon, different codes are sent to different targeted users but only the targeted users themselves can use their respective codes. That is, when coupons are generated, each of them is associated with a targeted identity and in runtime, an identity check will happen and only the associated identity can use the code to get the discount.

    Coupon creation

    From the new winform Discount Manager, you can create all three types of coupons. Creating public coupon is easy -- just need to specify the one and only, all well-known code. However, creating private and/or restricted coupon requires go through a new coupon generation service (COM+ component). The service itself is created and configured during Feature Pack 1 installation. Make sure the identity you configure to run coupon generation service have enough permission in your marketing database -- It requires at least being granted mktg_promoCodeGenerator_role (and in order to protect your system, please don't grant other unnecessary database roles).

    Why using a generation service, you may ask. Well, the most significant reason is that enables an asynchornized implementation so if you want to create a large number of coupons, for example, one million codes (and yes, we do test one million codes generation. so feel free to do it.), you can start configure the generation from UI and click the button and the UI control is right back to you so you can do other discount management work while the backend is generating coupons at the same time. Also, this approach helps to make sure the data integrity (no duplicate codes generated), scalability and fault-tolerant ability (fail-over even a SQL server reboot during code generation).

    Coupon usage limit

    When you generate coupon using Discount Manager, you can control the number of times a code can be used by setting the usage limit. So setting the usage limit to 1000 means the specific code can be used for up to 1000 times and setting it to 0 means the unlimited usage. Pretty straightforward.

    However, please note the usage limit has a different impact on public coupons compared with other coupons. Since a public coupon can have only one code, so the usage limit is for everyone using this coupon. For example, a public coupon "ABC123" has a usage limit as 1000, everybody comes to the site can use it and no matter who uses it, the avaiable usage count will keep decreasing. Private and restricted coupons, on the other hand, have many codes and each code has that usage limit specified. Another example, a site has 1 million registered user, we can create a restricted coupon, which has 1 million different codes, each code is sent to a different user and usage limit is 1000. So shopper A logs in and can use his code up to 1000 times and it won't affect number of coupon shopper B can use (since B has a differnt code).

    So here you go, a new out-of-box solution for coupon code. Hope you can choose the correct type of coupon to fit your business need and add more flexibility in your merchandizing system. And we welcome your comments/feedback, espeically any unaddressed business needs.

  • Commerce Server Feature pack 1 -- what is new in marketing resource

    I spent a good, quality week in Daytona beach, Florida. Nice place, nice people, nice beach. What's not to like? Now I am back to work: let's be honest, how can I get into the work mood? -- How about the release of feature pack 1, something to cheer for about several months hard work. Just like everyone else in the group, I am so excited about the release and anxious to hear from you guys for feedbacks about FP1.

    We really packaged some cool stuff this time. As you will probably find out soon, a new-designed, much painless UI replacement for bizdesk, a nice stagging solution for enterprise scenarios and an out-of-box solution for coupon (promotion code), to name a few. However, just like everything else, while you enjoy the new features, chances are there will be some issues bothering you. Let's talk about some potential issues you may face relating to a key addup in FP1, the marketing resource.

    Marketing resource is designed to hold new discount business data (including customers, campaigns, discounts, expressions and coupons) in feature pack 1. By using marketing resource, you will have a much easier time to manage your discount data by using the Discount Manager, a windows form application included in FP1. It is not only a better look-and-feel UI tool, it also gives you system better security protection and much better performance when multiple users concurrently access the system. Using marketing resource, you also will be able to enjoy the coupon functionality -- we acutally provide three different types of coupons: public coupons, which are shared among lots of different users, private coupons, which can be sent to individual user and is allowed for the receiver to share with his/her friends and restricted coupons, which will be sent to specific individuals and only who receive the coupons can use them.

    If you are kind of familiar with Commerce Server 2002 campaign system, you may have the question that we have another discount system in campaign resource, so are we duplicating the discounts? Good observation. with feature pack installed, it is possible that you will have one set of discounts in campaign database and another set of data in marketing. The reason? we want our customers to start using marketing system instead of the campaign system for the advantage I mentioned above (so it somehow can be regarded as an upgrade). However, if you want to stick your discounts in campaign resource, you still can. So the choice is yours.

    That being said, you may ask, what am I supposed to do with discounts? Ok, hopefully I can walk you through some typical scenarios. First of all, you need to install Feature pack 1. And now ask yourself, do you want to use marketing system (refered to the advantaged I mentioned). If the answer is yes, you can find a pup file called FP1.pup under FP1\Pup Packages directory. Open that file, choose to add marketing resource to your existing commerce site. (after marketing resource is added, you may want to open the FP1.pup file again to add MarketingWebService and CatalogWebService apps.)

    Ok, now you have the marketing resource, but if you already have discount data in your existing site, they are in campaign system. So you need to run feature pack 1 discount migration tool (you can refer to feature pack documentation, which locates under Documentation directory) to migrate the discount data from campaign to marketing.

    After this step is done, when you are using discount manager (the windows form app I mentioned above), you will find out the existing discounts are migrated and can be managed by your new UI tool. In fact, at this moment, under the hood, discount data exist in both place, campaign system and marketing system. So there is an important step you need to do -- to tell your runtime production site that which discounts you want to use. (given we spend coupon of steps to reach here, I assume we want to use discounts from marketing resource, right? :-)) To do that, you need to edit the runtime site web.config, look for the <caches> section, you will find your existing discount cache is defined like this:
     <cache name="Discounts" type="Discounts" refreshInterval="0" retryInterval="60"/>

    Now for discounts in marketing resource, we actually use another type of discount cache, named "MarketingDiscounts". So if you change the above configuration to:
     <cache name="Discounts" type="MarketingDiscounts" refreshInterval="0" retryInterval="60"/>

    The runtime site will load the discounts from marketing resource. Otherwise, it will still load from campaign resource. (in another word, any change you made using new Discount Manager UI will not take into effect unless you change the discount cache type).

    Another thing you may notice is that we are only talking about discount data here. Not advertisements. You are right again. For advertisement data, they are still only in one place, the campaign system. We plan to give you choice to move them to marketing resource as well (so that you can use the new UI tool instead of bizdesk to manage advertisements) in next release.

    Finally, one more reason you may want to upgrade your discounts to marketing resource: in Commerce Server 2002, discounts are in campaign resource, and the expressions that discounts refer to are in a different resource, profile resource. So it is impossible to set up a foreign key relationship. Which mean, an example of bad thing, you use bizdesk to create an expression called "books" and create a discount which is "$5 off books purchase". Then you may accidently delete the "books" expressions and the bizdesk won't complain but your discount, in fact, won't work correctly. In feature pack 1, we move both discounts data and expressions data to marketing database and yes, foreign key relationship is established. So using new UI, the same data integrity problem won't happen.

    That will do for today. Again, I strong suggest you try out the feature pack if it sounds like fitting your scenario. and feel free to talk with us (in newsgroup or blog or whatever else) about your experiences of using FP1. We are definitely looking forward to hearing from you.

  • Get useful information about discount applied record from OrderForm

    Commerce Server 2002 provides a rather powerful discount engine. In addition to simple scenario where only one discount applies, it also supports features like multiple discounts applying to same Order (even same basket line item), distributing order level discounts to each lineitem.

    When those complicated cases happen, sometimes it is a headache to find out the detailed record of applied discounts. (For example, trying to answer the question that how much money does discount X cause the customer to save when customer returns the products.)  CS2002 discount engine writes detailed info into strong type data structures in OrderForm. From the questions i get from newsgroup, it doesn't look like those info has been well understood, not to mention ultized by the community. Let's talk about it this time.

    1) (item.)_itemlevel_discounts_applied. For each basket line item, if there is any line item level discount applied, you can find a SimpleList value in the line item Dictionary (key is _itemlevel_discounts_applied) and it contains detailed info about all the applied line item discounts. Each element in the SimpleList is a Dictionary and it is for each distinct discount applied to this item. For each Dictionary, following entries are interesting, (I list them by key -- type -- description)

              discount_id                 VT_I4            Campaign item ID

              discount_priority          VT_I4            discount priority (the smaller the value, the higher the priority)

              discount_timestamp     VT_DATE      last-modified timestamp of the discount

              cy_discount_amount    VT_CY          how much was actually taken off of the line item by this discount

              discount_type              VT_I4            1 means it is a currency value discount.  2 means a percentage discount

              cy_discount_value        VT_CY          Currency or percentage value of this discount

              discount_name            VT_BSTR       Discount name

     

    Let's say, if after running the basket pipeline, we want to calculate how much money a specific discount, X (whose ID, let's assume, is 1), has taken off from the OrderForm, we can run following site code (written in vb).

     

            Dim cartOrderForm As OrderForm
            Dim cartLineItem As LineItem
            Dim discountApplicationRecords As ISimpleList
            Dim discountApplicationRecord As IDictionary
            Dim campaignItemID As Integer
            Dim discountAmount As Decimal

     

            ' assume basket pipeline is executed and we get the OrderForm in variable cartOrderForm

     

            discountAmount = 0
            For Each cartLineItem In cartOrderForm.LineItems
                If Not (cartLineItem.Item("_itemlevel_discounts_applied") Is System.DBNull.Value) Then

                    discountApplicationRecords = CType(cartLineItem.Item("_itemlevel_discounts_applied"), ISimpleList)

                    For Each discountApplicationRecord In discountApplicationRecords
                          campaignItemID = CType(discountApplicationRecord.Value("discount_id"), Integer)

                          If campaignItemID = 1 Then
                               discountAmount += CType(discountApplicationRecord.Value("cy_discount_amount"), Decimal)
                          End If

                    Next
                End If
            Next

     

            '  now discountAmount contains the value of the money amount taken off from the OrderForm by discount 1.

     

    2) (item.)_orderlevel_discounts_applied. Similar to _itemlevel_discounts_applied, this SimpleList records the order level discounts applied against this line item. (remember, Commerce Server 2002 discontributes the order subtotal discount to each line items. So a $20 off order subtotal discount can possibly to $15 off the first item and $5 off the second item). The breakdown of simliar entries in each Dictionary (for each order level discount) in this SimpleList.

     

              discount_id                 VT_I4            Campaign item ID

              discount_priority          VT_I4            discount priority (the smaller the value, the higher the priority)

              discount_timestamp     VT_DATE      last-modified timestamp of the discount

              cy_discount_amount    VT_CY          how much was actually taken off of the line item by this discount

              discount_type              VT_I4            1 means it is a currency value discount.  2 means a percentage discount

              cy_discount_value        VT_CY          Currency or percentage value of this discount

              discount_name            VT_BSTR       Discount name

     

    3) (orderform.)_discounts_trace_info: this entry contains helpful trace information about how discounts are applied to the OrderForm (a reminder: if you enable multiple discounts apply to same item, the scenario can be complicated). the trace info will be enabled only when the Context dictionary's _trace_discounts is set to true before running the basket pipeline. So in your production site, you can turn it off to improve performance. Commerce Server .net API provides a simple way to access Context Dictionary, which is, by PipelineInfo class. Here is a code snippet to enable the trace and run basket pipeline (C# code):

            Private Basket basket;

            // set up user's Basket

            PipelineInfo pipeInfo = new PipelineInfo(“Basket“);
            pipeInfo["_trace_discount"] = true;

            basket.RunPipeline(pipeInfo);

    Ok, I guess that's it for today. There are still quite a few useful info from OrderForm we can discuss. I will take a one week vacation to take my kid to Florida beach (his first trip to beach, going to be a good one). And till next time, have a good one.

     

    Thanks,

    -- Andy

     

  • Hello, (blog) world

    yet another new comer to the blog world, let me introduce myself a little bit. My name is Andy Xu, if you have confidence in your Chinese speaking ability, try my Chinese first name, Yuxiang. I worked in Microsoft Commerce Server group as a software engieer. Most of my work focus on the campaign/targeting area. I'd like to use this blogging opportunity to discuss with you about any topic related to commerce server product, and your feedback/opinion/comments on our product is very welcome.

    Other than work, I am a sports fan (that is, IF my two year old son would leave any free time for me). I got my graduated school degree from Johns Hopkins University in Baltimore, MD, which is the first place I visited in US. So it comes no surprise that Orioles and Ravens are my favoriate sports teams nowadays. --- Just want to say, thanks god that baseball season begins and for the first time in about 6 years, Orioles show some promise to be a contender again.

    All right, so much for the sports. Like I said above, I am looking forward to talking about commerce server topics with you here. Enjoy.

    -- Andy

This Blog

Syndication

Tags

No tags have been created or used yet.

News

    These postings are provided "AS IS" with no warranties, and confer no rights.
    Use of included script and code samples are subject to the terms specified here.

© 2008 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker