Example #1
0
    def post(self):
    #----------------------------------------------------------------------
        # request.form is werkzeug.datastructures.ImmutableMultiDict
        # and each field will show up as list if we don't convert to dict here
        form = {k:v for k,v in list(request.form.items())}

        # process a couple of form entries for easier reading
        theseservices = []
        for service in ['is_finish_line', 'is_course_marking', 'is_premium_promotion']:
            if form.get(service, False):
                # skip 'is_' portion
                theseservices.append(service[3:])
        services = ', '.join(theseservices)
        form['services'] = services
        form['is_new_race'] = 'yes' if form.get('is_new_race', False) else 'no'

        # turn form into email
        html = render_template( 'events-servicesquery-mail.jinja2', **form)

        # TODO: this should be in database
        subject = '[FSRC-RACE-REQUEST] {}'.format(form['subject'])
        tolist = current_app.config['SERVICEQUERY_TO']
        # TODO: these should be in database
        cclist = current_app.config['SERVICEQUERY_CC'] + ['{} <{}>'.format(form['contact_name'], form['contact_email'])]
        fromlist = current_app.config['SERVICEQUERY_CONTACT']
        sendmail( subject, fromlist, tolist, html, ccaddr=cclist )

        context = {
                   'pagename'         : 'request race services - success',
                   'pageassets_css'   : 'materialize-css',
                   'pageassets_js'    : 'materialize-js',
                   'servicesquery_contact' : current_app.config['SERVICEQUERY_CONTACT'],
                  }
        return render_template( 'events-servicesquery-success.jinja2', **context )
Example #2
0
    def post(self):
    #----------------------------------------------------------------------
        try:
            # request.form is werkzeug.datastructures.ImmutableMultiDict
            # and each field will show up as list if we don't convert to dict here
            # form = {k:v for k,v in request.form.items()}
            form = loads(request.form['json'])

            # figure out RD for this race
            race = SponsorRace.query.filter_by(race=form['race']['text']).one()
            rdemail = race.email


            # log this request, won't be committed until after sendmail
            log = SponsorQueryLog(**{k:form[k]['text'] for k in form['_keyorder']})
            log.time = dt.dt2asc(datetime.now())
            db.session.add(log)

            # turn form into email
            html = render_template( 'sponsorship-email.jinja2', formdata=form)

            subject = 'Thanks for sponsoring {}!'.format(race.race)

            # TODO: these could be in database
            tolist = '{} <{}>'.format(form['name']['text'], form['email']['text'])
            cclist = [rdemail] + current_app.config['SPONSORSHIPQUERY_CC']
            fromlist = '{} <{}>'.format(race.race, current_app.config['SPONSORSHIPQUERY_CONTACT'])
            sendmail( subject, fromlist, tolist, html, ccaddr=cclist )

            # everything seemed to work ok, so committing
            db.session.commit()

            return 'OK'

        except:
            return "<br/>{}".format(format_exc())
