def reviewremind(request, id, uid): context = {} event = get_object_or_404(Event, pk=id) if event.closed or event.reviewed: return HttpResponse("Event Closed") cci = event.ccinstances.filter(crew_chief_id=uid) if cci: # only do heavy lifting if we need to pdf_handle = generate_pdfs_standalone([event.id]) filename = "%s.workorder.pdf" % slugify(event.event_name) attachments = [{"file_handle": pdf_handle, "name": filename}] cci = cci[0] ReportReminder.objects.create(event=cci.event, crew_chief=cci.crew_chief) email_body = 'This is a reminder that you have a pending crew chief report for "%s" \n' \ ' Please Visit %s%s to complete it' % (event.event_name, request.get_host(), reverse("my-ccreport", args=[event.id])) email = DLEG(subject="LNL Crew Chief Report Reminder Email", to_emails=[cci.crew_chief.email], body=email_body, attachments=attachments) email.send() messages.add_message(request, messages.INFO, 'Reminder Sent') return HttpResponseRedirect(reverse('event-review', args=(event.id,))) else: return HttpResponse("Bad Call")
def form_valid(self, form): # if the person was just changed from unaffiliated to an associate member, send them an email. if 'groups' in form.changed_data and 'groups' in form.cleaned_data: oldgroups = form.initial['groups'] newgroups = form.cleaned_data['groups'] if not oldgroups and Group.objects.get( name='Associate') in newgroups: email = DefaultLNLEmailGenerator( subject="Welcome to LNL!", to_emails=[self.object.email], bcc=[settings.EMAIL_TARGET_S], reply_to=[settings.EMAIL_TARGET_S], context={'new_member': self.object}, template_basename='emails/email_welcome') email.send() messages.success(self.request, "Welcome email sent") # Ensure that title is stripped when no longer an officer if Group.objects.get(name="Officer") not in newgroups: self.object.title = None self.object.save() messages.success(self.request, "Account Info Saved!", extra_tags='success') return super(UserUpdateView, self).form_valid(form)
def reviewremind(request, id, uid): event = get_object_or_404(Event, pk=id) if event.closed or event.reviewed: return HttpResponse("Event Closed") cci = event.ccinstances.filter(crew_chief_id=uid) if cci: # only do heavy lifting if we need to pdf_handle = generate_pdfs_standalone([event.id]) filename = "%s.workorder.pdf" % slugify(event.event_name) attachments = [{"file_handle": pdf_handle, "name": filename}] cci = cci[0] ReportReminder.objects.create(event=cci.event, crew_chief=cci.crew_chief) email_body = 'This is a reminder that you have a pending crew chief report for "%s" \n' \ ' Please Visit %s%s to complete it' % (event.event_name, request.get_host(), reverse("my-ccreport", args=[event.id])) email = DLEG(subject="LNL Crew Chief Report Reminder Email", to_emails=[cci.crew_chief.email], body=email_body, attachments=attachments) email.send() messages.add_message(request, messages.INFO, 'Reminder Sent') return HttpResponseRedirect(reverse('event-review', args=(event.id,))) else: return HttpResponse("Bad Call")
def cancel(request, id): set_revision_comment("Cancelled", None) context = {} context['msg'] = "Event Cancelled" event = get_object_or_404(BaseEvent, pk=id) if not request.user.has_perm('events.cancel_event', event): raise PermissionDenied if event.closed: messages.add_message(request, messages.ERROR, 'Event is closed.') return HttpResponseRedirect(reverse('events:detail', args=(event.id,))) event.cancelled = True event.cancelled_by = request.user event.cancelled_on = timezone.now() event.save() if event.contact and event.contact.email: targets = [event.contact.email] else: targets = [] email_body = 'The event "%s" has been cancelled by %s. If this is incorrect, please contact our vice president at [email protected].' % (event.event_name, str(request.user)) if request.user.email: email_body = email_body[:-1] email_body += " or try them at %s." % request.user.email email = DLEG(subject="Event Cancelled", to_emails=targets, body=email_body, bcc=[settings.EMAIL_TARGET_VP]) email.send() return HttpResponseRedirect(reverse('events:detail', args=(event.id,)))
def email_cc_notification(sender, instance, created, raw=False, **kwargs): """ Sends an email to a crew cheif to notify them of being made one """ if created and not raw: i = instance # generate our pdf event = i.event pdf_handle = generate_pdfs_standalone([event.id]) filename = "%s.workorder.pdf" % slugify(event.event_name) attachments = [{"file_handle": pdf_handle, "name": filename}] if i.setup_start: local = timezone.localtime(i.setup_start) local_formatted = local.strftime("%A %B %d at %I:%M %p") else: local_formatted = "a time of your choice " email_body = """ You\'ve been added as a crew chief to the event "%s". \n You have signed up to be crew chief for %s, with your setup starting on %s in the %s \n \n Please note that the attached Workorder PDF contains all services relating to the event, not just your assigned service. """ % (i.event.event_name, i.service, local_formatted, i.setup_location, ) e = DLEG(subject="Crew Chief Add Notification", to_emails=[instance.crew_chief.email], body=email_body, attachments=attachments) e.send()
def email_cc_notification(sender, instance, created, raw=False, **kwargs): """ Sends an email to a crew cheif to notify them of being made one """ if created and not raw: i = instance # generate our pdf event = i.event pdf_handle = generate_pdfs_standalone([event.id]) filename = "%s.workorder.pdf" % slugify(event.event_name) attachments = [{"file_handle": pdf_handle, "name": filename}] local = timezone.localtime(i.setup_start) local_formatted = local.strftime("%A %B %d at %I:%M %p") email_body = """ You\'ve been added as a crew chief to the event "%s". \n You have signed up to be crew chief for %s, with your setup starting on %s in the %s \n \n Please note that the attached Workorder PDF contains all services relating to the event, not just your assigned service. """ % ( i.event.event_name, i.service, local_formatted, i.setup_location, ) e = DLEG(subject="Crew Chief Add Notification", to_emails=[instance.crew_chief.email], body=email_body, attachments=attachments) e.send()
def email_billing_delete(sender, instance, **kwargs): if not instance.opt_out_update_email: i = instance email_body = """ The bill for the amount of $%s on "%s" has been deleted """ % (i.amount, i.event.event_name,) e = DLEG(subject="LNL Billing Deletion Notification", to_emails=[i.event.contact.email], body=email_body, bcc=[settings.EMAIL_TARGET_T]) e.send()
def email_billing_create(sender, instance, created, raw=False, **kwargs): """ Sends an email to the client to notify of a bill being created """ if created and not instance.opt_out_initial_email and not raw: i = instance email_body = """ A New LNL bill has been posted for "%s" on %s for the amount of $%s """ % (i.event.event_name, i.date_billed, i.amount) e = DLEG(subject="LNL Billing Create Notification", to_emails=[i.event.contact.email], body=email_body, bcc=[settings.EMAIL_TARGET_T]) e.send()
def email_billing_marked_paid(sender, instance, created, raw=False, **kwargs): """ Sends an email to the client to notify of a bill having been paid """ if not created and not raw: if instance.date_paid and not instance.opt_out_update_email: i = instance email_body = """ Thank you for paying the bill for "%s" on %s for the amount of $%s """ % (i.event.event_name, i.date_paid, i.amount) e = DLEG(subject="LNL Billing Paid Notification", to_emails=[i.event.contact.email], body=email_body, bcc=[settings.EMAIL_TARGET_T]) e.send()
def initial_user_create_notify(sender, instance, created, raw=False, **kwargs): if created and not raw: i = instance email_body = """ A new user has joined LNLDB: %s (%s) """ % (i.username, i.email) e = DLEG(subject="LNL User Joined", to_emails=[settings.EMAIL_TARGET_S], body=email_body) e.send()
def email_billing_delete(sender, instance, **kwargs): if not instance.opt_out_update_email: i = instance email_body = """ The bill for the amount of $%s on "%s" has been deleted """ % ( i.amount, i.event.event_name, ) e = DLEG(subject="LNL Billing Deletion Notification", to_emails=[i.event.contact.email], body=email_body, bcc=[settings.EMAIL_TARGET_T]) e.send()
def form_valid(self, form): messages.success(self.request, "Billing Email Created!", extra_tags='success') response = super(MultiBillingEmailCreate, self).form_valid(form) # send the email i = form.instance to = list(i.email_to_users.values_list('email', flat=True)) to.extend(list(i.email_to_orgs.values_list('exec_email', flat=True))) pdf_handle = generate_multibill_pdf_standalone(self.multibilling, self.request.user, request=self.request) filename = "bill.pdf" attachments = [{"file_handle": pdf_handle, "name": filename}] email = DLEG(subject=i.subject, body=i.message, to_emails=to, reply_to=[settings.EMAIL_TARGET_T], bcc=[settings.EMAIL_TARGET_T], attachments=attachments) email.send() i.sent_at = timezone.now() i.save() return response
def denial(request, id): context = {} context['msg'] = "Deny Event" event = get_object_or_404(BaseEvent, pk=id) if not request.user.has_perm('events.decline_event', event): raise PermissionDenied if event.closed: messages.add_message(request, messages.ERROR, 'Event is closed.') return HttpResponseRedirect(reverse('events:detail', args=(event.id,))) if event.cancelled: messages.add_message(request, messages.INFO, 'Event has already been cancelled!') return HttpResponseRedirect(reverse('events:detail', args=(event.id,))) if request.method == 'POST': form = EventDenialForm(request.POST, instance=event) if form.is_valid(): set_revision_comment("Denied", form) e = form.save(commit=False) e.cancelled = True e.cancelled_by = request.user e.cancelled_on = timezone.now() e.closed = True e.closed_by = request.user e.closed_on = timezone.now() e.save() # confirm with user messages.add_message(request, messages.INFO, 'Denied Event') if e.contact and e.contact.email: email_body = 'Sorry, but your event "%s" has been denied. \n Reason: "%s"' % ( event.event_name, event.cancelled_reason) email = DLEG(subject="Event Denied", to_emails=[e.contact.email], body=email_body, bcc=[settings.EMAIL_TARGET_VP]) email.send() else: messages.add_message(request, messages.INFO, 'No contact info on file for denial. Please give them the bad news.') return HttpResponseRedirect(reverse('events:detail', args=(e.id,))) else: context['form'] = form else: form = EventDenialForm(instance=event) context['form'] = form return render(request, 'form_crispy.html', context)
def form_valid(self, form): # if the person was just changed from unaffiliated to an associate member, send them an email. if 'groups' in form.changed_data and 'groups' in form.cleaned_data: oldgroups = form.initial['groups'] newgroups = form.cleaned_data['groups'] if not oldgroups and Group.objects.get(name='Associate') in newgroups: email = DefaultLNLEmailGenerator( subject="Welcome to LNL!", to_emails=[self.object.email], bcc=[settings.EMAIL_TARGET_S], reply_to=[settings.EMAIL_TARGET_S], context={'new_member': self.object}, template_basename='emails/email_welcome' ) email.send() messages.success(self.request, "Welcome email sent") messages.success(self.request, "Account Info Saved!", extra_tags='success') return super(UserUpdateView, self).form_valid(form)
def approval(request, id): context = {} context['msg'] = "Approve Event" event = get_object_or_404(Event, pk=id) if not request.user.has_perm('events.approve_event', event): raise PermissionDenied if event.approved: messages.add_message(request, messages.INFO, 'Event has already been approved!') return HttpResponseRedirect(reverse('events.views.flow.viewevent', args=(event.id,))) if request.method == 'POST': form = EventApprovalForm(request.POST, instance=event) if form.is_valid(): e = form.save(commit=False) e.approved = True e.approved_on = timezone.now() e.approved_by = request.user e.save() # confirm with user messages.add_message(request, messages.INFO, 'Approved Event') if e.contact and e.contact.email: email_body = 'Your event "%s" has been approved!' % event.event_name email = DLEG(subject="Event Approved", to_emails=[e.contact.email], body=email_body, bcc=[settings.EMAIL_TARGET_VP]) email.send() else: messages.add_message(request, messages.INFO, 'No contact info on file for approval. Please give them the good news!') return HttpResponseRedirect(reverse('events.views.flow.viewevent', args=(e.id,))) else: context['formset'] = form else: unbilled_events = Event.objects.filter(org__in=event.org.all()).filter(billings__date_paid__isnull=True, billings__date_billed__isnull=False).filter(closed=False).filter(cancelled=False).filter(test_event=False) unbilled_events = map(str, unbilled_events) if event.org.exists() and unbilled_events: messages.add_message(request, messages.WARNING, "Organization has unbilled events: %s" % ", ".join(unbilled_events)) form = EventApprovalForm(instance=event) context['formset'] = form return render(request, 'form_crispy.html', context)
def denial(request, id): context = {} context['msg'] = "Deny Event" event = get_object_or_404(Event, pk=id) if not request.user.has_perm('events.deny_event', event): raise PermissionDenied if event.cancelled: messages.add_message(request, messages.INFO, 'Event has already been cancelled!') return HttpResponseRedirect(reverse('events.views.flow.viewevent', args=(event.id,))) if request.method == 'POST': form = EventDenialForm(request.POST, instance=event) if form.is_valid(): e = form.save(commit=False) e.cancelled = True e.cancelled_on = timezone.now() e.cancelled_by = request.user e.closed_by = request.user e.closed_on = timezone.now() e.save() # confirm with user messages.add_message(request, messages.INFO, 'Denied Event') if e.contact and e.contact.email: email_body = 'Your event "%s" has been denied! \n Reason: "%s"' % ( event.event_name, event.cancelled_reason) email = DLEG(subject="Event Denied", to_emails=[e.contact.email], body=email_body, bcc=[settings.EMAIL_TARGET_VP]) email.send() else: messages.add_message(request, messages.INFO, 'No contact info on file for denial. Please give them the bad news.') return HttpResponseRedirect(reverse('events.views.flow.viewevent', args=(e.id,))) else: context['formset'] = form else: form = EventDenialForm(instance=event) context['formset'] = form return render(request, 'form_crispy.html', context)
def done(self, form_list, **kwargs): # return HttpResponse([form.cleaned_data for form in form_list]) event = Event.event_mg.consume_workorder_formwiz(form_list, self) # return HttpResponseRedirect(reverse('events.views.my.myeventdetail',args=(event.id,))) email_body = "You have successfully submitted an event titled %s" % event.event_name email = DLEG(subject="New Event Submitted", to_emails=[event.contact.email], body=email_body, bcc=[settings.EMAIL_TARGET_VP]) email.send() if event.projection: email_bodyp = 'The event "%s" has a request for projection' % event.event_name emailp = DLEG(subject="New Event Submitted w/ Projection", to_emails=[settings.EMAIL_TARGET_HP], body=email_bodyp) emailp.send() return render(self.request, 'wizard_finished.html', {})
def done(self, form_list, **kwargs): # return HttpResponse([form.cleaned_data for form in form_list]) event = Event.event_mg.consume_workorder_formwiz(form_list, self) # return HttpResponseRedirect(reverse('events.views.my.myeventdetail',args=(event.id,))) email_body = "You have successfully submitted an event titled %s" % event.event_name email = DLEG(subject="New Event Submitted", to_emails=[event.contact.email], body=email_body, bcc=[settings.EMAIL_TARGET_VP]) email.send() if event.projection: email_bodyp = 'The event "%s" has a request for projection' % event.event_name emailp = DLEG(subject="New Event Submitted w/ Projection", to_emails=[settings.EMAIL_TARGET_HP], body=email_bodyp) emailp.send() context = RequestContext(self.request) return render(self.request, 'wizard_finished.html', context)
def snipe_checkout(request): if not settings.SNIPE_URL: return HttpResponse('This page is unavailable because SNIPE_URL is not set.', status=501) if not settings.SNIPE_API_KEY: return HttpResponse('This page is unavailable because SNIPE_API_KEY is not set.', status=501) # Get the list of users in the rental group from Snipe error_message = 'Error communicating with Snipe. Did not check out anything.' checkout_to_choices = [] response = requests.request('GET', '{}api/v1/users'.format(settings.SNIPE_URL), headers={ 'authorization': 'Bearer {}'.format(settings.SNIPE_API_KEY), }) if response.status_code == 200: try: data = json.loads(response.text) if data.get('status') == 'error': return HttpResponse(error_message, status=502) checkout_to_choices = [(user['id'], user['name']) for user in data['rows'] if 'rental' in ((group['name'] for group in user['groups']['rows']) if user['groups'] is not None else ())] except ValueError: return HttpResponse(error_message, status=502) else: return HttpResponse(error_message, status=502) # Handle the form error_message = 'Error communicating with Snipe. Some things may have been checked out while some were not. ' \ 'Please go check Snipe.' if request.method == 'POST': receipt_info = {} form = forms.SnipeCheckoutForm(checkout_to_choices, request.POST, request.FILES) if form.is_valid(): success_count_assets = 0 success_count_accessories = 0 for tag in [tag for tag in re.split('[^a-zA-Z0-9]', form.cleaned_data['asset_tags']) if tag]: match = re.match('LNLACC([0-9]+)', tag) if match: tag = match.group(1) # This tag represents an accessory response = requests.request('GET', '{}api/v1/accessories/{}'.format(settings.SNIPE_URL, tag), headers={'authorization': 'Bearer {}'.format(settings.SNIPE_API_KEY), 'accept': 'application/json'}) if response.status_code == 200: try: data = json.loads(response.text) if data.get('status') == 'error': # No accessory with that ID exists in Snipe messages.add_message(request, messages.ERROR, 'No such accessory with ID {}'.format(tag)) continue accessory_name = data['name'] rental_price = float(data['order_number']) if data['order_number'] is not None else None # Check out the accessory response = requests.request('POST', '{}api/v1/accessories/{}/checkout'.format(settings.SNIPE_URL, tag), data=json.dumps({ 'assigned_to': form.cleaned_data['checkout_to'], }), headers={ 'authorization': 'Bearer {}'.format(settings.SNIPE_API_KEY), 'accept': 'application/json', 'content-type': 'application/json', }) if response.status_code == 200: data = json.loads(response.text) if data.get('status') == 'error': # Snipe refused to check out the accessory (maybe they are all checked out) messages.add_message(request, messages.ERROR, 'Unable to check out accessory {}. Snipe says: {}'.format(tag, data['messages'])) continue # The accessory was successfully checked out success_count_accessories += 1 if tag in receipt_info: if receipt_info[tag]['name'] != accessory_name \ or receipt_info[tag]['rental_price'] != rental_price: return HttpResponse(error_message, status=502) receipt_info[tag]['quantity'] += 1 else: receipt_info[tag] = {'name': accessory_name, 'rental_price': rental_price, 'quantity': 1} else: return HttpResponse(error_message, status=502) except ValueError: return HttpResponse(error_message, status=502) else: return HttpResponse(error_message, status=502) else: # This tag represents an asset response = requests.request('GET', '{}api/v1/hardware/bytag/{}'.format(settings.SNIPE_URL, tag), headers={'authorization': 'Bearer {}'.format(settings.SNIPE_API_KEY), 'accept': 'application/json'}) if response.status_code == 200: try: data = json.loads(response.text) if data.get('status') == 'error': # The asset tag does not exist in Snipe messages.add_message(request, messages.ERROR, 'No such asset tag {}'.format(tag)) continue asset_name = data['name'] if 'custom_fields' in data and 'Rental Price' in data['custom_fields'] and \ 'value' in data['custom_fields']['Rental Price'] and data['custom_fields']['Rental Price']['value'] is not None: rental_price = float(data['custom_fields']['Rental Price']['value']) else: rental_price = None # Check out the asset response = requests.request('POST', '{}api/v1/hardware/{}/checkout'.format(settings.SNIPE_URL, data['id']), data=json.dumps({ 'checkout_to_type': 'user', 'assigned_user': form.cleaned_data['checkout_to'], }), headers={ 'authorization': 'Bearer {}'.format(settings.SNIPE_API_KEY), 'accept': 'application/json', 'content-type': 'application/json', }) if response.status_code == 200: data = json.loads(response.text) if data.get('status') == 'error': # Snipe refused to check out the asset (maybe it is already checked out) messages.add_message(request, messages.ERROR, 'Unable to check out asset {} - {}. Snipe says: {}'.format(tag, asset_name, data['messages'])) continue # The asset was successfully checked out success_count_assets += 1 if tag in receipt_info: return HttpResponse(error_message, status=502) receipt_info[tag] = {'name': asset_name, 'rental_price': rental_price, 'quantity': 1} else: return HttpResponse(error_message, status=502) except ValueError: return HttpResponse(error_message, status=502) else: return HttpResponse(error_message, status=502) if success_count_assets > 0 or success_count_accessories > 0: messages.add_message(request, messages.SUCCESS, 'Successfully checked out {} assets and {} accessories'.format(success_count_assets, success_count_accessories)) rental_prices = [(None if asset_info['rental_price'] is None else asset_info['rental_price'] * asset_info['quantity']) for asset_info in receipt_info.values()] total_rental_price = None if None in rental_prices else sum(rental_prices) checkout_to_name = next((item[1] for item in checkout_to_choices if item[0] == form.cleaned_data['checkout_to'])) # Before returning the response, email a PDF receipt html = render_to_string('pdf_templates/inventory-receipt.html', request=request, context={ 'title': 'Checkout Receipt', 'receipt_info': receipt_info, 'num_assets': success_count_assets, 'num_accessories': success_count_accessories, 'total_rental_price': total_rental_price, 'checkout_to': checkout_to_name, }) pdf_file = BytesIO() pisa.CreatePDF(html, dest=pdf_file, link_callback=link_callback) pdf_handle = pdf_file.getvalue() filename = 'LNL-checkout-receipt-{}.pdf'.format(timezone.now().isoformat()) attachments = [{'file_handle': pdf_handle, 'name': filename}] email = DefaultLNLEmailGenerator(subject='LNL Inventory Checkout Receipt', attachments=attachments, to_emails=(request.user.email, settings.DEFAULT_TO_ADDR), body='A receipt for the rental checkout by {} to {} is ' 'attached.'.format(request.user, checkout_to_name)) email.send() # Return the response return render(request, 'inventory/checkout_receipt.html', { 'receipt_info': receipt_info, 'num_assets': success_count_assets, 'num_accessories': success_count_accessories, 'total_rental_price': total_rental_price, 'checkout_to': form.cleaned_data['checkout_to'], 'checkout_to_name': checkout_to_name, }) else: form = forms.SnipeCheckoutForm(checkout_to_choices, initial={'checkout_to': form.cleaned_data['checkout_to']}) else: if 'checkout_to' in request.GET: form = forms.SnipeCheckoutForm(checkout_to_choices, initial={'checkout_to': request.GET['checkout_to']}) else: form = forms.SnipeCheckoutForm(checkout_to_choices) return render(request, "form_crispy.html", { 'msg': 'Inventory checkout', 'form': form, })
def approval(request, id): context = {} context['msg'] = "Approve Event" event = get_object_or_404(BaseEvent, pk=id) if not request.user.has_perm('events.approve_event', event): raise PermissionDenied if event.closed: messages.add_message(request, messages.ERROR, 'Event is closed.') return HttpResponseRedirect(reverse('events:detail', args=(event.id,))) if event.approved: messages.add_message(request, messages.INFO, 'Event has already been approved!') return HttpResponseRedirect(reverse('events:detail', args=(event.id,))) is_event2019 = isinstance(event, Event2019) context['is_event2019'] = is_event2019 if is_event2019: mk_serviceinstance_formset = inlineformset_factory(BaseEvent, ServiceInstance, extra=3, exclude=[]) mk_serviceinstance_formset.form = curry_class(ServiceInstanceForm, event=event) if request.method == 'POST': form = EventApprovalForm(request.POST, instance=event) if is_event2019: services_formset = mk_serviceinstance_formset(request.POST, request.FILES, instance=event) if form.is_valid() and (not is_event2019 or services_formset.is_valid()): set_revision_comment("Approved", form) e = form.save(commit=False) e.approved = True e.approved_on = timezone.now() e.approved_by = request.user e.save() if is_event2019: services_formset.save() # confirm with user messages.add_message(request, messages.INFO, 'Approved Event') if e.contact and e.contact.email: email_body = 'Your event "%s" has been approved!' % event.event_name email = DLEG(subject="Event Approved", to_emails=[e.contact.email], body=email_body, bcc=[settings.EMAIL_TARGET_VP]) email.send() else: messages.add_message(request, messages.INFO, 'No contact info on file for approval. Please give them the good news!') return HttpResponseRedirect(reverse('events:detail', args=(e.id,))) else: context['form'] = form if is_event2019: context['services_formset'] = services_formset else: # has a bill, but no paid bills, and is not otherwise closed unbilled_events = Event.objects.filter(org__in=event.org.all())\ .exclude(billings__date_paid__isnull=False)\ .filter(billings__date_billed__isnull=False)\ .filter(closed=False)\ .filter(cancelled=False)\ .filter(test_event=False)\ .distinct() unbilled_events = map(str, unbilled_events) if event.org.exists() and unbilled_events: messages.add_message(request, messages.WARNING, "Organization has unbilled events: %s" % ", ".join(unbilled_events)) for org in event.org.filter(delinquent=True): messages.add_message(request, messages.WARNING, "The client '%s' has been marked as delinquent. \ This means that the client has one or more long-outstanding bills which they should be required to \ pay before you approve this event." % org) context['form'] = EventApprovalForm(instance=event) if is_event2019: context['services_formset'] = mk_serviceinstance_formset(instance=event) return render(request, 'form_crispy_approval.html', context)