VIP & Happy Hour (or timed special) Discounts without Triggers


#1

How do I set up VIP Member Discounts and Happy Hour Discounts and have them interact with each other so that VIP Members do not get Happy Hour Discounts on top of their VIP Discount? That is, how do I prevent double-discount for a VIP?

And how can I set this up so that it is all automatic; so that it doesn’t require user interaction such as using Automation Command Buttons on the Ticket Level nor the Order-line Level?

This Tutorial will show you how to set this up and includes these features:

  • Product-level Discounts for HH and VIP
  • Discounts do not use a Price Definition; instead they use Custom Product Tags
  • VIP Discount overrides HH Discount when you select a Customer who is marked as being a “VIP”
  • Happy Hour Days/Times implemented without Triggers will come into effect when you want them to, based on Start/Stop Days and Times that you set
  • supports VIP and/or HH discounts: choose to use only VIP or only HH, or use both at the same time

This is a fairly lengthy setup, and is somewhat complex, so be sure to double-check everything that you do, then triple-check it. Take comfort in knowing that if you are successful in setting this up, you will have learned about some most advanced and powerful features available in SambaPOS.

###Setup Quick Links

Product Tag Captions
Custom Data Field for Customer Entity
Order Tags
Actions
Rules
Printer Template Tags
VIP Ticket State (optional)
POS Nav Tile ( V5 only )
DB Tools Import Files


How to add buy 1 get 2, promotion?
VIP & Happy Hour
Happy Hour prices with portions
Based on the topic linked, I would like to make both discounts?
Customer Price Level
Add %discount to customer accounts
Integration with third party app (The Drink Exchange)
VIP and HH Help
Promotion Points for VIP conflict
Welcome to SambaPOS 5
Excluding items from ticket kitchen receip, geting a client discount button and slow printing issue
Specific Entity Search Rule Action
Problems arising from setear then triggers to implement HH
#3

##Product Tag Captions

Product Tag Captions - VIP1,VIP2,VIP3,HH

These Tags will be used to set the Discount Amount for various Products based on VIP Level or HH Status.

VIP1, VIP2, VIP3: VIP Discounts for VIP Levels 1,2,3
HH: Happy Hour Discount


Product Tag Editor - Discount Amounts for VIP1, VIP2, VIP3, HH on a per-Product basis

The values entered into these fields will be deducted from the original Product Price, based on various conditions.


Happy Hour Monday - Friday 10% all items
#4

##Customer Entity Type - add a Custom Data Field for VIP Level

We will use the VIP Level custom data field to set the VIP Level for Customers


###Customer Entity - edit your Customers to provide a VIP Level of 1, 2, or 3

Customers should have a VIP Level of 1, 2, or 3, (or blank if they are not a VIP). These Levels correspond directly to the Discount Amounts that are set on each Product in the D1, D2, D3 fields.

:bulb: You can also use the Batch Entity Editor for mass edits of Customer VIP Level


:exclamation: All of the steps above must be done manually - they cannot be provided as DB Tools Import Files. The remaining steps below can be implemented either manually or via DB Tools Import Files


#5

:exclamation: All of the steps above must be done manually - they cannot be provided as DB Tools Import Files. The remaining steps below can be implemented either manually or via DB Tools Import Files

##Order Tags##

###Order Tag for HH

We will use this Order Tag to apply the Happy Hour Discount amount.

Order Tag Group (Name): HH Discount
Order Tag: Happy Hour Discount
Prefix List: none
Mappings: none


###Order Tags for VIP

We will use these Order Tags to apply the VIP Discount amount, based on the VIP Level.

Order Tag Group (Name): VIP Discount
Order Tag: VIP Discount 1
Order Tag: VIP Discount 2
Order Tag: VIP Discount 3
Prefix List: none
Mappings: none


###V5 Only

In V5 we can set the Display Format of the Order Tags

<color #FFFF55FF>{0}</color>


#6

Actions

