From 2d4eae94f0bc06f271225ad5444e6fb2cd14efbb Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Tue, 3 Jun 2025 15:38:52 +0200 Subject: [PATCH] Add support for sponsors requesting explicit contract at click-through levels Click-through contracts makes it easier for most, but some sponsor organisations require an actual contract at these levels as well. To handle this, add an option during contract/address verification to request an explicit contract, which can then be either manual or digital, and will both prevent the clickthrough contract and invoice to be sent until thsi contract has been completed. --- .../0035_sponsor_explicitcontract.py | 18 ++++++++++++++++++ postgresqleu/confsponsor/models.py | 1 + postgresqleu/confsponsor/util.py | 2 +- postgresqleu/confsponsor/views.py | 13 ++++++++----- template/confsponsor/admin_dashboard.html | 2 +- template/confsponsor/admin_sponsor.html | 6 +++--- .../confsponsor/admin_sponsor_details.html | 2 +- template/confsponsor/signupform.html | 14 ++++++++++++++ template/confsponsor/sponsor.html | 4 ++-- 9 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 postgresqleu/confsponsor/migrations/0035_sponsor_explicitcontract.py diff --git a/postgresqleu/confsponsor/migrations/0035_sponsor_explicitcontract.py b/postgresqleu/confsponsor/migrations/0035_sponsor_explicitcontract.py new file mode 100644 index 00000000..7b53b368 --- /dev/null +++ b/postgresqleu/confsponsor/migrations/0035_sponsor_explicitcontract.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.11 on 2025-06-03 13:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('confsponsor', '0034_rename_instantbuy'), + ] + + operations = [ + migrations.AddField( + model_name='sponsor', + name='explicitcontract', + field=models.BooleanField(default=False, verbose_name='Requested explicit contract'), + ), + ] diff --git a/postgresqleu/confsponsor/models.py b/postgresqleu/confsponsor/models.py index d6d9b404..1e56c985 100644 --- a/postgresqleu/confsponsor/models.py +++ b/postgresqleu/confsponsor/models.py @@ -166,6 +166,7 @@ class Sponsor(models.Model): signmethod = models.IntegerField(null=False, blank=False, default=1, choices=((0, 'Digital signatures'), (1, 'Manual signatures')), verbose_name='Signing method') autoapprovesigned = models.BooleanField(null=False, blank=False, default=True, verbose_name="Approve on signing", help_text="Automatically approve once digital signatures are completed") contract = models.OneToOneField(DigisignDocument, null=True, blank=True, help_text="Contract, when using digital signatures", on_delete=models.SET_NULL) + explicitcontract = models.BooleanField(null=False, blank=False, default=False, verbose_name='Requested explicit contract') def __str__(self): return self.name diff --git a/postgresqleu/confsponsor/util.py b/postgresqleu/confsponsor/util.py index f9daeafa..9e87617d 100644 --- a/postgresqleu/confsponsor/util.py +++ b/postgresqleu/confsponsor/util.py @@ -175,7 +175,7 @@ def get_pdf_fields_for_conference(conference, sponsor=None, overrides={}): fields.append( ('static:euvat', sponsor.vatnumber if sponsor else overrides.get('static:euvat', 'Sponsor EU VAT number')), ) - if sponsor and sponsor.level.contractlevel == 1: + if sponsor and sponsor.level.contractlevel == 1 and not sponsor.explicitcontract: # Only add clickthrough contract fields if it's a clickthrough level (or a preview, with no sponsor yet) fields.extend([ ('static:clickthrough', overrides.get('static:clickthrough', 'Click-through agreement')), diff --git a/postgresqleu/confsponsor/views.py b/postgresqleu/confsponsor/views.py index 09701e70..5b7cdae0 100644 --- a/postgresqleu/confsponsor/views.py +++ b/postgresqleu/confsponsor/views.py @@ -389,7 +389,7 @@ def _generate_and_send_sponsor_contract(sponsor): send_sponsor_manager_email( sponsor, 'Your contract for {}'.format(conference.conferencename), - 'confsponsor/mail/{}.txt'.format('sponsor_contract_instant' if level.contractlevel == 1 else 'sponsor_contract_manual'), + 'confsponsor/mail/{}.txt'.format('sponsor_contract_instant' if (level.contractlevel == 1 and not sponsor.explicitcontract) else 'sponsor_contract_manual'), { 'conference': conference, 'sponsor': sponsor, @@ -455,7 +455,7 @@ def sponsor_signup(request, confurlname, levelurlname): # Stage 2 = contract choice. When submitted, sign up. # If there is no contract needed on this level, or there is no choice # of contract because only one available, we bypass stage 1. - if stage == '1' and (level.contractlevel != 2 or not conference.contractprovider or not conference.manualcontracts): + if stage == '1' and ((level.contractlevel != 2 and request.POST.get('explicitcontract', '') != '1') or not conference.contractprovider or not conference.manualcontracts): stage = '2' def _render_contract_choices(): @@ -480,6 +480,7 @@ def sponsor_signup(request, confurlname, levelurlname): 'form': form, 'noform': 1, 'contractchoices': contractchoices, + 'explicitcontract': request.POST.get('explicitcontract', '') == '1', }) if stage == '0': @@ -507,7 +508,7 @@ def sponsor_signup(request, confurlname, levelurlname): # If the Continue editing button is selected we should go back # to just rendering the normal form. Otherwise, go ahead and create the record. if request.POST.get('submit', '') != 'Continue editing': - if request.POST.get('contractchoice', '') not in ('0', '1') and level.contractlevel == 2: + if request.POST.get('contractchoice', '') not in ('0', '1') and (level.contractlevel == 2 or request.POST.get('explicitcontract', '') == '1'): return _render_contract_choices() social = { @@ -525,8 +526,9 @@ def sponsor_signup(request, confurlname, levelurlname): level=level, social=social, invoiceaddr=form.cleaned_data['address'], - signmethod=1 if request.POST.get('contractchoice', '') == '1' or not conference.contractprovider or level.contractlevel < 2 else 0, + signmethod=1 if request.POST.get('contractchoice', '') == '1' or not conference.contractprovider or level.contractlevel < 2 or request.POST.get('explicitcontract', '') == '1' else 0, autoapprovesigned=conference.autocontracts, + explicitcontract=request.POST.get('explicitcontract', '') == '1', ) if settings.EU_VAT: sponsor.vatstatus = int(form.cleaned_data['vatstatus']) @@ -539,7 +541,7 @@ def sponsor_signup(request, confurlname, levelurlname): error = None - if level.contractlevel < 2: + if level.contractlevel < 2 and request.POST.get('explicitcontract', '') != '1': # No contract or click-through contract if level.contractlevel == 1: # Click-through contract @@ -548,6 +550,7 @@ def sponsor_signup(request, confurlname, levelurlname): mailstr += "Level does not require a signed contract. Verify the details and approve\nthe sponsorship using:\n\n{0}/events/sponsor/admin/{1}/{2}/".format( settings.SITEBASE, conference.urlname, sponsor.id) else: + # Contract required! contractid, error = _generate_and_send_sponsor_contract(sponsor) if sponsor.signmethod == 1: diff --git a/template/confsponsor/admin_dashboard.html b/template/confsponsor/admin_dashboard.html index 8fa6f119..e7d0ae89 100644 --- a/template/confsponsor/admin_dashboard.html +++ b/template/confsponsor/admin_dashboard.html @@ -88,7 +88,7 @@ sponsor manually, you may want to confirm them manually as well... {%else%} Invoiced {%endif%} - {%elif s.level.contractlevel < 2 %} + {%elif s.level.contractlevel < 2 and not s.explicitcontract %} Pending organizer verification {%else%} {%if s.signmethod == 0 and s.contract %} diff --git a/template/confsponsor/admin_sponsor.html b/template/confsponsor/admin_sponsor.html index 99b3caf7..75ae0a83 100644 --- a/template/confsponsor/admin_sponsor.html +++ b/template/confsponsor/admin_sponsor.html @@ -140,7 +140,7 @@

