Example #1
0
    def add(cls, redeem_code, user):
        sql = (
            'insert into {.table_name} (code_id, user_id, activity_id, consumed_time)'
            ' values(%s, %s, %s, %s)').format(cls)
        params = (redeem_code.id_, user.id_, redeem_code.activity.id_,
                  datetime.now())
        try:
            id_ = db.execute(sql, params)
        except MySQLdb.IntegrityError:
            raise RedeemCodeUsedError()
        code_used_times = cls.count_by_code_id(redeem_code.id_)
        code_usage = cls.get(id_)

        #: 超出兑换码本身使用次数限制时抛出异常
        if code_used_times > redeem_code.max_usage_limit_per_code:
            code_usage.delete_by_id(code_usage.id_)
            raise RedemptionBeyondLimitPerCodeError()
        usage_used_times = cls.count_by_user_and_activity(
            user.id_, redeem_code.activity.id_)

        #: 用户在本次活动中使用兑换码数量超过活动限制时抛出异常
        if usage_used_times > redeem_code.activity.max_usage_limit_per_user:
            code_usage.delete_by_id(code_usage.id_)
            raise RedemptionBeyondLimitPerUserError()
        else:
            db.commit()

        #: 清除缓存
        cls.clear_cache(id_)
        cls.clear_cache_by_user_id(user.id_)
        cls.clear_cache_by_user_and_activity_id(user.id_,
                                                redeem_code.activity.id_)
        cls.clear_cache_by_code_id(redeem_code.id_)

        return cls.get(id_)
Example #2
0
    def add(cls,
            service_id,
            user_id,
            order_amount,
            fin_order_id,
            creation_time=None):
        """Creates a unpaid order.

        :param service_id: the UUID of chosen P2P service.
        :param user_id: the user id of order creator.
        :param order_amount: the payment amount for this order.
        :param fin_order_id: the UUID of remote order.
        :returns: the created order.
        """
        cls.check_before_adding(service_id, user_id, order_amount)

        creation_time = creation_time or datetime.datetime.now()
        sql = ('insert into {.table_name} (service_id, user_id, order_amount,'
               ' fin_order_id, creation_time, status) '
               'values (%s, %s, %s, %s, %s, %s)').format(cls)
        params = (service_id, user_id, order_amount, fin_order_id,
                  creation_time, OrderStatus.unpaid.value)

        id_ = db.execute(sql, params)
        db.commit()

        order = cls.get(id_)
        order.clear_cache()
        return order
Example #3
0
    def add(cls, account_id):
        if not Account.get(account_id):
            raise NotFoundError(account_id, Account)

        existent = cls.get(account_id)
        if existent:
            # 临时做法,弥补之前未添加创建时间的错误
            if existent.creation_time is None:
                supply_sql = ('update {.table_name} set creation_time=%s'
                              'where account_id=%s').format(cls)
                supply_params = (datetime.now(), account_id)
                db.execute(supply_sql, supply_params)
                db.commit()
                cls.clear_cache(account_id)
            return existent

        sql = ('insert into {.table_name} (account_id, creation_time) '
               'values (%s, %s) '
               'on duplicate key update account_id = account_id').format(cls)
        params = (account_id, datetime.now())
        db.execute(sql, params)
        db.commit()

        from core.models.hoard.profile import HoardProfile
        # if user hasn't hoard profile
        if not HoardProfile.get(account_id):
            add_savings_users()

        cls.clear_cache(account_id)
        return cls.get(account_id)
Example #4
0
    def add(cls, account, bankcard, amount, type_, transaction_id,
            status=Status.raw):
        """Creates a raw transaction."""
        assert isinstance(account, WalletAccount)
        assert isinstance(amount, decimal.Decimal)
        assert isinstance(type_, cls.Type)
        assert isinstance(status, cls.Status)

        if not account.service_provider.is_avalable_bankcard(bankcard):
            raise UnavailableBankError(bankcard, account.service_provider)
        if str(account.local_account.id_) != str(bankcard.user_id):
            raise ValueError('mismatched user id')

        sql = (
            'insert into {0} (account_id, amount, type, bankcard_id, status,'
            ' transaction_id) '
            'values (%s, %s, %s, %s, %s, %s)').format(cls.table_name)
        params = (
            account.id_, amount, type_.value, bankcard.id_, status.value,
            transaction_id)

        id_ = db.execute(sql, params)
        db.commit()

        cls.clear_cache(id_)
        cls.clear_cache_by_bankcard(bankcard.id_)
        cls.clear_cache_by_account(account.id_)
        cls.clear_cache_for_sum_amount()

        return cls.get(id_)