Now we’ll set up all of the Automation required to make this work… first, define the Actions…

Store current PriceList Indicator (optional)

This is a simple visual indicator that we can use in various areas of the program, and it is optional since it is not required by any of Rules or Constraints, but it is nice to have.

Action Type: Update Program Setting
Setting Name: PriceList
Setting Value: [:PriceList]
Update Type: Update
Is Local: False


###Store HH Day(s) and Start/Stop Times

We will use this action to set Happy Hour Day(s) and Start/Stop Times.

Action Type: Update Program Setting
Setting Name: [:HHname]
Setting Value: [:HHvalue]
Update Type: Update
Is Local: False


###Update Ticket State VIP

We will use this action to update the VIP State of the Ticket. If a VIP Customer is assigned to the Ticket, the VIP State will be Active. If there is no Customer assigned, or if the assigned Customer is not a VIP, the VIP State will be InActive.

Action Type: Update Ticket State
State Name: VIP
State: [:VIPState (Active or InActive)]


###Update Order State DiscountType

This action will be used to update the Order DiscountType State of HH, VIP, or ND (No Discount).

Action Type: Update Order State
State Name: DiscountType
State: [:DiscountType State]


###Tag Order Discount

This action will apply an Order Tag to set the Discount Amount for the Order, based on the Order DiscountType State.

Action Type: Tag Order
Order Tag Name: [:DiscountName]
Order Tag Value: [:DiscountType]
Order Tag Price: [:DiscountPrice]


###UnTag Order Discount

This action will remove an Order Tag to UNset the Discount Amount for the Order, based on the Order DiscountType State.

Action Type: Untag Order
Order Tag Name: [:DiscountName]
Order Tag Value: [:DiscountType]


Daily Specials V5
#7

Rules

Now we get to the Rules, which is where all the real magic happens. First, the obligatory notice…

:exclamation: ALL Rules require a default mapping (* * * *)


###Reset HH Day & Time on Application Started

This Rule will blank out the Start/End Day & Time for Happy Hour when you start SambaPOS.

Event: Application Started
Execute Rule if Matches

HH Store HH DateTime
Constraint:
HHname: HHstartDay
HHvalue:

HH Store HH DateTime
Constraint:
HHname: HHendDay
HHvalue:

HH Store HH DateTime
Constraint:
HHname: HHstartTime
HHvalue:

HH Store HH DateTime
Constraint:
HHname: HHendTime
HHvalue:

HH Store Current Price Definition (optional)
Constraint:
PriceList:


###Set HH Start/End Time for Monday and Tuesday

This Rule sets the Start/End Time for Happy Hour to run from 3pm to 5pm on Monday and Tuesday.

Event: Application Started
Execute Rule if Matches
Constraints:
{DATE:ddd} Matches Mon|Tue

HH Store HH DateTime
Constraint:
HHname: HHstartDay
HHvalue: {DATE:ddd}

HH Store HH DateTime
Constraint:
HHname: HHendDay
HHvalue: {DATE:ddd}

HH Store HH DateTime
Constraint:
HHname: HHstartTime
HHvalue: 1459

HH Store HH DateTime
Constraint:
HHname: HHendTime
HHvalue: 1701


###Set HH Start/End Time for Wednesday, Thursday and Friday

This Rule sets the Start/End Time for Happy Hour to run from 4pm to 7pm on Wednesday, Thursday, and Friday.

Event: Application Started
Execute Rule if Matches
Constraints:
{DATE:ddd} Matches Wed|Thu|Fri

HH Store HH DateTime
Constraint:
HHname: HHstartDay
HHvalue: {DATE:ddd}

HH Store HH DateTime
Constraint:
HHname: HHendDay
HHvalue: {DATE:ddd}

HH Store HH DateTime
Constraint:
HHname: HHstartTime
HHvalue: 1559

HH Store HH DateTime
Constraint:
HHname: HHendTime
HHvalue: 1901


###Modify Ticket VIP State when Entity Changed

