Automatic discount based on customer discount-level with set amounts per product

I figured it out.

In the Actions to update Ticket State and Order State, I was using a variable named [:State], which I assume is Reserved. I’ve changed the action variables to [:TState] and [:OState], respectively, and it is behaving normally now.

1 Like

@emre, any chance we can get access to Order State and/or Order Tag inside Ticket State Changed Event?

I store either VIP or HH inside {ORDER STATE:DiscountType}.
When Ticket Entity is removed or changed (non-VIP), the Ticket State is updated to null or InActive, and it fires Actions to update Order State. I’m trying to prevent the removal of an HH Order State, and/or the replacement of an HH Order State with a VIP Order State.
As I watch the cycling through the past Orders, I realized that neither {ORDER STATE:DiscountType} nor {ORDER TAG:HH Discount} are available in the Ticket State Changed Event.

Umm @QMcKay I think I understand how it comes to that point. Unfortunately we can’t access {ORDER STATE} from Ticket State Changed event as that event is ticket related and we can’t determine which order’s state we need. Instead we need to access {TICKET STATE} from Order State Changed event. I feel there might be a issue here as we have some weird cases that needs to be handled. For example

  • Ticket started as anonymous and a customer assigned after hh ends.
  • Customer assigned before hh period and hh started.
  • Customer changed / assigned inside hh and some orders created before hh.
  • … etc.

If we elaborate such cases we can find the best method to implement both HH and VIP discounts.

1 Like

Yeah, thanks for that @emre. I spent all day working on this yesterday, and at the end, without thinking about it much, I fired out the request. Waking up this morning with a fresh mind, I realized that it wouldn’t be possible, because as you say: which Order’s State? Today it seems like a ridiculous request for obvious reasons. :stuck_out_tongue_winking_eye:

I know there is a solution in here somewhere… I need to map out the flow in a different way. I have been able to get VIP and HH to work together 99% of the time - but in certain scenarios, it fails due to the order of operation on the Ticket/Orders/Entities. I want to make it unbreakable, and I know it can be done; perhaps it needs to be expanded beyond the simplicity that I was hoping for, but I know I can get there.

I wonder… what is State Value used for? Is this like a “note”?

Yes we can think it like a note. For example we store gift reasons there.

It can be discount type… However I won’t recommend using it like that if you are planning to do so. Discount type should be a state as we’ll be able to control from which state to which state it can flow. For example we can have three Discount states for order. VIP, HH and NA (not available).

  • NA can switch to VIP or HH.
  • HH can’t switch to VIP.
  • VIP can’t switch to HH.
  • HH can’t switch to NA
  • VIP can switch to NA.

So our flow constraints can be…

  • NA >> VIP,HH
  • HH >> ?
  • VIP >> NA

All that can be controlled via Current State parameter of Update Order State action. If you fill in Current State value, (eg current state NA, > State VIP) So only orders that currently have NA state will switch to VIP state.

2 Likes

I’ll show one more sample. You can review this sample how to implement even most complex cases by using ticket and order states.

SambaPOSPromo_201411102014SQM.zip (445.2 KB)

This sample also demonstrates how to implement happy hour without configuring triggers and it will be available to all terminals immediately.

You can change this to configure hh enabling rule.

… and this one to configure hh disabling rule.

@QMcKay might not work exactly aligned to your case. I’ve tried to implement constraints I’ve detailed on my previous post.


####Summary

For anyone who missed whole idea I’ll add a short summary here.

We’ve configured three level discounts for customers and each discount level configured individually for each product. For example D1 (think it as member discount) can be %10 for coffee but %5 for wine. Similarly D2 (gold member discount) can be %15 for coffee and %9 for wine. (you can also use fixed amounts instead of rates.)

However we also have Happy Hour implementation (HH Discount) so during happy hour we need to disable member discounts and only apply happy hour discounts. Also after HH period ends additional orders from members should automatically receive member discounts while preserving previous HH discounts. Also Customer switching or removing cases should be handled correctly. HH discounts also should work for tickets without a customer.

wow !! describing it was harder than implementing it :slight_smile:

2 Likes

You make it look so simple @emre. :wink:

I think I have a working solution for my case. But it is very involved…