This sponsorship is awaiting an invoice to be paid.

-{%if sponsor.level.contractlevel == 2 %} +{%if sponsor.level.contractlevel == 2 or sponsor.explicitcontract %} {%comment%}Only full contract sponsorships should be manually confirmed{%endcomment%}

Iff there is a signed and countersigned contract available @@ -161,7 +161,7 @@ for this sponsor, it can be confirmed before the invoice is paid. {%else%} {%comment%}Sponsor has no invoice{%endcomment%} {%if sponsor.level.levelcost %} -{%if sponsor.level.contractlevel < 2%} +{%if sponsor.level.contractlevel < 2 and not sponsor.explicitcontract %}

This sponsorship has not yet been issued an invoice. This is a {%if sponsor.level.contractlevel == 1 %}click-through{%else%}no{%endif%} @@ -192,7 +192,7 @@ This sponsorship has not yet been issued an invoice. Once the contract has been received, go ahead and generate the invoice.

{%endif%}{%comment%}Digital contracts{%endcomment%} -{%endif%}{%comment%}contractlevel < 2{%endcomment%} +{%endif%}{%comment%}contractlevel < 2 and not explicitcontract{%endcomment%} {%else%}{%comment%}levelcost != 0 {%endcomment%}

This sponsorship has zero cost, which means payment is handled manually. diff --git a/template/confsponsor/admin_sponsor_details.html b/template/confsponsor/admin_sponsor_details.html index dac8b191..deacbc8c 100644 --- a/template/confsponsor/admin_sponsor_details.html +++ b/template/confsponsor/admin_sponsor_details.html @@ -41,7 +41,7 @@ {%if sponsor.level.contractlevel == 0 %} No contract needed for this level. - {%elif sponsor.level.contractlevel == 1 %} + {%elif sponsor.level.contractlevel == 1 and not sponsor.explicitcontract %} Click-through contract completed. {%if not sponsor.confirmed%}

