def test_get_gifts_by_given_to(self):
        """Gifts endpoint which retrieves all gifts by given_to list ( methods = [ POST ] )."""

        with self.app.app_context():
            url = '/donation/gifts/given-to'

            # The given_to field enums: [ 'ACTION', 'NERF', 'SUPPORT' ]
            given_tos = GiftModel.given_to.property.columns[0].type.enums

            # Ensure that with no database entries endpoint returns nothing.
            response = self.test_client.post(url,
                                             data=json.dumps(
                                                 {'given_to': given_tos[0]}),
                                             content_type='application/json',
                                             headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 0)

            # Create one gift for each given_to.
            gift_models = []
            for given_to in given_tos:
                gift_model = from_json(GiftSchema(),
                                       get_gift_dict({
                                           'searchable_id':
                                           uuid.uuid4(),
                                           'given_to':
                                           given_to
                                       }),
                                       create=True)
                gift_models.append(gift_model.data)

            # Create one gift with the same enumeration for return of multiple gifts.
            gift_model = from_json(GiftSchema(),
                                   get_gift_dict({
                                       'searchable_id': uuid.uuid4(),
                                       'given_to': given_tos[0]
                                   }),
                                   create=True)
            gift_models.append(gift_model.data)

            database.session.bulk_save_objects(gift_models)
            database.session.commit()

            # Ensure that with the one duplicated given_to two gifts are returned.
            response = self.test_client.post(url,
                                             data=json.dumps(
                                                 {'given_to': given_tos[0]}),
                                             content_type='application/json',
                                             headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 2)

            # Ensure that with 2 given_tos 3 gifts are returned.
            response = self.test_client.post(
                url,
                data=json.dumps({'given_to': [given_tos[0], given_tos[1]]}),
                content_type='application/json',
                headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 3)
Example #2
0
    def post( self ):
        """Endpoint to return several Gifts from table given a date or a range of dates for attached Transactions."""
        gifts = get_gifts_by_date( request.json[ 'date' ] )
        # We are using dump many=True and so if a single gift returned need to put it in a list.

        schema = GiftSchema( many=True )
        result = schema.dump( gifts ).data
        return result, status.HTTP_200_OK
Example #3
0
    def post( self ):
        """Simple endpoint to return several rows from table given a list of ID's."""
        if not request.json[ 'searchable_ids' ]:
            return []

        gifts = get_gifts_by_searchable_ids( request.json[ 'searchable_ids' ] )
        schema = GiftSchema( many=True )
        result = schema.dump( gifts ).data
        return result, status.HTTP_200_OK
    def test_get_gifts_by_user_id_get(self):
        """Gifts endpoint which retrieves all gifts with given user_id ( methods = [ GET ] )."""

        with self.app.app_context():
            url = '/donation/gift/user/{}'

            # Ensure that with no database entries endpoint returns nothing.
            response = self.test_client.get(url.format(1),
                                            headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 0)

            # Create a gift with a user_id.
            gift_model = from_json(GiftSchema(),
                                   get_gift_dict({
                                       'searchable_id': uuid.uuid4(),
                                       'user_id': 1
                                   }),
                                   create=True)
            database.session.add(gift_model.data)
            database.session.commit()

            # Ensure that with a user_id on a gift it is returned
            response = self.test_client.get(url.format(1),
                                            headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 1)
    def test_gift_model(self):
        """A test to ensure that gifts are saved correctly to the database."""

        with self.app.app_context():

            gift_dict = get_gift_dict({
                'user_id': 1,
                'recurring_subscription_id': 'abcdefg'
            })

            gift_model = from_json(GiftSchema(), gift_dict, create=True)
            database.session.add(gift_model.data)
            database.session.commit()

            gift_query = GiftModel.query.filter_by(
                user_id=gift_dict['user_id']).one()
            gift_session = database.session.query(GiftModel).filter_by(
                user_id=gift_dict['user_id']).one()

            kwargs = {
                'self': self,
                'model_dict': gift_dict,
                'model': GiftModel,
                'model_data': gift_model.data,
                'model_query': gift_query,
                'model_session': gift_session
            }
            ensure_query_session_aligned(kwargs)
Example #6
0
    def test_get_transactions_by_gift( self ):
        """Retrieves all transactions with a specified gift searchable_id ( methods = [ GET ] )."""

        with self.app.app_context():
            # The parameter is for the searchable_id.
            url = '/donation/gifts/{}/transactions'

            # Create 3 gifts to attach transactions to.
            # Create each gift with a reproducible UUID.
            total_gifts = 5
            searchable_ids = get_gift_searchable_ids()
            gift_models = [ ]
            for i in range( 0, total_gifts ):  # pylint: disable=W0612
                gift_json = get_gift_dict()
                del gift_json[ 'id' ]
                gift_json[ 'searchable_id' ] = searchable_ids[ i ]
                gift_model = GiftSchema().load( gift_json ).data
                gift_models.append( gift_model )
            database.session.bulk_save_objects( gift_models )
            database.session.commit()

            # Create 3 transactions attached to the same gift ID = 1, one transaction to 4 and none on 5.
            total_transactions = 5
            transaction_models = []
            for i in range( 0, total_transactions ):  # pylint: disable=W0612
                transaction_json = get_transaction_dict()
                del transaction_json[ 'id' ]
                if i <= 2:
                    transaction_json[ 'gift_id' ] = 1
                    transaction_json[ 'gift_searchable_id' ] = uuid.UUID( searchable_ids[ 0 ] ).hex
                elif i == 3:
                    transaction_json[ 'gift_id' ] = i
                    transaction_json[ 'gift_searchable_id' ] = uuid.UUID( searchable_ids[ i ] ).hex
                else:
                    transaction_json[ 'gift_id' ] = i
                    transaction_json[ 'gift_searchable_id' ] = uuid.UUID( searchable_ids[ i ] ).hex

                transaction_model = TransactionSchema().load( transaction_json ).data
                transaction_models.append( transaction_model )

            database.session.bulk_save_objects( transaction_models )
            database.session.commit()

            # searchable_ids[ 0 ] is gift ID = 1 and will have 3 transactions.
            response = self.test_client.get( url.format( uuid.UUID( searchable_ids[ 0 ] ).hex ), headers=self.headers )
            self.assertEqual( len( json.loads( response.data.decode( 'utf-8' ) ) ), 3 )

            # searchable_ids[ 2 ] is gift ID = 3 and will have 1 transactions.
            response = self.test_client.get( url.format( uuid.UUID( searchable_ids[ 2 ] ).hex ), headers=self.headers )
            self.assertEqual( len( json.loads( response.data.decode( 'utf-8' ) ) ), 1 )

            # searchable_ids[ 4 ] is gift ID = 5 and will have 0 transactions.
            response = self.test_client.get( url.format( uuid.UUID( searchable_ids[ 4 ] ).hex ), headers=self.headers )
            self.assertEqual( len( json.loads( response.data.decode( 'utf-8' ) ) ), 0 )