I added 2 more states for VR (VIP Removed) and HP (Happy Hour Pending). At first it was just for VR, so that HH would not automatically be applied for ND retroactively… then I figured, why not? If the Order fell within the Happy Hour Window, we could check that and honor the HH price. So I put it into a pending state (HP), then run some date/time checks against the Order, and if they pass, HH is applied.

Wow @QMcKay that way you’ve handled much more cases than I’ve thought. Amazing…

While implementing states I was thinking I’m doing something not very useful as too few people will use it. However I’m glad I’ve did it so I’ll be able to learn a lot of things from talented people. I wish I could sit next to you and watch while you’re implementing it… It would teach me a lot of bad-ass ways to improve that.

Anyway how you’re pushing SambaPOS limits sufficiently makes me think about new ways to optimize things. Being able to implement such complex ideas with rules was just one of the essential steps. Now I think we should quickly improve these…

  • Enable disable rules in group by rule tags so we can have multiple implementations of such discounts or similar promotional, loyalty implementations. That allows us to test how slightly different promotion methods performs.

  • Implement something to align custom reports to promotional date ranges to compare differences with other promotional ranges. Learn new things from that experience, choose better performing one, optimize it more and create new ideas to test.

3 Likes

States are awesome. So much flexibility with them.

I cant find this action, it will be usefull (I think) for my happy hour implementation…

Thanks!!!

G.

@gerlandog, I don’t think this is a new Action. It is the old “Refresh Ticket” Action that we use all the time: Display Ticket Action with Ticket Id = 0.

@emre is stating that the original flow of this discount required the “hard” refresh in 1 of the Rules, but as of v4.1.75, the refresh is not necessary, and it was removed from the Tutorial when 4.1.75 was released.

I used to be deathly afraid of them because of a lack of understanding. When I came to realize that they are somewhat similar to Order Tags and Ticket Tags, yet more flexible/powerful, the fear went away. I mean, you can essentially use States in place of Tags in many scenarios…

So it got me wondering, after looking at the gigantic Rule-set: Is it worth it? It looks overly-complex to me at first glance. Happy Hour in itself is fairly simple. As is VIP discounts. But put them together and it looks scary. I can’t help but think there must be some opportunity for optimization in there somewhere…

Ticket States (named VIP) used:

  • Active: customer has a VIP Level (1,2,3)
  • InActive: customer does not have a VIP Level, or there is no customer assigned to the Ticket

Order States (named DiscountType) used:

  • <> : (blank) when an Order is first added; will be updated immediately to ND
  • ND : No Discount (same as blank, but easier to identify and work with)
  • VIP : VIP Discount as defined by D1/D2/D3 Product Tags
  • HH : Happy Hour Discount as defined by HH Product Tag; overrides VIP
  • VR : VIP Removed (temporary holding State when VIP Customer removed from Ticket, or Customer changed to non-VIP Customer)
  • HP : Happy Hour Pending (temporary holding State until we verify whether Item Order Time fell within the HH timeframe)

This is where I think I might be able to get rid of 1 or 2 States and Rules:

As I developed the flow, VR was necessary so that VIP-removal would not automatically become HH. Then I figured: why couldn’t it become HH if it qualified? We can check Order Time and apply HH if it qualified. So then I created HP to use while checking the Order Time, and would update it to HH or ND as applicable.

ND > VIP > VR > HP > HH or ND

If HH overrides VIP, how could that happen? In testing, I had manual control over turning HH on and off, and modifying the HH Start/End Times, that’s how. If I didn’t have that control, the above scenario would theoretically never come into play. So why do we need that flow? We probably don’t! This would be because: if the original Order Time was inside the HH Window, the flow would have been:

ND > HH

That should be the case whether or not a VIP Customer is selected on the Ticket. Now what happens when we are not inside HH Window? Depending on Customer VIP Level:

ND > VIP or simply ND … let’s assume ND > VIP

Now we remove VIP Level Customer:

VIP > VR

Why? So it doesn’t become HH. Why would it become HH? Because I wasn’t checking Order Time, it would automatically become HH if the HH PriceList was defined, which I was switching on/off at will. I shouldn’t be checking the PriceList status at all; instead I should be checking the HH Start/End Time and comparing it to the Order Time. But through development, that came later.

