Esempio n. 1
0
    def test_withdraw(self):

        user_old_cash = self.fund.cash

        d = to_decimal("1.12")
        transfer = do_withdraw(
            self.shop_user, d, order_id="test_order_id", note="test_withdraw"
        )
        self.assertEqual(transfer.amount, d)
        self.assertEqual(transfer.order_id, "test_order_id")
        self.assertEqual(transfer.note, "test_withdraw")

        self.fund.refresh_from_db()
        self.assertEqual(self.fund.cash, user_old_cash - d)

        # test insufficient cash
        delta = self.fund.cash + to_decimal("0.1")
        with self.assertRaises(exceptions.NotEnoughBalance):
            do_withdraw(
                self.shop_user, delta, order_id="test_order_id2", note="test_withdraw"
            )

        user_old_cash = self.fund.cash

        self.fund.refresh_from_db()

        self.assertEquals(self.fund.cash, user_old_cash)
Esempio n. 2
0
    def test_transfer(self):
        old_amount = self.fund.amount_d
        old_amount2 = self.fund2.amount_d
        delta = to_decimal("2.3")

        transfer = do_transfer(
            self.shop_user, self.shop_user2, delta, note="test transfer"
        )

        self.fund.refresh_from_db()
        self.fund2.refresh_from_db()

        self.assertEquals(self.fund.total, old_amount["total"] - delta)
        self.assertEquals(self.fund.hold, old_amount["hold"] - delta)
        self.assertEquals(self.fund.cash, old_amount["cash"])

        self.assertEquals(self.fund2.total, old_amount2["total"] + delta)
        self.assertEquals(self.fund2.cash, old_amount2["cash"] + delta)
        self.assertEquals(self.fund2.hold, old_amount2["hold"])

        self.assertEquals(transfer.note, "test transfer")

        # test insufficient cash
        old_amount = self.fund.amount_d
        old_amount2 = self.fund2.amount_d

        delta = self.fund.total + to_decimal("0.1")
        with self.assertRaises(exceptions.NotEnoughBalance):
            do_transfer(self.shop_user, self.shop_user2, delta, note="test transfer2")

        self.fund.refresh_from_db()
        self.fund2.refresh_from_db()

        self.assertEquals(self.fund.amount_d, old_amount)
        self.assertEquals(self.fund2.amount_d, old_amount2)
Esempio n. 3
0
    def test_order_update_deposit(self):
        csettings = CashBackSettings()
        csettings.threshold = "1"

        minimal = self.minimal_example

        order = self.app.pay.create_order(self.wechat_user, self.request, **minimal)
        result = self.success(self.app.pay, order)

        old_hold = self.fund.hold

        order.update(result)

        # test deposit
        new_fund = Fund.objects.get(id=self.fund.id)
        self.assertEqual(self.fund.cash + to_decimal("1.01"), new_fund.cash)
        self.assertEqual(old_hold + to_decimal("1.01"), new_fund.hold)
        self.assertEqual(self.fund.total + to_decimal("2.02"), new_fund.total)
        transfer = FundTransfer.objects.get(
            to_fund=self.fund, order_id=order.id, type="DEPOSIT"
        )
        self.assertEqual(transfer.note, f"user:{self.shop_user.id} deposit")

        # test cashback
        cashback_transfer = FundTransfer.objects.get(
            to_fund=self.fund, order_id=order.id, type="CASHBACK"
        )
        self.assertEqual(cashback_transfer.amount, to_decimal("1.01"))

        fund_action = FundAction.objects.get(fund=self.fund, transfer=cashback_transfer)
        self.assertDictEqual(
            fund_action.balance, json.loads(json_dumps(new_fund.amount_d))
        )
Esempio n. 4
0
    def test_order_update_transfer(self):
        # test deposit & transfer
        minimal = self.minimal_example
        minimal["ext_info"]["to_user_id"] = self.shop_user2.id
        order = self.app.pay.create_order(self.wechat_user, self.request, **minimal)
        result = self.success(self.app.pay, order)
        order.update(result)

        new_fund = Fund.objects.get(id=self.fund.id)
        new_fund2 = Fund.objects.get(id=self.fund2.id)

        self.assertEqual(self.fund.cash, new_fund.cash)
        self.assertEqual(self.fund2.cash + to_decimal("1.01"), new_fund2.cash)

        transfer = FundTransfer.objects.get(
            to_fund=self.fund, order_id=order.id, type="DEPOSIT"
        )
        self.assertEqual(transfer.note, f"deposit&buy")
        self.assertEqual(transfer.amount, to_decimal("1.01"))

        transfer = FundTransfer.objects.get(
            from_fund=self.fund, to_fund=self.fund2, order_id=order.id, type="TRANSFER"
        )
        self.assertEqual(transfer.note, f"deposit&buy")
        self.assertEqual(transfer.amount, to_decimal("1.01"))
