def setUp(self): super(AddEstimates, self).setUp() self.login_as_member('new') # use post training project to require estimates membership = models.Membership.objects.get( member_id=self.member_id, giving_project_id=self.post_id) member = models.Member.objects.get(pk=self.member_id) member.current = membership.pk member.save() # create donors without estimates donor = models.Donor(firstname='Al', lastname='Bautista', membership=membership) donor.save() self.donor_id1 = donor.pk donor = models.Donor(firstname='Velcro', lastname='Cat', membership=membership) donor.save() self.donor_id2 = donor.pk # set up base form POST data given 2 donors we just created self.base_form_data = { 'form-MAX_NUM_FORMS': 2, 'form-INITIAL_FORMS': 2, 'form-TOTAL_FORMS': 2, 'form-0-donor': unicode(self.donor_id1), 'form-0-amount': u'', 'form-0-likelihood': u'', 'form-1-donor': unicode(self.donor_id2), 'form-1-amount': u'', 'form-1-likelihood': u'', }
def test_estimates_done(self): """ Verify add estimates form is not shown if contacts have estimates """ # use post-training membership membership = models.Membership.objects.get(pk=self.post_id) member = membership.member member.current = self.post_id member.save() # create contacts with amount & likelihood contact = models.Donor(firstname='Anna', membership=membership, amount=0, likelihood=0) contact.save() contact = models.Donor(firstname='Banana', membership=membership, amount=567, likelihood=34) contact.save() response = self.client.get(self.url) # verify estimates form is not shown self.assertTemplateNotUsed('fund/forms/add_estimates.html') self.assertEqual(response.context['request'].membership, membership)
def setUp(self): super(OverdueEmails, self).setUp() self.login_as_member('new') # create 2 donors on new member's pre membership donor = models.Donor(firstname='En', membership_id=self.pre_id) donor.save() self.donor1 = donor.pk donor = models.Donor(firstname='Tva', membership_id=self.pre_id) donor.save() self.donor2 = donor.pk # create another member, membership, donor member = models.Member.objects.create_with_user(email='*****@*****.**', first_name='Two', last_name='Dos') member.save() gp = models.GivingProject.objects.get(title='Post training') membership = models.Membership(giving_project=gp, member=member, approved=True) membership.save() donor = models.Donor(firstname='Tre', membership=membership) donor.save() self.donor3 = donor.pk
def test_merge_duplicates(self): """ Verify that duplicate contacts are merged before form is displayed Add duplicates in all 3 ways (last, phone, email). """ unique_donors = models.Donor.objects.filter( membership__member_id=self.member_id).count() self.assertEqual(unique_donors, 8) expect_to_contain = [] # create copies of existing donors from fixtures # match by first + last name, add notes donor = models.Donor.objects.get(pk=1) self.assertTrue(donor.lastname) self.assertEqual(donor.notes, '') copy = models.Donor(membership_id=self.ship_id, firstname=donor.firstname, lastname=donor.lastname, notes='Beep.') copy.save() expect_to_contain += [donor.firstname, donor.lastname, copy.notes] # match by first + email donor = models.Donor.objects.get(pk=2) self.assertTrue(donor.email) copy = models.Donor(membership_id=self.ship_id, firstname=donor.firstname, email=donor.email) copy.save() expect_to_contain += [donor.firstname, donor.email] # match by first + phone, add last name donor = models.Donor.objects.get(pk=3) self.assertEqual(donor.lastname, '') self.assertTrue(donor.phone) copy = models.Donor(membership_id=self.ship_id, firstname=donor.firstname, lastname='Surname', phone=donor.phone) copy.save() expect_to_contain += [donor.firstname, copy.lastname, donor.phone] res = self.client.get(self.get_url, follow=True) self.assertEqual(res.status_code, 200) self.assertTemplateUsed(res, self.template) formset = res.context['formset'] self.assertEqual(formset.initial_form_count(), unique_donors) for expected_string in expect_to_contain: self.assertContains(res, expected_string, 1)
def test_gift_notifications(self): # enter gift received from donor test_donor = models.Donor.objects.get(pk=self.donor_id) test_donor.received_this = 100 test_donor.save() member = models.Member.objects.create_with_user(email='*****@*****.**', password='******', first_name='A', last_name='B') membership = models.Membership(member=member, giving_project_id=1) membership.save() donor = models.Donor(membership=membership, firstname='Greta', lastname='Polkis', received_next=55) donor.save() # run cron task response = self.client.get(self.cron_url, follow=True) self.assertEqual(response.status_code, 200) # verify notification shows response = self.client.get(self.url, follow=True) self.assertTemplateUsed(response, 'fund/home.html') self.assertContains(response, 'gift or pledge received') self.assertContains(response, unicode(test_donor)) # verify notification doesn't show on reload response = self.client.get(self.url, follow=True) self.assertTemplateUsed(response, 'fund/home.html') self.assertNotContains(response, 'gift or pledge received') # verify emails sent self.assertEqual(len(mail.outbox), 2) testacct_emailed = False abcd_emailed = False for email in mail.outbox: self.assertIn('gift or pledge received', email.body) if email.to == [member.user.username]: self.assertFalse(abcd_emailed) self.assertIn(unicode(donor), email.body) self.assertNotIn(unicode(test_donor), email.body) abcd_emailed = True elif email.to == [self.email]: self.assertFalse(testacct_emailed) self.assertIn(unicode(test_donor), email.body) self.assertNotIn(unicode(donor), email.body) testacct_emailed = True else: self.fail( 'Unexpected gift notification email recipient: {}'.format( email.to)) self.assertTrue(abcd_emailed) self.assertTrue(testacct_emailed)
def test_contacts_without_est(self): """ Going to home page with contacts that do not have estimates """ # using pre-training membership membership = models.Membership.objects.get(pk=self.pre_id) # create contacts without amount or likelihood contact1 = models.Donor(firstname='Anna', membership=membership) contact1.save() contact2 = models.Donor(firstname='Banana', membership=membership) contact2.save() response = self.client.get(self.url) # verify estimates form is not shown self.assertEqual(response.context['request'].membership, membership) self.assertTemplateNotUsed('fund/forms/add_estimates.html') # using post-training membership member = membership.member member.current = self.post_id member.save() membership = models.Membership.objects.get(pk=self.post_id) # move created contacts to current membership contact1.membership = membership contact1.save() contact2.membership = membership contact2.save() response = self.client.get(self.url, follow=True) # verify estimates form is shown self.assertTemplateUsed('fund/forms/add_estimates.html') self.assertEqual(response.context['request'].membership, membership)
def test_same_member(self): """ overdue step in two memberships for same member """ donor = models.Donor(membership_id=self.post_id, firstname='Other') donor.save() step = models.Step(donor_id=self.donor1, date=timezone.now() - timedelta(days=3)) step.save() step = models.Step(donor=donor, date=timezone.now() - timedelta(days=9)) step.save() self.assertEqual(len(mail.outbox), 0) response = self.client.get(self.url, follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(len(mail.outbox), 2)
def setup_member(self, member): self.member_id = member.pk post_gp = models.GivingProject.objects.get(title="Post training") post_ship = models.Membership(giving_project=post_gp, member=member, approved=True) post_ship.save() if member.first_name == 'current': self.ship_id = post_ship.pk member.current = post_ship.pk member.save() # create donor & step donor = models.Donor(membership=post_ship, firstname='Anna', amount=500, talked=True, likelihood=50) donor.save() step = models.Step(donor=donor, description='Talk to about project', created=timezone.now(), date='2013-04-06') step.save() self.donor_id = donor.pk self.step_id = step.pk elif member.first_name == 'new': self.post_id = post_ship.pk pre_gp = models.GivingProject.objects.get(title='Pre training') pre_ship = models.Membership(giving_project=pre_gp, member=member, approved=True) pre_ship.save() self.pre_id = self.ship_id = pre_ship.pk member.current = pre_ship.pk member.save() else: raise Exception('setup_member got unexpected name: {}'.format( member.first_name))
def test_basic(self): # membership with a few donors, some progress self.login_as_member('new') ship_id = self.post_id # first donor donor = models.Donor(membership_id=ship_id, firstname='Alice', amount=240, likelihood=75, talked=True) donor.save() step = models.Step(donor=donor, date='2015-04-01', description='Talk', completed='2015-04-01') step.save() step = models.Step(donor=donor, date='2015-5-25', description='Ask') step.save() # second donor donor = models.Donor(membership_id=ship_id, firstname='Bab', talked=True, amount=300, likelihood=50, asked=True, promised=300, received_this=100, received_next=100) donor.save() step = models.Step(donor=donor, date='2015-04-01', description='Ask', completed='2015-04-01', asked=True) step.save() step = models.Step(donor=donor, date='2015-04-08', description='Follow upt', completed='2015-04-08', promised=300) step.save() step = models.Step(donor=donor, date='2015-5-25', description='Thank') step.save() donors = models.Donor.objects.filter( membership_id=ship_id).prefetch_related('step_set') progress, incomplete_steps = _compile_membership_progress(donors) self.assertIsInstance(progress, dict) self.assertEqual(progress['estimated'], 330) self.assertEqual(progress['contacts'], 2) self.assertEqual(progress['asked'], 1) self.assertEqual(progress['talked'], 1) self.assertEqual(progress['promised'], 100) self.assertEqual(progress['received'], 200) self.assertEqual(progress['contacts_remaining'], 0) self.assertEqual(progress['togo'], 30) self.assertEqual(len(incomplete_steps), 2) for donor in donors: self.assertIsInstance(donor.next_step, models.Step) self.assertIs(type(donor.completed_steps), list) self.assertTrue(len(donor.completed_steps) > 0)
def add_mult(request): """ Add multiple contacts, with or without estimates If a user enters duplicates (same first & last name), they'll get a confirmation form before donors are saved GET is via redirect from home, and should render top blocks as well as form POST will be via AJAX and does not need block info """ membership = request.membership est = membership.giving_project.require_estimates() if est: contact_formset = formset_factory(forms.MassDonor, extra=5) else: contact_formset = formset_factory(forms.MassDonorPre, extra=5) empty_error = u'' if request.method == 'POST': membership.last_activity = timezone.now() membership.save() formset = contact_formset(request.POST) if formset.is_valid(): if formset.has_changed(): logger.info('AddMult valid formset') # get list of existing donors to check for duplicates donors = models.Donor.objects.filter(membership=membership) donors = [unicode(donor) for donor in donors] duplicates = [] for form in formset.cleaned_data: if form: # ignore blank rows confirm = form['confirm'] and form['confirm'] == '1' if not confirm and (form['firstname'] + ' ' + form['lastname'] in donors): # this entry is a duplicate that has not yet been confirmed initial = { 'firstname': form['firstname'], 'lastname': form['lastname'], 'confirm': u'1' } if est: initial['amount'] = form['amount'] initial['likelihood'] = form['likelihood'] duplicates.append(initial) else: # not a duplicate if est: contact = models.Donor( membership=membership, firstname=form['firstname'], lastname=form['lastname'], amount=form['amount'], likelihood=form['likelihood']) else: contact = models.Donor( membership=membership, firstname=form['firstname'], lastname=form['lastname']) contact.save() logger.info('contact created') if duplicates: logger.info('Showing confirmation page for duplicates: ' + str(duplicates)) empty_error = ( u'<ul class="errorlist"><li>The contacts below have the ' 'same name as contacts you have already entered. Press submit again ' 'to confirm that you want to add them.</li></ul>') if est: contact_formset = formset_factory(forms.MassDonor) else: contact_formset = formset_factory(forms.MassDonorPre) formset = contact_formset(initial=duplicates) else: # saved successfully (no duplicates check needed) return HttpResponse("success") else: # empty formset empty_error = u'<ul class="errorlist"><li>Please enter at least one contact.</li></ul>' else: # invalid formset logger.info(formset.errors) return render(request, 'fund/forms/add_contacts.html', { 'formset': formset, 'empty_error': empty_error }) else: # GET formset = contact_formset() steps, news, grants = _get_block_content(membership) header = membership.giving_project.title return render( request, 'fund/forms/add_contacts.html', { '1active': 'true', 'header': header, 'news': news, 'grants': grants, 'steps': steps, 'formset': formset })
def copy_contacts(request): # base formset copy_formset = formset_factory(forms.CopyContacts, extra=0) if request.method == 'POST': logger.info(request.POST) if 'skip' in request.POST: logger.info('User skipping copy contacts') request.membership.copied_contacts = True request.membership.save() return HttpResponse('success') else: formset = copy_formset(request.POST) logger.info('Copy contracts submitted') if formset.is_valid(): for form in formset.cleaned_data: if form['select']: contact = models.Donor(membership=request.membership, firstname=form['firstname'], lastname=form['lastname'], phone=form['phone'], email=form['email'], notes=form['notes']) contact.save() logger.debug('Contact created') request.membership.copied_contacts = True request.membership.save() return HttpResponse('success') else: # invalid logger.warning('Copy formset somehow invalid?! ' + str(request.POST)) logger.warning(formset.errors) else: # GET all_donors = (models.Donor.objects.filter( membership__member=request.membership.member).order_by( 'firstname', 'lastname', '-added')) # extract name, contact info, notes. handle duplicates initial_data = [] for donor in all_donors: if (initial_data and donor.firstname == initial_data[-1]['firstname'] and (donor.lastname and donor.lastname == initial_data[-1]['lastname'] or donor.phone and donor.phone == initial_data[-1]['phone'] or donor.email and donor.email == initial_data[-1]['email'])): logger.info('Duplicate found! ' + str(donor)) initial_data[-1]['lastname'] = initial_data[-1][ 'lastname'] or donor.lastname initial_data[-1][ 'phone'] = initial_data[-1]['phone'] or donor.phone initial_data[-1][ 'email'] = initial_data[-1]['email'] or donor.email initial_data[-1]['notes'] += donor.notes initial_data[-1]['notes'] = initial_data[-1][ 'notes'][:253] # cap below field char limit else: # not duplicate; add a row initial_data.append({ 'firstname': donor.firstname, 'lastname': donor.lastname, 'phone': donor.phone, 'email': donor.email, 'notes': donor.notes }) logger.debug('Loading copy contacts formset') logger.info('Initial data list of ' + str(len(initial_data))) formset = copy_formset(initial=initial_data) return render(request, 'fund/forms/copy_contacts.html', {'formset': formset})