Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions salesforce/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ def has_add_permission(self, request):
return False

class AdoptionOpportunityRecordAdmin(admin.ModelAdmin):
list_display = ['email', 'book_name', 'school', 'yearly_students', 'verified']
list_filter = ('book_name', 'school', 'verified', 'last_update')
search_fields = ['email', 'account_id']
list_display = ['account_uuid', 'book_name', 'fall_student_number', 'spring_student_number', 'summer_student_number']
list_filter = ('book_name', 'created')
search_fields = ['account_uuid', ]

def has_add_permission(self, request):
return False
Expand Down
55 changes: 15 additions & 40 deletions salesforce/management/commands/update_opportunities.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from salesforce.salesforce import Salesforce

class Command(BaseCommand):
help = "update book adoptions from salesforce.com for getting adoptions by account id"
help = "update book adoptions from salesforce.com for getting adoptions by account uuid"

def handle(self, *args, **options):
with Salesforce() as sf:
Expand All @@ -14,55 +14,30 @@ def handle(self, *args, **options):
if now.month < 7: # Salesforce needs the school base year, this is how they calculate it
year = year - 1

#first, we need to upload any records that have been updated
adoptions_num_updated = 0

adoptions = AdoptionOpportunityRecord.objects.filter(verified=True)
data = []
for adoption in adoptions:
data_dict_item = {
'Id': adoption.opportunity_id,
'CloseDate': adoption.last_update.strftime('%Y-%m-%d'),
'Type': 'Renewal - Verified'
}
data.append(data_dict_item)
results = sf.bulk.Opportunity.update(data)
for result in results:
if result['success']: # we don't need to store these anymore, they are in SF now with a new opportunity type (so we don't get them in the next step)
adoptions_num_updated = adoptions_num_updated + 1
adoptions.get(opportunity_id=result['id']).delete()

# truncate the table
AdoptionOpportunityRecord.objects.all().delete()

# then we will get any new records
command = "SELECT Id, Accounts_UUID__c, Book_Text__c, Contact_Email__c, School_Name__c, Yearly_Students__c, Students__c, Type, Base_Year__c, IsWon from Opportunity WHERE OS_Accounts_ID__c != null AND Type = 'Renewal' AND Base_Year__c = {} AND IsWon = True".format(year)
command = "SELECT Id, Accounts_UUID__c, Book_Text__c, Base_Year__c, IsWon, Fall_Students__c, Spring_Students__c, Summer_Students__c from Opportunity WHERE Accounts_UUID__c != null AND Base_Year__c = {} AND IsWon = True".format(year)

response = sf.query_all(command)
records = response['records']

num_created = 0
num_updated = 0
for record in records:
try:
opportunity = AdoptionOpportunityRecord.objects.get(opportunity_id=record['Id'])
opportunity.account_uuid = record['Accounts_UUID__c']
opportunity.book_name = record['Book_Text__c']
opportunity.email = record['Contact_Email__c']
opportunity.school = record['School_Name__c']
opportunity.yearly_students = record['Yearly_Students__c']
num_updated = num_updated + 1
except AdoptionOpportunityRecord.DoesNotExist:
opportunity = AdoptionOpportunityRecord.objects.create(
opportunity_id=record['Id'],
account_uuid=record['Accounts_UUID__c'],
book_name= record['Book_Text__c'],
email= record['Contact_Email__c'],
school= record['School_Name__c'],
yearly_students= record['Yearly_Students__c']
opportunity, created = AdoptionOpportunityRecord.objects.update_or_create(
opportunity_id=record['Id'],
defaults = {'account_uuid': record['Accounts_UUID__c'],
'book_name': record['Book_Text__c'],
'fall_student_number': record['Fall_Students__c'],
'spring_student_number': record['Spring_Students__c'],
'summer_student_number': record['Summer_Students__c'],
}
)
num_created = num_created + 1


opportunity.save()
if created:
num_created = num_created + 1

response = self.style.SUCCESS("Successfully updated opportunity records. {} were newly created and {} were updated. {} were synced with Salesforce".format(num_created, num_updated, adoptions_num_updated))
response = self.style.SUCCESS("Successfully updated opportunity records. {} were newly created.".format(num_created))
self.stdout.write(response)
28 changes: 28 additions & 0 deletions salesforce/migrations/0102_auto_20220512_0814.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 3.2.5 on 2022-05-12 13:14

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('salesforce', '0101_merge_20220506_1353'),
]

operations = [
migrations.AddField(
model_name='adoptionopportunityrecord',
name='fall_student_number',
field=models.IntegerField(blank=True, null=True),
),
migrations.AddField(
model_name='adoptionopportunityrecord',
name='spring_student_number',
field=models.IntegerField(blank=True, null=True),
),
migrations.AddField(
model_name='adoptionopportunityrecord',
name='summer_student_number',
field=models.IntegerField(blank=True, null=True),
),
]
41 changes: 41 additions & 0 deletions salesforce/migrations/0103_auto_20220516_1045.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Generated by Django 3.2.5 on 2022-05-16 15:45

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('salesforce', '0102_auto_20220512_0814'),
]

operations = [
migrations.RemoveField(
model_name='adoptionopportunityrecord',
name='account_id',
),
migrations.RemoveField(
model_name='adoptionopportunityrecord',
name='confirmed_yearly_students',
),
migrations.RemoveField(
model_name='adoptionopportunityrecord',
name='email',
),
migrations.RemoveField(
model_name='adoptionopportunityrecord',
name='last_update',
),
migrations.RemoveField(
model_name='adoptionopportunityrecord',
name='school',
),
migrations.RemoveField(
model_name='adoptionopportunityrecord',
name='verified',
),
migrations.RemoveField(
model_name='adoptionopportunityrecord',
name='yearly_students',
),
]
10 changes: 3 additions & 7 deletions salesforce/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,12 @@ def __str__(self):

