Exemplo n.º 1
0
    def test_balance(self):
        url = reverse('merchant-balance')
        response = self.client.get(url, Token=self.token)
        resp_json = response.json()
        self.assertEqual(
            resp_json,
            dict(
                wechat_balance=1000,
                wechat_withdrawable_balance=500.05,
                alipay_balance=2000,
                alipay_withdrawable_balance=1000.05,
                wechat_nickname=self.merchant_admin.wechat_nickname,
                alipay_user_name=self.merchant_admin.alipay_user_name,
            ))

        with self.not_change_account():
            # 更改可提现余额为0.99
            self.account.withdrawable_balance = set_amount(0.99)
            self.account.alipay_withdrawable_balance = set_amount(0.99)
            self.account.save()
            # 检查可提现金额显示为0.99(前端显示为0)
            response = self.client.get(url, Token=self.token)
            resp_json = response.json()
            self.assertEqual(
                resp_json,
                dict(
                    wechat_balance=1000,
                    wechat_withdrawable_balance=0.99,
                    alipay_balance=2000,
                    alipay_withdrawable_balance=0.99,
                    wechat_nickname=self.merchant_admin.wechat_nickname,
                    alipay_user_name=self.merchant_admin.alipay_user_name,
                ))
Exemplo n.º 2
0
    def setUpTestData(cls):
        cls.factory = PayunionFactory()

        # 商户分类
        cls.merchant_category = None
        for p in range(4):
            parent = cls.factory.create_merchant_category(
                name='parent{}'.format(p))
            for c in range(4):
                cls.merchant_category = cls.factory.create_merchant_category(
                    parent=parent, name='{}_child{}'.format(parent.name, c))

        # 商户街道
        for p in range(4):
            parent = cls.factory.create_area(name='市{}'.format(p))
            for c in range(4):
                child = cls.factory.create_area(parent=parent,
                                                name='{}_区{}'.format(
                                                    parent.name, c))
                for cc in range(4):
                    cls.area = cls.factory.create_area(
                        parent=child,
                        name='{}_区{}_街道{}'.format(parent.name, c, cc))

        cls.account = cls.factory.create_account(
            balance=set_amount(1000.00),
            withdrawable_balance=set_amount('500.05'),
            alipay_balance=set_amount(2000),
            alipay_withdrawable_balance=set_amount('1000.05'),
            real_name='张三',
            bank_card_number='1234567890123',
            bank_name='中国招商银行成都玉林路支行')

        cls.merchant = cls.factory.create_merchant(
            name='就是这个公司',
            status=MERCHANT_STATUS['USING'],
            account=cls.account,
            area=cls.area,
            category=cls.merchant_category,
            avatar_url='https://merchant_avatar.jpg',
            photo_url='https://merchant_photo.jpg',
            id_card_back_url=True,
            id_card_front_url=True,
            day_begin_minute=8 * 60,  # 商户订单日结时间设置为08:00
        )
        cls.merchant_admin = cls.factory.create_merchant_admin(
            merchant_admin_type=MERCHANT_ADMIN_TYPES['ADMIN'],
            work_merchant=cls.merchant,
            wechat_nickname='张微信',
            alipay_user_name='张付宝',
            voice_on=True)
        cls.merchant_cashier = cls.factory.create_merchant_admin(
            merchant_admin_type=MERCHANT_ADMIN_TYPES['CASHIER'],
            work_merchant=cls.merchant)

        # 创建token并缓存, 绕过登录
        super(TestMerchantViewSet, cls).setUpTestData()
Exemplo n.º 3
0
    def setUpTestData(cls):
        cls.factory = PayunionFactory()
        cls.account = cls.factory.create_account(
            balance=set_amount(1000.00),
            withdrawable_balance=set_amount('500.05'),
            alipay_balance=set_amount(2000),
            alipay_withdrawable_balance=set_amount(0.99),
            bank_card_number='1234567890123'
        )
        cls.merchant = cls.factory.create_merchant(
            name='就是这个公司',
            account=cls.account,
            day_begin_minute=8 * 60,  # 商户订单日结时间设置为08:00
        )
        cls.merchant_admin = cls.factory.create_merchant_admin(
            status=SYSTEM_USER_STATUS['USING'],
            work_merchant=cls.merchant,
            merchant_admin_type=MERCHANT_ADMIN_TYPES['ADMIN']

        )
        cls.manager = MerchantManager(cls.merchant)

        # create cashiers
        cls.normal_cashier_a = cls.factory.create_merchant_admin(
            status=SYSTEM_USER_STATUS['USING'],
            work_merchant=cls.merchant,
            merchant_admin_type=MERCHANT_ADMIN_TYPES['CASHIER']
        )

        cls.normal_cashier_b = cls.factory.create_merchant_admin(
            status=SYSTEM_USER_STATUS['USING'],
            work_merchant=cls.merchant,
            merchant_admin_type=MERCHANT_ADMIN_TYPES['CASHIER']
        )

        cls.other_merchant_cashier = cls.factory.create_merchant_admin(
            status=SYSTEM_USER_STATUS['USING'],
            merchant_admin_type=MERCHANT_ADMIN_TYPES['CASHIER']
        )

        cls.disabled_cashier = cls.factory.create_merchant_admin(
            status=SYSTEM_USER_STATUS['DISABLED'],
            work_merchant=cls.merchant,
            merchant_admin_type=MERCHANT_ADMIN_TYPES['CASHIER']
        )
Exemplo n.º 4
0
    def test_account_wechat_withdraw_balance(self):
        # 能正确查询到商户账户微信可提现余额
        self.assertEqual(self.manager.account_wechat_withdraw_balance, 500.05)

        # 修改余额为0.01后不足微信最小可提现余额, 可提现余额逻辑显示为0.01(前端显示为0)
        with self.not_change_account():
            self.account.withdrawable_balance = set_amount('0.01')
            self.account.save()
            self.assertEqual(self.manager.account_wechat_withdraw_balance, 0.01)
Exemplo n.º 5
0
 def create_marketer(cls, user):
     account = cls.factory.create_account(
         balance=set_amount(10),
         withdrawable_balance=set_amount('0.50'),
         alipay_balance=set_amount('15006.50'),
         alipay_withdrawable_balance=set_amount('15006.50'),
         real_name=user['name'])
     cls.marketer = cls.factory.create_marketer(
         wechat_openid=user['openid'],
         wechat_unionid=user['unionid'],
         inviter_type=MARKETER_TYPES[user['type']],
         status=SYSTEM_USER_STATUS['USING'],
         name=user['name'],
         phone='13333333333',
         id_card_front_url=cls.C.id_card_front_url,
         id_card_back_url=cls.C.id_card_back_url,
         account=account,
     )
Exemplo n.º 6
0
    def test_alipay_wechat_withdraw_balance(self):
        # 不足支付宝最小可提现余额, 可提现余额逻辑显示为0
        self.assertEqual(self.manager.account_alipay_withdraw_balance, 0.99)

        # 修改余额为100.3后能正确查询到
        with self.not_change_account():
            self.account.alipay_withdrawable_balance = set_amount('100.3')
            self.account.save()
            self.assertEqual(self.manager.account_alipay_withdraw_balance, 100.3)
Exemplo n.º 7
0
 def _create_coupon_rule(self):
     self.coupon_rule = self.factory.create_coupon_rule(
         merchant=self.merchant,
         discount=set_amount(100.1),
         min_charge=set_amount(300),
     )
     for day in (Config.day_1, Config.day_2, Config.day_3, Config.day_4):
         for i in range(20):
             coupon = self.factory.create_coupon(
                 rule=self.coupon_rule,
                 status=(COUPON_STATUS['NOT_USED'],
                         COUPON_STATUS['USED'])[i % 2])
             payment = self.factory.create_payment(
                 order_price=set_amount(300),
                 coupon=coupon,
                 status=PAYMENT_STATUS['FINISHED'],
                 datetime=day)
             self.factory.create_transaction(content_object=payment,
                                             amount=payment.order_price -
                                             self.coupon_rule.discount)