Example #5
0
    def create(cls, user, device_binding, notification):
        from core.models.notification import Notification

        assert isinstance(user, Account)
        assert isinstance(device_binding, DeviceBinding)
        assert isinstance(notification, Notification)

        if not (user.id_ == device_binding.user_id == notification.user_id):
            raise ValueError('invalid push tempt as user infos are unmatched')

        if cls.get_by_device_and_notification(
                device_binding.device_id, notification.id_):
            raise ValueError('notification can only be pushed once')

        sql = ('insert into {.table_name} (user_id, device_id, notification_id, '
               'status, creation_time) values (%s, %s, %s, %s, %s)').format(cls)
        params = (user.id_, device_binding.device_id, notification.id_,
                  cls.Status.created.value, datetime.now())
        id_ = db.execute(sql, params)
        db.commit()

        cls.clear_cache_key_by_user(user.id_)
        cls.clear_cache_key_by_device_and_notification(
            device_binding.device_id, notification.id_)
        return cls.get(id_)
Example #6
0
    def add(cls, subject, subject_type, content, content_type, start_time,
            stop_time, endpoint):
        assert isinstance(subject_type, cls.SubjectType)
        assert isinstance(content_type, cls.ContentType)
        assert start_time < stop_time
        assert datetime.datetime.now() < stop_time

        initial_status = cls.Status.present

        sql = ('insert into {0} (subject_type, content_type, status,'
               ' start_time, stop_time, endpoint, creation_time) '
               'values (%s, %s, %s, %s, %s, %s, %s)').format(cls.table_name)
        params = (subject_type.value, content_type.value, initial_status.value,
                  start_time, stop_time, endpoint, datetime.datetime.now())

        id_ = db.execute(sql, params)
        db.commit()

        cls.clear_cache(id_)
        for date in datetime_range(start_time, stop_time):
            cls.clear_cache_by_date(date)

        instance = cls.get(id_)
        instance.subject = subject
        instance.content = content

        return instance
Example #7
0
    def create(cls, user_id, kind, properties=None):
        assert isinstance(kind, NotificationKind)
        assert properties is None or isinstance(properties, dict)

        # 校验参数
        user = Account.get(user_id)
        if not user:
            raise ValueError('invalid user id')

        if kind.is_once_only:
            id_list = cls.get_id_list_by_user_and_kind(user.id_, kind.id_)
            if id_list:
                return cls.get(id_list[0])

        sql = ('insert into {.table_name} (user_id, kind_id, is_read, '
               'creation_time) values (%s, %s, %s, %s)').format(cls)
        params = (user_id, kind.id_, False, datetime.now())
        id_ = db.execute(sql, params)
        db.commit()

        instance = cls.get(id_)
        instance.properties = properties or {}

        # 单播消息则提交并加入推送队列
        cls.clear_cache_by_user(user.id_)
        cls.clear_cache_by_user_and_kind(user.id_, kind.id_)

        # 由推送控制中心来记录和完成推送
        if kind.allow_push:
            mq_notification_push.produce(str(id_))
        return instance
Example #8
0
 def add(cls, user_id, get_type, lottery_num, creation_time):
     sql = ('insert into {.table_name}'
            ' (user_id, get_type, lottery_num, creation_time)'
            ' values (%s, %s, %s, %s)').format(cls)
     params = (user_id, get_type, lottery_num, creation_time)
     db.execute(sql, params)
     db.commit()
Example #9
0
 def add(cls, user_id, gift_id, creation_time):
     sql = (u'insert into {.table_name}'
            u' (user_id, gift_id, creation_time)'
            u' values (%s, %s, %s)').format(cls)
     params = (user_id, gift_id, creation_time)
     db.execute(sql, params)
     db.commit()
Example #10
0
    def add(cls, user_id, code_type, verify_delta=timedelta(hours=24)):
        assert isinstance(verify_delta, timedelta)

        created_time = datetime.now()
        verify_time = created_time + verify_delta

        cls._remove(user_id)

        verify_code = gen_verify_code(code_type)

        i = 0
        while i < MAX_RETRY:
            try:
                id = db.execute(
                    'insert into user_verify '
                    '(user_id, code_type, verify_code, created_time, '
                    'verify_time) values(%s, %s, %s, %s, %s)',
                    (user_id, code_type, verify_code, created_time,
                     verify_time))
                if id:
                    db.commit()
                    c = cls.get(id)
                    return c
                else:
                    i += 1
                    verify_code = gen_verify_code(code_type)
                    db.rollback()
            except IntegrityError:
                i += 1
                verify_code = gen_verify_code(code_type)
                db.rollback()
