Esempio n. 1
0
class PostajobTestBase(MyJobsBase):
    def setUp(self):
        super(PostajobTestBase, self).setUp()
        self.user = UserFactory(password='******')
        self.company = CompanyFactory(product_access=True, posting_access=True)

        self.site = SeoSiteFactory(canonical_company=self.company)
        self.bu = BusinessUnitFactory()
        self.site.business_units.add(self.bu)
        self.site.save()
        self.company.job_source_ids.add(self.bu)
        self.company.save()
        self.company_user = CompanyUserFactory(user=self.user,
                                               company=self.company)
        SitePackageFactory(owner=self.company)
        self.package = Package.objects.get()
        self.sitepackage = SitePackage.objects.get()
        self.sitepackage.sites.add(self.site)
        self.product = ProductFactory(package=self.package, owner=self.company)

        self.login_user()

    def login_user(self, user=None):
        if not user:
            user = self.user
        self.client.post(reverse('home'),
                         data={
                             'username': user.email,
                             'password': '******',
                             'action': 'login',
                             })
Esempio n. 2
0
    def setUp(self):
        super(MyDashboardViewsTests, self).setUp()
        group = Group.objects.get(name=CompanyUser.GROUP_NAME)
        self.user.groups.add(group)

        self.business_unit = BusinessUnitFactory()

        self.company.job_source_ids.add(self.business_unit)
        self.admin = CompanyUserFactory(user=self.user,
                                        company=self.company)
        self.microsite = SeoSiteFactory()
        self.microsite.business_units.add(self.business_unit)

        self.candidate_user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=self.candidate_user,
                           feed='http://test.jobs/jobs/feed/rss?',
                           url='http://test.jobs/search?q=django',
                           label='test Jobs')

        for i in range(5):
            # Create 5 new users
            user = UserFactory(email='*****@*****.**' % i)
            for search in SEARCH_OPTS:
                # Create 15 new searches and assign three per user
                SavedSearchFactory(user=user,
                                   url='http://test.jobs/search?q=%s' % search,
                                   feed='http://test.jobs/jobs/feed/rss?',
                                   label='%s Jobs' % search)
        update_solr_task(settings.TEST_SOLR_INSTANCE)
Esempio n. 3
0
    def test_site_package_make_unique_for_company(self):
        package = SitePackage.objects.create(**self.site_package_data)
        package.make_unique_for_company(self.company)
        self.assertEqual(self.company.site_package, package)
        package.delete()

        package = SitePackage.objects.create(**self.site_package_data)
        for x in range(1000, 1003):
            site = SeoSiteFactory(id=x, domain="%s.jobs" % x)
            package.sites.add(site)
        self.assertItemsEqual(package.sites.all().values_list('id', flat=True),
                              [1000, 1001, 1002])
        for x in range(100, 103):
            site = SeoSiteFactory(id=x, domain="%s.jobs" % x)
            site.business_units.add(self.bu)
            site.save()
        # Site packages with existing sites associated with it should
        # only end up with the sites for a company.
        package.make_unique_for_company(self.company)
        self.assertEqual(self.company.site_package, package)
        self.assertItemsEqual(package.sites.all().values_list('id', flat=True),
                              [100, 101, 102, 2])
Esempio n. 4
0
    def setUp(self):
        super(PostajobTestBase, self).setUp()
        self.user = UserFactory(password='******')
        self.company = CompanyFactory(product_access=True, posting_access=True)

        self.site = SeoSiteFactory(canonical_company=self.company)
        self.bu = BusinessUnitFactory()
        self.site.business_units.add(self.bu)
        self.site.save()
        self.company.job_source_ids.add(self.bu)
        self.company.save()
        self.company_user = CompanyUserFactory(user=self.user,
                                               company=self.company)
        SitePackageFactory(owner=self.company)
        self.package = Package.objects.get()
        self.sitepackage = SitePackage.objects.get()
        self.sitepackage.sites.add(self.site)
        self.product = ProductFactory(package=self.package, owner=self.company)

        self.login_user()
Esempio n. 5
0
    def setUp(self):
        super(ModelTests, self).setUp()
        self.user = User.objects.create(email='*****@*****.**')
        self.company = CompanyFactory()
        CompanyProfile.objects.create(company=self.company)
        self.site = SeoSiteFactory()
        self.bu = BusinessUnitFactory()
        self.site.business_units.add(self.bu)
        self.site.save()
        self.company.job_source_ids.add(self.bu)
        self.company.save()

        # Use the newly created site for testing instead of secure.my.jobs.
        settings.SITE = self.site

        self.request_data = {
            'title': 'title',
            'company': self.company.id,
            'reqid': '1',
            'description': 'sadfljasdfljasdflasdfj',
            'link': 'www.google.com',
            'on_sites': '0',
            'apply_info': '',
        }

        self.request_location = {
            'city': 'Indianapolis',
            'state': 'Indiana',
            'state_short': 'IN',
            'country': 'United States',
            'country_short': 'USA',
            'zipcode': '46268',
        }

        self.site_package_data = {
            'name': 'Test Site Package',
        }