Exemplo n.º 8
0
    def _create_different_type_coupon_rules(self):
        # 指定日期区间
        self.factory.create_coupon_rule(
            merchant=self.merchant,
            discount=set_amount(100),
            min_charge=set_amount(300),
            valid_strategy=VALID_STRATEGY['DATE_RANGE'],
            start_date=Config.jan,
            end_date=Config.feb,
        )

        # 指定有效天数
        self.factory.create_coupon_rule(
            number=10,
            merchant=self.merchant,
            discount=set_amount(1000),
            min_charge=set_amount(3000),
            valid_strategy=VALID_STRATEGY['EXPIRATION'],
            expiration_days=90,
        )
Exemplo n.º 9
0
    def alipay_withdraw(self, amount):
        """支付宝提现 amount为0时不进行任何操作"""
        if amount != 0:
            try:
                alipay_payment.withdraw(self.obj, set_amount(amount))
            except BalanceInsufficient:
                return MerchantError.withdrawable_balance_not_sufficient
            except (ApiRequestError, ApiReturnedError):
                return MerchantError.withdraw_api_error

        return None
Exemplo n.º 10
0
    def validate(self, attrs):
        now = timezone.now()
        # update CouponRule, only has param 'stock'
        if 'discount' not in attrs:
            return attrs

        # create CouponRule
        attrs['discount'] = set_amount(attrs['discount'])
        attrs['min_charge'] = set_amount(attrs['min_charge'])

        # 最低消费 > 优惠减免
        if not float(attrs['discount']) < float(attrs['min_charge']):
            self.fail(MerchantError.min_charge_must_greater_than_discount['error_code'])

        # 指定日期区间时
        if attrs['valid_strategy'] == VALID_STRATEGY['DATE_RANGE']:
            # 必须传入参数start_date与end_date
            if attrs.get('start_date') is None or attrs.get('end_date') is None:
                self.fail(MerchantError.must_have_param_start_date_and_end_date['error_code'])
            # 开始日期 <= 结束日期
            if not attrs['start_date'] <= attrs['end_date']:
                self.fail(MerchantError.end_date_must_greater_than_start_date['error_code'])

            # 时间段:开始时间可选择1年内
            if attrs['start_date'] > now.date().replace(year=now.year + 1):
                self.fail(MerchantError.start_date_must_be_in_1_year['error_code'])

            # 时间段:结束时间按开始时间起计算的1年内
            if attrs['end_date'] > attrs['start_date'].replace(year=now.year + 1):
                self.fail(MerchantError.start_date_must_be_in_1_year_from_start_date['error_code'])

        # 指定有效天数时
        if attrs['valid_strategy'] == VALID_STRATEGY['EXPIRATION']:
            if attrs.get('expiration_days') is None:
                self.fail(MerchantError.must_have_param_expiration_days['error_code'])

        return attrs
Exemplo n.º 11
0
 def create_coupon_rule(
         self,
         number=Config.default_number,
         merchant=None,
         discount=None,
         min_charge=None,
         valid_strategy=None,
         start_date=None,
         end_date=None,
         expiration_days=None,
         stock=None,
         photo_url=None,
         note=None,
         datetime=None,
         update_datetime=None,
 ):
     for _ in range(number):
         e = CouponRule.objects.create(
             merchant=self.create_merchant() if merchant is None else merchant,
             discount=set_amount(choice(Config.discount)) if discount is None else discount,
             min_charge=set_amount(choice(Config.min_charge)) if min_charge is None else min_charge,
             valid_strategy=self.random_choice(VALID_STRATEGY) if valid_strategy is None else valid_strategy,
             start_date=fake.date_time_this_year(before_now=True) if start_date is None else start_date,
             end_date=fake.future_datetime(end_date="+90d", tzinfo=None) if end_date is None else end_date,
             expiration_days=randint(30, 90) if expiration_days is None else expiration_days,
             stock=randint(0, 100) if stock is None else stock,
             photo_url=choice(Config.image_urls) if photo_url is None else photo_url,
             note=fake.text(max_nb_chars=300, ext_word_list=None) if note is None else note,
         )
         if datetime:
             e.datetime = fake.date_time_this_year(before_now=True) if datetime is True else datetime
         if update_datetime:
             e.update_datetime = fake.date_time_this_year(
                 before_now=True) if update_datetime is True else update_datetime
         e.save()
     return e
Exemplo n.º 12
0
    def validate(self, attrs):
        channel = attrs.get('channel')
        amount = attrs.get('amount')

        if channel == PAY_CHANNELS.WECHAT and WECHAT_MAX_WITHDRAW_AMOUNT < amount:
            self.fail(MerchantError.exceeding_the_wechat_maximum_withdrawal_balance['error_code'])

        # 可提现余额不足
        if (channel == PAY_CHANNELS.WECHAT and self.instance.withdrawable_balance < set_amount(
                amount)) \
                or (
                channel == PAY_CHANNELS.ALIPAY and self.instance.alipay_withdrawable_balance < set_amount(
            amount)):
            self.fail(MerchantError.withdrawable_balance_not_sufficient['error_code'])

        return attrs
Exemplo n.º 13
0
    def wechat_withdraw(
            self,
            amount,
            client_ip,
            app_id=dynasettings.SUBSCRIPTION_ACCOUNT_APP_ID_MERCHANT):
        """微信提现 amount为0时不进行任何操作"""
        if amount != 0:
            try:
                wechat_payment.withdraw(self.obj, set_amount(amount),
                                        client_ip, app_id)
            except BalanceInsufficient:
                return MerchantError.withdrawable_balance_not_sufficient
            except (ApiRequestError, ApiReturnedError):
                return MerchantError.withdraw_api_error

        return None
Exemplo n.º 14
0
    def test_serialize_relative_payment(self):
        for day in (Config.day_1, Config.day_2, Config.day_3, Config.day_4):
            payment = self.factory.create_payment(
                coupon=self.factory.create_coupon(rule=self.coupon_rule),
                order_price=set_amount(300),
                datetime=day)
            self.factory.create_transaction(content_object=payment,
                                            amount=payment.order_price -
                                            self.coupon_rule.discount)
        payments = self.manager.relative_payment()[:20]  # page
        data = self.manager.serialize_relative_payment(payments)

        for e in data:
            day = e['month']
            payments = e['cur_page_transactions']
            self.assertTrue(re.match('2018-0[1-4]-01', day))
            self.assertIn(payments[0]['title'], ('微信支付', '支付宝支付'))
            self.assertEqual(payments[0]['desc'], '[满300减100.1优惠券]')
            self.assertTrue(
                re.match('0[1-4]-01 00:00', payments[0]['datetime']))
            self.assertEqual(payments[0]['amount'], 300 - 100.1)
            self.assertIn(payments[0]['status'], ('', '已退款', '退款中'))
Exemplo n.º 15
0
    def set_account_balance(account_instance, amount, channel):
        """
        为instance设置金额
        :param account_instance: Account实例
        :param amount:  设置的金额
        :param channel:  相关渠道
        :return: account对象
        """
        assert isinstance(account_instance, Account)
        amount = set_amount(amount)

        if channel == config.PAY_CHANNELS.ALIPAY:
            account_instance.alipay_balance = amount
            account_instance.alipay_withdrawable_balance = amount
        elif channel == config.PAY_CHANNELS.WECHAT:
            account_instance.balance = amount
            account_instance.withdrawable_balance = amount
        else:
            assert channel in (config.PAY_CHANNELS.WECHAT,
                               config.PAY_CHANNELS.ALIPAY)

        account_instance.save()
        return account_instance
