def remind_empty_submissions(self, whatstr, conference):
        # Get all sessions with empty abstract (they forgot to hit save), if they have not been touched in
        # 3 days (this will also make the reminder show up every 3 days, and not every day, since we touch
        # the lastmodified timestemp when a reminder is sent).

        for sess in conference.conferencesession_set.filter(
                abstract='',
                status=0,
                lastmodified__lt=timezone.now() - timedelta(days=3)):
            for spk in sess.speaker.all():
                send_conference_mail(
                    conference,
                    spk.email,
                    "Your submission".format(conference),
                    'confreg/mail/speaker_empty_submission.txt',
                    {
                        'conference': conference,
                        'session': sess,
                    },
                    receivername=spk.name,
                )
                whatstr.write(
                    "Reminded speaker {0} that they have made an empty submission\n"
                    .format(spk.name))
            sess.lastmodified = timezone.now()
            sess.save()
    def remind_empty_speakers(self, whatstr, conference):
        # Get all the speakers with an active submission to this conference
        # but no bio included, if they have not been touched in  3 days.

        speakers = Speaker.objects.filter(
            conferencesession__conference=conference,
            conferencesession__status=0,
            lastmodified__lt=timezone.now() - timedelta(days=3),
            abstract='',
        ).distinct()

        for spk in speakers:
            send_conference_mail(
                conference,
                spk.email,
                "Your submission".format(conference),
                'confreg/mail/speaker_empty_profile.txt',
                {
                    'conference': conference,
                    'speaker': spk,
                },
                receivername=spk.name,
            )
            spk.lastmodified = timezone.now()
            spk.save()
            whatstr.write(
                "Reminded speaker {0} that their profile is empty\n".format(
                    spk.name))
    def remind_unregistered_speakers(self, whatstr, conference):
        # Get speakers that are approved but not registered
        speakers = list(
            Speaker.objects.raw(
                "SELECT s.* FROM confreg_speaker s WHERE EXISTS (SELECT 1 FROM confreg_conferencesession sess INNER JOIN confreg_conferencesession_speaker css ON css.conferencesession_id=sess.id WHERE sess.conference_id=%s AND css.speaker_id=s.id AND sess.status=1 and sess.lastnotifiedstatus=1 AND sess.lastnotifiedtime<%s) AND NOT EXISTS (SELECT 1 FROM confreg_conferenceregistration r WHERE r.conference_id=%s AND r.attendee_id=s.user_id AND r.payconfirmedat IS NOT NULL AND r.canceledat IS NULL)",
                [
                    conference.id,
                    timezone.now() - timedelta(days=7), conference.id
                ]))
        if speakers:
            whatstr.write("Found {0} unregistered speakers:\n".format(
                len(speakers)))
            for speaker in speakers:
                # Update the last notified date on all sessions that are in
                # status approved, to make sure we don't send a second
                # reminder tomorrow.
                ConferenceSession.objects.filter(
                    conference=conference, speaker=speaker,
                    status=1).update(lastnotifiedtime=timezone.now())

                send_conference_mail(
                    conference,
                    speaker.user.email,
                    "Your registration".format(conference),
                    'confreg/mail/speaker_remind_register.txt',
                    {
                        'conference': conference,
                    },
                    receivername=speaker.fullname,
                )

                whatstr.write(
                    "Reminded speaker {0} to register\n".format(speaker))

            whatstr.write("\n\n")
    def remind_pending_speakers(self, whatstr, conference):
        # Remind speakers that are in pending status. But only the ones
        # where we've actually sent the status emails, meaning the
        # lastsent is the same as the current.
        speakers = Speaker.objects.filter(conferencesession__conference=conference,
                                          conferencesession__status=3,
                                          conferencesession__lastnotifiedstatus=3,
                                          conferencesession__lastnotifiedtime__lt=datetime.now() - timedelta(days=7)).distinct()
        if speakers:
            whatstr.write("Found {0} unconfirmed talks:\n".format(len(speakers)))

            for speaker in speakers:
                sessions = speaker.conferencesession_set.filter(conference=conference, status=3)
                for s in sessions:
                    s.lastnotifiedtime = datetime.now()
                    s.save()

                send_conference_mail(conference,
                                     speaker.user.email,
                                     "Your submissions".format(conference),
                                     'confreg/mail/speaker_remind_confirm.txt',
                                     {
                                         'conference': conference,
                                         'sessions': sessions,
                                     },
                                     receivername=speaker.fullname,
                )

                whatstr.write("Reminded speaker {0} to confirm {1} talks\n".format(speaker, len(sessions)))

            whatstr.write("\n\n")
    def process_invoice_payment(self, invoice):
        try:
            pv = PurchasedVoucher.objects.get(pk=invoice.processorid)
        except PurchasedVoucher.DoesNotExist:
            raise Exception("Could not find voucher order %s" %
                            invoice.processorid)

        if pv.batch:
            raise Exception(
                "This voucher order has already been processed: %s" %
                invoice.processorid)

        # Set up the batch
        batch = PrepaidBatch(conference=pv.conference,
                             regtype=pv.regtype,
                             buyer=pv.user,
                             buyername="{0} {1}".format(
                                 pv.user.first_name, pv.user.last_name),
                             sponsor=pv.sponsor)
        batch.save()

        for n in range(0, pv.num):
            v = PrepaidVoucher(conference=pv.conference,
                               vouchervalue=base64.b64encode(
                                   os.urandom(37)).rstrip(b'=').decode('utf8'),
                               batch=batch)
            v.save()

        pv.batch = batch
        pv.save()

        if pv.sponsor:
            send_conference_sponsor_notification(
                pv.conference,
                "Sponsor %s purchased vouchers" % pv.sponsor.name,
                "The sponsor\n%s\nhas purchased %s vouchers of type \"%s\".\n\n"
                % (pv.sponsor.name, pv.num, pv.regtype.regtype),
            )
        else:
            # For non-sponsors, there is no dashboard available, so we send the actual vouchers in an
            # email directly.
            send_conference_mail(
                pv.conference,
                pv.batch.buyer.email,
                "Entry vouchers to {}".format(pv.conference.conferencename),
                'confreg/mail/prepaid_vouchers.txt',
                {
                    'batch': batch,
                    'vouchers': batch.prepaidvoucher_set.all(),
                    'conference': pv.conference,
                },
                sender=pv.conference.contactaddr,
            )
