Example #1
0
    def availableDurations(self):
        '''
        A lesson can always be booked for the length of a single slot, but this method
        checks if multiple slots are available.  This method requires that slots are
        non-overlapping, which needs to be enforced on slot save.
        '''
        potential_slots = InstructorAvailabilitySlot.objects.filter(
            instructor=self.instructor,
            location=self.location,
            room=self.room,
            pricingTier=self.pricingTier,
            startTime__gte=self.startTime,
            startTime__lte=self.startTime + timedelta(minutes=getConstant('privateLessons__maximumLessonLength')),
        ).exclude(id=self.id).order_by('startTime')

        duration_list = [self.duration,]
        last_start = self.startTime
        last_duration = self.duration
        max_duration = self.duration

        for slot in potential_slots:
            if max_duration + slot.duration > getConstant('privateLessons__maximumLessonLength'):
                break
            if (
                slot.startTime == last_start + timedelta(minutes=last_duration) and
                slot.isAvailable
            ):
                duration_list.append(max_duration + slot.duration)
                last_start = slot.startTime
                last_duration = slot.duration
                max_duration += slot.duration

        return duration_list
Example #2
0
def createReferrerVoucher(customer):
    voucherId = generateUniqueVoucherId(
        getConstant('referrals__voucherPrefix'))
    category = getConstant('referrals__referrerCategory')
    originalAmount = 0
    maxAmountPerUse = None
    singleUse = False
    forFirstTimeCustomersOnly = False
    expirationDate = None
    disabled = False
    name = _("Referral Bonus for %s, %s" % (customer.fullName, customer.email))

    voucher = Voucher(voucherId=voucherId,
                      name=name,
                      category=category,
                      originalAmount=originalAmount,
                      maxAmountPerUse=maxAmountPerUse,
                      singleUse=singleUse,
                      forFirstTimeCustomersOnly=forFirstTimeCustomersOnly,
                      expirationDate=expirationDate,
                      disabled=disabled)
    voucher.save()

    cv = CustomerVoucher(customer=customer, voucher=voucher)
    cv.save()

    return voucher
Example #3
0
def createReferrerVoucher(customer):
    voucherId = generateUniqueVoucherId(getConstant('referrals__voucherPrefix'))
    category = getConstant('referrals__referrerCategory')
    originalAmount = 0
    maxAmountPerUse = None
    singleUse = False
    forFirstTimeCustomersOnly = False
    expirationDate = None
    disabled = False
    name = _("Referral Bonus for %s, %s" % (customer.fullName,customer.email))

    voucher = Voucher(
        voucherId=voucherId,name=name,
        category=category,
        originalAmount=originalAmount,
        maxAmountPerUse=maxAmountPerUse,
        singleUse=singleUse,
        forFirstTimeCustomersOnly=forFirstTimeCustomersOnly,
        expirationDate=expirationDate,
        disabled=disabled
    )
    voucher.save()

    cv = CustomerVoucher(customer=customer,voucher=voucher)
    cv.save()

    return voucher
Example #4
0
def createReferreeVoucher(name, amountPerUse):
    voucherId = generateUniqueVoucherId(
        getConstant('referrals__voucherPrefix'))
    category = getConstant('referrals__refereeCategory')
    originalAmount = 1e9
    maxAmountPerUse = amountPerUse
    singleUse = False
    forFirstTimeCustomersOnly = True
    expirationDate = None
    disabled = False

    voucher = Voucher(voucherId=voucherId,
                      name=name,
                      category=category,
                      originalAmount=originalAmount,
                      maxAmountPerUse=maxAmountPerUse,
                      singleUse=singleUse,
                      forFirstTimeCustomersOnly=forFirstTimeCustomersOnly,
                      expirationDate=expirationDate,
                      disabled=disabled)
    voucher.save()

    # Find all beginner classes
    dts = DanceTypeLevel.objects.filter(name="Beginner",
                                        danceType__name="Lindy Hop")
    classes = ClassDescription.objects.filter(danceTypeLevel=dts.first())
    for c in classes:
        cv = ClassVoucher(voucher=voucher, classDescription=c)
        cv.save()
    return voucher
Example #5
0
def ensureReferralVouchersExist(customer):
    # is there a referral voucher for this person?
    # Find all CustomerVouchers for this person
    vrd = referralVoucherExists(customer)

    referreeDiscount = getConstant('referrals__refereeDiscount')
    referrerDiscount = getConstant('referrals__referrerDiscount')

    if vrd:
        vrd.amount = referrerDiscount
        vrd.save()

        vrd.referreeVoucher.maxAmountPerUse = referreeDiscount
        vrd.referreeVoucher.save()
    else:
        name = _('Referral: %s' % customer.fullName)

        # create the referree voucher
        referreeVoucher = createReferreeVoucher(name, referreeDiscount)

        # create the referrer voucher
        referrerVoucher = createReferrerVoucher(customer)

        # create the thing that ties them together
        vrd = VoucherReferralDiscount.objects.get_or_create(
            referrerVoucher=referrerVoucher,
            referreeVoucher=referreeVoucher,
            referrerBonus=referrerDiscount)

    return vrd
Example #6
0
def createReferreeVoucher(name,amountPerUse):
    voucherId = generateUniqueVoucherId(getConstant('referrals__voucherPrefix'))
    category = getConstant('referrals__refereeCategory')
    originalAmount = 1e9
    maxAmountPerUse = amountPerUse
    singleUse = False
    forFirstTimeCustomersOnly = True
    expirationDate = None
    disabled = False

    voucher = Voucher(
        voucherId=voucherId,name=name,
        category=category,
        originalAmount=originalAmount,
        maxAmountPerUse=maxAmountPerUse,
        singleUse=singleUse,
        forFirstTimeCustomersOnly=forFirstTimeCustomersOnly,
        expirationDate=expirationDate,
        disabled=disabled
    )
    voucher.save()

    # Find all beginner classes
    dts = DanceTypeLevel.objects.filter(name="Beginner",danceType__name="Lindy Hop")
    classes = ClassDescription.objects.filter(danceTypeLevel=dts.first())
    for c in classes:
        cv = ClassVoucher(voucher=voucher,classDescription=c)
        cv.save()
    return voucher
Example #7
0
    def availableDurations(self):
        '''
        A lesson can always be booked for the length of a single slot, but this method
        checks if multiple slots are available.  This method requires that slots are
        non-overlapping, which needs to be enforced on slot save.
        '''
        potential_slots = InstructorAvailabilitySlot.objects.filter(
            instructor=self.instructor,
            location=self.location,
            room=self.room,
            pricingTier=self.pricingTier,
            startTime__gte=self.startTime,
            startTime__lte=self.startTime + timedelta(
                minutes=getConstant('privateLessons__maximumLessonLength')),
        ).exclude(id=self.id).order_by('startTime')

        duration_list = [
            self.duration,
        ]
        last_start = self.startTime
        last_duration = self.duration
        max_duration = self.duration

        for slot in potential_slots:
            if max_duration + slot.duration > getConstant(
                    'privateLessons__maximumLessonLength'):
                break
            if (slot.startTime == last_start + timedelta(minutes=last_duration)
                    and slot.isAvailable):
                duration_list.append(max_duration + slot.duration)
                last_start = slot.startTime
                last_duration = slot.duration
                max_duration += slot.duration

        return duration_list
Example #8
0
        def revenueMismatch(self):
            comparison = self.revenueReported + self.revenueRefundsReported
            if not getConstant('registration__buyerPaysProcessingFees'):
                comparison += self.feesReported
            if not getConstant('registration__buyerPaysSalesTax'):
                comparison += self.taxesReported

            return round(self.total, 2) != round(comparison, 2)