{% csrf_token %}
{%endif%} {%else%}{%comment%}Full contract{%endcomment%} {%if sponsor.signmethod == 0%} diff --git a/template/confsponsor/signupform.html b/template/confsponsor/signupform.html index 689e4d1b..684a37dc 100644 --- a/template/confsponsor/signupform.html +++ b/template/confsponsor/signupform.html @@ -65,6 +65,19 @@ the invoice cannot be changed. step. If anything about it is incorrect please click Continue editing and correct it before proceeding.

+ +{% if level.contractlevel == 1 %} +

Contract options

+

+ As this level uses a click-thruogh contract, no specific contract signature is + required. However, if your organization requires a signed contract, you can + explicitly request one here. +

+

+ Request explicit contract +

+{% endif %} + {%endif%}

Invoice address preview

@@ -97,6 +110,7 @@ the invoice cannot be changed. +{%if explicitcontract %}{%endif%} {%endif%}{# contractchoices #} {%if level.contractlevle == 2 and not noform %} diff --git a/template/confsponsor/sponsor.html b/template/confsponsor/sponsor.html index 9f11f934..6a4679ae 100644 --- a/template/confsponsor/sponsor.html +++ b/template/confsponsor/sponsor.html @@ -40,7 +40,7 @@ {% if sponsor.level.contractlevel == 0 %} This level requires no contract. -{% elif sponsor.level.contractlevel == 1 %} +{% elif sponsor.level.contractlevel == 1 and not sponsor.explicitcontract %} Click-through contract agreed to. View copy of contract {% else %} {%if sponsor.signmethod == 0%} @@ -75,7 +75,7 @@ Manual contract signed. {%endwith%} {%else%} {%comment%}No invoice generated{%endcomment%} -{%if sponsor.level.contractlevel < 2 %} +{%if sponsor.level.contractlevel < 2 and not sponsor.explicitcontract %} {%comment%}No invoice generated but clickthrough contract or no contract, so awaiting admin approval{%endcomment%}

Your sponsorship request has been submitted, and is currently awaiting confirmation -- 2.39.5