示例#6
0
    def handle(self, *args, **options):
        # Any entries that actually have an invoice will be canceled by the invoice
        # system, as the expiry time of the invoice is set synchronized. In this
        # run, we only care about offers that have not been picked up at all.
        wlentries = RegistrationWaitlistEntry.objects.filter(
            registration__payconfirmedat__isnull=True,
            registration__invoice__isnull=True,
            offerexpires__lt=datetime.now())

        for w in wlentries:
            reg = w.registration

            # Create a history entry so we know exactly when it happened
            RegistrationWaitlistHistory(waitlist=w,
                                        text="Offer expired at {0}".format(
                                            w.offerexpires)).save()

            # Notify conference organizers
            send_simple_mail(
                reg.conference.notifyaddr,
                reg.conference.notifyaddr,
                'Waitlist expired',
                'User {0} {1} <{2}> did not complete the registration before the waitlist offer expired.'
                .format(reg.firstname, reg.lastname, reg.email),
                sendername=reg.conference.conferencename)

            # Also send an email to the user
            send_conference_mail(
                reg.conference,
                reg.email,
                'Your waitlist offer has expired',
                'confreg/mail/waitlist_expired.txt',
                {
                    'conference': reg.conference,
                    'reg': reg,
                    'offerexpires': w.offerexpires,
                },
                receivername=reg.fullname,
            )

            # Now actually expire the offer
            w.offeredon = None
            w.offerexpires = None
            # Move the user to the back of the waitlist (we have a history entry for the
            # initial registration date, so it's still around)
            w.enteredon = datetime.now()

            w.save()
    def remind_pending_multiregs(self, whatstr, conference):
        # Reminde owners of "multiregs" that have not been completed. Basic rules
        # are the same as remind_pending_registrations(), but we only consider
        # those that are managed by somebody else.
        regs = ConferenceRegistration.objects.filter(
            conference=conference,
            conference__active=True,
            conference__enddate__gt=timezone.now(),
            attendee__isnull=True,
            registrator__isnull=False,
            payconfirmedat__isnull=True,
            invoice__isnull=True,
            bulkpayment__isnull=True,
            registrationwaitlistentry__isnull=True,
            created__lt=timezone.now() - timedelta(days=5),
            lastmodified__lt=timezone.now() - timedelta(days=5))

        if regs:
            multiregs = set([r.registrator for r in regs])

            whatstr.write(
                "Found {0} unconfirmed multiregistrations that are stalled:\n".
                format(len(multiregs)))

            for r in multiregs:
                send_conference_mail(
                    conference,
                    r.email,
                    "Your registrations".format(conference),
                    'confreg/mail/multireg_stalled_registration.txt',
                    {
                        'conference': conference,
                        'registrator': r,
                    },
                    receivername="{0} {1}".format(r.first_name, r.last_name),
                )

                whatstr.write(
                    "Reminded user {0} ({1}) that their multi-registration is not confirmed\n"
                    .format(r.username, r.email))

            whatstr.write("\n\n")

            # Separately mark each part of the multireg as touched
            for reg in regs:
                reg.lastmodified = timezone.now()
                reg.save()
