Exemplo n.º 1
0
    def post(self, credit_transfer_id):

        auto_resolve = AccessControl.has_sufficient_tier(
            g.user.roles, 'ADMIN', 'superadmin')

        post_data = request.get_json()

        uuid = post_data.get('uuid')

        queue = 'low-priority'

        transfer_type = post_data.get('transfer_type')
        transfer_amount = abs(
            round(Decimal(post_data.get('transfer_amount') or 0), 6))
        token_id = post_data.get('token_id')
        target_balance = post_data.get('target_balance')

        transfer_use = post_data.get('transfer_use')
        try:
            use_ids = transfer_use.split(',')  # passed as '3,4' etc.
        except AttributeError:
            use_ids = transfer_use

        sender_user_id = post_data.get('sender_user_id')
        recipient_user_id = post_data.get('recipient_user_id')

        # These could be phone numbers, email, nfc serial numbers, card numbers etc
        sender_public_identifier = post_data.get('sender_public_identifier')
        recipient_public_identifier = post_data.get(
            'recipient_public_identifier')

        sender_transfer_account_id = post_data.get(
            'sender_transfer_account_id')
        recipient_transfer_account_id = post_data.get(
            'recipient_transfer_account_id')

        recipient_transfer_accounts_ids = post_data.get(
            'recipient_transfer_accounts_ids')

        # invert_recipient_list will send to everyone _except_ for the users in recipient_transfer_accounts_ids
        invert_recipient_list = post_data.get('invert_recipient_list', False)
        invert_recipient_list = False if invert_recipient_list == False else True

        credit_transfers = []
        response_list = []
        is_bulk = False
        transfer_card = None

        if uuid:
            existing_transfer = CreditTransfer.query.filter_by(
                uuid=uuid).first()

            # We return a 201 here so that the client removes the uuid from the cache
            response_object = {
                'message': 'Transfer Successful',
                'data': {
                    'credit_transfer':
                    credit_transfer_schema.dump(existing_transfer).data,
                }
            }
            return make_response(jsonify(response_object)), 201

        if transfer_amount <= 0 and not target_balance and not (
                transfer_amount == 0 and transfer_type == "BALANCE"):
            response_object = {
                'message': 'Transfer amount must be positive',
            }
            return make_response(jsonify(response_object)), 400

        if recipient_transfer_accounts_ids:
            is_bulk = True
            batch_uuid = str(uuid4())

            if transfer_type not in ["DISBURSEMENT", "BALANCE"]:
                response_object = {
                    'message':
                    'Bulk transfer must be either disbursement or balance',
                }
                return make_response(jsonify(response_object)), 400

            transfer_user_list = []
            individual_sender_user = None

            if invert_recipient_list:
                all_accounts_query = TransferAccount.query.filter(
                    TransferAccount.is_ghost != True).filter_by(
                        organisation_id=g.active_organisation.id)
                all_user_accounts_query = (all_accounts_query.filter(
                    TransferAccount.account_type == TransferAccountType.USER))
                all_accounts_except_selected_query = all_user_accounts_query.filter(
                    not_(
                        TransferAccount.id.in_(
                            recipient_transfer_accounts_ids)))
                for individual_recipient_user in all_accounts_except_selected_query.all(
                ):
                    transfer_user_list.append(
                        (individual_sender_user,
                         individual_recipient_user.primary_user, None))
            else:
                for transfer_account_id in recipient_transfer_accounts_ids:
                    try:
                        individual_recipient_user, transfer_card = find_user_with_transfer_account_from_identifiers(
                            None, None, transfer_account_id)
                        transfer_user_list.append(
                            (individual_sender_user, individual_recipient_user,
                             transfer_card))
                    except (NoTransferAccountError, UserNotFoundError) as e:
                        response_list.append({
                            'status': 400,
                            'message': str(e)
                        })

        else:
            batch_uuid = None
            try:
                individual_sender_user, transfer_card = find_user_with_transfer_account_from_identifiers(
                    sender_user_id, sender_public_identifier,
                    sender_transfer_account_id)

                individual_recipient_user, _ = find_user_with_transfer_account_from_identifiers(
                    recipient_user_id, recipient_public_identifier,
                    recipient_transfer_account_id)
                transfer_user_list = [
                    (individual_sender_user, individual_recipient_user,
                     transfer_card)
                ]

            except Exception as e:
                response_object = {
                    'message': str(e),
                }
                return make_response(jsonify(response_object)), 400

        if token_id:
            token = Token.query.get(token_id)
            if not token:
                response_object = {'message': 'Token not found'}
                return make_response(jsonify(response_object)), 404
        else:
            active_organisation = g.active_organisation
            if active_organisation is None:
                response_object = {'message': 'Must provide token_id'}
                return make_response(jsonify(response_object)), 400
            else:
                token = active_organisation.token

        for sender_user, recipient_user, transfer_card in transfer_user_list:
            try:
                if transfer_type == 'PAYMENT':
                    transfer = make_payment_transfer(
                        transfer_amount,
                        token=token,
                        send_user=sender_user,
                        receive_user=recipient_user,
                        transfer_use=transfer_use,
                        transfer_mode=TransferModeEnum.WEB,
                        uuid=uuid,
                        automatically_resolve_complete=False,
                        queue=queue,
                        batch_uuid=batch_uuid,
                        transfer_card=transfer_card)

                elif transfer_type == 'RECLAMATION':
                    transfer = make_payment_transfer(
                        transfer_amount,
                        token=token,
                        send_user=sender_user,
                        uuid=uuid,
                        transfer_subtype=TransferSubTypeEnum.RECLAMATION,
                        transfer_mode=TransferModeEnum.WEB,
                        require_recipient_approved=False,
                        automatically_resolve_complete=False,
                        queue=queue,
                        batch_uuid=batch_uuid)

                elif transfer_type == 'DISBURSEMENT':
                    transfer = make_payment_transfer(
                        transfer_amount,
                        token=token,
                        send_user=g.user,
                        receive_user=recipient_user,
                        uuid=uuid,
                        transfer_subtype=TransferSubTypeEnum.DISBURSEMENT,
                        transfer_mode=TransferModeEnum.WEB,
                        automatically_resolve_complete=False,
                        queue=queue,
                        batch_uuid=batch_uuid)

                elif transfer_type == 'BALANCE':
                    transfer = make_target_balance_transfer(
                        target_balance,
                        recipient_user,
                        uuid=uuid,
                        automatically_resolve_complete=False,
                        transfer_mode=TransferModeEnum.WEB,
                        queue=queue,
                    )
                if auto_resolve:
                    transfer.add_approver_and_resolve_as_completed()

            except (InsufficientBalanceError, AccountNotApprovedError,
                    InvalidTargetBalanceError, BlockchainError,
                    Exception) as e:

                if is_bulk:
                    response_list.append({'status': 400, 'message': str(e)})

                else:
                    db.session.commit()
                    response_object = {'message': str(e)}
                    return make_response(jsonify(response_object)), 400

            else:
                message = 'Transfer Successful' if auto_resolve else 'Transfer Pending. Must be approved.'
                if is_bulk:
                    credit_transfers.append(transfer)
                    response_list.append({'status': 201, 'message': message})

                else:
                    db.session.flush()
                    credit_transfer = credit_transfer_schema.dump(
                        transfer).data

                    response_object = {
                        'message': message,
                        'is_create': True,
                        'data': {
                            'credit_transfer': credit_transfer,
                        }
                    }

                    return make_response(jsonify(response_object)), 201

        db.session.flush()

        message = 'Bulk Transfer Creation Successful' if auto_resolve else 'Bulk Transfer Pending. Must be approved.'
        response_object = {
            'message': message,
            'bulk_responses': response_list,
            'data': {
                'credit_transfers':
                credit_transfers_schema.dump(credit_transfers).data
            }
        }

        return make_response(jsonify(response_object)), 201