Example #9
0
 def title(self, obj):
     if not obj:
         return _('%s Events Calendar' %
                  getConstant('contact__businessName'))
     else:
         this_instructor = self.get_member(obj)
         return _('%s Staff Calendar for %s' %
                  (getConstant('contact__businessName'),
                   this_instructor.fullName))
Example #10
0
def provideCustomerReferralCode(sender, **kwargs):
    '''
    If the vouchers app is installed and referrals are enabled, then the customer's profile page can show their voucher referral code.
    '''
    customer = kwargs.pop('customer')
    if getConstant('vouchers__enableVouchers') and getConstant(
            'referrals__enableReferralProgram'):
        vrd = ensureReferralVouchersExist(customer)

        return {'referralVoucherId': vrd.referreeVoucher.voucherId}
Example #11
0
 def __str__(self):
     if self.accrualDate:
         return '%s %s: %s = %s%s' % (
             self.category.name,
             self.accrualDate.strftime('%B %Y'), self.description,
             getConstant('general__currencySymbol'), self.total)
     else:
         return '%s: %s = %s%s' % (self.category.name, self.description,
                                   getConstant('general__currencySymbol'),
                                   self.total)
Example #12
0
def provideCustomerReferralCode(sender,**kwargs):
    '''
    If the vouchers app is installed and referrals are enabled, then the customer's profile page can show their voucher referral code.
    '''
    customer = kwargs.pop('customer')
    if getConstant('vouchers__enableVouchers') and getConstant('referrals__enableReferralProgram'):
        vrd = ensureReferralVouchersExist(customer)

        return {
            'referralVoucherId': vrd.referreeVoucher.voucherId
        }
Example #13
0
    def render(self, context, instance, placeholder):
        ''' Add the cart-specific context to this form '''
        context = super(StripePaymentFormPlugin, self).render(context, instance, placeholder)

        context.update({
            'stripe_key': getattr(settings,'STRIPE_PUBLIC_KEY',''),
            'business_name': getConstant('contact__businessName'),
            'currencyCode': getConstant('general__currencyCode'),
        })

        return context
Example #14
0
    def render(self, context, instance, placeholder):
        ''' Create a UUID and check if a voucher with that ID exists before rendering '''
        context = super(StripeGiftCertificateFormPlugin, self).render(context, instance, placeholder)

        context.update({
            'stripe_key': getattr(settings,'STRIPE_PUBLIC_KEY',''),
            'business_name': getConstant('contact__businessName'),
            'currencyCode': getConstant('general__currencyCode'),
        })

        return context
Example #15
0
def checkRequirements(sender,**kwargs):
    '''
    Check that the customer meets all prerequisites for the items in the registration.
    '''

    if not getConstant('requirements__enableRequirements'):
        return

    logger.debug('Signal to check RegistrationContactForm handled by prerequisites app.')

    formData = kwargs.get('formData',{})
    first = formData.get('firstName')
    last = formData.get('lastName')
    email = formData.get('email')

    request = kwargs.get('request',{})
    registration = kwargs.get('registration',None)

    customer = Customer.objects.filter(
        first_name=first,
        last_name=last,
        email=email).first()

    requirement_warnings = []
    requirement_errors = []

    for ter in registration.temporaryeventregistration_set.all():
        if hasattr(ter.event,'getRequirements'):
            for req in ter.event.getRequirements():
                if not req.customerMeetsRequirement(
                    customer=customer,
                    danceRole=ter.role
                ):
                    if req.enforcementMethod == Requirement.EnforcementChoice.error:
                        requirement_errors.append((ter.event.name, req.name))
                    if req.enforcementMethod == Requirement.EnforcementChoice.warning:
                        requirement_warnings.append((ter.event.name,req.name))

    if requirement_errors:
        raise ValidationError(format_html(
            '<p>{}</p> <ul>{}</ul> <p>{}</p>',
            ugettext('Unfortunately, you do not meet the following requirements/prerequisites for the items you have chosen:\n'),
            mark_safe(''.join(['<li><em>%s:</em> %s</li>\n' % x for x in requirement_errors])),
            getConstant('requirements__errorMessage') or '',
        ))

    if requirement_warnings:
        messages.warning(request,format_html(
            '<p>{}</p> <ul>{}</ul> <p>{}</p>',
            mark_safe(ugettext('<strong>Please Note:</strong> It appears that you do not meet the following requirements/prerequisites for the items you have chosen:\n')),
            mark_safe(''.join(['<li><em>%s:</em> %s</li>\n' % x for x in requirement_warnings])),
            getConstant('requirements__warningMessage') or '',
        ))
Example #16
0
    def render(self, context, instance, placeholder):
        ''' Add the cart-specific context to this form '''
        context = super(PayAtDoorFormPlugin,
                        self).render(context, instance, placeholder)

        context.update({
            'business_name': getConstant('contact__businessName'),
            'currencyCode': getConstant('general__currencyCode'),
            'form': self.get_form(context, instance, placeholder),
        })

        return context
Example #17
0
    def refund(self, amount=None):
        saleIds = self.getSaleIds()
        refundData = []

        leftToRefund = amount or 0
        for this_id in saleIds:
            # No need to continue if the full amount requested has been refunded
            if amount is not None and leftToRefund <= 0:
                break

            this_sale = Sale.find(this_id)

            if amount is not None:
                this_amount = min(float(this_sale.amount.total), leftToRefund)

                refund = this_sale.refund({
                    'amount': {
                        'total': '{0:.2f}'.format(this_amount),
                        'currency': getConstant('general__currencyCode'),
                    }
                })
            else:
                refund = this_sale.refund()

            if refund.success():
                logger.info('Refund successfully processed.')

                refundData.append({
                    'status':
                    'success',
                    'refund_id':
                    refund.id,
                    'sale_id':
                    refund.sale_id,
                    'refundAmount':
                    float(refund.amount.total),

                    # This is (annoyingly) hard-coded for now because the Paypal REST API does
                    # not yet report fees in the event of a refund.  Hopefully this can be removed
                    # soon.
                    'fees':
                    -1 * ((float(this_sale.transaction_fee.value) -
                           getConstant('paypal__fixedTransactionFee')) *
                          (float(refund.amount.total) /
                           float(this_sale.amount.total))),
                })
                leftToRefund -= this_amount
            else:
                logger.error('Error processing refund.')
                refundData.append({'status': 'error', 'errors': refund.error})

        return refundData
Example #18
0
def updateFinancialItems():
    '''
    Every hour, create any necessary revenue items and expense items for
    activities that need them.
    '''
    logger.info('Creating automatically-generated financial items.')

    if getConstant('financial__autoGenerateExpensesCompletedEvents'):
        createExpenseItemsForCompletedEvents()
    if getConstant('financial__autoGenerateExpensesVenueRental'):
        createExpenseItemsForVenueRental()
    if getConstant('financial__autoGenerateRevenueRegistrations'):
        createRevenueItemsForRegistrations()
Example #19
0
def updateFinancialItems():
    '''
    Every hour, create any necessary revenue items and expense items for
    activities that need them.
    '''
    logger.info('Creating automatically-generated financial items.')

    if getConstant('financial__autoGenerateExpensesEventStaff'):
        createExpenseItemsForEvents()
    if getConstant('financial__autoGenerateExpensesVenueRental'):
        createExpenseItemsForVenueRental()
    if getConstant('financial__autoGenerateRevenueRegistrations'):
        createRevenueItemsForRegistrations()
