From 8209dff476fa67cd2b129c4d9d9f7c82f5177c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Wed, 21 Feb 2024 15:33:18 +0100 Subject: [PATCH] Revert "Move to pandoc for rendering sponsorship contracts (#2343)" (#2374) This reverts commit a4990b711ccd6e34e87d8d4b97169846fba5414f. --- .github/workflows/ci.yml | 12 - Aptfile | 0 Dockerfile | 42 +-- base-requirements.txt | 7 +- pydotorg/settings/base.py | 1 + sponsors/contracts.py | 89 ------ sponsors/pandoc_filters/__init__.py | 0 sponsors/pandoc_filters/pagebreak.py | 90 ------ sponsors/pdf.py | 78 +++++ sponsors/reference.docx | Bin 12636 -> 0 bytes sponsors/tests/test_contracts.py | 39 --- sponsors/tests/test_pdf.py | 113 +++++++ sponsors/use_cases.py | 2 +- sponsors/views_admin.py | 2 +- .../sponsors/admin/contract-template.docx | Bin 0 -> 15199 bytes .../admin/contracts/renewal-agreement.md | 119 -------- .../admin/contracts/sponsorship-agreement.md | 209 ------------- .../sponsors/admin/preview-contract.html | 283 ++++++++++++++++++ .../admin/renewal-contract-template.docx | Bin 0 -> 9323 bytes texlive.packages | 2 - 20 files changed, 483 insertions(+), 605 deletions(-) delete mode 100644 Aptfile delete mode 100644 sponsors/contracts.py delete mode 100644 sponsors/pandoc_filters/__init__.py delete mode 100644 sponsors/pandoc_filters/pagebreak.py create mode 100644 sponsors/pdf.py delete mode 100644 sponsors/reference.docx delete mode 100644 sponsors/tests/test_contracts.py create mode 100644 sponsors/tests/test_pdf.py create mode 100644 templates/sponsors/admin/contract-template.docx delete mode 100644 templates/sponsors/admin/contracts/renewal-agreement.md delete mode 100644 templates/sponsors/admin/contracts/sponsorship-agreement.md create mode 100644 templates/sponsors/admin/preview-contract.html create mode 100644 templates/sponsors/admin/renewal-contract-template.docx delete mode 100644 texlive.packages diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 28bfcc5ee..97298ffca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,18 +17,6 @@ jobs: steps: - name: Check out repository uses: actions/checkout@v2 - - name: Install platform dependencies - run: | - sudo apt -y update - sudo apt -y install --no-install-recommends \ - texlive-latex-base \ - texlive-latex-recommended \ - texlive-plain-generic \ - lmodern - - name: Install pandoc - run: | - wget https://github.com/jgm/pandoc/releases/download/2.17.1.1/pandoc-2.17.1.1-1-amd64.deb - sudo dpkg -i pandoc-2.17.1.1-1-amd64.deb - uses: actions/setup-python@v2 with: python-version: 3.9.16 diff --git a/Aptfile b/Aptfile deleted file mode 100644 index e69de29bb..000000000 diff --git a/Dockerfile b/Dockerfile index f8aca13a2..4d1046a98 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,47 +1,9 @@ -FROM python:3.9-bookworm +FROM python:3.9-bullseye ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 - -# By default, Docker has special steps to avoid keeping APT caches in the layers, which -# is good, but in our case, we're going to mount a special cache volume (kept between -# builds), so we WANT the cache to persist. -RUN set -eux; \ - rm -f /etc/apt/apt.conf.d/docker-clean; \ - echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache; - -# Install System level build requirements, this is done before -# everything else because these are rarely ever going to change. -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt,sharing=locked \ - set -x \ - && apt-get update \ - && apt-get install --no-install-recommends -y \ - pandoc \ - texlive-latex-base \ - texlive-latex-recommended \ - texlive-fonts-recommended \ - texlive-plain-generic \ - lmodern - -RUN case $(uname -m) in \ - "x86_64") ARCH=amd64 ;; \ - "aarch64") ARCH=arm64 ;; \ - esac \ - && wget --quiet https://github.com/jgm/pandoc/releases/download/2.17.1.1/pandoc-2.17.1.1-1-${ARCH}.deb \ - && dpkg -i pandoc-2.17.1.1-1-${ARCH}.deb - RUN mkdir /code WORKDIR /code - COPY dev-requirements.txt /code/ COPY base-requirements.txt /code/ - -RUN pip --no-cache-dir --disable-pip-version-check install --upgrade pip setuptools wheel - -RUN --mount=type=cache,target=/root/.cache/pip \ - set -x \ - && pip --disable-pip-version-check \ - install \ - -r dev-requirements.txt - +RUN pip install -r dev-requirements.txt COPY . /code/ diff --git a/base-requirements.txt b/base-requirements.txt index 06e1990e4..0badc58eb 100644 --- a/base-requirements.txt +++ b/base-requirements.txt @@ -44,11 +44,12 @@ django-filter==2.4.0 django-ordered-model==3.4.3 django-widget-tweaks==1.4.8 django-countries==7.2.1 +xhtml2pdf==0.2.5 +django-easy-pdf3==0.1.2 num2words==0.5.10 django-polymorphic==3.0.0 sorl-thumbnail==12.7.0 +docxtpl==0.12.0 +reportlab==3.6.6 django-extensions==3.1.4 django-import-export==2.7.1 - -pypandoc==1.12 -panflute==2.3.0 diff --git a/pydotorg/settings/base.py b/pydotorg/settings/base.py index ccbf3acab..25874dd5d 100644 --- a/pydotorg/settings/base.py +++ b/pydotorg/settings/base.py @@ -173,6 +173,7 @@ 'ordered_model', 'widget_tweaks', 'django_countries', + 'easy_pdf', 'sorl.thumbnail', 'banners', diff --git a/sponsors/contracts.py b/sponsors/contracts.py deleted file mode 100644 index 7e72cde39..000000000 --- a/sponsors/contracts.py +++ /dev/null @@ -1,89 +0,0 @@ -import os -import tempfile - -from django.http import HttpResponse -from django.template.loader import render_to_string -from django.utils.dateformat import format - -import pypandoc - -dirname = os.path.dirname(__file__) -DOCXPAGEBREAK_FILTER = os.path.join(dirname, "pandoc_filters/pagebreak.py") -REFERENCE_DOCX = os.path.join(dirname, "reference.docx") - - -def _clean_split(text, separator="\n"): - return [ - t.replace("-", "").strip() - for t in text.split("\n") - if t.replace("-", "").strip() - ] - - -def _contract_context(contract, **context): - start_date = contract.sponsorship.start_date - context.update( - { - "contract": contract, - "start_date": start_date, - "start_day_english_suffix": format(start_date, "S"), - "sponsor": contract.sponsorship.sponsor, - "sponsorship": contract.sponsorship, - "benefits": _clean_split(contract.benefits_list.raw), - "legal_clauses": _clean_split(contract.legal_clauses.raw), - } - ) - previous_effective = contract.sponsorship.previous_effective_date - context["previous_effective"] = previous_effective if previous_effective else "UNKNOWN" - context["previous_effective_english_suffix"] = format(previous_effective, "S") if previous_effective else "UNKNOWN" - return context - - -def render_markdown_from_template(contract, **context): - template = "sponsors/admin/contracts/sponsorship-agreement.md" - if contract.sponsorship.renewal: - template = "sponsors/admin/contracts/renewal-agreement.md" - context = _contract_context(contract, **context) - return render_to_string(template, context) - - -def render_contract_to_pdf_response(request, contract, **context): - response = HttpResponse( - render_contract_to_pdf_file(contract, **context), content_type="application/pdf" - ) - return response - - -def render_contract_to_pdf_file(contract, **context): - with tempfile.NamedTemporaryFile() as docx_file: - with tempfile.NamedTemporaryFile(suffix=".pdf") as pdf_file: - markdown = render_markdown_from_template(contract, **context) - pdf = pypandoc.convert_text( - markdown, "pdf", outputfile=pdf_file.name, format="md" - ) - return pdf_file.read() - - -def render_contract_to_docx_response(request, contract, **context): - response = HttpResponse( - render_contract_to_docx_file(contract, **context), - content_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document", - ) - response[ - "Content-Disposition" - ] = f"attachment; filename={'sponsorship-renewal' if contract.sponsorship.renewal else 'sponsorship-contract'}-{contract.sponsorship.sponsor.name.replace(' ', '-').replace('.', '')}.docx" - return response - - -def render_contract_to_docx_file(contract, **context): - markdown = render_markdown_from_template(contract, **context) - with tempfile.NamedTemporaryFile() as docx_file: - docx = pypandoc.convert_text( - markdown, - "docx", - outputfile=docx_file.name, - format="md", - filters=[DOCXPAGEBREAK_FILTER], - extra_args=[f"--reference-doc", REFERENCE_DOCX], - ) - return docx_file.read() diff --git a/sponsors/pandoc_filters/__init__.py b/sponsors/pandoc_filters/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sponsors/pandoc_filters/pagebreak.py b/sponsors/pandoc_filters/pagebreak.py deleted file mode 100644 index 525b89c57..000000000 --- a/sponsors/pandoc_filters/pagebreak.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# ------------------------------------------------------------------------------ -# Source: https://github.com/pandocker/pandoc-docx-pagebreak-py/ -# Revision: c8cddccebb78af75168da000a3d6ac09349bef73 -# ------------------------------------------------------------------------------ -# MIT License -# -# Copyright (c) 2018 pandocker -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ------------------------------------------------------------------------------ - -""" pandoc-docx-pagebreakpy -Pandoc filter to insert pagebreak as openxml RawBlock -Only for docx output - -Trying to port pandoc-doc-pagebreak -- https://github.com/alexstoick/pandoc-docx-pagebreak -""" - -import panflute as pf - - -class DocxPagebreak(object): - pagebreak = pf.RawBlock("", format="openxml") - sectionbreak = pf.RawBlock("", - format="openxml") - toc = pf.RawBlock(r""" - - - - - - TOC \o "1-3" \h \z \u - - - - - - -""", format="openxml") - - def action(self, elem, doc): - if isinstance(elem, pf.RawBlock): - if elem.text == r"\newpage": - if (doc.format == "docx"): - pf.debug("Page Break") - elem = self.pagebreak - # elif elem.text == r"\newsection": - # if (doc.format == "docx"): - # pf.debug("Section Break") - # elem = self.sectionbreak - # else: - # elem = [] - elif elem.text == r"\toc": - if (doc.format == "docx"): - pf.debug("Table of Contents") - para = [pf.Para(pf.Str("Table"), pf.Space(), pf.Str("of"), pf.Space(), pf.Str("Contents"))] - div = pf.Div(*para, attributes={"custom-style": "TOC Heading"}) - elem = [div, self.toc] - else: - elem = [] - return elem - - -def main(doc=None): - dp = DocxPagebreak() - return pf.run_filter(dp.action, doc=doc) - - -if __name__ == "__main__": - main() diff --git a/sponsors/pdf.py b/sponsors/pdf.py new file mode 100644 index 000000000..9855beee3 --- /dev/null +++ b/sponsors/pdf.py @@ -0,0 +1,78 @@ +""" +This module is a wrapper around django-easy-pdf so we can reuse code +""" +import io +import os +from django.conf import settings +from django.http import HttpResponse +from django.utils.dateformat import format + +from docxtpl import DocxTemplate +from easy_pdf.rendering import render_to_pdf_response, render_to_pdf + +from markupfield_helpers.helpers import render_md +from django.utils.html import mark_safe + + +def _clean_split(text, separator='\n'): + return [ + t.replace('-', '').strip() + for t in text.split('\n') + if t.replace('-', '').strip() + ] + + +def _contract_context(contract, **context): + start_date = contract.sponsorship.start_date + context.update({ + "contract": contract, + "start_date": start_date, + "start_day_english_suffix": format(start_date, "S"), + "sponsor": contract.sponsorship.sponsor, + "sponsorship": contract.sponsorship, + "benefits": _clean_split(contract.benefits_list.raw), + "legal_clauses": _clean_split(contract.legal_clauses.raw), + "renewal": contract.sponsorship.renewal, + }) + previous_effective = contract.sponsorship.previous_effective_date + context["previous_effective"] = previous_effective if previous_effective else "UNKNOWN" + context["previous_effective_english_suffix"] = format(previous_effective, "S") if previous_effective else None + return context + + +def render_contract_to_pdf_response(request, contract, **context): + template = "sponsors/admin/preview-contract.html" + context = _contract_context(contract, **context) + return render_to_pdf_response(request, template, context) + + +def render_contract_to_pdf_file(contract, **context): + template = "sponsors/admin/preview-contract.html" + context = _contract_context(contract, **context) + return render_to_pdf(template, context) + + +def _gen_docx_contract(output, contract, **context): + context = _contract_context(contract, **context) + renewal = context["renewal"] + if renewal: + template = os.path.join(settings.TEMPLATES_DIR, "sponsors", "admin", "renewal-contract-template.docx") + else: + template = os.path.join(settings.TEMPLATES_DIR, "sponsors", "admin", "contract-template.docx") + doc = DocxTemplate(template) + doc.render(context) + doc.save(output) + return output + + +def render_contract_to_docx_response(request, contract, **context): + response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document') + response['Content-Disposition'] = 'attachment; filename=contract.docx' + return _gen_docx_contract(output=response, contract=contract, **context) + + +def render_contract_to_docx_file(contract, **context): + fp = io.BytesIO() + fp = _gen_docx_contract(output=fp, contract=contract, **context) + fp.seek(0) + return fp.read() diff --git a/sponsors/reference.docx b/sponsors/reference.docx deleted file mode 100644 index bf094ca4f3f29b535da99c765b735eaee71420d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12636 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%0D(b%B@_FB(DPPG z&0-g(r3Rwn9F|ya1EjZf5p!cs^V5e5ZrET>?rO&LZgV<8>y|PaqQ=B8^hbNN#5@lG z0asUMKV77q?P6^*ryGXhe|7wL{4^-TYsU*g{?my6?{RnDL<%&%Rsewdqhdk#28DJ-dJc@MXwm#QOhEI1QdJ= zw+08&iV{+vYD)Ju&N{VUf0P7KmtpWi7ursN&SVQ)f$~RDk1=CqiBf_jvQG~b*O=CK zV3KAQLC4&IfxT~*kvnG%bXdDXpTFaQ-8)tQLGU>*qRLSx*I9R^xi-j4EM;a@4fV_M z=;yL$-Whpw-}3U2q)2lT2nm~`#`MbwIa^}|*lDs`in=xFY-z+XKz5-;T8E>9rKX#g z>-^fmKz7f25wC!%-DGwc6lQ)iXrmfORRo5Eedxs1pSC5{%MOX=wWp!}ubewA;a7+K zx@V-P>}F@;sPoecw@6#F=%S?N!;BwtzIKqtH5W3uX-;nT zlewkvbhrB8XW({gOBU!eI)sOecHd@EhQfxQ&jpbg?wV{`kxqv7J#0Tsi zhakfr$2j}4mb2PWz>AYFt;4HLx36?bs(bBRS4YEs(Ep8C4^55|`XO7b1`U=B- zMjiO^A(Kjq%7+I}B!-|f6P_}{B((Rd0>$Rn5#KY0O*l4aU7y1YX(UsB%r)M08I|3M z`dB?YzXhVZON#HBu7PLuMGVnIKU_AV>8XR-@@=~p^3WTA{0}L0m_50C<_`=PKSVZV zTWzKh2qZ=`^sPMGQD6qlt_e??PMEAqxP`lEo_9UY3Fka{ynMv%8SFvWM^j^U!T-l#<8{R#hl jTK;_ySJ8lg{2wf=ycFc?@B#rre*HCrzeXZ-Kd=55B-B^E diff --git a/sponsors/tests/test_contracts.py b/sponsors/tests/test_contracts.py deleted file mode 100644 index c330c13a8..000000000 --- a/sponsors/tests/test_contracts.py +++ /dev/null @@ -1,39 +0,0 @@ -from datetime import date -from model_bakery import baker -from unittest.mock import patch, Mock - -from django.http import HttpRequest -from django.test import TestCase -from django.utils.dateformat import format - -from sponsors.contracts import render_contract_to_docx_response - - -class TestRenderContract(TestCase): - def setUp(self): - self.contract = baker.make_recipe("sponsors.tests.empty_contract", sponsorship__start_date=date.today()) - - # DOCX unit test - def test_render_response_with_docx_attachment(self): - request = Mock(HttpRequest) - self.contract.sponsorship.renewal = False - response = render_contract_to_docx_response(request, self.contract) - - self.assertEqual(response.get("Content-Disposition"), "attachment; filename=sponsorship-contract-Sponsor.docx") - self.assertEqual( - response.get("Content-Type"), - "application/vnd.openxmlformats-officedocument.wordprocessingml.document" - ) - - - # DOCX unit test - def test_render_renewal_response_with_docx_attachment(self): - request = Mock(HttpRequest) - self.contract.sponsorship.renewal = True - response = render_contract_to_docx_response(request, self.contract) - - self.assertEqual(response.get("Content-Disposition"), "attachment; filename=sponsorship-renewal-Sponsor.docx") - self.assertEqual( - response.get("Content-Type"), - "application/vnd.openxmlformats-officedocument.wordprocessingml.document" - ) diff --git a/sponsors/tests/test_pdf.py b/sponsors/tests/test_pdf.py new file mode 100644 index 000000000..e4d140cf2 --- /dev/null +++ b/sponsors/tests/test_pdf.py @@ -0,0 +1,113 @@ +from datetime import date +from docxtpl import DocxTemplate +from markupfield_helpers.helpers import render_md +from model_bakery import baker +from pathlib import Path +from unittest.mock import patch, Mock + +from django.conf import settings +from django.http import HttpResponse, HttpRequest +from django.template.loader import render_to_string +from django.test import TestCase +from django.utils.html import mark_safe +from django.utils.dateformat import format + +from sponsors.pdf import render_contract_to_pdf_file, render_contract_to_pdf_response, render_contract_to_docx_response + + +class TestRenderContract(TestCase): + def setUp(self): + self.contract = baker.make_recipe("sponsors.tests.empty_contract", sponsorship__start_date=date.today()) + text = f"{self.contract.benefits_list.raw}\n\n**Legal Clauses**\n{self.contract.legal_clauses.raw}" + html = render_md(text) + self.context = { + "contract": self.contract, + "start_date": self.contract.sponsorship.start_date, + "start_day_english_suffix": format(self.contract.sponsorship.start_date, "S"), + "sponsor": self.contract.sponsorship.sponsor, + "sponsorship": self.contract.sponsorship, + "benefits": [], + "legal_clauses": [], + "renewal": None, + "previous_effective": "UNKNOWN", + "previous_effective_english_suffix": None, + } + self.template = "sponsors/admin/preview-contract.html" + + # PDF unit tests + @patch("sponsors.pdf.render_to_pdf") + def test_render_pdf_using_django_easy_pdf(self, mock_render): + mock_render.return_value = "pdf content" + + content = render_contract_to_pdf_file(self.contract) + + self.assertEqual(content, "pdf content") + mock_render.assert_called_once_with(self.template, self.context) + + @patch("sponsors.pdf.render_to_pdf_response") + def test_render_response_using_django_easy_pdf(self, mock_render): + response = Mock(HttpResponse) + mock_render.return_value = response + + request = Mock(HttpRequest) + content = render_contract_to_pdf_response(request, self.contract) + + self.assertEqual(content, response) + mock_render.assert_called_once_with(request, self.template, self.context) + + # DOCX unit test + @patch("sponsors.pdf.DocxTemplate") + def test_render_response_with_docx_attachment(self, MockDocxTemplate): + template = Path(settings.TEMPLATES_DIR) / "sponsors" / "admin" / "contract-template.docx" + self.assertTrue(template.exists()) + mocked_doc = Mock(DocxTemplate) + MockDocxTemplate.return_value = mocked_doc + + request = Mock(HttpRequest) + response = render_contract_to_docx_response(request, self.contract) + + MockDocxTemplate.assert_called_once_with(str(template.resolve())) + mocked_doc.render.assert_called_once_with(self.context) + mocked_doc.save.assert_called_once_with(response) + self.assertEqual(response.get("Content-Disposition"), "attachment; filename=contract.docx") + self.assertEqual( + response.get("Content-Type"), + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ) + + @patch("sponsors.pdf.DocxTemplate") + def test_render_response_with_docx_attachment__renewal(self, MockDocxTemplate): + renewal_contract = baker.make_recipe("sponsors.tests.empty_contract", sponsorship__start_date=date.today(), + sponsorship__renewal=True) + text = f"{renewal_contract.benefits_list.raw}\n\n**Legal Clauses**\n{renewal_contract.legal_clauses.raw}" + html = render_md(text) + renewal_context = { + "contract": renewal_contract, + "start_date": renewal_contract.sponsorship.start_date, + "start_day_english_suffix": format(self.contract.sponsorship.start_date, "S"), + "sponsor": renewal_contract.sponsorship.sponsor, + "sponsorship": renewal_contract.sponsorship, + "benefits": [], + "legal_clauses": [], + "renewal": True, + "previous_effective": "UNKNOWN", + "previous_effective_english_suffix": None, + } + renewal_template = "sponsors/admin/preview-contract.html" + + template = Path(settings.TEMPLATES_DIR) / "sponsors" / "admin" / "renewal-contract-template.docx" + self.assertTrue(template.exists()) + mocked_doc = Mock(DocxTemplate) + MockDocxTemplate.return_value = mocked_doc + + request = Mock(HttpRequest) + response = render_contract_to_docx_response(request, renewal_contract) + + MockDocxTemplate.assert_called_once_with(str(template.resolve())) + mocked_doc.render.assert_called_once_with(renewal_context) + mocked_doc.save.assert_called_once_with(response) + self.assertEqual(response.get("Content-Disposition"), "attachment; filename=contract.docx") + self.assertEqual( + response.get("Content-Type"), + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ) diff --git a/sponsors/use_cases.py b/sponsors/use_cases.py index 91271ff64..bbb6f2483 100644 --- a/sponsors/use_cases.py +++ b/sponsors/use_cases.py @@ -3,7 +3,7 @@ from sponsors import notifications from sponsors.models import Sponsorship, Contract, SponsorContact, SponsorEmailNotificationTemplate, SponsorshipBenefit, \ SponsorshipPackage -from sponsors.contracts import render_contract_to_pdf_file, render_contract_to_docx_file +from sponsors.pdf import render_contract_to_pdf_file, render_contract_to_docx_file class BaseUseCaseWithNotifications: diff --git a/sponsors/views_admin.py b/sponsors/views_admin.py index fd8631d3f..e9a808ccc 100644 --- a/sponsors/views_admin.py +++ b/sponsors/views_admin.py @@ -14,7 +14,7 @@ from sponsors.forms import SponsorshipReviewAdminForm, SponsorshipsListForm, SignedSponsorshipReviewAdminForm, \ SendSponsorshipNotificationForm, CloneApplicationConfigForm from sponsors.exceptions import InvalidStatusException -from sponsors.contracts import render_contract_to_pdf_response, render_contract_to_docx_response +from sponsors.pdf import render_contract_to_pdf_response, render_contract_to_docx_response from sponsors.models import Sponsorship, SponsorBenefit, EmailTargetable, SponsorContact, BenefitFeature, \ SponsorshipCurrentYear, SponsorshipBenefit, SponsorshipPackage diff --git a/templates/sponsors/admin/contract-template.docx b/templates/sponsors/admin/contract-template.docx new file mode 100644 index 0000000000000000000000000000000000000000..5bdc44525a4d15367bcaad989f5d63ba6c278233 GIT binary patch literal 15199 zcmaL819&Cdwl*Bwwr$(CZQHidv7L0BbZpyp$4SSwoqXN#4PB)v8ge z=6DC@Q**ou(!d}n01yxm02P_B>HvQe=->PLPNp`_^mKpTtLFQpfEf|Mw!L$WGQ8cJ zRYgo1y1vb3N%#iDPhNs$$w-uFZT(V!YFAL}!()CqIwCIG#QEs(ASEeQN9smu<1ox2P!=xjiJIW*uby{$~)f#7n#c1+e0N!c0 zykz(|53rlpw5Fnzj!KJtPal%xea=bJh7Zj+p+xH^lY~)QHWfM5fm9JZo(n*|?$IK$j-SxY^u>#(> znM~2Bq})|sKm}=Vhy$lbk>lUPp9KN{Q20L$g!uam6MJI?Cwm8HdSiPhQ#ub@8(*af zxd8@*&O6kEtFpZ!(Uip!B|%FdC-#OG*f0Y&K)X4e>4x`;V759?c4w6$5l z+KLneAhB>wfyHLDK(yN{;IR&cG^u#7TB$BZ^?V)5(J!Cg`uHr1y8XqrQsHN&e&o+T zl#|4}I9Y{ALjw`QcLLf^xK3I-x#!YKV2LwA7dnm(V;cJmdNBFq&gx%T53p6+Xf>E` z@8M)Oj_36lN`Fdt=sej!x_pCUYFkt^Cvb#N(&Rh2v)Px}Q(bpj!#vGX^T!Y)QxUOt?(XUr22u zZa-TC0sw6MN2Cz`j+CK;!ylk>6esNZe*^VIUGPJFmt#L7T5++wRE>ZY)NYg`OFU&I z^@8a64Xa>2`)px)+RF^z#1+r$3S`YiiN+Tvq#HbFq8xc@{)#Bz{CR@m^rX8)Yz&F+zj_8Y@+L?qesHKH-MocN*HBO z1E``PtFpVGzlu)wxxXm&Sj|UVqjez|h@KM0bhr$*0`Y zmFtkcXR%mI?8wQWj`1MRH#s*CBcHW13&L35Ns+->yU?wopzwDvBa$xJ=p08JgQBW} zj+K}*i5%0KQ+vjViy*RH)x+yIXei`@$G@t!*~Qr^0fm`^h6B!vs$pWFbP!mE_uEV} z9nbs}vZsmJS4fx*-E(aDQTF7(I?(PcH$$9LGg&jsmS%anv9|JopR(rg{{#-Jgc7CV zZ#X3XBOJ(ohr`&_*~Q-WFGQy6p!yk5LU%SxAy(H_z!T;hqd2%#p5lKs13KG}%0~Hm z69-+!hU4?eE%1H_S0bz;TD8$rQv%S!!jaS3e-v{__Kj^D;DzKJfYEfgE$a}2ej5Xf zq9L&6EJd*@UYXv8P2)7CBNnw+`tGR25mip|^9jH8ORwv@`!Rtc%P| zt91sHk*g;Z!P+QYmQS0^P%cvjC|qNhCEkF7(TEJbXcF>^3q7m2CiQfhb;+*A@)jsF zczw#HInLWF`n`9~=iAfR#4$MN49C;}gVSJ0vu`!b&62&#>t_v|=@Ou;SV+?jK$mqO z>J#c|Z=lr2P|#g=1=0*{E93?hD&5yS5zXmBoClm{T&Yfi`SWQ;dlzjQM?u6i#nVND z(7yhMis_6BX*-Y^0tJ+dC1WGwi z*rraDtW7t6#U`5Jit08OEBH{~GO;gfS1~1)c{g|}o8b?VyTWou|-3-61^I@5Z3-20a90j{PwdnNKQ+g-P*U?4006_clDf`Ag; zbK=ye=ETq`Mp2BgOo;0aZ41{ZX}Rwn;W;4FGDulf_9$1Blfsw%VWn~|3*dwMhzSrq zU!U$N7Mi(vsjprRbrD^AlW4%Lo#h5YK1sHE+J|Ime&NVGZ$TY3$s9Mpv7YZLR4gy#YW)0~%Gc5q zMz8c`Dpgw>g{(q$KOI)ovNR@dl%pxe#DS_bep0Gg8PccNQ%3Nol>fXzPn| ze4gE8qVP*R;rX<5K7szkmlrT=GXXFFz$?XnimyKf_pkW+U3Fb;P3>I%3NPIkI~2*x zFaKPkeOk(sa~;ZeBNtR|$A`a5G=z#F~_pFNNhUuQ6Lk(loNg@|iUnTW+CY zPHTWsuPsMRm$F=!D|fW;*Qhr*Kd!G;%*|Zp$Xjolt@d)PabuMXkNW{-gYY79@Bq?Q z^MZw)W_d(@nce%>(0n*&$|IAKc^@%(Ho8SCr&ZeSW+17Z68R}AtO#FXw5uU$w66RhqSGHp^jU!+uZEK_XU+Mz25k?~a+`%uL4TjLr((JbK?2Ra@p0!P}`*etOZ~3^m zaMH86Kz&0o1012!EqW+yQZ{`E;Ooq7zh#Hd{rc*?8TE(LZ^t~`JpyL;zL>|8eY_nh ztx}hKdjl>IH@=xvjWqy)qp5MF`ZdlGp_p{m)x4^=a(?{@sQ?! z4qv5Yq4DuL!N1O5h%Lk|NF_WZRN97UkQP}NouUvN80q9&9pcgt10whF_GHky_AX1~ z+;rf?J^G+gHSoiJkYOVxD(W=w1Um%|`9jQI2XO6ea|o2JzBBO3Yj;?`EkRY|aKOp! zd#{3;ag}!gfAPabg-?MBm7eTfg5(fox+bz^iiZ`{wbU%UMkuL=>#K|Ep>8Dkw!s`u zDH*7=SDrH>W>(-q=g%c-<@Z4|`L3x;6eMqpqPOC>EdbhITF& z9Yi3ATb;n#>V%tAj^sHC3g~TlB5QuJz@Pj;qJ_##qan=3p}SjwyAcmsbYey+NZF2$h{GfDPGLYH8bxPuPz$keJ;n<~G1R5*(tedO14z~o*S z=*r?(-`wgyaV(7O^v$h)MlGO8rgm?3U#hr%1k=>y;(y1vY>B8$T>X_Fxy$~9R=zJ#yBiA(t901}Er<%gjq2*k!#nhTsaCQ>*iSp#2{ zv2S821=w6zKMU$3Q>Y?UR>}luY|cZclp}xBmqFi8O}(@4LBSinOV z=4Dy*fp!r9rG(0fpI|Ce=XT5)o!ZZcGHd#hYVXP)6T+vr@oQWk)T44E^!iVOm{gyo z^zv}tw(}p-%`+~MubU?tH+JSLM}w$%SWEy6cA)CRqIwF?CpyJQZ?SHHA&b!;U=-o4 z+oFKfWtA9M$P1*$%7Tn7!)Y8+=Bh<5!#fP)Wf6^1#F4hLVq91$*p=xAh+VQ%B#Ji* zLwv&{>lXI_mz74DNOk~lGKuLC>&WVqOY=sPSI7H289TVG?kMclw##~>rdu!m(hms~ zmX2M_dw5lw&=nfqKp8*0436;X@)H@Iw5^m5_>tDS>2$U<74%a%+|45zXhRyj&n_>O z?#`BiRez$3wg!O1AUz~V?Td(Vr9~i%TS^EkI%cVi?U_kMp9f1JnAWhCbgSUjATjKK z9T-R@1g;#m>}X|Zdlkc(j=(R6;lpjkxac3r`t?E#L6WHkHsxszI1o0pdfFLAS(5B%e~i}$k>v&IOf|DnAj!qd12Z%PxHDT% zv)b7O-HojM@*rHxoTvv*)YLb_$ z9}?3{U(IzrLZ&9}30b#t8CHOvMTUiU=NzU@PPCQ?hWNJrY#AiXX%J%)WtP0QXuI}q zrPLmYq!EL?bC4PGp+wM1zUnz75>FSEx)LYT=5+)UGK(n>Bot5ZL<$OoE|T5X>%>-$ z#N@1iw%Rb%4O#Y=_Vx~g{h=sX);znU)1ns5Jjk~!;4S0}lsEOd$R3`z3%B#9l)|>2 zn4RyMVX4WUMD83ReMRI9h-a z_zXNcz5Iw0SY-=q5nM+6y66%a=n@kisGdj~O!Z_ru^H?MzC&Ig6dLxZa6x^^bSOhr z%p_hU{z+w9OfrtCeV94NKKsghACHEf@5oDKcJHANkFj@ZqMR5yLWuOv4pm)yS(({C zin~t@?P{T!JZA5)a@Ij!pf4Xdq+Kj%CHzx{XCYg$_}bvUDxQ$R5YQFnXbHxEhuUKz zkNdDdBVAQZ08SG70g952aRl%`X`E_pSy!6JuN(>}eX18j@W&LWDNeiiSp$e^YmJ-s zilN8y(VKm(#daV;*CeV105f#NI*v^-Lg$JDnj{~kBT z<9hg&cX)$lu*qVh5p1V+)u??G@}k4o1snx|=9+od*QkX1FnSstM9HkqpxNYOESK!x z9^dWqsYUstCN9eFZTey>Cd#kmyj8Z-Bf~ntSGQL3Bsf?YrTs)TVrX_GP)3Jf!iuG- zLY*Wi{wQl!;zA#_CQm@C1l07-a1GRFZLn2}c1fO0)yUUfSSH0L#c}tfljx!@yFjFc zN)`Fw4$sDDf?| zLd8}(L36AJC0=QJh!$4>%;;0d+*rS@u1=N>KxBsIEPHmT*X=%8?c_&LBFSjUawVES{Qcc`Yx?q4as8$oUv<$*aw4Lgf z2={l=j)*bl{_M3*{RW$Ly&;$p*TA#WA)2fSZS94g1e9sY_8~-`0x^jqvpq|myv3{o zQs7}?1JM4%KY@GBGPmL2eZfc2P5a@SR>I zid{m2h`1c7YcMJF4Y2!opV6)1;r*o~hw8p&8X=gRjBL*Rp*fUigyZw7T5m4DMzgrx zENkbxC4)R-A!kJolHID(>>9qBZ_-zf%`N0fV`^fB_CbhcQ$1UWMuq0s@ z1S6&3J+>KkRkKW{${HzE{e8QGRtqp}>IMm3C|MKrBH|Vpi%&|UqB#-0W%z)FNoM3a>cH2i$s||1t!tR$66(OaJ7|?@myFw22YMo zI%04V^7oc$$nH41&I~Usu^2YjgtihG_mKMtDA?C3(}?z^BL=>~ed*Nrz%|?ed;N+8 zT>GUVG$E17J8yoOqvnOW2x5YJE-Owo>SV>>2jePzbl>Odw(2W2j_w(%kc>>v;4X1k zpWKDy%$X%qT0j{od+cX*>3JJ9I%ojx#CW2yDjY3JDS-xbg&@gnkrkn_P~=9f0&8Yx4b@E+*&r=-D=;FY{#?BuqTZWrwa%)y zE9wHyNAQmJK{yjXc0YW(m;o^r#fJ`Kfd|QN(UcZArjADh7I~a}Z)V`EV$F&EmYXnb zGQX!%ibs9TGVc-LfUY6~*dijw1>9;}K}tSB4GvYfF2P+5=@06WSF;NZFIlzpsNKv!L}ViM2FTyRp;=r zdo^RL{c!I9qlAJx2H^c(b|sn=Qg#qw`>59?$SOGtS{_Xu5sd<58u0?XN1`>d%IU*Z znruEp%0Tr~^GiXCZ8`&vo~;op#%t6yG}GM8_01>|u@!>-ceWU&5mP?iP|yt-pHA{? z#^;fgq*Z7|l}8F3@MEWVRl7VJ`R5C*jH7SaaJM2$8|>Qt@o~G)M~G7O_e5CEK>%`k z6wB^anH{Qr+|CIk^hZ>pkdm!RV$8iLJULkU>s83aIT)G{Q)cm!ww+@?2fKOGXPSLe zXQCNyUa{B%7BoC70ns2(!M@GVi+&2eMt*cZ0=VaEmdGdqb8qCERRdjoUmB8(TVS^6 z=>Z2asWfWW8fJeN*X3nyhu4YDeSBG_sdY$Q4LVM1z|p!~X)vA%)xv`jqi(Br&suRj zA@s~OOEMxwWDIM9xmmx?mXB?r7&{LVH*0^|Da+^em7*qwwvcv7$H@uM%sxzndwzyU z9}!=SU7>==@(tg4f+G4cbh6&_J4#HMH|vu`rEd>Mq>N0W8zRabe?BQVHjpq*PYBZA zYw0CDKt5rLN@GWP^Zn9@KU#m}e_mkkl8H%e)j-CW>KgO9Hm9GS5<&6H zuVP(|+=%#n9N;yLr4}Zs`RI6s5uMt!L+}u~9k0f|z>CAng)c4w5lx{wD z2jUiaevukJW9sQ;Q>{U$M=ksLjy}QaQaCPPqcLW!0#5giF`BI^c=7x2B^oBUOdrX# ztr%2uq`1c34seD_w(E%Jw^eOX-JnJH;kBJ`6%$|%9Y9uwl@yxTh<>afjl{sXUUHB= zDu*S)*$vY?(dN8%?g-7+g=_H#Zj!s0^&9vAHlX8NrHiF!IncQZ>1x}D&{R@}5l{9| z#M!c>nE|i7ZrW6+8h48~P|Inec=&WOmL~JgRk*2+?~zQSYzHNabDlc$C*afxBDAvD zyiNPrZ7xF}rTJ4elKL#&x(M4E`s}I}*{Vb{P9XMCc8(TTqxg=0FA~OT7$lN5FNfK8 z_=e#ZMr6_&p}Ym@xh2BTPCQWo|}9@8%HY>91r-`-q%=Zkw9U&=+Etx54lEENc$ zpuW?rfzusTVAnMU$nrAQ=u|?P)7HI#VR58-8G4`Xd3JI29HMYS_JUS z!EiI}tS`($+yuY2WD(c&PVbVC0xr^i({c0GR9t{<&?wZ~QaUa7Jm&Q@0(C@u)g7_L zzE0k$aBL&h4hV#d=-Hp=0K`aolzkbnEtzaKBsJcvW1BzmTnik3#Rse4)mZ>>4PwH0 zIGxI!miEDSXTpBsNfG+%)pUakq*cWGrU$iT?tC++QUCSJI@)Jv`!%v}g!(pu>h`2a zmfSW~GRv_XoXbjA;^Ky9GM(^t__O|lk;%X@rU=)&BHhW!%f`r9kZ8O+uI~o{-tpol zg_C|*`q=_CJV$uf7e#`X%m_!$fVnZ}VdaN`$in4XoG1^DGcX8m>QTgPPlaxCyJNgC zxe}|Z0nj%GfyUq5MuBJVh-P040`Ch<*=kp{jaMWeNT%&IU7 za4)?sG(-a9$dR2-1#=#%a1>yZ9LPMO3-(UoIg`!7>!}=oFDkW~dxwFDRI`%V9UeeN zt^$TaX~;U{lP%SIiI*n6@PK6|_`LU*=EFq}%KPo5GyC-vsop+ED0Pt;6!(>o15%s_ zBm+?hhZQZ(njWDi909_tJIfMCGIGpOK3_oEJ<7!_`@RUVq|5oboEke?fq5y~GRr-A z8l!ltwM}pDC{i`2Wu2Qi6(J8rOKr<*OLxDoTx?U(tXG~frE(b_q1K%t>=2n{FoK{b zbce{_0~vV7lOBTtqZ1S0@pR?+f0T_#ZP)vNLijO=35Ly|FrsBb-Emh1&drNU4Pu=n z$qN6N<=^&#FH}PO$Tf`n0d$bX# zCV4A3CDxI;yL))KX)n5{Z;QCq^F)xVov~=JBfq7POfuerz;v|RUqd~avH9J1Z$LiJ zD|ppwZ*d-5CzQPd9sSDQpsjHNuibO6fVfPRyljY?+TjC{6UQP?`(RQ30Ak}ID(d@> z>RHM0sHinmo({?+c8G@gR=FEE?yloe1JSW<%WIp*K_}J37@6{RR=q`5J`qm8)mI}a z7bo83Cu}b^eM?{Ih6@XYf$0mF*AyL@L8H?sW84^-T{E`mc2S)SQ68Vtf*`@Uk4KG` z#EQ1W2||VrRNX05Ux&BpSPoy>?>pV4X!7T&96Zl@?-d@k&R4&t>{QjAReO|?6ag6T zUJoKX9PG`Hx}SGkdbFn(b*3}5U&D3l{Jy3?U>)tB4i7)T-LKrNxf)7nwL6E7Mmmwb zR^cSh48n{Tzv7@kU%BQtAKc^aMrtU>q9W%5gEu&b?XCcQMVhjn^hBs)DIyWzSZMjnmHh=-OsjH<3rgNOvuRruUl~ z5xDeDJPsN>4s1e3JoVG_Wrj}VLmSJDlVWAL*fI>0HoZHZKr#(?S-``_ymuRC+mKo= z&(B?878qql7?@%1tcs8^D@d>{A*;u`SA1(boGYMT-OlIhCJqoE9H-N{kDYf9q8}5UV^CBIj*gx6Auk2sj&f&KF3%Cxx zzM#Udaxn?SfS~*d$>E1`p(}JN3(j%dTQb=cGJhvK=zPb|Zo&kN}0L z-rMpU9R)50KsrUdRbWM8CumZ&Cy+!y%Vv<$h!iaax8r~qS;Anm5ovZc493`ml=@HH zqNPM37=^T|Pa<^#*f9!S@z_jnR%A07+LNCNN$+K_a;Yo&7?*H)5W=L*Zz}X%K*sr5 z6G42@XF*0ZUWX#_t%V;vs+fBfA+$l0hSP5#FoWM?1nNZnqnS?{9@<_(?#q4|SyY5f z?RRq|81zZ&&DS@8EDh+F2~J|4(lv!bfCGb63a*F^muudto~cJ~y$TZ7YR9aT0aQ|$<80x)bxJPM@W!Ezv?!#FcBMcgXE%_RV->5@Pj@%AJ1 z)BjAc%#aNUzpUCUvx5!#31{Hig_Hpem;*(lE-0Z#DyL>I_<%)I6TxTNbty~q215us zteM-Z?oGNe&y1|jFCd|ap3($1r-Ec`RM`f4bu^1!J^}qDk1*PuDyqq;QNX(j@G(wO zkbE*amAV6gAkR=LiiKb+xI$z`vD?JdN)9k&e{zR{;oXBHZF6G&#yVP%yUqxt$9PQ{{9ZrNw?AGsJvq; z`g{>Mcq=B|fNcF$wU}G7zS#n&G=9|R2D$NEf#oj8c+~BMos;prx$$L1k6Z~ z-y-{^uZ9XwjG1s%69+35J5RXPK&+dBg5l7WFiAU48_`$R)Cu4OQfIKH8FGvk!9u#GBIsfN0E)~JZURUR{)7Cb<~ zs4DP%y>UdA5*B6K`fz9SCEWQ1t%{3zzdp8T;MrG}da32np&&cA4&tbBQDjx{u)FO?}+MOJ} zJCZ3QiE5^`_PU@&l1c_TK~n+kD1P|W4~UX=0ob$7NYar+an*{0<&B`yOhC{}*9r~C z2O~O#@KAlxDld!GpgpNmm0r~n8#elDtg_iuOBKv}Pe5o5C&lDSDez~3&S5v?e1t>Z2&(IAck1wy+%PIZkQ+>yWO6d1+xc{qJu8b$9r2H#F;Ww=C^iRcn74?+@DomdB6n05=*wyRRi zPIphp8)7fY(c~`)+fqU#sP9sXf9V!Ou1OxoB}`Jg;k444NBQv&x_TddPA%cFz7YZ4 zmNVXQYqbqG-Yz#B(Z>y)Oq80}JjufiEu`_|@UQZ7dwFhHCz#Pf3;&F50>Cs~f?>J5 zSesnoO7wgYyUTsQabMsS{OW3Z?}_!T#(mRS6jbC?^WFuO5vPKyY+Q&{;Zo8BLN9e5 zq(C%1fN`moOJ)Ye!}ThdRyC^6G;dX~YMKMSo2%<;w*1C6t=b@Vuodu;oKq(MP<7JC zF75xr{7CwE2TZkTV*X@F&cF|Ib1gw$oG-W3o!xwPwyI?byNsS2>>6Z&FB-i zvKvpXgm`H?56Vifu-;Gh82vFyel;P&?X2Wd@lx>zgK^5ix%HniNT~1=Pmajwn=NXx z5f#JDtf0UhsyP*Dfu(q47@3~IpIjSI3t01vRhU|whdz@I7x$L-m<+1O4G}l&rbKcm z!N`3U)2uxFG%P(7h=U|hBN6^oCjG6>O`j3bWqa7TZ7Y@)I-TxUcGk*1)o$1(Jtl8V zm}Z*!_f=}aAc49%CayhX5dM!Xsvu8DJkVdBOoSx z)*&^s;Lj#{7N^VlpO+xF%JL*;7G6dLi6+XN*NMNEZ6$s|sx2Nfl3|d49a1T-Ld05Iem^PZ^vQx z7cF(*o8^<^+|fLl1F%GUIE?fDd6FJhyy8QuoE@!?4!tun>wnpU(rK_OpcN~o>dmSXr?K%_HmrS5GMiQb%8*F zJL8c%#S*VE`nXzB12&>xA}Bo)*4d%h60Sm?rUyJvuT9ZTAmH)3@lK=zhVWRRyc^&{ ziEukXB=Tdk-9(smkW2@(0>OU1EIAJc60C-9M42%|rn#J|9ER2qNGZ{`VqCbMV0jp9 z3ux+_2LjUNNIBUd8gPKxp=n(Fq5w6x>UUH&W<0loeYkg>fpd51Xw@M22Lrh?2F!#f zAqN*2Eh&CgJX>3p6>ke<1|O_kyvhe(!bk1ZlzGh?@Sx*Hq;A+fP`(5=tnL$9u;<8B z$il5WBrOK+BFA?nHz_06=k5)5OV7mswk2?l>=IbDLm>H|9RY=RN_794hjhtq|@=B?%`ncg=h+`L5}r*>YI@c8S+)02QPFqv zPcbTe-#S(zro@86x(zpy3jk-8AK(zj zDfQs8?Xjm_MjmjN>07#`4`!Jjb1(4Jh%NeGi3N9DmYjH?V zGfBKI?INte8!P1zAL)&+n%;l+Wmpxw|BhNpldWujVvUW*VK{&A``b^jHDcdXRg1_s z{>_-Erz>RR`l>j@8mV@lEz1a!Kr=8mWt{gH`rUf~Z~VY)4@0r*K=Ml0^ zo~}M3^?HMVw!Yk<&f)yG6f9w+;U|26mm(D)w?rV9h69VQU}~nXwG_&O@~Gj{C91=K z(Jlh+D?XRlS-L6ePa<|R<)f!hUINY=?SmU%Kw+9XTGU76I@~*&yq>I;E06*}gDdfN2zD5yeBLub#cXANBe%gF% zxeN#IPHS$?Y&osK^n;7qsNwIvib(X^C#%52#!%)3OJrp?_FwQnZN}^` zc@NiquBjYDr;&pb-fb9Za9UMl5;TSE>PPlCU3Gpnt;C&v>QKQjpMC zN}~+473R4yEH|S33cN<5vpezy|EE*THmL^PfJk zA$3LPH4X&7tD5WMoR$6bWG2##WH{wZrD|u(E8S7(CDBx$M2L9(t(4ktb+SN~B|CtX zx))YY>x(Uidy8D?bG#M`6+jCGRCW zkE$c}FaYXD-E!ChVFp!2^R31Gk^bDpXjz6JbBZIjZO1q~oaai&h~I3sQsPVO^kP5=lr$K}?s1Ie>0B9HG_`ZJ=H2_xR9iK!?px zeOc_t%0edyxI_C}og+S`S&QbFskwyZ-ix^s$r82fI=@)G0L~z^IAnDMz3BHq_&@5U zCJ0o*-I0;%3{2k%_@`_hMOc*fy#rDF;}a=gB#bUjut_ z_xUWEpAxKZ2c{@N4Hg%&s-N+!8Ry@;+c#;>pT{A{Qc^y`LctehMFl!(L6G=rU29o3 z4ma!~ki+1-Xds2Wvj(Sp`lnD0fDUDQR`>_!!xTB3o92|FRCE(#6uSA;gzP zuY;H^%Z=Ii=CEgh-oG}fS&-O8uS+)h*B&Q_=*nfx=A zC;7EEZ0i^bmi9VTEEwM&`F>^K8c|$n^XfvrjdZUZvz3xzH8aTXm*zFADRdv$akfOs z4Xp^$u-=2!E|82?u6zJQxUUXEHq_ce=KXPCTldg^K!|J?b>aTq#ZM3VpFsGZZd_+m z7nk3??tf)jQ-$BG3IUiutctEQSP5SWA_BS};g29601b|#QmYSE7xD8oHH3L;r&EuU z9z1&0Jwp1~3=O3kSud3=pkm@NaU*L!mo0HMB?f^j0`iE~&SGq5ivv!T7^2BTp?2SN zVwz4wluT(m;DE2Ak;I0y#sNjveHw`m$V{C^E9Ym|MK$@>0r)ags^7_=hBQbg;R=sA zO)bwsEowva(|B>*gd{1+kFD?OTl*Lwx^k4m5k;Ig9LIp=K*R|H-_<%!+(^YBGOaRS zgRi=>`F{u&&c=WA$n1vE7ICgj&tkq)^tVz1ey-u zm0WIPvv!tUZRvjec3yCZ)_7zs$lrD>_`Ut#&ip^D0W*6$7ZpPzo4)L4F#GdlN+M04szCP|+_D-_gt)c{J zl=H)bWvGi1)l-*3{d9Tswya1IEkI)-p}U0V7RDA^r>ILPsC3E4)`gZC+1ePDmW~C% zHVBHfhWdnM)@#{l!&Q-6MG}fGb1+R;V{Qy2@lE^XOR#-v+dE(V}2%ToKZTH@;TF;RaUjBuOg+1}=(j97G zc;cYX1ir$4>~oZM?xk7i+;FKR&0p?LV_7wduPE;pkq@ms#kf*l7!=i@!h7N~wSLcu z{hd2xW;&o~W`(dcYTeUpmyi3Y6B2EJuM9fl)uaAP{Nwg(fb3RYaU@jc*I%rlqb4p} z&fiAw1^G{g|3gF37XEGY-<{<8DxMCe&bogl3SB9GF}OsZd_?zYrF1k1LK5Bjj3ITC zS)DEIN9{F{81lOdh60yPi}1$@JMrmA70t2YVm}K1&EY z7aV;DPNAtBzV8@XqfIw1>9qAIsv?-))U;1ykTFbkvB>%318+wuD#zu7O*3pnh8@cAd^*-Zn- z=p(%!Jbk%xl-PDq$iO!XU!K|I;{5=;7$He8$2p+EI-6h520zE1mktGry=ycoja&#>NKlpDK)pC8A&>G$~Qs&jCJdMo`I z-^ zjri~KH*VrT75~l(`;(^rC4|5K>i@^t`=|QfSxkSZWB-zg-@K;(QU5O@**~@a&K3IO zV*e7Y-|qN7+W+D`{qq8UCqw*64*wFS-wF9I0>r-&jQ*+r_bKwfk3JFNe<4u(Q~mEH z_|H80U(!kUU+VvwRsU1@@1^5UmHwAxG5weF|53C5d8NN6&wn2U0n2~i#@`ChKh^)9 x0{-2I7OelJ{%`sApZb6I%YR34hwXn&8w%2(zg-vr0Q&c<>$jUkbNu=C{{R-(A5Z`Q literal 0 HcmV?d00001 diff --git a/templates/sponsors/admin/contracts/renewal-agreement.md b/templates/sponsors/admin/contracts/renewal-agreement.md deleted file mode 100644 index 3a401c9d7..000000000 --- a/templates/sponsors/admin/contracts/renewal-agreement.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: SPONSORSHIP AGREEMENT RENEWAL -geometry: -- margin=1.25in -font-size: 12pt -pagestyle: empty -header-includes: -- \pagenumbering{gobble} ---- - -**THIS SPONSORSHIP AGREEMENT RENEWAL** (the **"Agreement"**) -is entered into and made effective as of the -{{start_date|date:"j"}}{{start_day_english_suffix}} of {{start_date|date:"F Y"}} -(the **"Effective Date"**), -by and between the **Python Software Foundation** (the **"PSF"**), -a Delaware nonprofit corporation, -and **{{sponsor.name|upper}}** (**"Sponsor"**), -a {{sponsor.state}} corporation. -Each of the PSF and Sponsor are hereinafter sometimes individually -referred to as a **"Party"** and collectively as the **"Parties"**. - -## RECITALS - -**WHEREAS**, the PSF is a tax-exempt charitable organization (EIN 04-3594598) -whose mission is to promote, protect, and advance the Python programming language, -and to support and facilitate the growth of a diverse -and international community of Python programmers (the **"Programs"**); - -**WHEREAS**, Sponsor is {{contract.sponsor_info}}; and - -**WHEREAS**, Sponsor and the PSF previously entered into a Sponsorship Agreement -with the effective date of the -{{ previous_effective|date:"j" }}{{ previous_effective_english_suffix }} of {{ previous_effective|date:"F Y" }} -and a term of one year (the “Sponsorship Agreement”). - -**WHEREAS**, Sponsor wishes to renew its support the Programs by making a contribution to the PSF. - -## AGREEMENT - -**NOW, THEREFORE**, in consideration of the foregoing and the mutual covenants contained herein, and for other good and valuable consideration, the receipt and sufficiency of which are hereby acknowledged, the Parties hereto agree to extend and amend the Sponsorship Agreement as follows: - -1. [**Replacement of the Exhibit**]{.underline} Exhibit A to the Sponsorship Agreement is replaced with Exhibit A below. - -1. [**Renewal**]{.underline} Approval and incorporation of this new exhibit with the previous Sponsor Benefits shall be considered written notice by Sponsor to the PSF that you wish to continue the terms of the Sponsorship Agreement for an additional year and to contribute the new Sponsorship Payment specified in Exhibit A, beginning on the Effective Date, as contemplated by Section 6 of the Sponsorship Agreement. - -  - - -### \[Signature Page Follows\] - -::: {.page-break} -\newpage -::: - -## SPONSORSHIP AGREEMENT RENEWAL - -**IN WITNESS WHEREOF**, the Parties hereto have duly executed this **Sponsorship Agreement Renewal** as of the **Effective Date**. - -  - -**PSF**: -**PYTHON SOFTWARE FOUNDATION**, -a Delaware non profit corporation - -  - -By:        ________________________________ -Name:   Loren Crary -Title:     Director of Resource Development - -  - -  - -**SPONSOR**: -**{{sponsor.name|upper}}**, -a {{sponsor.state}} entity - -  - -By:        ________________________________ -Name:   ________________________________ -Title:     ________________________________ - -::: {.page-break} -\newpage -::: - -## SPONSORSHIP AGREEMENT RENEWAL - -### EXHIBIT A - -1. [**Sponsorship**]{.underline} During the Term of this Agreement, in return for the Sponsorship Payment, the PSF agrees to identify and acknowledge Sponsor as a {{sponsorship.year}} {{sponsorship.level_name}} Sponsor of the Programs and of the PSF, in accordance with the United States Internal Revenue Service guidance applicable to qualified sponsorship payments. - - Acknowledgments of appreciation for the Sponsorship Payment may identify and briefly describe Sponsor and its products or product lines in neutral terms and may include Sponsor’s name, logo, well-established slogan, locations, telephone numbers, or website addresses, but such acknowledgments shall not include (a) comparative or qualitative descriptions of Sponsor’s products, services, or facilities; (b) price information or other indications of savings or value associated with Sponsor’s products or services; (c) a call to action; (d) an endorsement; or (e) an inducement to buy, sell, or use Sponsor’s products or services. Any such acknowledgments will be created, or subject to prior review and approval, by the PSF. - - The PSF’s acknowledgment may include the following: - - - [**Display of Logo**]{.underline} The PSF will display Sponsor’s logo and other agreed-upon identifying information on www.python.org, and on any marketing and promotional media made by the PSF in connection with the Programs, solely for the purpose of acknowledging Sponsor as a sponsor of the Programs in a manner (placement, form, content, etc.) reasonably determined by the PSF in its sole discretion. Sponsor agrees to provide all the necessary content and materials for use in connection with such display. - - - Additional acknowledgment as provided in Sponsor Benefits. - -1. [**Sponsorship Payment**]{.underline} The amount of Sponsorship Payment shall be {{sponsorship.verbose_sponsorship_fee|title}} USD ($ {{sponsorship.sponsorship_fee}}). The Sponsorship Payment is due within thirty (30) days of the Effective Date. To the extent that any portion of a payment under this section would not (if made as a Separate payment) be deemed a qualified sponsorship payment under IRC § 513(i), such portion shall be deemed and treated as separate from the qualified sponsorship payment. - -1. [**Receipt of Payment**]{.underline} Sponsor must submit full payment in order to secure Sponsor Benefits. - -1. [**Refunds**]{.underline} The PSF does not offer refunds for sponsorships. The PSF may cancel the event(s) or any part thereof. In that event, the PSF shall determine and refund to Sponsor the proportionate share of the balance of the aggregate Sponsorship fees applicable to event(s) received which remain after deducting all expenses incurred by the PSF. - -1. [**Sponsor Benefits**]{.underline} Sponsor Benefits per the Agreement are: - - 1. Acknowledgement as described under "Sponsorship" above. - -{%for benefit in benefits%} 1. {{benefit}} -{%endfor%} - -{%if legal_clauses%}1. Legal Clauses. Related legal clauses are: - -{%for clause in legal_clauses%} 1. {{clause}} -{%endfor%}{%endif%} diff --git a/templates/sponsors/admin/contracts/sponsorship-agreement.md b/templates/sponsors/admin/contracts/sponsorship-agreement.md deleted file mode 100644 index ee0d91ce3..000000000 --- a/templates/sponsors/admin/contracts/sponsorship-agreement.md +++ /dev/null @@ -1,209 +0,0 @@ ---- -title: SPONSORSHIP AGREEMENT -geometry: -- margin=1.25in -font-size: 12pt -pagestyle: empty -header-includes: -- \pagenumbering{gobble} ---- - -**THIS SPONSORSHIP AGREEMENT** (the **"Agreement"**) -is entered into and made effective as of the -{{start_date|date:"j"}}{{start_day_english_suffix}} of {{start_date|date:"F Y"}} -(the **"Effective Date"**), -by and between the **Python Software Foundation** (the **"PSF"**), -a Delaware nonprofit corporation, -and **{{sponsor.name|upper}}** (**"Sponsor"**), -a {{sponsor.state}} corporation. -Each of the PSF and Sponsor are hereinafter sometimes individually -referred to as a **"Party"** and collectively as the **"Parties"**. - -## RECITALS - -**WHEREAS**, the PSF is a tax-exempt charitable organization (EIN 04-3594598) -whose mission is to promote, protect, and advance the Python programming language, -and to support and facilitate the growth of a diverse -and international community of Python programmers (the **"Programs"**); - -**WHEREAS**, Sponsor is {{contract.sponsor_info}}; and - -**WHEREAS**, Sponsor wishes to support the Programs by making a contribution to the PSF. - -## AGREEMENT - -**NOW, THEREFORE**, in consideration of the foregoing and the mutual covenants contained herein, and for other good and valuable consideration, the receipt and sufficiency of which are hereby acknowledged, the Parties hereto agree as follows: - -1. [**Recitals Incorporated**]{.underline}. Each of the above Recitals is incorporated into and is made a part of this Agreement. - -1. [**Exhibits Incorporated by Reference**]{.underline}. All exhibits referenced in this Agreement are incorporated herein as integral parts of this Agreement and shall be considered reiterated herein as fully as if such provisions had been set forth verbatim in this Agreement. - -1. [**Sponsorship Payment**]{.underline} In consideration for the right to sponsor the PSF and its Programs, and to be acknowledged by the PSF as a sponsor in the manner described herein, Sponsor shall make a contribution to the PSF (the "Sponsorship Payment") in the amount shown in Exhibit A. - -1. [**Acknowledgement of Sponsor**]{.underline} In return for the Sponsorship Payment, Sponsor will be entitled to receive the sponsorship package described in Exhibit A attached hereto (the "Sponsor Benefits"). - -1. [**Intellectual Property**]{.underline} The PSF is the sole owner of all right, title, and interest to all the PSF information, including the PSF’s logo, trademarks, trade names, and copyrighted information, unless otherwise provided. - - (a) [Grant of License by the PSF]{.underline} The PSF hereby grants to Sponsor a limited, non- exclusive license to use certain of the PSF’s intellectual property, including the PSF’s name, acronym, and logo (collectively, the "PSF Intellectual Property"), solely in connection with promotion of Sponsor’s sponsorship of the Programs. Sponsor agrees that it shall not use the PSF’s Property in a manner that states or implies that the PSF endorses Sponsor (or Sponsor’s products or services). The PSF retains the right, in its sole and absolute discretion, to review and approve in advance all uses of the PSF Intellectual Property, which approval shall not be unreasonably withheld. - - (a) [Grant of License by Sponsor]{.underline} Sponsor hereby grants to the PSF a limited, non-exclusive license to use certain of Sponsor’s intellectual property, including names, trademarks, and copyrights (collectively, "Sponsor Intellectual Property"), solely to identify Sponsor as a sponsor of the Programs and the PSF. Sponsor retains the right to review and approve in advance all uses of the Sponsor Intellectual Property, which approval shall not be unreasonably withheld. - -1. [**Term**]{.underline} The Term of this Agreement will begin on the Effective Date and continue for a period of one (1) year. The Agreement may be renewed for one (1) year by written notice from Sponsor to the PSF. - -1. [**Termination**]{.underline} The Agreement may be terminated (i) by either Party for any reason upon sixty (60) days prior written notice to the other Party; (ii) if one Party notifies the other Party that the other Party is in material breach of its obligations under this Agreement and such breach (if curable) is not cured with fifteen (15) days of such notice; (iii) if both Parties agree to terminate by mutual written consent; or (iv) if any of Sponsor information is found or is reasonably alleged to violate the rights of a third party. The PSF shall also have the unilateral right to terminate this Agreement at any time if it reasonably determines that it would be detrimental to the reputation and goodwill of the PSF or the Programs to continue to accept or use funds from Sponsor. Upon expiration or termination, no further use may be made by either Party of the other’s name, marks, logo or other intellectual property without the express prior written authorization of the other Party. - -1. [**Code of Conduct**]{.underline} Sponsor and all of its representatives shall conduct themselves at all times in accordance with the Python Software Foundation Code of Conduct (https://www.python.org/psf/conduct) and/or the PyCon Code of Conduct (https://pycon.us/code-of-conduct), as applicable. The PSF reserves the right to eject from any event any Sponsor or representative violating those standards. - -1. [**Deadlines**]{.underline} Company logos, descriptions, banners, advertising pages, tote bag inserts and similar items and information must be provided by the applicable deadlines for inclusion in the promotional materials for the PSF. - -1. [**Assignment of Space**]{.underline} If the Sponsor Benefits in Exhibit A include a booth or other display space, the PSF shall assign display space to Sponsor for the period of the display. Location assignments will be on a first-come, first-served basis and will be made solely at the discretion of the PSF. Failure to use a reserved space will result in penalties (up to 50% of your Sponsorship Payment). - -1. [**Job Postings**]{.underline} Sponsor will ensure that any job postings to be published by the PSF on Sponsor’s behalf comply with all applicable municipal, state, provincial, and federal laws. - -1. [**Representations and Warranties**]{.underline} Each Party represents and warrants for the benefit of the other Party that it has the legal authority to enter into this Agreement and is able to comply with the terms herein. Sponsor represents and warrants for the benefit of the PSF that it has full right and title to the Sponsor Intellectual Property to be provided under this Agreement and is not under any obligation to any party that restricts the Sponsor Intellectual Property or would prevent Sponsor’s performance under this Agreement. - -1. [**Successors and Assigns**]{.underline} This Agreement and all the terms and provisions hereof shall be binding upon and inure to the benefit of the Parties and their respective legal representatives, heirs, successors, and/or assigns. The transfer, or any attempted assignment or transfer, of all or any portion of this Agreement by a Party without the prior written consent of the other Party shall be null and void and of no effect. - -1. [**No Third-Party Beneficiaries**]{.underline} This Agreement is not intended to benefit and shall not be construed to confer upon any person, other than the Parties, any rights, remedies, or other benefits, including but not limited to third-party beneficiary rights. - -1. [**Severability**]{.underline} If any one or more of the provisions of this Agreement shall be held to be invalid, illegal, or unenforceable, the validity, legality, or enforceability of the remaining provisions of this Agreement shall not be affected thereby. To the extent permitted by applicable law, each Party waives any provision of law which renders any provision of this Agreement invalid, illegal, or unenforceable in any respect. - -1. [**Confidential Information**]{.underline} As used herein, "Confidential Information" means all confidential information disclosed by a Party ("Disclosing Party") to the other Party ("Receiving Party"), whether orally or in writing, that is designated as confidential or that reasonably should be understood to be confidential given the nature of the information. Each Party agrees: (a) to observe complete confidentiality with respect to the Confidential Information of the Disclosing Party; (b) not to disclose, or permit any third party or entity access to disclose, the Confidential Information (or any portion thereof) of the Disclosing Party without prior written permission of Disclosing Party; and (c) to ensure that any employees, or any third parties who receive access to the Confidential Information, are advised of the confidential and proprietary nature thereof and are prohibited from disclosing the Confidential Information and using the Confidential Information other than for the benefit of the Receiving Party in accordance with this Agreement. Without limiting the foregoing, each Party shall use the same degree of care that it uses to protect the confidentiality of its own confidential information of like kind, but in no event less than reasonable care. Neither Party shall have any liability with respect to Confidential Information to the extent such information: (w) is or becomes publicly available (other than through a breach of this Agreement); (x) is or becomes available to the Receiving Party on a non-confidential basis, provided that the source of such information was not known by the Receiving Party (after such inquiry as would be reasonable in the circumstances) to be the subject of a confidentiality agreement or other legal or contractual obligation of confidentiality with respect to such information; (y) is developed by the Receiving Party independently and without reference to information provided by the Disclosing Party; or (z) is required to be disclosed by law or court order, provided the Receiving Party gives the Disclosing Party prior notice of such compelled disclosure (to the extent legally permitted) and reasonable assistance, at the Disclosing Party’s cost. - -1. [**Independent Contractors**]{.underline} Nothing contained herein shall constitute or be construed as the creation of any partnership, agency, or joint venture relationship between the Parties. Neither of the Parties shall have the right to obligate or bind the other Party in any manner whatsoever, and nothing herein contained shall give or is intended to give any rights of any kind to any third party. The relationship of the Parties shall be as independent contractors. - -1. [**Indemnification**]{.underline} Sponsor agrees to indemnify and hold harmless the PSF, its officers, directors, employees, and agents, for any and all claims, losses, damages, liabilities, judgments, or settlements, including reasonable attorneys’ fees, costs (including costs associated with any official investigations or inquiries) and other expenses, incurred on account of Sponsor’s acts or omissions in connection with the performance of this Agreement or breach of this Agreement or with respect to the manufacture, marketing, sale, or dissemination of any of Sponsor’s products or services. The PSF shall have no liability to Sponsor with respect to its participation in this Agreement or receipt of the Sponsorship Payment, except for intentional or willful acts of the PSF or its employees or agents. The rights and responsibilities established in this section shall survive indefinitely beyond the term of this Agreement. - -1. [**Notices**]{.underline} All notices or other communications to be given or delivered under the provisions of this Agreement shall be in writing and shall be mailed by certified or registered mail, return receipt requested, or given or delivered by reputable courier, facsimile, or electronic mail to the Party to receive notice at the following addresses or at such other address as any Party may by notice direct in accordance with this Section: - - - If to Sponsor: - - > {{sponsor.primary_contact.name}} - > {{sponsor.name}} - > {{sponsor.mailing_address_line_1}}{%if sponsor.mailing_address_line_2%} - > {{sponsor.mailing_address_line_2 }}{% endif %} - > {{sponsor.city}}, {{sponsor.state}} {{sponsor.postal_code}} {{sponsor.country}} - > Facsimile: {{sponsor.primary_contact.phone}} - > Email: {{sponsor.primary_contact.email}} - -   - - If to the PSF: - - > Deb Nicholson - > Executive Director - > Python Software Foundation - > 9450 SW Gemini Dr. ECM # 90772 - > Beaverton, OR 97008 USA - > Facsimile: +1 (858) 712-8966 - > Email: deb@python.org - -   - - With a copy to: - - > Archer & Greiner, P.C. - > Attention: Noel Fleming - > Three Logan Square - > 1717 Arch Street, Suite 3500 - > Philadelphia, PA 19103 USA - > Facsimile: (215) 963-9999 - > Email: nfleming@archerlaw.com - -   - - Notices given by registered or certified mail shall be deemed as given on the delivery date shown on the return receipt, and notices given in any other manner shall be deemed as given when received. - -1. [**Governing Law; Jurisdiction**]{.underline} This Agreement shall be construed in accordance with the laws of the State of Delaware, without regard to its conflicts of law principles. Jurisdiction and venue for litigation of any dispute, controversy, or claim arising out of or in connection with this Agreement shall be only in a United States federal court in Delaware or a Delaware state court having subject matter jurisdiction. Each of the Parties hereto hereby expressly submits to the personal jurisdiction of the foregoing courts located in Delaware and hereby waives any objection or defense based on personal jurisdiction or venue that might otherwise be asserted to proceedings in such courts. - -1. [**Force Majeure**]{.underline} The PSF shall not be liable for any failure or delay in performing its obligations hereunder if such failure or delay is due in whole or in part to any cause beyond its reasonable control or the reasonable control of its contractors, agents, or suppliers, including, but not limited to, strikes, or other labor disturbances, acts of God, acts of war or terror, floods, sabotage, fire, natural, or other disasters, including pandemics. To the extent the PSF is unable to substantially perform hereunder due to any cause beyond its control as contemplated herein, it may terminate this Agreement as it may decide in its sole discretion. To the extent the PSF so terminates the Agreement, Sponsor releases the PSF and waives any claims for damages or compensation on account of such termination. - -1. [**No Waiver**]{.underline} A waiver of any breach of any provision of this Agreement shall not be deemed a waiver of any repetition of such breach or in any manner affect any other terms of this Agreement. - -1. [**Limitation of Damages**]{.underline} Except as otherwise provided herein, neither Party shall be liable to the other for any consequential, incidental, or punitive damages for any claims arising directly or indirectly out of this Agreement. - -1. [**Cumulative Remedies**]{.underline} All rights and remedies provided in this Agreement are cumulative and not exclusive, and the exercise by either Party of any right or remedy does not preclude the exercise of any other rights or remedies that may now or subsequently be available at law, in equity, by statute, in any other agreement between the Parties, or otherwise. - -1. [**Captions**]{.underline} The captions and headings are included herein for convenience and do not constitute a part of this Agreement. - -1. [**Amendments**]{.underline} No addition to or change in the terms of this Agreement will be binding on any Party unless set forth in writing and executed by both Parties. - -1. [**Counterparts**]{.underline} This Agreement may be executed in one or more counterparts, each of which shall be deemed an original and all of which shall be taken together and deemed to be one instrument. A signed copy of this Agreement delivered by facsimile, electronic mail, or other means of electronic transmission shall be deemed to have the same legal effect as delivery of an original signed copy of this Agreement. - -1. [**Entire Agreement**]{.underline} This Agreement (including the Exhibits) sets forth the entire agreement of the Parties and supersedes all prior oral or written agreements or understandings between the Parties as to the subject matter of this Agreement. Except as otherwise expressly provided herein, neither Party is relying upon any warranties, representations, assurances, or inducements of the other Party. - -  - - -### \[Signature Page Follows\] - -::: {.page-break} -\newpage -::: - -## SPONSORSHIP AGREEMENT - -**IN WITNESS WHEREOF**, the Parties hereto have duly executed this **Sponsorship Agreement** as of the **Effective Date**. - -  - -> **PSF**: -> **PYTHON SOFTWARE FOUNDATION**, -> a Delaware non profit corporation - -  - -> By:        ________________________________ -> Name:   Loren Crary -> Title:     Director of Resource Development - -  - -  - -> **SPONSOR**: -> **{{sponsor.name|upper}}**, -> a {{sponsor.state}} entity - -  - -> By:        ________________________________ -> Name:   ________________________________ -> Title:     ________________________________ - -::: {.page-break} -\newpage -::: - -## SPONSORSHIP AGREEMENT - -### EXHIBIT A - -1. [**Sponsorship**]{.underline} During the Term of this Agreement, in return for the Sponsorship Payment, the PSF agrees to identify and acknowledge Sponsor as a {{sponsorship.year}} {{sponsorship.level_name}} Sponsor of the Programs and of the PSF, in accordance with the United States Internal Revenue Service guidance applicable to qualified sponsorship payments. - - Acknowledgments of appreciation for the Sponsorship Payment may identify and briefly describe Sponsor and its products or product lines in neutral terms and may include Sponsor’s name, logo, well-established slogan, locations, telephone numbers, or website addresses, but such acknowledgments shall not include (a) comparative or qualitative descriptions of Sponsor’s products, services, or facilities; (b) price information or other indications of savings or value associated with Sponsor’s products or services; (c) a call to action; (d) an endorsement; or (e) an inducement to buy, sell, or use Sponsor’s products or services. Any such acknowledgments will be created, or subject to prior review and approval, by the PSF. - - The PSF’s acknowledgment may include the following: - - (a) [**Display of Logo**]{.underline} The PSF will display Sponsor’s logo and other agreed-upon identifying information on www.python.org, and on any marketing and promotional media made by the PSF in connection with the Programs, solely for the purpose of acknowledging Sponsor as a sponsor of the Programs in a manner (placement, form, content, etc.) reasonably determined by the PSF in its sole discretion. Sponsor agrees to provide all the necessary content and materials for use in connection with such display. - - (a) Additional acknowledgment as provided in Sponsor Benefits. - -1. [**Sponsorship Payment**]{.underline} The amount of Sponsorship Payment shall be {{sponsorship.verbose_sponsorship_fee|title}} USD ($ {{sponsorship.sponsorship_fee}}). The Sponsorship Payment is due within thirty (30) days of the Effective Date. To the extent that any portion of a payment under this section would not (if made as a Separate payment) be deemed a qualified sponsorship payment under IRC § 513(i), such portion shall be deemed and treated as separate from the qualified sponsorship payment. - -1. [**Receipt of Payment**]{.underline} Sponsor must submit full payment in order to secure Sponsor Benefits. - -1. [**Refunds**]{.underline} The PSF does not offer refunds for sponsorships. The PSF may cancel the event(s) or any part thereof. In that event, the PSF shall determine and refund to Sponsor the proportionate share of the balance of the aggregate Sponsorship fees applicable to event(s) received which remain after deducting all expenses incurred by the PSF. - -1. [**Sponsor Benefits**]{.underline} Sponsor Benefits per the Agreement are: - - 1. Acknowledgement as described under "Sponsorship" above. - -{%for benefit in benefits%} 1. {{benefit}} -{%endfor%} - -{%if legal_clauses%}1. Legal Clauses. Related legal clauses are: - -{%for clause in legal_clauses%} 1. {{clause}} -{%endfor%}{%endif%} diff --git a/templates/sponsors/admin/preview-contract.html b/templates/sponsors/admin/preview-contract.html new file mode 100644 index 000000000..f89fd02b0 --- /dev/null +++ b/templates/sponsors/admin/preview-contract.html @@ -0,0 +1,283 @@ +{% extends "easy_pdf/base.html" %} +{% load humanize %} + +{% block extra_style %} + +{% endblock %} + +{% block content %} +

SPONSORSHIP AGREEMENT

+ +

THIS SPONSORSHIP AGREEMENT (the “Agreement”) is entered into and made +effective as of the {{ start_date|date:"dS" }} day of {{ start_date|date:"F, Y"}} (the “Effective Date”), by and between +Python Software Foundation (the “PSF”), a Delaware nonprofit corporation, and {{ sponsor.name|upper }} (“Sponsor”), a {{ sponsor.state }} corporation. Each of the PSF and Sponsor are +hereinafter sometimes individually referred to as a “Party” and collectively as the “Parties”.

+ +

RECITALS

+ +

WHEREAS, the PSF is a tax-exempt charitable organization (EIN 04-3594598) whose +mission is to promote, protect, and advance the Python programming language, and to support +and facilitate the growth of a diverse and international community of Python programmers (the +“Programs”);

+ +

WHEREAS, Sponsor is {{ contract.sponsor_info}}; and

+ +

WHEREAS, Sponsor wishes to support the Programs by making a contribution to the +PSF.

+ +

AGREEMENT

+ +

NOW, THEREFORE, in consideration of the foregoing and the mutual covenants +contained herein, and for other good and valuable consideration, the receipt and sufficiency of +which are hereby acknowledged, the Parties hereto agree as follows:

+ +
    +
  1. Recitals Incorporated. Each of the above Recitals is incorporated into and is made a part of this Agreement.
  2. + +
  3. Exhibits Incorporated by Reference. All exhibits referenced in this Agreement are incorporated herein as integral parts of this Agreement and shall be considered reiterated herein as fully as if such provisions had been set forth verbatim in this Agreement.
  4. + +
  5. Sponsorship Payment. In consideration for the right to sponsor the PSF and its Programs, and to be acknowledged by the PSF as a sponsor in the manner described herein, Sponsor shall make a contribution to the PSF (the “Sponsorship Payment”) in the amount shown in Exhibit A.
  6. + +
  7. Acknowledgement of Sponsor. In return for the Sponsorship Payment, Sponsor will be entitled to receive the sponsorship package described in Exhibit A attached hereto (the “Sponsor Benefits”).
  8. + +
  9. Intellectual Property. The PSF is the sole owner of all right, title, and interest to all the PSF information, including the PSF’s logo, trademarks, trade names, and copyrighted information, unless otherwise provided.
  10. + +
      +
    1. Grant of License by the PSF. The PSF hereby grants to Sponsor a limited, non-exclusive license to use certain of the PSF’s intellectual property, including the PSF’s name, acronym, and logo (collectively, the “PSF Intellectual Property”), solely in connection with promotion of Sponsor’s sponsorship of the Programs. Sponsor agrees that it shall not use the PSF’s Property in a manner that states or implies that the PSF endorses Sponsor (or Sponsor’s products or services). The PSF retains the right, in its sole and absolute discretion, to review and approve in advance all uses of the PSF Intellectual Property, which approval shall not be unreasonably withheld.
    2. + +
    3. Grant of License by Sponsor. Sponsor hereby grants to the PSF a limited, non-exclusive license to use certain of Sponsor’s intellectual property, including names, trademarks, and copyrights (collectively, “Sponsor Intellectual Property”), solely to identify Sponsor as a sponsor of the Programs and the PSF. Sponsor retains the right to review and approve in advance all uses of the Sponsor Intellectual Property, which approval shall not be unreasonably withheld.
    4. +
    + + +
  11. Term. The Term of this Agreement will begin on {{ start_date|date:"dS, F Y"}} and continue for a period of one (1) year. The Agreement may be renewed for one (1) year by written notice from Sponsor to the PSF.
  12. + +
  13. Termination. The Agreement may be terminated (i) by either Party for any reason upon sixty (60) days prior written notice to the other Party; (ii) if one Party notifies the other Party that the other Party is in material breach of its obligations under this Agreement and such breach (if curable) is not cured with fifteen (15) days of such notice; (iii) if both Parties agree to terminate by mutual written consent; or (iv) if any of Sponsor information is found or is reasonably alleged to violate the rights of a third party. The PSF shall also have the unilateral right to terminate this Agreement at any time if it reasonably determines that it would be detrimental to the reputation and goodwill of the PSF or the Programs to continue to accept or use funds from Sponsor. Upon expiration or termination, no further use may be made by either Party of the other’s name, marks, logo or other intellectual property without the express prior written authorization of the other Party.
  14. + +
  15. Code of Conduct. Sponsor and all of its representatives shall conduct themselves at all times in accordance with the Python Software Foundation Code of Conduct (https://www.python.org/psf/codeofconduct) and/or the PyCon Code of Conduct (https://us.pycon.org/2021/about/code-of-conduct/), as applicable. The PSF reserves the right to eject from any event any Sponsor or representative violating those standards.
  16. + +
  17. Deadlines. Company logos, descriptions, banners, advertising pages, tote bag inserts and similar items and information must be provided by the applicable deadlines for inclusion in the promotional materials for the PSF.
  18. + +
  19. Assignment of Space. If the Sponsor Benefits in Exhibit A include a booth or other display space, the PSF shall assign display space to Sponsor for the period of the display. Location assignments will be on a first-come, first-served basis and will be made solely at the discretion of the PSF. Failure to use a reserved space will result in penalties (up to 50% of your Sponsorship Payment).
  20. + +
  21. Job Postings. Sponsor will ensure that any job postings to be published by the PSF on Sponsor’s behalf comply with all applicable municipal, state, provincial, and federal laws.
  22. + +
  23. Representations and Warranties. Each Party represents and warrants for the benefit of the other Party that it has the legal authority to enter into this Agreement and is able to comply with the terms herein. Sponsor represents and warrants for the benefit of the PSF that it has full right and title to the Sponsor Intellectual Property to be provided under this Agreement and is not under any obligation to any party that restricts the Sponsor Intellectual Property or would prevent Sponsor’s performance under this Agreement.
  24. + +
  25. Successors and Assigns. This Agreement and all the terms and provisions hereof shall be binding upon and inure to the benefit of the Parties and their respective legal representatives, heirs, successors, and/or assigns. The transfer, or any attempted assignment or transfer, of all or any portion of this Agreement by a Party without the prior written consent of the other Party shall be null and void and of no effect.
  26. + +
  27. No Third-Party Beneficiaries. This Agreement is not intended to benefit and shall not be construed to confer upon any person, other than the Parties, any rights, remedies, or other benefits, including but not limited to third-party beneficiary rights.
  28. + +
  29. Severability. If any one or more of the provisions of this Agreement shall be held to be invalid, illegal, or unenforceable, the validity, legality, or enforceability of the remaining provisions of this Agreement shall not be affected thereby. To the extent permitted by applicable law, each Party waives any provision of law which renders any provision of this Agreement invalid, illegal, or unenforceable in any respect.
  30. + +
  31. Confidential Information. As used herein, “Confidential Information” means all confidential information disclosed by a Party (“Disclosing Party”) to the other Party (“Receiving Party”), whether orally or in writing, that is designated as confidential or that reasonably should be understood to be confidential given the nature of the information. Each Party agrees: (a) to observe complete confidentiality with respect to the Confidential Information of the Disclosing Party; (b) not to disclose, or permit any third party or entity access to disclose, the Confidential Information (or any portion thereof) of the Disclosing Party without prior written permission of Disclosing Party; and (c) to ensure that any employees, or any third parties who receive access to the Confidential Information, are advised of the confidential and proprietary nature thereof and are prohibited from disclosing the Confidential Information and using the Confidential Information other than for the benefit of the Receiving Party in accordance with this Agreement. Without limiting the foregoing, each Party shall use the same degree of care that it uses to protect the confidentiality of its own confidential information of like kind, but in no event less than reasonable care. Neither Party shall have any liability with respect to Confidential Information to the extent such information: (w) is or becomes publicly available (other than through a breach of this Agreement); (x) is or becomes available to the Receiving Party on a non-confidential basis, provided that the source of such information was not known by the Receiving Party (after such inquiry as would be reasonable in the circumstances) to be the subject of a confidentiality agreement or other legal or contractual obligation of confidentiality with respect to such information; (y) is developed by the Receiving Party independently and without reference to information provided by the Disclosing Party; or (z) is required to be disclosed by law or court order, provided the Receiving Party gives the Disclosing Party prior notice of such compelled disclosure (to the extent legally permitted) and reasonable assistance, at the Disclosing Party’s cost.
  32. + +
  33. Independent Contractors. Nothing contained herein shall constitute or be construed as the creation of any partnership, agency, or joint venture relationship between the Parties. Neither of the Parties shall have the right to obligate or bind the other Party in any manner whatsoever, and nothing herein contained shall give or is intended to give any rights of any kind to any third party. The relationship of the Parties shall be as independent contractors.
  34. + +
  35. Indemnification. Sponsor agrees to indemnify and hold harmless the PSF, its officers, directors, employees, and agents, for any and all claims, losses, damages, liabilities, judgments, or settlements, including reasonable attorneys’ fees, costs (including costs associated with any official investigations or inquiries) and other expenses, incurred on account of Sponsor’s acts or omissions in connection with the performance of this Agreement or breach of this Agreement or with respect to the manufacture, marketing, sale, or dissemination of any of Sponsor’s products or services. The PSF shall have no liability to Sponsor with respect to its participation in this Agreement or receipt of the Sponsorship Payment, except for intentional or willful acts of the PSF or its employees or agents. The rights and responsibilities established in this section shall survive indefinitely beyond the term of this Agreement.
  36. + +
  37. + Notices. All notices or other communications to be given or delivered under the provisions of this Agreement shall be in writing and shall be mailed by certified or registered mail, return receipt requested, or given or delivered by reputable courier, facsimile, or electronic mail to the Party to receive notice at the following addresses or at such other address as any Party may by notice direct in accordance with this Section: + +
    +
    +

    If to Sponsor:

    +
    +

    {{ sponsor.primary_contact.name }}

    +

    {{ sponsor.name }}

    +

    {{ sponsor.mailing_address_line_1 }}

    + {% if sponsor.mailing_address_line_2 %} +

    {{ sponsor.mailing_address_line_2 }}

    + {% endif %} +

    Facsimile: {{ sponsor.primary_contact.phone }}

    +

    Email: {{ sponsor.primary_contact.email }}

    +
    +

    If to the PSF:

    +
    +

    Ewa Jodlowska

    +

    Executive Director

    +

    Python Software Foundation

    +

    9450 SW Gemini Dr. ECM # 90772

    +

    Beaverton, OR 97008 USA

    +

    Facsimile: +1 (858) 712-8966

    +

    Email: ewa@python.org

    +
    +

    With a copy to:

    +

    Fleming Petenko Law

    +

    1800 John F. Kennedy Blvd

    +

    Suite 904

    +

    Philadelphia, PA 19103 USA

    +

    Facsimile: (267) 422-9864

    +

    Email: info@nonprofitlawllc.com

    +
    +
    +

    Notices given by registered or certified mail shall be deemed as given on the delivery date shown on the return receipt, and notices given in any other manner shall be deemed as given when received.

    +
  38. + +
  39. Governing Law; Jurisdiction. This Agreement shall be construed in accordance with the laws of the State of Delaware, without regard to its conflicts of law principles. Jurisdiction and venue for litigation of any dispute, controversy, or claim arising out of or in connection with this Agreement shall be only in a United States federal court in Delaware or a Delaware state court having subject matter jurisdiction. Each of the Parties hereto hereby expressly submits to the personal jurisdiction of the foregoing courts located in Delaware and hereby waives any objection or defense based on personal jurisdiction or venue that might otherwise be asserted to proceedings in such courts.
  40. + +
  41. Force Majeure. The PSF shall not be liable for any failure or delay in performing its obligations hereunder if such failure or delay is due in whole or in part to any cause beyond its reasonable control or the reasonable control of its contractors, agents, or suppliers, including, but not limited to, strikes, or other labor disturbances, acts of God, acts of war or terror, floods, sabotage, fire, natural, or other disasters, including pandemics. To the extent the PSF is unable to substantially perform hereunder due to any cause beyond its control as contemplated herein, it may terminate this Agreement as it may decide in its sole discretion. To the extent the PSF so terminates the Agreement, Sponsor releases the PSF and waives any claims for damages or compensation on account of such termination.
  42. + +
  43. No Waiver. A waiver of any breach of any provision of this Agreement shall not be deemed a waiver of any repetition of such breach or in any manner affect any other terms of this Agreement.
  44. + +
  45. Limitation of Damages. Except as otherwise provided herein, neither Party shall be liable to the other for any consequential, incidental, or punitive damages for any claims arising directly or indirectly out of this Agreement.
  46. + +
  47. Cumulative Remedies. All rights and remedies provided in this Agreement are cumulative and not exclusive, and the exercise by either Party of any right or remedy does not preclude the exercise of any other rights or remedies that may now or subsequently be available at law, in equity, by statute, in any other agreement between the Parties, or otherwise.
  48. + +
  49. Captions. The captions and headings are included herein for convenience and do not constitute a part of this Agreement.
  50. + +
  51. Amendments. No addition to or change in the terms of this Agreement will be binding on any Party unless set forth in writing and executed by both Parties.
  52. + +
  53. Counterparts. This Agreement may be executed in one or more counterparts, each of which shall be deemed an original and all of which shall be taken together and deemed to be one instrument. A signed copy of this Agreement delivered by facsimile, electronic mail, or other means of electronic transmission shall be deemed to have the same legal effect as delivery of an original signed copy of this Agreement.
  54. + +
  55. Entire Agreement. This Agreement (including the Exhibits) sets forth the entire agreement of the Parties and supersedes all prior oral or written agreements or understandings between the Parties as to the subject matter of this Agreement. Except as otherwise expressly provided herein, neither Party is relying upon any warranties, representations, assurances, or inducements of the other Party.
  56. +
+ +

[Signature Page Follows]

+
+ +

SPONSORSHIP AGREEMENT

+ + +

IN WITNESS WHEREOF, the Parties hereto have duly executed this __________________ Agreement as of the Effective Date.

+ +
+

PSF:

+

PYTHON SOFTWARE FOUNDATION,

+

a Delaware nonprofit corporation

+ +
+
+ +

By: + ___________________________________

+
+

Ewa Jodlowska

+

Executive Director

+
+ +
+
+ +

SPONSOR:

+

______________________________________,

+

a {{ sponsor.state }} entity.

+
+

By: ___________________________________

+ +
+
+ +

SPONSORSHIP AGREEMENT

+ +

EXHIBIT A

+ +
    +
  1. Sponsorship. During the Term of this Agreement, in return for the Sponsorship Payment, the PSF agrees to identify and acknowledge Sponsor as a {{ start_date|date:'Y' }} {{ sponsorship.level_name }} Sponsor of the Programs and of the PSF, in accordance with the United States Internal Revenue Service guidance applicable to qualified sponsorship payments.
  2. + +

    Acknowledgments of appreciation for the Sponsorship Payment may identify and briefly describe Sponsor and its products or product lines in neutral terms and may include Sponsor’s name, logo, well-established slogan, locations, telephone numbers, or website addresses, but such acknowledgments shall not include (a) comparative or qualitative descriptions of Sponsor’s products, services, or facilities; (b) price information or other indications of savings or value associated with Sponsor’s products or services; (c) a call to action; (d) an endorsement; or (e) an inducement to buy, sell, or use Sponsor’s products or services. Any such acknowledgments will be created, or subject to prior review and approval, by the PSF.

    + +

    The PSF’s acknowledgment may include the following:

    + +
      +
    1. Display of Logo. The PSF will display Sponsor’s logo and other agreed-upon identifying information on www.python.org, and on any marketing and promotional media made by the PSF in connection with the Programs, solely for the purpose of acknowledging Sponsor as a sponsor of the Programs in a manner (placement, form, content, etc.) reasonably determined by the PSF in its sole discretion. Sponsor agrees to provide all the necessary content and materials for use in connection with such display.
    2. + +
    3. [Other use or Acknowledgement.]
    4. +
    + +
  3. Sponsorship Payment. The amount of Sponsorship Payment shall be {{ sponsorship.verbose_sponsorship_fee|title }} USD ($ {{ sponsorship.sponsorship_fee|intcomma }}). The Sponsorship Payment is due within thirty (30) days of the Effective Date. To the extent that any portion of a payment under this section would not (if made as a Separate payment) be deemed a qualified sponsorship payment under IRC § 513(i), such portion shall be deemed and treated as separate from the qualified sponsorship payment.
  4. + +
  5. Receipt of Payment. Sponsor must submit full payment in order to secure Sponsor Benefits.
  6. + +
  7. Refunds. The PSF does not offer refunds for sponsorships. The PSF may cancel the event(s) or any part thereof. In that event, the PSF shall determine and refund to Sponsor the proportionate share of the balance of the aggregate Sponsorship fees applicable to event(s) received which remain after deducting all expenses incurred by the PSF.
  8. + +
  9. Sponsor Benefits. Sponsor Benefits per the Agreement are:
  10. + +
      +
    1. Acknowledgement as described under “Sponsorship” above.
    2. + {% for benefit in benefits %} +
    3. {{ benefit }}
    4. + {% endfor %} +
    + + + {% if legal_clauses %} +
  11. Legal Clauses. Related legal clauses are:
  12. +
      + {% for clause in legal_clauses %} +
    1. {{ clause }}
    2. + {% endfor %} +
    + {% endif %} +
+ +{% endblock %} diff --git a/templates/sponsors/admin/renewal-contract-template.docx b/templates/sponsors/admin/renewal-contract-template.docx new file mode 100644 index 0000000000000000000000000000000000000000..3e36801a316f85a4a0484c7b4ed1a227a9fb4285 GIT binary patch literal 9323 zcma)C1yozxwhiuu;_hDD-QC@3X>kg{f;$us?iBY@+@-j?OM&99#hre*|Gj^E@Bi

E*dJc2N$B6)ouG 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 uz+Wd(o%mnyza-?p3o*ymGZjwy)a`s>Q`g|M! literal 0 HcmV?d00001 diff --git a/texlive.packages b/texlive.packages deleted file mode 100644 index fc8668ea0..000000000 --- a/texlive.packages +++ /dev/null @@ -1,2 +0,0 @@ -xcolor -etoolbox