This Rule sets the Ticket VIP State to Active or InActive based on whether the Customer has a VIP Level.

Event: Ticket Entity Changed
Execute Rule if Matches
Constraints:
Entity Type Name Equals Customers

Update Ticket VIP State
Constraint: [=TN('{ENTITY DATA:Customer:VIP Level}')] < 1
VIPState (Active or InActive): InActive

Update Ticket VIP State
Constraint: [=TN('{ENTITY DATA:Customer:VIP Level}')] > 0
VIPState (Active or InActive): Active


###DeActivate Ticket VIP State when Entity Removed

This Rule sets the Ticket VIP State to InActive when the Customer Entity is removed.

img src="/uploads/default/8371/082d6a52079a6c81.png" width=“690” height=“373”>

Event: Ticket Entity Changed
Execute Rule if Matches
Constraints:
{ENTITY DATA:Customer:VIP Level} Less 1
{ENTITY DATA:Customer:VIP Level} Is Null

CD Update Ticket VIP State
Constraint:
VIPState (Active or InActive): InActive


###Modify Ticket VIP State when Ticket Opened

This Rule sets the Ticket VIP State to Active or InActive when an existing Ticket is opened, based on whether the Customer has a VIP Level.

Event: Ticket Opened
Execute Rule if Matches
Constraints:
{ENTITY NAME:Customer} Is Not Null

CD Update Ticket VIP State
Constraint:
VIPState (Active or InActive): Unknown

CD Update Ticket VIP State
Constraint: [=TN('{ENTITY DATA:Customer:VIP Level}')] < 1
VIPState (Active or InActive): InActive

CD Update Ticket VIP State
Constraint: [=TN('{ENTITY DATA:Customer:VIP Level}')] > 0
VIPState (Active or InActive): Active


###Update Order DiscountType State for VIP

This Rule updates the Order State to VIP when the Ticket State changes to VIP Active.

Event: Ticket State Updated
Execute Rule if Matches
Constraints:
State Name Equals VIP
State Matches Active

CD Update Order State DiscountType
Constraint:
DiscountType State: VIP


###Update Order DiscountType State for NonVIP

This Rule updates the Order State to HP (HH Pending) when the Ticket State changes to VIP InActive.

Event: Ticket State Updated
Execute Rule if Matches
Constraints:
State Name Equals VIP
State Equals InActive
State Is Null

**CD Update Order State DiscountType **
Constraint:
DiscountType State: HP


###Update Order State when Order Added to Ticket with Happy Hour Active

This Rule updates the Order State when an Order is added to the Ticket and the Ticket State is VIP InActive, and if the Order Time falls within the Day and Time of Happy Hour. When those conditions are met, the HH Product Tag value is checked. If the HH Tag value is greater than zero (0), the Order State becomes HH, otherwise it becomes ND (No Discount).

Event: Order Added to Ticket
Execute Rule if Matches All
Constraints:
[=FD('{ORDER DATE}','ddd')] Matches {SETTING:HHstartDay}
[=FD('{ORDER TIME}','HHmm')] Greater {SETTING:HHstartTime}
[=FD('{ORDER TIME}','HHmm')] Less {SETTING:HHendTime}
{TICKET STATE:VIP} Not Equals Active

CD Update Order State DiscountType
Constraint: [=TN('{ITEM TAG:HH}')] > 0
DiscountType State: HH

CD Update Order State DiscountType
Constraint: [=TN('{ITEM TAG:HH}')] < 1
DiscountType State: ND


###Update Order State when Order Added to Ticket with Ticket State VIP Active

This Rule updates the Order State when an Order is added to the Ticket and the Ticket State is VIP Active. When that condition is met, the D1, D2, or D3 Product Tag value is checked. If the Dx Tag value is greater than zero (0), the Order State becomes VIP, otherwise it becomes ND (No Discount)…

Event: Order Added to Ticket
Execute Rule if Matches
Constraints:
{TICKET STATE:VIP} Equals Active