Example #20
0
def createRevenueItemsForRegistrations(request=None, datetimeTuple=None):

    if hasattr(request, 'user'):
        submissionUser = request.user
    else:
        submissionUser = None

    this_category = getConstant('financial__registrationsRevenueCat')

    filters_events = {
        'revenueitem__isnull': True,
        'finalEventRegistration__isnull': False
    }

    if datetimeTuple:
        timelist = list(datetimeTuple)
        timelist.sort()

        filters_events[
            'finalEventRegistration__event__eventoccurrence__startTime__gte'] = timelist[
                0]
        filters_events[
            'finalEventRegistration__event__eventoccurrence__startTime__lte'] = timelist[
                1]
    else:
        c = getConstant(
            'financial__autoGenerateRevenueRegistrationsWindow') or 0
        if c > 0:
            filters_events[
                'finalEventRegistration__event__eventoccurrence__startTime__gte'] = timezone.now(
                ) - relativedelta(months=c)

    for item in InvoiceItem.objects.filter(**filters_events).distinct():
        if item.finalRegistration.paidOnline:
            received = True
        else:
            received = False

        revenue_description = _('Event Registration ') + str(
            item.finalEventRegistration.id
        ) + ': ' + item.invoice.finalRegistration.fullName
        RevenueItem.objects.create(invoiceItem=item,
                                   category=this_category,
                                   description=revenue_description,
                                   submissionUser=submissionUser,
                                   grossTotal=item.grossTotal,
                                   total=item.total,
                                   received=received,
                                   receivedDate=item.invoice.modifiedDate)
Example #21
0
 def checkIfAvailable(self, dateTime=timezone.now()):
     '''
     Available slots are available, but also tentative slots that have been held as tentative
     past their expiration date
     '''
     return (
         self.startTime >= dateTime + timedelta(days=getConstant('privateLessons__closeBookingDays')) and
         self.startTime <= dateTime + timedelta(days=getConstant('privateLessons__openBookingDays')) and not
         self.eventRegistration and (
             self.status == self.SlotStatus.available or (
                 self.status == self.SlotStatus.tentative and
                 getattr(getattr(self.temporaryEventRegistration,'registration',None),'expirationDate',timezone.now()) <= timezone.now()
             )
         )
     )
Example #22
0
 def checkIfAvailable(self, dateTime=timezone.now()):
     '''
     Available slots are available, but also tentative slots that have been held as tentative
     past their expiration date
     '''
     return (self.startTime >= dateTime +
             timedelta(days=getConstant('privateLessons__closeBookingDays'))
             and self.startTime <= dateTime +
             timedelta(days=getConstant('privateLessons__openBookingDays'))
             and not self.eventRegistration
             and (self.status == self.SlotStatus.available or
                  (self.status == self.SlotStatus.tentative and getattr(
                      getattr(self.temporaryEventRegistration,
                              'registration', None), 'expirationDate',
                      timezone.now()) <= timezone.now())))
Example #23
0
def sendReminderEmails():

    if not getConstant('general__enableCronTasks'):
        return

    reminders_needed = EventReminder.objects.filter(
        **{
            'time__lte': timezone.now(),
            'completed': False,
            'notifyList__isnull': False
        })
    if reminders_needed:
        for note in reminders_needed:
            for user in note.notifyList.all():
                sent = sendReminderEmailToUser(user, note)
                if sent:
                    # Mark reminder as sent so it won't be sent twice.
                    note.completed = True
                    note.save()
                    logger.info("Email notification sent to user: "******"Unable to send email to user: "******"No notifications to send!")
        pass
Example #24
0
def applyReferrerVouchersTemporarily(sender, **kwargs):
    '''
    Unlike voucher codes which have to be manually supplied, referrer discounts are
    automatically applied here, assuming that the referral program is enabled.
    '''

    # Only continue if the referral program is enabled
    if not getConstant('referrals__enableReferralProgram'):
        return

    logger.debug('Signal fired to temporarily apply referrer vouchers.')

    regSession = kwargs.pop('data', {})
    reg = kwargs.pop('registration')
    email = regSession.get("email", '')

    # Email address is unique for users, so use that
    try:
        c = Customer.objects.get(user__email=email)
        vouchers = c.getReferralVouchers()
    except ObjectDoesNotExist:
        vouchers = None

    if not vouchers:
        logger.debug('No referral vouchers found.')
        return

    for v in vouchers:
        TemporaryVoucherUse(voucher=v, registration=reg, amount=0).save()
Example #25
0
    def clean(self):
        '''
        Only allow submission if there are not already slots in the submitted window,
        and only allow rooms associated with the chosen location.
        '''

        super(SlotCreationForm, self).clean()

        startDate = self.cleaned_data.get('startDate')
        endDate = self.cleaned_data.get('endDate')
        startTime = self.cleaned_data.get('startTime')
        endTime = self.cleaned_data.get('endTime')
        instructor = self.cleaned_data.get('instructorId')

        existingSlots = InstructorAvailabilitySlot.objects.filter(
            instructor=instructor,
            startTime__gt=(
                ensure_localtime(datetime.combine(startDate, startTime)) -
                timedelta(minutes=getConstant(
                    'privateLessons__lessonLengthInterval'))),
            startTime__lt=ensure_localtime(datetime.combine(endDate, endTime)),
        )

        if existingSlots.exists():
            raise ValidationError(_(
                'Newly created slots cannot overlap existing slots for this instructor.'
            ),
                                  code='invalid')
Example #26
0
def applyFinalDiscount(sender,**kwargs):
    # Get the registration and the customer
    if not getConstant('general__discountsEnabled'):
        return

    logger.debug('Signal fired to finalize application of discounts.')

    reg = kwargs.pop('registration',None)

    if not reg:
        logger.debug('No registration passed, discounts not applied.')
        return

    trds = TemporaryRegistrationDiscount.objects.filter(registration=reg.temporaryRegistration)

    obj = None
    for temp_discount in trds:
        obj = RegistrationDiscount.objects.create(
            registration=reg,
            discount=temp_discount.discount,
            discountAmount=temp_discount.discountAmount,
        )

    logger.debug('Discounts applied.')
    return obj
Example #27
0
def applyReferrerVouchersTemporarily(sender,**kwargs):
    '''
    Unlike voucher codes which have to be manually supplied, referrer discounts are
    automatically applied here, assuming that the referral program is enabled.
    '''

    # Only continue if the referral program is enabled
    if not getConstant('referrals__enableReferralProgram'):
        return

    logger.debug('Signal fired to temporarily apply referrer vouchers.')

    reg = kwargs.pop('registration')

    # Email address is unique for users, so use that
    try:
        c = Customer.objects.get(user__email=reg.email)
        vouchers = c.getReferralVouchers()
    except ObjectDoesNotExist:
        vouchers = None

    if not vouchers:
        logger.debug('No referral vouchers found.')
        return

    for v in vouchers:
        TemporaryVoucherUse(voucher=v,registration=reg,amount=0).save()
Example #28
0
def updateFinancialItems():
    '''
    Every hour, create any necessary revenue items and expense items for
    activities that need them.
    '''
    if not getConstant('general__enableCronTasks'):
        return

    logger.info('Creating automatically-generated financial items.')

    if getConstant('financial__autoGenerateExpensesEventStaff'):
        createExpenseItemsForEvents()
    if getConstant('financial__autoGenerateExpensesVenueRental'):
        createExpenseItemsForVenueRental()
    if getConstant('financial__autoGenerateRevenueRegistrations'):
        createRevenueItemsForRegistrations()