Example #11
0
 def add(cls, user_id):
     sql = ('insert into {0} (id, secret_key, is_enabled, creation_time) '
            'values (%s, %s, %s, %s)').format(cls.table_name)
     params = (user_id, cls.generate_key(), False, datetime.datetime.now())
     db.execute(sql, params)
     db.commit()
     return cls.get(user_id)
Example #12
0
 def _set_is_frozen(self, flag):
     self.is_frozen = bool(flag)
     sql = 'update oauth_token set is_frozen = %s where id = %s'
     params = (self.is_frozen, self.id_)
     db.execute(sql, params)
     db.commit()
     self.clear_cache_by_instance()
Example #13
0
    def record(cls, date, annual_rate, ttp_income, fund_code):
        """Creates or updates one record of some day."""
        # The ``on duplicate key update`` is useful in this situation.
        # But there are some MySQL issues (Bug #11765650, Bug #58637) stop us
        # from using it.
        #
        # The annual rates could be updated by schedule tasks only. We could
        # trust it that it is far away from concurrent writting.
        # So UPDATE after SELECT is safe there.
        #
        # See also:
        # http://dev.mysql.com/doc/refman/5.6/en/insert-on-duplicate.html
        id_ = cls.get_id_by_date(date, fund_code)
        if id_:
            sql = ('update {0} set annual_rate = %s, ttp_income = %s '
                   'where id = %s').format(cls.table_name)
            params = (annual_rate, ttp_income, id_)
            db.execute(sql, params)
        else:
            sql = ('insert into {0} (date, annual_rate, ttp_income,'
                   ' fund_code) '
                   'values (%s, %s, %s, %s)').format(cls.table_name)
            params = (date, annual_rate, ttp_income, fund_code)
            id_ = db.execute(sql, params)

        db.commit()
        cls.clear_cache(id_)

        return cls.get(id_)
Example #14
0
    def bind(cls, account_id, p2p_account, p2p_token, commit=True):
        """Creates new binding relationship and cancels all existent."""
        cls.check_before_binding(account_id)

        params = (account_id, p2p_account, p2p_token)

        if not Account.get(account_id):
            raise NotFoundError(account_id, Account)

        existent = cls.get_by_local(account_id)

        if existent:
            cls.unbind(account_id, commit=False)

        if cls.get_by_remote(p2p_account) or cls.get_by_p2p_token(p2p_token):
            raise RemoteAccountUsedError(p2p_account)

        sql = ('insert into {.table_name} (account_id, p2p_account, p2p_token)'
               'values (%s, %s, %s)').format(cls)
        db.execute(sql, params)
        if commit:
            db.commit()

        cls.clear_cache(account_id)

        return cls.get_by_local(account_id)
Example #15
0
 def status(self, new_status):
     assert isinstance(new_status, self.Status)
     db.execute('update {.table_name} set status=%s where id=%s',
                (new_status.value, self.id_))
     db.commit()
     self._status = new_status.value
     self.clear_cache(self.id_)
Example #16
0
    def add(cls, account_id):
        """Creates a new profile for specific account and return it.

        If a profile exists, it will be return directly.

        :param account_id: the primary key of local account.
        :returns: the created (or existent) profile.
        """
        if not Account.get(account_id):
            raise NotFoundError(account_id, Account)

        existent = cls.get(account_id)
        if existent:
            return existent

        sql = ('insert into {.table_name} (account_id) values (%s) '
               'on duplicate key update account_id = %s').format(cls)
        params = (account_id, account_id)
        db.execute(sql, params)
        db.commit()

        from core.models.hoard.zhiwang.profile import ZhiwangProfile
        from core.models.hoard.xinmi.profile import XMProfile
        # if user hasn't zhiwang and xm profile
        if not ZhiwangProfile.get(account_id) and not XMProfile.get(
                account_id):
            add_savings_users()

        cls.clear_cache(account_id)
        cls.clear_cache_for_account_ids()
        return cls.get(account_id)