Example #3
0
    def editor_method_posthook(self, form):
        #----------------------------------------------------------------------
        '''
        send contract to client contact if asked to do so, after processing put()

        note row has already been committed to the database, so can be retrieved
        '''
        # the following can be true only for put() [edit] method
        if 'addlaction' in form and form['addlaction'] in [
                'sendcontract', 'resendcontract'
        ]:
            folderid = current_app.config['CONTRACTS_DB_FOLDER']

            # need an instance of contract manager to take care of saving the contract
            cm = ContractManager(contractType='race services',
                                 templateType='contract',
                                 driveFolderId=folderid)

            # pull record(s) from database and save as flat dotted record
            data = get_request_data(form)
            print(('data={}'.format(data)))
            for thisid in data:
                eventdb = Event.query.filter_by(id=thisid).one()

                # different subject line if contract had been accepted before. This must match contractviews.AcceptAgreement.post
                annotation = ''

                # if we are generating a new version of the contract
                if form['addlaction'] == 'sendcontract':
                    # if there was already a document sent, indicate that we're updating it
                    if eventdb.contractDocId:
                        eventdb.isContractUpdated = True
                        annotation = '(updated) '

                    # check appropriate fields are present for certain services
                    servicenames = {s.service for s in eventdb.services}
                    if servicenames & {'coursemarking', 'finishline'}:
                        self._fielderrors = []
                        for field in [
                                'race', 'date', 'mainStartTime', 'mainDistance'
                        ]:
                            if not data[thisid][field]:
                                self._fielderrors.append({
                                    'name':
                                    field,
                                    'status':
                                    'please supply'
                                })
                        ## handle select fields
                        for field in [
                                'state', 'services', 'client', 'course', 'lead'
                        ]:
                            if not data[thisid][field]['id']:
                                self._fielderrors.append({
                                    'name':
                                    '{}.id'.format(field),
                                    'status':
                                    'please select'
                                })
                        if self._fielderrors:
                            raise parameterError('missing fields')

                    # calculate service fees
                    servicefees = []

                    feetotal = 0
                    for service in eventdb.services:
                        servicefee = {'service': service.serviceLong}
                        # fixed fee
                        if service.feeType.feeType == 'fixed':
                            thisfee = service.fee
                            servicefee['fee'] = thisfee
                            servicefees.append(servicefee)

                        # fee is based on another field
                        elif service.feeType.feeType == 'basedOnField':
                            field = service.basedOnField
                            # not clear why this needs to be converted to int, but otherwise see unicode value
                            # if can't be converted, then invalid format
                            try:
                                fieldval = int(getattr(eventdb, field))
                            except (TypeError, ValueError) as e:
                                fieldval = None

                            # field not set, then set self._fielderrors appropriately
                            if not fieldval:
                                formfield = self.dbmapping[
                                    field]  # hopefully not a function
                                self._fielderrors = [{
                                    'name':
                                    formfield,
                                    'status':
                                    'needed to calculate fee'
                                }]
                                raise parameterError(
                                    'cannot calculate fee if {} not set'.
                                    format(field))

                            feebasedons = FeeBasedOn.query.filter_by(
                                serviceId=service.id).order_by(
                                    FeeBasedOn.fieldValue).all()
                            foundfee = False
                            for feebasedon in feebasedons:
                                lastfieldval = feebasedon.fieldValue
                                if debug:
                                    current_app.logger.debug(
                                        'fieldval={} feebasedon.fieldValue={}'.
                                        format(fieldval,
                                               feebasedon.fieldValue))
                                if debug:
                                    current_app.logger.debug(
                                        'type(fieldval)={} type(feebasedon.fieldValue)={}'
                                        .format(type(fieldval),
                                                type(feebasedon.fieldValue)))
                                if fieldval <= feebasedon.fieldValue:
                                    thisfee = feebasedon.fee
                                    servicefee['fee'] = thisfee
                                    servicefees.append(servicefee)
                                    foundfee = True
                                    break

                            # if fee not found, then set fielderrors appropriately
                            if not foundfee:
                                formfield = self.dbmapping[
                                    field]  # hopefully not a function
                                self._fielderrors = [{
                                    'name':
                                    formfield,
                                    'status':
                                    'cannot calculate fee if this is greater than {}'
                                    .format(lastfieldval)
                                }]
                                raise parameterError(
                                    'cannot calculate fee if {} greater than {}'
                                    .format(field, lastfieldval))

                        # not sure how we could get here, but best to be defensive
                        else:
                            raise parameterError('unknown feeType: {}'.format(
                                service.feeType.feeType))

                        # accumulate total fee
                        feetotal += thisfee

                    # need to calculate addons in addition to services
                    for addon in eventdb.addOns:
                        thisfee = addon.fee
                        servicefee = {
                            'service': addon.longDescr,
                            'fee': thisfee
                        }
                        servicefees.append(servicefee)

                        # accumulate total fee
                        feetotal += thisfee

                    # generate contract
                    if debug:
                        current_app.logger.debug(
                            'editor_method_posthook(): (before create()) eventdb.__dict__={}'
                            .format(eventdb.__dict__))
                    docid = cm.create(
                        '{}-{}-{}.docx'.format(eventdb.client.client,
                                               eventdb.race.race,
                                               eventdb.date),
                        eventdb,
                        addlfields={
                            'servicenames':
                            [s.service for s in eventdb.services],
                            'servicefees': servicefees,
                            'event': eventdb.race.race,
                            'totalfees': {
                                'service': 'TOTAL',
                                'fee': feetotal
                            },
                        })

                    # update database to show contract sent
                    eventdb.state = State.query.filter_by(
                        state=STATE_CONTRACT_SENT).one()
                    eventdb.contractSentDate = dt.dt2asc(date.today())
                    eventdb.contractDocId = docid

                    # find index with correct id and show database updates
                    for resprow in self._responsedata:
                        if resprow['rowid'] == thisid:
                            resprow['state'] = {
                                key: val
                                for (key, val
                                     ) in list(eventdb.state.__dict__.items())
                                if key[0] != '_'
                            }
                            resprow[
                                'contractSentDate'] = eventdb.contractSentDate
                            resprow['contractDocId'] = eventdb.contractDocId

                # if we are just resending current version of the contract
                else:
                    docid = eventdb.contractDocId
                    annotation = '(resend) '

                # email sent depends on current state as this flows from 'sendcontract' and 'resendcontract'
                if eventdb.state.state == STATE_COMMITTED:
                    # prepare agreement accepted email
                    templatestr = (db.session.query(Contract).filter(
                        Contract.contractTypeId == ContractType.id).filter(
                            ContractType.contractType == 'race services'
                        ).filter(
                            Contract.templateTypeId == TemplateType.id).filter(
                                TemplateType.templateType ==
                                'agreement accepted view').one()).block
                    template = Template(templatestr)
                    subject = '{}ACCEPTED - FSRC Race Support Agreement: {} - {}'.format(
                        annotation, eventdb.race.race, eventdb.date)

                elif eventdb.state.state == STATE_CONTRACT_SENT:
                    # send contract mail to client
                    templatestr = (db.session.query(Contract).filter(
                        Contract.contractTypeId == ContractType.id).filter(
                            ContractType.contractType == 'race services'
                        ).filter(
                            Contract.templateTypeId == TemplateType.id).filter(
                                TemplateType.templateType ==
                                'contract email').one()).block
                    template = Template(templatestr)
                    subject = '{}FSRC Race Support Agreement: {} - {}'.format(
                        annotation, eventdb.race.race, eventdb.date)

                # state must be STATE_COMMITTED or STATE_CONTRACT_SENT, else logic error
                else:
                    raise parameterError(
                        'editor_method_posthook(): bad state seen for {}: {}'.
                        format(form['addlaction'], eventdb.state.state))

                # merge database fields into template and send email
                mergefields = deepcopy(eventdb.__dict__)
                mergefields[
                    'viewcontracturl'] = 'https://docs.google.com/document/d/{}/view'.format(
                        docid)
                mergefields[
                    'downloadcontracturl'] = 'https://docs.google.com/document/d/{}/export?format=pdf'.format(
                        docid)
                # need to bring in full path for email, so use url_root
                mergefields[
                    'acceptcontracturl'] = request.url_root[:-1] + url_for(
                        'frontend.acceptagreement', docid=docid)
                mergefields['servicenames'] = [
                    s.service for s in eventdb.services
                ]
                mergefields['event'] = eventdb.race.race

                html = template.render(mergefields)
                tolist = eventdb.client.contactEmail
                cclist = current_app.config['CONTRACTS_CC']
                fromlist = current_app.config['CONTRACTS_CONTACT']
                sendmail(subject, fromlist, tolist, html, ccaddr=cclist)
Example #4
0
    def post(self, docid):
        #----------------------------------------------------------------------
        # this should work because we just did get using same docid
        thisevent = Event.query.filter_by(contractDocId=docid).one()

        # get form fields and add to database
        name = request.form['name']
        email = request.form['email']
        notes = request.form['notes']
        thisevent.contractSignedDate = dt.dt2asc(date.today())
        thisevent.contractApprover = name
        thisevent.contractApproverEmail = email
        thisevent.contractApproverNotes = notes
        thisevent.state = State.query.filter_by(state=STATE_COMMITTED).one()
        # need to get merge fields before commit, first force load of client
        clientgarbage = thisevent.client
        mergefields = deepcopy(thisevent.__dict__)
        db.session.commit()

        # prepare agreement accepted email and view
        templatestr = (db.session.query(Contract).filter(
            Contract.contractTypeId == ContractType.id).filter(
                ContractType.contractType == 'race services').filter(
                    Contract.templateTypeId == TemplateType.id).filter(
                        TemplateType.templateType ==
                        'agreement accepted view').one()).block

        # add needed fields
        mergefields['servicenames'] = [s.service for s in thisevent.services]
        mergefields['event'] = thisevent.race.race

        # drive urls
        # see https://www.labnol.org/internet/direct-links-for-google-drive/28356/
        webviewurl = 'https://docs.google.com/document/d/{}/view'.format(docid)
        mergefields['viewcontracturl'] = webviewurl
        pdfurl = 'https://docs.google.com/document/d/{}/export?format=pdf'.format(
            docid)
        mergefields['downloadcontracturl'] = pdfurl

        # send agreement accepted email
        template = Template(templatestr)
        html = template.render(mergefields)
        tolist = mergefields['client'].contactEmail
        cclist = current_app.config['CONTRACTS_TREAS_CC']
        fromlist = current_app.config['CONTRACTS_CONTACT']
        print(('mergefields={}'.format(mergefields)))
        # different subject line if contract had been accepted before. This must match eventscontract.EventsContract.editor_method_posthook
        annotation = ''
        if thisevent.isContractUpdated:
            annotation = '(updated) '

        subject = '{}ACCEPTED - FSRC Race Support Agreement: {} - {}'.format(
            annotation, mergefields['event'], mergefields['date'])
        sendmail(subject, fromlist, tolist, html, ccaddr=cclist)

        # update for web view
        mergefields['webview'] = True

        if debug:
            current_app.logger.debug(
                'AcceptAgreement.post(): mergefields={}'.format(mergefields))
        return render_template_string(templatestr, **mergefields)
Example #5
0
    def editor_method_posthook(self, form):
        #----------------------------------------------------------------------
        '''
        send contract to client contact if asked to do so, after processing put()

        note row has already been committed to the database, so can be retrieved
        '''

        # someday we might allow multiple records to be processed in a single request

        # pull record(s) from database and save as flat dotted record
        data = get_request_data(form)
        for thisid in data:
            sponsordb = Sponsor.query.filter_by(id=thisid).one_or_none()

            # if we're creating, we just flushed the row, but the id in the form was 0
            # retrieve the created row through saved id
            if not sponsordb:
                thisid = self.created_id
                sponsordb = Sponsor.query.filter_by(id=thisid).one()

            # the following can be true only for put() [edit] method
            if 'addlaction' in form and form['addlaction'] in [
                    'sendcontract', 'resendcontract'
            ]:
                folderid = current_app.config['CONTRACTS_DB_FOLDER']

                # need an instance of contract manager to take care of saving the contract
                cm = ContractManager(
                    contractType='race sponsorship',
                    templateType='sponsor agreement',
                    driveFolderId=folderid,
                    doctype='html',
                )

                racedate = SponsorRaceDate.query.filter_by(
                    race_id=sponsordb.race.id,
                    raceyear=sponsordb.raceyear).one()

                # bring in subrecords
                garbage = sponsordb.race
                garbage = sponsordb.client
                garbage = sponsordb.level

                # calculate the benefits (see https://stackoverflow.com/questions/40699642/how-to-query-many-to-many-sqlalchemy)
                benefitsdb = SponsorBenefit.query.join(
                    SponsorBenefit.levels).filter(
                        SponsorLevel.id == sponsordb.level.id).order_by(
                            SponsorBenefit.order).all()
                benefits = [b.benefit for b in benefitsdb]

                # calculate display for coupon count. word (num) if less than 10, otherwise num
                # but note there may not be a coupon count
                # ccouponcount is capitalized
                ncoupons = sponsordb.level.couponcount
                if ncoupons:
                    if ncoupons < 10:
                        wcoupons = 'zero one two three four five six seven eight nine'.split(
                        )[ncoupons]
                        couponcount = '{} ({})'.format(
                            wcoupons, ncoupons) if ncoupons else None
                    else:
                        couponcount = str(ncoupons)
                    ccouponcount = couponcount.capitalize()
                else:
                    couponcount = None
                    ccouponcount = None

                # pick up variables
                variablesdb = SponsorRaceVbl.query.filter_by(
                    race_id=sponsordb.race.id).all()
                variables = {v.variable: v.value for v in variablesdb}

                # if we are generating a new version of the contract
                if form['addlaction'] == 'sendcontract':

                    # set up dateagreed, if not already there
                    if not sponsordb.dateagreed:
                        sponsordb.dateagreed = dt.dt2asc(date.today())

                    # additional fields for contract
                    addlfields = {
                        '_date_':
                        humandt.dt2asc(dt.asc2dt(sponsordb.dateagreed)),
                        '_racedate_':
                        humandt.dt2asc(dt.asc2dt(racedate.racedate)),
                        '_rdcertlogo_':
                        pathjoin(current_app.static_folder,
                                 'rd-cert-logo.png'),
                        '_raceheader_':
                        '<img src="{}" width=6in>'.format(
                            pathjoin(
                                current_app.static_folder,
                                '{}-header.png'.format(
                                    sponsordb.race.raceshort.lower()))),
                        '_benefits_':
                        benefits,
                        '_raceloc_':
                        racedate.raceloc,
                        '_racebeneficiary_':
                        racedate.beneficiary,
                        '_couponcount_':
                        ccouponcount,  # ok to assume this is first word in sentence
                    }
                    addlfields.update(variables)

                    # generate contract
                    if debug:
                        current_app.logger.debug(
                            'editor_method_posthook(): (before create()) sponsordb.__dict__={}'
                            .format(sponsordb.__dict__))
                    docid = cm.create(
                        '{} {} {} Sponsor Agreement'.format(
                            sponsordb.raceyear, sponsordb.race.raceshort,
                            sponsordb.client.client),
                        sponsordb,
                        addlfields=addlfields,
                    )

                    # update database to show contract sent/agreed
                    sponsordb.state = State.query.filter_by(
                        state=STATE_COMMITTED).one()
                    sponsordb.contractDocId = docid

                    # find index with correct id and show database updates
                    for resprow in self._responsedata:
                        if resprow['rowid'] == thisid:
                            resprow['state'] = {
                                key: val
                                for (key, val) in list(
                                    sponsordb.state.__dict__.items())
                                if key[0] != '_'
                            }
                            resprow['dateagreed'] = sponsordb.dateagreed
                            resprow['contractDocId'] = sponsordb.contractDocId

                    # configure coupon provider with coupon code (supported providers)
                    if sponsordb.race.couponprovider and sponsordb.level.couponcount and sponsordb.level.couponcount > 0:
                        expiration = racedate.racedate
                        numregistrations = sponsordb.level.couponcount
                        clientname = sponsordb.client.client
                        raceid = sponsordb.race.couponproviderid
                        couponcode = sponsordb.couponcode
                        start = sponsordb.dateagreed
                        if sponsordb.race.couponprovider.lower(
                        ) == 'runsignup':
                            with RunSignUp(
                                    key=current_app.config['RSU_KEY'],
                                    secret=current_app.config['RSU_SECRET'],
                                    debug=debug) as rsu:
                                coupons = rsu.getcoupons(raceid, couponcode)
                                # rsu search includes any coupons with the couponcode with the coupon string, so we need to filter
                                coupons = [
                                    c for c in coupons
                                    if c['coupon_code'] == couponcode
                                ]
                                if coupons:
                                    coupon = coupons[
                                        -1]  # should be only one entry, but last is the current one (?)
                                    coupon_id = coupon['coupon_id']
                                    # override start with the date portion of start_date
                                    start = coupon['start_date'].split(' ')[0]
                                else:
                                    coupon_id = None
                                rsu.setcoupon(raceid,
                                              couponcode,
                                              start,
                                              expiration,
                                              numregistrations,
                                              clientname,
                                              coupon_id=coupon_id)

                # if we are just resending current version of the contract
                else:
                    docid = sponsordb.contractDocId

                # prepare agreement email (new contract or resending)
                templatestr = (db.session.query(Contract).filter(
                    Contract.contractTypeId == ContractType.id).filter(
                        ContractType.contractType ==
                        'race sponsorship').filter(
                            Contract.templateTypeId == TemplateType.id).filter(
                                TemplateType.templateType ==
                                'sponsor email').one()).block
                template = Template(templatestr)
                subject = '{} Sponsorship Agreement for {}'.format(
                    sponsordb.race.race, sponsordb.client.client)

                # bring in subrecords
                garbage = sponsordb.race

                # merge database fields into template and send email
                mergefields = deepcopy(sponsordb.__dict__)
                mergefields[
                    'viewcontracturl'] = 'https://docs.google.com/document/d/{}/view'.format(
                        docid)
                mergefields[
                    'downloadcontracturl'] = 'https://docs.google.com/document/d/{}/export?format=pdf'.format(
                        docid)
                # need to bring in full path for email, so use url_root
                # mergefields['_race_'] = sponsordb.race.race
                racedate = SponsorRaceDate.query.filter_by(
                    race_id=sponsordb.race.id,
                    raceyear=sponsordb.raceyear).one()
                mergefields['_racedate_'] = humandt.dt2asc(
                    dt.asc2dt(racedate.racedate))
                mergefields['_coupondate_'] = variables['_coupondate_']
                mergefields['_couponcount_'] = couponcount

                html = template.render(mergefields)
                tolist = sponsordb.client.contactEmail
                rdemail = '{} <{}>'.format(sponsordb.race.racedirector,
                                           sponsordb.race.rdemail)
                cclist = current_app.config['SPONSORSHIPAGREEMENT_CC'] + [
                    rdemail
                ]
                fromlist = '{} <{}>'.format(
                    sponsordb.race.race,
                    current_app.config['SPONSORSHIPQUERY_CONTACT'])
                sendmail(subject, fromlist, tolist, html, ccaddr=cclist)

            # calculate and update trend
            calculateTrend(sponsordb)
            # kludge to force response data to have correct trend
            # TODO: remove when #245 fixed
            thisndx = [i['rowid'] for i in self._responsedata].index(thisid)
            self._responsedata[thisndx]['trend'] = sponsordb.trend
