Skip to content

Instantly share code, notes, and snippets.

@onjin
Created November 19, 2014 10:28
Show Gist options
  • Save onjin/2acc27efe96926d7d9e8 to your computer and use it in GitHub Desktop.
Save onjin/2acc27efe96926d7d9e8 to your computer and use it in GitHub Desktop.
python business_rules package example
# pip install business-rules
from decimal import Decimal
from pprint import pprint
from business_rules import (
variables, actions, fields, export_rule_data, run_all
)
class Request(object):
def __init__(self, contractor, cart):
self.contractor = contractor
self.cart = cart
class Contractor(object):
def __init__(self, symbol):
self.symbol = symbol
class Cart(object):
def __init__(self, total):
self.total = total
def get_total(self):
return self.total
class PaymentMethod(object):
def __init__(self, symbol, gateway_symbol, amount, is_active):
self.symbol = symbol
self.gateway_symbol = gateway_symbol
self.amount = amount
self.is_active = is_active
class PaymentMethodVariables(variables.BaseVariables):
def __init__(self, request, method):
self.method = method
self.request = request
@variables.string_rule_variable()
def current_contractor(self):
return getattr(self.request.contractor, 'symbol')
@variables.string_rule_variable()
def method_symbol(self):
return self.method.symbol
@variables.string_rule_variable()
def gateway_symbol(self):
return self.method.gateway.symbol
@variables.numeric_rule_variable()
def cart_total(self):
return self.request.cart.get_total()
class PaymentMethodActions(actions.BaseActions):
def __init__(self, request, method):
self.method = method
self.request = request
@actions.rule_action(params={
'active': fields.FIELD_SELECT_MULTIPLE
})
def change_active(self, active):
self.method.is_active = active
@actions.rule_action(params={
'amount': fields.FIELD_NUMERIC,
})
def set_amount(self, amount):
self.method.amount = amount
if __name__ == '__main__':
request = Request(Contractor('stefan'), Cart(Decimal('101')))
method = PaymentMethod('cash', 'general', Decimal('1.12'), True)
rules = export_rule_data(PaymentMethodVariables, PaymentMethodActions)
pprint(rules)
run_all(
rule_list=[
{
'conditions': {
'all': [
{
'name': 'current_contractor',
'operator': 'equal_to',
'value': 'stefan',
},
],
},
'actions': [
{
'name': 'change_active',
'params': {
'active': False,
},
},
]
},
{
'conditions': {
'all': [
{
'name': 'cart_total',
'operator': 'greater_than',
'value': Decimal('100'),
},
],
},
'actions': [
{
'name': 'change_active',
'params': {
'active': True,
},
},
{
'name': 'set_amount',
'params': {
'amount': Decimal('0'),
},
},
]
},
],
defined_variables=PaymentMethodVariables(request, method),
defined_actions=PaymentMethodActions(request, method),
stop_on_first_trigger=False
)
pprint(method.__dict__)
@esmejia277
Copy link

Hi there, thanks for you example.
I want to use an "Any" or "o" options to my rules, how can i do that?
I have this rule_list but it's not working, thanks a lot.

`rule_list = [
{
'actions': [{'name': 'aplica_o_no_aplica'}],

    'conditions': {
        'any': [
            {
                'name': 'tipo_vinculacion',
                'operator': 'equal_to',
                'value': 'Asociado',
            },
        ],
        'all': [
            {
                'name': 'numero_salarios_minimo',
                'operator': 'greater_than_or_equal_to',
                'value': 1,
            },
            {
                'name': 'actividad_economica',
                'operator': 'equal_to',
                'value': 'Asalariado',
            },
        ],
    },
    
},

]`

@onjin
Copy link
Author

onjin commented Aug 27, 2020

It should be working as tipo_vinculaction == Asociado or (numero_salarios_minimo >= 1 and actividad_economica = Asalariado)

@esmejia277
Copy link

esmejia277 commented Aug 27, 2020

It should be working as tipo_vinculaction == Asociado or (numero_salarios_minimo >= 1 and actividad_economica = Asalariado)

It's not working, look at this.

My rule list

rule_list = [
    {
        'actions': [{'name': 'aplica_o_no_aplica'}],
        
        'conditions': {
            'any': [
                {
                    'name': 'tipo_vinculacion',
                    'operator': 'equal_to',
                    'value': 'Asociado',
                },
                
            ],
            
            'all': [
                {
                    'name': 'numero_salarios_minimo',
                    'operator': 'greater_than_or_equal_to',
                    'value': 1,
                },
                {
                    'name': 'actividad_economica',
                    'operator': 'equal_to',
                    'value': 'Asalariado',
                },
            ],
        
        },
    },
]