CD Update Order State DiscountType
Constraint: [=TN('{ITEM TAG:VIP{ENTITY DATA:Customer:VIP Level}}')]>0
DiscountType State: VIP

CD Update Order State DiscountType
Constraint: [=TN('{ITEM TAG:VIP{ENTITY DATA:Customer:VIP Level}}')]<1
DiscountType State: ND


###Check Order Time from HP and set Order State to ND, HH, or VIP

This Rule fires when the Ticket State VIP becomes InActive, and the Order State has changed to HP (HH Pending). The Order State is then set to ND or HH by comparing the Order Time to the HH Start/Stop times.

Event: Order State Updated
Execute Rule if Matches
Constraints:
State Name Equals DiscountType
State Matches HP

CD Update Order State DiscountType
Constraint: '[=FD('{ORDER DATE}','ddd')]' !='{SETTING:HHstartDay}' || [=TN(FD('{ORDER TIME}','HHmm'))]<[=TN('{SETTING:HHstartTime}')] || [=TN(FD('{ORDER TIME}','HHmm'))]>[=TN('{SETTING:HHendTime}')] || {ORDER TAG:HH Discount}<1
DiscountType State: ND

CD Update Order State DiscountType
Constraint: '[=FD('{ORDER DATE}','ddd')]'=='{SETTING:HHstartDay}' && [=TN(FD('{ORDER TIME}','HHmm'))]>[=TN('{SETTING:HHstartTime}')] && [=TN(FD('{ORDER TIME}','HHmm'))]<[=TN('{SETTING:HHendTime}')]
DiscountType State: HH

CD Update Order State DiscountType
Constraint: [=TN('{ITEM TAG:VIP{ENTITY DATA:Customer:VIP Level}}')]>0
DiscountType State: VIP


###Tag Order Discount for HH or VIP

This Rule will Tag an Order with a Discount amount when the Order State is HH or VIP. If the Order State is HH, and the Product Tag for HH is greater than zero (0), the Order is Tagged with the Happy Hour Discount. If the Order State is VIP, and the Product Tag for D1, D2, or D3 is greater than zero (0), the Order is Tagged with a VIP Discount.

Event: Order State Updated
Execute Rule if Matches
Constraints:
State Name Equals DiscountType
State Matches VIP
State Matches HH
{ORDER STATE:GStatus} Not Equals Gift

CD Tag Order Discount
Constraint: '{ORDER STATE:DiscountType}'=='VIP' && [=TN('{ITEM TAG:VIP{ENTITY DATA:Customer:VIP Level}}')]>0
DiscountName: VIP Discount
DiscountType: VIP Discount {ENTITY DATA:Customer:VIP Level}
DiscountPrice: [=-1*(TN('{ITEM TAG:VIP{ENTITY DATA:Customer:VIP Level}}'))]

CD Tag Order Discount
Constraint: '{ORDER STATE:DiscountType}'=='HH' && [=TN('{ITEM TAG:HH}')]>0
DiscountName: HH Discount
DiscountType: Happy Hour Discount
DiscountPrice: [=-1*(TN('{ITEM TAG:HH}'))]


###UnTag Order from HH to VIP

This Rule removes the Happy Hour Discount when the Order State is VIP, so that the Order isn’t double-discounted.

Event: Order State Updated
Execute Rule if Matches
Constraints:
State Name Equals DiscountType
State Matches VIP

CD UnTag Order Discount
Constraint:
DiscountName: HH Discount
DiscountType: {ORDER TAG:HH Discount}


###UnTag Order for ND or Gift

This Rule removes HH and VIP Discounts when the Order State is Gift.

Event: Order State Updated
Execute Rule if Matches
Constraints:
State Name Equals GStatus
State Equals Gift
State Name Equals DiscountType
State Equals ND

CD UnTag Order Discount
Constraint:
DiscountName: VIP Discount
DiscountType: {ORDER TAG:VIP Discount}