Example #7
0
    def get( self ):
        """Simple endpoint to retrieve all rows from table."""

        query_terms = build_filter_from_request_args( request.args )
        link_header_query_terms = None
        # Build the page and sort information from the filter results on the query string.
        # Delete these keys and pass along only the model filter/search terms.
        page_information = {}
        sort_information = []
        if query_terms:
            page_information = {}
            if 'paginate' in query_terms and query_terms[ 'paginate' ]:
                page_information = {
                    'page_number': query_terms[ 'paginate' ][ 'page_number' ],
                    'rows_per_page': query_terms[ 'paginate' ][ 'rows_per_page' ]
                }
                del query_terms[ 'paginate' ]

            link_header_query_terms = copy.deepcopy( query_terms )

            if 'sort' in query_terms and query_terms[ 'sort' ]:
                sort_information = query_terms[ 'sort' ]
                del query_terms[ 'sort' ]

        gifts = get_gifts( query_terms, page_information=page_information, sort_information=sort_information )

        if page_information:
            transformed_data = transform_data(
                'donation/gifts',
                link_header_query_terms,
                gifts,
                GiftSchema
            )
            response = jsonify( transformed_data[ 'page' ] )
            response.headers[ 'Link' ] = transformed_data[ 'link-header' ]
            response.status_code = status.HTTP_200_OK
            return response

        schema = GiftSchema( many=True )
        result = schema.dump( gifts ).data
        return result, status.HTTP_200_OK
Example #8
0
def create_gift_and_transaction():
    """A function to create a gift and an attached transaction for a given Braintree sale.

    Sometimes while testing a developer will need to have a specific gift and transaction in the database that
    would have been created for a Braintree sale. This function allows you to specify Braintree reference numbers,
    e.g. transaction sale ID and the subscription reference number, and create the gift and transaction associated
    with that sale.
    """

    with app.app_context():

        # These are the Braintree subscription ID and transaction sale ID to create a gift and transaction for.
        # Change this to suit your needs.
        subscription_id = 'kfwgzr'
        transaction_id = '83afbynd'

        date_start = datetime.utcnow().replace( hour=23, minute=59, second=59, microsecond=9999 )
        utc_dates = [ date_start - timedelta( hours=hours, minutes=30 ) for hours in range( 1, 25 ) ]

        pairs = 1
        for date_in_utc in utc_dates:
            i = 0
            while i < pairs:
                i += 1
                # Create a gift.
                gift_json = get_gift_dict( { 'recurring_subscription_id': subscription_id } )
                gift_json[ 'searchable_id' ] = uuid.uuid4()
                del gift_json[ 'id' ]

                gift_model = GiftSchema().load( gift_json ).data

                database.session.add( gift_model )
                database.session.flush()
                gift_id = gift_model.id

                # Create 4 transactions per each gift.
                transaction_json = get_transaction_dict( { 'gift_id': gift_id } )
                transaction_json[ 'type' ] = 'Gift'
                transaction_json[ 'status' ] = 'Completed'
                del transaction_json[ 'id' ]
                transaction_model = TransactionSchema().load( transaction_json ).data
                transaction_model.reference_number = transaction_id
                transaction_model.date_in_utc = date_in_utc

                transaction_model.reference_number = transaction_id
                transaction_model.notes = '{} : {}'.format( str( 1 ), str( gift_json[ 'searchable_id' ] ) )
                database.session.add( transaction_model )

        database.session.commit()
    def test_get_gifts_by_user_id_post(self):
        """Gifts endpoint which retrieves all gifts with list of given user_id's ( methods = [ POST ] )."""

        with self.app.app_context():
            url = '/donation/gift/user'

            # Ensure that with no database entries endpoint returns nothing.
            response = self.test_client.post(url,
                                             data=json.dumps(
                                                 {'user_ids': [1, 3]}),
                                             content_type='application/json',
                                             headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 0)

            # Create a gift with a user_id.
            max_number_of_users = 5
            gift_models = create_model_list(GiftSchema(), get_gift_dict(),
                                            max_number_of_users, 'user_id')

            database.session.bulk_save_objects(gift_models)
            database.session.commit()

            # Ensure that with no users endpoint returns no gifts.
            response = self.test_client.post(url,
                                             data=json.dumps({'user_ids': []}),
                                             content_type='application/json',
                                             headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 0)

            # Ensure that with one user endpoint returns one gift.
            response = self.test_client.post(url,
                                             data=json.dumps({'user_ids':
                                                              [2]}),
                                             content_type='application/json',
                                             headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 1)

            # Ensure that with multiple users endpoint returns multiple gifts.
            response = self.test_client.post(url,
                                             data=json.dumps(
                                                 {'user_ids': [2, 3, 4]}),
                                             content_type='application/json',
                                             headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 3)
    def test_put_gift_update_note(self):
        """Gifts endpoint to add a note to a gift with searchable_id ( methods = [ PUT ] )."""

        with self.app.app_context():
            # Parameter in URL is for a searchable_id_prefix.
            url = '/donation/gift/{}/notes'

            agent_dict = get_agent_dict({
                'name': 'Aaron Peters',
                'user_id': 3255162,
                'type': 'Staff Member'
            })
            agent_model = from_json(AgentSchema(), agent_dict, create=True)
            database.session.add(agent_model.data)

            gift_transactions = TransactionModel.query.all()
            # Ensure no transactions in the database.
            self.assertEqual(len(gift_transactions), 0)

            gift_json = get_gift_dict()
            del gift_json['id']
            gift_json['searchable_id'] = uuid.uuid4()
            gift_model = GiftSchema().load(gift_json).data
            database.session.add(gift_model)
            database.session.commit()

            transaction_note = {
                'enacted_by_agent_id': '5',
                'note': 'Add this to the Gift please.'
            }

            response = self.test_client.put(url.format(
                gift_model.searchable_id.hex),
                                            data=json.dumps(transaction_note),
                                            content_type='application/json',
                                            headers=self.headers)

            self.assertEqual(response.status_code, status.HTTP_200_OK)

            # Make sure a transaction was added.
            gift_transactions = TransactionModel.query.all()

            self.assertEqual(len(gift_transactions), 1)
            self.assertEqual(gift_transactions[0].notes,
                             transaction_note['note'])
    def test_get_gifts(self):
        """Gifts endpoint with no ID's retrieves all ( methods = [ GET ] )."""

        with self.app.app_context():
            url = '/donation/gifts'

            # Ensure a GET with no saved gifts returns 0.
            response = self.test_client.get(url, headers=self.headers)
            self.assertEqual(len(json.loads(response.data.decode('utf-8'))), 0)

            # To create each gift with a new UUID call get_gift_dict() separately.
            total_gifts = 5
            gift_models = []
            for i in range(0, total_gifts):  # pylint: disable=W0612
                gift_json = get_gift_dict()
                del gift_json['id']
                gift_json['searchable_id'] = uuid.uuid4()
                gift_model = GiftSchema().load(gift_json).data
                gift_models.append(gift_model)
            database.session.bulk_save_objects(gift_models)
            database.session.commit()

            # Ensure GET returns all gifts.
            response = self.test_client.get(url, headers=self.headers)
            self.assertEqual(len(json.loads(response.data.decode('utf-8'))),
                             total_gifts)

            # Ensure GET retrieves 2 gifts and they have the correct ID's.
            searchable_ids = [
                str(gift_models[0].searchable_id),
                str(gift_models[1].searchable_id)
            ]
            searchable_id_parameters = 'in:{},{}'.format(
                searchable_ids[0], searchable_ids[1])
            url_with_parameters = '{}?searchable_id={}'.format(
                url, searchable_id_parameters)
            response = self.test_client.get(url_with_parameters,
                                            headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 2)
            self.assertEqual(data_returned[0]['searchable_id'],
                             searchable_ids[0])
            self.assertEqual(data_returned[1]['searchable_id'],
                             searchable_ids[1])
    def test_get_gifts_by_date_future(self):
        """Gifts endpoint which retrieves all gifts newer than date, or between 2 dates ( methods = [ POST ] )."""

        with self.app.app_context():
            url = '/donation/gifts/date'

            # Ensure that with no database entries endpoint returns nothing.
            date_in_utc_now = datetime.utcnow()
            response = self.test_client.post(
                url,
                data=json.dumps({'date':
                                 date_in_utc_now.strftime('%Y-%m-%d')}),
                content_type='application/json',
                headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 0)

            # Create some gifts to retrieve.
            total_gifts = 2
            gift_models = create_model_list(GiftSchema(), get_gift_dict(),
                                            total_gifts)

            # Create a set of transactions and attach to a specific gift.
            # Here are the time deltas: { gift 1: [ 0, -2, -4, -6 ], gift 2: [ -8, -10, -12, -14 ] }
            total_transactions = 4
            transaction_models = create_gift_transactions_date(
                TransactionSchema(), get_transaction_dict(),
                total_transactions, total_gifts)

            database.session.bulk_save_objects(gift_models)
            database.session.bulk_save_objects(transaction_models)
            database.session.commit()

            date_in_utc_now = datetime.utcnow()

            # Date in the future should bring back no results.
            date_in_utc = date_in_utc_now + timedelta(days=2)
            response = self.test_client.post(
                url,
                data=json.dumps({'date': date_in_utc.strftime('%Y-%m-%d')}),
                content_type='application/json',
                headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 0)