Exemplo n.º 2
0
def make_transfers(disbursement_id, auto_resolve=False):
    send_transfer_account = g.user.default_organisation.queried_org_level_transfer_account
    from server.models.user import User
    from server.models.transfer_account import TransferAccount
    from server.models.disbursement import Disbursement
    disbursement = db.session.query(Disbursement).filter(
        Disbursement.id == disbursement_id).first()
    for idx, ta in enumerate(disbursement.transfer_accounts):
        try:
            user = ta.primary_user
            if disbursement.transfer_type == 'DISBURSEMENT':
                transfer = make_payment_transfer(
                    disbursement.disbursement_amount,
                    send_user=g.user,
                    receive_user=db.session.query(User).filter(
                        User.id == user.id).first(),
                    send_transfer_account=send_transfer_account,
                    receive_transfer_account=db.session.query(TransferAccount).
                    filter(TransferAccount.id == ta.id).first(),
                    transfer_subtype=TransferSubTypeEnum.DISBURSEMENT,
                    transfer_mode=TransferModeEnum.WEB,
                    automatically_resolve_complete=False,
                )
            if disbursement.transfer_type == 'RECLAMATION':
                transfer = make_payment_transfer(
                    disbursement.disbursement_amount,
                    send_user=db.session.query(User).filter(
                        User.id == user.id).first(),
                    send_transfer_account=db.session.query(TransferAccount).
                    filter(TransferAccount.id == ta.id).first(),
                    transfer_subtype=TransferSubTypeEnum.RECLAMATION,
                    transfer_mode=TransferModeEnum.WEB,
                    require_recipient_approved=False,
                    automatically_resolve_complete=False,
                )
            if disbursement.transfer_type == 'BALANCE':
                transfer = make_target_balance_transfer(
                    disbursement.disbursement_amount,
                    db.session.query(User).filter(User.id == user.id).first(),
                    automatically_resolve_complete=False,
                    transfer_mode=TransferModeEnum.WEB,
                )

            disbursement.credit_transfers.append(transfer)
            if auto_resolve and disbursement.state == 'APPROVED':
                transfer.approvers = disbursement.approvers
                transfer.add_approver_and_resolve_as_completed()
        except Exception as e:
            disbursement.errors = disbursement.errors + [
                str(ta) + ': ' + str(e)
            ]

        db.session.commit()
        percent_complete = (
            (idx + 1) / len(disbursement.transfer_accounts)) * 100

        yield {
            'message': 'success' if percent_complete == 100 else 'pending',
            'percent_complete': math.floor(percent_complete),
            'data': {
                'credit_transfers':
                credit_transfers_schema.dump(
                    disbursement.credit_transfers).data
            }
        }
    clear_metrics_cache()
    rebuild_metrics_cache()
