コード例 #1
0
    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)
コード例 #2
0
    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
コード例 #3
0
    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)
コード例 #4
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
コード例 #5
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
コード例 #6
0
    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} 추가됨!")
コード例 #7
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'})
                     ],
                     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)
コード例 #8
0
    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)
コード例 #9
0
    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
コード例 #10
0
    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
コード例 #11
0
    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
コード例 #12
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
コード例 #13
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)
コード例 #14
0
 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()
コード例 #15
0
    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)
コード例 #16
0
    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
コード例 #17
0
    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
コード例 #18
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)
コード例 #19
0
    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
コード例 #20
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)
コード例 #21
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)
コード例 #22
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)
コード例 #23
0
    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
コード例 #24
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}
コード例 #25
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
コード例 #26
0
    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
コード例 #27
0
    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} 추가됨!")
コード例 #28
0
    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
コード例 #29
0
 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
コード例 #30
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