def build_models_sale(user, gift, transactions):
    """Given the dictionaries for the models go ahead and build them.

    :param dict user: User dictionary with necessary model fields, and may have additional fields.
    :param dict gift: Gift dictionary with necessary model fields, and may have additional fields.
    :param transactions: The list of transactions. If this is a Braintree sale, for example, there will be one
           transaction in the list. On the other hand if this is an administrative sale where the method used is
           a check or money order there will be 2 transactions.
    :return:
    """

    # We are not caging at the front of the sale, and do that at the end.
    # The user is stored in QueuedDonorModel and the gift is given a user_id = -2
    user_id = -2

    # Build the gift model dictionary, and flush to get new auto-incremented gift_id.
    try:
        # Build the gift.
        if not gift['campaign_id']:
            gift['campaign_id'] = None
        elif not get_campaign_by_id(gift['campaign_id']):
            gift['campaign_id'] = get_campaigns_by_type('is_default', 1)[0].id

        gift['user_id'] = user_id
        gift_model = from_json(GiftSchema(), gift)
        database.session.add(gift_model.data)
        database.session.flush()
        gift_id = gift_model.data.id
        user['gift_id'] = gift_id
        user['gift_searchable_id'] = gift_model.data.searchable_id
        user['campaign_id'] = gift_model.data.campaign_id

        # Build the transactions.
        for transaction in transactions:
            transaction['gift_id'] = gift_id
            transaction_model = from_json(TransactionSchema(), transaction)
            database.session.add(transaction_model.data)
            database.session.flush()
            transaction['id'] = transaction_model.data.id
        database.session.commit()
    except:
        database.session.rollback()
        raise BuildModelsGiftTransactionsPathError()
Example #14
0
def build_gift(gift_dict):
    """Given a dictionary for the Gift builds, commits and returns the model.

    Uses flush() so we can get the Gift ID.

    :param gift_dict: The Gift dictionary.
    :return: gift_model.data: The Gift model built from the given dictionary and has the new auto-incremented ID.
    """

    with app.app_context():
        gift_model = from_json(GiftSchema(), gift_dict, create=True)
        database.session.add(gift_model.data)
        database.session.flush()
        database.session.commit()
        print()
        print('Build GiftModel')
        print('    gift_model.id      : {}'.format(gift_model.data.id))
        print('    gift_model.given_to: {}'.format(gift_model.data.given_to))
        print()
        return gift_model.data