Esempio n. 5
0
    def test_transfer_api(self):
        self.client.authenticate(self.user)
        gql = """
        mutation _($input: TransferInput!){
          transfer(input: $input){
            success
          }
        }"""
        test_request_uuid = uuid.uuid4().hex
        variables = {
            "input": {
                "to": str(self.shop_user2.uuid),
                "amount": "0.1",
                "note": "test transfer",
                "requestId": test_request_uuid,
                "paymentPassword": "******",
            }
        }
        # test with not set payment password
        data = self.client.execute(gql, variables)
        self.assertIsNotNone(data.errors)
        self.assertEquals("need_set_payment_password", data.errors[0].message)

        # test resbumitted
        data = self.client.execute(gql, variables)
        self.assertIsNotNone(data.errors)
        self.assertEquals("resubmitted", data.errors[0].message)

        self.shop_user.set_payment_password("654321")

        # test wrong paymentpassword
        variables["input"]["paymentPassword"] = "******"
        variables["input"]["requestId"] = uuid.uuid4().hex
        data = self.client.execute(gql, variables)
        self.assertIsNotNone(data.errors)
        self.assertEquals("wrong_password", data.errors[0].message)

        # test true paymentpassword
        variables["input"]["paymentPassword"] = "******"
        variables["input"]["requestId"] = uuid.uuid4().hex

        old_amount = self.fund.amount_d
        old_amount2 = self.fund2.amount_d

        data = self.client.execute(gql, variables)
        self.assertIsNone(data.errors)

        self.fund2.refresh_from_db()
        self.fund.refresh_from_db()

        self.assertEquals(self.fund.total, old_amount["total"] - to_decimal("0.1"))
        self.assertEquals(self.fund2.cash, old_amount2["cash"] + to_decimal("0.1"))
Esempio n. 6
0
 def get_quota(self, name: str, default=0) -> Decimal:
     try:
         sq = self.get(name=name)
         return sq.quota
     except self.model.DoesNotExist:
         pass
     return to_decimal(default)
Esempio n. 7
0
 def expired_days(self) -> int:
     r = SystemQuota.objects.get_quota(
         self.CASHBACK_EXPIRED_DAYS, default=to_decimal("365")
     )
     if r:
         return int(r)
     else:
         return 0
Esempio n. 8
0
def order_updated(result, order, state, attach, **kwargs):
    # TODO: how to unify wechat, alipay?
    if state != UnifiedOrderResult.State.SUCCESS:
        logger.info(f"{order} deposit signal, skip for no-success state")
        return

    if FundTransfer.objects.filter(order_id=order.id).exists():
        logger.info(f"{order} deposit signal, skip for duplicate trigger")
        return

    con = get_redis_connection()
    lock_name = f"order:{order.id}_update_signal"

    provider = order.ext_info["provider"]
    user = ShopUser.objects.get_user_by_openid(provider, order.openid)

    amount = to_decimal(order.total_fee / 100)
    is_transfer = bool(order.ext_info and order.ext_info.get("to_user_id"))

    if is_transfer:
        to_user_id = order.ext_info["to_user_id"]
        to_user = ShopUser.objects.get(id=to_user_id)
        note = "deposit&buy"
    else:
        note = f"user:{user.id} deposit"

    # Ensure cocurrent callback in 10 seconds
    with con.lock(lock_name, timeout=10):
        with transaction.atomic():
            if is_transfer:
                do_deposit(user, amount, order_id=order.id, note=note)
                do_transfer(user,
                            to_user,
                            amount,
                            order_id=order.id,
                            note=note)
            else:
                do_deposit(user, amount, order_id=order.id, note=note)

            do_cash_back(user, amount, order_id=order.id, note=note)

    logger.info(f"{order} deposit success: {note}")