Exemplo n.º 16
0
    def test_merchant_statistics(self):

        first_day = timezone.now().replace(year=2018, month=1, day=1, hour=9)
        second_day = timezone.now().replace(year=2018, month=1, day=2, hour=9)

        # 1. 创建一笔退款订单
        refund_payment = self.factory.create_payment(
            datetime=second_day,
            merchant=self.merchant,
            order_price=set_amount(100),
            status=PAYMENT_STATUS.REFUND
        )

        # 退款订单
        self.factory.create_transaction(
            transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
            datetime=second_day,
            account=self.account,
            amount=set_amount(100),
            content_object=refund_payment
        )
        self.factory.create_transaction(
            transaction_type=TRANSACTION_TYPE.MERCHANT_REFUND,
            datetime=second_day,
            account=self.account,
            amount=-set_amount(100),
            content_object=self.factory.create_refund(
                datetime=second_day, status=REFUND_STATUS.FINISHED, payment=refund_payment)
        )

        # 2. 两天分别创建一笔未支付订单, 一笔优惠订单, 一笔普通订单, 一笔引流收益
        for datetime_ in (first_day, second_day):
            # 未支付订单
            self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.UNPAID,
                merchant=self.merchant,
                order_price=set_amount(100),
            )

            # 优惠券订单
            coupon = self.factory.create_coupon(
                discount=set_amount(10),
                min_charge=set_amount(100),
                status=COUPON_STATUS.USED,
                use_datetime=datetime_,
            )
            use_coupon_payment = self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.FINISHED,
                merchant=self.merchant,
                order_price=set_amount(110),
                coupon=coupon,
                platform_share=set_amount(3),
                originator_share=set_amount(1),
                inviter_share=set_amount(1)
            )
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(95),
                content_object=use_coupon_payment,
            )

            # 普通订单
            not_use_coupon_payment = self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.FINISHED,
                merchant=self.merchant,
                order_price=set_amount(100),
                platform_share=set_amount(0),
                originator_share=set_amount(0),
                inviter_share=set_amount(0)
            )
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(100),
                content_object=not_use_coupon_payment,
            )

            # 引流收益
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_SHARE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(1),
            )

        # 3. 检查第二日
        second_day_begin = second_day.replace(hour=0, minute=0, second=0, microsecond=0)
        result = self.manager.merchant_business_report(
            datetime_start=second_day_begin,
            datetime_end=second_day_begin + timedelta(days=1)
        )
        self.assertEqual(result, {'turnover': 200,
                                  'originator_expenditure': 5,
                                  'originator_earning': 1,
                                  'payment': {'use_coupon': 1, 'not_use_coupon': 2}})

        # 4. 检查第一日
        first_day_begin = first_day.replace(hour=0, minute=0, second=0, microsecond=0)
        result = self.manager.merchant_business_report(
            datetime_start=first_day_begin,
            datetime_end=first_day_begin + timedelta(days=1)
        )
        self.assertEqual(result, {'turnover': 200,
                                  'originator_expenditure': 5,
                                  'originator_earning': 1,
                                  'payment': {'use_coupon': 1, 'not_use_coupon': 1}})
Exemplo n.º 17
0
    def test_business_report(self):
        first_day = timezone.now().replace(year=2018, month=1, day=1, hour=9)
        second_day = timezone.now().replace(year=2018, month=1, day=2, hour=9)

        # 1. 创建一笔退款订单
        refund_payment = self.factory.create_payment(
            datetime=second_day,
            merchant=self.merchant,
            order_price=set_amount(100),
            status=PAYMENT_STATUS.REFUND)

        # 退款订单
        self.factory.create_transaction(
            transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
            datetime=second_day,
            account=self.account,
            amount=set_amount(100),
            content_object=refund_payment)
        self.factory.create_transaction(
            transaction_type=TRANSACTION_TYPE.MERCHANT_REFUND,
            datetime=second_day,
            account=self.account,
            amount=-set_amount(100),
            content_object=self.factory.create_refund(
                datetime=second_day,
                status=REFUND_STATUS.FINISHED,
                payment=refund_payment))

        # 2. 两天分别创建一笔未支付订单, 一笔优惠订单, 一笔普通订单, 一笔引流收益
        for datetime_ in (first_day, second_day):
            # 未支付订单
            self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.UNPAID,
                merchant=self.merchant,
                order_price=set_amount(100),
            )

            # 优惠券订单
            coupon = self.factory.create_coupon(
                discount=set_amount(10),
                min_charge=set_amount(100),
                status=COUPON_STATUS.USED,
                use_datetime=datetime_,
            )
            use_coupon_payment = self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.FINISHED,
                merchant=self.merchant,
                order_price=set_amount(110),
                coupon=coupon,
                platform_share=set_amount(3),
                originator_share=set_amount(1),
                inviter_share=set_amount(1))
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(95),
                content_object=use_coupon_payment,
            )

            # 普通订单
            not_use_coupon_payment = self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.FINISHED,
                merchant=self.merchant,
                order_price=set_amount(100),
                platform_share=set_amount(0),
                originator_share=set_amount(0),
                inviter_share=set_amount(0))
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(100),
                content_object=not_use_coupon_payment,
            )

            # 引流收益
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_SHARE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(1),
            )

        url = reverse('merchant-business_report')

        # 第一日数据
        response = self.client.get(
            url,
            dict(start_date=first_day.strftime('%Y-%m-%d'),
                 end_date=first_day.strftime('%Y-%m-%d')),
            Token=self.token,
            format='json')
        result = response.json()
        self.assertEqual(
            result, {
                'turnover': 200,
                'originator_expenditure': 5,
                'originator_earning': 1,
                'payment': {
                    'use_coupon': 1,
                    'not_use_coupon': 1
                }
            })

        # 第二日数据
        response = self.client.get(
            url,
            dict(start_date=second_day.strftime('%Y-%m-%d'),
                 end_date=second_day.strftime('%Y-%m-%d')),
            Token=self.token,
            format='json')
        result = response.json()
        self.assertEqual(
            result, {
                'turnover': 200,
                'originator_expenditure': 5,
                'originator_earning': 1,
                'payment': {
                    'use_coupon': 1,
                    'not_use_coupon': 2
                }
            })

        # 第1-10日数据
        response = self.client.get(
            url,
            dict(start_date=first_day.strftime('%Y-%m-%d'),
                 end_date=(first_day +
                           timedelta(days=9)).strftime('%Y-%m-%d')),
            Token=self.token,
            format='json')
        result = response.json()
        self.assertEqual(
            result, {
                'turnover': 400,
                'originator_expenditure': 10,
                'originator_earning': 2,
                'payment': {
                    'use_coupon': 2,
                    'not_use_coupon': 3
                }
            })