Example #17
0
    def save(cls, user_id, person_name, person_ricn):
        if not cls._validate(person_name, person_ricn):
            raise IdentityValidationError(person_name, person_ricn)

        person_ricn = person_ricn.upper()
        if cls.get_by_ricn(person_ricn):
            raise IdentityUsedError

        if not is_matched_in_mathilde(person_name, person_ricn):
            raise IdentityDismatchError

        updated_time = datetime.datetime.now()
        sql = ('insert into {0} (id, person_name, person_ricn, updated_time) '
               'values (%s, %s, %s, %s) on duplicate key update'
               ' person_name = %s, person_ricn = %s,'
               ' updated_time = %s').format(cls.table_name)
        params = (user_id, person_name, person_ricn, updated_time, person_name,
                  person_ricn, updated_time)

        db.execute(sql, params)
        db.commit()

        cls.clear_cache(user_id)
        instance = cls.get(user_id)
        identity_saved.send(instance)
        return instance
Example #18
0
    def update(self, mobile_phone, bank_id, city_id, province_id,
               local_bank_name, is_default):
        self.is_default = is_default
        changed = [field_name for field_name, field_changed in [
            ('mobile_phone', self.mobile_phone != mobile_phone),
            ('bank_id', self.bank_id != bank_id),
            ('city_id', self.city_id != city_id),
            ('province_id', self.province_id != province_id),
            ('local_bank_name', self.local_bank_name != local_bank_name),
        ] if field_changed]
        if changed:
            sql = ('update {.table_name} set bank_id_sha1 = %s '
                   'where id = %s').format(self)
            params = (calculate_checksum(bank_id), self.id_)
            db.execute(sql, params)

            self.update_props_items({
                'mobile_phone': mobile_phone,
                'card_number': self.card_number,
                'bank_id': bank_id,
                'city_id': city_id,
                'province_id': province_id,
                'local_bank_name': local_bank_name,
                'is_default': self.is_default,
            })
            db.commit()
            bankcard_updated.send(self, changed_fields=changed)

        return changed
Example #19
0
    def record_for_binding(cls, bankcard, provider):
        """This method is a context manager for binding bankcard.

        The caller should access the remote API of third-party service provider
        with this context.

        :param bankcard: The bankcard instance.
        :param provider: The service provider instance.
        """
        assert isinstance(bankcard, BankCard)
        assert isinstance(provider, ServiceProvider)

        id_ = cls.get_id_by_bankcard(bankcard.id_, provider.id_)
        if not id_:
            sql = ('insert into {0} (bankcard_id, provider_id, is_confirmed,'
                   ' creation_time) '
                   'values (%s, %s, %s, %s)').format(cls.table_name)
            params = (bankcard.id_, provider.id_, False,
                      datetime.datetime.now())
            id_ = db.execute(sql, params)
            db.commit()

        yield

        sql = ('update {0} set is_confirmed = %s '
               'where id = %s').format(cls.table_name)
        params = (True, id_)
        db.execute(sql, params)
        db.commit()

        cls.clear_cache(id_)
        cls.clear_cache_by_bankcard(bankcard.id_, provider.id_)
Example #20
0
    def restore(cls, id_, user_id):
        if not Account.get(user_id):
            raise ValueError('invalid user %r' % user_id)

        instance = cls(id_, user_id, None, None, None, None)
        new_card = cls.get_by_card_number(instance.card_number)
        if new_card:
            raise BankCardChanged(new_card.id_)

        card_number_sha1 = calculate_checksum(instance.card_number)
        bank_id_sha1 = calculate_checksum(instance.bank_id)

        sql = ('insert into {.table_name} (id, user_id, card_number_sha1,'
               ' bank_id_sha1, status) '
               'values (%s, %s, %s, %s, %s)').format(cls)
        params = (id_, user_id, card_number_sha1, bank_id_sha1,
                  cls.Status.active.value)
        db.execute(sql, params)
        db.commit()

        bankcard = cls.get(id_)
        rsyslog.send('\t'.join([
            str(id_),
            str(user_id),
            str(bankcard.card_number),
            str(bankcard.bank_id),
            str(bankcard.mobile_phone),
            str(bankcard.province_id),
            str(bankcard.city_id),
            str(bankcard.local_bank_name),
        ]), tag='restore_bankcard')
        return bankcard
