def test_20_percent_discount_from_fifth_order(self, an_order_factory): an_order = an_order_factory() an_order_factory() an_order_factory() an_order_factory() an_order_factory() Rule(name='Minimum delivery cost of $20', conditions=[ RuleCondition(variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='0'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=20)).save() Rule(name='%20 discount from 5th order', conditions=[ RuleCondition(variable=RuleCondition.ORDER_QUANTITY, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='5'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.PERCENTAGE, value=-20)).save() self.assert_price(an_order, 16)
def test_quote_price_with_datetime_rules(self, an_order): an_order.date = datetime.strptime('Sat, 30 Nov 2019 18:30:00 -0300', "%a, %d %b %Y %H:%M:%S %z") an_order.save() Rule(name='5% discount today', conditions=[ RuleCondition( variable=RuleCondition.ORDER_DATE, operator=RuleCondition.IS, condition_value='Sat, 30 Nov 2019 18:30:00 -0300'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.PERCENTAGE, value=-5)).save() Rule(name='base price', conditions=[ RuleCondition(variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='0'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=20)).save() assert self.rule_service.quote_price(an_order.id) == 19
def test_recharge_of_10_from_monday_to_friday_from_5_pm_to_7_pm( self, an_order_factory): an_order = an_order_factory() an_order.date = datetime.strptime('Wed, 27 Nov 2019 17:30:00 GMT', "%a, %d %b %Y %H:%M:%S %Z") an_order.save() another_order = an_order_factory() another_order.date = datetime.strptime('Sat, 30 Nov 2019 17:30:00 GMT', "%a, %d %b %Y %H:%M:%S %Z") another_order.save() Rule(name='$10 recharge from monday to friday from 5pm to 7pm', conditions=[ RuleCondition(variable=RuleCondition.ORDER_DAY, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='1'), RuleCondition(variable=RuleCondition.ORDER_DAY, operator=RuleCondition.LESS_THAN_EQUAL, condition_value='5'), RuleCondition( variable=RuleCondition.ORDER_TIME, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='Sat, 30 Nov 2019 15:00:00 -0300'), RuleCondition( variable=RuleCondition.ORDER_TIME, operator=RuleCondition.LESS_THAN_EQUAL, condition_value='Sat, 30 Nov 2019 19:00:00 -0300'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=10)).save() self.assert_price(an_order, 10) self.assert_price(another_order, 0)
def test_quote_price_with_value_per_unit_consequence( self, mocked_get, an_order, a_distance_response): mocked_get.return_value = a_distance_response(54) # to Escobar an_order.owner.location.latitude = -34.3467 an_order.owner.location.longitude = -58.8186 an_order.owner.save() # from Buenos Aires an_order.ordered_products[ 0].product.place.coordinates.latitude = -34.603722 an_order.ordered_products[ 0].product.place.coordinates.longitude = -58.381592 an_order.ordered_products[0].product.place.save() Rule(name='$20 per km', conditions=[ RuleCondition(variable=RuleCondition.ORDER_DISTANCE, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='20'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.PER_UNIT_VALUE, value=20, variable=RuleCondition.ORDER_DISTANCE)).save() assert self.rule_service.quote_price(an_order.id) == 20 * 54
def test_quote_price_with_distance_rule(self, mocked_get, an_order, a_distance_response): mocked_get.return_value = a_distance_response(54) # to Escobar an_order.owner.location.latitude = -34.3467 an_order.owner.location.longitude = -58.8186 an_order.owner.save() # from Buenos Aires an_order.ordered_products[ 0].product.place.coordinates.latitude = -34.603722 an_order.ordered_products[ 0].product.place.coordinates.longitude = -58.381592 an_order.ordered_products[0].product.place.save() Rule(name='$200 if distance is greater than 50km', conditions=[ RuleCondition(variable=RuleCondition.ORDER_DISTANCE, operator=RuleCondition.GREATER_THAN, condition_value='50'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=200)).save() # rule should apply cause the distance is ~54 > 50 assert self.rule_service.quote_price(an_order.id) == 200
async def add_rule_by_self( self, ctx, name: str, message: discord.Message, emoji: str, reward_sticker: Optional[int], reward_role: Optional[discord.Role], ): with session_scope() as session: rule = Rule( name=name, by_admin=False, message_id=message.id, emoji=str(emoji) ) if reward_sticker is not None: rule.reward_sticker = reward_sticker if reward_role is not None: rule.reward_role_id = reward_role.id session.add(rule) session.commit() self.bot.logger.info("rule add: " + repr(rule)) await message.add_reaction(emoji) await ctx.send(f"규칙 #{rule.id} 추가됨!")
def _decorator(self, *args, **kwargs): jt = JobTemplate(log_level=LogLevel.complete, name="Gob") r = Rule(condition=RuleCondition.if_col_present, conditional={'column': 'id'}, checks=[ Check(check_type=CheckType.uniqueness, check_metadata={'column': 'id'}) ], children=[ Rule(condition=RuleCondition.if_col_present, conditional={'column': 'bloo'}) ]) jt.data_sources.append(self.dummy_datasource()) jt.rules.append(r) db_session.add(jt) db_session.commit() jt.become_read_only_clone() func(self, jt)
def test_five_percent_discount_wednesdays_from_three_pm_to_four_pm( self, an_order_factory): an_order = an_order_factory() an_order.date = datetime.strptime('Wed, 27 Nov 2019 15:30:00 GMT', "%a, %d %b %Y %H:%M:%S %Z") an_order.save() another_order = an_order_factory() another_order.date = datetime.strptime('Wed, 27 Nov 2019 16:30:00 GMT', "%a, %d %b %Y %H:%M:%S %Z") another_order.save() Rule(name='Minimum delivery cost of $20', conditions=[ RuleCondition(variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='0'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=20)).save() Rule(name='5% discount on wednesdays from 3pm to 4pm', conditions=[ RuleCondition(variable=RuleCondition.ORDER_DAY, operator=RuleCondition.IS, condition_value='3'), RuleCondition( variable=RuleCondition.ORDER_TIME, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='Sat, 30 Nov 2019 15:00:00 -0300'), RuleCondition( variable=RuleCondition.ORDER_TIME, operator=RuleCondition.LESS_THAN_EQUAL, condition_value='Sat, 30 Nov 2019 16:00:00 -0300') ], consequence=RuleConsequence( consequence_type=RuleConsequence.PERCENTAGE, value=-5, )).save() self.assert_price(an_order, 19.0) self.assert_price(another_order, 20)
def test_percentage_consequence_should_apply_last(self, an_order): Rule(name='new rule', conditions=[ RuleCondition(variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.LESS_THAN, condition_value='2'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.PERCENTAGE, value=-10)).save() Rule(name='new rule', conditions=[ RuleCondition(variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.LESS_THAN, condition_value='2'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=10)).save() assert self.rule_service.quote_price(an_order.id) == 9
def test_should_calculate_quotation_based_on_rules(self, an_order, a_delivery_user): Rule(name='$20 base', conditions=[], consequence={ 'consequence_type': RuleConsequence.VALUE, 'value': 20 }).save() order_service.take(an_order.id, a_delivery_user.id) assert Order.objects.get(id=an_order.id).quotation == 20
def test_take_favor_order_should_not_calculate_quotation( self, a_favor_order, another_customer_user): Rule(name='$20 base', conditions=[], consequence={ 'consequence_type': RuleConsequence.VALUE, 'value': 20 }).save() order_service.take(a_favor_order.id, another_customer_user.id) assert Order.objects.get(id=a_favor_order.id).quotation == 0
def test_should_return_zero_if_quotation_is_negative(self, an_order): Rule(name='$20 discount', conditions=[ RuleCondition(variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='0'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=-20, )).save() assert self.rule_service.quote_price(an_order.id) == 0
def test_rule_runs_include_children_rule_checks(self, r, d, jr): r.children.append( Rule(condition=RuleCondition.if_table_name_matches, conditional={'pattern': 'test_uniqueness'}, checks=[ Check(check_type=CheckType.null, check_metadata={'column': 'id'}) ])) checks_to_run = self.run_rule(r, d, jr) self.assertTrue((d, 'test.test_uniqueness_success', r.children[0].checks[0]) in checks_to_run)
def _decorator(self, *args, **kwargs): r = Rule(condition=RuleCondition.if_col_present, conditional={'column': 'id'}, checks=[ Check(check_type=CheckType.uniqueness, check_metadata={'column': 'id'}) ]) d = self.dummy_datasource() jr = self.dummy_job_run(d) self.s.add_all([r, d, jr]) d.open_connection() func(self, r, d, jr) d.close_connection()
def test_price_per_extra_km(self, mocked_get, an_order, a_distance_response): mocked_get.return_value = a_distance_response(54) # to Escobar an_order.owner.location.latitude = -34.3467 an_order.owner.location.longitude = -58.8186 an_order.owner.save() # from Buenos Aires an_order.ordered_products[ 0].product.place.coordinates.latitude = -34.603722 an_order.ordered_products[ 0].product.place.coordinates.longitude = -58.381592 an_order.ordered_products[0].product.place.save() Rule(name='$15 per extra kilometer above 2', conditions=[ RuleCondition(variable=RuleCondition.ORDER_DISTANCE, operator=RuleCondition.GREATER_THAN, condition_value='2'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.PER_UNIT_VALUE, value=15, variable=RuleCondition.ORDER_DISTANCE)).save() Rule(name='discount first 2km', conditions=[ RuleCondition(variable=RuleCondition.ORDER_DISTANCE, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='2'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=-30, )).save() self.assert_price(an_order, 52 * 15)
def test_apply_consequence_with_one_rule(self, an_order): Rule(name='new rule', conditions=[ RuleCondition(variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.LESS_THAN, condition_value='2') ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=5)).save() an_order.owner.reputation = 1 an_order.owner.save() assert self.rule_service.quote_price(an_order.id) == 5
def test_mark_order_as_completed_increases_delivery_balance_by_85_percent_of_order_trip( self, a_client, a_client_user, an_order, a_delivery_user): Rule(name='$20 base', conditions=[], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value='20')).save() self.login(a_client, a_client_user.email, a_client_user.password) self.patch(a_client, 'api/v1/orders/{}'.format(str(an_order.id)), {'delivery': a_delivery_user.id}) self.patch(a_client, 'api/v1/orders/{}'.format(str(an_order.id)), {'status': Order.DELIVERED_STATUS}) assert Order.objects.get(id=an_order.id).delivery.balance == 0.85 * 20
def test_minimum_delivery_cost(self, mocked_get, an_order, a_distance_response): mocked_get.return_value = a_distance_response(1) Rule(name='Minimum delivery cost of $20', conditions=[ RuleCondition(variable=RuleCondition.ORDER_DISTANCE, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='0'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=20)).save() self.assert_price(an_order, 20)
def test_create_benefit_redeemable_rule_without_cost_sets_it_to_zero(self): rule = Rule( name='Minimum delivery cost of $10 for premium users', conditions=[ RuleCondition(variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='0'), ], consequence=RuleConsequence(consequence_type=RuleConsequence.VALUE, value=10), benefit=True, redeemable=True, ).save() assert rule.cost == 0
def test_benefit_rules_do_not_apply_to_flat_users(self, a_customer_user, an_order): an_order.owner = a_customer_user an_order.save() Rule(name='Minimum delivery cost of $10 for premium users', conditions=[ RuleCondition(variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='0'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=10), benefit=True).save() assert not self.rule_service.quote_price(an_order.id)
def test_100_discount_on_first_order(self, an_order_factory): an_order = an_order_factory() Rule(name='$100 discount on first order', conditions=[ RuleCondition(variable=RuleCondition.ORDER_QUANTITY, operator=RuleCondition.IS, condition_value='1'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=-100)).save() self.assert_price(an_order, 0) an_order_factory() self.assert_price(an_order, 0)
def _decorator(self, *args, **kwargs): jt = JobTemplate(log_level=LogLevel.complete, name="Gob") r = Rule(condition=RuleCondition.if_col_present, conditional={'column': 'id'}, checks=[ Check(check_type=CheckType.uniqueness, check_metadata={'column': 'id'}) ]) jt.data_sources.append(self.dummy_datasource()) jt.rules.append(r) self.s.add_all([jt, r]) # Actually runs the job jr = JobRun.create_job_run(jt) # Refresh Obj from DB jr = self.s.query(JobRun).get(jr.id) jt = self.s.query(JobTemplate).get(jt.id) func(self, jt, jr)
def test_should_not_apply_rule_if_its_not_active(self, an_order): rule = Rule(name='$20 base', conditions=[ RuleCondition( variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='0'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=20, )).save() rule.active = False rule.save() assert self.rule_service.quote_price(an_order.id) == 0
def test_quote_order_returns_order_quotation(self, a_client, a_client_user, an_order): Rule(name='$20 base', conditions=[ RuleCondition(variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='0') ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value='20')).save() self.login(a_client, a_client_user.email, a_client_user.password) response = self.get( a_client, 'api/v1/orders/{}/quotation'.format(str(an_order.id))) assert_200(response) assert json.loads(response.data) == {'price': 20}
def test_quote_price_with_location_rule(self, mocked_get, an_order, a_geocode_response): mocked_get.return_value = a_geocode_response('Ingeniero Maschwitz') # Ing Maschwitz an_order.owner.location.latitude = -34.3814 an_order.owner.location.longitude = -58.7569 an_order.owner.save() Rule(name='$200 if order is in Ingeniero Maschwitz', conditions=[ RuleCondition(variable=RuleCondition.ORDER_POSITION, operator=RuleCondition.IS, condition_value='Ingeniero Maschwitz'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=200)).save() assert self.rule_service.quote_price(an_order.id) == 200
def test_redeemable_benefits_apply_to_users_with_the_benefit( self, a_customer_user, an_order): an_order.owner = a_customer_user an_order.save() Rule(name='Minimum delivery cost of $10 for premium users', conditions=[ RuleCondition(variable=RuleCondition.USER_REPUTATION, operator=RuleCondition.GREATER_THAN_EQUAL, condition_value='0'), ], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=10), benefit=True, redeemable=True, redeemed_by=[a_customer_user.id]).save() assert self.rule_service.quote_price(an_order.id) == 10
async def add_rule_by_admin( self, ctx, name: str, channel: discord.TextChannel, emoji: str, reward_sticker: Optional[int], reward_role: Optional[discord.Role], ): with session_scope() as session: rule = Rule( name=name, by_admin=True, channel_id=channel.id, emoji=str(emoji) ) if reward_sticker is not None: rule.reward_sticker = reward_sticker if reward_role is not None: rule.reward_role_id = reward_role.id session.add(rule) session.commit() self.bot.logger.info("rule add: " + repr(rule)) await ctx.send(f"규칙 #{rule.id} 추가됨!")
def CreateRule(self, ruleText): name = str() terms = list() # List of Terms result = None # Term type ruleLine = ruleText self.__CheckRuleLineIsValid(ruleLine) # get rule name ruleName = ruleLine\ .split(":")[0]\ .strip() name = ruleName # remove parsed data rule name ruleLine = re.split(" if ", ruleLine, flags=re.IGNORECASE)[1]\ .strip() firstTerm = self.CreateTerm(ruleLine) firstTerm.LogicalConnective = LogicalConnectiveEnum.If terms.append(firstTerm) # remove parsed initial term ruleLine = " " + ruleLine\ .split(firstTerm.VariableValue, 1)[1][firstTerm.ClosingParenthesesCount:]\ .strip() # get result text resultText = re.split(" then ", ruleLine, flags=re.IGNORECASE)[1]\ .strip() result = self.CreateTerm(resultText) result.LogicalConnective = LogicalConnectiveEnum.Then # remove result text, add a white space to make the replace symmetric # this just makes sure we replace and ruleLine = " " + re.split(" then ", ruleLine, flags=re.IGNORECASE)[0]\ .strip() if not ruleLine.strip(): # we dont have chained antecedents, break earlier rule = Rule(name, terms, result) return rule # chained and/or connectives, this is just a hacky way of making sure # we split all connectives. # this however might break on unknown connectives. chainedTerms = ruleLine\ .replace(" and ", "#and# ")\ .replace(" or ", " #or# ")\ .split("#") # safely remove all nones and white space whiteSpaceInTerms = [ term for term in chainedTerms if (term.isspace() or not term) ] for whiteSpace in whiteSpaceInTerms: chainedTerms.remove(whiteSpace) # add subsequent terms for i in range(0, len(chainedTerms), 2): connectiveText = chainedTerms[i]\ .strip() termText = chainedTerms[i + 1] logicalConnective = \ LogicalConnectiveEnum.And if connectiveText == str(LogicalConnectiveEnum.And) \ else LogicalConnectiveEnum.Or if connectiveText == str(LogicalConnectiveEnum.Or) \ else LogicalConnectiveEnum._None if (logicalConnective == LogicalConnectiveEnum._None): # something not right, cannot have subsequent terms with # None or unknown connectives print( "Incorrect Logical Connective used for subsequent term - ", chainedVariableConnectiveText) continue chainedTerm = self.CreateTerm(termText) chainedTerm.LogicalConnective = logicalConnective terms.append(chainedTerm) rule = Rule(name, terms, result) return rule
def test_should_return_zero_if_no_conditions(self, a_consequence, an_order): Rule(name='new rule', conditions=[], consequence=a_consequence).save() assert self.rule_service.quote_price(an_order.id) == 0
def test_should_apply_consequence_if_no_condition(self, an_order): Rule(name='new rule', conditions=[], consequence=RuleConsequence( consequence_type=RuleConsequence.VALUE, value=5)).save() assert self.rule_service.quote_price(an_order.id) == 5