Example #29
0
def getAddonItems(sender, **kwargs):
    # Check if this is a new customer
    if not getConstant('general__discountsEnabled'):
        return

    logger.debug('Signal fired to request free add-ons.')

    reg = kwargs.pop('registration', None)
    if not reg:
        logger.warning('No registration passed, addons not applied.')
        return

    newCustomer = True
    customer = Customer.objects.filter(email=reg.email,
                                       first_name=reg.firstName,
                                       last_name=reg.lastName).first()
    if (customer and
            customer.numClassSeries > 0) or sender != RegistrationSummaryView:
        newCustomer = False

    # No need to get all objects, just the ones that could qualify one for an add-on
    cart_object_list = reg.temporaryeventregistration_set.filter(
        dropIn=False).filter(
            Q(event__series__pricingTier__isnull=False)
            | Q(event__publicevent__pricingTier__isnull=False))

    availableAddons = getApplicableDiscountCombos(cart_object_list,
                                                  newCustomer,
                                                  reg.student,
                                                  customer=customer,
                                                  addOn=True,
                                                  dateTime=reg.dateTime)
    return [x.code.name for x in availableAddons]
Example #30
0
    def __init__(self, object, **kwargs):
        timeZone = pytz.timezone(getattr(settings, 'TIME_ZONE', 'UTC'))
        if kwargs.get('timeZone', None):
            try:
                timeZone = pytz.timezone(kwargs.get('timeZone', None))
            except pytz.exceptions.UnknownTimeZoneError:
                pass

        self.id = 'privateEvent_' + str(object.event.id)
        self.type = 'privateEvent'
        self.id_number = object.event.id
        self.title = object.event.name
        self.description = object.event.description

        if hasattr(object.event, 'category') and object.event.category:
            self.category = object.event.category.name
            self.color = object.event.category.displayColor
        else:
            self.category = None
            self.color = getConstant('calendar__defaultEventColor')
        self.start = timezone.localtime(object.startTime, timeZone)
        self.end = timezone.localtime(object.endTime, timeZone)
        self.allDay = object.allDayForDate(object.startTime)
        if hasattr(object, 'event.location'):
            self.location = object.event.location.name + '\n' + object.event.location.address + '\n' + object.event.location.city + ', ' + object.event.location.state + ' ' + object.event.location.zip
        else:
            self.location = None
        self.url = reverse('admin:management_privateevent_change',
                           args=([object.event.id]))
Example #31
0
def applyFinalDiscount(sender, **kwargs):
    # Get the registration and the customer
    if not getConstant('general__discountsEnabled'):
        return

    logger.debug('Signal fired to finalize application of discounts.')

    reg = kwargs.pop('registration', None)

    if not reg:
        logger.debug('No registration passed, discounts not applied.')
        return

    trds = TemporaryRegistrationDiscount.objects.filter(
        registration=reg.temporaryRegistration)

    obj = None
    for temp_discount in trds:
        obj = RegistrationDiscount.objects.create(
            registration=reg,
            discount=temp_discount.discount,
            discountAmount=temp_discount.discountAmount,
        )

    logger.debug('Discounts applied.')
    return obj
Example #32
0
def ensureReferralVouchersExist(customer,referreeDiscount=getConstant('referrals__refereeDiscount'),referrerDiscount=getConstant('referrals__referrerDiscount')):
    # is there a referral voucher for this person?
    # Find all CustomerVouchers for this person
    exists,vrd = referralVoucherExists(customer)

    if not exists:
        name = _('Referral: %s' % customer.fullName)

        # create the referree voucher
        referreeVoucher = createReferreeVoucher(name,referreeDiscount)

        # create the referrer voucher
        referrerVoucher = createReferrerVoucher(customer)

        # create the thing that ties them together
        vrd = VoucherReferralDiscount(referrerVoucher=referrerVoucher,
                                      referreeVoucher=referreeVoucher,
                                      referrerBonus=referrerDiscount)
        vrd.save()

    # TODO: Do I need to save?
    vrd.amount = referrerDiscount
    vrd.save()
    vrd.referreeVoucher.maxAmountPerUse = referreeDiscount
    vrd.referreeVoucher.save()

    return vrd
Example #33
0
    def form_valid(self, form):
        '''
        Create slots and return success message.
        '''
        startDate = form.cleaned_data['startDate']
        endDate = form.cleaned_data['endDate']
        startTime = form.cleaned_data['startTime']
        endTime = form.cleaned_data['endTime']
        instructor = form.cleaned_data['instructorId']

        interval_minutes = getConstant('privateLessons__lessonLengthInterval')

        this_date = startDate
        while this_date <= endDate:
            this_time = startTime
            while this_time < endTime:
                InstructorAvailabilitySlot.objects.create(
                    instructor=instructor,
                    startTime=ensure_localtime(datetime.combine(this_date, this_time)),
                    duration=interval_minutes,
                    location=form.cleaned_data.get('location'),
                    room=form.cleaned_data.get('room'),
                    pricingTier=form.cleaned_data.get('pricingTier'),
                )
                this_time = (ensure_localtime(datetime.combine(this_date, this_time)) + timedelta(minutes=interval_minutes)).time()
            this_date += timedelta(days=1)

        return JsonResponse({'valid': True})
Example #34
0
    def __init__(self,object,**kwargs):
        timeZone = pytz.timezone(getattr(settings,'TIME_ZONE','UTC'))
        if kwargs.get('timeZone',None):
            try:
                timeZone = pytz.timezone(kwargs.get('timeZone',None))
            except pytz.exceptions.UnknownTimeZoneError:
                pass

        self.id = 'privateEvent_' + str(object.event.id)
        self.type = 'privateEvent'
        self.id_number = object.event.id
        self.title = object.event.name
        self.description = object.event.description

        if hasattr(object.event,'category') and object.event.category:
            self.category = object.event.category.name
            self.color = object.event.category.displayColor
        else:
            self.category = None
            self.color = getConstant('calendar__defaultEventColor')
        self.start = timezone.localtime(object.startTime,timeZone)
        self.end = timezone.localtime(object.endTime,timeZone)
        self.allDay = object.allDayForDate(object.startTime)
        if hasattr(object,'event.location'):
            self.location = object.event.location.name + '\n' + object.event.location.address + '\n' + object.event.location.city + ', ' + object.event.location.state + ' ' + object.event.location.zip
            self.room = getattr(object.event,'room',None)
        else:
            self.location = None
            self.room = None
        self.url = object.event.link
Example #35
0
    def form_valid(self, form):
        '''
        Create slots and return success message.
        '''
        startDate = form.cleaned_data['startDate']
        endDate = form.cleaned_data['endDate']
        startTime = form.cleaned_data['startTime']
        endTime = form.cleaned_data['endTime']
        instructor = form.cleaned_data['instructorId']

        interval_minutes = getConstant('privateLessons__lessonLengthInterval')

        this_date = startDate
        while this_date <= endDate:
            this_time = startTime
            while this_time < endTime:
                InstructorAvailabilitySlot.objects.create(
                    instructor=instructor,
                    startTime=ensure_localtime(
                        datetime.combine(this_date, this_time)),
                    duration=interval_minutes,
                    location=form.cleaned_data.get('location'),
                    room=form.cleaned_data.get('room'),
                    pricingTier=form.cleaned_data.get('pricingTier'),
                )
                this_time = (
                    ensure_localtime(datetime.combine(this_date, this_time)) +
                    timedelta(minutes=interval_minutes)).time()
            this_date += timedelta(days=1)

        return JsonResponse({'valid': True})