Exemplo n.º 18
0
    def _create_transactions(self):
        # 1月2月3月4月5月 一个月对应创建一条 提现/普通订单/优惠券订单/分成/结算transaction
        # 提现
        self.withdraw = self.factory.create_withdraw(
            withdraw_type=WITHDRAW_TYPE.ALIPAY,
            account=self.account,
            amount=set_amount(Config.withdraw),
            datetime=Config.jan,
            status=WITHDRAW_STATUS['PROCESSING']
        )
        self.withdraw_transaction = self.factory.create_transaction(
            content_object=self.withdraw,
            account=self.account,
            datetime=Config.jan,
            amount=set_amount(Config.withdraw),
            transaction_type=TRANSACTION_TYPE['MERCHANT_WITHDRAW'])

        # 普通订单
        self.payment_without_coupon = self.factory.create_payment(
            merchant=self.merchant,
            datetime=Config.feb,
            pay_channel=PAY_CHANNELS['WECHAT'],
            note='这是一个普通订单',
            status=PAYMENT_STATUS['REFUND'],
            order_price=set_amount(Config.receive),
        )
        self.payment_without_coupon_transaction = self.factory.create_transaction(
            content_object=self.payment_without_coupon,
            account=self.account,
            datetime=Config.feb,
            amount=set_amount(Config.receive),
            transaction_type=TRANSACTION_TYPE['MERCHANT_RECEIVE'])

        # 优惠券订单
        coupon = self.factory.create_coupon(
            rule=self.factory.create_coupon_rule(discount=set_amount(100),
                                                 min_charge=set_amount(300)))
        self.payment_with_coupon = self.factory.create_payment(
            merchant=self.merchant,
            datetime=Config.mar,
            pay_channel=PAY_CHANNELS['ALIPAY'],
            note='这是一个优惠券订单',
            status=PAYMENT_STATUS['FROZEN'],
            coupon=coupon,
            order_price=set_amount(200.1),
            platform_share=set_amount(33),
            inviter_share=set_amount(33),
            originator_share=set_amount(34),
        )
        self.payment_with_coupon_transaction = self.factory.create_transaction(
            content_object=self.payment_with_coupon,
            account=self.account,
            datetime=Config.mar,
            amount=set_amount(Config.receive),
            transaction_type=TRANSACTION_TYPE['MERCHANT_RECEIVE'],
        )

        # 引流收益订单
        share_merchant = self.factory.create_merchant(name='引流到达的商户')
        coupon = self.factory.create_coupon(
            rule=self.factory.create_coupon_rule(discount=set_amount(100),
                                                 min_charge=set_amount(300)))
        self.share_payment = self.factory.create_payment(
            coupon=coupon,
            datetime=Config.apr,
            status=PAYMENT_STATUS['FINISHED'],
            merchant=share_merchant,
            order_price=set_amount(200.1),
            platform_share=set_amount(33),
            inviter_share=set_amount(33),
            originator_share=set_amount(34),
        )
        self.share_transaction = self.factory.create_transaction(
            content_object=self.share_payment,
            account=self.account,
            datetime=Config.apr + timedelta(hours=2),
            amount=set_amount(Config.share),
            transaction_type=TRANSACTION_TYPE['MERCHANT_SHARE'])

        # 企业商户结算
        self.settlement = self.factory.create_settlement(
            status=SETTLEMENT_STATUS.FINISHED,
            account=self.account,
            datetime=Config.may,
            finished_datetime=Config.may + timedelta(hours=1),
            wechat_amount=set_amount(-Config.wechat_settlement),
            alipay_amount=set_amount(-Config.alipay_settlement),
        )
        self.settlement_transaction = self.factory.create_transaction(
            content_object=self.settlement,
            account=self.account,
            datetime=Config.may,
            amount=set_amount(Config.withdraw / 2),
            transaction_type=TRANSACTION_TYPE['MERCHANT_WECHAT_SETTLEMENT'])
        self.factory.create_transaction(
            content_object=self.settlement,
            account=self.account,
            datetime=Config.may,
            amount=set_amount(Config.withdraw / 2),
            transaction_type=TRANSACTION_TYPE['MERCHANT_ALIPAY_SETTLEMENT'])
Exemplo n.º 19
0
    def test_create(self):

        # 指定日期范围
        url = reverse('coupon-list')
        coupon_rule_json = dict(discount=100,
                                min_charge='300',
                                valid_strategy=VALID_STRATEGY['DATE_RANGE'],
                                start_date='2018-01-01',
                                end_date='2018-01-01',
                                stock=100,
                                photo_url='a url',
                                note='a note')
        response = self.client.post(url,
                                    data=coupon_rule_json,
                                    Token=self.token,
                                    format='json')  # auth by token
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        resp_json = response.json()

        # 检查response
        expect = copy.copy(coupon_rule_json)
        expect.update(
            dict(
                discount=coupon_rule_json['discount'],
                min_charge=int(coupon_rule_json['min_charge']),
                expiration_days=None,
            ))
        self.assertEqual(resp_json, expect)

        # 检查创建的coupon_rule
        coupon_rule = CouponRule.objects.filter(
            merchant=self.merchant, stock=coupon_rule_json['stock']).first()
        self.assertEqual(coupon_rule.discount,
                         set_amount(coupon_rule_json['discount']))
        self.assertEqual(coupon_rule.min_charge,
                         set_amount(coupon_rule_json['min_charge']))
        self.assertEqual(coupon_rule.valid_strategy,
                         coupon_rule_json['valid_strategy'])
        self.assertEqual(str(coupon_rule.start_date),
                         coupon_rule_json['start_date'])
        self.assertEqual(str(coupon_rule.end_date),
                         coupon_rule_json['end_date'])
        self.assertEqual(coupon_rule.expiration_days, None)
        self.assertEqual(coupon_rule.stock, coupon_rule_json['stock'])
        self.assertEqual(coupon_rule.photo_url, coupon_rule_json['photo_url'])
        self.assertEqual(coupon_rule.note, coupon_rule_json['note'])

        # 参数格式不正确  减免金额小于最低消费
        data = copy.copy(coupon_rule_json)
        data.update(dict(
            discount=101,
            min_charge=100,
        ))
        response = self.client.post(url,
                                    data=data,
                                    Token=self.token,
                                    format='json')  # auth by token
        resp_json = response.json()
        self.assertEqual(
            resp_json,
            NonFieldError(MerchantError.min_charge_must_greater_than_discount))

        # 参数格式不正确  无start_date 或 end_date
        data = copy.copy(coupon_rule_json)
        del data['start_date']
        response = self.client.post(url,
                                    data=data,
                                    Token=self.token,
                                    format='json')  # auth by token
        resp_json = response.json()
        self.assertEqual(
            resp_json,
            NonFieldError(
                MerchantError.must_have_param_start_date_and_end_date))

        # 参数格式不正确  需 start_date <= end_date
        data = copy.copy(coupon_rule_json)
        data.update(dict(
            start_date='2018-03-01',
            end_date='2018-01-01',
        ))
        response = self.client.post(url,
                                    data=data,
                                    Token=self.token,
                                    format='json')  # auth by token
        resp_json = response.json()
        self.assertEqual(
            resp_json,
            NonFieldError(MerchantError.end_date_must_greater_than_start_date))

        # 指定有效天数
        coupon_rule_json = dict(discount=100,
                                min_charge='300',
                                valid_strategy=VALID_STRATEGY['EXPIRATION'],
                                expiration_days=90,
                                stock=200,
                                photo_url='another url',
                                note='another note')
        response = self.client.post(url,
                                    data=coupon_rule_json,
                                    Token=self.token,
                                    format='json')  # auth by token
        resp_json = response.json()

        # 检查response
        expect = copy.copy(coupon_rule_json)
        expect.update(
            dict(
                discount=coupon_rule_json['discount'],
                min_charge=float(coupon_rule_json['min_charge']),
                start_date=None,
                end_date=None,
            ))
        self.assertEqual(resp_json, expect)

        # 检查创建的coupon_rule
        coupon_rule = CouponRule.objects.filter(
            merchant=self.merchant, stock=coupon_rule_json['stock']).first()
        self.assertEqual(coupon_rule.valid_strategy,
                         coupon_rule_json['valid_strategy'])
        self.assertEqual(coupon_rule.start_date, None)
        self.assertEqual(coupon_rule.end_date, None)
        self.assertEqual(coupon_rule.expiration_days,
                         coupon_rule_json['expiration_days'])

        # 参数格式不正确  指定有效天数时无expiration_days
        data = copy.copy(coupon_rule_json)
        del data['expiration_days']
        response = self.client.post(url,
                                    data=data,
                                    Token=self.token,
                                    format='json')  # auth by token
        resp_json = response.json()
        self.assertEqual(
            resp_json,
            NonFieldError(MerchantError.must_have_param_expiration_days))

        # 有效天数不正确需>0
        data = copy.copy(coupon_rule_json)
        data['expiration_days'] = 0
        response = self.client.post(url,
                                    data=data,
                                    Token=self.token,
                                    format='json')  # auth by token
        resp_json = response.json()
        self.assertEqual(resp_json, {
            'expiration_days': ['请确保该值大于或者等于 1。'],
            'error_code': 'min_value'
        })

        # 参数格式不正确 满减金额与最低消费必须为整数
        # 指定有效天数
        coupon_rule_json = dict(discount=100,
                                min_charge='300.01',
                                valid_strategy=VALID_STRATEGY['EXPIRATION'],
                                expiration_days=90,
                                stock=200,
                                photo_url='another url',
                                note='another note')
        response = self.client.post(url,
                                    data=coupon_rule_json,
                                    Token=self.token,
                                    format='json')  # auth by token
        resp_json = response.json()
        self.assertEqual(resp_json, {
            'min_charge': ['请确保总计不超过 0 个小数位。'],
            'error_code': 'max_decimal_places'
        })
