Changeset - 3fe83d14667f
[Not reviewed]
0 3 1
Ben Sturmfels (bsturmfels) - 18 days ago 2024-09-30 07:40:29
ben@sturm.com.au
Add annual renew
4 files changed with 56 insertions and 14 deletions:
0 comments (0 inline, 0 general)
conservancy/supporters/migrations/0003_remove_sustainerorder_monthly_recurring_and_more.py
Show inline comments
 
new file 100644
 
# Generated by Django 4.2.11 on 2024-09-30 03:33
 

	
 
from django.db import migrations, models
 

	
 

	
 
class Migration(migrations.Migration):
 

	
 
    dependencies = [
 
        ('supporters', '0002_sustainerorder_monthly_recurring_and_more'),
 
    ]
 

	
 
    operations = [
 
        migrations.RemoveField(
 
            model_name='sustainerorder',
 
            name='monthly_recurring',
 
        ),
 
        migrations.AddField(
 
            model_name='sustainerorder',
 
            name='recurring',
 
            field=models.CharField(default='', max_length=10),
 
            preserve_default=False,
 
        ),
 
        migrations.AlterField(
 
            model_name='sustainerorder',
 
            name='acknowledge_publicly',
 
            field=models.BooleanField(default=True),
 
        ),
 
        migrations.AlterField(
 
            model_name='sustainerorder',
 
            name='add_to_mailing_list',
 
            field=models.BooleanField(default=True),
 
        ),
 
    ]
conservancy/supporters/models.py
Show inline comments
...
 
@@ -6,32 +6,37 @@ class Supporter(models.Model):
 
    """Conservancy Supporter listing"""
 

	
 
    display_name = models.CharField(max_length=200, blank=False)
 
    display_until_date = models.DateTimeField("date until which this supporter name is displayed")
 
    ledger_entity_id = models.CharField(max_length=200, blank=False)
 

	
 
    def test(self):
 
        return "TESTING"
 
    def __str__(self):
 
        return self.display_name
 

	
 
    class Meta:
 
        ordering = ('ledger_entity_id',)
 

	
 

	
 
class SustainerOrder(models.Model):
 
    RENEW_CHOICES = [
 
        ('', 'None'),
 
        ('month', 'Monthly'),
 
        ('year', 'Annual'),
 
    ]
 
    TSHIRT_CHOICES = [
 
        (
 
            '',
 
            (("None", "None"),),
 
        ),
 
        (
 
            "Men's",
 
            (
 
                ("Men's S", "Men's S"),
 
                ("Men's M", "Men's M"),
 
                ("Men's L", "Men's L"),
 
                ("Men's XL", "Men's XL"),
 
                ("Men's 2XL", "Men's 2XL"),
 
            ),
 
        ),
 
        (
...
 
@@ -50,32 +55,32 @@ class SustainerOrder(models.Model):
 
                ("Fitted women's S", "Fitted women's S"),
 
                ("Fitted women's M", "Fitted women's M"),
 
                ("Fitted women's L", "Fitted women's L"),
 
                ("Fitted women's XL", "Fitted women's XL"),
 
                ("Fitted women's 2XL", "Fitted women's 2XL"),
 
            ),
 
        ),
 
    ]
 

	
 
    created_time = models.DateTimeField(auto_now_add=True)
 
    name = models.CharField(max_length=255)
 
    email = models.EmailField()
 
    amount = models.IntegerField(
 
        validators=[
 
            validators.MinValueValidator(100),
 
        ])
 
    monthly_recurring = models.BooleanField(default=False)
 
    recurring = models.CharField(max_length=10)
 
    paid_time = models.DateTimeField(null=True, blank=True)
 
    acknowledge_publicly = models.BooleanField(default=False)
 
    add_to_mailing_list = models.BooleanField(default=False)
 
    acknowledge_publicly = models.BooleanField(default=True)
 
    add_to_mailing_list = models.BooleanField(default=True)
 
    tshirt_size = models.CharField(max_length=50, choices=TSHIRT_CHOICES)
 
    street = models.CharField(max_length=255, blank=True)
 
    city = models.CharField(max_length=255, blank=True)
 
    state = models.CharField(max_length=255, blank=True)
 
    zip_code = models.CharField(max_length=255, blank=True)
 
    country = models.CharField(max_length=255, blank=True)
 

	
 
    def __str__(self):
 
        return f'Sustainer order {self.id}: {self.email}'
 

	
 
    def paid(self):
 
        return self.paid_time is not None