Example #15
0
    def test_build_transaction( self ):
        """Transactions endpoint to add a transaction to a gift with searchable_id ( methods = [ POST ] )."""

        with self.app.app_context():
            # Parameter in URL is for a searchable_id_prefix.
            url = '/donation/gift/transaction'

            agent_dict = get_agent_dict( { 'name': 'Aaron Peters', 'user_id': 3255162, 'type': 'Staff Member' } )
            agent_model = from_json( AgentSchema(), agent_dict, create=True )
            database.session.add( agent_model.data )

            # Create a gift to attach a transaction to.
            gift_json = get_gift_dict()
            del gift_json[ 'id' ]
            gift_json[ 'searchable_id' ] = uuid.uuid4()
            gift_model = GiftSchema().load( gift_json ).data
            database.session.add( gift_model )
            database.session.commit()

            gift = GiftModel.query.all()[ 0 ]

            # Ensure no transactions currently on gift.
            self.assertEqual( len( gift.transactions ), 0 )

            new_transaction = get_transaction_dict(
                {
                    'gift_searchable_id': gift_json[ 'searchable_id' ].hex,
                    'enacted_by_agent_id': None
                }
            )

            self.test_client.post(
                url,
                data=json.dumps( new_transaction ),
                content_type='application/json',
                headers=self.headers
            )

            # Ensure the new transactions is now on the gift.
            self.assertEqual( len( gift.transactions ), 1 )
            self.assertEqual( gift.transactions[ 0 ].gift_searchable_id.hex, gift_json[ 'searchable_id' ].hex )
    def test_get_gifts_partial_id(self):
        """Gifts endpoint to get a list of Gifts given a partial searchable_id ( methods = [ GET ] )."""

        with self.app.app_context():
            # Parameter in URL is for a searchable_id_prefix.
            url = '/donation/gifts/uuid_prefix/{}'

            # Create each gift with a reproducible UUID.
            total_gifts = 5
            searchable_ids = get_gift_searchable_ids()
            gift_models = []
            for i in range(0, total_gifts):  # pylint: disable=W0612
                gift_json = get_gift_dict()
                del gift_json['id']
                gift_json['searchable_id'] = searchable_ids[i]
                gift_model = GiftSchema().load(gift_json).data
                gift_models.append(gift_model)
            database.session.bulk_save_objects(gift_models)
            database.session.commit()

            # searchable_ids[ 0:2 ] have the same first 5 characters: this test should return those 2.
            response = self.test_client.get(url.format(searchable_ids[0][:5]),
                                            headers=self.headers)
            self.assertEqual(len(json.loads(response.data.decode('utf-8'))), 2)

            # searchable_ids[ 1 ] shares first 5 characters, but is unique as a whole and should return 1.
            searchable_id_uuid = uuid.UUID(searchable_ids[1]).hex
            response = self.test_client.get(url.format(searchable_id_uuid),
                                            headers=self.headers)
            self.assertEqual(len(json.loads(response.data.decode('utf-8'))), 1)

            # searchable_ids[ 2 ] is unique and first 5 characters should return 1.
            response = self.test_client.get(url.format(searchable_ids[2][:5]),
                                            headers=self.headers)
            self.assertEqual(len(json.loads(response.data.decode('utf-8'))), 1)

            # searchable_ids[ 5 ] is not in the database.
            searchable_id_uuid = uuid.UUID(searchable_ids[5]).hex
            response = self.test_client.get(url.format(searchable_id_uuid),
                                            headers=self.headers)
            self.assertEqual(len(json.loads(response.data.decode('utf-8'))), 0)
    def test_get_gifts_with_id(self):
        """Gifts-transaction endpoint with one gift ID retrieves all transactions on gift ( methods = [ GET ] )."""

        with self.app.app_context():
            url = '/donation/gifts/{}/transactions'

            # Ensure that with no database entries endpoint returns nothing.
            response = self.test_client.get(url.format(str(uuid.uuid4())),
                                            headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 0)

            # Create some gifts to retrieve.
            total_gifts = 5
            gift_models = create_model_list(GiftSchema(), get_gift_dict(),
                                            total_gifts)

            # Create a set of transactions and attach to a specific gift.
            total_transactions = 5
            transaction_gift_id = 3

            transaction_models = create_model_list(
                TransactionSchema(),
                get_transaction_dict({'gift_id': transaction_gift_id}),
                total_transactions)

            database.session.bulk_save_objects(gift_models)
            database.session.bulk_save_objects(transaction_models)
            database.session.commit()

            # Build the URL using the searchable_id of the gift.
            gift_3 = GiftModel.query.filter_by(id=3).one_or_none()
            searchable_id = gift_3.searchable_id

            # Ensure GET retrieves the specified gift and all its transactions.
            response = self.test_client.get(url.format(str(searchable_id)),
                                            headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), total_transactions)
Example #18
0
    def test_admin_record_bounced_check(self):
        """Test for recording a bounced check."""

        with self.app.app_context():
            # Create 2 gifts: one for the transaction that needs to record bounced check, the other to query against.

            # Create the bank and sourced by agents for recording a check.
            agent_dict = get_agent_dict({
                'name': 'Fidelity Bank',
                'type': 'Organization'
            })
            bank_agent_model = from_json(AgentSchema(),
                                         agent_dict,
                                         create=True)
            database.session.add(bank_agent_model.data)
            database.session.flush()

            agent_user_id = 3255162
            agent_dict = get_agent_dict({
                'name': 'Aaron Peters',
                'user_id': agent_user_id,
                'type': 'Staff Member'
            })
            user_agent_model = from_json(AgentSchema(),
                                         agent_dict,
                                         create=True)
            database.session.add(user_agent_model.data)
            database.session.flush()

            # Here is the first gift as check.
            gift_dict = get_gift_dict({
                'method_used_id': 3,
                'sourced_from_agent_id': 1,
                'reference_number': '1201',
                'customer_id': ''
            })
            gift_model = from_json(GiftSchema(), gift_dict, create=True)
            database.session.add(gift_model.data)
            database.session.flush()
            gift_searchable_id = gift_model.data.searchable_id

            # Create the 2nd gift as check.
            gift_dict = get_gift_dict({
                'method_used_id': 3,
                'sourced_from_agent_id': 1
            })
            gift_model = from_json(GiftSchema(), gift_dict, create=True)
            database.session.add(gift_model.data)
            database.session.flush()

            # Create 2 transactions on the first gift for the check.
            transaction_dict = get_transaction_dict({
                'gift_id':
                1,
                'enacted_by_agent_id':
                1,
                'type':
                'Gift',
                'gross_gift_amount':
                Decimal('25.00'),
                'reference_number':
                '1201'
            })
            transaction_model = from_json(TransactionSchema(),
                                          transaction_dict,
                                          create=True)
            database.session.add(transaction_model.data)

            transaction_dict = get_transaction_dict({
                'gift_id':
                1,
                'enacted_by_agent_id':
                2,
                'type':
                'Deposit to Bank',
                'gross_gift_amount':
                Decimal('25.00'),
                'reference_number':
                '<bank-deposit-number>'
            })
            transaction_model = from_json(TransactionSchema(),
                                          transaction_dict,
                                          create=True)
            database.session.add(transaction_model.data)

            # Put a transaction on the second gift.
            transaction_dict = get_transaction_dict({
                'gift_id':
                2,
                'enacted_by_agent_id':
                1,
                'type':
                'Refund',
                'gross_gift_amount':
                Decimal('25.00')
            })
            transaction_model = from_json(TransactionSchema(),
                                          transaction_dict,
                                          create=True)
            database.session.add(transaction_model.data)

            database.session.flush()
            database.session.commit()

            # Call the function to test.
            # Needs the JWT Ultsys agent user ID because calling function directly ( not through resource ).
            payload = {
                'gift_searchable_id': gift_searchable_id,
                'reference_number': '1201',
                'transaction_notes': '',
                'gross_gift_amount': '0.00',
                'user_id': 3255162
            }

            # Calling the function for recording the bounced check directly and bypassing JWT is resource.
            record_bounced_check = admin_record_bounced_check(payload)

            transaction_bounced_check = TransactionModel.query\
                .filter_by( type=self.parameters[ 'transaction_type_bounced' ] ).one_or_none()

            self.assertEqual(record_bounced_check, True)
            self.assertEqual(transaction_bounced_check.enacted_by_agent_id, 2)
            self.assertEqual(transaction_bounced_check.type,
                             self.parameters['transaction_type_bounced'])
            self.assertEqual(transaction_bounced_check.gross_gift_amount,
                             self.parameters['gift_amount_bounced'])
