add fund designation to donations

pull/94/head
eric 2021-06-25 13:41:35 -04:00
parent 1856f47b48
commit da7d651387
13 changed files with 115 additions and 24 deletions

View File

@ -106,3 +106,9 @@ ORDER_BY_KEYS = {
'title':['title'], 'title':['title'],
'none':[], #no ordering 'none':[], #no ordering
} }
DONATION_CHOICES = (
('general', 'The FEF General Fund'),
('monographs', 'The FEF Open Access Monographs Fund'),
)

View File

@ -46,6 +46,7 @@ from regluit.core.parameters import (
REWARDS, REWARDS,
BUY2UNGLUE, BUY2UNGLUE,
THANKS, THANKS,
DONATION_CHOICES,
) )
from regluit.core.lookups import ( from regluit.core.lookups import (
OwnerLookup, OwnerLookup,
@ -347,7 +348,7 @@ class CampaignThanksForm(forms.Form):
) )
preapproval_amount = forms.DecimalField( preapproval_amount = forms.DecimalField(
required = True, required = True,
min_value=D('5.00'), min_value=D('2.00'),
max_value=D('2000.00'), max_value=D('2000.00'),
decimal_places=2, decimal_places=2,
label="Pledge Amount", label="Pledge Amount",
@ -357,6 +358,7 @@ class CampaignThanksForm(forms.Form):
pe = PledgeExtra( anonymous=self.cleaned_data['anonymous'] ) pe = PledgeExtra( anonymous=self.cleaned_data['anonymous'] )
class DonationForm(forms.Form): class DonationForm(forms.Form):
# used only for validation; not currently used for display
amount = forms.DecimalField( amount = forms.DecimalField(
required = True, required = True,
min_value=D('5.00'), min_value=D('5.00'),
@ -364,6 +366,7 @@ class DonationForm(forms.Form):
decimal_places=2, decimal_places=2,
label="Donation Amount", label="Donation Amount",
) )
reason = forms.ChoiceField(choices=DONATION_CHOICES, required=False)
class CampaignPledgeForm(forms.Form): class CampaignPledgeForm(forms.Form):
@ -434,6 +437,7 @@ class TokenCCMixin(forms.Form):
class BaseCCMixin(forms.Form): class BaseCCMixin(forms.Form):
work_id = forms.IntegerField(required=False, widget=forms.HiddenInput()) work_id = forms.IntegerField(required=False, widget=forms.HiddenInput())
reason = forms.CharField(required=False, widget=forms.HiddenInput())
preapproval_amount = forms.DecimalField( preapproval_amount = forms.DecimalField(
required=False, required=False,
min_value=D('1.00'), min_value=D('1.00'),

View File

@ -0,0 +1,66 @@
{% extends 'basedocumentation.html' %}
{% load sass_tags %}
{% block title %} Free Ebook Foundation Donations {% endblock %}
{% block extra_css %}
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/pledge.scss' %}" />
{% endblock %}
{% block topsection %}
{% endblock %}
{% block doccontent %}
<h2> Donating to Unglue.it </h2>
<p>
Unglue.it is a program of the <a href="https://ebookfoundation.org">Free Ebook Foundation</a> (FEF), which is a charitable, not-for-profit corporation.
Donations to the Free Ebook Foundation are tax-deductible in the United States.
</p>
<p>
When you donate to the Free Ebook Foundation, you can specify how you would like your donation to be used. There are currently two options:
</p>
<ul class="bullets">
<li> <a href="#monographs">The FEF Open Access Monographs Fund</a>: to support the Ungluing of peer-reviewed monographs that advance scholarship, science and learning </li>
<li> <a href="#general">The FEF General Fund</a>: to support the operation and maintenance of the Foundation's programs, including Unglue.it.
</ul>
<h3 id="monographs">The FEF Open Access Monograph Fund</h3>
<p>
Scholars write books to spread their ideas, so it makes sense to make them free and available.
We refer to these books as "monographs" because they usually embody the scholarship of a single author.
Already, over 30,000 of these books are available to download from the Unglue.it database.
Sadly, many more books are locked up behind paywalls - not because their authors want to make money, but because the publishers of these books need to recoup the cost of editorial work and design.
Many new books will remain unpublished because publishers committed to Open Access have insufficient resources to publish all the books deserving of wider audiences.
</p>
<p>
As a small step towards addressing these needs, we're offering donors a chance to help us unglue more of these monographs by donating to a special fund.
The fund will be used to match contributions to qualified ungluing campaigns on Unglue.it.
To participate, authors should first work with a publisher to establish a campaign target, and then create an ungluing campaign.
To get started, follow the steps at our <a href="{% url 'rightsholders' %}">right holder tools page</a>.
Our staff will verify that the book has been or will be peer-reviewed and advances scholarship, science and learning.
Resources from the fund will be allocated to maximize the success of the eligible campaigns.
If you want to donate to a specific campaign, just donate to the campaign directly.
</p>
<h3 id="general">The FEF General Fund</h3>
<p>
If you prefer to support all the work of the Free Ebook Foundation, including Unglue.it, Free-Programming-Books, and our work supporting Project Gutenberg, just use the General Fund.
</p>
<h2 id="donationform">Donate Now!</h2>
<div id="authorize" class="jsmod-content" >
<form class="askform" method="POST" action="{% url 'newdonation' %}">
<p class=" form-row clearfix">
<input id="id_reason_monographs" checked type="radio" value="monographs" name="reason"><label for="id_reason_monographs">FEF Open Access Monographs Fund</label>
</p> <p class=" form-row clearfix">
<input id="id_reason_general" type="radio" value="general" name="reason"><label for="id_reason_general">FEF General Fund</label>
</p>
<div class="donate_amount clearfix">
<label>Amount ($): </label><input id="amount" max="20000.00" min="5.00" name="amount" step="0.01" type="number" value="10.00" class="donate"></div>
<div class="button">
<input name="pledge" type="submit" value="Donate" id="donatesubmit" class="donate" />
</div>
</form>
</div>
{% endblock %}

View File

@ -203,8 +203,9 @@ function put_un_in_cookie2(){
<div class="jsmodule"> <div class="jsmodule">
<h3 class="module-title">Donate!</h3> <h3 class="module-title">Donate!</h3>
<div class="jsmod-content"> <div class="jsmod-content">
<div>Please help support Unglue.it by making a tax-deductible donation to the Free Ebook Foundation.</div> <div>Please help support Unglue.it by making a tax-deductible donation to the Free Ebook Foundation. Donations are currently directed to our <a href="{% url "about_funds" %}#monographs">Monographs Matching Fund</a>.</div>
<form class="askform" method="POST" action="{% url 'newdonation' %}"> <form class="askform" method="POST" action="{% url 'newdonation' %}">
<input type="hidden" value="monographs" name="reason">
<div class="donate_amount"> <div class="donate_amount">
<label>Amount ($): </label><input id="amount" max="20000.00" min="5.00" name="amount" step="0.01" type="number" value="10.00" class="donate"></div> <label>Amount ($): </label><input id="amount" max="20000.00" min="5.00" name="amount" step="0.01" type="number" value="10.00" class="donate"></div>
<div class="button"> <div class="button">

View File

@ -1,6 +1,6 @@
{% load humanize %}{% ifequal transaction.host 'credit' %}Your Unglue.it transaction has completed and ${{transaction.max_amount|default:"0"}} has been deducted from your Unglue.it credit balance. You have ${{transaction.user.credit.available|default:"0"}} of credit left. {% else %}{% if transaction.max_amount > transaction.amount %}Your transaction for ${{transaction.max_amount|default:"0"}} has completed. Your credit card has been charged ${{transaction.amount}} and the rest has been deducted from your unglue.it credit balance. You have ${{transaction.user.credit.available|default:"0"}} of credit left. {% else %}Your Unglue.it credit card transaction has completed and your credit card has been charged ${{ transaction.amount|default:"0" }}. {% endif %}{% endifequal %} {% load humanize %}{% ifequal transaction.host 'credit' %}Your Unglue.it transaction has completed and ${{transaction.max_amount|default:"0"}} has been deducted from your Unglue.it credit balance. You have ${{transaction.user.credit.available|default:"0"}} of credit left. {% else %}{% if transaction.max_amount > transaction.amount %}Your transaction for ${{transaction.max_amount|default:"0"}} has completed. Your credit card has been charged ${{transaction.amount}} and the rest has been deducted from your unglue.it credit balance. You have ${{transaction.user.credit.available|default:"0"}} of credit left. {% else %}Your Unglue.it credit card transaction has completed and your credit card has been charged ${{ transaction.amount|default:"0" }}. {% endif %}{% endifequal %}
Your donation of ${{transaction.max_amount|default:"0"}} to the Free Ebook Foundation will help us make free ebooks of all types more accessible for those that need them. The Free Ebook Foundation is a US 501(c)3 non-profit organization. Our tax ID number is 61-1767266. Your gift is tax deductible to the full extent provided by the law. Your donation of ${{transaction.max_amount|default:"0"}} to the Free Ebook Foundation {{ transaction.fund.name }} will help us make free ebooks more accessible for those that need them. The Free Ebook Foundation is a US 501(c)3 non-profit organization. Our tax ID number is 61-1767266. Your gift is tax deductible to the full extent provided by the law.
For more information about the Free Ebook Foundation, visit https://ebookfoundation.org/ For more information about the Free Ebook Foundation, visit https://ebookfoundation.org/

View File

@ -23,7 +23,7 @@
{% endblock %} {% endblock %}
{% block comments_textual %} {% block comments_textual %}
<p>Your donation of ${{transaction.max_amount|default:"0"}} to the Free Ebook Foundation will help us make free ebooks of all types more accessible for those that need them. The Free Ebook Foundation is a US 501(c)3 non-profit organization. Our tax ID number is 61-1767266. Your gift is tax deductible to the full extent provided by the law.<p> <p>Your donation of ${{transaction.max_amount|default:"0"}} to the Free Ebook Foundation {{ transaction.fund.name }} will help us make free ebooks more accessible for those that need them. The Free Ebook Foundation is a US 501(c)3 non-profit organization. Our tax ID number is 61-1767266. Your gift is tax deductible to the full extent provided by the law.<p>
<p>For more information about the Free Ebook Foundation, visit <a href="https://ebookfoundation.org/ ">our website</a>. <p>For more information about the Free Ebook Foundation, visit <a href="https://ebookfoundation.org/ ">our website</a>.
</p> </p>
<p>Thank you again for your support. <p>Thank you again for your support.

View File

@ -1 +1 @@
You have donated ${{transaction.amount}} to the Free Ebook Foundation. You have donated ${{transaction.amount}} to the Free Ebook Foundation{{ transaction.fund.name }}.

View File

@ -7,9 +7,9 @@
{% block extra_extra_head %} {% block extra_extra_head %}
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/searchandbrowse2.scss' %}" /> <link type="text/css" rel="stylesheet" href="{% sass_src 'scss/searchandbrowse2.scss' %}" />
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/book_panel2.scss' %}" />
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/pledge.scss' %}" /> <link type="text/css" rel="stylesheet" href="{% sass_src 'scss/pledge.scss' %}" />
{% if campaign %}
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/book_panel2.scss' %}" />
<script src="/static/js/slides.min.jquery.js"></script> <script src="/static/js/slides.min.jquery.js"></script>
<script src="/static/js/slideshow.js"></script> <script src="/static/js/slideshow.js"></script>
<script src="/static/js/greenpanel.js"></script> <script src="/static/js/greenpanel.js"></script>
@ -24,6 +24,7 @@
<script type="text/javascript" src="/static/js/wishlist.js"></script> <script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script> <script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/embed.js"></script> <script type="text/javascript" src="/static/js/embed.js"></script>
{% endif %}
{% endblock %} {% endblock %}
{% block doccontent %} {% block doccontent %}
@ -31,7 +32,7 @@
<h2 class="thank-you">Thank you!</h2> <h2 class="thank-you">Thank you!</h2>
{% if not campaign %} {% if not campaign %}
<p class="pledge_complete">You've just donated ${{ transaction.amount|floatformat:2|intcomma }} to the <a href="https://ebookfoundation.org">Free Ebook Foundation</a></p> <p class="pledge_complete">You've just donated ${{ transaction.amount|floatformat:2|intcomma }} to the <a href="{% url 'about_funds' %}#{{ transaction.reason }}">Free Ebook Foundation {{ transaction.fund.name }}</a></p>
{% elif campaign.type == 1 %} {% elif campaign.type == 1 %}
{% if campaign.donation %} {% if campaign.donation %}
<p class="pledge_complete">You've just donated ${{ transaction.amount|floatformat:2|intcomma }} in support of <I><a href="{% url 'work' work.id %}">{{ work.title }}</a></I>. If it reaches its goal of ${{ campaign.target|intcomma }} by {{ campaign.deadline|date:"M d Y"}}, it will be unglued for all to enjoy. Otherwise, your donation will be used to support qualifying ungluing campaigns. Your donation to the Free Ebook Foundation is tax-deductible in the US.</p> <p class="pledge_complete">You've just donated ${{ transaction.amount|floatformat:2|intcomma }} in support of <I><a href="{% url 'work' work.id %}">{{ work.title }}</a></I>. If it reaches its goal of ${{ campaign.target|intcomma }} by {{ campaign.deadline|date:"M d Y"}}, it will be unglued for all to enjoy. Otherwise, your donation will be used to support qualifying ungluing campaigns. Your donation to the Free Ebook Foundation is tax-deductible in the US.</p>

View File

@ -119,6 +119,8 @@ urlpatterns = [
url(r"^feedback/thanks/$", TemplateView.as_view(template_name="thanks.html")), url(r"^feedback/thanks/$", TemplateView.as_view(template_name="thanks.html")),
url(r"^about/$", TemplateView.as_view(template_name="about_main.html"), url(r"^about/$", TemplateView.as_view(template_name="about_main.html"),
name="about"), name="about"),
url(r"^about/funds/$", TemplateView.as_view(template_name="about_funds.html"),
name="about_funds"),
url(r"^comments/$", views.comment, name="comment"), url(r"^comments/$", views.comment, name="comment"),
url(r"^info/(?P<template_name>[\w\.]*)$", views.InfoPageView.as_view()), url(r"^info/(?P<template_name>[\w\.]*)$", views.InfoPageView.as_view()),
url(r"^info/languages/(?P<template_name>[\w\.]*)$", views.InfoLangView.as_view()), url(r"^info/languages/(?P<template_name>[\w\.]*)$", views.InfoLangView.as_view()),

View File

@ -1153,14 +1153,16 @@ class NewDonationView(FormView):
def form_valid(self, form): def form_valid(self, form):
p = PaymentManager() p = PaymentManager()
t, url = p.process_transaction('USD', form.cleaned_data["amount"], t, url = p.process_transaction('USD', form.cleaned_data["amount"],
user = self.request.user, user=self.request.user,
paymentReason="Donation to {}".format(COMPANY_TITLE), paymentReason=form.cleaned_data.get("reason", ""),
) )
if url: if url:
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
else: else:
logger.error("Attempt to produce transaction id {0} failed".format(t.id)) logger.error("Attempt to produce transaction id %s failed", t.id)
return HttpResponse("Our attempt to set up your donation failed. We have logged this problem.") return HttpResponse(
"Our attempt to set up your donation failed. We have logged this problem."
)
class FundView(FormView): class FundView(FormView):

View File

@ -734,6 +734,7 @@ class PaymentManager(object):
user=user, user=user,
pledge_extra=pledge_extra, pledge_extra=pledge_extra,
donation=donation, donation=donation,
reason=paymentReason,
) )
t.save() t.save()
# does user have enough credit to transact now? # does user have enough credit to transact now?

View File

@ -28,18 +28,16 @@ from notification import models as notification
## regluit imports ## regluit imports
from regluit.payment.parameters import ( from regluit.payment.parameters import (
PAYMENT_TYPE_NONE,
PAYMENT_TYPE_AUTHORIZATION,
PAYMENT_HOST_NONE,
PAYMENT_HOST_CREDIT,
EXECUTE_TYPE_NONE, EXECUTE_TYPE_NONE,
TRANSACTION_STATUS_NONE, FUNDS,
PAYMENT_HOST_CREDIT,
PAYMENT_HOST_NONE,
PAYMENT_TYPE_AUTHORIZATION,
PAYMENT_TYPE_NONE,
TRANSACTION_STATUS_ACTIVE, TRANSACTION_STATUS_ACTIVE,
TRANSACTION_STATUS_ERROR, TRANSACTION_STATUS_ERROR,
TRANSACTION_STATUS_FAILED, TRANSACTION_STATUS_FAILED,
TRANSACTION_STATUS_NONE,
) )
from regluit.payment.signals import credit_balance_added, pledge_created from regluit.payment.signals import credit_balance_added, pledge_created
@ -97,7 +95,7 @@ class Transaction(models.Model):
# error message from a transaction # error message from a transaction
error = models.CharField(max_length=256, null=True) error = models.CharField(max_length=256, null=True)
# IPN.reason_code # reason_code - originally an IPN thing, now used for fund identification
reason = models.CharField(max_length=64, null=True) reason = models.CharField(max_length=64, null=True)
# creation and last modified timestamps # creation and last modified timestamps
@ -232,7 +230,7 @@ class Transaction(models.Model):
@classmethod @classmethod
def create(cls, amount=0.00, host=PAYMENT_HOST_NONE, max_amount=0.00, currency='USD', def create(cls, amount=0.00, host=PAYMENT_HOST_NONE, max_amount=0.00, currency='USD',
status=TRANSACTION_STATUS_NONE, campaign=None, user=None, pledge_extra=None, status=TRANSACTION_STATUS_NONE, campaign=None, user=None, pledge_extra=None,
donation=False): donation=False, reason=''):
if user and user.is_anonymous: if user and user.is_anonymous:
user = None user = None
t = cls.objects.create( t = cls.objects.create(
@ -244,11 +242,16 @@ class Transaction(models.Model):
campaign=campaign, campaign=campaign,
user=user, user=user,
donation=donation, donation=donation,
reason=reason,
) )
if pledge_extra: if pledge_extra:
t.set_pledge_extra(pledge_extra) t.set_pledge_extra(pledge_extra)
return t return t
def fund(self):
val = "general" if not self.reason else self.reason
return FUNDS.get(self.reason, {"name": ""})
class PaymentResponse(models.Model): class PaymentResponse(models.Model):
# The API used # The API used
api = models.CharField(max_length=64, null=False) api = models.CharField(max_length=64, null=False)

View File

@ -53,3 +53,8 @@ TRANSACTION_STATUS_FAILED = 'Failed'
TRANSACTION_STATUS_WRITTEN_OFF = 'Written-Off' TRANSACTION_STATUS_WRITTEN_OFF = 'Written-Off'
COMPANY_TITLE = 'Free Ebook Foundation' COMPANY_TITLE = 'Free Ebook Foundation'
FUNDS = {
"general": {"name": "General Fund"},
"monographs": {"name": "Monographs Fund"},
}