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_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_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_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
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_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_apply_with_value_per_unit_should_multiple_value_by_condition_variable( self, mocked_distance, a_client, an_order): # pylint: disable=unused-argument mocked_distance.return_value = 10 consequence = RuleConsequence( consequence_type=RuleConsequence.PER_UNIT_VALUE, value=-10, variable=RuleCondition.ORDER_DISTANCE) result = self.consequence_service.apply(consequence, 200, an_order) assert result == 100
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_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_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_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_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_redeemable_rule_should_be_benefit(self): with pytest.raises(ValidationError): self.rule_service.create( 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=False, redeemable=True, )
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_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_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_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 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_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_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
def a_consequence(): return RuleConsequence(consequence_type=RuleConsequence.VALUE, value=0)
def test_apply_with_negative_value_should_reduce_it(self): consequence = RuleConsequence(consequence_type=RuleConsequence.VALUE, value=-1) result = self.consequence_service.apply(consequence, 10) assert result == 9
def test_apply_with_percentage_should_add_right_value(self): consequence = RuleConsequence( consequence_type=RuleConsequence.PERCENTAGE, value=10) result = self.consequence_service.apply(consequence, 10) assert result == 11.0
def test_apply_with_percentage_and_negative_value_should_reduce(self): consequence = RuleConsequence( consequence_type=RuleConsequence.PERCENTAGE, value=-10) result = self.consequence_service.apply(consequence, 10) assert result == 9.0
def test_apply_with_positive_value_adds_it(self): consequence = RuleConsequence(consequence_type=RuleConsequence.VALUE, value=1) result = self.consequence_service.apply(consequence, 10) assert result == 11
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