Example #19
0
def create_database_transactions():
    """Uses Braintree sales during a specified interval to build the initial gift and transaction in the database.

    Very useful for filling the database and then running the transaction updater for testing. The transactions
    created here will have type 'Gift' and status 'Completed'.
    """

    dates = {'month_0': 7, 'day_0': 1, 'month_1': 7, 'day_1': 31}
    date1 = datetime.utcnow().replace(month=dates['month_1'],
                                      day=dates['day_1'],
                                      hour=23,
                                      minute=59,
                                      second=59,
                                      microsecond=9999)
    date0 = datetime.utcnow().replace(month=dates['month_0'],
                                      day=dates['day_0'],
                                      hour=0,
                                      minute=0,
                                      second=0,
                                      microsecond=0)
    print('{} ~ {}'.format(date0.strftime(MODEL_DATE_STRING_FORMAT),
                           date1.strftime(MODEL_DATE_STRING_FORMAT)))

    with app.app_context():

        date_in_utc = datetime.fromtimestamp(0)
        sales_authorized = {}
        search_at(date0, date1, 'authorized_at', sales_authorized)
        for sales_id, sale in sales_authorized.items():  # pylint: disable=unused-variable
            gift_dict = {
                'id': None,
                'searchable_id': uuid.uuid4(),
                'user_id': 999999999,
                'method_used': 'Web Form Credit Card',
                'sourced_from_agent_id': AGENT_ID,
                'given_to': MERCHANT_ID_GIVEN_TO[sale.merchant_account_id],
                'recurring_subscription_id': sale.subscription_id
            }
            gift_model = from_json(GiftSchema(), gift_dict)
            database.session.add(gift_model.data)
            database.session.flush()
            database.session.commit()

            for history_item in sale.status_history:
                date_in_utc = datetime.fromtimestamp(0)
                if history_item.status == 'authorized':
                    date_in_utc = history_item.timestamp.strftime(
                        MODEL_DATE_STRING_FORMAT)
                    break

            transaction_dict = {
                'gift_id':
                gift_model.data.id,
                'date_in_utc':
                date_in_utc,
                'enacted_by_agent_id':
                AGENT_ID,
                'type':
                'Gift',
                'status':
                'Completed',
                'reference_number':
                sale.id,
                'gross_gift_amount':
                sale.amount,
                'fee':
                sale.service_fee_amount
                if sale.service_fee_amount else Decimal(0),
                'notes':
                'Automated creation of transaction.'
            }

            transaction_model = from_json(TransactionSchema(),
                                          transaction_dict)
            database.session.add(transaction_model.data)
            database.session.commit()
Example #20
0
 def post( self ):
     """Endpoint to return several Gifts from table given a given_to."""
     gifts = get_gifts_by_given_to( request.json[ 'given_to' ] )
     schema = GiftSchema( many=True )
     result = schema.dump( gifts ).data
     return result, status.HTTP_200_OK
Example #21
0
    def test_get_transactions_by_gifts( self ):
        """Retrieves all transactions or those in a list of gift searchable_id's ( methods = [ GET, POST ] )."""

        with self.app.app_context():
            # The parameter is for the searchable_id.
            url = '/donation/gifts/transactions'

            # Create 3 gifts to attach transactions to.
            # Create each gift with a reproducible UUID.
            total_gifts = 5
            searchable_ids = get_gift_searchable_ids()
            gift_models = [ ]
            for i in range( 0, total_gifts ):  # pylint: disable=W0612
                gift_json = get_gift_dict()
                del gift_json[ 'id' ]
                gift_json[ 'searchable_id' ] = searchable_ids[ i ]
                gift_model = GiftSchema().load( gift_json ).data
                gift_models.append( gift_model )
            database.session.bulk_save_objects( gift_models )
            database.session.commit()

            # Create 3 transactions attached to the same gift ID = 1, one transaction to 4 and none on 5.
            total_transactions = 5
            transaction_models = []
            for i in range( 0, total_transactions ):  # pylint: disable=W0612
                transaction_json = get_transaction_dict()
                del transaction_json[ 'id' ]
                if i <= 2:
                    transaction_json[ 'gift_id' ] = 1
                    transaction_json[ 'gift_searchable_id' ] = uuid.UUID( searchable_ids[ 0 ] ).hex
                elif i == 3:
                    transaction_json[ 'gift_id' ] = i
                    transaction_json[ 'gift_searchable_id' ] = uuid.UUID( searchable_ids[ i ] ).hex
                else:
                    transaction_json[ 'gift_id' ] = i
                    transaction_json[ 'gift_searchable_id' ] = uuid.UUID( searchable_ids[ i ] ).hex

                transaction_model = TransactionSchema().load( transaction_json ).data
                transaction_models.append( transaction_model )

            database.session.bulk_save_objects( transaction_models )
            database.session.commit()

            # Get all transactions in the database.
            response = self.test_client.get( url, headers=self.headers )
            self.assertEqual( len( json.loads( response.data.decode( 'utf-8' ) ) ), 5 )

            # searchable_ids[ 0 ] is gift ID = 1 and will have 3 transactions: test string searchable ID.
            response = self.test_client.post(
                url,
                data=json.dumps( { 'searchable_ids': uuid.UUID( searchable_ids[ 0 ] ).hex } ),
                content_type='application/json',
                headers=self.headers
            )

            self.assertEqual( len( json.loads( response.data.decode( 'utf-8' ) ) ), 3 )

            # Gift ID = 1 and 2 and will have a total of 4 transactions: test list of searchable ID's.
            response = self.test_client.post(
                url,
                data=json.dumps(
                    {
                        'searchable_ids':
                            [ uuid.UUID( searchable_ids[ 0 ] ).hex, uuid.UUID( searchable_ids[ 2 ] ).hex ]
                    }
                ),
                content_type='application/json',
                headers=self.headers
            )

            self.assertEqual( len( json.loads( response.data.decode( 'utf-8' ) ) ), 4 )