My main

if __name__ == '__main__':
    rule3 = Rule("Asociado", "Asalariado", 1)
    
    rules_to_evaluate = [rule3]
    
    for rule in rules_to_evaluate:
        run_all(rule_list=rule_list,
                defined_variables=RuleVariables(rule),
                defined_actions=RuleActions(rule),
                stop_on_first_trigger=True
               )
    
    for rule in rules_to_evaluate:
        print(rule)

And i get this error

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-13-0c85c2a5a640> in <module>
      8                 defined_variables=RuleVariables(rule),
      9                 defined_actions=RuleActions(rule),
---> 10                 stop_on_first_trigger=True
     11                )
     12 

c:\users\pronostica\documents\projects\bancoomeva-api\env\lib\site-packages\business_rules\engine.py in run_all(rule_list, defined_variables, defined_actions, stop_on_first_trigger)
      8     rule_was_triggered = False
      9     for rule in rule_list:
---> 10         result = run(rule, defined_variables, defined_actions)
     11         if result:
     12             rule_was_triggered = True

c:\users\pronostica\documents\projects\bancoomeva-api\env\lib\site-packages\business_rules\engine.py in run(rule, defined_variables, defined_actions)
     17 def run(rule, defined_variables, defined_actions):
     18     conditions, actions = rule['conditions'], rule['actions']
---> 19     rule_triggered = check_conditions_recursively(conditions, defined_variables)
     20     if rule_triggered:
     21         do_actions(actions, defined_actions)

c:\users\pronostica\documents\projects\bancoomeva-api\env\lib\site-packages\business_rules\engine.py in check_conditions_recursively(conditions, defined_variables)
     43         # help prevent errors - any and all can only be in the condition dict
     44         # if they're the only item
---> 45         assert not ('any' in keys or 'all' in keys)
     46         return check_condition(conditions, defined_variables)
     47 

AssertionError:

I checked the documentation (https://github.com/venmo/business-rules) and they recommend to form the list of dicts like this...

# current_inventory < 5 OR (current_month = "December" AND current_inventory < 20)
{ "conditions": { "any": [
      { "name": "current_inventory",
        "operator": "less_than",
        "value": 5,
      },
    ]},
      { "all": [
        {  "name": "current_month",
          "operator": "equal_to",
          "value": "December",
        },
        { "name": "current_inventory",
          "operator": "less_than",
          "value": 20,
        }
      ]},
  },
  "actions": [
    { "name": "order_more",
      "params":{"number_to_order": 40},
    },
  ],
}]

The "all" dict is out of "conditions" key... it's not working that way neither

@onjin
Copy link
Author

onjin commented Aug 27, 2020

ou, I see now. The example in README has a syntax error, but I've found proper example in tests,

so try this one

        {
            "conditions": {
                "any": [
                    {
                        "name": "tipo_vinculacion",
                        "operator": "equal_to",
                        "value": "Asociado",
                    },
                    {
                        "all": [
                            {
                                "name": "numero_salarios_minimo",
                                "operator": "greater_than_or_equal_to",
                                "value": 1,
                            },
                            {
                                "name": "actividad_economica",
                                "operator": "equal_to",
                                "value": "Asalariado",
                            },
                        ],
                    },
                ],
            },
            "actions": [{"name": "aplica_o_no_aplica"}],
        },
    ]```

@esmejia277
Copy link

ou, I see now. The example in README has a syntax error, but I've found proper example in tests,

so try this one

        {
            "conditions": {
                "any": [
                    {
                        "name": "tipo_vinculacion",
                        "operator": "equal_to",
                        "value": "Asociado",
                    },
                    {
                        "all": [
                            {
                                "name": "numero_salarios_minimo",
                                "operator": "greater_than_or_equal_to",
                                "value": 1,
                            },
                            {
                                "name": "actividad_economica",
                                "operator": "equal_to",
                                "value": "Asalariado",
                            },
                        ],
                    },
                ],
            },
            "actions": [{"name": "aplica_o_no_aplica"}],
        },
    ]```

Ohh, finally it worked, thanks a lot!!

@onjin
Copy link
Author

onjin commented Aug 27, 2020

That's great :) you welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment