From 972ccc09354d6e3dc21d775c0967f113379323f0 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Fri, 29 Sep 2023 21:29:12 -0400 Subject: [PATCH 01/27] Update art show emails and application text Fixes SEI-SD 1509, 1511, 1529, 1510, and 1512. Adds days_between to help adjust art show emails' dates to the desired dates. Also improves the automated emails page's formatting, adds a blurb explaining automated emails, and adds buttons to let you quickly go to emails for a specific department. --- uber/automated_emails.py | 6 +- uber/site_sections/art_show_applications.py | 2 +- .../art_show_applications/index.html | 20 +++-- uber/templates/email_admin/pending.html | 59 ++++++++------ uber/templates/emails/art_show/approved.html | 4 +- .../templates/emails/art_show/mailing_in.html | 8 +- .../emails/art_show/payment_reminder.txt | 9 +-- uber/utils.py | 79 ++++++++++++++++++- 8 files changed, 136 insertions(+), 51 deletions(-) diff --git a/uber/automated_emails.py b/uber/automated_emails.py index 973105218..2b491b85c 100644 --- a/uber/automated_emails.py +++ b/uber/automated_emails.py @@ -26,7 +26,7 @@ from uber.models import AdminAccount, Attendee, AttendeeAccount, ArtShowApplication, AutomatedEmail, Department, Group, \ GuestGroup, IndieGame, IndieJudge, IndieStudio, MarketplaceApplication, MITSTeam, MITSApplicant, PanelApplication, \ PanelApplicant, PromoCodeGroup, Room, RoomAssignment, Shift -from uber.utils import after, before, days_after, days_before, localized_now, DeptChecklistConf +from uber.utils import after, before, days_after, days_before, days_between, localized_now, DeptChecklistConf class AutomatedEmailFixture: @@ -309,7 +309,7 @@ def __init__(self, subject, template, filter, ident, **kwargs): 'Reminder to pay for your {EVENT_NAME} Art Show application', 'art_show/payment_reminder.txt', lambda a: a.status == c.APPROVED and a.is_unpaid, - when=days_before(14, c.ART_SHOW_PAYMENT_DUE), + when=days_between((14, c.ART_SHOW_PAYMENT_DUE), (1, c.EPOCH)), ident='art_show_payment_reminder') ArtShowAppEmailFixture( @@ -330,7 +330,7 @@ def __init__(self, subject, template, filter, ident, **kwargs): '{EVENT_NAME} Art Show MAIL IN Instructions', 'art_show/mailing_in.html', lambda a: a.status == c.APPROVED and not a.is_unpaid and a.delivery_method == c.BY_MAIL, - when=days_before(40, c.ART_SHOW_DEADLINE), + when=days_between((c.ART_SHOW_REG_START, 13), (16, c.ART_SHOW_WAITLIST)), ident='art_show_mail_in') diff --git a/uber/site_sections/art_show_applications.py b/uber/site_sections/art_show_applications.py index a45dc4681..bd0d266f5 100644 --- a/uber/site_sections/art_show_applications.py +++ b/uber/site_sections/art_show_applications.py @@ -19,7 +19,7 @@ def index(self, session, message='', **params): ignore_csrf=True) attendee = None - if not c.ART_SHOW_OPEN: + if not c.ART_SHOW_OPEN and not c.DEV_BOX: return render('static_views/art_show_closed.html') if c.AFTER_ART_SHOW_DEADLINE \ else render('static_views/art_show_not_open.html') diff --git a/uber/templates/art_show_applications/index.html b/uber/templates/art_show_applications/index.html index f0265382b..16ada7fdd 100644 --- a/uber/templates/art_show_applications/index.html +++ b/uber/templates/art_show_applications/index.html @@ -16,26 +16,32 @@

{{ c.EVENT_NAME }} Art Show Application

+ {% if c.DEV_BOX %} +
+ You are on a development box. + {% if c.BEFORE_ART_SHOW_REG_START %} + Otherwise, you would be automatically redirected to the "art show reg not yet open" page. + {% elif c.AFTER_ART_SHOW_DEADLINE and not c.AT_THE_CON %} + Otherwise, you would be automatically redirected to the "art show reg closed" page. + {% endif %} + +
+ {% endif %} {% 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 %} - {% if c.AFTER_ART_SHOW_DEADLINE and c.HAS_ART_SHOW_ACCESS %} -

- Art show applications have closed, but because you are a logged in - administrator you can submit a new application using this form. -

- {% endif %} {% if c.AFTER_ART_SHOW_WAITLIST %}

The deadline for art show applications has passed. You may still submit an application to be put on our waiting list. Applications will close completely on {{ c.ART_SHOW_DEADLINE|datetime_local }}. + Space is limited and may be filled prior to the application window closing.

{% endif %}

Art show applications are due by {{ c.ART_SHOW_WAITLIST|datetime_local }}. Any applications submitted after this date will be automatically waitlisted. Applications will close completely on {{ c.ART_SHOW_DEADLINE|datetime_local }}. Please review the {{ c.EVENT_NAME }} Art Show rules - here.

+ here. Space is limited and may be filled prior to the application window closing.

Your Information

diff --git a/uber/templates/email_admin/pending.html b/uber/templates/email_admin/pending.html index 45ce5e3d6..818990814 100644 --- a/uber/templates/email_admin/pending.html +++ b/uber/templates/email_admin/pending.html @@ -2,25 +2,6 @@ {% block title %}Automated Emails Pending Approval{% endblock %} {% block content %} - - - {% macro email_table(emails) %} Template - - + + - + @@ -83,18 +64,44 @@
Sender Emails SentEmails waiting to send but need approvalShow ExamplesEmails Waiting to SendExamples Approval StatusDate emails generatedDate Restrictions
{% endmacro %} -

Automated Emails

-
+

Pending Automated Emails

+
+
{% if not automated_emails %}

There are currently no automated emails. The system is probably updating, - and should be finished in at most 5 minutes. + and should be finished in at most {{ "5" if c.DEV_BOX else "15" }} minutes.

{% else %} +

+ The emails below will be sent to any qualifying attendee or group as long as that email is active and approved. + Attendees or groups who qualify for an email before it is approved will receive the email when it is approved. +

+

+ If there are date restrictions for an email, that email will not be sent outside of those dates. + Emails may be "unapproved" after approval to stop them being sent to newly qualifying attendees or groups. +

+

+ Please note that the emails below represent most, but not all, of the automated emails the system sends. + Any emails that don't appear here are sent in response to an action (e.g., a dealer changing their application) and cannot be approved or unapproved. +

+ +
{% for sender, emails in automated_emails.items() %} -

{{ sender }}

+ +

{{ sender }}

{{ email_table(emails) }} + {% if not loop.last %}
{% endif %} {% endfor %} {% endif %} +
+
+ {% endblock %} diff --git a/uber/templates/emails/art_show/approved.html b/uber/templates/emails/art_show/approved.html index 1cc3f02c8..4d06d08b3 100644 --- a/uber/templates/emails/art_show/approved.html +++ b/uber/templates/emails/art_show/approved.html @@ -15,8 +15,8 @@ {% if app.attendee.badge_status == c.NOT_ATTENDING %}