Exemplo n.º 3
0
    def post(self, credit_transfer_id):

        auto_resolve = AccessControl.has_sufficient_tier(
            g.user.roles, 'ADMIN', 'superadmin')

        post_data = request.get_json()

        uuid = post_data.get('uuid')

        transfer_type = post_data.get('transfer_type')
        transfer_amount = abs(
            round(float(post_data.get('transfer_amount') or 0), 6))
        token_id = post_data.get('token_id')
        target_balance = post_data.get('target_balance')

        transfer_use = post_data.get('transfer_use')

        sender_user_id = post_data.get('sender_user_id')
        recipient_user_id = post_data.get('recipient_user_id')

        # These could be phone numbers, email, nfc serial numbers, card numbers etc
        sender_public_identifier = post_data.get('sender_public_identifier')
        recipient_public_identifier = post_data.get(
            'recipient_public_identifier')

        sender_transfer_account_id = post_data.get(
            'sender_transfer_account_id')
        recipient_transfer_account_id = post_data.get(
            'recipient_transfer_account_id')

        recipient_transfer_accounts_ids = post_data.get(
            'recipient_transfer_accounts_ids')
        credit_transfers = []
        response_list = []
        is_bulk = False

        if uuid:
            existing_transfer = CreditTransfer.query.filter_by(
                uuid=uuid).first()

            # We return a 201 here so that the client removes the uuid from the cache
            response_object = {
                'message': 'Transfer Successful',
                'data': {
                    'credit_transfer':
                    credit_transfer_schema.dump(existing_transfer).data,
                }
            }
            return make_response(jsonify(response_object)), 201

        if transfer_amount <= 0 and not target_balance:
            response_object = {
                'message': 'Transfer amount must be positive',
            }
            return make_response(jsonify(response_object)), 400

        if recipient_transfer_accounts_ids:
            is_bulk = True

            if transfer_type not in ["DISBURSEMENT", "BALANCE"]:
                response_object = {
                    'message':
                    'Bulk transfer must be either disbursement or balance',
                }
                return make_response(jsonify(response_object)), 400

            transfer_user_list = []
            for transfer_account_id in recipient_transfer_accounts_ids:
                try:
                    individual_sender_user = None
                    individual_recipient_user = find_user_with_transfer_account_from_identifiers(
                        None, None, transfer_account_id)

                    transfer_user_list.append(
                        (individual_sender_user, individual_recipient_user))

                except (NoTransferAccountError, UserNotFoundError) as e:
                    response_list.append({'status': 400, 'message': str(e)})

        else:
            try:
                individual_sender_user = find_user_with_transfer_account_from_identifiers(
                    sender_user_id, sender_public_identifier,
                    sender_transfer_account_id)

                individual_recipient_user = find_user_with_transfer_account_from_identifiers(
                    recipient_user_id, recipient_public_identifier,
                    recipient_transfer_account_id)

                transfer_user_list = [(individual_sender_user,
                                       individual_recipient_user)]

            except Exception as e:
                response_object = {
                    'message': str(e),
                }
                return make_response(jsonify(response_object)), 400

        if token_id:
            token = Token.query.get(token_id)
            if not token:
                response_object = {'message': 'Token not found'}
                return make_response(jsonify(response_object)), 404
        else:
            active_organisation = g.active_organisation
            if active_organisation is None:
                response_object = {'message': 'Must provide token_id'}
                return make_response(jsonify(response_object)), 400
            else:
                token = active_organisation.token

        for sender_user, recipient_user in transfer_user_list:

            try:
                if transfer_type == 'PAYMENT':
                    transfer = make_payment_transfer(
                        transfer_amount,
                        token=token,
                        send_user=sender_user,
                        receive_user=recipient_user,
                        transfer_use=transfer_use,
                        uuid=uuid,
                        automatically_resolve_complete=auto_resolve)

                elif transfer_type == 'RECLAMATION':
                    transfer = make_payment_transfer(
                        transfer_amount,
                        token=token,
                        send_user=sender_user,
                        uuid=uuid,
                        transfer_subtype=TransferSubTypeEnum.RECLAMATION,
                        require_recipient_approved=False,
                        automatically_resolve_complete=auto_resolve)

                elif transfer_type == 'DISBURSEMENT':
                    transfer = make_payment_transfer(
                        transfer_amount,
                        token=token,
                        send_user=g.user,
                        receive_user=recipient_user,
                        uuid=uuid,
                        transfer_subtype=TransferSubTypeEnum.DISBURSEMENT,
                        automatically_resolve_complete=auto_resolve)

                elif transfer_type == 'BALANCE':
                    transfer = make_target_balance_transfer(
                        target_balance,
                        recipient_user,
                        uuid=uuid,
                        automatically_resolve_complete=auto_resolve)

            except (InsufficientBalanceError, AccountNotApprovedError,
                    InvalidTargetBalanceError, BlockchainError,
                    Exception) as e:

                if is_bulk:
                    response_list.append({'status': 400, 'message': str(e)})

                else:
                    db.session.commit()
                    response_object = {'message': str(e)}
                    return make_response(jsonify(response_object)), 400

            else:
                message = 'Transfer Successful' if auto_resolve else 'Transfer Pending. Must be approved.'

                if is_bulk:
                    credit_transfers.append(transfer)

                    response_list.append({'status': 201, 'message': message})

                else:
                    db.session.flush()

                    credit_transfer = credit_transfer_schema.dump(
                        transfer).data

                    response_object = {
                        'message': message,
                        'is_create': True,
                        'data': {
                            'credit_transfer': credit_transfer,
                        }
                    }

                    return make_response(jsonify(response_object)), 201

        db.session.flush()

        message = 'Bulk Transfer Creation Successful' if auto_resolve else 'Bulk Transfer Pending. Must be approved.'
        response_object = {
            'message': message,
            'bulk_responses': response_list,
            'data': {
                'credit_transfers':
                credit_transfers_schema.dump(credit_transfers).data
            }
        }

        return make_response(jsonify(response_object)), 201