Exemplo n.º 20
0
    def test_statistics(self):

        yesterday = timezone.now().replace(hour=1)
        today = timezone.now().replace(hour=9)

        # 1. 今日创建一笔退款订单
        refund_payment = self.factory.create_payment(
            datetime=today,
            merchant=self.merchant,
            order_price=set_amount(100),
            status=PAYMENT_STATUS.REFUND)

        # 退款订单
        self.factory.create_transaction(
            transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
            datetime=today,
            account=self.account,
            amount=set_amount(100),
            content_object=refund_payment)
        self.factory.create_transaction(
            transaction_type=TRANSACTION_TYPE.MERCHANT_REFUND,
            datetime=today,
            account=self.account,
            amount=-set_amount(100),
            content_object=self.factory.create_refund(
                datetime=today,
                status=REFUND_STATUS.FINISHED,
                payment=refund_payment))

        # 2. 昨日今日分别创建一笔未支付订单, 一笔优惠订单, 一笔普通订单, 一笔引流收益
        for datetime_ in (yesterday, today):
            # 未支付订单
            self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.UNPAID,
                merchant=self.merchant,
                order_price=set_amount(100),
            )

            # 优惠券订单
            coupon = self.factory.create_coupon(
                discount=set_amount(10),
                min_charge=set_amount(100),
                status=COUPON_STATUS.USED,
                use_datetime=datetime_,
            )
            use_coupon_payment = self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.FINISHED,
                merchant=self.merchant,
                order_price=set_amount(110),
                coupon=coupon,
                platform_share=set_amount(3),
                originator_share=set_amount(1),
                inviter_share=set_amount(1))
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(95),
                content_object=use_coupon_payment,
            )

            # 普通订单
            not_use_coupon_payment = self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.FINISHED,
                merchant=self.merchant,
                order_price=set_amount(100),
                platform_share=set_amount(0),
                originator_share=set_amount(0),
                inviter_share=set_amount(0))
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(100),
                content_object=not_use_coupon_payment,
            )

            # 引流收益
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_SHARE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(1),
            )

        url = reverse('merchant-statistics')
        response = self.client.get(url, Token=self.token)
        statistics = response.json()
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            statistics, {
                'name': '就是这个公司',
                'status': self.merchant.status,
                'avatar_url': self.merchant.avatar_url,
                'wechat_balance': 1000,
                'alipay_balance': 2000,
                'turnover': 200,
                'originator_expenditure': 5,
                'originator_earning': 1,
                'payment': {
                    'use_coupon': 1,
                    'not_use_coupon': 2
                }
            })  # 订单数要计算退款订单
