Example #1
0
    def get(self, disbursement_id):
        accounts = db.session.query(TransferAccount)\
            .filter(TransferAccount.disbursements.any(id=disbursement_id))\
            .options(joinedload(TransferAccount.disbursements))
        accounts, total_items, total_pages, new_last_fetched = paginate_query(
            accounts)
        if accounts is None:
            response_object = {
                'message': 'No transfer accounts',
            }

            return make_response(jsonify(response_object)), 400

        transfer_accounts = transfer_accounts_schema.dump(accounts).data
        d = db.session.query(Disbursement).filter_by(
            id=disbursement_id).first()
        disbursement = disbursement_schema.dump(d).data

        response_object = {
            'status': 'success',
            'message': 'Successfully Loaded.',
            'data': {
                'transfer_accounts': transfer_accounts,
                'disbursement': disbursement
            }
        }
        return make_response(jsonify(response_object)), 200
Example #2
0
    def get(self, disbursement_id):
        transfers = db.session.query(CreditTransfer)\
            .filter(CreditTransfer.disbursement.has(id=disbursement_id))\
            .options(joinedload(CreditTransfer.disbursement))

        transfers, total_items, total_pages, new_last_fetched = paginate_query(
            transfers)

        if transfers is None:
            response_object = {
                'message': 'No credit transfers',
            }

            return make_response(jsonify(response_object)), 400

        transfer_list = credit_transfers_schema.dump(transfers).data

        d = db.session.query(Disbursement).filter_by(
            id=disbursement_id).first()

        disbursement = disbursement_schema.dump(d).data

        response_object = {
            'status': 'success',
            'message': 'Successfully Loaded.',
            'items': total_items,
            'pages': total_pages,
            'last_fetched': new_last_fetched,
            'data': {
                'credit_transfers': transfer_list,
                'disbursement': disbursement
            }
        }
        return make_response(jsonify(response_object)), 200
Example #3
0
    def put(self, disbursement_id):
        put_data = request.get_json()
        action = put_data.get('action', '').upper()
        notes = put_data.get('notes') or ''

        if not disbursement_id:
            return {'message': 'Please provide a disbursement_id'}, 400
        if not action:
            return {'message': 'Please provide an action'}, 400
        if action not in ['APPROVE',
                          'REJECT']:  # We might want more actions later!
            return {'message': f'{action} not a valid action'}, 400

        # Ensure it's impossible to have two threads operating on the same disbursement
        with red.lock(name=f'Disbursemnt{disbursement_id}',
                      timeout=10,
                      blocking_timeout=20):

            disbursement = Disbursement.query.filter(Disbursement.id == disbursement_id)\
                .options(joinedload(Disbursement.credit_transfers))\
                .first()
            disbursement.notes = notes
            if not disbursement:
                return {
                    'message':
                    f'Disbursement with ID \'{disbursement_id}\' not found'
                }, 400

            if disbursement.state in ['APPROVED', 'REJECTED']:
                return {
                    'message':
                    f'Disbursement with ID \'{disbursement_id}\' has already been set to {disbursement.state.lower()}!'
                }, 400

            if action == 'APPROVE':
                disbursement.approve()
                db.session.commit()
                auto_resolve = False
                if current_app.config[
                        'REQUIRE_MULTIPLE_APPROVALS'] or AccessControl.has_sufficient_tier(
                            g.user.roles, 'ADMIN', 'superadmin'):
                    auto_resolve = True
                # A disbursement isn't necessarily approved after approve() is called, since we can require multiple approvers
                task_uuid = None
                if disbursement.state == 'APPROVED':
                    task_uuid = add_after_request_checkable_executor_job(
                        make_transfers,
                        kwargs={
                            'disbursement_id': disbursement.id,
                            'auto_resolve': auto_resolve
                        })

                data = disbursement_schema.dump(disbursement).data
                return {
                    'status': 'success',
                    'data': {
                        'disbursement': data
                    },
                    'task_uuid': task_uuid
                }, 200

            if action == 'REJECT':
                disbursement.reject()
                db.session.commit()

                data = disbursement_schema.dump(disbursement).data

                return {
                    'status': 'success',
                    'data': {
                        'disbursement': data
                    },
                }, 200
Example #4
0
    def post(self):
        post_data = request.get_json()

        # --- Handle Parameters ---
        # HANDLE PARAM : label - Name for the disbursement
        label = post_data.get('label') or ''
        # HANDLE PARAM : search_string - Any search string. An empty string (or None) will just return everything!
        search_string = post_data.get('search_string') or ''
        # HANDLE PARAM : params - Standard filter object. Exact same as the ones Metrics uses!
        encoded_filters = post_data.get('params')
        filters = process_transfer_filters(encoded_filters)
        # HANDLE PARAM : include_accounts - Explicitly include these users
        include_accounts = post_data.get('include_accounts', [])
        # HANDLE PARAM : include_accounts - Explicitly exclude these users
        exclude_accounts = post_data.get('exclude_accounts', [])
        disbursement_amount = abs(
            round(Decimal(post_data.get('disbursement_amount') or 0), 6))
        if include_accounts and exclude_accounts:
            return {
                'message':
                'Please either include or exclude users (include is additive from the whole search, while exclude is subtractive)'
            }
        # HANDLE PARAM : transfer_type - Transfer type-- either DISBURSEMENT, RECLAMATION, or BALANCE
        transfer_type = post_data.get('transfer_type', 'DISBURSEMENT')
        if transfer_type not in ['DISBURSEMENT', 'RECLAMATION', 'BALANCE']:
            return {
                'message':
                f'{transfer_type} not a valid transfer type. Please choose one of DISBURSEMENT, RECLAMATION, or BALANCE'
            }

        order_arg = request.args.get('order') or 'DESC'
        if order_arg.upper() not in ['ASC', 'DESC']:
            return {
                'message':
                'Invalid order value \'{}\'. Please use \'ASC\' or \'DESC\''.
                format(order_arg)
            }
        order = asc if order_arg.upper() == 'ASC' else desc
        sort_by_arg = request.args.get('sort_by') or 'rank'

        # --- Build Disbursement Object ---
        d = Disbursement(creator_user=g.user,
                         label=label,
                         search_string=search_string,
                         search_filter_params=encoded_filters,
                         include_accounts=include_accounts,
                         exclude_accounts=exclude_accounts,
                         disbursement_amount=disbursement_amount,
                         transfer_type=transfer_type)

        if include_accounts:
            transfer_accounts = db.session.query(TransferAccount).filter(
                TransferAccount.id.in_(include_accounts)).all()
        else:
            search_query = generate_search_query(search_string,
                                                 filters,
                                                 order,
                                                 sort_by_arg,
                                                 include_user=True)
            search_query = search_query.filter(
                TransferAccount.id.notin_(exclude_accounts))
            results = search_query.all()
            transfer_accounts = [
                r[0] for r in results
            ]  # Get TransferAccount (TransferAccount, searchRank, User)
        d.transfer_accounts.extend(transfer_accounts)

        db.session.flush()

        disbursement = disbursement_schema.dump(d).data

        response_object = {
            'data': {
                'status': 'success',
                'disbursement': disbursement
            }
        }
        return make_response(jsonify(response_object)), 201