added payment links to prices

This commit is contained in:
2025-06-25 17:14:03 +02:00
parent 5b598f2966
commit 3a0659b63b
9 changed files with 154 additions and 13 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,43 @@
"""add stripe payment links to pricing plans
Revision ID: add_stripe_payment_links
Revises: 9206bf87bb8e
Create Date: 2024-12-19 13:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy import text
# revision identifiers, used by Alembic.
revision = 'add_stripe_payment_links'
down_revision = '9206bf87bb8e'
branch_labels = None
depends_on = None
def upgrade():
conn = op.get_bind()
# Check if columns already exist
result = conn.execute(text("""
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'pricing_plans'
AND column_name IN ('monthly_stripe_link', 'annual_stripe_link')
"""))
existing_columns = [row[0] for row in result.fetchall()]
# Add Stripe payment link columns if they don't exist
if 'monthly_stripe_link' not in existing_columns:
op.add_column('pricing_plans', sa.Column('monthly_stripe_link', sa.String(length=500), nullable=True))
if 'annual_stripe_link' not in existing_columns:
op.add_column('pricing_plans', sa.Column('annual_stripe_link', sa.String(length=500), nullable=True))
def downgrade():
# Remove Stripe payment link columns
op.drop_column('pricing_plans', 'annual_stripe_link')
op.drop_column('pricing_plans', 'monthly_stripe_link')

View File

@@ -603,6 +603,9 @@ class PricingPlan(db.Model):
is_custom = db.Column(db.Boolean, default=False) is_custom = db.Column(db.Boolean, default=False)
button_text = db.Column(db.String(50), default='Get Started') button_text = db.Column(db.String(50), default='Get Started')
button_url = db.Column(db.String(200), default='#') button_url = db.Column(db.String(200), default='#')
# Stripe payment links
monthly_stripe_link = db.Column(db.String(500), nullable=True)
annual_stripe_link = db.Column(db.String(500), nullable=True)
order_index = db.Column(db.Integer, default=0) order_index = db.Column(db.Integer, default=0)
is_active = db.Column(db.Boolean, default=True) is_active = db.Column(db.Boolean, default=True)
# Quota fields # Quota fields

View File

@@ -469,7 +469,8 @@ def create_pricing_plan():
annual_price = float(request.form.get('annual_price')) annual_price = float(request.form.get('annual_price'))
features = json.loads(request.form.get('features', '[]')) features = json.loads(request.form.get('features', '[]'))
button_text = request.form.get('button_text', 'Get Started') button_text = request.form.get('button_text', 'Get Started')
button_url = request.form.get('button_url', '#') monthly_stripe_link = request.form.get('monthly_stripe_link', '')
annual_stripe_link = request.form.get('annual_stripe_link', '')
is_popular = request.form.get('is_popular') == 'true' is_popular = request.form.get('is_popular') == 'true'
is_custom = request.form.get('is_custom') == 'true' is_custom = request.form.get('is_custom') == 'true'
is_active = request.form.get('is_active') == 'true' is_active = request.form.get('is_active') == 'true'
@@ -496,7 +497,8 @@ def create_pricing_plan():
annual_price=annual_price, annual_price=annual_price,
features=features, features=features,
button_text=button_text, button_text=button_text,
button_url=button_url, monthly_stripe_link=monthly_stripe_link,
annual_stripe_link=annual_stripe_link,
is_popular=is_popular, is_popular=is_popular,
is_custom=is_custom, is_custom=is_custom,
is_active=is_active, is_active=is_active,
@@ -582,7 +584,8 @@ def update_pricing_plan(plan_id):
annual_price = float(request.form.get('annual_price')) annual_price = float(request.form.get('annual_price'))
features = json.loads(request.form.get('features', '[]')) features = json.loads(request.form.get('features', '[]'))
button_text = request.form.get('button_text', 'Get Started') button_text = request.form.get('button_text', 'Get Started')
button_url = request.form.get('button_url', '#') monthly_stripe_link = request.form.get('monthly_stripe_link', '')
annual_stripe_link = request.form.get('annual_stripe_link', '')
is_popular = request.form.get('is_popular') == 'true' is_popular = request.form.get('is_popular') == 'true'
is_custom = request.form.get('is_custom') == 'true' is_custom = request.form.get('is_custom') == 'true'
is_active = request.form.get('is_active') == 'true' is_active = request.form.get('is_active') == 'true'
@@ -605,7 +608,8 @@ def update_pricing_plan(plan_id):
plan.annual_price = annual_price plan.annual_price = annual_price
plan.features = features plan.features = features
plan.button_text = button_text plan.button_text = button_text
plan.button_url = button_url plan.monthly_stripe_link = monthly_stripe_link
plan.annual_stripe_link = annual_stripe_link
plan.is_popular = is_popular plan.is_popular = is_popular
plan.is_custom = is_custom plan.is_custom = is_custom
plan.is_active = is_active plan.is_active = is_active

View File

@@ -164,7 +164,8 @@ function loadPlanForEdit(planId) {
document.getElementById('editMonthlyPrice').value = plan.monthly_price; document.getElementById('editMonthlyPrice').value = plan.monthly_price;
document.getElementById('editAnnualPrice').value = plan.annual_price; document.getElementById('editAnnualPrice').value = plan.annual_price;
document.getElementById('editButtonText').value = plan.button_text; document.getElementById('editButtonText').value = plan.button_text;
document.getElementById('editButtonUrl').value = plan.button_url; document.getElementById('editMonthlyStripeLink').value = plan.monthly_stripe_link || '';
document.getElementById('editAnnualStripeLink').value = plan.annual_stripe_link || '';
document.getElementById('editIsPopular').checked = plan.is_popular; document.getElementById('editIsPopular').checked = plan.is_popular;
document.getElementById('editIsCustom').checked = plan.is_custom; document.getElementById('editIsCustom').checked = plan.is_custom;
document.getElementById('editIsActive').checked = plan.is_active; document.getElementById('editIsActive').checked = plan.is_active;

View File

@@ -47,9 +47,27 @@
</ul> </ul>
</div> </div>
<a href="{{ plan.button_url }}" class="btn {% if plan.is_popular %}btn-primary{% else %}btn-outline-primary{% endif %} btn-lg w-100 mt-auto px-4 py-3"> <!-- Dynamic Payment Button -->
{% if plan.is_custom %}
<a href="{{ contact_url }}" class="btn {% if plan.is_popular %}btn-primary{% else %}btn-outline-primary{% endif %} btn-lg w-100 mt-auto px-4 py-3">
{{ plan.button_text }} {{ plan.button_text }}
</a> </a>
{% else %}
{% if plan.monthly_stripe_link or plan.annual_stripe_link %}
<a href="{{ plan.monthly_stripe_link or plan.annual_stripe_link }}"
class="btn {% if plan.is_popular %}btn-primary{% else %}btn-outline-primary{% endif %} btn-lg w-100 mt-auto px-4 py-3 payment-button"
data-plan-id="{{ plan.id }}"
data-monthly-link="{{ plan.monthly_stripe_link or '' }}"
data-annual-link="{{ plan.annual_stripe_link or '' }}"
target="_blank">
{{ plan.button_text }}
</a>
{% else %}
<a href="{{ contact_url }}" class="btn {% if plan.is_popular %}btn-primary{% else %}btn-outline-primary{% endif %} btn-lg w-100 mt-auto px-4 py-3">
{{ plan.button_text }}
</a>
{% endif %}
{% endif %}
</div> </div>
</div> </div>
</div> </div>
@@ -242,6 +260,14 @@ document.addEventListener('DOMContentLoaded', function() {
// Simply animate the number change // Simply animate the number change
animateNumber(price, monthlyValue, annualValue); animateNumber(price, monthlyValue, annualValue);
}); });
// Update payment links to annual
document.querySelectorAll('.payment-button').forEach(button => {
const annualLink = button.getAttribute('data-annual-link');
if (annualLink) {
button.href = annualLink;
}
});
} else { } else {
// Switch to monthly prices with animation // Switch to monthly prices with animation
monthlyPrices.forEach((price, index) => { monthlyPrices.forEach((price, index) => {
@@ -251,6 +277,14 @@ document.addEventListener('DOMContentLoaded', function() {
// Simply animate the number change back to monthly // Simply animate the number change back to monthly
animateNumber(price, currentValue, originalMonthlyValue); animateNumber(price, currentValue, originalMonthlyValue);
}); });
// Update payment links to monthly
document.querySelectorAll('.payment-button').forEach(button => {
const monthlyLink = button.getAttribute('data-monthly-link');
if (monthlyLink) {
button.href = monthlyLink;
}
});
} }
}); });
}); });

View File

@@ -53,6 +53,35 @@
</div> </div>
</div> </div>
<!-- Stripe Payment Links -->
{% if plan.monthly_stripe_link or plan.annual_stripe_link %}
<div class="mb-3">
<strong>Payment Links:</strong>
<div class="mt-2">
{% if plan.monthly_stripe_link %}
<div class="mb-1">
<small class="text-muted">
<i class="fas fa-credit-card me-1"></i>Monthly:
<a href="{{ plan.monthly_stripe_link }}" target="_blank" class="text-primary">
Stripe Payment Link
</a>
</small>
</div>
{% endif %}
{% if plan.annual_stripe_link %}
<div class="mb-1">
<small class="text-muted">
<i class="fas fa-credit-card me-1"></i>Annual:
<a href="{{ plan.annual_stripe_link }}" target="_blank" class="text-primary">
Stripe Payment Link
</a>
</small>
</div>
{% endif %}
</div>
</div>
{% endif %}
<div class="mb-3"> <div class="mb-3">
<strong>Features:</strong> <strong>Features:</strong>
<ul class="list-unstyled mt-2"> <ul class="list-unstyled mt-2">
@@ -220,11 +249,24 @@
value="Get Started"> value="Get Started">
</div> </div>
</div> </div>
</div>
<!-- Stripe Payment Links Section -->
<div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="mb-3"> <div class="mb-3">
<label for="buttonUrl" class="form-label">Button URL</label> <label for="monthlyStripeLink" class="form-label">Monthly Stripe Payment Link</label>
<input type="text" class="form-control" id="buttonUrl" name="button_url" <input type="url" class="form-control" id="monthlyStripeLink" name="monthly_stripe_link"
value="#"> placeholder="https://buy.stripe.com/...">
<small class="text-muted">Stripe payment link for monthly billing</small>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="annualStripeLink" class="form-label">Annual Stripe Payment Link</label>
<input type="url" class="form-control" id="annualStripeLink" name="annual_stripe_link"
placeholder="https://buy.stripe.com/...">
<small class="text-muted">Stripe payment link for annual billing</small>
</div> </div>
</div> </div>
</div> </div>
@@ -367,10 +409,24 @@
<input type="text" class="form-control" id="editButtonText" name="button_text"> <input type="text" class="form-control" id="editButtonText" name="button_text">
</div> </div>
</div> </div>
</div>
<!-- Stripe Payment Links Section -->
<div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="mb-3"> <div class="mb-3">
<label for="editButtonUrl" class="form-label">Button URL</label> <label for="editMonthlyStripeLink" class="form-label">Monthly Stripe Payment Link</label>
<input type="text" class="form-control" id="editButtonUrl" name="button_url"> <input type="url" class="form-control" id="editMonthlyStripeLink" name="monthly_stripe_link"
placeholder="https://buy.stripe.com/...">
<small class="text-muted">Stripe payment link for monthly billing</small>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="editAnnualStripeLink" class="form-label">Annual Stripe Payment Link</label>
<input type="url" class="form-control" id="editAnnualStripeLink" name="annual_stripe_link"
placeholder="https://buy.stripe.com/...">
<small class="text-muted">Stripe payment link for annual billing</small>
</div> </div>
</div> </div>
</div> </div>