Esempio n. 6
0
class MyDashboardViewsTests(MyJobsBase):
    def setUp(self):
        super(MyDashboardViewsTests, self).setUp()
        group = Group.objects.get(name=CompanyUser.GROUP_NAME)
        self.user.groups.add(group)

        self.business_unit = BusinessUnitFactory()

        self.company.job_source_ids.add(self.business_unit)
        self.admin = CompanyUserFactory(user=self.user,
                                        company=self.company)
        self.microsite = SeoSiteFactory()
        self.microsite.business_units.add(self.business_unit)

        self.candidate_user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=self.candidate_user,
                           feed='http://test.jobs/jobs/feed/rss?',
                           url='http://test.jobs/search?q=django',
                           label='test Jobs')

        for i in range(5):
            # Create 5 new users
            user = UserFactory(email='*****@*****.**' % i)
            for search in SEARCH_OPTS:
                # Create 15 new searches and assign three per user
                SavedSearchFactory(user=user,
                                   url='http://test.jobs/search?q=%s' % search,
                                   feed='http://test.jobs/jobs/feed/rss?',
                                   label='%s Jobs' % search)
        update_solr_task(settings.TEST_SOLR_INSTANCE)

    def tearDown(self):
        super(MyDashboardViewsTests, self).tearDown()
        for location in settings.TEST_SOLR_INSTANCE.values():
            solr = pysolr.Solr(location)
            solr.delete(q='*:*')

    def add_analytics_data(self, type_, num_to_add=2):
        """
        Adds testing analytics data to Solr.

        Adds two entries per page category, one for unauthenticated and one for
        authenticated hits.
        """
        dicts = []
        base_dict = {
            'domain': self.microsite.domain,
            'view_date': datetime.now(),
            'company_id': self.company.pk,
        }
        home_dict = {
            'page_category': 'home'
        }
        view_dict = {
            'job_view_guid': '1'*32,
            'job_view_buid': self.business_unit.pk,
            'page_category': 'listing'
        }
        search_dict = {
            'page_category': 'results'
        }
        apply_dict = {
            'job_view_guid': '2'*32,
            'job_view_buid': self.business_unit.pk,
            'page_category': 'redirect'
        }

        if type_ == 'home':
            analytics_dict = home_dict
        elif type_ == 'listing':
            analytics_dict = view_dict
        elif type_ == 'results':
            analytics_dict = search_dict
        else:
            analytics_dict = apply_dict

        analytics_dict.update(base_dict)
        for _ in range(num_to_add):
            dicts.append(analytics_dict.copy())

        for analytics_dict in dicts:
            analytics_dict['aguid'] = uuid.uuid4().hex
            analytics_dict['uid'] = 'analytics##%s#%s' % (
                analytics_dict['view_date'],
                analytics_dict['aguid']
            )

        for location in settings.TEST_SOLR_INSTANCE.values():
            solr = pysolr.Solr(location)
            solr.add(dicts)

    @unittest.skip("Correct behavior undefined with respect to duplicates.")
    def test_number_of_searches_and_users_is_correct(self):
        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id))
        # 6 users total
        self.assertEqual(response.context['total_candidates'], 6)

        old_search = SavedSearch.objects.all()[0]
        old_search.created_on -= timedelta(days=31)
        old_search.save()

        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id),
            {'microsite': 'test.jobs'})

        self.assertEqual(response.context['total_candidates'], 6)

    def test_facets(self):
        education = EducationFactory(user=self.candidate_user)
        adr = AddressFactory(user=self.candidate_user)
        license = LicenseFactory(user=self.candidate_user)
        self.candidate_user.save()
        update_solr_task(settings.TEST_SOLR_INSTANCE)

        base_url = 'http://testserver/candidates/view?company={company}'
        country_str = base_url + '&location={country}'
        education_str = base_url + '&education={education}'
        license_str = base_url + '&license={license_name}'

        country_str = country_str.format(
            company=self.company.pk, country=adr.country_code)
        education_str = education_str.format(
            company=self.company.pk, education=education.education_level_code)
        license_str = license_str.format(
            company=self.company.pk, license_name=license.license_name)

        q = '?company={company}'
        q = q.format(company=str(self.company.id))
        response = self.client.post(reverse('dashboard')+q)
        soup = BeautifulSoup(response.content)

        types = ['Country', 'Education', 'License']
        hrefs = []
        for facet_type in types:
            container = soup.select('#%s-details-table' % facet_type)[0]
            href = container.select('a')[0].attrs['href']
            hrefs.append(href)

        self.assertIn(country_str, hrefs)
        self.assertIn(education_str, hrefs)
        self.assertIn(license_str, hrefs)

    def test_filters(self):
        adr = AddressFactory(user=self.candidate_user)
        self.candidate_user.save()
        update_solr_task(settings.TEST_SOLR_INSTANCE)

        country_str = 'http://testserver/candidates/view?company={company}&location={country}'
        country_filter_str = '<a class="applied-filter" href="http://testserver/candidates/view?company={company}"><span>&#10006;</span> {country_long}</a><br>'
        region_str = 'http://testserver/candidates/view?company={company}&amp;location={country}-{region}'
        region_filter_str = '<a class="applied-filter" href="http://testserver/candidates/view?company={company}&amp;location={country}"><span>&#10006;</span> {region}, {country}</a>'
        city_str = 'http://testserver/candidates/view?company={company}&amp;location={country}-{region}-{city}'
        city_filter_str = '<a class="applied-filter" href="http://testserver/candidates/view?company={company}&amp;location={country}-{region}"><span>&#10006;</span> {city}, {region}, {country}</a>'

        country_str = country_str.format(company=self.company.pk, country=adr.country_code)
        country_filter_str = country_filter_str.format(company=self.company.pk, country=adr.country_code,
                                                       country_long=country_codes[adr.country_code])
        region_str = region_str.format(company=self.company.pk, country=adr.country_code,
                                       region=adr.country_sub_division_code)
        region_filter_str = region_filter_str.format(company=self.company.pk, region=adr.country_sub_division_code,
                                                     country=adr.country_code,
                                                     country_long=country_codes[adr.country_code])
        city_str = city_str.format(company=self.company.pk, country=adr.country_code,
                                   region=adr.country_sub_division_code,
                                   city=adr.city_name)
        city_filter_str = city_filter_str.format(company=self.company.pk, country=adr.country_code,
                                                 region=adr.country_sub_division_code,
                                                 city=adr.city_name,
                                                 country_long=country_codes[adr.country_code])

        q = '?company={company}'
        q = q.format(company=str(self.company.id))
        response = self.client.post(reverse('dashboard')+q)
        self.assertIn(country_str, response.content)

        q = '?company={company}&location={country}'
        q = q.format(company=str(self.company.id), country=adr.country_code)
        response = self.client.post(reverse('dashboard')+q)
        self.assertIn(country_filter_str, response.content)
        self.assertIn(region_str, response.content)

        q = '?company={company}&location={country}-{region}'
        q = q.format(company=str(self.company.id), country=adr.country_code,
                     region=adr.country_sub_division_code)
        response = self.client.post(reverse('dashboard')+q)
        self.assertIn(region_filter_str, response.content)
        self.assertIn(city_str, response.content)

        q = '?company={company}&location={country}-{region}-{city}'
        q = q.format(company=str(self.company.id), country=adr.country_code,
                     region=adr.country_sub_division_code,
                     city=adr.city_name)
        response = self.client.post(reverse('dashboard')+q)
        self.assertIn(city_filter_str, response.content)

    @unittest.skip("Correct behavior undefined with respect to duplicates.")
    def test_search_field(self):
        # Build url
        def build_url(search):
            q = '?company={company}&search={search}'
            q = q.format(company=str(self.company.id), search=search)
            return reverse('dashboard') + q

        # assert it finds all 5 searches.
        response = self.client.post(build_url('python'))
        soup = BeautifulSoup(response.content)
        count_box = soup.select('.count-box-left')
        count = int(count_box[0].text)
        self.assertEqual(count, 5)

        # 6 users total
        response = self.client.post(build_url('example'))
        soup = BeautifulSoup(response.content)
        count_box = soup.select('.count-box-left')
        count = int(count_box[0].text)
        self.assertIn(count, [6, 7])

    def test_search_email(self):
        """We should be able to search for an exact email."""
        user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=user,
                           url='http://test.jobs/search?q=python',
                           feed='http://test.jobs/jobs/feed/rss?',
                           label='Python Jobs')
        user.save()
        update_solr_task(settings.TEST_SOLR_INSTANCE)

        q = '?company={company}&search={search}'
        q = q.format(company=str(self.company.id), search='*****@*****.**')
        url = reverse('dashboard') + q

        response = self.client.post(url)
        soup = BeautifulSoup(response.content)
        self.assertEqual(len(soup.select('#row-link-table tr')), 1)

    def test_search_domain(self):
        """We should be able to search for domain."""
        user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=user,
                           url='http://test.jobs/search?q=python',
                           feed='http://test.jobs/jobs/feed/rss?',
                           label='Python Jobs')
        user.save()
        update_solr_task(settings.TEST_SOLR_INSTANCE)

        q = '?company={company}&search={search}'
        q = q.format(company=str(self.company.id), search='shouldWork.com')
        url = reverse('dashboard') + q

        response = self.client.post(url)
        soup = BeautifulSoup(response.content)
        self.assertEqual(len(soup.select('#row-link-table tr')), 1)

    def test_search_updates_facet_counts(self):
        # Add ProfileData to the candidate_user
        EducationFactory(user=self.candidate_user)
        AddressFactory(user=self.candidate_user)
        LicenseFactory(user=self.candidate_user)
        self.candidate_user.save()

        # Create a new user with ProfileData
        user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=user,
                           url='http://test.jobs/search?q=python',
                           feed='http://test.jobs/jobs/feed/rss?',
                           label='Python Jobs')
        EducationFactory(user=user)
        AddressFactory(user=user)
        LicenseFactory(user=user)
        user.save()

        update_solr_task(settings.TEST_SOLR_INSTANCE)

        # Assert there are two users with country codes
        country_tag = '#Country-details-table .facet-count'
        q = '?company={company}'
        q = q.format(company=str(self.company.id))
        response = self.client.post(reverse('dashboard') + q)
        soup = BeautifulSoup(response.content)
        self.assertEqual(int(soup.select(country_tag)[0].text), 2)

        # When we search, the facet count updates.
        q = '?company={company}&search={search}'
        q = q.format(company=str(self.company.id), search='find')
        response = self.client.post(reverse('dashboard') + q)
        soup = BeautifulSoup(response.content)
        self.assertEqual(int(soup.select(country_tag)[0].text), 1)

    # Tests to see if redirect from /candidates/ goes to candidates/view/
    def test_redirect_to_candidates_views_default_page(self):
        response = self.client.post('/candidates/')

        # response returns HttpResponsePermanentRedirect which returns a 301
        # status code instead of the normal 302 redirect status code
        self.assertRedirects(response, '/candidates/view/', status_code=301,
                             target_status_code=200)

        response = self.client.post(reverse('dashboard'))

        self.assertEqual(response.status_code, 200)

        soup = BeautifulSoup(response.content)
        company_name = soup.find('h1')
        company_name = company_name.next

        self.assertEqual(company_name, self.company.name)

    # Eventually these opted-in/out will be changed to
    # track if user is part of company's activity feed
    def test_candidate_has_opted_in(self):
        response = self.client.post(
            reverse('candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'}).findAll(
            'a', {'class': 'accordion-toggle'})
        info = soup.find('div', {'id': 'candidate-content'}).findAll('li')

        self.assertEqual(len(titles), 6)
        self.assertEqual(len(info), 16)
        self.assertEqual(response.status_code, 200)

    def test_candidate_page_load_without_profileunits_with_activites(self):
        response = self.client.post(
            reverse('candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'}).findAll(
            'a', {'class': 'accordion-toggle'})
        info = soup.find('div', {'id': 'candidate-content'}).findAll('li')

        self.assertEqual(len(titles), 1)
        self.assertEqual(len(info), 3)
        self.assertEqual(response.status_code, 200)

    def test_candidate_page_load_without_profileunits_and_activites(self):
        saved_search = SavedSearch.objects.get(user=self.candidate_user)
        saved_search.delete()
        response = self.client.post(
            reverse('candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'})

        self.assertFalse(info)
        self.assertEqual(response.status_code, 404)

    def test_export_csv(self):
        response = self.client.post(
            reverse('export_candidates')+'?company=' +
            str(self.company.id)+'&ex-t=csv')
        self.assertTrue(response.content)
        self.assertEqual(response.status_code, 200)

    def test_export_xml(self):
        response = self.client.post(
            reverse('export_candidates')+'?company=' +
            str(self.company.id)+'&ex-t=xml')
        self.assertTrue(response.content.index('candidates'))
        self.assertEqual(response.status_code, 200)

    def test_export_json(self):
        response = self.client.post(
            reverse('export_candidates')+'?company=' +
            str(self.company.id)+'&ex-t=json')
        self.assertTrue(response.content.index('candidates'))
        self.assertEqual(response.status_code, 200)

    def test_dashboard_analytics_no_data(self):
        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id),
            {'microsite': 'test.jobs'})

        soup = BeautifulSoup(response.content)

        for selector in ['#total-clicks',
                         '#total-home',
                         '#total-job-views',
                         '#total-search']:

            container = soup.select(selector)
            # Empty list means no elements were found.
            self.assertEqual(container, [])

    def test_dashboard_analytics_with_data(self):
        for type_ in ['home', 'listing', 'results']:
            self.add_analytics_data(type_)
        num_clicks = 1234
        self.add_analytics_data('redirect', num_to_add=num_clicks)

        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id))

        soup = BeautifulSoup(response.content)

        for selector in ['#total-clicks',
                         '#total-home',
                         '#total-job-views',
                         '#total-search']:

            # This should be the parent container for all analytics data
            # of this type
            container = soup.select(selector)[0]

            # All hits, humanized
            all_hits = container.select('span')[0]
            if selector == '#total-clicks':
                expected = '1.2k'
            else:
                expected = '2'
            self.assertEqual(all_hits.text.strip(), expected)

            # All hits, raw number
            if selector == '#total-clicks':
                full = container.attrs['data-original-title']
                self.assertEqual(full.strip(),
                                 '1,234')
            else:
                with self.assertRaises(KeyError):
                    # This is marked as having no effect, which is intended
                    container.attrs['data-original-title']

    def test_dashboard_with_no_microsites(self):
        """
        Trying to access the dashboard of a company that has no microsites
        associated with it should not create malformed solr queries.
        """
        self.microsite.delete()
        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id))
        self.assertEqual(response.status_code, 200)