Example #6
0
def preraceemail(startdate, enddate):
#----------------------------------------------------------------------
    '''Send pre-race email to race director and lead.'''

    # set up tag which is used to control this email
    senttag = Tag.query.filter_by(tag=TAG_PRERACEMAILSENT).one()
    inhibittag = Tag.query.filter_by(tag=TAG_PRERACEMAILINHIBITED).one()

    # calculate start and end date window
    if startdate == 'auto' and enddate == 'auto':
        # calculate start and end date window
        start = dbdate.dt2asc(date.today())
        end = dbdate.dt2asc(date.today() + timedelta(app.config['DAYS_PRERACE_EMAIL']))

    # verify both dates are present, check user input format is yyyy-mm-dd
    else:
        if startdate == 'auto' or enddate == 'auto':
            print('ERROR: startdate and enddate must both be specified')
            return

        if (not match(r'^(19[0-9]{2}|2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)$', startdate) or
                not match(r'^(19[0-9]{2}|2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)$', enddate)):
            print('ERROR: startdate and enddate must be in yyyy-mm-dd format')
            return

        # cli specified dates format is fine, and both dates specified
        start = startdate
        end = enddate

    # use correct filter to get races in next N days
    events = Event.query.filter(Event.date.between(start, end)).all()

    for event in events:
        # ignore uncommitted events
        if event.state.state != STATE_COMMITTED: continue

        # don't send if this message has already been sent or was inhibited by admin
        if senttag in event.tags or inhibittag in event.tags: continue

        # don't send if only premium promotion service
        if len(event.services) == 1 and event.services[0].service == 'premiumpromotion': continue

        # send pre-race mail to client
        templatestr = (db.session.query(Contract)
                   .filter(Contract.contractTypeId==ContractType.id)
                   .filter(ContractType.contractType=='race services')
                   .filter(Contract.templateTypeId==TemplateType.id)
                   .filter(TemplateType.templateType=='pre-race email')
                   .one()
                  ).block
        template = Template( templatestr )

        # bring in needed relations
        garbage = event.client
        garbage = event.lead
        garbage = event.course

        # merge database fields into template and send email
        mergefields = deepcopy(event.__dict__)
        docid = event.contractDocId

        mergefields['viewcontracturl'] = 'https://docs.google.com/document/d/{}/view'.format(docid)
        mergefields['servicenames'] = [s.service for s in event.services] 
        mergefields['event'] = event.race.race

        html = template.render( mergefields )

        subject = 'FSRC Pre-race Coordination: {} - {}'.format(event.race.race, event.date)
        tolist = event.client.contactEmail
        cclist = app.config['CONTRACTS_CC'] + [event.lead.email]
        fromlist = app.config['CONTRACTS_CONTACT']
        
        sendmail( subject, fromlist, tolist, html, ccaddr=cclist )

        # mark as sent
        event.tags.append(senttag)
        db.session.commit()