Exemplo n.º 21
0
    def _create_transactions(self):
        # 1月2月3月5月, 每月分别创建2条 营业额/提现/分成transaction
        share_merchant = self.factory.create_merchant(name='引流到达的商户')
        for time in (Config.jan, Config.feb, Config.mar, Config.may):
            for i in range(2):
                # 提现
                withdraw = self.factory.create_withdraw(
                    withdraw_type=WITHDRAW_TYPE.ALIPAY if i %
                    2 else WITHDRAW_TYPE.WECHAT,
                    account=self.account,
                    amount=set_amount(-Config.withdraw),
                    datetime=time)
                self.factory.create_transaction(
                    content_object=withdraw,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.withdraw),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_WITHDRAW'])

                # 企业商户结算
                settlement = self.factory.create_settlement(
                    status=SETTLEMENT_STATUS.FINISHED,
                    account=self.account,
                    finished_datetime=time,
                    wechat_amount=set_amount(-Config.wechat_settlement),
                    alipay_amount=set_amount(-Config.alipay_settlement),
                )
                self.factory.create_transaction(
                    content_object=settlement,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.withdraw / 2),
                    transaction_type=TRANSACTION_TYPE[
                        'MERCHANT_WECHAT_SETTLEMENT'])
                self.factory.create_transaction(
                    content_object=settlement,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.withdraw / 2),
                    transaction_type=TRANSACTION_TYPE[
                        'MERCHANT_ALIPAY_SETTLEMENT'])

                coupon_rule = self.factory.create_coupon_rule(
                    discount=set_amount(100), min_charge=set_amount(300))

                # 支付成功
                coupon = self.factory.create_coupon(rule=coupon_rule)
                payment = self.factory.create_payment(
                    merchant=self.merchant,
                    datetime=time,
                    coupon=coupon,
                    status=PAYMENT_STATUS['FINISHED'])
                self.factory.create_transaction(
                    content_object=payment,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.receive),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_RECEIVE'])

                # 退款
                coupon = self.factory.create_coupon(rule=coupon_rule)
                payment = self.factory.create_payment(
                    merchant=self.merchant,
                    datetime=time,
                    coupon=coupon,
                    status=PAYMENT_STATUS['REFUND'])
                self.factory.create_transaction(
                    content_object=payment,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.receive),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_RECEIVE'])
                self.factory.create_transaction(
                    content_object=payment,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(-Config.receive),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_REFUND'])

                # 引流分成
                coupon_rule = self.factory.create_coupon_rule(
                    merchant=self.merchant)
                share = self.factory.create_payment(
                    coupon=self.factory.create_coupon(
                        rule=coupon_rule, originator_merchant=self.merchant),
                    datetime=time,
                    merchant=share_merchant)
                self.factory.create_transaction(
                    content_object=share,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.share),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_SHARE'])
Exemplo n.º 22
0
    def create_merchant(cls, user):
        # 商户account
        account = cls.factory.create_account(
            balance=set_amount(10),
            withdrawable_balance=set_amount('0.50'),
            alipay_balance=set_amount('15006.50'),
            alipay_withdrawable_balance=set_amount('15006.50'),
            real_name=user['name'])

        # 付款二维码, 使用唯一可测试的code
        payment_qr_code = cls.factory.create_payment_qrcode(uuid='129d3209ad9f87771719df50347492d9') \
            if 'qr_code_uuid' in user else None

        # 商户
        merchant = cls.factory.create_merchant(
            name=f"一家咖啡店({user['name']}店)",
            status=MERCHANT_STATUS['USING'],
            location_lat=30.533743,
            location_lon=104.068197,
            account=account,
            area=cls.area,
            category=cls.merchant_category,
            inviter=cls.marketer,
            avatar_url=cls.C.avatar_url,
            photo_url=cls.C.photo_url,
            id_card_back_url=cls.C.id_card_back_url,
            id_card_front_url=cls.C.id_card_front_url,
            payment_qr_code=payment_qr_code)
        cls.factory.create_merchant_admin(
            wechat_openid=user['openid'],
            wechat_unionid=user['unionid'],
            merchant_admin_type=MERCHANT_ADMIN_TYPES['ADMIN'],
            work_merchant=merchant,
            wechat_nickname=user['name'])

        # 创建投放完成的优惠券
        coupon_rule = cls.factory.create_coupon_rule(merchant=merchant,
                                                     stock=0)

        share_merchant = cls.factory.create_merchant(
            name='通过发优惠券引流客户到达的商户',
            area=cls.area,
            category=cls.merchant_category,
            inviter=cls.marketer,
        )
        grant_coupon_merchant = cls.factory.create_merchant(
            name='发优惠券的商户',
            area=cls.area,
            category=cls.merchant_category,
            inviter=cls.marketer,
        )

        cls.factory.create_coupon(number=1,
                                  rule=coupon_rule,
                                  status=COUPON_STATUS['NOT_USED'],
                                  originator_merchant=grant_coupon_merchant,
                                  use_datetime=timezone.now())
        cls.factory.create_coupon(number=2,
                                  rule=coupon_rule,
                                  status=COUPON_STATUS['USED'],
                                  originator_merchant=grant_coupon_merchant,
                                  use_datetime=timezone.now())
        cls.factory.create_coupon(number=4,
                                  rule=coupon_rule,
                                  status=COUPON_STATUS['DESTROYED'],
                                  originator_merchant=grant_coupon_merchant,
                                  use_datetime=timezone.now())
        cls.factory.create_coupon(number=8,
                                  rule=coupon_rule,
                                  status=COUPON_STATUS['USED'],
                                  originator_merchant=grant_coupon_merchant,
                                  use_datetime=timezone.now().replace(
                                      hour=7,
                                      minute=59,
                                      second=59,
                                      microsecond=0))

        for day in range(10):
            withdraw = cls.factory.create_withdraw(account=account,
                                                   amount=set_amount(
                                                       cls.C.withdraw))
            cls.factory.create_transaction(
                content_object=withdraw,
                account=account,
                datetime=withdraw.datetime,
                transaction_type=TRANSACTION_TYPE['MERCHANT_WITHDRAW'])

            withdraw = cls.factory.create_withdraw(
                withdraw_type=WITHDRAW_TYPE.ALIPAY,
                account=account,
                amount=set_amount(cls.C.withdraw))
            cls.factory.create_transaction(
                content_object=withdraw,
                account=account,
                amount=-withdraw.amount,
                datetime=withdraw.datetime,
                transaction_type=TRANSACTION_TYPE['MERCHANT_WITHDRAW'])

            coupon_rule = cls.factory.create_coupon_rule(
                merchant=merchant,
                datetime=timezone.now(),
                end_date=timezone.now().replace(year=2019))

            coupon = cls.factory.create_coupon(
                rule=coupon_rule,
                originator_merchant=grant_coupon_merchant,
                obtain_datetime=timezone.now() - timedelta(days=day),
                use_datetime=timezone.now() - timedelta(days=day),
            )
            payment = cls.factory.create_payment(
                merchant=merchant,
                coupon=coupon,
                datetime=timezone.now() - timedelta(days=day),
            )
            cls.factory.create_transaction(
                content_object=payment,
                account=account,
                datetime=payment.datetime,
                transaction_type=TRANSACTION_TYPE['MERCHANT_RECEIVE'])

            without_coupon_payment = cls.factory.create_payment(
                merchant=merchant,
                datetime=timezone.now() - timedelta(days=day),
            )
            cls.factory.create_transaction(
                content_object=without_coupon_payment,
                account=account,
                datetime=without_coupon_payment.datetime,
                transaction_type=TRANSACTION_TYPE['MERCHANT_RECEIVE'])

            share = cls.factory.create_payment(
                coupon=cls.factory.create_coupon(
                    rule=coupon_rule,
                    originator_merchant=grant_coupon_merchant),
                datetime=timezone.now() - timedelta(days=day),
                merchant=share_merchant)
            cls.factory.create_transaction(
                content_object=share,
                account=account,
                datetime=share.datetime,
                transaction_type=TRANSACTION_TYPE['MERCHANT_SHARE'])
Exemplo n.º 23
0
 def banlance(min_balance=1, max_balance=10000000):
     return set_amount(randint(min_balance, max_balance))
Exemplo n.º 24
0
 def setUpTestData(cls):
     cls.factory = PayunionFactory()
     cls.coupon_rule = cls.factory.create_coupon_rule(
         discount=set_amount(100.1), min_charge=set_amount(300))
     cls.manager = CouponRuleManager(cls.coupon_rule)
Exemplo n.º 25
0
    def test_merchant_earning_list_by_day(self):
        first_day = timezone.now().replace(year=2018, month=1, day=1, hour=9)
        second_day = timezone.now().replace(year=2018, month=1, day=2, hour=9)
        third_day = timezone.now().replace(year=2018, month=1, day=4, hour=9)

        first_day_begin = first_day.replace(hour=0, minute=0, second=0, microsecond=0)

        # 1. 创建一笔退款订单
        refund_payment = self.factory.create_payment(
            datetime=second_day,
            merchant=self.merchant,
            order_price=set_amount(100),
            status=PAYMENT_STATUS.REFUND
        )

        # 退款订单
        self.factory.create_transaction(
            transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
            datetime=second_day,
            account=self.account,
            amount=set_amount(100),
            content_object=refund_payment
        )
        self.factory.create_transaction(
            transaction_type=TRANSACTION_TYPE.MERCHANT_REFUND,
            datetime=second_day,
            account=self.account,
            amount=-set_amount(100),
            content_object=self.factory.create_refund(
                datetime=second_day, status=REFUND_STATUS.FINISHED, payment=refund_payment)
        )

        # 2. 三天分别创建一笔未支付订单, 一笔优惠订单, 一笔普通订单, 一笔引流收益
        for datetime_ in (first_day, second_day, third_day):
            # 未支付订单
            self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.UNPAID,
                merchant=self.merchant,
                order_price=set_amount(100),
            )

            # 优惠券订单
            coupon = self.factory.create_coupon(
                discount=set_amount(10),
                min_charge=set_amount(100),
                status=COUPON_STATUS.USED,
                use_datetime=datetime_,
            )
            use_coupon_payment = self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.FINISHED,
                merchant=self.merchant,
                order_price=set_amount(110),
                coupon=coupon,
                platform_share=set_amount(3),
                originator_share=set_amount(1),
                inviter_share=set_amount(1)
            )
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(95),
                content_object=use_coupon_payment,
            )

            # 普通订单
            not_use_coupon_payment = self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.FINISHED,
                merchant=self.merchant,
                order_price=set_amount(100),
                platform_share=set_amount(0),
                originator_share=set_amount(0),
                inviter_share=set_amount(0)
            )
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(100),
                content_object=not_use_coupon_payment,
            )

            # 引流收益
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_SHARE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(1),
            )

        result = self.manager.merchant_earning_list_by_day(
            date_start=first_day_begin.date() - timedelta(days=1),
            date_end=first_day_begin.date() + timedelta(days=5)
        )

        self.assertEqual(
            result,
            [{'date': '2017-12-31', 'amount': 0},
             {'date': '2018-01-01', 'amount': 195 + 1},
             {'date': '2018-01-02', 'amount': 195 + 1},
             {'date': '2018-01-03', 'amount': 0},
             {'date': '2018-01-04', 'amount': 195 + 1},
             {'date': '2018-01-05', 'amount': 0},
             {'date': '2018-01-06', 'amount': 0}]
        )
Exemplo n.º 26
0
    def test_update(self):
        self._create_coupon_rule()
        # 修改优惠券库存
        for stock in (0, 1, 300, 301):
            coupon_rule = self.coupon_rule
            old_update_datetime = coupon_rule.update_datetime

            url = reverse('coupon-detail', kwargs=dict(pk=self.coupon_rule.id))
            response = self.client.put(url,
                                       data=dict(stock=stock),
                                       Token=self.token,
                                       format='json')  # auth by token
            detail = response.json()
            self.assertEqual(
                detail,
                dict(
                    discount=get_amount(self.coupon_rule.discount),
                    min_charge=get_amount(self.coupon_rule.min_charge),
                    valid_strategy=self.coupon_rule.valid_strategy,
                    start_date=self.coupon_rule.start_date.strftime(
                        '%Y-%m-%d'),
                    end_date=self.coupon_rule.end_date.strftime('%Y-%m-%d'),
                    expiration_days=self.coupon_rule.expiration_days,
                    stock=stock,
                    photo_url=self.coupon_rule.photo_url,
                    note=self.coupon_rule.note,
                ))

            # 检查修改库存的coupon_rule
            coupon_rule.refresh_from_db()

            self.assertEqual(coupon_rule.discount,
                             set_amount(detail['discount']))
            self.assertEqual(coupon_rule.min_charge,
                             set_amount(detail['min_charge']))
            self.assertEqual(coupon_rule.valid_strategy,
                             detail['valid_strategy'])
            self.assertEqual(str(coupon_rule.start_date), detail['start_date'])
            self.assertEqual(str(coupon_rule.end_date), detail['end_date'])
            self.assertNotEqual(coupon_rule.update_datetime,
                                old_update_datetime)

        # 不存在的优惠券
        url = reverse('coupon-detail', kwargs=dict(pk='id_not_exist'))
        response = self.client.put(url, Token=self.token,
                                   format='json')  # auth by token
        resp_json = response.json()
        self.assertEqual(resp_json, {
            'detail': '未找到。',
            'error_code': 'not_found'
        })

        # 非商户创建的优惠券
        another_coupon_rule = self.factory.create_coupon_rule()
        url = reverse('coupon-detail', kwargs=dict(pk=another_coupon_rule.id))
        response = self.client.put(url, Token=self.token,
                                   format='json')  # auth by token
        resp_json = response.json()
        self.assertEqual(resp_json, {
            'detail': '未找到。',
            'error_code': 'not_found'
        })