VIP and Happy Hour Discounts without Triggers. Happy Hour Discount overrides VIP Discount…

  • 1 less State (VR)
  • 5 less Rules that previously handled VR and updates to PriceList
  • 1 less Action (Execute Automation Command wasn’t necessary)
  • number of Actions being fired inside various Rules reduced substantially

Ticket States (named VIP) used:

  • Active: customer has a VIP Level (1,2,3)
  • InActive: customer does not have a VIP Level, or there is no customer assigned to the Ticket

Order States (named DiscountType) used:

  • <> : (blank) when an Order is first added; to be updated to ND, HH, or VIP
  • ND : No Discount (same as blank, but easier to identify and work with)
  • VIP : VIP Discount as defined by D1/D2/D3 Product Tags
  • HH : Happy Hour Discount as defined by HH Product Tag; overrides VIP
  • HP : Happy Hour Pending (temporary holding State while we chech the Item Order Time against the HH Window) to be updated to HH or ND.

DB Tools Import Files:
Automation: Discount_VIP_HH_Automation.zip (2.1 KB)
VIP Order Tags: VIP_OrderTags.zip (588 Bytes)
HH Order Tag: HH_OrderTags.zip (563 Bytes)


Customer Entity Type VIP Level field:

Happy Hour Order Tag:

VIP Discount Order Tags:

Product Tags:

Edit Discount Amounts in the Product Tag Editor:

Set your Happy Hour Days and Times via Rules:

Printer Template:

[<J00>Total FREE:|{ORDER STATE TOTAL:Gift}]

[<J00>Discounts:|[=F(TN('{ORDER TAG TOTAL:Discount}')+TN('{ORDER TAG TOTAL:VIP Discount}')+TN('{ORDER TAG TOTAL:HH Discount}'))]]

[<J00>TOTAL SAVINGS:|[=F(-1*(TN('{ORDER TAG TOTAL:Discount}')+TN('{ORDER TAG TOTAL:VIP Discount}')+TN('{ORDER TAG TOTAL:HH Discount}')+TN('{ORDER STATE TOTAL:Gift}')))]]
1 Like

Sorry to bump this topic again. I have an issue, I think caused by adding the Order Portion Changed event. A number of my products have the Auto Select property set, to prompt the user to select a portion size after adding it to the ticket.

The following screen appears correctly, but after tapping a portion, it does not automatically close. I manually have to click the bottom right Close button after selecting the portion.

I can add an action to the Order Portion Changed event of Display Ticket (with an empty id), which partially fixes this issue. It automatically closes the right portion selection screen, but leaves the order selected (so I still have the Cancel, Void etc buttons available on the right).

After adding the Display Ticket action this is not that much of a problem, but I wondered if you have any ideas of a (better) solution?

Not sure what your issue has to do with this Topic, but anyway…

Auto-Select is designed to open the Modifier Screen, which also happens to contain Portions (if any). By design, this screen will not close automatically - this is how it has always been.

If you want to add an Action to the Order Portion Changed Event to force the Order Tag screen to close, you could try Display Ticket Action with an ID of 0 (not blank).

On the other hand, if it is just Portions you want to look at for certain Items, without the need to open the Order Tag screen (i.e. do not use Auto-Select), you might want to set up the new features introduced in v4.1.78 …

1 Like

It won’t automatically close as you’ve added Member Discount button. That will automatically close after portion selection if you have only portion buttons.

1 Like

Hm… I just got this same problem. What seems to happen is this:

  • when you just click on an item in the menu, it applies the correct discount
  • when you select this item now in the ticket, and click on +, it also is correct (doubles the discount)
  • but if you first enter a number in the numberpad and then click on an item, the discount becomes double of what it should be

Not really a problem when you change
[=-1*(TN(’{QUANTITY}’)TN(’{ITEM TAG:{ENTITY DATA:Customer:Discount}}’))]
into
[=-1
(TN(’{ITEM TAG:{ENTITY DATA:Customer:Discount}}’))]
like @qmckay said, but it’s still a bit strange…

I’m not sure if it has anything to do with this implementation of customer discounts or something else, but I found a problem that’s already present when I use the database you uploaded.

When you choose any item from the menu (doesn’t matter if it has discount or not), then select a customer, then go back to ‘select customer’ screen but click on the cross (for no customer), then cancel the order and close the ticket. The ticket will stay orange on the floor plan (even though there’s no orders on it anymore).

check if it still has an entity on it?