示例#8
0
    def save_form(self, form, claim, request):
        if int(form.cleaned_data['vouchercount']) == 0:
            # No vouchers --> unclaim this benefit
            claim.claimdata = "0"
            claim.declined = True
            claim.confirmed = True
        else:
            # Actual number, form has been validated, so create the vouchers.
            batch = PrepaidBatch(
                conference=self.level.conference,
                regtype=RegistrationType.objects.get(
                    conference=self.level.conference,
                    regtype=self.params['type']),
                buyer=request.user,
                buyername="%s %s" %
                (request.user.first_name, request.user.last_name),
                sponsor=claim.sponsor)
            batch.save()
            vouchers = []
            for n in range(0, int(form.cleaned_data['vouchercount'])):
                v = PrepaidVoucher(
                    conference=self.level.conference,
                    vouchervalue=base64.b64encode(
                        os.urandom(37)).rstrip(b'=').decode('utf8'),
                    batch=batch)
                v.save()
                vouchers.append(v)

            # Send an email about the new vouchers
            send_conference_mail(
                self.level.conference,
                request.user.email,
                "Entry vouchers",
                'confreg/mail/prepaid_vouchers.txt',
                {
                    'batch': batch,
                    'vouchers': vouchers,
                    'conference': self.level.conference,
                },
                sender=self.level.conference.sponsoraddr,
            )

            # Finally, finish the claim
            claim.claimdata = batch.id
            claim.confirmed = True  # Always confirmed, they're generated after all
        return True
    def remind_pending_registrations(self, whatstr, conference):
        # Get registrations made which have no invoice, no bulk registration,
        # and are not completed. We look at registrations created more than 5
        # days ago and also unmodified for 5 days. This is intentionally not 7
        # days in order to "rotate the day of week" the reminders go out on.
        # Only send reminders if attendee has a value, meaning we don't send
        # reminders to registrations that are managed by somebody else.
        regs = ConferenceRegistration.objects.filter(
            conference=conference,
            conference__active=True,
            conference__enddate__gt=timezone.now(),
            attendee__isnull=False,
            payconfirmedat__isnull=True,
            invoice__isnull=True,
            bulkpayment__isnull=True,
            registrationwaitlistentry__isnull=True,
            created__lt=timezone.now() - timedelta(days=5),
            lastmodified__lt=timezone.now() - timedelta(days=5))

        if regs:
            whatstr.write(
                "Found {0} unconfirmed registrations that are stalled:\n".
                format(len(regs)))
            for reg in regs:
                send_conference_mail(
                    conference,
                    reg.email,
                    "Your registration".format(conference),
                    'confreg/mail/attendee_stalled_registration.txt',
                    {
                        'conference': conference,
                        'reg': reg,
                    },
                    receivername=reg.fullname,
                )
                reg.lastmodified = timezone.now()
                reg.save()

                whatstr.write(
                    "Reminded attendee {0} that their registration is not confirmed\n"
                    .format(reg.fullname))

            whatstr.write("\n\n")
示例#10
0
def confirm_sponsor(sponsor, who):
    # Confirm a sponsor, including sending the confirmation email.
    # This will save the specified sponsor model as well, but the function
    # expects to be wrapped in external transaction handler.
    sponsor.confirmed = True
    sponsor.confirmedat = timezone.now()
    sponsor.confirmedby = who
    sponsor.save()

    for manager in sponsor.managers.all():
        send_conference_mail(sponsor.conference,
                             manager.email,
                             "Sponsorship confirmed",
                             'confsponsor/mail/sponsor_confirmed.txt', {
                                 'sponsor': sponsor,
                                 'conference': sponsor.conference,
                             },
                             sender=sponsor.conference.sponsoraddr,
                             receivername='{0} {1}'.format(
                                 manager.first_name, manager.last_name))