Esempio n. 7
0
class ModelTests(MyJobsBase):
    def setUp(self):
        super(ModelTests, self).setUp()
        self.user = User.objects.create(email='*****@*****.**')
        self.company = CompanyFactory()
        CompanyProfile.objects.create(company=self.company)
        self.site = SeoSiteFactory()
        self.bu = BusinessUnitFactory()
        self.site.business_units.add(self.bu)
        self.site.save()
        self.company.job_source_ids.add(self.bu)
        self.company.save()

        # Use the newly created site for testing instead of secure.my.jobs.
        settings.SITE = self.site

        self.request_data = {
            'title': 'title',
            'company': self.company.id,
            'reqid': '1',
            'description': 'sadfljasdfljasdflasdfj',
            'link': 'www.google.com',
            'on_sites': '0',
            'apply_info': '',
        }

        self.request_location = {
            'city': 'Indianapolis',
            'state': 'Indiana',
            'state_short': 'IN',
            'country': 'United States',
            'country_short': 'USA',
            'zipcode': '46268',
        }

        self.site_package_data = {
            'name': 'Test Site Package',
        }

    def test_job_creation_and_deletion(self):
        locations = JobLocationFactory.create_batch(5)
        job = JobFactory(owner=self.company, created_by=self.user)
        job.locations = locations
        job.save()
        self.assertEqual(Job.objects.all().count(), 1)
        self.assertEqual(JobLocation.objects.all().count(), 5)
        job.delete()
        self.assertEqual(Job.objects.all().count(), 0)
        self.assertEqual(JobLocation.objects.all().count(), 0)

    def test_job_add_to_solr(self):
        job = JobFactory(owner=self.company, created_by=self.user)
        job.locations.add(JobLocationFactory())
        job.add_to_solr()

        guids = " OR ".join(job.guids())
        query = "guid:%s" % guids
        self.assertEqual(self.ms_solr.search(query).hits, 1)

    def test_job_remove_from_solr(self):
        job = JobFactory(owner=self.company, created_by=self.user)
        locations = JobLocationFactory.create_batch(2)
        job.locations = locations
        job.save()
        job.remove_from_solr()

        guids = " OR ".join(job.guids())
        query = "guid:%s" % guids
        self.assertEqual(self.ms_solr.search(query).hits, 0)

    def test_job_generate_guid(self):
        guid = '1'*32

        # Confirm that pre-assigned guids are not being overwritten.
        location = JobLocationFactory(guid=guid)
        self.assertEqual(guid, location.guid)
        location.delete()

        # Confirm that if a guid isn't assigned one is getting assigned
        # to it properly.
        location = JobLocationFactory()
        self.assertIsNotNone(location.guid)
        self.assertNotEqual(location.guid, guid)

    def test_site_package_make_unique_for_site(self):
        package = SitePackage.objects.create(**self.site_package_data)
        package.make_unique_for_site(self.site)
        self.assertEqual(self.site.site_package, package)
        package.delete()

        package = SitePackage.objects.create(**self.site_package_data)
        for x in range(100, 110):
            site = SeoSiteFactory(id=x, domain="%s.jobs" % x)
            package.sites.add(site)

        # Site packages with existing sites associated with it should still
        # only end up with one associated site.
        site = SeoSiteFactory(id=4000, domain="4000.jobs")
        package.make_unique_for_site(site)
        self.assertEqual(site.site_package, package)

    def test_site_package_make_unique_for_company(self):
        package = SitePackage.objects.create(**self.site_package_data)
        package.make_unique_for_company(self.company)
        self.assertEqual(self.company.site_package, package)
        package.delete()

        package = SitePackage.objects.create(**self.site_package_data)
        for x in range(1000, 1003):
            site = SeoSiteFactory(id=x, domain="%s.jobs" % x)
            package.sites.add(site)
        self.assertItemsEqual(package.sites.all().values_list('id', flat=True),
                              [1000, 1001, 1002])
        for x in range(100, 103):
            site = SeoSiteFactory(id=x, domain="%s.jobs" % x)
            site.business_units.add(self.bu)
            site.save()
        # Site packages with existing sites associated with it should
        # only end up with the sites for a company.
        package.make_unique_for_company(self.company)
        self.assertEqual(self.company.site_package, package)
        self.assertItemsEqual(package.sites.all().values_list('id', flat=True),
                              [100, 101, 102, 2])

    def create_purchased_job(self, pk=None):
        if not hasattr(self, 'package'):
            self.package = SitePackageFactory(owner=self.company)
        if not hasattr(self, 'product'):
            self.product = ProductFactory(
                package=self.package, owner=self.company)
        if not hasattr(self, 'purchased_product'):
            self.purchased_product = PurchasedProductFactory(
                product=self.product, owner=self.company)
        exp_date = date.today() + timedelta(self.product.posting_window_length)
        self.assertEqual(self.purchased_product.expiration_date, exp_date)
        return PurchasedJobFactory(
            owner=self.company, created_by=self.user, 
            purchased_product=self.purchased_product, pk=pk)

    def test_purchased_job_add(self):
        self.create_purchased_job()
        self.assertEqual(PurchasedJob.objects.all().count(), 1)
        self.assertEqual(SitePackage.objects.all().count(), 1)
        self.assertEqual(Request.objects.all().count(), 1)
        package = SitePackage.objects.get()
        job = PurchasedJob.objects.get()
        self.assertItemsEqual(job.site_packages.all(), [package])

    def test_purchased_job_add_to_solr(self):
        job = self.create_purchased_job()
        job.locations.add(JobLocationFactory())
        job.save()
        # Add to solr and delete from solr shouldn't be called until
        # the job is approved.
        guids = " OR ".join(job.guids())
        query = "guid:%s" % guids
        self.assertEqual(self.ms_solr.search(query).hits, 0)
        job.is_approved = True

        # Jobs won't be added/deleted until it's confirmed that the
        # purchased product is paid for as well.
        job.purchased_product.paid = True
        job.purchased_product.save()
        job.save()
        # Now that the job is approved, it should've been sent to solr.
        guids = " OR ".join(job.guids())
        query = "guid:%s" % guids
        self.assertEqual(self.ms_solr.search(query).hits, 1)

    def test_purchased_product_jobs_remaining(self):
        num_jobs_allowed = Product._meta.get_field_by_name('num_jobs_allowed')
        expected_num_jobs = num_jobs_allowed[0].default
        for x in range(50, 50 + expected_num_jobs):
            if hasattr(self, 'purchased_product'):
                self.assertTrue(self.purchased_product.can_post_more())
            self.create_purchased_job()
            expected_num_jobs -= 1
            self.assertEqual(self.purchased_product.jobs_remaining,
                             expected_num_jobs)
        self.assertFalse(self.purchased_product.can_post_more())

    def test_invoice_send_invoice_email(self):
        self.create_purchased_job()
        group, _ = Group.objects.get_or_create(name=Product.ADMIN_GROUP_NAME)

        # No one to receive the email.
        self.purchased_product.invoice.send_invoice_email()
        self.assertEqual(len(mail.outbox), 0)

        # Only recipient is specified recipient.
        self.purchased_product.invoice.send_invoice_email(other_recipients=['*****@*****.**'])
        self.assertItemsEqual(mail.outbox[0].to,
                              ['*****@*****.**'])

        mail.outbox = []

        # Only recipients are admins.
        user = CompanyUserFactory(user=self.user, company=self.company)
        user.group.add(group)
        user.save()
        self.purchased_product.invoice.send_invoice_email()
        self.assertItemsEqual(mail.outbox[0].to,
                              [u'*****@*****.**'])
        self.assertItemsEqual(mail.outbox[0].from_email,
                              '*****@*****.**')

        mail.outbox = []

        self.site.email_domain = 'test.domain'
        self.site.save()

        # Recipients are admins + specified recipients.
        self.purchased_product.invoice.send_invoice_email(other_recipients=['*****@*****.**'])
        self.assertItemsEqual(mail.outbox[0].to,
                              ['*****@*****.**', u'*****@*****.**'])
        self.assertEqual(mail.outbox[0].from_email,
                              '*****@*****.**')

        mail.outbox = []

        # Only recipient is [email protected] (no admins)
        self.purchased_product.invoice.send_invoice_email(send_to_admins=False,
                                                          other_recipients=['*****@*****.**'])
        # Only one in .to should be [email protected]
        self.assertEquals(len(mail.outbox[0].to), 1)
        self.assertItemsEqual(mail.outbox[0].to, ['*****@*****.**'])

    def test_invoice_unchanged_after_purchased_product_deletion(self):
        self.create_purchased_job()
        invoice = self.purchased_product.invoice
        invoice.send_invoice_email(other_recipients=['*****@*****.**'])
        old_email = mail.outbox.pop()

        self.purchased_product.delete()
        invoice.send_invoice_email(other_recipients=['*****@*****.**'])
        new_email = mail.outbox.pop()

        self.assertEqual(old_email.body, new_email.body)

    def test_invoice_unchanged_after_product_changed(self):
        self.create_purchased_job()
        invoice = self.purchased_product.invoice
        invoice.send_invoice_email(other_recipients=['*****@*****.**'])
        old_email = mail.outbox.pop()

        self.purchased_product.product.name = 'new name'
        self.purchased_product.product.save()
        invoice.send_invoice_email(other_recipients=['*****@*****.**'])
        new_email = mail.outbox.pop()

        self.assertEqual(old_email.body, new_email.body)

    def test_productgrouping_add_delete(self):
        self.create_purchased_job()
        ProductGrouping.objects.create(display_title='Test Grouping',
                                       explanation='Test Grouping',
                                       name='Test Grouping',
                                       owner=self.company)
        self.assertEqual(ProductGrouping.objects.all().count(), 1)
        grouping = ProductGrouping.objects.get()

        order = ProductOrder.objects.create(product=self.product,
                                            group=grouping)
        grouping_products = grouping.products.all().values_list('pk', flat=True)
        self.assertItemsEqual(grouping_products, [order.product.pk])

        grouping.delete()
        self.assertEqual(ProductGrouping.objects.all().count(), 0)
        self.assertEqual(ProductOrder.objects.all().count(), 0)

    def test_request_generation(self):
        cu = CompanyUserFactory(user=self.user, company=self.company)
        cu.make_purchased_microsite_admin()

        self.create_purchased_job()
        self.assertEqual(PurchasedJob.objects.all().count(), 1)
        self.assertEqual(Request.objects.all().count(), 1)
        self.assertEqual(len(mail.outbox), 1)
        self.assertItemsEqual(mail.outbox[0].from_email,
                              '*****@*****.**')
        mail.outbox = []

        # Already approved jobs should not generate an additional request.
        PurchasedJobFactory(
            owner=self.company, created_by=self.user, 
            purchased_product=self.purchased_product, is_approved=True)

        self.assertEqual(PurchasedJob.objects.all().count(), 2)
        self.assertEqual(Request.objects.all().count(), 1)
        self.assertEqual(len(mail.outbox), 0)

    def test_offlinepurchase_create_purchased_products(self):
        user = CompanyUserFactory(user=self.user, company=self.company)
        offline_purchase = OfflinePurchaseFactory(
            owner=self.company, created_by=user)
        package = SitePackageFactory(owner=self.company)
        product = ProductFactory(package=package, owner=self.company)

        for x in range(1, 15):
            PurchasedProduct.objects.all().delete()
            OfflineProduct.objects.all().delete()
            OfflineProductFactory(
                product=product,
                offline_purchase=offline_purchase,
                product_quantity=x)
            offline_purchase.create_purchased_products(self.company)
            self.assertEqual(PurchasedProduct.objects.all().count(), x)

        product_two = ProductFactory(package=package, owner=self.company)
        for x in range(1, 15):
            PurchasedProduct.objects.all().delete()
            OfflineProduct.objects.all().delete()
            OfflineProductFactory(product=product, 
                                  offline_purchase=offline_purchase,
                                  product_quantity=x)
            OfflineProductFactory(product=product_two,
                                  offline_purchase=offline_purchase,
                                  product_quantity=x)
            offline_purchase.create_purchased_products(self.company)
            self.assertEqual(PurchasedProduct.objects.all().count(), x*2)

    def test_offlinepurchase_filter_by_sites(self):
        cu = CompanyUserFactory(user=self.user, company=self.company)
        for x in range(8800, 8815):
            domain = 'testsite-%s.jobs' % x
            site = SeoSiteFactory(id=x, domain=domain, name=domain)
            site_package = SitePackageFactory(owner=self.company)
            site_package.make_unique_for_site(site)
            product = ProductFactory(package=site_package, owner=self.company)
            for y in range(1, 5):
                purchase = OfflinePurchaseFactory(owner=self.company, created_by=cu)
                OfflineProduct.objects.create(product=product,
                                              offline_purchase=purchase)
            count = OfflinePurchase.objects.filter_by_sites([site]).count()
            self.assertEqual(count, 4)

        self.assertEqual(OfflinePurchase.objects.all().count(), 60)

    def test_invoice_filter_by_sites(self):
        cu = CompanyUserFactory(user=self.user, company=self.company)
        for x in range(8800, 8815):
            domain = 'testsite-%s.jobs' % x
            site = SeoSiteFactory(id=x, domain=domain, name=domain)
            site_package = SitePackageFactory(owner=self.company)
            site_package.make_unique_for_site(site)
            product = ProductFactory(package=site_package, owner=self.company)
            for y in range(1, 5):
                # OfflinePurchaseFactory() automatically creates the invoice.
                purchase = OfflinePurchaseFactory(owner=self.company, created_by=cu)
                OfflineProduct.objects.create(product=product,
                                              offline_purchase=purchase)
            # Confirm it correctly picks up Invoices associated with
            # OfflinePurchases.
            self.assertEqual(Invoice.objects.filter_by_sites([site]).count(), 4)
            for y in range(1, 5):
                # PurchasedProductFactory() also automatically creates
                # the invoice.
                PurchasedProductFactory(product=product, owner=self.company)
            # Confirm it correctly picks up Invoices associated with
            # PurchasedProducts.
            self.assertEqual(Invoice.objects.filter_by_sites([site]).count(), 8)

        self.assertEqual(Invoice.objects.all().count(), 120)

    def test_product_filter_by_sites(self):
        for x in range(8800, 8815):
            domain = 'testsite-%s.jobs' % x
            site = SeoSiteFactory(id=x, domain=domain, name=domain)
            site_package = SitePackageFactory(owner=self.company)
            site_package.make_unique_for_site(site)
            for y in range(1, 5):
                ProductFactory(package=site_package, owner=self.company)
            self.assertEqual(Product.objects.filter_by_sites([site]).count(), 4)

        self.assertEqual(Product.objects.all().count(), 60)

    def test_request_filter_by_sites(self):
        for x in range(8800, 8815):
            domain = 'testsite-%s.jobs' % x
            site = SeoSiteFactory(id=x, domain=domain, name=domain)
            site_package = SitePackageFactory(owner=self.company)
            site_package.make_unique_for_site(site)
            product = ProductFactory(package=site_package, owner=self.company)
            purchased_product = PurchasedProductFactory(product=product,
                                                        owner=self.company)
            for y in range(1, 5):
                # Unapproved purchased jobs should create Requests.
                PurchasedJobFactory(owner=self.company, created_by=self.user,
                                    purchased_product=purchased_product)
            self.assertEqual(Request.objects.filter_by_sites([site]).count(), 4)

        self.assertEqual(Request.objects.all().count(), 60)

    def test_purchasedproduct_filter_by_sites(self):
        for x in range(8800, 8815):
            domain = 'testsite-%s.jobs' % x
            site = SeoSiteFactory(id=x, domain=domain, name=domain)
            site_package = SitePackageFactory(owner=self.company)
            site_package.make_unique_for_site(site)
            for y in range(1, 5):
                product = ProductFactory(package=site_package, owner=self.company)
                PurchasedProductFactory(product=product, owner=self.company)
            count = PurchasedProduct.objects.filter_by_sites([site]).count()
            self.assertEqual(count, 4)

        self.assertEqual(PurchasedProduct.objects.all().count(), 60)

    def test_job_filter_by_sites(self):
        for x in range(8800, 8815):
            domain = 'testsite-%s.jobs' % x
            site = SeoSiteFactory(id=x, domain=domain, name=domain)
            site_package = SitePackageFactory(owner=self.company)
            site_package.make_unique_for_site(site)
            for y in range(1, 5):
                job = JobFactory(owner=self.company, created_by=self.user)
                job.site_packages.add(site_package)
                job.save()
            self.assertEqual(Job.objects.filter_by_sites([site]).count(), 4)

        self.assertEqual(Job.objects.all().count(), 60)

    def test_purchasedjob_filter_by_sites(self):
        for x in range(8800, 8815):
            domain = 'testsite-%s.jobs' % x
            site = SeoSiteFactory(id=x, domain=domain, name=domain)
            site_package = SitePackageFactory(owner=self.company)
            site_package.make_unique_for_site(site)
            product = ProductFactory(package=site_package, owner=self.company)
            purchased_product = PurchasedProductFactory(product=product,
                                                        owner=self.company)
            for y in range(1, 5):
                job = PurchasedJobFactory(owner=self.company,
                                          created_by=self.user,
                                          purchased_product=purchased_product)
                job.site_packages.add(site_package)
                job.save()
            count = PurchasedJob.objects.filter_by_sites([site]).count()
            self.assertEqual(count, 4)

        self.assertEqual(PurchasedJob.objects.all().count(), 60)

    def test_productgrouping_filter_by_sites(self):
        for x in range(8800, 8815):
            domain = 'testsite-%s.jobs' % x
            site = SeoSiteFactory(id=x, domain=domain, name=domain)
            site_package = SitePackageFactory(owner=self.company)
            site_package.make_unique_for_site(site)
            product = ProductFactory(package=site_package, owner=self.company)
            for y in range(1, 5):
                grouping = ProductGroupingFactory(owner=self.company,
                                                  display_order=y)
                ProductOrder.objects.create(product=product, group=grouping,
                                            display_order=y)
            count = ProductGrouping.objects.filter_by_sites([site]).count()
            self.assertEqual(count, 4)

        self.assertEqual(ProductGrouping.objects.all().count(), 60)

    def test_sitepackage_filter_by_sites(self):
        for x in range(8800, 8815):
            domain = 'testsite-%s.jobs' % x
            site = SeoSiteFactory(id=x, domain=domain, name=domain)
            for y in range(1, 5):
                site_package = SitePackageFactory(owner=self.company)
                site_package.sites.add(site)
                site_package.save()
            count = SitePackage.objects.filter_by_sites([site]).count()
            self.assertEqual(count, 4)
            count = Package.objects.filter_by_sites([site]).count()
            self.assertEqual(count, 4)

        self.assertEqual(SitePackage.objects.all().count(), 60)
        self.assertEqual(Package.objects.all().count(), 60)

    def test_product_filter_by_site_multiple_sites(self):
        site_in_both_packages = SeoSiteFactory(domain='secondsite.jobs', id=7)

        single_site_package = SitePackageFactory(owner=self.company)
        single_site_package.make_unique_for_site(site_in_both_packages)

        both_sites_package = SitePackageFactory(owner=self.company)
        both_sites_package.sites.add(site_in_both_packages)
        both_sites_package.sites.add(self.site)
        both_sites_package.save()

        ProductFactory(package=single_site_package, owner=self.company)
        ProductFactory(package=both_sites_package, owner=self.company)

        self.assertEqual(Product.objects.all().count(), 2)

        # Confirm that filtering by both sites gets both jobs.
        both_sites = [site_in_both_packages, self.site]
        count = Product.objects.filter_by_sites(both_sites).count()
        self.assertEqual(count, 2)

        # Confirm that filtering by the site that only has one job only
        # gets one job.
        count = Product.objects.filter_by_sites([self.site]).count()
        self.assertEqual(count, 1)

        # Confirm that filtering by the site the site that has both jobs gets
        # both jobs.
        count = Product.objects.filter_by_sites([site_in_both_packages]).count()
        self.assertEqual(count, 2)

    def test_job_filter_by_site_multiple_sites(self):
        site_in_both_packages = SeoSiteFactory(domain='secondsite.jobs', id=7)

        single_site_package = SitePackageFactory(owner=self.company)
        single_site_package.make_unique_for_site(site_in_both_packages)

        both_sites_package = SitePackageFactory(owner=self.company)
        both_sites_package.sites.add(site_in_both_packages)
        both_sites_package.sites.add(self.site)
        both_sites_package.save()

        job_on_both = JobFactory(owner=self.company, created_by=self.user)
        job_on_both.site_packages.add(both_sites_package)
        job_on_both.save()

        job_on_new_site = JobFactory(owner=self.company, created_by=self.user)
        job_on_new_site.site_packages.add(single_site_package)
        job_on_new_site.save()

        self.assertEqual(Job.objects.all().count(), 2)

        # Confirm that filtering by both sites gets both jobs.
        both_sites = [site_in_both_packages, self.site]
        count = Job.objects.filter_by_sites(both_sites).count()
        self.assertEqual(count, 2)

        # Confirm that filtering by the site that only has one job only
        # gets one job.
        self.assertEqual(Job.objects.filter_by_sites([self.site]).count(), 1)

        # Confirm that filtering by the site the site that has both jobs gets
        # both jobs.
        count = Job.objects.filter_by_sites([site_in_both_packages]).count()
        self.assertEqual(count, 2)

    def test_purchasedproduct_filter_by_site_multiple_sites(self):
        site_in_both_packages = SeoSiteFactory(domain='secondsite.jobs', id=7)

        single_site_package = SitePackageFactory(owner=self.company)
        single_site_package.make_unique_for_site(site_in_both_packages)

        both_sites_package = SitePackageFactory(owner=self.company)
        both_sites_package.sites.add(site_in_both_packages)
        both_sites_package.sites.add(self.site)
        both_sites_package.save()

        single_site_product = ProductFactory(package=single_site_package, owner=self.company)
        PurchasedProductFactory(product=single_site_product, owner=self.company)

        both_sites_product = ProductFactory(package=both_sites_package, owner=self.company)
        PurchasedProductFactory(product=both_sites_product, owner=self.company)

        self.assertEqual(PurchasedProduct.objects.all().count(), 2)

        # Confirm that filtering by both sites gets both products.
        both_sites = [site_in_both_packages, self.site]
        count = PurchasedProduct.objects.filter_by_sites(both_sites).count()
        self.assertEqual(count, 2)

        # Confirm that filtering by the site that only has one product only
        # gets one product.
        count = PurchasedProduct.objects.filter_by_sites([self.site]).count()
        self.assertEqual(count, 1)

        # Confirm that filtering by the site the site that has both products
        #  gets both jobs.
        objs = PurchasedProduct.objects.filter_by_sites([site_in_both_packages])
        count = objs.count()
        self.assertEqual(count, 2)

    def test_purchasedjob_filter_by_site_multiple_sites(self):
        site_in_both_packages = SeoSiteFactory(domain='secondsite.jobs', id=7)

        single_site_package = SitePackageFactory(owner=self.company)
        single_site_package.make_unique_for_site(site_in_both_packages)

        both_sites_package = SitePackageFactory(owner=self.company)
        both_sites_package.sites.add(site_in_both_packages)
        both_sites_package.sites.add(self.site)
        both_sites_package.save()

        single_site_product = ProductFactory(package=single_site_package, owner=self.company)
        single_site_purchasedproduct = PurchasedProductFactory(
            product=single_site_product, owner=self.company)

        both_sites_product = ProductFactory(package=both_sites_package, owner=self.company)
        both_sites_purchasedproduct = PurchasedProductFactory(
            product=both_sites_product, owner=self.company
        )

        PurchasedJobFactory(owner=self.company, created_by=self.user,
                            purchased_product=single_site_purchasedproduct)
        PurchasedJobFactory(owner=self.company, created_by=self.user,
                            purchased_product=both_sites_purchasedproduct)

        self.assertEqual(PurchasedJob.objects.all().count(), 2)

        # Confirm that filtering by both sites gets both jobs.
        both_sites = [site_in_both_packages, self.site]
        count = PurchasedJob.objects.filter_by_sites(both_sites).count()
        self.assertEqual(count, 2)

        # Confirm that filtering by the site that only has one job only
        # gets one job.
        count = PurchasedJob.objects.filter_by_sites([self.site]).count()
        self.assertEqual(count, 1)

        # Confirm that filtering by the site the site that has both jobs gets
        # both jobs.
        objs = PurchasedJob.objects.filter_by_sites([site_in_both_packages])
        count = objs.count()
        self.assertEqual(count, 2)

    def test_sitepackage_filter_by_site_multiple_sites(self):
        site_in_both_packages = SeoSiteFactory(domain='secondsite.jobs', id=7)

        single_site_package = SitePackageFactory(owner=self.company)
        single_site_package.make_unique_for_site(site_in_both_packages)

        both_sites_package = SitePackageFactory(owner=self.company)
        both_sites_package.sites.add(site_in_both_packages)
        both_sites_package.sites.add(self.site)
        both_sites_package.save()

        self.assertEqual(SitePackage.objects.all().count(), 2)
        self.assertEqual(Package.objects.all().count(), 2)

        # Confirm that filtering by both sites gets both packages.
        both_sites = [site_in_both_packages, self.site]
        count = SitePackage.objects.filter_by_sites(both_sites).count()
        self.assertEqual(count, 2)
        count = Package.objects.filter_by_sites(both_sites).count()
        self.assertEqual(count, 2)

        # Confirm that filtering by the site that only has one package only
        # gets one package.
        count = SitePackage.objects.filter_by_sites([self.site]).count()
        self.assertEqual(count, 1)
        count = Package.objects.filter_by_sites([self.site]).count()
        self.assertEqual(count, 1)

        # Confirm that filtering by the site the site that has both packages
        # gets both packages.
        objs = SitePackage.objects.filter_by_sites([site_in_both_packages])
        count = objs.count()
        self.assertEqual(count, 2)
        count = Package.objects.filter_by_sites([site_in_both_packages]).count()
        self.assertEqual(count, 2)

    def test_productgrouping_filter_by_site_multiple_sites(self):
        site_in_both_packages = SeoSiteFactory(domain='secondsite.jobs', id=7)

        single_site_package = SitePackageFactory(owner=self.company)
        single_site_package.make_unique_for_site(site_in_both_packages)

        both_sites_package = SitePackageFactory(owner=self.company)
        both_sites_package.sites.add(site_in_both_packages)
        both_sites_package.sites.add(self.site)
        both_sites_package.save()

        single_site_product = ProductFactory(package=single_site_package, owner=self.company)
        single_site_grouping = ProductGroupingFactory(owner=self.company)
        ProductOrder.objects.create(product=single_site_product,
                                    group=single_site_grouping)

        both_sites_product = ProductFactory(package=both_sites_package, owner=self.company)
        both_sites_grouping = ProductGroupingFactory(owner=self.company)
        ProductOrder.objects.create(product=both_sites_product,
                                    group=both_sites_grouping)

        # Confirm that filtering by both sites gets both groupings.
        both_sites = [site_in_both_packages, self.site]
        count = ProductGrouping.objects.filter_by_sites(both_sites).count()
        self.assertEqual(count, 2)

        # Confirm that filtering by the site that only has one grouping only
        # gets one grouping.
        count = ProductGrouping.objects.filter_by_sites([self.site]).count()
        self.assertEqual(count, 1)

        # Confirm that filtering by the site the site that has both jobs gets
        # both jobs.
        objs = ProductGrouping.objects.filter_by_sites([site_in_both_packages])
        count = objs.count()
        self.assertEqual(count, 2)

    def test_offlinepurchase_filter_by_site_multiple_sites(self):
        cu = CompanyUserFactory(user=self.user, company=self.company)
        site_in_both_packages = SeoSiteFactory(domain='secondsite.jobs', id=7)

        single_site_package = SitePackageFactory(owner=self.company)
        single_site_package.make_unique_for_site(site_in_both_packages)

        both_sites_package = SitePackageFactory(owner=self.company)
        both_sites_package.sites.add(site_in_both_packages)
        both_sites_package.sites.add(self.site)
        both_sites_package.save()

        single_site_product = ProductFactory(package=single_site_package, owner=self.company)
        single_site_purchase = OfflinePurchaseFactory(owner=self.company, created_by=cu)
        OfflineProduct.objects.create(product=single_site_product,
                                      offline_purchase=single_site_purchase)

        both_sites_product = ProductFactory(package=both_sites_package, owner=self.company)
        both_sites_purchase = OfflinePurchaseFactory(owner=self.company, created_by=cu)
        OfflineProduct.objects.create(product=both_sites_product,
                                      offline_purchase=both_sites_purchase)

        # Confirm that filtering by both sites gets both groupings.
        both_sites = [site_in_both_packages, self.site]
        count = OfflinePurchase.objects.filter_by_sites(both_sites).count()
        self.assertEqual(count, 2)

        # Confirm that filtering by the site that only has one grouping only
        # gets one grouping.
        count = OfflinePurchase.objects.filter_by_sites([self.site]).count()
        self.assertEqual(count, 1)

        # Confirm that filtering by the site the site that has both jobs gets
        # both jobs.
        objs = OfflinePurchase.objects.filter_by_sites([site_in_both_packages])
        count = objs.count()
        self.assertEqual(count, 2)

    def test_invoice_from_offlinepurchase_filter_by_site_multiple_sites(self):
        cu = CompanyUserFactory(user=self.user, company=self.company)
        site_in_both_packages = SeoSiteFactory(domain='secondsite.jobs', id=7)

        single_site_package = SitePackageFactory(owner=self.company)
        single_site_package.make_unique_for_site(site_in_both_packages)

        both_sites_package = SitePackageFactory(owner=self.company)
        both_sites_package.sites.add(site_in_both_packages)
        both_sites_package.sites.add(self.site)
        both_sites_package.save()

        single_site_product = ProductFactory(package=single_site_package, owner=self.company)
        single_site_purchase = OfflinePurchaseFactory(owner=self.company, created_by=cu)
        OfflineProduct.objects.create(product=single_site_product,
                                      offline_purchase=single_site_purchase)

        both_sites_product = ProductFactory(package=both_sites_package, owner=self.company)
        both_sites_purchase = OfflinePurchaseFactory(owner=self.company, created_by=cu)
        OfflineProduct.objects.create(product=both_sites_product,
                                      offline_purchase=both_sites_purchase)

        # Confirm that filtering by both sites gets both groupings.
        both_sites = [site_in_both_packages, self.site]
        count = Invoice.objects.filter_by_sites(both_sites).count()
        self.assertEqual(count, 2)

        # Confirm that filtering by the site that only has one grouping only
        # gets one grouping.
        count = Invoice.objects.filter_by_sites([self.site]).count()
        self.assertEqual(count, 1)

        # Confirm that filtering by the site the site that has both jobs gets
        # both jobs.
        count = Invoice.objects.filter_by_sites([site_in_both_packages]).count()
        self.assertEqual(count, 2)

    def test_invoice_from_purchasedproduct_filter_by_site_multiple_sites(self):
        site_in_both_packages = SeoSiteFactory(domain='secondsite.jobs', id=7)

        single_site_package = SitePackageFactory(owner=self.company)
        single_site_package.make_unique_for_site(site_in_both_packages)

        both_sites_package = SitePackageFactory(owner=self.company)
        both_sites_package.sites.add(site_in_both_packages)
        both_sites_package.sites.add(self.site)
        both_sites_package.save()

        single_site_product = ProductFactory(package=single_site_package, owner=self.company)
        PurchasedProductFactory(product=single_site_product, owner=self.company)

        both_sites_product = ProductFactory(package=both_sites_package, owner=self.company)
        PurchasedProductFactory(product=both_sites_product, owner=self.company)

        self.assertEqual(Invoice.objects.all().count(), 2)

        # Confirm that filtering by both sites gets both products.
        both_sites = [site_in_both_packages, self.site]
        count = Invoice.objects.filter_by_sites(both_sites).count()
        self.assertEqual(count, 2)

        # Confirm that filtering by the site that only has one product only
        # gets one product.
        count = Invoice.objects.filter_by_sites([self.site]).count()
        self.assertEqual(count, 1)

        # Confirm that filtering by the site the site that has both products
        #  gets both jobs.
        count = Invoice.objects.filter_by_sites([site_in_both_packages]).count()
        self.assertEqual(count, 2)

    def test_request_filter_by_site_multiple_sites(self):
        site_in_both_packages = SeoSiteFactory(domain='secondsite.jobs', id=7)

        single_site_package = SitePackageFactory(owner=self.company)
        single_site_package.make_unique_for_site(site_in_both_packages)

        both_sites_package = SitePackageFactory(owner=self.company)
        both_sites_package.sites.add(site_in_both_packages)
        both_sites_package.sites.add(self.site)
        both_sites_package.save()

        single_site_product = ProductFactory(package=single_site_package, owner=self.company)
        single_site_purchasedproduct = PurchasedProductFactory(
            product=single_site_product, owner=self.company)
        # Unapproved PurchasedJobs generate Requests.
        PurchasedJobFactory(owner=self.company, created_by=self.user,
                            purchased_product=single_site_purchasedproduct)

        both_sites_product = ProductFactory(package=both_sites_package, owner=self.company)
        both_sites_purchasedproduct = PurchasedProductFactory(
            product=both_sites_product, owner=self.company)
        PurchasedJobFactory(owner=self.company, created_by=self.user,
                            purchased_product=both_sites_purchasedproduct)

        self.assertEqual(Request.objects.all().count(), 2)

        # Confirm that filtering by both sites gets both products.
        both_sites = [site_in_both_packages, self.site]
        count = Request.objects.filter_by_sites(both_sites).count()
        self.assertEqual(count, 2)

        # Confirm that filtering by the site that only has one product only
        # gets one product.
        count = Request.objects.filter_by_sites([self.site]).count()
        self.assertEqual(count, 1)

        # Confirm that filtering by the site the site that has both products
        #  gets both jobs.
        count = Request.objects.filter_by_sites([site_in_both_packages]).count()
        self.assertEqual(count, 2)

    def test_request_on_purchasedjob_update(self):
        # Creating a PurchasedJob for a Product that requires approval
        # creates a Request
        job = PurchasedJobFactory(owner=self.company, created_by=self.user)
        self.assertEqual(Request.objects.count(), 1)

        # Re-saving that job should not create a new request.
        job.save()
        self.assertEqual(Request.objects.count(), 1)

        # Approving the job should also not create a new request.
        job.is_approved = True
        job.save()
        self.assertEqual(Request.objects.count(), 1)

        # Marking the job as not approved and saving it should not create
        # a new request if no action was taken on the old request.
        job.is_approved = False
        job.save()
        self.assertEqual(Request.objects.count(), 1)

        # Marking the job as not approved and saving it should create
        # a new request if there is no pending request.
        request = Request.objects.get()
        request.action_taken = True
        request.save()
        job.save()
        self.assertEqual(Request.objects.count(), 2)