Example #36
0
    def refund(self, amount=None):
        saleIds = self.getSaleIds()
        refundData = []

        leftToRefund = amount or 0
        for this_id in saleIds:
            # No need to continue if the full amount requested has been refunded
            if amount is not None and leftToRefund <= 0:
                break

            this_sale = Sale.find(this_id)

            if amount is not None:
                this_amount = min(float(this_sale.amount.total), leftToRefund)

                refund = this_sale.refund({
                    'amount': {
                        'total': '{0:.2f}'.format(this_amount),
                        'currency': getConstant('general__currencyCode'),
                    }
                })
            else:
                refund = this_sale.refund()

            if refund.success():
                logger.info('Refund successfully processed.')

                refundData.append({
                    'status': 'success',
                    'refund_id': refund.id,
                    'sale_id': refund.sale_id,
                    'refundAmount': float(refund.amount.total),

                    # This is (annoyingly) hard-coded for now because the Paypal REST API does
                    # not yet report fees in the event of a refund.  Hopefully this can be removed
                    # soon.
                    'fees': -1 * (
                        (float(this_sale.transaction_fee.value) - getConstant('paypal__fixedTransactionFee')) *
                        (float(refund.amount.total) / float(this_sale.amount.total))
                    ),
                })
                leftToRefund -= this_amount
            else:
                logger.error('Error processing refund.')
                refundData.append({'status': 'error', 'errors': refund.error})

        return refundData
Example #37
0
def createExpenseItemsForVenueRental(request=None, datetimeTuple=None):

    filters = {'venueexpense': None, 'location__rentalRate__gt': 0}

    if datetimeTuple:
        timelist = list(datetimeTuple)
        timelist.sort()

        filters['eventoccurrence__startTime__gte'] = timelist[0]
        filters['eventoccurrence__startTime__lte'] = timelist[1]
    else:
        c = getConstant(
            'financial__autoGenerateExpensesVenueRentalWindow') or 0
        if c > 0:
            filters['eventoccurrence__startTime__gte'] = timezone.now(
            ) - relativedelta(months=c)

    # Only create expense items for venues with a positive rental rate
    for event in Event.objects.filter(**filters).distinct():
        replacements = {
            'month': month_name[event.month],
            'year': event.year,
            'type': _('Event/Series venue rental'),
            'location': event.location.name,
            'for': _('for'),
            'name': event.name,
        }
        expense_description = '%(month)s %(year)s %(type)s: %(location)s %(for)s %(name)s' % replacements

        if hasattr(request, 'user'):
            submissionUser = request.user
        else:
            submissionUser = None

        hoursRented = event.duration
        rentalRate = event.location.rentalRate
        total = hoursRented * rentalRate

        this_category = getConstant('financial__venueRentalExpenseCat')

        ExpenseItem.objects.create(eventvenue=event,
                                   category=this_category,
                                   description=expense_description,
                                   submissionUser=submissionUser,
                                   hours=hoursRented,
                                   wageRate=rentalRate,
                                   total=total)
Example #38
0
 def get_context_data(self,**kwargs):
     context = super(BookPrivateLessonView,self).get_context_data(**kwargs)
     context.update({
         'instructor_list': Instructor.objects.filter(
             availableForPrivates=True,instructorprivatelessondetails__isnull=False
         ),
         'defaultLessonLength': getConstant('privateLessons__defaultLessonLength'),
     })
     return context
Example #39
0
 def getCustomerReferralVouchers(customer):
     cvs = CustomerVoucher.objects.filter(
         **{
             'customer':
             customer,
             'voucher__category':
             getConstant('referrals__referrerCategory'),
         })
     return [cv.voucher for cv in cvs]
Example #40
0
 def get_context_data(self,**kwargs):
     context = super(BookPrivateLessonView,self).get_context_data(**kwargs)
     context.update({
         'instructor_list': Instructor.objects.filter(
             availableForPrivates=True,instructorprivatelessondetails__isnull=False
         ),
         'defaultLessonLength': getConstant('privateLessons__defaultLessonLength'),
     })
     return context
Example #41
0
def checkVoucherCode(sender, **kwargs):
    '''
    Check that the given voucher code is valid
    '''
    logger.debug(
        'Signal to check RegistrationContactForm handled by vouchers app.')

    formData = kwargs.get('formData', {})
    request = kwargs.get('request', {})
    registration = kwargs.get('registration', None)
    session = getattr(request, 'session', {}).get(REG_VALIDATION_STR, {})

    id = formData.get('gift', '')
    first = formData.get('firstName')
    last = formData.get('lastName')
    email = formData.get('email')

    # Clean out the session data relating to vouchers so that we can revalidate it.
    session.pop('total_voucher_amount', 0)
    session.pop('voucher_names', None)
    session.pop('gift', None)

    if id == '':
        return

    if not getConstant('vouchers__enableVouchers'):
        raise ValidationError({'gift': _('Vouchers are disabled.')})

    if session.get('gift', '') != '':
        raise ValidationError({'gift': _('Can\'t have more than one voucher')})

    eventids = [
        x.event.id
        for x in registration.temporaryeventregistration_set.exclude(
            dropIn=True)
    ]
    seriess = Series.objects.filter(id__in=eventids)

    obj = Voucher.objects.filter(voucherId=id).first()
    if not obj:
        raise ValidationError({'gift': _('Invalid Voucher Id')})
    else:
        customer = Customer.objects.filter(first_name=first,
                                           last_name=last,
                                           email=email).first()

        # This will raise any other errors that may be relevant
        try:
            obj.validateForCustomerAndSeriess(customer, seriess)
        except ValidationError as e:
            # Ensures that the error is applied to the correct field
            raise ValidationError({'gift': e})

    # If we got this far, then the voucher is determined to be valid, so the registration
    # can proceed with no errors.
    return
Example #42
0
def checkVoucherCode(sender, **kwargs):
    '''
    Check that the given voucher code is valid
    '''
    logger.debug(
        'Signal to check RegistrationContactForm handled by vouchers app.')

    formData = kwargs.get('formData', {})
    request = kwargs.get('request', {})
    session = getattr(request, 'session', {}).get(REG_VALIDATION_STR, {})

    id = formData.get('gift', '')
    first = formData.get('firstName')
    last = formData.get('lastName')
    email = formData.get('email')

    # Clean out the session data relating to vouchers so that we can revalidate it.
    session.pop('total_voucher_amount', 0)
    session.pop('voucher_names', None)
    session.pop('gift', None)

    if id == '':
        return

    if not getConstant('vouchers__enableVouchers'):
        raise ValidationError({'gift': _('Vouchers are disabled.')})

    if session.get('gift', '') != '':
        raise ValidationError({'gift': _('Can\'t have more than one voucher')})

    seriesinfo = session['regInfo'].get('events', {})
    seriesids = [
        int(k) for k, v in seriesinfo.items() if v.get('register', False)
        and not [x for x in v.keys() if x.startswith('dropin_')]
    ]
    seriess = Series.objects.filter(id__in=seriesids)

    obj = Voucher.objects.filter(voucherId=id).first()
    if not obj:
        raise ValidationError({'gift': _('Invalid Voucher Id')})
    else:
        customer = Customer.objects.filter(first_name=first,
                                           last_name=last,
                                           email=email).first()

        # This will raise any other errors that may be relevant
        try:
            obj.validateForCustomerAndSeriess(customer, seriess)
        except ValidationError as e:
            # Ensures that the error is applied to the correct field
            raise ValidationError({'gift': e})

    # If we got this far, then the voucher is determined to be valid, so
    # we can enter it into the session data.
    session['gift'] = id