CD UnTag Order Discount
Constraint:
DiscountName: HH Discount
DiscountType: {ORDER TAG:HH Discount}


###Tag Order Discount when UnGifted

This Rule will Tag an Order with a Discount when the Order is UnGifted.

Event: Order State Updated
Execute Rule if Matches
Constraints:
State Name -Equals- GStatus
State -Not Equals- Gift

CD Tag Order Discount
Constraint: '{ORDER STATE:DiscountType}'=='VIP' && [=TN('{ITEM TAG:VIP{ENTITY DATA:Customer:VIP Level}}')]>0
DiscountName: VIP Discount
DiscountType: VIP Discount {ENTITY DATA:Customer:VIP Level}
DiscountPrice: [=-1*(TN('{ITEM TAG:VIP{ENTITY DATA:Customer:VIP Level}}'))]

CD Tag Order Discount
Constraint: '{ORDER STATE:DiscountType}'=='HH' && [=TN('{ITEM TAG:HH}')]>0
DiscountName: HH Discount
DiscountType: Happy Hour Discount
DiscountPrice: [=-1*(TN('{ITEM TAG:HH}'))]


Adding in HH Rule
How to setup Promotion on data time in V5(5.1.62)
#8

##Printer Template Tags

Printer Template Tags to display savings to the Customer on their Bill

[<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}'))]]

Discount Printer Template Syntax
#9

VIP Ticket State (optional)

If you want the VIP Ticket State to show on the Ticket Screen for non-Admin users, you need to set up these States, and ensure Show on Ticket is checked.

If you do not set up these States in this manner, regular users (non-Admin) will not be able to see the VIP Ticket State, but functionality will not be affected.

Ticket State for VIP Active
Name: Active
State Name: VIP
State Type: Ticket State

Ticket State for VIP InActive
Name: InActive
State Name: VIP
State Type: Ticket State


#10

POS Navigation Tile

<size 46><sym></sym></size> <size 48><bold>POS</bold></size>
[=('{SETTING:ISCURRENTWORKPERIODOPEN}'=='TRUE' ? 'Ready' : '<color red><italic>NOT</italic></color> ready')]

<size 26>Happy Hour [=('{SETTING:PriceList}'=='HH' ? 'ACTIVE' + '<linebreak/>' + '{SETTING:HHstartTime}'  + ' to ' + '{SETTING:HHendTime}': '<italic>InActive</italic>')]</size>

Update Program Setting PriceList (optional)

This Rule updates Program Setting named PriceList to indicate Happy Hour Active (HH) or Inactive (blank). This setting is useful for displaying the status of Happy Hour in the Application Subtitle and/or on a Navigation Tile as shown above. There are other ways to manage this status display, but this Rule is simple and effective because it allows for checking a single value (PriceList) instead of checking Days/Times to determine its status.

Name: HH Update PriceList
Event: Application Screen Changed
Execute Rule if Matches
Constraints:
Current Screen Equals Navigation

HH Store Current PriceList
Constraint: '{DATE:ddd}'!='{SETTING:HHstartDay}' || [=TN('{DATE:HHmm}')]<[=TN('{SETTING:HHstartTime}')] || [=TN('{DATE:HHmm}')]>[=TN('{SETTING:HHendTime}')]
PriceList: (blank)

HH Store Current PriceList
Constraint: '{DATE:ddd}'=='{SETTING:HHstartDay}' && [=TN('{DATE:HHmm}')]>[=TN('{SETTING:HHstartTime}')] && [=TN('{DATE:HHmm}')]<[=TN('{SETTING:HHendTime}')]
PriceList: HH


VIP & Happy Hour, "PriceList" not functioning
#12

Database Tools Import Files

:exclamation: The first few steps of this Tutorial must be done manually - they cannot be provided as DB Tools Import Files. Specifically, you must manually set up:

VIP Ticket States
VIP_Ticket_States.zip (481 Bytes)