Example #7
0
def sendrenewemails(startdate, enddate):
#----------------------------------------------------------------------
    '''(initial deployment) Send "renewal" emails for renewed events between two dates yyyy-mm-dd.
    NOTE: emails are not sent to premium promotion only events.
    '''

    # set up tag which is used to control this email
    senttag = Tag.query.filter_by(tag=TAG_POSTRACEMAILSENT).one()
    inhibittag = Tag.query.filter_by(tag=TAG_POSTRACEMAILINHIBITED).one()

    # check input argument format
    if (not match(r'^(19[0-9]{2}|2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)$', startdate)
            or not match(r'^(19[0-9]{2}|2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)$', enddate)):
        print('ERROR: dates must be in yyyy-mm-dd format')
        return

    # do arguments make sense?
    if enddate < startdate:
        print('ERROR: enddate must be greater than or equal to startdate')
        return

    # use filter to get races specified
    events = Event.query.filter(Event.date.between(startdate, enddate)).all()

    for event in events:
        # ignore events which are not renewed renewed
        if event.state.state != STATE_RENEWED_PENDING: continue

        # bring in event this was renewed from
        # the latest event associated with this race is the one, but before this one
        prevevents = Event.query.filter(Event.race_id == event.race_id).filter(Event.date < event.date).order_by(Event.date).all()
        prevevent = prevevents[-1]

        # don't send email if this message has already been sent or was inhibited by admin
        # don't send email if only premium promotion service
        if senttag in prevevent.tags or inhibittag in prevevent.tags: continue
        if len(event.services) == 1 and event.services[0].service == 'premiumpromotion': continue

        # get post-race mail template
        templatestr = (db.session.query(Contract)
                   .filter(Contract.contractTypeId==ContractType.id)
                   .filter(ContractType.contractType=='race services')
                   .filter(Contract.templateTypeId==TemplateType.id)
                   .filter(TemplateType.templateType=='post-race email')
                   .one()
                  ).block
        template = Template( templatestr )

        # bring in needed relations
        garbage = event.client
        garbage = event.lead
        garbage = event.course

        # merge database fields into template and send email
        # deepcopy getting error AttributeError: 'Race' object has no attribute '_sa_instance_state'
        # so just collect what we need
        mergefields = deepcopy(event.__dict__)

        mergefields['nextyeartext'] = 'based on your most recent race'
        mergefields['servicenames'] = [s.service for s in event.services] 
        mergefields['event'] = event.race.race
        # this shouldn't happen, but need to handle case where renew_event couldn't find renewed race
        mergefields['renew_date'] = event.date if event else '[oops - an error occurred determining race date, please contact us]'

        html = template.render( mergefields )

        subject = 'FSRC Race Support Services is holding {} for {}'.format(event.date, event.race.race)
        tolist = event.client.contactEmail
        cclist = app.config['CONTRACTS_CC']
        fromlist = app.config['CONTRACTS_CONTACT']
        
        sendmail( subject, fromlist, tolist, html, ccaddr=cclist )

        # mark as sent
        prevevent.tags.append(senttag)

        # pick up all db changes (event.tags)
        db.session.commit()