Example #22
0
def create_database_tables():
    """A function to create the DONATE database tables, specifically the GiftModel with UUID.

    The GiftModel is build using Marshmallow schema GiftSchema, which deserializes a dictionary to the model:
    The searchable_id in the gift_json is:
        gift_json[ 'searchable_id' ] = uuid.uuid4()
    This gets passed to the GiftSchema where:
        searchable_id = fields.UUID()
    And so the validation step is passed.
    MySql does not have a UUID type though and there we have ( GiftModel ):
        searchable_id = database.Column( database.BINARY( 16 ), nullable=False, default=uuid.uuid4().bytes )
    The helper model class BinaryUUID in binary_uuid.py handles the serialization in and out.
    """

    with app.app_context():

        type = { 3: 'Gift', 2: 'Deposit to Bank', 1: 'Dispute', 0: 'Refund' }
        # Create 100 gifts.
        for i in range( 0, 100 ):
            gift_json = get_gift_dict()
            del gift_json[ 'id' ]
            gift_json[ 'searchable_id' ] = uuid.uuid4()
            gift_model = GiftSchema().load( gift_json ).data

            # Add the index as a note for debugging Gifts, since they exclude ID.
            gift_model.notes = '{} : {}'.format( str( i + 1 ), str( gift_json[ 'searchable_id' ] ) )

            database.session.add( gift_model )
            database.session.flush()
            gift_id = gift_model.id

            # Create 4 transactions per each gift.
            transactions = []
            start_datetime = datetime.utcnow()
            for j in range( 0, 4 ):  # pylint: disable=unused-variable
                test_datetime = start_datetime - timedelta( days=j )
                test_datetime = test_datetime.strftime( '%Y-%m-%d %H:%M:%S' )
                transaction_json = get_transaction_dict( {
                    'gift_id': gift_id,
                    'date_in_utc': test_datetime,
                    'gross_gift_amount': Decimal( 25 - j ),
                    'type': type[ j ],
                    'status': 'Completed'
                } )
                del transaction_json[ 'id' ]
                transaction_model = TransactionSchema().load( transaction_json ).data
                transactions.append( transaction_model )
            database.session.bulk_save_objects( transactions )

        # Create the agents.
        # agent_jsons = [
        #     { 'name': 'Donate API', 'user_id': None, 'staff_id': None, 'type': 'Automated' },
        #     { 'name': 'Braintree', 'user_id': None, 'staff_id': None, 'type': 'Organization' },
        #     { 'name': 'PayPal', 'user_id': None, 'staff_id': None, 'type': 'Organization' },
        #     { 'name': 'Credit Card Issuer', 'user_id': None, 'staf_id': None, 'type': 'Organization' },
        #     { 'name': 'Unspecified NumbersUSA Staff', 'user_id': None, 'staff_id': None, 'type': 'Staff Member' },
        #     { 'name': 'Dan Marsh', 'user_id': 1234, 'staff_id': 4321, 'type': 'Staff Member' },
        #     { 'name': 'Joshua Turcotte', 'user_id': 7041, 'staff_id': 1407, 'type': 'Staff Member' },
        #     { 'name': 'Donate API', 'user_id': None, 'staff_id': None, 'type': 'Automated' }
        # ]
        # agents = []
        # for agent_json in agent_jsons:
        #     agent_model = AgentSchema().load( agent_json ).data
        #     agents.append( agent_model )
        # database.session.bulk_save_objects( agents )

        database.session.commit()
Example #23
0
 def post( self ):
     """Endpoint to return several Gifts from table given a list of user ID's."""
     gifts = get_gifts_by_user_id( request.json[ 'user_ids' ] )
     schema = GiftSchema( many=True )
     result = schema.dump( gifts ).data
     return result, status.HTTP_200_OK
Example #24
0
 def get( self, user_id ):
     """Endpoint to return several Gifts from table given a user ID."""
     gift = get_gifts_by_user_id( user_id )
     schema = GiftSchema( many=True )
     result = schema.dump( gift ).data
     return result, status.HTTP_200_OK
    def test_get_gift_update_note(self):
        """Gifts endpoint to get a list of notes given a gift_searchable_id ( methods = [ GET ] )."""

        with self.app.app_context():
            # Parameter in URL is for a searchable_id_prefix.
            url = '/donation/gift/{}/notes'

            # Create 3 gifts to attach transactions to.
            # Create each gift with a reproducible UUID.
            total_gifts = 4
            searchable_ids = get_gift_searchable_ids()
            gift_models = []
            for i in range(0, total_gifts):  # pylint: disable=W0612
                gift_json = get_gift_dict()
                del gift_json['id']
                gift_json['searchable_id'] = searchable_ids[i]
                gift_model = GiftSchema().load(gift_json).data
                gift_models.append(gift_model)
            database.session.bulk_save_objects(gift_models)
            database.session.commit()

            # Create 3 transactions attached to the same gift ID = 1 and one transaction to each remaining gift.
            total_transactions = 5
            transaction_models = []
            for i in range(0, total_transactions):  # pylint: disable=W0612
                transaction_json = get_transaction_dict()
                del transaction_json['id']
                if i <= 2:
                    transaction_json['gift_id'] = 1
                    transaction_json['gift_searchable_id'] = uuid.UUID(
                        searchable_ids[0]).hex
                elif i == 3:
                    transaction_json['gift_id'] = i
                    transaction_json['gift_searchable_id'] = uuid.UUID(
                        searchable_ids[i]).hex
                    transaction_json['notes'] = ''
                else:
                    transaction_json['gift_id'] = i
                    transaction_json['gift_searchable_id'] = uuid.UUID(
                        searchable_ids[i]).hex

                transaction_model = TransactionSchema().load(
                    transaction_json).data
                transaction_models.append(transaction_model)

            database.session.bulk_save_objects(transaction_models)
            database.session.commit()

            # searchable_ids[ 0 ] is gift ID = 1 and will have 3 transactions.
            response = self.test_client.get(url.format(
                uuid.UUID(searchable_ids[1]).hex),
                                            headers=self.headers)
            self.assertEqual(len(json.loads(response.data.decode('utf-8'))), 0)

            # searchable_ids[ 1 ] is gift ID = 2 and will have 0 transactions.
            response = self.test_client.get(url.format(
                uuid.UUID(searchable_ids[1]).hex),
                                            headers=self.headers)
            self.assertEqual(len(json.loads(response.data.decode('utf-8'))), 0)

            # searchable_ids[ 2 ] is gift ID = 3 and will have 1 transaction with note = ''.
            response = self.test_client.get(url.format(
                uuid.UUID(searchable_ids[2]).hex),
                                            headers=self.headers)
            self.assertEqual(len(json.loads(response.data.decode('utf-8'))), 0)

            # searchable_ids[ 3 ] is gift ID = 4 and will have 1 transaction with a note != ''.
            response = self.test_client.get(url.format(
                uuid.UUID(searchable_ids[3]).hex),
                                            headers=self.headers)
            self.assertEqual(len(json.loads(response.data.decode('utf-8'))), 1)
    def test_braintree_webhooks(self, mock_init_gateway_function,
                                mock_subscription_function,
                                get_ultsys_user_function):  # pylint: disable=unused-argument
        """Make sure the webhook endpoint receives a payload and makes updates as expected."""

        with self.app.app_context():
            url = '/donation/webhook/braintree/subscription'

            # Create the sourced by agent for the subscription webhook.
            agent_model = from_json(AgentSchema(),
                                    get_agent_jsons()[0],
                                    create=True)
            database.session.add(agent_model.data)
            database.session.commit()

            # Here is the first gift as check.
            gift_dict = get_gift_dict({
                'user_id':
                1,
                'method_used':
                METHOD_USED,
                'sourced_from_agent_id':
                1,
                'recurring_subscription_id':
                'recurring_subscription_id'
            })
            gift_model = from_json(GiftSchema(), gift_dict, create=True)
            database.session.add(gift_model.data)
            database.session.flush()

            # Create a transaction on the gift.
            transaction_dict = get_transaction_dict({
                'gift_id':
                gift_model.data.id,
                'enacted_by_agent_id':
                agent_model.data.id,
                'type':
                'Gift',
                'gross_gift_amount':
                Decimal('1.00')
            })
            transaction_model = from_json(TransactionSchema(),
                                          transaction_dict,
                                          create=True)
            database.session.add(transaction_model.data)

            database.session.commit()

            # Here is the fake POST from Braintree when the subscription webhook is triggered.
            response = self.test_client.post(
                url,
                data={
                    'bt_signature': 'bt_signature',
                    'bt_payload': 'subscription_charged_successfully'
                })

            self.assertEqual(response.status_code, status.HTTP_200_OK)

            method_used_id = MethodUsedModel.get_method_used(
                'name', METHOD_USED).id
            gift = GiftModel.query.filter_by(id=1).one_or_none()
            self.assertEqual(gift.method_used_id, method_used_id)
            self.assertEqual(gift.sourced_from_agent_id, SOURCED_FROM_AGENT)
            self.assertEqual(gift.recurring_subscription_id,
                             RECURRING_SUBSCRIPTION_ID)

            transaction = TransactionModel.query.filter_by(id=1).one_or_none()
            self.assertEqual(transaction.gift_id, 1)
            self.assertEqual(transaction.type, 'Gift')
            self.assertEqual(transaction.status, 'Completed')

            response = self.test_client.post(
                url,
                data={
                    'bt_signature': 'bt_signature',
                    'bt_payload': 'subscription_charged_unsuccessfully'
                })

            self.assertEqual(response.status_code, status.HTTP_200_OK)
            transaction = TransactionModel.query.filter_by(id=3).one_or_none()
            self.assertEqual(transaction.status, 'Declined')

            response = self.test_client.post(url,
                                             data={
                                                 'bt_signature':
                                                 'bt_signature',
                                                 'bt_payload':
                                                 'subscription_went_past_due'
                                             })

            self.assertEqual(response.status_code, status.HTTP_200_OK)

            transaction = TransactionModel.query.filter_by(id=4).one_or_none()
            self.assertEqual(transaction.status, 'Failed')

            response = self.test_client.post(url,
                                             data={
                                                 'bt_signature':
                                                 'bt_signature',
                                                 'bt_payload':
                                                 'subscription_expired'
                                             })

            self.assertEqual(response.status_code, status.HTTP_200_OK)

            transaction = TransactionModel.query.filter_by(id=5).one_or_none()
            self.assertEqual(transaction.status, 'Failed')