Exemplo n.º 4
0
def make_transfers(disbursement_id, auto_resolve=False):
    send_transfer_account = g.user.default_organisation.queried_org_level_transfer_account
    from server.models.user import User
    from server.models.transfer_account import TransferAccount
    from server.models.disbursement import Disbursement
    disbursement = db.session.query(Disbursement).filter(
        Disbursement.id == disbursement_id).first()
    for idx, ta in enumerate(disbursement.transfer_accounts):
        user = ta.primary_user
        if disbursement.transfer_type == 'DISBURSEMENT':
            transfer = make_payment_transfer(
                disbursement.disbursement_amount,
                send_user=g.user,
                receive_user=db.session.query(User).filter(
                    User.id == user.id).first(),
                send_transfer_account=send_transfer_account,
                receive_transfer_account=db.session.query(TransferAccount).
                filter(TransferAccount.id == ta.id).first(),
                transfer_subtype=TransferSubTypeEnum.DISBURSEMENT,
                transfer_mode=TransferModeEnum.WEB,
                automatically_resolve_complete=False,
            )
        if disbursement.transfer_type == 'RECLAMATION':
            transfer = make_payment_transfer(
                disbursement.disbursement_amount,
                send_user=db.session.query(User).filter(
                    User.id == user.id).first(),
                send_transfer_account=db.session.query(TransferAccount).filter(
                    TransferAccount.id == ta.id).first(),
                transfer_subtype=TransferSubTypeEnum.RECLAMATION,
                transfer_mode=TransferModeEnum.WEB,
                require_recipient_approved=False,
                automatically_resolve_complete=False,
            )
        if disbursement.transfer_type == 'BALANCE':
            transfer = make_target_balance_transfer(
                disbursement.disbursement_amount,
                db.session.query(User).filter(User.id == user.id).first(),
                automatically_resolve_complete=False,
                transfer_mode=TransferModeEnum.WEB,
            )

        disbursement.credit_transfers.append(transfer)

        if auto_resolve:
            # See below comment on batching issues
            transfer.resolve_as_complete_and_trigger_blockchain(
                batch_uuid=None)

        db.session.commit()
        percent_complete = (
            (idx + 1) / len(disbursement.transfer_accounts)) * 100
        yield {
            'message': 'success' if percent_complete == 100 else 'pending',
            'percent_complete': math.floor(percent_complete),
            'data': {
                'credit_transfers':
                credit_transfers_schema.dump(
                    disbursement.credit_transfers).data
            }
        }