Example #8
0
def cancellaterace(startdate, enddate):
    # ----------------------------------------------------------------------
    '''Send pre-race premium promotion email.'''
    # set up tags which are used to control this email
    senttag = Tag.query.filter_by(tag=TAG_PRERACERENEWEDCANCELED).one()

    # calculate start and end date window
    if startdate == 'auto' and enddate == 'auto':
        # only send for races within one week window
        # this causes sending DAYS_PRERACE_LATE_CANCEL in advance of the event,
        # but if it doesn't happen for some reason will retry for a week
        start = dbdate.dt2asc(date.today() + timedelta(app.config['DAYS_PRERACE_LATE_CANCEL']) - timedelta(7))
        end = dbdate.dt2asc(date.today() + timedelta(app.config['DAYS_PRERACE_LATE_CANCEL']))

    # verify both dates are present, check user input format is yyyy-mm-dd
    else:
        if startdate == 'auto' or enddate == 'auto':
            print('ERROR: startdate and enddate must both be specified')
            return

        if (not match(r'^(19[0-9]{2}|2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)$', startdate) or
                not match(r'^(19[0-9]{2}|2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)$', enddate)):
            print('ERROR: startdate and enddate must be in yyyy-mm-dd format')
            return

        # cli specified dates format is fine, and both dates specified
        start = startdate
        end = enddate

    # debug
    if debug: print('start={} end={}'.format(start, end))

    # use filter to get races in which occurred at least N days ago
    events = Event.query.filter(Event.date.between(start, end)).all()

    for event in events:
        # ignore events unless they're in renewed-pending state
        if event.state.state != STATE_RENEWED_PENDING: continue

        # don't send email if this message has already been sent or was inhibited by admin
        # this is done for all events, regardless of what services were 'renewed'
        if senttag in event.tags: continue

        # cancel event
        event.state = State.query.filter_by(state=STATE_CANCELED).one()

        # get canceled email template
        templatestr = (db.session.query(Contract)
                       .filter(Contract.contractTypeId == ContractType.id)
                       .filter(ContractType.contractType == 'race services')
                       .filter(Contract.templateTypeId == TemplateType.id)
                       .filter(TemplateType.templateType == 'canceled email')
                       .one()
                       ).block
        template = Template(templatestr)

        # bring in needed relations
        garbage = event.client

        # merge database fields into template and send email
        # deepcopy getting error AttributeError: 'Race' object has no attribute '_sa_instance_state'
        # so just collect what we need
        mergefields = deepcopy(event.__dict__)

        mergefields['event'] = event.race.race
        mergefields['renew_date'] = event.date

        html = template.render(mergefields)

        subject = 'Automatically canceling {}'.format(event.race.race)
        tolist = app.config['CONTRACTS_CC']
        cclist = None
        fromlist = app.config['CONTRACTS_CONTACT']

        sendmail(subject, fromlist, tolist, html, ccaddr=cclist)

        # mark as sent
        event.tags.append(senttag)

        # pick up all db changes (event.tags)
        db.session.commit()