def manage_recurring_sales( sale_id, sale, history_attributes, priority_sale_data ):
    """Logic for one item in the loop over sales for new statuses when they are recurring.

    :param sale_id: The key of the loop, the Braintree sale ID.
    :param sale: The value for the loop, a Braintree sale.
    :param history_attributes: The history attributes for the sale.
    :return:
    """

    try:
        # Try to get the user ID from previous gifts.
        gifts_with_subscription_id = GiftModel.query.filter_by( recurring_subscription_id=sale.subscription_id ).all()
        user_id = None
        for gift in gifts_with_subscription_id:
            if gift.user_id and gift.user_id != 999999999:
                user_id = gift.user_id
        if not user_id:
            user_id = 999999999

        if user_id == 999999999:
            priority_sale_data.append(
                get_row_of_data(
                    sale,
                    BRAINTREE_SALE_FIELDS,
                    'Recurring transaction without an initial transaction in database.'
                )
            )
        else:
            try:
                # This is a subscription and needs its own gift if not already present.
                transaction_initial = TransactionModel.query.filter_by( reference_number=sale_id ) \
                    .filter_by( type='Gift' ) \
                    .filter_by( status='Completed' ).one_or_none()

                if not transaction_initial:
                    gift_dict = {
                        'id': None,
                        'searchable_id': uuid.uuid4(),
                        'user_id': user_id,
                        'customer_id': sale.customer[ 'id' ],
                        'method_used': 'Admin-Entered Credit Card',
                        'sourced_from_agent_id': AGENT_ID,
                        'given_to': MERCHANT_ACCOUNT_ID[ sale.merchant_account_id ],
                        'recurring_subscription_id': sale.subscription_id
                    }
                    gift_model = from_json( GiftSchema(), gift_dict )
                    database.session.add( gift_model.data )
                    database.session.flush()
                    database.session.commit()
                    gift_id = gift_model.data.id
                else:
                    gift_id = transaction_initial.gift_id

                transaction_models = build_transactions(
                    sale, history_attributes, gift_id, sale.refunded_transaction_id
                )
                database.session.bulk_save_objects( transaction_models )
            except:  # noqa: E722
                database.session.rollback()
                logging.debug(
                    UpdaterCriticalPathError( where='manage_recurring_sales rolling back', type_id=sale_id ).message
                )
    except:  # noqa: E722
        logging.debug(
            UpdaterCriticalPathError( where='manage_recurring_sales', type_id=sale_id ).message
        )