conservancy/supporters/templates/supporters/sustainers_stripe2.html
Show inline comments
...
 
@@ -22,43 +22,47 @@
 
          x-data="{
 
                    tshirt_size: 'None',
 
                    tshirt_required: function () { return this.tshirt_size !== 'None' },
 
                    recurring: 'once',
 
                  }">
 
      {% csrf_token %}
 
      {{ form.errors }}
 
      <div class="mb2"><label>Name
 
        <span class="db mt1">{{ form.name }}</span>
 
      </label></div>
 
      <div class="mb2"><label>Email
 
        <span class="db mt1">{{ form.email }}</span>
 
      </label>
 
      <p class="f7 black-60 mt1">To send your receipt</p>
 
      </div>
 
      <div class="mb2"><label>
 
        <label class="mr1"><input type="radio" name="recurring" value="once" x-model="recurring"> Once</label>
 
        <label><input type="radio" name="recurring" value="monthly" x-model="recurring"> Monthly</label>
 
        <label class="mr1"><input type="radio" name="recurring" value="" x-model="recurring"> Once</label>
 
        <label class="mr1"><input type="radio" name="recurring" value="month" x-model="recurring"> Monthly</label>
 
        <label><input type="radio" name="recurring" value="year" x-model="recurring"> Annual</label>
 
      </label></div>
 
      <div class="mb2" x-show="recurring === 'once'"><label>Amount
 
      <div class="mb2" x-show="recurring === ''"><label>Amount
 
        <span class="db mt1">$ {{ form.amount }}</span>
 
      </label></div>
 
      <div class="mb2" x-show="recurring === 'monthly'"><label>Amount
 
      <div class="mb2" x-show="recurring === 'month'"><label>Amount
 
          <span class="db mt1">$ {{ form.amount_monthly }}</span>
 
      </label></div>
 
      <div class="mv3"><label class="lh-title"><input type="checkbox"> Acknowledge me on the public <a href="">list of sustainers</a></label></div>
 
      <div class="mv3"><label class="lh-title"><input type="checkbox"> Add me to the low-traffic <a href="https://lists.sfconservancy.org/pipermail/announce/">announcements</a> email list</label></div>
 
      <div class="mb2" x-show="recurring === 'year'"><label>Amount
 
          <span class="db mt1">$ {{ form.amount }}</span>
 
      </label></div>
 
      <div class="mv3"><label class="lh-title">{{ form.acknowledge_publicly }} Acknowledge me on the public <a href="">list of sustainers</a></label></div>
 
      <div class="mv3"><label class="lh-title">{{ form.add_to_mailing_list }} Add me to the low-traffic <a href="https://lists.sfconservancy.org/pipermail/announce/">announcements</a> email list</label></div>
 
      <div class="mv3">
 
        <label>T-shirt:
 
          <!-- Form field has an x-model attribute in forms.py. -->
 
          <span class="db mt1">{{ form.tshirt_size }}</span>
 
        </label>
 
        <p class="f7 black-60 mt1">Sizing:
 
          <a href="https://sfconservancy.org/videos/women-2017-to-2020-t-shirt-sizing.jpg" target="_blank" class="black-60">Women's</a>,
 
          <a href="https://sfconservancy.org/videos/men-2017-to-2020-t-shirt-sizing.jpg" target="_blank" class="black-60">Men's</a></p>
 
      </div>
 
      <!-- Using Alpine.js to show/hide the address based on T-shirt choice. -->
 
      <template x-if="tshirt_required">
 
        <fieldset id="address">
 
          <legend>Postal address</legend>
 
        <div class="mb2"><label>Street
 
          <span class="db mt1">{{ form.street }}</span>
 
        </label></div>