Example #43
0
def createExpenseItemsForCompletedEvents(request=None, datetimeTuple=None):

    filters = {'expenseitem': None}

    if datetimeTuple:
        timelist = list(datetimeTuple)
        timelist.sort()

        filters['event__eventoccurrence__startTime__gte'] = timelist[0]
        filters['event__eventoccurrence__startTime__lte'] = timelist[1]
    else:
        c = getConstant(
            'financial__autoGenerateExpensesCompletedEventsWindow') or 0
        if c > 0:
            filters['event__eventoccurrence__startTime__gte'] = timezone.now(
            ) - relativedelta(months=c)

    for member in EventStaffMember.objects.filter(**filters).distinct():
        # If an EventStaffMember object for a completed class has no associated ExpenseItem, then create one.
        if member.event.isCompleted and not hasattr(member, 'expenseitem'):
            replacements = {
                'month': month_name[member.event.month],
                'year': member.event.year,
                'type': _('event'),
                'name': member.event.name,
                'memberName': member.staffMember.fullName,
            }
            expense_description = '%(month)s %(year)s %(type)s: %(name)s - %(memberName)s' % replacements

            if hasattr(request, 'user'):
                submissionUser = request.user
            else:
                submissionUser = None

            # Hours should be net of substitutes
            hours_taught = member.netHours
            wage_rate = member.category.defaultRate

            if member.category == getConstant(
                    'general__eventStaffCategoryAssistant'):
                this_category = getConstant(
                    'financial__assistantClassInstructionExpenseCat')
            elif member.category in [
                    getConstant('general__eventStaffCategoryInstructor'),
                    getConstant('general__eventStaffCategorySubstitute')
            ]:
                this_category = getConstant(
                    'financial__classInstructionExpenseCat')
            else:
                this_category = getConstant('financial__otherStaffExpenseCat')

            ExpenseItem.objects.create(eventstaffmember=member,
                                       category=this_category,
                                       description=expense_description,
                                       submissionUser=submissionUser,
                                       hours=hours_taught,
                                       wageRate=wage_rate)
Example #44
0
def checkVoucherCode(sender,**kwargs):
    '''
    Check that the given voucher code is valid
    '''
    logger.debug('Signal to check RegistrationContactForm handled by vouchers app.')

    formData = kwargs.get('formData',{})
    request = kwargs.get('request',{})
    registration = kwargs.get('registration',None)
    session = getattr(request,'session',{}).get(REG_VALIDATION_STR,{})

    id = formData.get('gift','')
    first = formData.get('firstName')
    last = formData.get('lastName')
    email = formData.get('email')

    # Clean out the session data relating to vouchers so that we can revalidate it.
    session.pop('total_voucher_amount',0)
    session.pop('voucher_names',None)
    session.pop('gift',None)

    if id == '':
        return

    if not getConstant('vouchers__enableVouchers'):
        raise ValidationError({'gift': _('Vouchers are disabled.')})

    if session.get('gift','') != '':
        raise ValidationError({'gift': _('Can\'t have more than one voucher')})

    eventids = [x.event.id for x in registration.temporaryeventregistration_set.exclude(dropIn=True)]
    seriess = Series.objects.filter(id__in=eventids)

    obj = Voucher.objects.filter(voucherId=id).first()
    if not obj:
        raise ValidationError({'gift':_('Invalid Voucher Id')})
    else:
        customer = Customer.objects.filter(
            first_name=first,
            last_name=last,
            email=email).first()

        # This will raise any other errors that may be relevant
        try:
            obj.validateForCustomerAndSeriess(customer,seriess)
        except ValidationError as e:
            # Ensures that the error is applied to the correct field
            raise ValidationError({'gift': e})

    # If we got this far, then the voucher is determined to be valid, so the registration
    # can proceed with no errors.
    return
Example #45
0
    def items(self,obj):
        if not getattr(obj,'is_staff') or not getConstant('calendar__privateCalendarFeedEnabled'):
            return []

        this_user = obj
        instructor_groups = list(this_user.groups.all().values_list('id',flat=True))

        occurrences = EventOccurrence.objects.filter(event__privateevent__isnull=False).filter(
            Q(event__privateevent__displayToGroup__in=instructor_groups) |
            Q(event__privateevent__displayToUsers=this_user) |
            (Q(event__privateevent__displayToGroup__isnull=True) & Q(event__privateevent__displayToUsers__isnull=True))).order_by('-startTime')

        return [EventFeedItem(x) for x in occurrences]
Example #46
0
def createRevenueItemsForRegistrations(request=None,datetimeTuple=None):

    if hasattr(request,'user'):
        submissionUser = request.user
    else:
        submissionUser = None

    this_category = getConstant('financial__registrationsRevenueCat')

    filters_events = {'revenueitem__isnull': True,'finalEventRegistration__isnull': False}

    if datetimeTuple:
        timelist = list(datetimeTuple)
        timelist.sort()

        filters_events['finalEventRegistration__event__eventoccurrence__startTime__gte'] = timelist[0]
        filters_events['finalEventRegistration__event__eventoccurrence__startTime__lte'] = timelist[1]
    else:
        c = getConstant('financial__autoGenerateRevenueRegistrationsWindow') or 0
        if c > 0:
            filters_events['finalEventRegistration__event__eventoccurrence__startTime__gte'] = timezone.now() - relativedelta(months=c)

    for item in InvoiceItem.objects.filter(**filters_events).distinct():
        if item.finalRegistration.paidOnline:
            received = True
        else:
            received = False

        revenue_description = _('Event Registration ') + str(item.finalEventRegistration.id) + ': ' + item.invoice.finalRegistration.fullName
        RevenueItem.objects.create(
            invoiceItem=item,
            category=this_category,
            description=revenue_description,
            submissionUser=submissionUser,
            grossTotal=item.grossTotal,
            total=item.total,
            received=received,
            receivedDate=item.invoice.modifiedDate
        )
Example #47
0
    def __init__(self, *args, **kwargs):
        super(PrivateLessonTeacherInlineForm,self).__init__(*args,**kwargs)

        self.fields['staffMember'].label = _('Instructor')
        self.fields['category'].initial = getConstant('privateLessons__eventStaffCategoryPrivateLesson').id

        # Impose restrictions on new records, but not on existing ones.
        if not kwargs.get('instance',None):
            # Filter out retired teachers
            self.fields['staffMember'].queryset = Instructor.objects.exclude(status__in=[Instructor.InstructorStatus.retired,Instructor.InstructorStatus.hidden,Instructor.InstructorStatus.retiredGuest])
        else:
            self.fields['staffMember'].queryset = Instructor.objects.all()

        self.fields['staffMember'].queryset = self.fields['staffMember'].queryset.order_by('status','firstName','lastName')
Example #48
0
def createRevenueItemForInvoiceItem(sender,instance,**kwargs):
    if 'loaddata' in sys.argv or ('raw' in kwargs and kwargs['raw']):
        return

    logger.debug('RevenueItem signal fired for InvoiceItem %s.' % instance.id)

    received_status = (instance.invoice.status == Invoice.PaymentStatus.paid)

    related_item = getattr(instance, 'revenueitem', None)
    if not related_item:
        related_item = RevenueItem.objects.create(
            invoiceItem=instance,
            invoiceNumber=instance.id,
            grossTotal=instance.grossTotal,
            total=instance.total,
            adjustments=instance.adjustments,
            fees=instance.fees,
            taxes=instance.taxes,
            buyerPaysSalesTax=instance.invoice.buyerPaysSalesTax,
            category=getConstant('financial__registrationsRevenueCat'),
            submissionUser=instance.invoice.submissionUser,
            currentlyHeldBy=instance.invoice.collectedByUser,
            received=received_status,
            paymentMethod=instance.invoice.get_payment_method(),
            description=_('Registration invoice %s' % instance.id)
        )
        logger.debug('RevenueItem created.')
    else:
        # Check that the existing revenueItem is still correct
        saveFlag = False

        for field in ['grossTotal','total','adjustments','fees','taxes']:
            if getattr(related_item,field) != getattr(instance,field):
                setattr(related_item,field,getattr(instance,field))
                saveFlag = True
        for field in ['buyerPaysSalesTax',]:
            if getattr(related_item,field) != getattr(instance.invoice,field):
                setattr(related_item,field,getattr(instance.invoice,field))
                saveFlag = True

        if related_item.received != received_status:
            related_item.received = received_status
            related_item.paymentMethod = instance.invoice.get_payment_method()
            saveFlag = True

        if saveFlag:
            related_item.save()
            logger.info('RevenueItem associated with InvoiceItem %s updated.' % instance.id)