Example #28
0
def valid_paypal_transaction(row, enacted_by_agent_id, agent_emails, ids,
                             bulk_objects):
    """Build the valid PayPal gifts/transactions.

    :param row: A row of CSV data.
    :param enacted_by_agent_id: The admin user making the download of PayPal data..
    :param agent_emails: The agent emails needed here.
    :param ids: The collected transaction and unresolved transaction IDs.
    :param bulk_objects: The lists for bulk saving.
    :return:
    """

    # This is a gift.
    try:
        # The returned Ultsys user object is something like: { 'ID': -999 }.
        user = get_ultsys_user({
            'email': {
                'eq': row['from_email_address']
            }
        }).json()[0]
    except (AttributeError, IndexError, KeyError):
        user = None

    gift_payload_user_id = user['ID'] if user else -1

    given_to = determine_given_to(row)

    gift_payload = {
        'user_id': gift_payload_user_id,
        'method_used': 'Admin-Entered Credit Card',
        'sourced_from_agent_id': agent_emails.get(row['to_email_address']),
        'given_to': given_to
    }

    # Subscription Number is optional.
    subscription_number = row.get('subscription_number')
    if subscription_number and subscription_number != 'NA':
        gift_payload['recurring_subscription_id'] = subscription_number

    gift_schema = from_json(GiftSchema(), gift_payload)
    gift_model = gift_schema.data

    # Need Gift ID to associate with transaction. Need to add and flush here --> slow.
    # Anyone know how to do it better?
    database.session.add(gift_model)
    database.session.flush()

    transaction_model = generate_a_transaction(row, ids['transaction'], {
        'agent_id': enacted_by_agent_id,
        'type': 'Gift',
        'gift_id': gift_model.id
    })

    if user and given_to == 'TBD':
        transaction_model.notes = 'Can not determine whether the gift belongs to ACTION or NERF with user_id: {}'\
            .format( user[ 'ID' ] )

    bulk_objects['transaction'].append(transaction_model)

    # Caging if do not know user or given_to
    if gift_payload_user_id == -1 or given_to == 'TBD':
        caged_donor_model = generate_caged_donor(row)
        caged_donor_model.gift_id = gift_model.id
        caged_donor_model.gift_searchable_id = gift_model.searchable_id
        bulk_objects['caged_donor'].append(caged_donor_model)

        ids['transaction'][row['transaction_id']] = gift_model.id
    def test_get_gifts_without_id(self):
        """Gifts-transaction endpoint with gift ID's retrieves all transactions on gifts ( methods = [ GET ] )."""

        with self.app.app_context():
            url = '/donation/gifts/transactions'

            # Create some gifts to retrieve.
            total_gifts = 5
            gift_models = create_model_list(GiftSchema(), get_gift_dict(),
                                            total_gifts)

            # Create 2 sets of transactions, each attached to a separate gift.
            total_transactions = 5
            transaction_gift_ids = [2, 4]

            transaction_models_1 = create_model_list(
                TransactionSchema(),
                get_transaction_dict({'gift_id': transaction_gift_ids[0]}),
                total_transactions)

            transaction_models_2 = create_model_list(
                TransactionSchema(),
                get_transaction_dict({'gift_id': transaction_gift_ids[1]}),
                total_transactions)

            database.session.bulk_save_objects(gift_models)
            database.session.bulk_save_objects(transaction_models_1)
            database.session.bulk_save_objects(transaction_models_2)
            database.session.commit()

            gift_2 = GiftModel.query.filter_by(id=2).one_or_none()
            searchable_id_2 = gift_2.searchable_id
            gift_4 = GiftModel.query.filter_by(id=4).one_or_none()
            searchable_id_4 = gift_4.searchable_id

            # Ensure a GET returns all transactions.
            response = self.test_client.get(url, headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 2 * total_transactions)

            # Ensure GET retrieves all transactions attached to the specified gift and the ID is correct.
            response = self.test_client.post(
                url,
                data=json.dumps({'searchable_ids': [str(searchable_id_2)]}),
                content_type='application/json',
                headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))

            self.assertEqual(len(data_returned), 5)
            self.assertEqual(data_returned[0]['gift_searchable_id'],
                             str(searchable_id_2))

            # Ensure GET retrieves all transactions attached to the 2 gifts.
            response = self.test_client.post(
                url,
                data=json.dumps({
                    'searchable_ids':
                    [str(searchable_id_2),
                     str(searchable_id_4)]
                }),
                content_type='application/json',
                headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 10)
    def test_get_gifts_by_date_past(self):
        """Gifts endpoint which retrieves all gifts newer than date, or between 2 dates ( methods = [ POST ] )."""

        with self.app.app_context():
            url = '/donation/gifts/date'

            # To create each gift with a new UUID call get_gift_dict() separately.
            totals = {'gifts': 2, 'transactions': 4}
            gift_models = []
            for i in range(0, totals['gifts']):  # pylint: disable=W0612
                gift_json = get_gift_dict()
                del gift_json['id']
                gift_json['searchable_id'] = uuid.uuid4()
                gift_model = GiftSchema().load(gift_json).data
                gift_models.append(gift_model)
            database.session.bulk_save_objects(gift_models)
            database.session.commit()

            # Create a set of transactions and attach to a specific gift.
            # Here are the time deltas: { gift 1: [ 0, -2, -4, -6 ], gift 2: [ -8, -10, -12, -14 ] }
            transaction_models = create_gift_transactions_date(
                TransactionSchema(), get_transaction_dict(),
                totals['transactions'], totals['gifts'])

            database.session.bulk_save_objects(transaction_models)
            database.session.commit()

            date_in_utc_now = datetime.utcnow().replace(hour=0,
                                                        minute=0,
                                                        second=0,
                                                        microsecond=0)

            # Date in the past on only gift 1.
            date_in_utc = date_in_utc_now - timedelta(days=2)
            response = self.test_client.post(
                url,
                data=json.dumps({'date': date_in_utc.strftime('%Y-%m-%d')}),
                content_type='application/json',
                headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))

            self.assertEqual(len(data_returned), 1)
            self.assertEqual(data_returned[0]['searchable_id'],
                             str(gift_models[0].searchable_id))

            # Date in the past which includes transactions on both gift 1 and gift 2.
            date_in_utc = date_in_utc_now - timedelta(days=10)
            response = self.test_client.post(
                url,
                data=json.dumps({'date': date_in_utc.strftime('%Y-%m-%d')}),
                content_type='application/json',
                headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))

            self.assertEqual(len(data_returned), 2)
            self.assertEqual(data_returned[0]['searchable_id'],
                             str(gift_models[0].searchable_id))
            self.assertEqual(data_returned[1]['searchable_id'],
                             str(gift_models[1].searchable_id))

            # Date range in the past, which includes transactions on both gift 1 and 2.
            date_in_utc_0 = date_in_utc_now - timedelta(days=6)
            date_in_utc_1 = date_in_utc_now - timedelta(days=8)
            response = self.test_client.post(
                url,
                data=json.dumps({
                    'date': [
                        date_in_utc_0.strftime('%Y-%m-%d'),
                        date_in_utc_1.strftime('%Y-%m-%d')
                    ]
                }),
                content_type='application/json',
                headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))

            self.assertEqual(len(data_returned), 2)
            self.assertEqual(data_returned[0]['searchable_id'],
                             str(gift_models[0].searchable_id))
            self.assertEqual(data_returned[1]['searchable_id'],
                             str(gift_models[1].searchable_id))

            # Date in the distant past, should bring back no results.
            date_in_utc = date_in_utc_now - timedelta(days=16)
            response = self.test_client.post(
                url,
                data=json.dumps({'date': date_in_utc.strftime('%Y-%m-%d')}),
                content_type='application/json',
                headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 2)

            # Date in the future, should bring back no results.
            date_in_utc = date_in_utc_now + timedelta(days=16)
            response = self.test_client.post(
                url,
                data=json.dumps({'date': date_in_utc.strftime('%Y-%m-%d')}),
                content_type='application/json',
                headers=self.headers)
            data_returned = json.loads(response.data.decode('utf-8'))
            self.assertEqual(len(data_returned), 0)