- As a reminder, you have indicated that you are not attending {{ c.EVENT_NAME }}. As such, you will need to contact - the art show staff at {{ c.ART_SHOW_EMAIL }} to coordinate sending your art. + As a reminder, you have indicated that you are not attending {{ c.EVENT_NAME }}. + You will receive an email with Mail in Instructions closer to the convention. {% endif %} {% if app.agent_code %} diff --git a/uber/templates/emails/art_show/mailing_in.html b/uber/templates/emails/art_show/mailing_in.html index c8755c19d..70b873b0e 100644 --- a/uber/templates/emails/art_show/mailing_in.html +++ b/uber/templates/emails/art_show/mailing_in.html @@ -22,13 +22,13 @@
  • PREPAID Return label to:
    Midwest Art Show -
    c/o Carol Gobeyn -
    607 Lilac Way +
    c/o Jacob Dawson +
    46 N Elizabeth St
    Lombard, IL 60148
    All art must be shipped via trackable means both ways. DO NOT SEND SIGNATURE REQUIRED. -
    Deadline to receive mail-in packages is Wednesday, November 23rd. +
    Deadline to receive mail-in packages is Wednesday, November 22nd.
  • @@ -36,7 +36,7 @@ Name, Tracking Number and shipper name.

    I will send back any unsold Art via your prepaid label on Monday, -December 5th. If all of your art sells we will send back your prepaid +December 4th. If all of your art sells we will send back your prepaid label, receipt and the check for your sales during the week after the convention.

    Thank you, diff --git a/uber/templates/emails/art_show/payment_reminder.txt b/uber/templates/emails/art_show/payment_reminder.txt index 85736fbbf..9bd0f24cb 100644 --- a/uber/templates/emails/art_show/payment_reminder.txt +++ b/uber/templates/emails/art_show/payment_reminder.txt @@ -1,10 +1,9 @@ {{ app.attendee.first_name }}, -Thanks again for applying to present in the Art Show for this year's {{ c.EVENT_NAME }}. Our records indicate that your -Art Show application is still unpaid, and if we do not receive payment by {{ c.ART_SHOW_PAYMENT_DUE|datetime_local }} then it will be -deleted. +Thanks again for applying to present in the Art Show for this year's {{ c.EVENT_NAME }}. Our records indicate that your Art Show application is still unpaid, and if we do not receive payment by {{ c.ART_SHOW_PAYMENT_DUE|datetime_local }} then it will be deleted. -You can use the credit card button on your application's page to {% if group.amount_pending %}finish your payment of {{ (group.amount_pending / 100)|format_currency }}{% else %}pay the {{ group.amount_unpaid|format_currency }} that you owe{% endif %}: -{{ c.URL_BASE }}/art_show_applications/edit?id={{ app.id }} +You can use the credit card button on your application's page to {% if group.amount_pending %}finish your payment of {{ (group.amount_pending / 100)|format_currency }}{% else %}pay the {{ group.amount_unpaid|format_currency }} that you owe{% endif %}: {{ c.URL_BASE }}/art_show_applications/edit?id={{ app.id }} + +If you are having issues with payment or need an extension please contact us at {{ c.ART_SHOW_EMAIL|email_only }}. {{ c.ART_SHOW_EMAIL_SIGNATURE }} diff --git a/uber/utils.py b/uber/utils.py index b895c0f16..a47f49178 100644 --- a/uber/utils.py +++ b/uber/utils.py @@ -392,7 +392,7 @@ def __init__(self, days, deadline): days = 0 if days < 0: - raise ValueError("'days' paramater must be >= 0. days={}".format(days)) + raise ValueError("'days' parameter must be >= 0. days={}".format(days)) self.starting_date = None if not deadline else deadline + timedelta(days=days) @@ -422,10 +422,10 @@ class days_before(DateBase): """ def __init__(self, days, deadline, until=None): if days <= 0: - raise ValueError("'days' paramater must be > 0. days={}".format(days)) + raise ValueError("'days' parameter must be > 0. days={}".format(days)) if until and days <= until: - raise ValueError("'days' paramater must be less than 'until'. days={}, until={}".format(days, until)) + raise ValueError("'days' parameter must be less than 'until'. days={}, until={}".format(days, until)) self.days, self.deadline, self.until = days, deadline, until @@ -462,6 +462,79 @@ def active_when(self): return 'between {} and {}'.format(start_txt, end_txt) +class days_between(DateBase): + """ + Returns true if today is between two deadlines, with optional values for days before and after each deadline. + + :param: days - number of days before deadline to start + :param: deadline - datetime of the deadline + :param: until - (optional) number of days prior to deadline to end (default: 0) + + Examples: + days_between((14, c.POSITRON_BEAM_DEADLINE), (5, c.EPOCH))() - True if it's 14 days before c.POSITRON_BEAM_DEADLINE and 5 days before c.EPOCH + days_between((c.WARP_COIL_DEADLINE, 5), c.EPOCH)() - True if it's 5 days after c.WARP_COIL_DEADLINE up to c.EPOCH + """ + def __init__(self, first_deadline_tuple, second_deadline_tuple): + self.errors = [] + + self.starting_date = self.process_deadline_tuple(first_deadline_tuple) + self.ending_date = self.process_deadline_tuple(second_deadline_tuple) + + if self.errors: + raise ValueError(f"{' '.join(self.errors)} Please use the following format: \ + optional days_before(int), deadline(datetime), optional days_after(int). \ + Note that you cannot set both days_before and days_after.") + + assert self.starting_date < self.ending_date + + def process_deadline_tuple(self, deadline_tuple): + days_before, deadline, days_after = None, None, None + + try: + first_val, second_val = deadline_tuple + if isinstance(first_val, int) and isinstance(second_val, int): + self.errors.append(f"Couldn't find a deadline in the tuple: {deadline_tuple}.") + return + elif isinstance(first_val, int): + days_before, deadline, days_after = first_val, second_val, 0 + elif isinstance(second_val, int): + days_before, deadline, days_after = 0, first_val, second_val + else: + self.errors.append(f"Malformed tuple: {deadline_tuple}.") + return + except TypeError: + days_before, deadline, days_after = 0, deadline_tuple, 0 + + if days_before: + return deadline - timedelta(days=days_before) + else: + return deadline + timedelta(days=days_after) + + def __call__(self): + if not self.starting_date or not self.ending_date: + return False + + return self.starting_date < self.now() < self.ending_date + + @property + def active_after(self): + return self.starting_date + + @property + def active_before(self): + return self.ending_date + + @property + def active_when(self): + if not self.starting_date or not self.ending_date: + return '' + + start_txt = self.starting_date.strftime(self._when_dateformat) + end_txt = self.ending_date.strftime(self._when_dateformat) + + return 'between {} and {}'.format(start_txt, end_txt) + + # ====================================================================== # Security # ====================================================================== From d48c05cbf449b633cf0ee482bbcb42626a592f43 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Fri, 29 Sep 2023 21:53:18 -0400 Subject: [PATCH 02/27] Improve handling of SSO accounts Apparently when an SSO account was provisioned, the staffer would get an email asking them to set their password. This stops that, prevents password reset emails from getting sent to SSO accounts, and removes the Account Settings option from SSO accounts. --- uber/automated_emails.py | 2 +- uber/models/__init__.py | 5 +-- uber/models/attendee.py | 6 ++++ uber/site_sections/preregistration.py | 36 ++++++++++++------- .../preregistration/update_account.html | 4 +++ 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/uber/automated_emails.py b/uber/automated_emails.py index 2b491b85c..82bc0d4c5 100644 --- a/uber/automated_emails.py +++ b/uber/automated_emails.py @@ -166,7 +166,7 @@ def body(self): AttendeeAccount, '{EVENT_NAME} account creation confirmed', 'reg_workflow/account_confirmation.html', - lambda a: not a.imported and a.hashed and not a.password_reset, + lambda a: not a.imported and a.hashed and not a.password_reset and not a.is_sso_account, needs_approval=False, allow_at_the_con=True, ident='attendee_account_confirmed') diff --git a/uber/models/__init__.py b/uber/models/__init__.py index 40a31188a..e60251dd7 100644 --- a/uber/models/__init__.py +++ b/uber/models/__init__.py @@ -1069,10 +1069,7 @@ def create_attendee_account(self, email=None, password=None): def add_attendee_to_account(self, attendee, account): from uber.utils import normalize_email - unclaimed_account = account.hashed != '' - if c.SSO_EMAIL_DOMAINS: - local, domain = normalize_email(account.email, split_address=True) - unclaimed_account = unclaimed_account and domain not in c.SSO_EMAIL_DOMAINS + unclaimed_account = account.hashed != '' and not account.is_sso_account if c.ONE_MANAGER_PER_BADGE and attendee.managers and not unclaimed_account: attendee.managers.clear() diff --git a/uber/models/attendee.py b/uber/models/attendee.py index 915babe9e..2f1b6a55b 100644 --- a/uber/models/attendee.py +++ b/uber/models/attendee.py @@ -2175,6 +2175,12 @@ def normalized_email(self): def normalized_email(cls): return func.replace(func.lower(func.trim(cls.email)), '.', '') + @property + def is_sso_account(self): + if c.SSO_EMAIL_DOMAINS: + local, domain = normalize_email(self.email, split_address=True) + return domain in c.SSO_EMAIL_DOMAINS + @property def has_only_one_badge(self): return len(self.attendees) == 1 diff --git a/uber/site_sections/preregistration.py b/uber/site_sections/preregistration.py index fbeaca029..cb4535416 100644 --- a/uber/site_sections/preregistration.py +++ b/uber/site_sections/preregistration.py @@ -128,17 +128,19 @@ def set_up_new_account(session, attendee, email=None): else: account = session.create_attendee_account(email) session.add_attendee_to_account(attendee, account) - session.add(PasswordReset(attendee_account=account, hashed=bcrypt.hashpw(token, bcrypt.gensalt()))) - - body = render('emails/accounts/new_account.html', { - 'attendee': attendee, 'account_email': email, 'token': token}, encoding=None) - send_email.delay( - c.ADMIN_EMAIL, - email, - c.EVENT_NAME + ' Account Setup', - body, - format='html', - model=account.to_dict('id')) + + if not account.is_sso_account: + session.add(PasswordReset(attendee_account=account, hashed=bcrypt.hashpw(token, bcrypt.gensalt()))) + + body = render('emails/accounts/new_account.html', { + 'attendee': attendee, 'account_email': email, 'token': token}, encoding=None) + send_email.delay( + c.ADMIN_EMAIL, + email, + c.EVENT_NAME + ' Account Setup', + body, + format='html', + model=account.to_dict('id')) @all_renderable(public=True) @check_post_con @@ -1811,15 +1813,25 @@ def reset_password(self, session, **params): 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']) + sso_url = "../{}message=SSO accounts do not have passwords.".format(params['admin_url']) else: success_url = "../landing/index?message=Check your email for a password reset link." + sso_url = "../landing/index?message=Please log in via the staff login link!" if not account: # Avoid letting attendees de facto search for other attendees by email + if c.SSO_EMAIL_DOMAINS: + local, domain = normalize_email(account_email, split_address=True) + if domain in c.SSO_EMAIL_DOMAINS: + raise HTTPRedirect(sso_url) raise HTTPRedirect(success_url) + if account.password_reset: session.delete(account.password_reset) session.commit() - + + if account.is_sso_account: + raise HTTPRedirect(sso_url) + token = genpasswd(short=True) session.add(PasswordReset(attendee_account=account, hashed=bcrypt.hashpw(token, bcrypt.gensalt()))) diff --git a/uber/templates/preregistration/update_account.html b/uber/templates/preregistration/update_account.html index c2cfbb01e..788362b72 100644 --- a/uber/templates/preregistration/update_account.html +++ b/uber/templates/preregistration/update_account.html @@ -1,7 +1,9 @@ {% import "forms/account.html" as account_fields with context %} +{% if not homepage_account.is_sso_account %} +{% endif %} {% if c.PAGE_PATH != '/preregistration/homepage' %} Go to Homepage {% endif %} @@ -9,6 +11,7 @@ Log Out

    +{% if not homepage_account.is_sso_account %}
    @@ -48,5 +51,6 @@
    +{% endif %} {{ account_fields.new_password_validation }} \ No newline at end of file From d3a81759c0fbdac16177c9ad8675bb137af34284 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Sat, 30 Sep 2023 19:06:29 -0400 Subject: [PATCH 03/27] Fix 500 errors with payment reminder email This was a copy-paste error, whoops --- uber/templates/emails/art_show/payment_reminder.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uber/templates/emails/art_show/payment_reminder.txt b/uber/templates/emails/art_show/payment_reminder.txt index 9bd0f24cb..8f92bf940 100644 --- a/uber/templates/emails/art_show/payment_reminder.txt +++ b/uber/templates/emails/art_show/payment_reminder.txt @@ -2,7 +2,7 @@ Thanks again for applying to present in the Art Show for this year's {{ c.EVENT_NAME }}. Our records indicate that your Art Show application is still unpaid, and if we do not receive payment by {{ c.ART_SHOW_PAYMENT_DUE|datetime_local }} then it will be deleted. -You can use the credit card button on your application's page to {% if group.amount_pending %}finish your payment of {{ (group.amount_pending / 100)|format_currency }}{% else %}pay the {{ group.amount_unpaid|format_currency }} that you owe{% endif %}: {{ c.URL_BASE }}/art_show_applications/edit?id={{ app.id }} +You can use the credit card button on your application's page to {% if app.attendee.amount_pending %}finish your payment of {{ (app.attendee.amount_pending / 100)|format_currency }}{% else %}pay the {{ app.attendee.amount_unpaid|format_currency }} that you owe{% endif %}: {{ c.URL_BASE }}/art_show_applications/edit?id={{ app.id }} If you are having issues with payment or need an extension please contact us at {{ c.ART_SHOW_EMAIL|email_only }}. From 6100666f3e4465da1eba58cd7f9c4d55384ad836 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Sat, 30 Sep 2023 19:15:17 -0400 Subject: [PATCH 04/27] Update agent instructions The agent code box isn't available during prereg this year so this removes the reference to it. --- uber/templates/emails/art_show/agent_code.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uber/templates/emails/art_show/agent_code.html b/uber/templates/emails/art_show/agent_code.html index b994f7f18..8f81285f9 100644 --- a/uber/templates/emails/art_show/agent_code.html +++ b/uber/templates/emails/art_show/agent_code.html @@ -9,8 +9,8 @@

    To assign an agent to your art application, send them the above code. -They must then add the code to their registration, either while signing up or -afterwards by {% if c.ATTENDEE_ACCOUNTS_ENABLED %}logging in{% else %}using the confirmation link they received by email when they +They must then add the code to their registration by +{% if c.ATTENDEE_ACCOUNTS_ENABLED %}logging in and updating their badge details after registering{% else %}using the confirmation link they received by email when they registered{% endif %}. You can check your Art Show application at any time to see your agent's status or assign a new agent. From d2bb267773d90f04430db7e937c00b49457c7c2e Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Sun, 1 Oct 2023 10:31:58 -0400 Subject: [PATCH 05/27] Fix price display for art show apps If you had an overridden price and a mailing fee, but no receipt had been generated, we only showed the override price. This fixes that. --- uber/models/art_show.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/uber/models/art_show.py b/uber/models/art_show.py index 152614e73..57224785e 100644 --- a/uber/models/art_show.py +++ b/uber/models/art_show.py @@ -138,10 +138,7 @@ def total_cost(self): @property def potential_cost(self): - if self.overridden_price is not None: - return self.overridden_price - else: - return self.default_cost or 0 + return self.default_cost or 0 def calc_app_price_change(self, **kwargs): preview_app = ArtShowApplication(**self.to_dict()) From 3e130a4409e410abf1516496061c0b95fe10551a Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Mon, 2 Oct 2023 22:15:14 -0400 Subject: [PATCH 06/27] Fix receipt updating for paid-by-group changes Attendee receipts will now update correctly when you change their "paid" status off of "paid by group" --- uber/models/attendee.py | 8 ++++---- uber/receipt_items.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/uber/models/attendee.py b/uber/models/attendee.py index 2f1b6a55b..c240e437e 100644 --- a/uber/models/attendee.py +++ b/uber/models/attendee.py @@ -1030,13 +1030,13 @@ def calc_promo_discount_change(self, promo_code): def calc_badge_comp_change(self, paid): preview_attendee = Attendee(**self.to_dict()) paid = int(paid) - comped_or_refunded = [c.NEED_NOT_PAY, c.REFUNDED] + free_badge_statuses = [c.NEED_NOT_PAY, c.REFUNDED, c.PAID_BY_GROUP] preview_attendee.paid = paid - if paid != c.NEED_NOT_PAY and self.paid != c.NEED_NOT_PAY: + if paid not in free_badge_statuses and self.paid not in free_badge_statuses: return 0, 0 - elif self.paid in comped_or_refunded and paid in comped_or_refunded: + elif self.paid in free_badge_statuses and paid in free_badge_statuses: return 0, 0 - elif paid == c.NEED_NOT_PAY: + elif paid in free_badge_statuses: return 0, self.badge_cost * -1 * 100 else: badge_cost = preview_attendee.calculate_badge_cost() * 100 diff --git a/uber/receipt_items.py b/uber/receipt_items.py index a1451c733..1ef3c2c6e 100644 --- a/uber/receipt_items.py +++ b/uber/receipt_items.py @@ -71,7 +71,7 @@ def mailing_fee_cost(app): } Attendee.credit_changes = { - 'paid': ('Badge Comp', "calc_badge_comp_change"), + 'paid': ('Badge Comped or Paid By Group', "calc_badge_comp_change"), 'birthdate': ('Age Discount', "calc_age_discount_change"), 'promo_code': ('Promo Code', "calc_promo_discount_change"), } From 9f4c6bd14db0cd2bbe0387dd1c0e267a14fbaad2 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Mon, 2 Oct 2023 22:26:43 -0400 Subject: [PATCH 07/27] Correctly set status for people not paid by group --- uber/models/attendee.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/uber/models/attendee.py b/uber/models/attendee.py index c240e437e..30a9a2ea1 100644 --- a/uber/models/attendee.py +++ b/uber/models/attendee.py @@ -510,11 +510,12 @@ def _status_adjustments(self): elif self.group.is_dealer and self.group.status != c.APPROVED: self.badge_status = c.UNAPPROVED_DEALER_STATUS - if self.badge_status == c.INVALID_GROUP_STATUS and (not self.group or self.group.is_valid): + if self.badge_status == c.INVALID_GROUP_STATUS and (not self.group or self.group.is_valid or self.paid != c.PAID_BY_GROUP): self.badge_status = c.NEW_STATUS if self.badge_status == c.UNAPPROVED_DEALER_STATUS and (not self.group or not self.group.is_dealer or + self.paid != c.PAID_BY_GROUP or self.group.status == c.APPROVED): self.badge_status = c.NEW_STATUS @@ -536,7 +537,7 @@ def _status_adjustments(self): elif self.badge_status == c.NEW_STATUS and not self.placeholder and self.first_name and ( self.paid in [c.HAS_PAID, c.NEED_NOT_PAY, c.REFUNDED] or self.paid == c.PAID_BY_GROUP - and self.group_id + and self.group and not self.group.is_unpaid): self.badge_status = c.COMPLETED_STATUS @@ -983,8 +984,6 @@ def calc_badge_cost_change(self, **kwargs): new_cost = preview_attendee.calculate_badge_prices_cost(self.badge_type) * 100 if 'ribbon' in kwargs: add_opt(preview_attendee.ribbon_ints, int(kwargs['ribbon'])) - if 'paid' in kwargs: - preview_attendee.paid = int(kwargs['paid']) current_cost = self.calculate_badge_cost() * 100 if not new_cost: From f2d29715acc29ac78c168cce8e5e9745d9005c33 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Thu, 5 Oct 2023 01:54:20 -0400 Subject: [PATCH 08/27] Fix 500 error when changing account email Also updates the account settings HTML because I was sick of looking at it. --- uber/site_sections/preregistration.py | 2 +- .../preregistration/update_account.html | 47 +++++++++---------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/uber/site_sections/preregistration.py b/uber/site_sections/preregistration.py index cb4535416..b18139800 100644 --- a/uber/site_sections/preregistration.py +++ b/uber/site_sections/preregistration.py @@ -108,7 +108,7 @@ def check_account(session, email, password, confirm_password, skip_if_logged_in= 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: + elif existing_account and 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: diff --git a/uber/templates/preregistration/update_account.html b/uber/templates/preregistration/update_account.html index 788362b72..ba06901d0 100644 --- a/uber/templates/preregistration/update_account.html +++ b/uber/templates/preregistration/update_account.html @@ -12,45 +12,44 @@
    {% if not homepage_account.is_sso_account %} -
    +  +
    +
    -
    + {{ csrf_token() }} -
    - -
    - +
    +
    + +

    -
    - -
    +
    +
    +
    -
    - -
    +
    +
    + + {{ account_fields.password_help }}
    - {{ account_fields.password_help }} -
    -
    - -
    +
    +
    -
    - -
    +
    +
    -{% endif %} -{{ account_fields.new_password_validation }} \ No newline at end of file +{{ account_fields.new_password_validation }} +{% endif %} \ No newline at end of file From 7a4c0481ebcf218dc79f07b15ae0ff908d1c3d23 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Thu, 5 Oct 2023 02:17:56 -0400 Subject: [PATCH 09/27] Fix dealers unsetting auto_recalc Somehow we were loading the dealer preregistration page with admin forms and it wasn't apparent until we found someone whose receipt was affected. Also hopefully fixes a bug where the system would decide you were adding extra badges when you tried to pay, although I can't reproduce it so it's not a sure thing. --- uber/site_sections/preregistration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uber/site_sections/preregistration.py b/uber/site_sections/preregistration.py index b18139800..bd2830175 100644 --- a/uber/site_sections/preregistration.py +++ b/uber/site_sections/preregistration.py @@ -956,9 +956,9 @@ def group_members(self, session, id, message='', **params): group = session.group(id) if group.is_dealer: - form_list = ['AdminTableInfo', 'ContactInfo'] + form_list = ['TableInfo', 'ContactInfo'] else: - form_list = ['AdminGroupInfo'] + form_list = ['GroupInfo'] forms = load_forms(params, group, group_forms, form_list) for form in forms.values(): From ec09a983385848f5364785be10af27fb418b5905 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Thu, 5 Oct 2023 02:21:50 -0400 Subject: [PATCH 10/27] Display updates and fixes Makes a bunch of stuff look better, mostly by adding missing divs. --- .../art_show_common/art_show_agent.html | 17 ++++++----- uber/templates/email_admin/sent.html | 4 ++- uber/templates/forms/group.html | 2 +- uber/templates/group_admin/form.html | 3 +- uber/templates/group_admin/index.html | 2 ++ uber/templates/preregistration/confirm.html | 8 ++--- .../preregistration/update_account.html | 30 ++++++++++++------- 7 files changed, 41 insertions(+), 25 deletions(-) diff --git a/uber/templates/art_show_common/art_show_agent.html b/uber/templates/art_show_common/art_show_agent.html index 0264ae5ae..595987974 100644 --- a/uber/templates/art_show_common/art_show_agent.html +++ b/uber/templates/art_show_common/art_show_agent.html @@ -1,8 +1,8 @@ -
    -
    - -
    - + +
    +
    + +

    {% if attendee.art_agent_applications %} You are currently an agent for the following artists:

      {% for app in attendee.art_agent_applications %} @@ -11,9 +11,12 @@ {% else %} You are not an agent for any artists in the {{ c.EVENT_NAME }} Art Show. {% endif %} - +

      +
    +
    + +
    -
    diff --git a/uber/templates/email_admin/sent.html b/uber/templates/email_admin/sent.html index 9b539a90e..88794adf6 100644 --- a/uber/templates/email_admin/sent.html +++ b/uber/templates/email_admin/sent.html @@ -5,6 +5,7 @@ {% for email in emails %}
    +

    {{ email.subject }} ({{ email.when|full_datetime_local }})

    To: {% if email.fk_id %} @@ -19,7 +20,8 @@

    To: -

    +
    +

    {% endfor %} {{ "js/resend-email-form.js"|serve_static_content }} diff --git a/uber/templates/forms/group.html b/uber/templates/forms/group.html index 01a535357..f539aa523 100644 --- a/uber/templates/forms/group.html +++ b/uber/templates/forms/group.html @@ -71,7 +71,7 @@
  • {{ (group.amount_paid / 100)|format_currency or '$0' }} paid{% if group.amount_unpaid %} so far
  • {{ group.amount_unpaid|format_currency }} unpaid
  • -
    {{ stripe_form('process_group_payment', group) }} +

    {{ stripe_form('process_group_payment', group) }}

    {% else %} {% if receipt and receipt.current_amount_owed and incomplete_txn %}

    diff --git a/uber/templates/group_admin/form.html b/uber/templates/group_admin/form.html index d047d32c0..3fcb352e8 100644 --- a/uber/templates/group_admin/form.html +++ b/uber/templates/group_admin/form.html @@ -7,7 +7,7 @@ {% include "check_in.html" %}
    - +
    {% if not group.is_new %}
    @@ -167,6 +167,7 @@

    Marketplace Info

    {% endif %}
    +
    {{ "js/window-hash-tabload.js"|serve_static_content }} {% if group.is_new %} @@ -65,7 +69,7 @@ {{ group_fields.signed_document }}

    "{{ group.name }}" Information

    {{ form_macros.form_validation('group-form', 'validate_dealer' if group.is_dealer else 'validate_group') }} -
    + {% if forms and 'group_info' in forms %} {% include "forms/group_info.html" %} @@ -74,12 +78,12 @@

    "{{ group.name }}" Information

    {% include "forms/contact_info.html" %} {% endif %} {% include "groupextra.html" %} - {% if not page_ro %} + {% if group.status in c.DEALER_EDITABLE_STATUSES %} {% endif %}
    -
    +
    {% endif%} From 5fb38a8bdc82113119357e2bbfb07bd5b8653654 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Fri, 6 Oct 2023 21:55:07 -0400 Subject: [PATCH 17/27] Fix "assign your badges" text in dealer emails unassigned_badges is not a property, so this text never showed up. --- uber/templates/emails/dealers/approved.html | 2 +- uber/templates/emails/dealers/payment_confirmation.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uber/templates/emails/dealers/approved.html b/uber/templates/emails/dealers/approved.html index e4b901ec5..ee1fcc309 100644 --- a/uber/templates/emails/dealers/approved.html +++ b/uber/templates/emails/dealers/approved.html @@ -6,7 +6,7 @@ on this page. Payment is expected by: {{ c.DEALER_PAYMENT_DUE|datetime_local }} or your application will be removed and your tables filled by another applicant. -{% if group.unassigned_badges %} +{% if group.unassigned %}

    Some of your badges are not yet assigned to a specific person. If you assign these badges now then it will take much less time for their owners to pick them up at the festival. diff --git a/uber/templates/emails/dealers/payment_confirmation.html b/uber/templates/emails/dealers/payment_confirmation.html index 0f4c46733..3326503fb 100644 --- a/uber/templates/emails/dealers/payment_confirmation.html +++ b/uber/templates/emails/dealers/payment_confirmation.html @@ -2,7 +2,7 @@ Your group ({{ group.name }}) has been preregistered for {{ c.EVENT_NAME }} this coming {{ event_dates() }} and your payment of {{ (attendee.amount_paid / 100)|format_currency }} has been received. Your group will have {{ group.tables }} Marketplace table{{ group.table|pluralize }}. The Marketplace coordinator will continue to be in touch with you to keep you informed of Marketplace rules and procedures. -{% if group.unassigned_badges %} +{% if group.unassigned %}

    Some of your badges are not yet assigned to a specific person. If you assign these badges now then it will take much less time for their owners to pick them up at the festival. From b287499446b25efb1342604d72c7f59279353a39 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Fri, 6 Oct 2023 21:58:14 -0400 Subject: [PATCH 18/27] Finish SignNow email invitations It actually mostly worked! Also adds the updates to the group member page that I thought I had put in an earlier commit (as is tradition). --- uber/site_sections/group_admin.py | 6 +- uber/templates/forms/group.html | 94 +++++++++++++++++-------------- uber/utils.py | 13 ++--- 3 files changed, 62 insertions(+), 51 deletions(-) diff --git a/uber/site_sections/group_admin.py b/uber/site_sections/group_admin.py index 2808b7112..545edd7ac 100644 --- a/uber/site_sections/group_admin.py +++ b/uber/site_sections/group_admin.py @@ -11,7 +11,7 @@ from uber.errors import HTTPRedirect from uber.forms import group as group_forms, load_forms from uber.models import Attendee, Email, Event, Group, GuestGroup, GuestMerch, PageViewTracking, Tracking, SignedDocument -from uber.utils import check, convert_to_absolute_url, validate_model +from uber.utils import check, convert_to_absolute_url, validate_model, add_opt from uber.payments import ReceiptManager @@ -105,6 +105,10 @@ def form(self, session, new_dealer='', message='', **params): document.last_emailed = datetime.now(UTC) session.add(document) existing_doc = document + if not existing_doc.last_emailed: + existing_doc.send_dealer_signing_invite(group) + existing_doc.last_emailed = datetime.now(UTC) + session.add(existing_doc) signnow_last_emailed = existing_doc.last_emailed group_info_form = forms.get('group_info', forms.get('table_info')) diff --git a/uber/templates/forms/group.html b/uber/templates/forms/group.html index f539aa523..8cdd60889 100644 --- a/uber/templates/forms/group.html +++ b/uber/templates/forms/group.html @@ -22,7 +22,7 @@

    {% if group.signnow_document %}Finish Signing{% else %}Review and Sign{% endif %}

    -

    Make sure to click "DONE" in the top right to confirm your signature.

    +

    Make sure to click "Finish" in the top right to confirm your signature.

    {% endif %} {% endif %} @@ -53,69 +53,77 @@
    {% endcall %}
    + {% else %} {# Always read-only for attendees #} {% if group.status == c.APPROVED %} {% elif group.status == c.CANCELLED %} -