Example #49
0
def applyVoucherCodesFinal(sender,**kwargs):
    '''
    Once a registration has been completed, vouchers are used and referrers are awarded
    '''
    logger.debug('Signal fired to mark voucher codes as applied.')

    finalReg = kwargs.pop('registration')
    tr = finalReg.temporaryRegistration

    tvus = TemporaryVoucherUse.objects.filter(registration=tr)

    for tvu in tvus:
        vu = VoucherUse(voucher=tvu.voucher,registration=finalReg,amount=tvu.amount)
        vu.save()
        if getConstant('referrals__enableReferralProgram'):
            awardReferrers(vu)
Example #50
0
    def create_series(self,**kwargs):
        """
        This method just creates a new series with the loaded class
        description that can be modified or used for various tests.
        """

        # Create one or more occurrences.  By default, the series
        # starts tomorrow, is a Level One Lindy Hop class with default
        # pricing and location, is enabled for registration, and is taught
        # by Frankie Manning.
        occurrences = max(kwargs.get('occurrences',1),1)
        startTime = kwargs.get('startTime', timezone.now() + timedelta(days=1))
        classDescription = kwargs.get('classDescription', self.levelOneClassDescription)
        pricingTier = kwargs.get('pricingTier', self.defaultPricing)
        location = kwargs.get('location', self.defaultLocation)
        status = kwargs.get('status', Event.RegStatus.enabled)
        instructors = kwargs.get('instructors', [self.defaultInstructor,])

        s = Series(
            classDescription=classDescription,
            pricingTier=pricingTier,
            location=location,
            status=status,
        )
        s.save()
        # Add an occurrence at the start Time
        # and if requested to set more than one occurrence, then
        # each additional occurrence is the day after the last one.
        for k in range(1,occurrences + 1):
            EventOccurrence.objects.create(
                event=s,
                startTime=startTime + timedelta(days=k - 1),
                endTime=startTime + timedelta(days=k - 1,hours=1)
            )
        # Add instructors (Frankie Manning by default)
        for i in instructors:
            seriesteacher = EventStaffMember.objects.create(
                event=s,
                category=getConstant('general__eventStaffCategoryInstructor'),
                staffMember=i,
            )
            seriesteacher.occurrences = s.eventoccurrence_set.all()
            seriesteacher.save()
        # Must save after adding event occurrences to ensure that
        # registration status is updated properly.
        s.save()
        return s
Example #51
0
def applyTemporaryDiscount(sender,**kwargs):
    # Get the registration and the customer
    if not getConstant('general__discountsEnabled'):
        return

    logger.debug('Signal fired to apply discounts.')

    reg = kwargs.pop('registration',None)
    discount = kwargs.pop('discount',None)
    discountAmount = kwargs.pop('discount_amount',None)

    if not reg or not discount:
        logger.warning('Incomplete information passed, discounts not applied.')
        return

    obj, created = TemporaryRegistrationDiscount.objects.update_or_create(
        registration=reg,
        discount=discount,
        defaults={'discountAmount': discountAmount,},
    )
    logger.debug('Discount applied.')
    return obj
Example #52
0
def applyTemporaryVouchers(sender,**kwargs):
    reg = kwargs.get('registration')
    price = kwargs.get('initial_price')

    logger.debug('Signal fired to apply temporary vouchers.')

    # Put referral vouchers first, so that they are applied last in the loop.
    referral_cat = getConstant('referrals__referrerCategory')

    tvus = list(reg.temporaryvoucheruse_set.filter(
        voucher__category=referral_cat
    )) + list(reg.temporaryvoucheruse_set.exclude(
        voucher__category=referral_cat
    ))

    if not tvus:
        logger.debug('No applicable vouchers found.')
        return ([],0)

    voucher_names = []
    total_voucher_amount = 0
    remaining_price = price

    while remaining_price > 0 and tvus:
        tvu = tvus.pop()

        if tvu.voucher.maxAmountPerUse:
            amount = min(tvu.voucher.amountLeft,tvu.voucher.maxAmountPerUse)
        else:
            amount = tvu.voucher.amountLeft
        amount = min(remaining_price,amount)
        tvu.amount = amount
        tvu.save()

        remaining_price -= amount
        voucher_names += [tvu.voucher.name]
        total_voucher_amount += amount

    return (voucher_names,total_voucher_amount)
Example #53
0
def json_event_feed(request,location_id=None,room_id=None):
    '''
    The Jquery fullcalendar app requires a JSON news feed, so this function
    creates the feed from upcoming PrivateEvent objects
    '''

    if not getConstant('calendar__privateCalendarFeedEnabled') or not request.user.is_staff:
        return JsonResponse({})
    this_user = request.user

    startDate = request.GET.get('start','')
    endDate = request.GET.get('end','')
    timeZone = request.GET.get('timezone',getattr(settings,'TIME_ZONE','UTC'))

    time_filter_dict_events = {}
    if startDate:
        time_filter_dict_events['startTime__gte'] = ensure_timezone(datetime.strptime(startDate,'%Y-%m-%d'))
    if endDate:
        time_filter_dict_events['endTime__lte'] = ensure_timezone(datetime.strptime(endDate,'%Y-%m-%d')) + timedelta(days=1)

    instructor_groups = list(this_user.groups.all().values_list('id',flat=True))

    filters = Q(event__privateevent__isnull=False) & (
        Q(event__privateevent__displayToGroup__in=instructor_groups) |
        Q(event__privateevent__displayToUsers=this_user) |
        (Q(event__privateevent__displayToGroup__isnull=True) & Q(event__privateevent__displayToUsers__isnull=True))
    )

    if location_id:
        filters = filters & Q(event__location__id=location_id)
    if room_id:
        filters = filters & Q(event__room_id=room_id)

    occurrences = EventOccurrence.objects.filter(filters).filter(**time_filter_dict_events).order_by('-startTime')

    eventlist = [EventFeedItem(x,timeZone=timeZone).__dict__ for x in occurrences]

    return JsonResponse(eventlist,safe=False)
Example #54
0
def getAddonItems(sender, **kwargs):
    # Check if this is a new customer
    if not getConstant('general__discountsEnabled'):
        return

    logger.debug('Signal fired to request free add-ons.')

    reg = kwargs.pop('registration',None)
    if not reg:
        logger.warning('No registration passed, addons not applied.')
        return

    newCustomer = True
    customers = Customer.objects.filter(user__email=reg.email)
    for c in customers:
        if c.numClassSeries > 0:
            newCustomer = False
            break

    # No need to get all objects, just the ones that could qualify one for an add-on
    cart_object_list = reg.temporaryeventregistration_set.filter(dropIn=False).filter(Q(event__series__pricingTier__isnull=False) | Q(event__publicevent__pricingTier__isnull=False))

    availableAddons = getApplicableDiscountCombos(cart_object_list, newCustomer, reg.student, addOn=True)
    return [x.code.name for x in availableAddons]
