Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
- Add Benefit and BenefitClick models for tracking affiliate offers - Create /korzysci blueprint with admin-only access (test mode) - Add admin panel at /admin/benefits for managing offers - Include WisprFlow as first benefit with branded link ref.wisprflow.ai/norda - Add QR code support for printed materials - Track clicks with user attribution and analytics Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
218 lines
7.6 KiB
Python
218 lines
7.6 KiB
Python
"""
|
|
Admin Benefits Routes
|
|
=====================
|
|
|
|
Zarządzanie korzyściami członkowskimi (oferty afiliacyjne).
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from flask import render_template, redirect, url_for, flash, request
|
|
from flask_login import login_required
|
|
|
|
from . import bp
|
|
from database import SessionLocal, Benefit, BenefitClick, SystemRole
|
|
from utils.decorators import role_required
|
|
|
|
|
|
@bp.route('/benefits')
|
|
@login_required
|
|
@role_required(SystemRole.ADMIN)
|
|
def admin_benefits():
|
|
"""Lista korzyści w panelu admina."""
|
|
db = SessionLocal()
|
|
try:
|
|
benefits = db.query(Benefit).order_by(
|
|
Benefit.is_active.desc(),
|
|
Benefit.display_order,
|
|
Benefit.name
|
|
).all()
|
|
|
|
# Statystyki
|
|
total_clicks = sum(b.click_count or 0 for b in benefits)
|
|
active_count = sum(1 for b in benefits if b.is_active)
|
|
|
|
return render_template(
|
|
'admin/benefits_list.html',
|
|
benefits=benefits,
|
|
total_clicks=total_clicks,
|
|
active_count=active_count
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@bp.route('/benefits/new', methods=['GET', 'POST'])
|
|
@login_required
|
|
@role_required(SystemRole.ADMIN)
|
|
def admin_benefits_new():
|
|
"""Dodaj nową korzyść."""
|
|
if request.method == 'POST':
|
|
db = SessionLocal()
|
|
try:
|
|
benefit = Benefit(
|
|
name=request.form.get('name'),
|
|
slug=request.form.get('slug'),
|
|
short_description=request.form.get('short_description'),
|
|
description=request.form.get('description'),
|
|
category=request.form.get('category'),
|
|
regular_price=request.form.get('regular_price'),
|
|
member_price=request.form.get('member_price'),
|
|
discount_description=request.form.get('discount_description'),
|
|
affiliate_url=request.form.get('affiliate_url'),
|
|
product_url=request.form.get('product_url'),
|
|
logo_url=request.form.get('logo_url'),
|
|
promo_code=request.form.get('promo_code'),
|
|
promo_code_instructions=request.form.get('promo_code_instructions'),
|
|
commission_rate=request.form.get('commission_rate'),
|
|
commission_duration=request.form.get('commission_duration'),
|
|
partner_platform=request.form.get('partner_platform'),
|
|
is_featured=request.form.get('is_featured') == 'on',
|
|
is_active=request.form.get('is_active') == 'on',
|
|
display_order=int(request.form.get('display_order', 0))
|
|
)
|
|
|
|
# Partner since date
|
|
partner_since_str = request.form.get('partner_since')
|
|
if partner_since_str:
|
|
try:
|
|
benefit.partner_since = datetime.strptime(partner_since_str, '%Y-%m-%d').date()
|
|
except ValueError:
|
|
pass
|
|
|
|
db.add(benefit)
|
|
db.commit()
|
|
|
|
flash(f'Dodano korzyść: {benefit.name}', 'success')
|
|
return redirect(url_for('admin.admin_benefits'))
|
|
|
|
except Exception as e:
|
|
db.rollback()
|
|
flash(f'Błąd: {str(e)}', 'error')
|
|
finally:
|
|
db.close()
|
|
|
|
return render_template(
|
|
'admin/benefits_form.html',
|
|
benefit=None,
|
|
categories=Benefit.CATEGORY_CHOICES
|
|
)
|
|
|
|
|
|
@bp.route('/benefits/<int:benefit_id>/edit', methods=['GET', 'POST'])
|
|
@login_required
|
|
@role_required(SystemRole.ADMIN)
|
|
def admin_benefits_edit(benefit_id):
|
|
"""Edytuj korzyść."""
|
|
db = SessionLocal()
|
|
try:
|
|
benefit = db.query(Benefit).filter(Benefit.id == benefit_id).first()
|
|
if not benefit:
|
|
flash('Korzyść nie istnieje.', 'error')
|
|
return redirect(url_for('admin.admin_benefits'))
|
|
|
|
if request.method == 'POST':
|
|
benefit.name = request.form.get('name')
|
|
benefit.slug = request.form.get('slug')
|
|
benefit.short_description = request.form.get('short_description')
|
|
benefit.description = request.form.get('description')
|
|
benefit.category = request.form.get('category')
|
|
benefit.regular_price = request.form.get('regular_price')
|
|
benefit.member_price = request.form.get('member_price')
|
|
benefit.discount_description = request.form.get('discount_description')
|
|
benefit.affiliate_url = request.form.get('affiliate_url')
|
|
benefit.product_url = request.form.get('product_url')
|
|
benefit.logo_url = request.form.get('logo_url')
|
|
benefit.promo_code = request.form.get('promo_code')
|
|
benefit.promo_code_instructions = request.form.get('promo_code_instructions')
|
|
benefit.commission_rate = request.form.get('commission_rate')
|
|
benefit.commission_duration = request.form.get('commission_duration')
|
|
benefit.partner_platform = request.form.get('partner_platform')
|
|
benefit.is_featured = request.form.get('is_featured') == 'on'
|
|
benefit.is_active = request.form.get('is_active') == 'on'
|
|
benefit.display_order = int(request.form.get('display_order', 0))
|
|
|
|
# Partner since date
|
|
partner_since_str = request.form.get('partner_since')
|
|
if partner_since_str:
|
|
try:
|
|
benefit.partner_since = datetime.strptime(partner_since_str, '%Y-%m-%d').date()
|
|
except ValueError:
|
|
pass
|
|
|
|
db.commit()
|
|
flash(f'Zapisano zmiany: {benefit.name}', 'success')
|
|
return redirect(url_for('admin.admin_benefits'))
|
|
|
|
return render_template(
|
|
'admin/benefits_form.html',
|
|
benefit=benefit,
|
|
categories=Benefit.CATEGORY_CHOICES
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@bp.route('/benefits/<int:benefit_id>/toggle', methods=['POST'])
|
|
@login_required
|
|
@role_required(SystemRole.ADMIN)
|
|
def admin_benefits_toggle(benefit_id):
|
|
"""Włącz/wyłącz korzyść."""
|
|
db = SessionLocal()
|
|
try:
|
|
benefit = db.query(Benefit).filter(Benefit.id == benefit_id).first()
|
|
if benefit:
|
|
benefit.is_active = not benefit.is_active
|
|
db.commit()
|
|
status = 'włączona' if benefit.is_active else 'wyłączona'
|
|
flash(f'Korzyść {benefit.name} została {status}.', 'success')
|
|
finally:
|
|
db.close()
|
|
|
|
return redirect(url_for('admin.admin_benefits'))
|
|
|
|
|
|
@bp.route('/benefits/<int:benefit_id>/delete', methods=['POST'])
|
|
@login_required
|
|
@role_required(SystemRole.ADMIN)
|
|
def admin_benefits_delete(benefit_id):
|
|
"""Usuń korzyść."""
|
|
db = SessionLocal()
|
|
try:
|
|
benefit = db.query(Benefit).filter(Benefit.id == benefit_id).first()
|
|
if benefit:
|
|
name = benefit.name
|
|
db.delete(benefit)
|
|
db.commit()
|
|
flash(f'Usunięto korzyść: {name}', 'success')
|
|
finally:
|
|
db.close()
|
|
|
|
return redirect(url_for('admin.admin_benefits'))
|
|
|
|
|
|
@bp.route('/benefits/<int:benefit_id>/clicks')
|
|
@login_required
|
|
@role_required(SystemRole.ADMIN)
|
|
def admin_benefits_clicks(benefit_id):
|
|
"""Historia kliknięć dla korzyści."""
|
|
db = SessionLocal()
|
|
try:
|
|
benefit = db.query(Benefit).filter(Benefit.id == benefit_id).first()
|
|
if not benefit:
|
|
flash('Korzyść nie istnieje.', 'error')
|
|
return redirect(url_for('admin.admin_benefits'))
|
|
|
|
clicks = db.query(BenefitClick).filter(
|
|
BenefitClick.benefit_id == benefit_id
|
|
).order_by(
|
|
BenefitClick.clicked_at.desc()
|
|
).limit(100).all()
|
|
|
|
return render_template(
|
|
'admin/benefits_clicks.html',
|
|
benefit=benefit,
|
|
clicks=clicks
|
|
)
|
|
finally:
|
|
db.close()
|