Exemplo n.º 27
0
    def test_list_earning(self):

        the_day_before_yesterday = timezone.now() - timedelta(days=2)
        yesterday = timezone.now() - timedelta(days=1)

        # 1. 昨日创建一笔退款订单
        refund_payment = self.factory.create_payment(
            datetime=yesterday,
            merchant=self.merchant,
            order_price=set_amount(100),
            status=PAYMENT_STATUS.REFUND)

        # 退款订单
        self.factory.create_transaction(
            transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
            datetime=yesterday,
            account=self.account,
            amount=set_amount(100),
            content_object=refund_payment)
        self.factory.create_transaction(
            transaction_type=TRANSACTION_TYPE.MERCHANT_REFUND,
            datetime=yesterday,
            account=self.account,
            amount=-set_amount(100),
            content_object=self.factory.create_refund(
                datetime=yesterday,
                status=REFUND_STATUS.FINISHED,
                payment=refund_payment))

        # 2. 前天昨天分别创建一笔未支付订单, 一笔优惠订单, 一笔普通订单, 一笔引流收益
        for datetime_ in (the_day_before_yesterday, yesterday):
            # 未支付订单
            self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.UNPAID,
                merchant=self.merchant,
                order_price=set_amount(100),
            )

            # 优惠券订单
            coupon = self.factory.create_coupon(
                discount=set_amount(10),
                min_charge=set_amount(100),
                status=COUPON_STATUS.USED,
                use_datetime=datetime_,
            )
            use_coupon_payment = self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.FINISHED,
                merchant=self.merchant,
                order_price=set_amount(110),
                coupon=coupon,
                platform_share=set_amount(3),
                originator_share=set_amount(1),
                inviter_share=set_amount(1))
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(95),
                content_object=use_coupon_payment,
            )

            # 普通订单
            not_use_coupon_payment = self.factory.create_payment(
                datetime=datetime_,
                status=PAYMENT_STATUS.FINISHED,
                merchant=self.merchant,
                order_price=set_amount(100),
                platform_share=set_amount(0),
                originator_share=set_amount(0),
                inviter_share=set_amount(0))
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_RECEIVE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(100),
                content_object=not_use_coupon_payment,
            )

            # 引流收益
            self.factory.create_transaction(
                transaction_type=TRANSACTION_TYPE.MERCHANT_SHARE,
                datetime=datetime_,
                account=self.account,
                amount=set_amount(1),
            )

        url = reverse('merchant-list_earning')
        start_date = timezone.now().date().replace(year=timezone.now().year -
                                                   1,
                                                   day=1)
        response = self.client.get(url,
                                   dict(start_date=start_date),
                                   Token=self.token)
        statistics = response.json()
        for earning in statistics:
            date, amount = earning['date'], earning['amount']
            if date in (the_day_before_yesterday.strftime('%Y-%m-%d'),
                        yesterday.strftime('%Y-%m-%d')):
                self.assertEqual(amount, 95 + 100 + 1)
            else:
                self.assertEqual(amount, 0)
Exemplo n.º 28
0
    def test_set_amount(self):
        self.assertEqual(set_amount(0), 0)
        self.assertEqual(set_amount(0.01), 1)
        self.assertEqual(set_amount(300), 30000)
        self.assertEqual(set_amount(300.3), 30030)
        self.assertEqual(set_amount(300.33), 30033)

        self.assertEqual(set_amount('0'), 0)
        self.assertEqual(set_amount('0.01'), 1)
        self.assertEqual(set_amount('300'), 30000)
        self.assertEqual(set_amount('300.00'), 30000)
        self.assertEqual(set_amount('300.3'), 30030)
        self.assertEqual(set_amount('300.30'), 30030)
        self.assertEqual(set_amount('300.33'), 30033)