Example #9
0
def postraceprocessing(startdate, enddate):
#----------------------------------------------------------------------
    '''Sending post-race email and renew race.'''
    # set up tag which is used to control this email
    senttag = Tag.query.filter_by(tag=TAG_POSTRACEMAILSENT).one()
    inhibittag = Tag.query.filter_by(tag=TAG_POSTRACEMAILINHIBITED).one()

    if startdate == 'auto' and enddate == 'auto':
        # processing for races DAYS_POSTRACE_EMAIL days after the event,
        # but if it doesn't happen for some reason will retry for a week
        # calculate start and end date window (try to send for 1 week)
        start = dbdate.dt2asc(date.today() - timedelta(app.config['DAYS_POSTRACE_EMAIL'] + 7))
        end = dbdate.dt2asc(date.today() - timedelta(app.config['DAYS_POSTRACE_EMAIL']))

    # verify both dates are present, check user input format is yyyy-mm-dd
    else:
        if startdate == 'auto' or enddate == 'auto':
            print('ERROR: startdate and enddate must both be specified')
            return

        if (not match(r'^(19[0-9]{2}|2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)$', startdate) or
                not match(r'^(19[0-9]{2}|2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)$', enddate)):
            print('ERROR: startdate and enddate must be in yyyy-mm-dd format')
            return

        # cli specified dates format is fine, and both dates specified
        start = startdate
        end = enddate

    # use filter to get races in which occurred at least N days ago
    events = Event.query.filter(Event.date.between(start, end)).all()

    for event in events:
        # ignore uncommitted events
        if event.state.state != STATE_COMMITTED: continue

        # renew event
        newevent = renew_event(event)
        
        # pick up any db changes related to renewal (renew, daterule, event.tags)
        db.session.commit()

        # don't send email if this message has already been sent or was inhibited by admin
        # don't send email if only premium promotion service
        if senttag in event.tags or inhibittag in event.tags: continue
        if len(event.services) == 1 and event.services[0].service == 'premiumpromotion': continue

        # get post-race mail template
        templatestr = (db.session.query(Contract)
                   .filter(Contract.contractTypeId==ContractType.id)
                   .filter(ContractType.contractType=='race services')
                   .filter(Contract.templateTypeId==TemplateType.id)
                   .filter(TemplateType.templateType=='post-race email')
                   .one()
                  ).block
        template = Template( templatestr )

        # bring in needed relations
        garbage = event.client
        garbage = event.lead
        garbage = event.course

        # merge database fields into template and send email
        # deepcopy getting error AttributeError: 'Race' object has no attribute '_sa_instance_state'
        # so just collect what we need
        mergefields = deepcopy(event.__dict__)

        mergefields['nextyeartext'] = 'for next year'
        mergefields['servicenames'] = [s.service for s in event.services] 
        mergefields['event'] = event.race.race
        # this shouldn't happen, but need to handle case where renew_event couldn't find renewed race
        mergefields['renew_date'] = newevent.date if newevent else '[oops - an error occurred determining race date, please contact us]'

        surveyfields = {
            'eventencoded' : quote_plus(event.race.race),
            'dateencoded'  : quote_plus(event.date),
        }
        surveytemplate = Template( app.config['CONTRACTS_SURVEY_URL'] )
        mergefields['surveylink'] = surveytemplate.render( surveyfields )

        html = template.render( mergefields )

        subject = 'Thank You for using FSRC Race Support Services - {}'.format(event.date)
        tolist = event.client.contactEmail
        cclist = app.config['CONTRACTS_CC']
        fromlist = app.config['CONTRACTS_CONTACT']
        
        sendmail( subject, fromlist, tolist, html, ccaddr=cclist )

        # mark as sent
        event.tags.append(senttag)

        # pick up all db changes (event.tags)
        db.session.commit()
Example #10
0
def leademail(startdate, enddate):
#----------------------------------------------------------------------
    '''Send pre-race email to lead.'''

    # set up tag which is used to control this email
    senttag = Tag.query.filter_by(tag=TAG_LEADEMAILSENT).one()

    # calculate start and end date window
    if startdate == 'auto' and enddate == 'auto':
        # only send for races coming up within DAYS_LEAD_EMAIL in advance of the event,
        # but if it doesn't happen for some reason will retry until event passed
        start = dbdate.dt2asc(date.today())
        end = dbdate.dt2asc(date.today() + timedelta(app.config['DAYS_LEAD_EMAIL']))

    # verify both dates are present, check user input format is yyyy-mm-dd
    else:
        if startdate == 'auto' or enddate == 'auto':
            print('ERROR: startdate and enddate must both be specified')
            return

        if (not match(r'^(19[0-9]{2}|2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)$', startdate) or
                not match(r'^(19[0-9]{2}|2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)$', enddate)):
            print('ERROR: startdate and enddate must be in yyyy-mm-dd format')
            return

        # cli specified dates format is fine, and both dates specified
        start = startdate
        end = enddate

    # use correct filter to get races in next N days
    events = Event.query.filter(Event.date.between(start, end)).all()

    for event in events:
        # ignore uncommitted events
        if event.state.state != STATE_COMMITTED: continue

        # don't send if this message has already been sent
        if senttag in event.tags: continue

        # don't send if only premium promotion service
        if len(event.services) == 1 and event.services[0].service == 'premiumpromotion': continue

        # send pre-race mail to client
        templatestr = (db.session.query(Contract)
                   .filter(Contract.contractTypeId==ContractType.id)
                   .filter(ContractType.contractType=='race services')
                   .filter(Contract.templateTypeId==TemplateType.id)
                   .filter(TemplateType.templateType=='lead email')
                   .one()
                  ).block
        template = Template( templatestr )

        # bring in needed relations
        garbage = event.client
        garbage = event.lead
        garbage = event.course

        # merge database fields into template and send email
        mergefields = deepcopy(event.__dict__)

        mergefields['servicedescrs'] = [s.serviceLong for s in event.services if s.service != 'premiumpromotion']
        mergefields['addlservices'] = [a.longDescr for a in event.addOns]
        mergefields['event'] = event.race.race

        html = template.render( mergefields )

        subject = 'FSRC race reminders for lead: {} - {}'.format(event.race.race, event.date)
        tolist = event.lead.email
        cclist = app.config['CONTRACTS_CC']
        fromlist = app.config['CONTRACTS_CONTACT']
        
        sendmail( subject, fromlist, tolist, html, ccaddr=cclist )

        # mark as sent
        event.tags.append(senttag)
        db.session.commit()