diff --git a/uber/models/__init__.py b/uber/models/__init__.py index 82f196a70..f45869eb5 100644 --- a/uber/models/__init__.py +++ b/uber/models/__init__.py @@ -34,7 +34,7 @@ from uber.errors import HTTPRedirect from uber.decorators import cost_property, department_id_adapter, presave_adjustment, suffix_property from uber.models.types import Choice, DefaultColumn as Column, MultiChoice -from uber.utils import check_csrf, normalize_email, normalize_phone, DeptChecklistConf, report_critical_exception, \ +from uber.utils import check_csrf, normalize_email_legacy, normalize_phone, DeptChecklistConf, report_critical_exception, \ valid_email, valid_password from uber.payments import ReceiptManager @@ -952,7 +952,7 @@ def guess_watchentry_attendees(self, entry): Attendee.watchlist_id == None).all() def get_attendee_account_by_email(self, email): - return self.query(AttendeeAccount).filter_by(email=normalize_email(email)).one() + return self.query(AttendeeAccount).filter_by(normalized_email=normalize_email_legacy(email)).one() def get_admin_account_by_email(self, email): from uber.utils import normalize_email_legacy @@ -967,7 +967,7 @@ def lookup_attendee(self, first_name, last_name, email, zip_code): last_name=last_name, zip_code=zip_code ).filter( - Attendee.normalized_email == normalize_email(email), + Attendee.normalized_email == normalize_email_legacy(email), Attendee.is_valid == True ).limit(10).all() @@ -1041,12 +1041,8 @@ def create_admin_account(self, attendee, password='', generate_pwd=True, **param def create_attendee_account(self, email=None, normalized_email=None, password=None): from uber.models import Attendee, AttendeeAccount - from uber.utils import normalize_email_legacy - - if email: - normalized_email = uber.utils.normalize_email(email) - new_account = AttendeeAccount(email=normalized_email, hashed=bcrypt.hashpw(password, bcrypt.gensalt()) if password else '') + new_account = AttendeeAccount(email=email, hashed=bcrypt.hashpw(password, bcrypt.gensalt()) if password else '') self.add(new_account) return new_account @@ -1058,7 +1054,7 @@ def add_attendee_to_account(self, attendee, account): account.attendees.append(attendee) def match_attendee_to_account(self, attendee): - existing_account = self.query(AttendeeAccount).filter_by(email=normalize_email(attendee.email)).first() + existing_account = self.query(AttendeeAccount).filter_by(normalized_email=normalize_email_legacy(attendee.email)).first() if existing_account: self.add_attendee_to_account(attendee, existing_account) @@ -1607,6 +1603,7 @@ def search(self, text, *filters): attendees = self.query(Attendee) \ .outerjoin(Attendee.group) \ .outerjoin(Attendee.promo_code) \ + .outerjoin(Attendee.managers) \ .outerjoin(aliased_pcg, PromoCode.group) \ .options( joinedload(Attendee.group), @@ -1685,9 +1682,11 @@ def check_text_fields(search_text): target, term, search_term, op = self.parse_attr_search_terms(search_text) if target == 'email': - attr_search_filter = Attendee.normalized_email.icontains(normalize_email(search_term)) + attr_search_filter = Attendee.normalized_email.contains(normalize_email_legacy(search_term)) + elif target == 'account_email': + attr_search_filter = AttendeeAccount.normalized_email.contains(normalize_email_legacy(search_term)) elif target == 'group': - attr_search_filter = Group.name.icontains(search_term.strip()) + attr_search_filter = Group.normalized_name.contains(search_term.strip().lower()) elif target == 'has_ribbon': attr_search_filter = Attendee.ribbon == Attendee.ribbon.type.convert_if_labels(search_term.title()) elif target in Attendee.searchable_bools: diff --git a/uber/models/attendee.py b/uber/models/attendee.py index c530f3c95..c7d2254a4 100644 --- a/uber/models/attendee.py +++ b/uber/models/attendee.py @@ -2158,7 +2158,7 @@ class AttendeeAccount(MagModel): hashed = Column(UnicodeText, private=True) password_reset = relationship('PasswordReset', backref='attendee_account', uselist=False) attendees = relationship( - 'Attendee', backref='managers', cascade='save-update,merge,refresh-expire,expunge', + 'Attendee', backref='managers', order_by='Attendee.registered', cascade='save-update,merge,refresh-expire,expunge', secondary='attendee_attendee_account') imported = Column(Boolean, default=False) @@ -2172,6 +2172,14 @@ def strip_email(self): def normalize_email(self): self.email = normalize_email(self.email) + @hybrid_property + def normalized_email(self): + return normalize_email_legacy(self.email) + + @normalized_email.expression + def normalized_email(cls): + return func.replace(func.lower(func.trim(cls.email)), '.', '') + @property def has_only_one_badge(self): return len(self.attendees) == 1 diff --git a/uber/models/commerce.py b/uber/models/commerce.py index e6aa17fd3..6af21f641 100644 --- a/uber/models/commerce.py +++ b/uber/models/commerce.py @@ -440,7 +440,7 @@ def available_actions(self): @property def refundable(self): - return self.receipt_txn.refundable and not self.comped and not self.reverted + return self.receipt_txn.refundable and not self.comped and not self.reverted and self.amount > 0 @property def cannot_delete_reason(self): diff --git a/uber/models/group.py b/uber/models/group.py index 306c920fd..09c6863f9 100644 --- a/uber/models/group.py +++ b/uber/models/group.py @@ -181,6 +181,14 @@ def floating(self): badges. """ return [a for a in self.attendees if a.is_unassigned and a.paid == c.PAID_BY_GROUP] + + @hybrid_property + def normalized_name(self): + return self.name.strip().lower() + + @normalized_name.expression + def normalized_name(cls): + return func.lower(func.trim(cls.name)) @hybrid_property def is_valid(self): diff --git a/uber/payments.py b/uber/payments.py index a8e84a04b..671487d96 100644 --- a/uber/payments.py +++ b/uber/payments.py @@ -278,6 +278,7 @@ def __init__(self, receipt=None, receipt_email='', description='', amount=0, cus self.receipt_email = receipt_email self.description = description self.customer_id = customer_id + self.refund_str = "refunded" # Set to "voided" when applicable to better inform admins self.intent, self.response, self.receipt_manager = None, None, None self.tracking_id = str(uuid4()) @@ -371,6 +372,7 @@ def stripe_or_authnet_refund(self, txn, amount): if self.response.transactionStatus == "capturedPendingSettlement": if amount != int(self.response.authAmount * 100): return "This transaction cannot be partially refunded until it's settled." + self.refund_str = "voided" error = self.send_authorizenet_txn(txn_type=c.VOID, txn_id=txn.charge_id) elif self.response.transactionStatus != "settledSuccessfully": return "This transaction cannot be refunded because of an invalid status: {}.".format(self.response.transactionStatus) @@ -641,6 +643,7 @@ def get_authorizenet_txn(self, txn_id): def send_authorizenet_txn(self, txn_type=c.AUTHCAPTURE, **params): from decimal import Decimal + payment_profile = None order = None @@ -695,6 +698,7 @@ def send_authorizenet_txn(self, txn_type=c.AUTHCAPTURE, **params): transaction.order = order transaction.transactionType = c.AUTHNET_TXN_TYPES[txn_type] + transaction.customerIP = cherrypy.request.remote.ip if self.amount: transaction.amount = Decimal(int(self.amount) / 100) @@ -815,6 +819,7 @@ def create_new_receipt(cls, model, create_model=False, items=None): for calculation in i[model.__class__.__name__].values(): item = calculation(model) if item: + log.debug(item) try: desc, cost, col_name, count = item except ValueError: diff --git a/uber/receipt_items.py b/uber/receipt_items.py index d441405da..fe33b5056 100644 --- a/uber/receipt_items.py +++ b/uber/receipt_items.py @@ -32,19 +32,19 @@ def overridden_app_cost(app): @cost_calculation.ArtShowApplication def panel_cost(app): - return ("General Panel", c.COST_PER_PANEL * 100, app.panels, None) if app.panels else None + return ("General Panel", c.COST_PER_PANEL * 100, 'panels', app.panels) if app.panels else None @cost_calculation.ArtShowApplication def table_cost(app): - return ("General Table", c.COST_PER_TABLE * 100, app.tables, None) if app.tables else None + return ("General Table", c.COST_PER_TABLE * 100, 'tables', app.tables) if app.tables else None @cost_calculation.ArtShowApplication def mature_panel_cost(app): - return ("Mature Panel", c.COST_PER_PANEL * 100, app.panels_ad, None) if app.panels_ad else None + return ("Mature Panel", c.COST_PER_PANEL * 100, 'panels_ad', app.panels_ad) if app.panels_ad else None @cost_calculation.ArtShowApplication def mature_table_cost(app): - return ("Mature Table", c.COST_PER_TABLE * 100, app.tables_ad, None) if app.tables_ad else None + return ("Mature Table", c.COST_PER_TABLE * 100, 'tables_ad', app.tables_ad) if app.tables_ad else None @cost_calculation.ArtShowApplication def mailing_fee_cost(app): @@ -151,7 +151,7 @@ def badge_cost(group): @cost_calculation.Group def set_cost(group): if not group.auto_recalc: - return ("Custom fee for group {}".format(group.name), group.cost * 100, None) + return ("Custom fee for group {}".format(group.name), group.cost * 100, 'cost') @cost_calculation.Attendee diff --git a/uber/site_sections/art_show_applications.py b/uber/site_sections/art_show_applications.py index 6575e3aed..656ff8a3b 100644 --- a/uber/site_sections/art_show_applications.py +++ b/uber/site_sections/art_show_applications.py @@ -180,7 +180,10 @@ def confirm_pieces(self, session, id, **params): 'Confirmation email sent') def confirmation(self, session, id): - return {'app': session.art_show_application(id)} + return { + 'app': session.art_show_application(id), + 'logged_in_account': session.current_attendee_account(), + } def mailing_address(self, session, message='', **params): app = session.art_show_application(params) diff --git a/uber/site_sections/preregistration.py b/uber/site_sections/preregistration.py index b329175ee..5dbad3e5f 100644 --- a/uber/site_sections/preregistration.py +++ b/uber/site_sections/preregistration.py @@ -24,7 +24,7 @@ from uber.models import Attendee, AttendeeAccount, Attraction, Email, Group, ModelReceipt, PromoCode, PromoCodeGroup, \ ReceiptTransaction, SignedDocument, Tracking from uber.tasks.email import send_email -from uber.utils import add_opt, check, check_pii_consent, localized_now, normalize_email, genpasswd, valid_email, \ +from uber.utils import add_opt, check, check_pii_consent, localized_now, normalize_email, normalize_email_legacy, genpasswd, valid_email, \ valid_password, SignNowDocument, validate_model from uber.payments import PreregCart, TransactionRequest, ReceiptManager @@ -109,12 +109,15 @@ def check_account(session, email, password, confirm_password, skip_if_logged_in= if email and valid_email(email): return valid_email(email) + + super_normalized_old_email = normalize_email_legacy(normalize_email(old_email)) - existing_account = session.query(AttendeeAccount).filter_by(email=normalize_email(email)).first() - if existing_account and (old_email and existing_account.email != normalize_email(old_email) - or logged_in_account and logged_in_account.email != existing_account.email + existing_account = session.query(AttendeeAccount).filter_by(normalized_email=normalize_email_legacy(email)).first() + if existing_account and (old_email and normalize_email_legacy(normalize_email(existing_account.email)) != super_normalized_old_email or not old_email and not logged_in_account): return "There's already an account with that email address." + elif logged_in_account and logged_in_account.normalized_email != existing_account.normalized_email: + return "You cannot reset someone's password while logged in as someone else." if update_password: if password and password != confirm_password: @@ -125,7 +128,7 @@ def check_account(session, email, password, confirm_password, skip_if_logged_in= def set_up_new_account(session, attendee, email=None): email = email or attendee.email token = genpasswd(short=True) - account = session.query(AttendeeAccount).filter_by(email=normalize_email(email)).first() + account = session.query(AttendeeAccount).filter_by(normalized_email=normalize_email_legacy(email)).first() if account: if account.password_reset: session.delete(account.password_reset) @@ -1391,7 +1394,7 @@ def validate_account_email(self, account_email, **params): def login(self, session, **params): email = params.get('account_email') # This email has already been validated password = params.get('account_password') - account = session.query(AttendeeAccount).filter_by(email=normalize_email(email)).first() + account = session.query(AttendeeAccount).filter(AttendeeAccount.normalized_email == normalize_email_legacy(email)).first() if account and not account.hashed: return {'success': False, 'message': "We had an issue logging you into your account. Please contact an administrator."} elif not account or not bcrypt.hashpw(password, account.hashed) == account.hashed: @@ -1403,7 +1406,7 @@ def login(self, session, **params): @ajax def create_account(self, session, **params): email = params.get('account_email') # This email has already been validated - account = session.query(AttendeeAccount).filter_by(email=normalize_email(email)).first() + account = session.query(AttendeeAccount).filter_by(normalized_email=normalize_email_legacy(email)).first() if account: return {'success': False, 'message': "You already have an account. Please use the 'forgot your password' link. \ Keep in mind your account may be from a prior year."} @@ -1429,12 +1432,21 @@ def homepage(self, session, message=''): if receipt and receipt.current_amount_owed and attendee.is_valid: attendees_who_owe_money[attendee.full_name] = receipt.current_amount_owed + account_attendee = None + account_attendees = session.valid_attendees().filter(~Attendee.badge_status.in_([c.REFUNDED_STATUS, c.NOT_ATTENDING]) + ).filter(Attendee.normalized_email == normalize_email_legacy(account.email)) + if account_attendees.count() == 1: + account_attendee = account_attendees.first() + if account_attendee not in account.attendees: + account_attendee = None + if not account: raise HTTPRedirect('../landing/index') return { 'message': message, 'homepage_account': account, + 'account_attendee': account_attendee, 'attendees_who_owe_money': attendees_who_owe_money, } @@ -1446,7 +1458,7 @@ def grant_account(self, session, id, message=''): message = "Something went wrong. Please try again." if not attendee.email: message = "This attendee needs an email address to set up a new account." - if session.current_attendee_account() and normalize_email(attendee.email) == session.current_attendee_account().email: + if session.current_attendee_account() and normalize_email_legacy(attendee.email) == session.current_attendee_account().normalized_email: message = "You cannot grant an account to someone with the same email address as your account." if not message: set_up_new_account(session, attendee) @@ -1821,7 +1833,7 @@ def update_account(self, session, id, **params): def reset_password(self, session, **params): if 'account_email' in params: account_email = params['account_email'] - account = session.query(AttendeeAccount).filter_by(email=normalize_email(account_email)).first() + account = session.query(AttendeeAccount).filter_by(normalized_email=normalize_email_legacy(account_email)).first() if 'admin_url' in params: success_url = "../{}message=Password reset email sent.".format(params['admin_url']) else: @@ -1853,7 +1865,7 @@ def new_password_setup(self, session, account_email, token, message='', **params if 'id' in params: account = session.attendee_account(params['id']) else: - account = session.query(AttendeeAccount).filter_by(email=normalize_email(account_email)).first() + account = session.query(AttendeeAccount).filter_by(normalized_email=normalize_email_legacy(account_email)).first() if not account or not account.password_reset: message = 'Invalid link. This link may have already been used or replaced.' elif account.password_reset.is_expired: @@ -1870,7 +1882,7 @@ def new_password_setup(self, session, account_email, token, message='', **params params.get('confirm_password'), False, True, account.email) if not message: - account.email = account_email + account.email = normalize_email(account_email) account.hashed = bcrypt.hashpw(account_password, bcrypt.gensalt()) session.delete(account.password_reset) for attendee in account.attendees: diff --git a/uber/site_sections/reg_admin.py b/uber/site_sections/reg_admin.py index 59f1999f6..53bc72193 100644 --- a/uber/site_sections/reg_admin.py +++ b/uber/site_sections/reg_admin.py @@ -5,6 +5,7 @@ from datetime import datetime from decimal import Decimal from pockets import groupify +from pockets.autolog import log from six import string_types from sqlalchemy import and_, or_, func from sqlalchemy.orm import joinedload, raiseload, subqueryload @@ -49,8 +50,12 @@ def revert_receipt_item(session, item): receipt_item = ReceiptManager.process_receipt_upgrade_item(model, col_name, receipt=receipt, new_val=item.revert_change[col_name]) session.add(receipt_item) model.apply(item.revert_change, restricted=False) + + error = check(model) + if not error: + session.add(model) - return check(model) + return error def comped_receipt_item(item): @@ -65,7 +70,7 @@ def comped_receipt_item(item): def assign_account_by_email(session, attendee, account_email): from uber.site_sections.preregistration import set_up_new_account - account = session.query(AttendeeAccount).filter_by(email=normalize_email(account_email)).first() + account = session.query(AttendeeAccount).filter_by(normalized_email=normalize_email_legacy(account_email)).first() if not account: if c.ONE_MANAGER_PER_BADGE and attendee.managers: # It's too confusing for an admin to move someone to a new account and still see them on their old account @@ -182,6 +187,7 @@ def remove_receipt_item(self, session, id='', **params): if isinstance(item_or_txn, ReceiptTransaction): for item in item_or_txn.receipt_items: item.closed = None + item.txn_id = None session.add(item) receipt = item_or_txn.receipt @@ -228,7 +234,13 @@ def comp_refund_receipt_item(self, session, id='', **params): error = refund.refund_or_cancel(item.receipt_txn) if error: return {'error': error} - message_add = " and refunded." + + model = session.get_model_by_receipt(item.receipt) + if isinstance(model, Attendee) and model.paid == c.HAS_PAID: + model.paid = c.REFUNDED + session.merge(model) + + message_add = f" and its transaction {refund.refund_str}." session.add_all(refund.get_receipt_items_to_add()) else: message_add = ". Its corresponding transaction was already fully refunded." @@ -254,7 +266,13 @@ def undo_refund_receipt_item(self, session, id='', **params): error = refund.refund_or_cancel(item.receipt_txn) if error: return {'error': error} - message_add = " and refunded." + + model = session.get_model_by_receipt(item.receipt) + if isinstance(model, Attendee) and model.paid == c.HAS_PAID: + model.paid = c.REFUNDED + session.merge(model) + + message_add = f" and its transaction {refund.refund_str}." session.add_all(refund.get_receipt_items_to_add()) else: message_add = ". Its corresponding transaction was already fully refunded." @@ -267,6 +285,7 @@ def undo_refund_receipt_item(self, session, id='', **params): @ajax def add_receipt_txn(self, session, id='', **params): receipt = session.model_receipt(id) + model = session.get_model_by_receipt(item.receipt) message = check_custom_receipt_item_txn(params, is_txn=True) if message: @@ -276,13 +295,17 @@ def add_receipt_txn(self, session, id='', **params): if params.get('txn_type', '') == 'refund': amount = amount * -1 - - session.add(ReceiptTransaction(receipt_id=receipt.id, - amount=amount * 100, - method=params.get('method'), - desc=params['desc'], - who=AdminAccount.admin_name() or 'non-admin' - )) + if isinstance(model, Attendee) and model.paid == c.HAS_PAID: + model.paid = c.REFUNDED + session.add(model) + + new_txn = ReceiptTransaction(receipt_id=receipt.id, + amount=amount * 100, + method=params.get('method'), + desc=params['desc'], + who=AdminAccount.admin_name() or 'non-admin' + ) + session.add(new_txn) try: session.commit() @@ -290,10 +313,13 @@ def add_receipt_txn(self, session, id='', **params): session.rollback() return {'error': "Encountered an exception while trying to save transaction."} - if (receipt.item_total - receipt.txn_total) <= 0: + if (receipt.item_total - receipt.txn_total) <= 0 and amount > 0: for item in receipt.open_receipt_items: + item.txn_id = item.txn_id or new_txn.id item.closed = datetime.now() session.add(item) + if isinstance(model, Attendee) and model.paid == c.NOT_PAID: + model.paid = c.HAS_PAID session.commit() @@ -317,6 +343,7 @@ def cancel_receipt_txn(self, session, id='', **params): txn.cancelled = datetime.now() for item in txn.receipt_items: item.closed = None + item.txn_id = None session.add(item) txn.receipt_items = [] session.commit() @@ -513,7 +540,7 @@ def add_all_accounts(self, session, show_all='', email_contains='', **params): if not show_all: attendees = attendees.filter_by(is_valid=True, is_unassigned=False) if email_contains: - attendees = attendees.filter(Attendee.normalized_email.contains(normalize_email(email_contains))) + attendees = attendees.filter(Attendee.normalized_email.contains(normalize_email_legacy(email_contains))) new_account = 0 assigned = 0 @@ -584,10 +611,10 @@ def attendee_account_form(self, session, id, message='', **params): new_email = params.get('new_account_email', '') if cherrypy.request.method == 'POST' and new_email: - if normalize_email(new_email) == normalize_email(account.email): + if normalize_email(normalize_email_legacy(new_email)) == normalize_email(account.normalized_email): message = "That is already the email address for this account!" else: - existing_account = session.query(AttendeeAccount).filter_by(email=normalize_email(new_email)).first() + existing_account = session.query(AttendeeAccount).filter_by(normalized_email=normalize_email_legacy(new_email)).first() if existing_account: message = "That account already exists. You can instead reassign this account's attendees." else: diff --git a/uber/site_sections/registration.py b/uber/site_sections/registration.py index 089ce0096..c32cd2fed 100644 --- a/uber/site_sections/registration.py +++ b/uber/site_sections/registration.py @@ -72,7 +72,8 @@ def index(self, session, message='', page='0', search_text='', uploaded_id='', o if c.DEV_BOX and not int(page): page = 1 - filter = Attendee.badge_status.in_([c.NEW_STATUS, c.COMPLETED_STATUS, c.WATCHED_STATUS]) if not invalid else None + filter = Attendee.badge_status.in_([c.NEW_STATUS, c.COMPLETED_STATUS, c.WATCHED_STATUS, c.UNAPPROVED_DEALER_STATUS] + ) if not invalid else None attendees = session.query(Attendee) if invalid else session.query(Attendee).filter(filter) total_count = attendees.count() count = 0 diff --git a/uber/tasks/email.py b/uber/tasks/email.py index dd03931a7..cdd671ec0 100644 --- a/uber/tasks/email.py +++ b/uber/tasks/email.py @@ -173,11 +173,12 @@ def send_automated_emails(): automated_emails_by_model = groupify(active_automated_emails, 'model') for model, query_func in AutomatedEmailFixture.queries.items(): - log.info("Sending automated emails for " + model.__name__) + log.debug("Sending automated emails for " + model.__name__) automated_emails = automated_emails_by_model.get(model.__name__, []) + log.debug("Found " + str(len(automated_emails)) + " emails for " + model.__name__) for automated_email in automated_emails: if automated_email.currently_sending: - log.info(automated_email.ident + " is marked as currently sending") + log.debug(automated_email.ident + " is marked as currently sending") if automated_email.last_send_time: if (datetime.now(pytz.UTC) - automated_email.last_send_time) < expiration: # Looks like another thread is still running and hasn't timed out. @@ -189,8 +190,11 @@ def send_automated_emails(): session.commit() unapproved_count = 0 + log.debug("Loading instances for " + automated_email.ident) model_instances = query_func(session) + log.debug("Finished loading instances") for model_instance in model_instances: + log.debug("Checking " + str(model_instance.id)) if model_instance.id not in automated_email.emails_by_fk_id: if automated_email.would_send_if_approved(model_instance): if automated_email.approved or not automated_email.needs_approval: diff --git a/uber/tasks/registration.py b/uber/tasks/registration.py index 40fab5aba..9296d2fda 100644 --- a/uber/tasks/registration.py +++ b/uber/tasks/registration.py @@ -147,18 +147,19 @@ def check_near_cap(): @celery.schedule(timedelta(days=1)) def email_pending_attendees(): - return - already_emailed_accounts = [] with Session() as session: four_days_old = datetime.now(pytz.UTC) - timedelta(hours=96) pending_badges = session.query(Attendee).filter(Attendee.badge_status == c.PENDING_STATUS, - or_(Attendee.registered < datetime.now(pytz.UTC) - timedelta(hours=24)) + Attendee.registered < datetime.now(pytz.UTC) - timedelta(hours=24) ).order_by(Attendee.registered) for badge in pending_badges: - if badge.registered < four_days_old: - session.delete(badge) + # Update `compare_date` to prevent early deletion of badges registered before a certain date + # Implemented for MFF 2023 but let's be honest, we'll probably need it again + compare_date = max(badge.registered, datetime(2023, 9, 12, tzinfo=pytz.UTC)) + if compare_date < four_days_old: + badge.badge_status = c.INVALID_STATUS session.commit() else: if c.ATTENDEE_ACCOUNTS_ENABLED: @@ -178,7 +179,7 @@ def email_pending_attendees(): body = render('emails/reg_workflow/pending_badges.html', {'account': badge.managers[0] if badge.managers else None, - 'attendee': badge}, encoding=None) + 'attendee': badge, 'compare_date': compare_date}, encoding=None) send_email.delay( c.REGDESK_EMAIL, email_to, @@ -188,6 +189,9 @@ def email_pending_attendees(): model=badge.managers[0].to_dict() if c.ATTENDEE_ACCOUNTS_ENABLED else badge.to_dict(), ident=email_ident ) + + if c.ATTENDEE_ACCOUNTS_ENABLED: + already_emailed_accounts.append(email_to) diff --git a/uber/templates/art_show_applications/confirmation.html b/uber/templates/art_show_applications/confirmation.html index 3caf20c37..e380a0ae2 100644 --- a/uber/templates/art_show_applications/confirmation.html +++ b/uber/templates/art_show_applications/confirmation.html @@ -1,9 +1,8 @@ {% extends "./preregistration/preregbase.html" %} {% block title %}Art Show Application Received{% endblock %} -{% block backlink %}{% endblock %} {% block content %} -
-

{% if c.AFTER_ART_SHOW_WAITLIST %}You've been added to our waitlist! +
+

{% if c.AFTER_ART_SHOW_WAITLIST %}You've been added to our waitlist! {% else %}Thanks for applying for the Art Show!{% endif %}

We've received your application for the {{ c.EVENT_NAME }} Art Show. You applied for {{ app.panels }} diff --git a/uber/templates/art_show_applications/edit.html b/uber/templates/art_show_applications/edit.html index c6cc38eb3..1b34d6e95 100644 --- a/uber/templates/art_show_applications/edit.html +++ b/uber/templates/art_show_applications/edit.html @@ -1,11 +1,10 @@ {% extends "preregistration/preregbase.html" %} {% block title %}Art Show Application{% endblock %} -{% block backlink %}{% endblock %} {% block content %} {% include "region_opts.html" %} {% set attendee = app.attendee %} -
-
+
+
Art Show Application Information
diff --git a/uber/templates/art_show_applications/index.html b/uber/templates/art_show_applications/index.html index 96b6371a0..d8277ce12 100644 --- a/uber/templates/art_show_applications/index.html +++ b/uber/templates/art_show_applications/index.html @@ -1,6 +1,5 @@ {% extends "preregistration/preregbase.html" %} {% block title %}Art Show Application{% endblock %} -{% block backlink %}{% endblock %} {% block content %} -
+
-

{{ c.EVENT_NAME }} Art Show Application

+

{{ c.EVENT_NAME }} Art Show Application

{% if c.AFTER_ART_SHOW_DEADLINE and not c.HAS_ART_SHOW_ACCESS %} Unfortunately, the deadline for art show applications has passed and we are no longer accepting applications. {% else %} @@ -66,6 +65,10 @@

Your Information

The confirmation number you received when you registered.

+
+ {% include 'art_show_applications/new_attendee_fields.html' %} +
+

Art Information

{% include 'art_show_applications/art_show_form.html' %} diff --git a/uber/templates/base.html b/uber/templates/base.html index f28510bce..6007c4985 100644 --- a/uber/templates/base.html +++ b/uber/templates/base.html @@ -519,7 +519,9 @@ {% endif %} {% endblock %} {% block header %}{% endblock %} - {% block alert %}{% endblock %} + {% block alert %} + + {% endblock %} {% block masthead %}{% endblock %} {% if title_text %}

{{ title_text }}

{% endif %} {% block content %}{% endblock %} diff --git a/uber/templates/confirm_tabs.html b/uber/templates/confirm_tabs.html index 1106423de..4c44523f8 100644 --- a/uber/templates/confirm_tabs.html +++ b/uber/templates/confirm_tabs.html @@ -45,7 +45,7 @@ {% endfor %} {% for art_show_app in attendee.art_show_applications %} -
{% endif %}
diff --git a/uber/templates/preregistration/homepage.html b/uber/templates/preregistration/homepage.html index cfd285e20..9ec371972 100644 --- a/uber/templates/preregistration/homepage.html +++ b/uber/templates/preregistration/homepage.html @@ -84,16 +84,6 @@

{{ c.EVENT_NAME_AND_YEAR }} Registration {% endif %}

{% endif %} -{% for attendee in account.imported_attendees %} - {% if loop.first %} -

Past Registrations

- {% if not account.valid_attendees %}
{% endif %} - {% endif %} -
- {% include "preregistration/attendee_card.html" %} -
- {% if loop.last and not account.valid_attendees %}
{% endif %} -{% endfor %} {% if not account.valid_attendees %} {% for attendee in account.pending_attendees %} {% if loop.first %} @@ -112,6 +102,16 @@

Pending Registrations

{% endif %} {% endfor %} {% endif %} +{% for attendee in account.imported_attendees %} + {% if loop.first %} +

Past Registrations

+ {% if not account.valid_attendees %}
{% endif %} + {% endif %} +
+ {% include "preregistration/attendee_card.html" %} +
+ {% if loop.last and not account.valid_attendees %}
{% endif %} +{% endfor %} {% for attendee in account.refunded_deferred_attendees %} {% if loop.first %}
@@ -176,4 +176,59 @@

Cancelled Registrations

}); }); + +{# TODO: move this to a script file #} + {% endblock %} diff --git a/uber/templates/preregistration/preregbase.html b/uber/templates/preregistration/preregbase.html index b6b9ea24b..e0d1d651f 100644 --- a/uber/templates/preregistration/preregbase.html +++ b/uber/templates/preregistration/preregbase.html @@ -6,6 +6,8 @@ Admin Form {% elif c.HAS_GROUP_ADMIN_ACCESS and group and not group.is_new %} Admin Form + {% elif c.HAS_ART_SHOW_ADMIN_ACCESS and app and not app.is_new %} + Admin Form {% elif c.CURRENT_ADMIN %} Admin Area {% endif %} @@ -28,7 +30,7 @@ {% endblock %} {% block masthead %} -
{{ c.ORGANIZATION_NAME }}
+
{{ c.ORGANIZATION_NAME }}
{% if homepage_account %}
{% include "preregistration/update_account.html" %}
{% elif logged_in_account %} diff --git a/uber/templates/preregistration/stripeForm.html b/uber/templates/preregistration/stripeForm.html index 4a7dc4dec..020002bc6 100644 --- a/uber/templates/preregistration/stripeForm.html +++ b/uber/templates/preregistration/stripeForm.html @@ -29,8 +29,9 @@ } {% if c.AUTHORIZENET_LOGIN_ID %} +{% set bootstrap5 = 'preregistration' in c.PAGE_PATH or 'landing' in c.PAGE_PATH or admin_area %}