Exemplo n.º 29
0
    def test_transaction_list(self):
        url = reverse('transaction-list')

        # 1月2月3月5月, 每月分别创建2条 营业额/提现/分成transaction
        share_merchant = self.factory.create_merchant(name='引流到达的商户')
        for time in (Config.jan, Config.feb, Config.mar, Config.may):
            for i in range(2):
                # 提现
                withdraw = self.factory.create_withdraw(
                    withdraw_type=WITHDRAW_TYPE.ALIPAY if i % 2 else WITHDRAW_TYPE.WECHAT,
                    account=self.account,
                    amount=set_amount(-Config.withdraw),
                    datetime=time)
                self.factory.create_transaction(
                    content_object=withdraw,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.withdraw),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_WITHDRAW'])

                coupon_rule = self.factory.create_coupon_rule(discount=set_amount(100),
                                                              min_charge=set_amount(300))

                # 支付成功
                coupon = self.factory.create_coupon(rule=coupon_rule)
                payment = self.factory.create_payment(
                    merchant=self.merchant,
                    datetime=time,
                    coupon=coupon,
                    status=PAYMENT_STATUS['FINISHED']
                )
                self.factory.create_transaction(
                    content_object=payment,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.receive),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_RECEIVE'])

                # 退款
                coupon = self.factory.create_coupon(rule=coupon_rule)
                payment = self.factory.create_payment(
                    merchant=self.merchant,
                    datetime=time,
                    coupon=coupon,
                    status=PAYMENT_STATUS['REFUND']
                )
                self.factory.create_transaction(
                    content_object=payment,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.receive),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_RECEIVE'])
                self.factory.create_transaction(
                    content_object=payment,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(-Config.receive),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_REFUND'])

                # 引流分成
                coupon_rule = self.factory.create_coupon_rule(merchant=self.merchant)
                share = self.factory.create_payment(
                    coupon=self.factory.create_coupon(rule=coupon_rule,
                                                      originator_merchant=self.merchant),
                    datetime=time, merchant=share_merchant)
                self.factory.create_transaction(
                    content_object=share,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.share),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_SHARE'])

                # 企业商户结算
                settlement = self.factory.create_settlement(
                    status=SETTLEMENT_STATUS.FINISHED,
                    account=self.account,
                    finished_datetime=time,
                    wechat_amount=set_amount(-Config.wechat_settlement),
                    alipay_amount=set_amount(-Config.alipay_settlement),
                )
                self.factory.create_transaction(
                    content_object=settlement,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.withdraw / 2),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_WECHAT_SETTLEMENT'])
                self.factory.create_transaction(
                    content_object=settlement,
                    account=self.account,
                    datetime=time,
                    amount=set_amount(Config.withdraw / 2),
                    transaction_type=TRANSACTION_TYPE['MERCHANT_ALIPAY_SETTLEMENT'])

        # 第一页
        response = self.client.get(url, dict(page=1), Token=self.token)
        first_page_resp_json = response.json()
        for month_data in first_page_resp_json['results']:
            if month_data['month'] == '2018/04':
                self.assertEqual(month_data['cur_page_transactions'], [])
                self.assertEqual(month_data['turnover'], 0)
                self.assertEqual(month_data['originator_earning'], 0)
                self.assertEqual(month_data['withdraw'], 0)
            else:
                # 获取的是该月总额
                self.assertEqual(month_data['turnover'], Config.receive * 2)
                self.assertEqual(month_data['originator_earning'], float(Config.share * 2))
                self.assertEqual(month_data['withdraw'], -float(Config.withdraw * 2))
                # 检查每笔订单详细展示
                for transaction in month_data['cur_page_transactions']:
                    self.assertIsInstance(transaction['id'], int)
                    self.assertIn(transaction['title'], (
                        '余额提现 - 到支付宝余额', '余额提现 - 到微信零钱', '微信支付', '支付宝支付',
                        '微信支付 - 优惠账单', '支付宝支付 - 优惠账单', '引流到达的商户', '账单结算',
                    ))
                    self.assertIn(transaction['desc'], ('[其他]', '[普通]', '[满300减100优惠券]'))
                    self.assertTrue(re.match('0[1-5]-01 00:00', transaction['datetime']))
                    self.assertIn(transaction['status'], ('已完成', '已退款', '退款中', '退款失败',
                                                          '处理中', '已失败', '已结算', '结算中', ''))
                    self.assertIn(transaction['transaction_type'],
                                  ('normal', 'discount', 'withdraw', 'original_earning'))

        # 第二页
        response = self.client.get(url, dict(page=2, type='all'), Token=self.token)
        resp_json = response.json()
        self.assertEqual(len(resp_json['results']), 2)  # 有两个月数据
        month_data = resp_json['results'][0]

        self.assertEqual(month_data['turnover'], float(Config.receive * 2))
        self.assertEqual(month_data['originator_earning'], float(Config.share * 2))
        self.assertEqual(month_data['withdraw'], -float(Config.withdraw * 2))
        for transaction in month_data['cur_page_transactions']:
            self.assertIsInstance(transaction['id'], int)
            self.assertIn(transaction['title'], (
                '余额提现 - 到支付宝余额', '余额提现 - 到微信零钱', '微信支付', '支付宝支付',
                '微信支付 - 优惠账单', '支付宝支付 - 优惠账单', '引流到达的商户', '账单结算',
            ))
            self.assertIn(transaction['desc'], ('[其他]', '[普通]', '[满300减100优惠券]'))
            self.assertTrue(re.match('0[1-5]-01 00:00', transaction['datetime']))
            self.assertIn(transaction['status'], ('已完成', '已退款', '退款中', '退款失败', '处理中',
                                                  '已失败', '已结算', '结算中', ''))
            self.assertIn(transaction['transaction_type'], ('normal', 'discount', 'withdraw', 'original_earning'))

        # 第一页 营业额
        response = self.client.get(url, dict(page=1, type='turnover'), Token=self.token)
        resp_json = response.json()
        for month_data in resp_json['results']:
            if month_data['month'] == '2018/04':
                self.assertEqual(month_data['cur_page_transactions'], [])
                self.assertEqual(month_data['turnover'], 0)
                self.assertEqual(month_data['originator_earning'], 0)
                self.assertEqual(month_data['withdraw'], 0)
            else:
                # 每月2笔营业额
                self.assertEqual(len(month_data['cur_page_transactions']), 4)
                # 获取的是该月总额
                self.assertEqual(month_data['turnover'], float(Config.receive * 2))
                self.assertEqual(month_data['originator_earning'], float(Config.share * 2))
                self.assertEqual(month_data['withdraw'], -float(Config.withdraw * 2))
                # 检查每笔订单详细展示
                for transaction in month_data['cur_page_transactions']:
                    self.assertIsInstance(transaction['id'], int)
                    self.assertIn(transaction['title'], (
                        '微信支付', '支付宝支付', '微信支付 - 优惠账单', '支付宝支付 - 优惠账单'
                    ))
                    self.assertEqual(transaction['desc'], '[满300减100优惠券]')
                    self.assertTrue(re.match('0[1-5]-01 00:00', transaction['datetime']))
                    self.assertIsInstance(transaction['amount'], float)
                    self.assertIn(transaction['status'], ('已退款', '退款中', '退款失败', ''))
                    self.assertIn(transaction['transaction_type'], ('normal', 'discount'))

        # 第一页 引流收益
        response = self.client.get(url, dict(page=1, type='originator_earning'), Token=self.token)
        resp_json = response.json()
        for month_data in resp_json['results']:
            if month_data['month'] == '2018/04':
                self.assertEqual(month_data['cur_page_transactions'], [])
                self.assertEqual(month_data['turnover'], 0)
                self.assertEqual(month_data['originator_earning'], 0)
                self.assertEqual(month_data['withdraw'], 0)
            else:
                # 每月2笔引流收益
                self.assertEqual(len(month_data['cur_page_transactions']), 2)
                # 获取的是该月总额
                self.assertEqual(month_data['turnover'], float(Config.receive * 2))
                self.assertEqual(month_data['originator_earning'], float(Config.share * 2))
                self.assertEqual(month_data['withdraw'], -float(Config.withdraw * 2))
                # 检查每笔订单详细展示
                for transaction in month_data['cur_page_transactions']:
                    self.assertIsInstance(transaction['id'], int)
                    self.assertEqual(transaction['title'], '引流到达的商户')
                    self.assertEqual(transaction['desc'], '[其他]')
                    self.assertTrue(re.match('0[1-5]-01 00:00', transaction['datetime']))
                    self.assertEqual(transaction['amount'], 1.01)
                    self.assertIn(transaction['status'], ('已退款', '退款中', '退款失败', ''))
                    self.assertEqual(transaction['transaction_type'], 'original_earning')

        # 第一页 提现
        response = self.client.get(url, dict(page=1, type='withdraw'), Token=self.token)
        resp_json = response.json()
        for month_data in resp_json['results']:
            if month_data['month'] == '2018/04':
                self.assertEqual(month_data['cur_page_transactions'], [])
                self.assertEqual(month_data['turnover'], 0)
                self.assertEqual(month_data['originator_earning'], 0)
                self.assertEqual(month_data['withdraw'], 0)
            else:
                # 每月2笔提现账单
                self.assertEqual(len(month_data['cur_page_transactions']), 2)
                # 获取的是该月总额
                self.assertEqual(month_data['turnover'], float(Config.receive * 2))
                self.assertEqual(month_data['originator_earning'], float(Config.share * 2))
                self.assertEqual(month_data['withdraw'], -float(Config.withdraw * 2))
                # 检查每笔订单详细展示
                for transaction in month_data['cur_page_transactions']:
                    self.assertIsInstance(transaction['id'], int)
                    self.assertIn(transaction['title'], ('余额提现 - 到支付宝余额', '余额提现 - 到微信零钱'))
                    self.assertEqual(transaction['desc'], '[其他]')
                    self.assertTrue(re.match('0[1-5]-01 00:00', transaction['datetime']))
                    self.assertEqual(transaction['amount'], -Config.withdraw)
                    self.assertIn(transaction['status'], ('已完成', '处理中', '已失败', ''))
                    self.assertEqual(transaction['transaction_type'], 'withdraw')

        # 第一页 结算账单
        response = self.client.get(url, dict(page=1, type='settlement'), Token=self.token)
        resp_json = response.json()
        for month_data in resp_json['results']:
            if month_data['month'] == '2018/04':
                self.assertEqual(month_data['cur_page_transactions'], [])
                self.assertEqual(month_data['turnover'], 0)
                self.assertEqual(month_data['originator_earning'], 0)
                self.assertEqual(month_data['withdraw'], 0)
            else:
                # 每月2笔结算账单
                self.assertEqual(len(month_data['cur_page_transactions']), 2)
                # 获取的是该月总额
                self.assertEqual(month_data['turnover'], float(Config.receive * 2))
                self.assertEqual(month_data['originator_earning'], float(Config.share * 2))
                self.assertEqual(month_data['withdraw'], -float(Config.withdraw * 2))
                # 检查每笔订单详细展示
                for transaction in month_data['cur_page_transactions']:
                    self.assertIsInstance(transaction['id'], int)
                    self.assertIn(transaction['title'], ('账单结算',))
                    self.assertEqual(transaction['desc'], '[其他]')
                    self.assertTrue(re.match('0[1235]-01 00:00', transaction['datetime']))
                    self.assertEqual(transaction['amount'], -Config.withdraw)
                    self.assertIn(transaction['status'], ('已结算',))
                    self.assertEqual(transaction['transaction_type'], 'withdraw')

        # 无数据页
        response = self.client.get(url, dict(page=3), Token=self.token)
        resp_json = response.json()
        self.assertEqual(resp_json['detail'], '无效页面。')
        self.assertEqual(resp_json['error_code'], 'not_found')

        # 请求不带page参数, 应返回第一页数据
        response = self.client.get(url, Token=self.token)
        resp_json = response.json()
        self.assertEqual(resp_json, first_page_resp_json)

        # 请求参数错误
        response = self.client.get(url, dict(page=1, type='wrong_type'), Token=self.token)
        resp_json = response.json()
        self.assertEqual(resp_json, NonFieldError(MerchantError.unsupported_transaction_type))