conservancy/supporters/views.py
Show inline comments
...
 
@@ -32,75 +32,75 @@ def sponsors(request):
 
    """Conservancy Sponsors Page view
 

	
 
    Performs object queries necessary to render the sponsors page.
 
    """
 
    supporters = Supporter.objects.all().filter(display_until_date__gte=datetime.now())
 
    supporters_count = len(supporters)
 
    anonymous_count  = len(supporters.filter(display_name='Anonymous'))
 
    supporters = supporters.exclude(display_name='Anonymous').order_by('ledger_entity_id')
 
    c = {
 
        'supporters' : supporters,
 
        'supporters_count' : supporters_count,
 
        'anonymous_count' : anonymous_count
 
    }
 
    return render(request, "supporters/sponsors.html", c)
 

	
 

	
 
def create_checkout_session(reference_id, email: str, amount: int, recurring: bool, base_url: str):
 
def create_checkout_session(reference_id, email: str, amount: int, recurring: str, base_url: str):
 
    # https://docs.stripe.com/payments/accept-a-payment
 
    YOUR_DOMAIN = base_url
 
    try:
 
        checkout_session = stripe.checkout.Session.create(
 
            client_reference_id=str(reference_id),
 
            line_items=[
 
                {
 
                    'price_data': {
 
                        'currency': 'usd',
 
                        'product_data': {'name': 'Contribution'},
 
                        'unit_amount': amount * 100,  # in cents
 
                        # https://docs.stripe.com/products-prices/pricing-models#variable-pricing
 
                        'recurring': {'interval': 'month'} if recurring else None,
 
                        'recurring': {'interval': recurring} if recurring else None,
 
                    },
 
                    'quantity': 1,
 
                },
 
            ],
 
            customer_email=email,
 
            mode='subscription' if recurring else 'payment',
 
            success_url=YOUR_DOMAIN + '/sustainer/success/?session_id={CHECKOUT_SESSION_ID}',
 
            cancel_url=YOUR_DOMAIN + '/sustainer/stripe/',
 
        )
 
    except Exception as e:
 
        return str(e)
 
    return checkout_session.url
 

	
 

	
 
def sustainers_stripe(request):
 
    return render(request, 'supporters/sustainers_stripe.html', {})
 

	
 

	
 
def sustainers_stripe2(request):
 
    if request.method == 'POST':
 
        form = forms.SustainerForm(request.POST)
 
        if form.is_valid():
 
            order = form.save(commit=False)
 
            if form.data['recurring'] == 'monthly':
 
            order.recurring = form.data['recurring']
 
            if order.recurring == 'month':
 
                order.amount = form.cleaned_data['amount_monthly']
 
                order.monthly_recurring = True
 
            order.save()
 
            base_url = f'{request.scheme}://{request.get_host()}'
 
            stripe_checkout_url = create_checkout_session(order.id, order.email, order.amount, order.monthly_recurring, base_url)
 
            stripe_checkout_url = create_checkout_session(order.id, order.email, order.amount, order.recurring, base_url)
 
            return redirect(stripe_checkout_url)
 
    else:
 
        form = forms.SustainerForm()
 
    return render(request, 'supporters/sustainers_stripe2.html', {'form': form})
 

	
 

	
 
stripe.api_key = 'sk_test_zaAqrpHmpkXnHQfAs4UWkE3d'
 

	
 
def fulfill_checkout(session_id):
 
    print("Fulfilling Checkout Session", session_id)
 

	
 
    # TODO: Make this function safe to run multiple times,
 
    # even concurrently, with the same session ID
 

	
 
    # TODO: Make sure fulfillment hasn't already been
 
    # peformed for this Checkout Session
0 comments (0 inline, 0 general)