示例#11
0
    def handle(self, *args, **options):
        # We're always going to process all conferences, since most will not have any
        # open discount codes.
        filt = Q(sponsor__isnull=False, is_invoiced=False) & (
            Q(validuntil__lte=today_global()) | Q(num_uses__gte=F('maxuses')))
        codes = DiscountCode.objects.annotate(
            num_uses=Count('registrations')).filter(filt)
        for code in codes:
            # Either the code has expired, or it is fully used by now. Time to generate the invoice. We'll also
            # send an email to the sponsor (and the admins) to inform them of what's happening.
            # The invoice will be a one-off one, we don't need a registered manager for it since the
            # discounts have already been given out.

            if code.count == 0:
                # In case there is not a single user, we just notify the user of this and set it to
                # invoiced in the system so we don't try again.
                code.is_invoiced = True
                code.save()
                send_conference_sponsor_notification(
                    code.conference,
                    "[{0}] Discount code expired".format(code.conference),
                    "Discount code {0} has expired without any uses.".format(
                        code.code),
                )

                for manager in code.sponsor.managers.all():
                    send_conference_mail(
                        code.conference,
                        manager.email,
                        "Discount code {0} expired".format(code.code),
                        'confsponsor/mail/discount_expired.txt', {
                            'code': code,
                            'sponsor': code.sponsor,
                            'conference': code.conference,
                        },
                        sender=code.conference.sponsoraddr,
                        receivername='{0} {1}'.format(manager.first_name,
                                                      manager.last_name))
            else:
                # At least one use, so we generate the invoice
                invoicerows = []
                for r in code.registrations.all():
                    if code.discountamount:
                        # Fixed amount discount. Always apply
                        discountvalue = code.discountamount
                    else:
                        # Percentage discount, so we need to calculate it. Ordered discount codes will
                        # only support a registration-only style discount code, so only count it
                        # against that.
                        discountvalue = r.regtype.cost * code.discountpercentage / 100
                    invoicerows.append([
                        'Attendee "{0}"'.format(r.fullname), 1, discountvalue,
                        r.conference.vat_registrations
                    ])
                # All invoices are always due immediately
                manager = InvoiceManager()
                code.invoice = manager.create_invoice(
                    code.sponsor_rep,
                    code.sponsor_rep.email,
                    "{0} {1}".format(code.sponsor_rep.first_name,
                                     code.sponsor_rep.last_name),
                    '%s\n%s' % (code.sponsor.name, code.sponsor.invoiceaddr),
                    '{0} discount code {1}'.format(code.conference, code.code),
                    timezone.now(),
                    timezone.now() + timedelta(days=1),
                    invoicerows,
                    accounting_account=settings.ACCOUNTING_CONFREG_ACCOUNT,
                    accounting_object=code.conference.accounting_object,
                    paymentmethods=code.conference.paymentmethods.all(),
                )
                code.invoice.save()
                code.is_invoiced = True
                code.save()

                wrapper = InvoiceWrapper(code.invoice)
                wrapper.email_invoice()

                # Now also fire off emails, both to the admins and to all the managers of the sponsor
                # (so they know where the invoice was sent).
                send_conference_sponsor_notification(
                    code.conference,
                    "[{0}] Discount code {1} has been invoiced".format(
                        code.conference, code.code),
                    "The discount code {0} has been closed,\nand an invoice has been sent to {1}.\n\nA total of {2} registrations used this code, and the total amount was {3}.\n"
                    .format(
                        code.code,
                        code.sponsor,
                        len(invoicerows),
                        code.invoice.total_amount,
                    ),
                )

                for manager in code.sponsor.managers.all():
                    send_conference_mail(
                        code.conference,
                        manager.email,
                        "Discount code {0} has been invoiced".format(
                            code.code),
                        'confsponsor/mail/discount_invoiced.txt', {
                            'code': code,
                            'conference': code.conference,
                            'sponsor': code.sponsor,
                            'invoice': code.invoice,
                            'curr': settings.CURRENCY_ABBREV,
                            'expired_time': code.validuntil < today_global(),
                        },
                        sender=code.conference.sponsoraddr,
                        receivername='{0} {1}'.format(manager.first_name,
                                                      manager.last_name))