class AdoptionOpportunityRecord(models.Model):
opportunity_id = models.CharField(max_length=255, unique=True)
account_id = models.CharField(max_length=255, null=True, blank=True) # TODO: for deletion after switching to UUID
account_uuid = models.UUIDField(null=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering if it might help data consistency to have the contact id here too - since we do have that in the /api/user endpoint

book_name = models.CharField(max_length=255)
email = models.EmailField(null=True, blank=True)
school = models.CharField(max_length=255)
yearly_students = models.CharField(max_length=255)
confirmed_yearly_students = models.IntegerField(null=True, blank=True,)
created = models.DateTimeField(auto_now_add=True)
last_update = models.DateTimeField(auto_now=True)
verified = models.BooleanField(default=False)
fall_student_number = models.IntegerField(null=True, blank=True,)
spring_student_number = models.IntegerField(null=True, blank=True,)
summer_student_number = models.IntegerField(null=True, blank=True,)

def __str__(self):
return self.opportunity_id
Expand Down
16 changes: 3 additions & 13 deletions salesforce/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,14 @@ class Meta:
model = AdoptionOpportunityRecord
fields = ('id',
'opportunity_id',
'account_id',
'account_uuid',
'book_name',
'email',
'school',
'yearly_students',
'confirmed_yearly_students',
'verified',
'created',
'last_update')
'created')
read_only_fields = ('id',
'opportunity_id',
'account_id',
'account_uuid',
'book_name',
'email',
'school',
'yearly_students',
'created',
'last_update',
)

class PartnerSerializer(serializers.ModelSerializer):
Expand Down
19 changes: 18 additions & 1 deletion salesforce/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from django.conf import settings
from django.core.management import call_command
from django.test import LiveServerTestCase, TestCase
from django.test import LiveServerTestCase, TestCase, Client
from six import StringIO
from django.core.exceptions import ValidationError

Expand Down Expand Up @@ -165,3 +165,20 @@ def test_mapbox_setting_creation(self):
setting = self.create_mapbox_setting()
self.assertTrue(isinstance(setting, MapBoxDataset))
self.assertEqual(setting.__str__(), setting.name)


class AdoptionOpportunityTest(TestCase):
def setUp(self):
self.client = Client()
self.opportunity = AdoptionOpportunityRecord(opportunity_id='0066f000015SSy5AAG',
book_name='US History',
account_uuid='f826f1b1-ead5-4594-82b3-df9a2753cb43',
fall_student_number=123,
spring_student_number=75,
summer_student_number=None)
self.opportunity.save()

def test_query_opportunity_by_account_uuid(self):
response = self.client.get('/apps/cms/api/salesforce/renewal?account_uuid=f826f1b1-ead5-4594-82b3-df9a2753cb43')
self.assertIn(b'"students": "123"', response.content)

2 changes: 1 addition & 1 deletion salesforce/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
urlpatterns = [
url(r'', include(router.urls)),
url(r'^adoption-status/', views.get_adoption_status),
url(r'renewal/(?P<account_id>\d+)/', views.AdoptionOpportunityRecordViewSet.as_view({'get': 'list', 'post': 'post'})),
url(r'^renewal/', views.AdoptionOpportunityRecordViewSet.as_view({'get': 'list'})),
url(r'reviews/', views.PartnerReviewViewSet.as_view({'get': 'list', 'post': 'post', 'patch': 'patch', 'delete': 'delete'})),
]
43 changes: 10 additions & 33 deletions salesforce/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,40 +123,17 @@ def list(self, request, *args, **kwargs):

class AdoptionOpportunityRecordViewSet(viewsets.ViewSet):
@action(methods=['get'], detail=True)
def list(self, request, account_id):
def list(self, request):
account_uuid = request.GET.get('account_uuid', False)
# a user can have many adoption records - one for each book
queryset = AdoptionOpportunityRecord.objects.filter(account_id=account_id, verified=False)
serializer = AdoptionOpportunityRecordSerializer(queryset, many=True)
return Response(serializer.data)

@action(methods=['post'], detail=True)
def post(self, request, account_id, format=None):
# this takes the adoption record as a post and looks it up, since a user can adopt more than one book
records = AdoptionOpportunityRecord.objects.filter(account_id=account_id)
if not records:
return JsonResponse({'error': 'No records associated with that ID.'})

# adoption id is included in the post request
id = self.request.data.get('id', None)
if id:
try:
record = AdoptionOpportunityRecord.objects.get(id=id)
except AdoptionOpportunityRecord.DoesNotExist:
return JsonResponse({'error': 'Invalid adoption id.'})

confirmed_yearly_students = self.request.data.get('confirmed_yearly_students', 0)
data = {"verified": True, "confirmed_yearly_students": confirmed_yearly_students}

serializer = AdoptionOpportunityRecordSerializer(record, data=data, partial=True)

if serializer.is_valid():
serializer.save()
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

return JsonResponse(data)
else:
return JsonResponse({'error': 'Must include adoption ID to update'})
queryset = AdoptionOpportunityRecord.objects.filter(account_uuid=account_uuid)
book_list = []
for record in queryset:
student_nums = [record.fall_student_number or 0, record.spring_student_number or 0, record.summer_student_number or 0]
book_list.append({"name": record.book_name , "students": str(max(student_nums))})
data = {"Books": book_list}

return JsonResponse(data)


def get_adoption_status(request):
Expand Down