Example #21
0
 def add(cls,
         alias,
         passwd_hash,
         salt,
         name,
         reg_type=ACCOUNT_REG_TYPE.MOBILE,
         gender=ACCOUNT_GENDER.UNKNOWN,
         status=ACCOUNT_STATUS.NEED_VERIFY):
     if Account.get_by_alias(alias):
         return
     try:
         id = db.execute(
             'insert into account '
             '(password, salt, name, gender, '
             'status, create_time)'
             'values(%s, %s, %s, %s, %s, %s)',
             (passwd_hash, salt, name, gender, status, datetime.now()))
         if id:
             db.execute(
                 'insert into account_alias (`id`, alias, reg_type) '
                 'values(%s, %s, %s)', (id, alias, reg_type))
             db.commit()
             return cls.get(id)
         else:
             db.rollback()
     except IntegrityError:
         db.rollback()
         warn('insert account failed')
Example #22
0
 def status(self, item):
     sql = 'update {.table_name} set status=%s where id=%s;'.format(self)
     params = (item.value, self.id_,)
     db.execute(sql, params)
     db.commit()
     self.clear_cache()
     self._status = item.value
Example #23
0
    def add(cls,
            user_id,
            division_id,
            street,
            receiver_name='',
            receiver_phone=''):
        """Creates an address record.

        :param user_id: The id of local account.
        :param division_id: The GB2260 division code of city.
        :param street: The concrete street information.
        :param receiver_name: The real name of express delivery receiver.
        :param receiver_phone: The phone number of express delivery receiver.
        """
        cls._validate(user_id, division_id, street)

        sql = ('insert into {0} (user_id, division_id, street, receiver_name,'
               ' receiver_phone) '
               'values (%s, %s, %s, %s, %s)').format(cls.table_name)
        params = (user_id, division_id, street, receiver_name, receiver_phone)

        id_ = db.execute(sql, params)
        db.commit()

        return cls.get(id_)
Example #24
0
    def add(cls, asset_no, order_code, bankcard_id, bank_account, product_id, user_id, status,
            annual_rate, actual_annual_rate, create_amount, current_amount, base_interest,
            expect_interest, current_interest, interest_start_date,
            interest_end_date, expect_payback_date, buy_time, creation_time=None):
        try:
            cls.check_before_adding(asset_no, order_code, create_amount, product_id)
        except AssetCreatedError:
            return None

        sql = ('insert into {.table_name}(asset_no, order_code, bankcard_id, bank_account, '
               'product_id, user_id, status, annual_rate, actual_annual_rate, create_amount, '
               'current_amount, base_interest, expect_interest, current_interest, '
               'interest_start_date, interest_end_date, expect_payback_date, buy_time, '
               'creation_time) values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, '
               '%s, %s, %s, %s, %s, %s, %s)').format(cls)
        params = (asset_no, order_code, bankcard_id, bank_account, product_id, user_id,
                  status.value, annual_rate, actual_annual_rate, create_amount, current_amount,
                  base_interest, expect_interest, current_interest, interest_start_date,
                  interest_end_date, expect_payback_date, buy_time,
                  creation_time or datetime.datetime.now())
        id_ = db.execute(sql, params)
        db.commit()

        instance = cls.get(id_)
        instance.clear_cache()
        return instance
Example #25
0
    def create(cls, loans_digest, loans, _commit=True):
        assert isinstance(loans_digest, XMLoansDigest)
        sql = 'insert into {.table_name} (loans_digest_id, creation_time) values(%s, %s)'.format(
            cls)
        params = (loans_digest.id_, datetime.datetime.now())
        id_ = db.execute(sql, params)

        if _commit:
            db.commit()
        instance = cls.get(id_)

        cls.clear_cache(id_)
        cls.clear_cache_by_loans_digest_id(loans_digest.id_)

        instance.update_props_items({
            'loan_receipt_no':
            loans.loan_receipt_no,
            'invest_id':
            loans.order_id,
            'debtor_name':
            loans.bc_name,
            'debtor_ricn':
            loans.debtor_identity_no,
            'debtor_type':
            loans.debtor_type,
            'debt_purpose':
            loans.debt_desc,
            'lending_amount':
            str(loans.loan_receipt_amt),
            'start_date':
            loans.start_date.isoformat()
        })
        return instance
Example #26
0
    def _commit_and_refresh(self, sql, params):
        db.execute(sql, params)
        db.commit()
        self.clear_cache()

        new_state = vars(self.get(self.id_))
        vars(self).update(new_state)