HH and VIP Order Tags
OrderTags.zip (624 Bytes)

Automation
Automation.zip (2.3 KB)


Full Package (all of the above)
!Complete_Setup_VIP_HH.zip (2.6 KB)


#13

… reserved for updates …


#14

Hi Thanks for the Happy Hour and works a treat now another question is how do i get it to work twice a day, for instance 8-10 am and 2-4 pm, i have tried different methods including creating a new set of rules and actions but no luck the only way i can do it at the moment is create another rule " HH MTWTFS 2-4 pm" and delete the mapping for the morning one and restart SambaPOS so the afternoon one will be next in line and add mapping back for AM one after the Pm one has finished. Any help would be appreciated.

Thanks Guys and Girls


#15

not sure if this will work as i havent tried this setup but try adding a pipe to the times to add an additional start and end time like where you set the day eg Mon|Tue|Wed so in the image below start time is 1459, if you wanted it to start again at 7pm try changing it to 1459|1859 and the end time is set at 1701 so if you wanted to add a second end time for 9pm try 1701|2101. Like i say i dont use this setup so havent played about with it and i dont know if the pipe character | works in the actions like ive described above, but have a try and see if it works


#16

Hi RickH Tried that Unfortunately it Stopped all Time Events lol, for some reason it will only work once a day but Thank You for responding. Hoping someone who has this feature will help.

Thanks all the same.


#17

Try copying the rule where you set the times and change to be the next start and finish times

So you will have 2 rules that start and finish happy hour at different times


#18

Hi RickH do you mean create a new rule with HH MTWTFS 2-4 to match HH MTWTFS 8-10 if so already tried it and nothing, wont kick in strange i know but mind boggling lol,

Thanks


#19

Unfrtunately, it isn’t that simple.

Where you store the values in Program Settings called HHstartTime and HHendTime, you need to store another value by a different name, for example HHstartTime2 and HHendTime2.

Then in any Rules where HHstartTime and/or HHendTime are checked for reference, you need to add checks for the “2” values. For example, in the Rule for Check Order Time from HP and set Order State to ND, HH, or VIP, the Action Constraints for CD Update Order State DiscountType need to go from this:

'[=FD('{ORDER DATE}','ddd')]'=='{SETTING:HHstartDay}' && 
[=TN(FD('{ORDER TIME}','HHmm'))]>[=TN('{SETTING:HHstartTime}')] 
&& [=TN(FD('{ORDER 
TIME}','HHmm'))]<[=TN('{SETTING:HHendTime}')]

To the following, where we check against HHstartTime, HHendTime and against HHstartTime2, HHendTime2:

'[=FD('{ORDER DATE}','ddd')]'=='{SETTING:HHstartDay}' && 
(([=TN(FD('{ORDER TIME}','HHmm'))]>[=TN('{SETTING:HHstartTime}')] 
&& [=TN(FD('{ORDER 
TIME}','HHmm'))]<[=TN('{SETTING:HHendTime}')]) || ([=TN(FD('{ORDER TIME}','HHmm'))]>[=TN('{SETTING:HHstartTime2}')] 
&& [=TN(FD('{ORDER 
TIME}','HHmm'))]<[=TN('{SETTING:HHendTime2}')]))

In pseudo code, we go from this:

OrderDate == HHdate
AND
( OrderTime > HHstart AND OrderTime < HHend ) 

To this:

OrderDate == HHdate
AND
(
  ( OrderTime > HHstart AND OrderTime < HHend ) 
 OR
  ( OrderTime > HHstart2 AND OrderTime < HHend2 ) 
)

#20

@QMcKay we have CSETTING (cached setting) tag that works like SETTING but keeps value in cache until cache resets. It might be better to read setting values that does not change during operation like HHEndTime with CSETTING as it will prevent to execute an SQL script everytime SETTING gets read.


#21

I just learned something…How long has that been available?


#22

I think it is available for few months but I’m not sure about the exact date :slight_smile: