Jump to content
thirty bees forum

[Free Module]Conseqs - execute custom action when something interesting happens


datakick

Recommended Posts

New release 0.1.0

I'm pushing this module towards the final shape. This new version is almost complete solution, from framework perspective. What's new:

1) Integration with @wakabayashi amazing krona module. You can now use any conseqs trigger to award loyalty points to your customer. For example, give extra loyalty points if bank payment is done within 5 days or placing order. Or anything else, the possibilities are unlimited 

2) Log errors -- shit happens, so we need to count with that. The last thing we want is conseq rule to cause 500 error page. From now on this is (almost) impossible. If any error happens during rule execution, it will NOT affect user in any way. Instead, error will be silently log, and page will render. You will see error log page in your back office conseq module page:

image.png.adc4e898f86ab0e55d19f4de8cb32be2.png

3) Measures - you can now measure some interesting values in your database, and react when this value changes over time.

This is the most important functionality in this release. Until now, conseqs could react to real-time events only. We could create rule that was executed when order is placed, or when customer visits some page. We needed some event to perform the action.

With measures, we don't need to anymore. It depends on cron task to periodically re-calculate some values. If the current value is different than measured value from the last run, we can trigger any action. This opens doors to many possibilities, and many new types of triggers. For example, this version contains trigger to detect and react to loyalty points expiration (pinging @30knees)

I know this sounds way too technical, so let me try to explain this by example:

Example:

Assignment: We want customer to be assigned to VIP group if (and only if) he purchased over $300 in the last 90 days 

Solution:

(you can download the complete solution  vip_group_example.json, and import it to your conseqs module)

1) we will create measure that will calculate amount purchased in last 90 days by customer. This measure will be based on following sql, which returns id customer, and purchased amount in the last 90 days:

SELECT `id_customer`, SUM(`total_paid_real` / `conversion_rate`) AS `total`
FROM `tb_orders` AS `o`
WHERE `o`.`valid` = 1 
  AND `o`.`date_add` > DATE_SUB(NOW(), INTERVAL 90 DAY)
GROUP BY `id_customer`

2) we will create new rule to assign customer to VIP group if measure value goes over threshold of $300

  • trigger = Measure Value Changed
  • add 2 conditions:
    • "Measure: Old value" < 300
    • "Measure: New value" >= 300 
  • action = Assign customer to group, bind values
    • "Customer ID" bind to "Measure: Customer: ID"
    • "Group" set to constant value of "VIP"

3) similarly, we will create new rule to assign customer back to Customer group, if measure value goes below $300

  • trigger = Measure Value Changed
  • add 2 conditions:
    • "Measure: Old value" >= 300
    • "Measure: New value" < 300 
  • action = Assign customer to group, bind values
    • "Customer ID" bind to "Measure: Customer: ID"
    • "Group" set to constant value of "Customer"

 

And we are done. Conseqs module will periodically recalculate measure, and executes one of these rules if necesseary.

The same process in screenshots:

1) create measure: 

image.png.3ab5e6899b639b41da0a0fdafca3ca46.png

2) create rule

image.png.99d83e9d2c46d6e7eb62a7f2fac794b2.png

 

image.png.5d22fde5b564ebce2c7802d10246409c.png

image.png.9d2f60ca76208c4294c32d6006aaf58c.png

 

 

  • Like 3
Link to comment
Share on other sites

12 hours ago, 30knees said:

This is awesome! Thank you so much. I already upgraded. Now to somehow transfer existing loyalty points to the krona module. 

I believe krona module supports this already. When you import players for the first time, you can use option 'Import Core Loyalty Points':

image.png.ac2ecd95635c8f3daf8101de95d41e05.png

Link to comment
Share on other sites

20 hours ago, datakick said:

 For example, this version contains trigger to detect and react to loyalty points expiration (pinging @30knees)

I am setting up Krona and I just realised: Does this trigger work only with the native loyalty module or also Krona?

Link to comment
Share on other sites

6 minutes ago, 30knees said:

I am setting up Krona and I just realised: Does this trigger work only with the native loyalty module or also Krona?

I believe Krona doesn't have loyalty points expiration feature

  • Thanks 1
Link to comment
Share on other sites

Hello Petr,

thanks for another great addon :classic_smile:

I've created a simple notification: send new email when the customer creates a shopping cart.

In the email template I can only insert the cart ID. I wonder if it is possible to add a list products that the customer added to the basket? Do you plan to extend the plugin with SQL queries?

Edited by Adik
Link to comment
Share on other sites

15 hours ago, Adik said:

I've created a simple notification: send new email when the customer creates a shopping cart.

In the email template I can only insert the cart ID. I wonder if it is possible to add a list products that the customer added to the basket? Do you plan to extend the plugin with SQL queries?

Conseqs actually parses email template, finds all {placeholders}, and then requires you to provide values for them. Now it depends on what data are available -- every kind of trigger provides different set of data you can use. For example, trigger "Order was updated" give you complete Order object, so you can it's data bind to email placeholders. But if you use trigger "Page view: Product", you don't have any order to work with. This trigger gives you Product object displayed on current page.

Other thing is that email templates are very dumb. We can't use any loops, for cycles, or even conditional statements in them. They are not smarty templates, unfortunately. So it's very hard to display dynamic content, like products in order. Thirtybees can do this only by using nasty hack -- it pregenerate html table with ordered products and pass it to email template in as one variable. I guess I could do something similar in conseqs (when dealing with Order, or Cart object)

Regarding sql queries -- what do you mean? Could you please explain more?

 

Link to comment
Share on other sites

Petr,

I would like to display in e-mail all products added by customer to the created cart.

So I need the SELECT query and two tables: tb_cart and tb_cart_product.

Edited by Adik
Link to comment
Share on other sites

4 minutes ago, Adik said:

Petr,

I would like to display in e-mail all products added by customer to the created cart.

So I need the SELECT query and two tables: tb_cart and tb_cart_product.

As I wrote before, I will add new variable 'Order: Products' that will contain html <table>...</table> with products in order. Similarly for cart object. That should be enough to address this use case.

Anyway, I do plan to add another feature that will allow you to define your own variables. It will be another (optional) step between Trigger and Conditions. In here, you will be able to create new variables, and used them later in Conditions and Actions. You will be able to define new variables using one of these ways:

  • expression to calculate new variable value based on old values (provided by Trigger)
    • {Custom:MyPrice} = {Order.Total} * 1.2
    • {Custom:Subject} = 'Hello ' + {Customer.First name} + ' ' + {Customer.Last name} 
    • ... this is very similar to what my DataKick module supports now
  • fetch some data from database using SQL query, like this:
    • SELECT COUNT(1) FROM tb_order WHERE id_customer = {Order:Customer:ID} 

That should give great flexibility to create (almost) any automation that comes to mind

  • Like 2
Link to comment
Share on other sites

New release: 0.2.0 

I'm happy to announce new version of this module. This version brings one important feature

Ability to impact execution path

Until now, conseqs rules were executed in parallel to the code that triggered it. It run in isolation and it could not impact execution path of the code that triggered it.

Let's take Before email is sent trigger as an example. Regardless of what action was executed, the email was always sent, unchanged. We were able to create rule to log information about email, but it wasn't possible to create action to prevent email from being sent, or to modify email subject..

That's not true anymore. This new version of module supports these kind of actions. 

New actions:

  • Change Order Status
    • you can create rules and change order status
    • example use case is to automatically cancel old, unpaid orders
  • Email: prevent sending email
    • this action will block email from being sent
    • for example, you can drop contact form notification emails
    • or you can ignore emails to disposable addresses (for example mailinator) 
  • Email: change subject
    • you can use this action to compose custom email subject
    • ideal for email personalisation
  • Email: add BCC recipient
    • you can add new recipient to BCC
    • great way to send yourself copy of all emails sent from your store 
  • Email: attach file
    • you can dynamically attach file(s) to your emails
    • for example, you can attach product manual to Order Confirmation email
  • Email: change recipient
    • you can use this action to change email recipient (to email address)
  • Email: change email template
    • this action will allow you to use different email template to render email
    • You can use this feature to have different templates for different customer groups, for example

 

I hope you will find these new features useful. If you have any feature requests or suggestions, please let me know. At the moment, I have the last big feature planned for this module -- Custom variables (as explained in previous post)

  • Like 2
  • Thanks 2
Link to comment
Share on other sites

I've released another version 0.3.0

From feature point of view, this version brings only two new actions:

  • Create Voucher
    • you can now dynamically create vouchers for your customers
    • example use case is to award your customer for posting review on your shop
  • Award loyalty points
    • this action is works with standard loyalty module, and it will appear only if you have this module installed and enabled
    • it will allow you to give your customer additional loyalty points for their action
    • for example, you can give them loyalty points for reviews, for page visits, etc...

Changes in licensing:

This version also changes licensing structure of this module. I decided to abandon trial-version model. Instead, I offer this as a free module with limited number of rules you can create. If you reach the rule limit, you will have to purchase license (or delete those you don't need).

I made this change because I believe module like this might benefit from big user base. My hope is that its users will create interesting integration and share them with other folks.

  • Like 5
  • Thanks 1
Link to comment
Share on other sites

16 minutes ago, 30knees said:

Would "Revws review" as a record type make sense to add (or I just didn't see it)?

It would definitely make sense to have that. The problem is that this is ObjectModel defined by module, so it is loaded and plugged in into the thirtybees system only when some function of revws module is executed (hook, ajax call,...). So it's hard to detect that it even exists.

I have a plan to scan modules directory, and look for all php files that extends ObjectModel class. That will ultimately allow me to support even object models defined by modules. But this task has low priority now

  • Thanks 1
Link to comment
Share on other sites

I've just released new version 0.4.0

PACKAGE REPOSITORY

There are some automations that almost every merchant using my module created. For example, everyone created their own version of reward for review rule.

Even though rule creation process is very simple and easy to understand, this repetition seems unnecessary. So I decided to come up with list of prepared solutions that you can simply import to your store and modify.

You will find new tab named Packages that will let you browse through packages stored on central repository. At the moment there are only few packages, but I'll add more. Also, if you create some cool automation, please export it, and send it to me. After careful validation and verification, I will add it to the repository. This needs to be manual process to prevent any hacking attempt

image.thumb.png.e0a26a08411606042e5e7bfceb21ee14.png

NEW CONDITIONS

There are two new conditions you can use to build your rules

  • starts with - evaluates to true if text starts with specific prefix
  • ends with - evaluates to true if text ends with specific suffix
  • Like 4
Link to comment
Share on other sites

1 hour ago, 30knees said:

Great idea! 

I wanted to test the voucher for review rule, but I get "Failed to load rule" when I click on it after adding it. Do you have an idea why this might be?

This kind of error happens when ajax response contains some extra text. This is often the case when you have enabled debug mode, and there is some php warning or notice.

I have retested this on my server, and I don't have the same problem. So it's probably some issue on your server

Link to comment
Share on other sites

21 hours ago, 30knees said:

Are there other possibilities I can look at if debug mode is disabled?

You should look what is in ajax response -- open browser javascript console, switch to network tab, and find the request that loads the rule.

On related note: I can see something strange on your frontoffice:

image.png.07249bc9a66dd140e453158235efd4ba.png

Those rnrnrnrn characters shouldn't be there. They probably meant to be \r\n characters -- linebreak. You should find the source of this unwanted output and fix it. It is quite likely that this will fix your conseqs issue as well (but maybe not)

 

Link to comment
Share on other sites

Is there a way, for example, to remove a product from a category after a certain date is reached?  For example, I have a preorder category.  I would like the products to automatically get removed from that category when their availability date is reached.

Link to comment
Share on other sites

8 hours ago, movieseals said:

Is there a way, for example, to remove a product from a category after a certain date is reached?  For example, I have a preorder category.  I would like the products to automatically get removed from that category when their availability date is reached.

Yes, it's possible.The trigger part is tricky one -- since this changes with time, the only way to implement this is using measure - for every product in your specific category track if it is available or not. This is sql to define such measure:

SELECT ps.id_product, 1 AS is_available
FROM tb_product_shop ps 
INNER join tb_category_product pc ON (ps.id_product = pc.id_product) 
WHERE pc.id_category = 5555 
  AND now() > ps.available_date

This will return list of every available product in category with id 5555 

image.png.7f0e6ccced000f59777bb935a821492c.png

With this measure in place, you can use trigger Measure value changed that will react when the result of that sql changes. When some product in category 5555 becomes available, sql result will include this product, and rule will be triggered.

You can now do whatever you want. To remove product from category, you will have to use custom sql action and execute this sql:

DELETE FROM tb_category_product 
WHERE id_product = {id} 
  AND id_category = 5555

Where {id} is a placeholder. You will need to bind this to product ID:

image.png.1cddf9b563961044e1f2b70bae22de47.png

You can have a look at my demo account, I've create this rule there (for category 2, not 5555)

  • Like 1
Link to comment
Share on other sites

On 6/24/2019 at 7:32 AM, datakick said:

You should look what is in ajax response -- open browser javascript console, switch to network tab, and find the request that loads the rule.

I found this in the module's own error log. Perhaps packages aren't always compatible with other setups?

Value '3' is not a valid select key: [1, 2, 5]
Rule
#2:  
Location:
/home/abcde/public_html/modules/conseqs/classes/parameters/select-parameter-definition.php line 50
Stacktrace:
#0 /home/abcde/public_html/modules/conseqs/classes/parameter-values.php(96): Conseqs\Parameters\SelectParameterDefinition->convertFromString('3')
#1 /home/abcde/public_html/modules/conseqs/actions/create-voucher.php(145): Conseqs\ParameterValues->getValue('params.currency')
#2 /home/abcde/public_html/modules/conseqs/classes/rules-manager.php(120): Conseqs\Actions\CreateVoucher->execute(Object(Conseqs\ParameterValues), Object(Conseqs\ParameterValues), Object(Conseqs\ParameterValues), Object(Conseqs\RuntimeModifier))
#3 [internal function]: Conseqs\RulesManager->runRuleInternal(Array, Array, Object(Conseqs\RuntimeModifier))
#4 /home/abcde/public_html/modules/conseqs/classes/error-handler.php(45): call_user_func_array(Array, Array)
#5 /home/abcde/public_html/modules/conseqs/classes/rules-manager.php(57): Conseqs\ErrorHandler->handleErrors('Rule #2', Array, Array, Array)
#6 /home/abcde/public_html/modules/conseqs/classes/rules-manager.php(330): Conseqs\RulesManager->runRule(Array, Array, Object(Conseqs\RuntimeModifier))
#7 /home/abcde/public_html/modules/conseqs/conseqs.php(355): Conseqs\RulesManager->dispatchHook('hookactionRevws...', Array)
#8 /home/abcde/public_html/classes/Hook.php(761): Conseqs->__call('hookactionRevws...', Array)
#9 /home/abcde/public_html/classes/Hook.php(469): HookCore::coreCallHook(Object(Conseqs), 'hookactionRevws...', Array)
#10 /home/abcde/public_html/classes/Hook.php(288): HookCore::execWithoutCache('actionRevwsRevi...', Array, NULL, false, true, false, NULL)
#11 /home/abcde/public_html/modules/revws/classes/notifications.php(152): HookCore::exec('actionRevwsRevi...', Array)
#12 [internal function]: Revws\Notifications->processReviewApproved(120, 'visitor', Object(Revws\Settings), Object(Revws\KronaIntegration))
#13 /home/abcde/public_html/modules/revws/classes/notifications.php(77): call_user_func(Array, 120, 'visitor', Object(Revws\Settings), Object(Revws\KronaIntegration))
#14 /home/abcde/public_html/modules/revws/classes/notifications.php(57): Revws\Notifications->process(Object(Revws))
#15 /home/abcde/public_html/modules/revws/controllers/front/api.php(282): Revws\Notifications->closeConnectionAndProcess(Object(Revws))
#16 /home/abcde/public_html/modules/revws/controllers/front/api.php(52): RevwsApiModuleFrontController->reply(NULL, -1, Array)
#17 /home/abcde/public_html/modules/revws/controllers/front/api.php(31): RevwsApiModuleFrontController->ajaxProcessCommand()
#18 /home/abcde/public_html/classes/controller/Controller.php(208): RevwsApiModuleFrontController->initContent()
#19 /home/abcde/public_html/classes/controller/FrontController.php(253): ControllerCore->run()
#20 /home/abcde/public_html/classes/Dispatcher.php(837): FrontControllerCore->run()
#21 /home/abcde/public_html/index.php(33): DispatcherCore->dispatch()
#22 {main}

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...