Esempio n. 9
0
    def test_withdraw_api(self):
        self.client.authenticate(self.user)
        gql = """
        mutation _($input: WithdrawInput!){
          withdraw(input: $input){
            success
          }
        }"""
        test_request_uuid = uuid.uuid4().hex
        variables = {
            "input": {
                "amount": decimal2str(to_decimal("0.1") + self.fund.cash),
                "requestId": test_request_uuid,
                "provider": "WECHAT",
            }
        }
        # test balance not enough
        data = self.client.execute(gql, variables)
        self.assertIsNotNone(data.errors)
        self.assertEquals("not_enough_balance", data.errors[0].message)

        # test resbumitted
        data = self.client.execute(gql, variables)
        self.assertIsNotNone(data.errors)
        self.assertEquals("resubmitted", data.errors[0].message)

        variables["input"]["amount"] = "0.1"
        variables["input"]["requestId"] = uuid.uuid4().hex

        old_fund_cash = self.fund.cash

        # test fail and revert
        def withdraw_fail(*args, **kw):
            raise exceptions.WithdrawError("fail")

        with patch.object(WeChatProvider, "withdraw") as mock_withdraw:
            mock_withdraw.side_effect = withdraw_fail

            data = self.client.execute(gql, variables)
            self.assertIsNotNone(data.errors)
            self.assertEqual("fail", data.errors[0].message)
            self.fund.refresh_from_db()
            self.assertEqual(old_fund_cash, self.fund.cash)

        # test withdraw success
        variables["input"]["requestId"] = uuid.uuid4().hex
        mocked_result = {
            "mch_appid": "wx478898d89cf437dc",
            "mchid": "1231736602",
            "nonce_str": "pslL019BgHIzSDqfv8FUy6EC32OtZauK",
            "partner_trade_no": "1231736602201910260304298054",
            "payment_no": "10100101184011910260023619583860",
            "payment_time": "2019-10-26 11:04:32",
            "result_code": "SUCCESS",
            "return_code": "SUCCESS",
            "return_msg": None,
        }
        with patch.object(WeChatProvider, "withdraw") as mock_withdraw:
            mock_withdraw.return_value = mocked_result

            data = self.client.execute(gql, variables)
            self.assertIsNone(data.errors)

        self.fund.refresh_from_db()
        self.assertEqual(old_fund_cash - to_decimal("0.1"), self.fund.cash)

        self.assertTrue(data.data["withdraw"]["success"])
Esempio n. 10
0
    def test_fund_api(self):
        self.client.authenticate(self.user)
        gql = """
        query {
          fund{
            total
            cash
            hold
            currency
          }
        }"""
        data = self.client.execute(gql)
        self.assertIsNone(data.errors)
        expected = {
            "total": decimal2str(self.fund.cash + self.hold_fund.amount),
            "cash": decimal2str(self.fund.cash),
            "hold": decimal2str(self.fund.hold),
            "currency": "CNY",
        }
        self.assertDictEqual(ordered_dict_2_dict(data.data["fund"]), expected)

        new_add_cash = to_decimal("1.2")
        transfer = do_deposit(
            self.shop_user, new_add_cash, order_id="1", note="test deposit"
        )
        old_cash = self.fund.cash

        self.fund.refresh_from_db()
        self.assertEquals(old_cash + new_add_cash, self.fund.cash)

        data = self.client.execute(gql)
        self.assertIsNone(data.errors)
        expected = {
            "total": decimal2str(self.fund.cash + self.hold_fund.amount),
            "cash": decimal2str(self.fund.cash),
            "hold": decimal2str(self.fund.hold),
            "currency": "CNY",
        }
        self.assertDictEqual(ordered_dict_2_dict(data.data["fund"]), expected)

        gql = """
        query _($before: String) {
          ledgerList(before: $before){
            edges{
              node{
                id
                type
                amount
                note
                status
                orderId
                createdAt
              }
            }
             pageInfo{
                startCursor
                endCursor
                hasNextPage
                hasPreviousPage
             }
          }
        }"""
        variables = {"before": None}
        data = self.client.execute(gql, variables)
        self.assertIsNone(data.errors)
        expected = {
            "id": str(transfer.uuid),
            "type": "DEPOSIT",
            "amount": decimal2str(new_add_cash),
            "note": "test deposit",
            "status": "SUCCESS",
            "orderId": "1",
            "createdAt": transfer.created_at.isoformat(),
        }
        self.assertDictEqual(
            ordered_dict_2_dict(data.data["ledgerList"]["edges"][0]["node"]), expected
        )
        page_info = data.data["ledgerList"]["pageInfo"]
        self.assertIsNotNone(page_info["startCursor"])
        self.assertIsNotNone(page_info["endCursor"])
        self.assertIsNotNone(page_info["hasNextPage"])
        self.assertIsNotNone(page_info["hasPreviousPage"])
Esempio n. 11
0
 def threshold(self):
     return SystemQuota.objects.get_quota(
         self.CASHBACK_THRESHOLD, default=to_decimal("1000")
     )
Esempio n. 12
0
 def expired_days(self, value):
     return SystemQuota.objects.set_quota(
         self.CASHBACK_EXPIRED_DAYS, to_decimal(value)
     )
Esempio n. 13
0
 def threshold(self, value):
     return SystemQuota.objects.set_quota(self.CASHBACK_THRESHOLD, to_decimal(value))