Example #55
0
    def form_valid(self, form):

        slotId = form.cleaned_data.pop('slotId')
        payAtDoor = form.cleaned_data.pop('payAtDoor',False)

        # Check that passed duration is valid.
        try:
            duration = int(form.cleaned_data.pop('duration'))
        except ValueError:
            form.add_error(None,ValidationError(_('Invalid duration.'),code='invalid'))
            return self.form_invalid(form)

        # Include the submission user if the user is authenticated
        if self.request.user.is_authenticated:
            submissionUser = self.request.user
        else:
            submissionUser = None

        try:
            thisSlot = InstructorAvailabilitySlot.objects.get(id=slotId)
        except ObjectDoesNotExist:
            form.add_error(None,ValidationError(_('Invalid slot ID.'),code='invalid'))
            return self.form_invalid(form)

        # Check that passed role is valid
        try:
            role = DanceRole.objects.filter(
                instructorprivatelessondetails__instructor=thisSlot.instructor,
            ).get(id=int(form.cleaned_data.pop('role')))
        except (ValueError, ObjectDoesNotExist):
            form.add_error(None,ValidationError(_('Invalid dance role.'),code='invalid'))
            return self.form_invalid(form)

        affectedSlots = InstructorAvailabilitySlot.objects.filter(
            instructor=thisSlot.instructor,
            location=thisSlot.location,
            room=thisSlot.room,
            pricingTier=thisSlot.pricingTier,
            startTime__gte=thisSlot.startTime,
            startTime__lt=thisSlot.startTime + timedelta(minutes=duration),
        ).filter(
            Q(status=InstructorAvailabilitySlot.SlotStatus.available) |
            (
                Q(status=InstructorAvailabilitySlot.SlotStatus.tentative) &
                ~Q(temporaryEventRegistration__registration__expirationDate__gte=timezone.now())
            )
        )

        # If someone cancels, there will already be one or more events associated
        # with these slots.  These need to be deleted, and we also validate to be
        # certain that we are not cancelling any Event which has finalized or in progress
        # registrations attached to it.
        existingEvents = PrivateLessonEvent.objects.filter(
            instructoravailabilityslot__id__in=[x.id for x in affectedSlots]
        ).distinct()

        if existingEvents.filter(
            Q(eventregistration__isnull=False) |
            Q(temporaryeventregistration__registration__expirationDate__gte=timezone.now())
        ).exists():
            form.add_error(None,ValidationError(_('Some or all of your requested lesson time is currently in the process of registration. Please select a new slot or try again later.'),code='invalid'))
            return self.form_invalid(form)
        else:
            existingEvents.delete()

        # Create the lesson record and set related info
        lesson = PrivateLessonEvent.objects.create(
            pricingTier=thisSlot.pricingTier,
            location=thisSlot.location,
            room=thisSlot.room,
            participants=form.cleaned_data.pop('participants'),
            comments=form.cleaned_data.pop('comments'),
            status=Event.RegStatus.hidden,
        )

        lesson_instructor = EventStaffMember.objects.create(
            event=lesson,
            category=getConstant('privateLessons__eventStaffCategoryPrivateLesson'),
            submissionUser=submissionUser,
            staffMember=thisSlot.instructor,
        )

        lesson_occurrence = EventOccurrence.objects.create(
            event=lesson,
            startTime=thisSlot.startTime,
            endTime=thisSlot.startTime + timedelta(minutes=duration),
        )
        lesson_instructor.occurrences.add(lesson_occurrence)

        # Ensure that lesson start and end time are saved appropriately for
        # the event.
        lesson.save()

        # The temporary  expires after a period of inactivity that is specified in preferences.
        expiry = timezone.now() + timedelta(minutes=getConstant('registration__sessionExpiryMinutes'))

        # Slots without pricing tiers can't go through the actual registration process.
        # Instead, they are sent to another view to get contact information.
        if not thisSlot.pricingTier or not getConstant('privateLessons__allowRegistration'):
            affectedSlots.update(
                lessonEvent=lesson,
                status=InstructorAvailabilitySlot.SlotStatus.tentative,
            )
            self.request.session[PRIVATELESSON_VALIDATION_STR] = {
                'lesson': lesson.id,
                'payAtDoor': payAtDoor,
                'expiry': expiry.strftime('%Y-%m-%dT%H:%M:%S%z'),
            }
            return HttpResponseRedirect(reverse('privateLessonStudentInfo'))

        # Slots with pricing tiers require an TemporaryRegistration to be created,
        # and then they are redirected through the registration system.
        else:

            regSession = self.request.session.get(REG_VALIDATION_STR, {})

            # Create a Temporary Registration associated with this lesson.
            reg = TemporaryRegistration(
                submissionUser=submissionUser,dateTime=timezone.now(),
                payAtDoor=payAtDoor,
                expirationDate=expiry,
            )

            tr = TemporaryEventRegistration(
                event=lesson, role=role,
                price=lesson.getBasePrice(payAtDoor=payAtDoor) * affectedSlots.count()
            )

            # Any remaining form data goes into the JSONfield.
            reg.data = form.cleaned_data or {}

            # Now we are ready to save and proceed.
            reg.priceWithDiscount = tr.price
            reg.save()
            tr.registration = reg
            tr.save()

            affectedSlots.update(
                lessonEvent=lesson,
                status=InstructorAvailabilitySlot.SlotStatus.tentative,
                temporaryEventRegistration=tr,
            )

            # Load the temporary registration into session data like a regular registration
            # and redirect to Step 2 as usual.
            regSession["temporaryRegistrationId"] = reg.id
            regSession["temporaryRegistrationExpiry"] = expiry.strftime('%Y-%m-%dT%H:%M:%S%z')
            self.request.session[REG_VALIDATION_STR] = regSession
            return HttpResponseRedirect(reverse('getStudentInfo'))
Example #56
0
 def __str__(self):
     if self.accrualDate:
         return '%s %s: %s = %s%s' % (self.category.name, self.accrualDate.strftime('%B %Y'),self.description, getConstant('general__currencySymbol'), self.total)
     else:
         return '%s: %s = %s%s' % (self.category.name, self.description, getConstant('general__currencySymbol'), self.total)
Example #57
0
    def finalizeBooking(self,**kwargs):
        notifyStudent = kwargs.get('notifyStudent',True)
        notifyTeachers = kwargs.get('notifyTeachers',getConstant('privateLessons__notifyInstructor'))
        eventRegistration = kwargs.get('eventRegistration',None)

        affectedSlots = self.instructoravailabilityslot_set.all()
        affectedSlots.update(
            status=InstructorAvailabilitySlot.SlotStatus.booked,
            eventRegistration=eventRegistration,
        )

        if notifyStudent:
            # This is the email template used to notify students that their private lesson has been
            # successfully scheduled

            template = getConstant('privateLessons__lessonBookedEmailTemplate')

            if template.defaultFromAddress and template.content:
                for customer in self.customers:
                    customer.email_recipient(
                        template.subject,
                        template.content,
                        send_html=False,
                        from_address=template.defaultFromAddress,
                        from_name=template.defaultFromName,
                        cc=template.defaultCC,
                        to=customer.email,
                        lesson=self,
                    )

        if notifyTeachers:
            # This is the email template used to notify individuals who run registration
            # that they have been compensated
            template = getConstant('privateLessons__lessonBookedInstructorEmailTemplate')

            if template.defaultFromAddress and template.content:
                emailMixin = EmailRecipientMixin()

                instructors = [
                    x.staffMember for x in
                    self.eventstaffmember_set.exclude(
                        Q(staffMember__privateEmail__isnull=True) & Q(staffMember__publicEmail__isnull=True)
                    )
                ]

                for instructor in instructors:
                    if not instructor.privateEmail and not instructor.publicEmail:
                        # Without an email address, instructor cannot be notified
                        continue
                    emailMixin.email_recipient(
                        template.subject,
                        template.content,
                        send_html=False,
                        from_address=template.defaultFromAddress,
                        from_name=template.defaultFromName,
                        cc=template.defaultCC,
                        to=instructor.privateEmail or instructor.publicEmail,
                        lesson=self,
                        instructor=instructor,
                        customers=self.customers,
                        calendarUrl=reverse('privateCalendar'),
                    )