示例#12
0
def sponsor_scanning(request, sponsorid):
    sponsor, is_admin = _get_sponsor_and_admin(sponsorid, request, False)

    if not sponsor.conference.askbadgescan:
        return HttpResponse(
            "Badge scanning questions are not enabled on this conference",
            status=403)

    if not SponsorClaimedBenefit.objects.filter(
            sponsor=sponsor,
            benefit__benefit_class=get_benefit_id(
                'badgescanning.BadgeScanning'),
            declined=False,
            confirmed=True).exists():
        return HttpResponse(
            "Badge scanning not a claimed benefit for this sponsor",
            status=403)

    if request.method == 'POST':
        if request.POST.get('what', '') == 'add':
            if not request.POST.get('email', ''):
                messages.warning(request, "Cannot add empty address")
                return HttpResponseRedirect(".")
            try:
                reg = ConferenceRegistration.objects.get(
                    conference=sponsor.conference,
                    email=request.POST.get('email').lower())
                if not reg.payconfirmedat:
                    messages.error(request, "Attendee is not confirmed")
                    return HttpResponseRedirect(".")
                if sponsor.sponsorscanner_set.filter(scanner=reg).exists():
                    messages.warning(
                        request, "Attendee already registered as a scanner")
                    return HttpResponseRedirect(".")
                scanner = SponsorScanner(sponsor=sponsor,
                                         scanner=reg,
                                         token=generate_random_token())
                scanner.save()
                sponsor.sponsorscanner_set.add(scanner)
                return HttpResponseRedirect(".")
            except ConferenceRegistration.DoesNotExist:
                messages.error(request, "Attendee not found")
                return HttpResponseRedirect(".")
        elif request.POST.get('what', '') == 'del':
            # There should only be one remove-<something>
            for k in request.POST.keys():
                if k.startswith('remove-'):
                    rid = k[len('remove-'):]
                    try:
                        scanner = SponsorScanner.objects.get(sponsor=sponsor,
                                                             pk=rid)
                        n = scanner.scanner.fullname
                        if scanner.scanner.scanned_attendees.exists():
                            messages.warning(
                                request,
                                "Attende {0} has scanned badges already, cannot be removed"
                                .format(n))
                        else:
                            scanner.delete()
                            messages.info(
                                request,
                                "Attendee {0} removed from scanning".format(n))
                    except SponsorScanner.DoesNotExist:
                        messges.error(request, "Attendee not found")
                    return HttpResponseRedirect(".")
                elif k.startswith('email-'):
                    rid = k[len('email-'):]
                    try:
                        scanner = SponsorScanner.objects.get(sponsor=sponsor,
                                                             pk=rid)
                        send_conference_mail(
                            sponsor.conference,
                            scanner.scanner.email,
                            "Attendee badge scanning",
                            "confsponsor/mail/badge_scanning_intro.txt",
                            {
                                'conference': sponsor.conference,
                                'sponsor': sponsor,
                                'scanner': scanner,
                            },
                            sender=sponsor.conference.sponsoraddr,
                            receivername=scanner.scanner.fullname,
                        )
                        messages.info(
                            request, "Instructions email sent to {0}".format(
                                scanner.scanner.fullname))
                    except SponsorScanner.DoesNotExist:
                        messages.error(request, "Attendee not found")
                    return HttpResponseRedirect(".")
            else:
                messages.error(request, "Invalid form submit")
                return HttpResponseRedirect(".")
        elif request.POST.get('what', '') == 'delscan':
            # There should only be one delete-scan-<id>
            for k in request.POST.keys():
                if k.startswith('delete-scan-'):
                    scid = int(k[len('delete-scan-'):])
                    try:
                        scan = ScannedAttendee.objects.get(sponsor=sponsor,
                                                           pk=scid)
                        scan.delete()
                    except ScannedAttendee.DoesNotExist:
                        messages.error(
                            request,
                            "Scan has already been removed or permission denied"
                        )
                    break
            else:
                messages.error(request, "Invalid form submit")
            return HttpResponseRedirect(".")
        else:
            # Unknown form, so just return
            return HttpResponseRedirect(".")

    scanned = ScannedAttendee.objects.select_related(
        'attendee', 'scannedby', 'attendee__country').filter(sponsor=sponsor)

    return render(request, 'confsponsor/sponsor_scanning.html', {
        'scanners': sponsor.sponsorscanner_set.all(),
        'scanned': scanned,
    })