Example #27
0
    def create(cls, notification_kind, subdivision_kind=None):
        from core.models.notification import NotificationKind
        assert isinstance(notification_kind, NotificationKind)
        assert subdivision_kind is None or isinstance(
            subdivision_kind, notification_kind.subdivision_kind_cls)

        # 双层通知类型组播由于面向平台、标签组,可以进行单例检查
        # 对于面向多别名、多设备的组播,由于有单次组播限制,因此无法进行单例检查
        if subdivision_kind:
            if cls.get_by_bilayer_kinds(notification_kind, subdivision_kind):
                raise ValueError(
                    'the bilayer multicast/broadcast has been pushed once')

        sql = (
            'insert into {.table_name} (notification_kind_id, subdivision_kind_id, '
            'is_pushed, creation_time) values (%s, %s, %s, %s)').format(cls)
        params = (notification_kind.id_,
                  subdivision_kind.id_ if subdivision_kind else None, False,
                  datetime.now())
        id_ = db.execute(sql, params)
        db.commit()

        cls.clear_cache(id_)
        cls.clear_cache_by_bilayer_kinds(
            notification_kind.id_,
            subdivision_kind.id_ if subdivision_kind else None)
        return cls.get(id_)
Example #28
0
    def add(cls, user_id):
        """Adds profile entity for specific user.

        Don't use it without any user's operation. If you need to obtain an
        attribute, use :meth:`.WalletProfile.get` instead::

            wallet_profile = WalletProfile.get(g.user.id_)
            wallet_foo = wallet_profile.foo if wallet_profile else None

        The following way will cause users lost their landing page::

            wallet_foo = WalletProfile.add(g.user.id_).

        :param user_id: The id of local account.
        """
        existent = cls.get(user_id)
        if existent:
            return existent

        sql = ('insert into {0} (id, creation_time) '
               'values (%s, %s)').format(cls.table_name)
        params = (user_id, datetime.now())
        id_ = db.execute(sql, params)
        db.commit()
        cls.clear_cache(id_)
        return cls.get(id_)
Example #29
0
    def create(cls, raw_product, wrapper_kind):
        # check the limit
        if (min(wrapper_kind.limit) < raw_product.min_amount
                or max(wrapper_kind.limit) > raw_product.max_amount):
            raise InvalidWrapRule(wrapper_kind.limit)

        # check the frozen time
        raw_days_period = [
            raw_product.profit_period['min'].value,
            raw_product.profit_period['max'].value
        ]
        if not min(raw_days_period) <= wrapper_kind.frozen_days.value <= max(
                raw_days_period):
            raise InvalidWrapRule(wrapper_kind.id_)

        instance = cls.get_by_kind_and_raw_product_id(wrapper_kind.id_,
                                                      raw_product.product_id)
        if instance is None:
            sql = ('insert into {.table_name} (kind_id, raw_product_id, '
                   'creation_time) values (%s, %s, %s)').format(cls)
            params = (wrapper_kind.id_, raw_product.product_id, datetime.now())
            id_ = db.execute(sql, params)
            db.commit()
            instance = cls.get(id_)
            instance.deploy(wrapper_kind)

            cls.clear_cache(id_)
            cls.clear_all_ids_cache()
            cls.clear_product_ids_by_raw_id_cache(raw_product.product_id)
            cls.clear_product_by_kind_and_raw_cache(wrapper_kind.id_,
                                                    raw_product.product_id)
        return instance
Example #30
0
    def add(cls,
            user_id,
            product_id,
            bankcard_id,
            amount,
            pay_amount,
            expect_interest,
            start_date,
            due_date,
            order_code,
            pay_code,
            wrapped_product_id=None,
            creation_time=None):
        cls.check_before_adding(user_id, bankcard_id, product_id, amount,
                                wrapped_product_id)

        sql = (
            'insert into {.table_name} (user_id, product_id, bankcard_id, amount, '
            'pay_amount, expect_interest, start_date, due_date, order_code, pay_code, '
            'status, wrapped_product_id, creation_time) values (%s, %s, %s, %s, %s, '
            '%s, %s, %s, %s, %s, %s, %s, %s)').format(cls)
        params = (user_id, product_id, bankcard_id, amount, pay_amount,
                  expect_interest, start_date, due_date, order_code, pay_code,
                  cls.Status.unpaid.value, wrapped_product_id, creation_time
                  or datetime.now())
        id_ = db.execute(sql, params)
        db.commit()

        order = cls.get(id_)
        order.clear_cache()
        return order