116 lines
5.2 KiB
Python
116 lines
5.2 KiB
Python
"""退费管理路由"""
|
|
from flask import render_template, request, redirect, url_for, flash, session, jsonify
|
|
from utils import permission_required, export_excel, login_required, log_operation
|
|
from models import db, Student, Course, StudentAccount, RefundRecord
|
|
import business_rules as rules
|
|
|
|
|
|
def register_routes(app):
|
|
|
|
@app.route('/refunds', endpoint='refund_list')
|
|
@login_required
|
|
@permission_required('refund_view')
|
|
def refund_list():
|
|
records = RefundRecord.query.order_by(RefundRecord.created_at.desc()).all()
|
|
return render_template('refund_list.html', records=records)
|
|
|
|
@app.route('/refunds/add', methods=['GET', 'POST'], endpoint='refund_add')
|
|
@login_required
|
|
@permission_required('refund_add')
|
|
def refund_add():
|
|
if request.method == 'POST':
|
|
student_id = int(request.form.get('student_id'))
|
|
course_id = int(request.form.get('course_id'))
|
|
reason = request.form.get('reason', '')
|
|
partial_raw = request.form.get('partial_amount', '').strip()
|
|
partial_amount = float(partial_raw) if partial_raw else None
|
|
|
|
account = rules.lock_student_account(student_id, course_id)
|
|
if not account:
|
|
flash('未找到该学员的课时账户', 'danger')
|
|
return redirect(url_for('refund_add'))
|
|
|
|
before = rules.account_snapshot_dict(account)
|
|
calc = rules.calculate_refund(student_id, course_id, partial_amount)
|
|
|
|
record = RefundRecord(
|
|
student_id=student_id,
|
|
course_id=course_id,
|
|
refund_amount=calc['refund_amount'],
|
|
remaining_normal_hours=calc['remaining_normal'],
|
|
remaining_gifted_hours=calc['remaining_gifted'],
|
|
deduct_gifted_hours=calc['deduct_gifted_amount'],
|
|
deduct_gifted_amount=calc['deduct_gifted_amount'],
|
|
promo_clawback_hours=calc['promo_clawback_hours'],
|
|
consumed_hours_value=calc['consumed_hours_value'],
|
|
material_fee_per_quarter=rules.MATERIAL_FEE_PER_QUARTER,
|
|
quarters=calc['quarters'],
|
|
total_deduct=calc['total_deduct'],
|
|
reason=reason,
|
|
operator_id=session.get('user_id'),
|
|
)
|
|
try:
|
|
db.session.add(record)
|
|
rules.apply_refund(
|
|
account, calc,
|
|
student_id=student_id, course_id=course_id,
|
|
)
|
|
after = rules.account_snapshot_dict(account)
|
|
log_operation(
|
|
'退费',
|
|
f'学员ID:{student_id} 退费{calc["refund_amount"]}元',
|
|
before=before, after=after, commit=False,
|
|
)
|
|
db.session.commit()
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
flash(f'退费失败: {e}', 'danger')
|
|
return redirect(url_for('refund_add'))
|
|
extra = ''
|
|
if calc['promo_clawback_hours']:
|
|
extra = f',优惠回退扣赠课{calc["promo_clawback_hours"]}课时'
|
|
flash(f'退费成功!退费金额: {calc["refund_amount"]}元{extra}', 'success')
|
|
return redirect(url_for('refund_list'))
|
|
|
|
students = Student.query.filter_by(status=1).all()
|
|
courses = Course.query.filter_by(status=1).all()
|
|
return render_template('refund_form.html', students=students, courses=courses)
|
|
|
|
@app.route('/refunds/export', endpoint='refund_export')
|
|
@login_required
|
|
@permission_required('refund_export')
|
|
def refund_export():
|
|
records = RefundRecord.query.order_by(RefundRecord.created_at.desc()).all()
|
|
headers = ['序号', '学员姓名', '课程名称', '退费金额', '已消课时金额',
|
|
'材料费', '赠课扣回金额', '优惠回退课时', '退费原因', '创建时间']
|
|
rows = []
|
|
for i, r in enumerate(records, 1):
|
|
student = db.session.get(Student, r.student_id)
|
|
course = db.session.get(Course, r.course_id)
|
|
gift_amt = getattr(r, 'deduct_gifted_amount', None) or r.deduct_gifted_hours
|
|
rows.append([
|
|
i,
|
|
student.name if student else '',
|
|
course.name if course else '',
|
|
r.refund_amount or 0,
|
|
r.consumed_hours_value or 0,
|
|
(r.quarters or 0) * rules.MATERIAL_FEE_PER_QUARTER,
|
|
gift_amt or 0,
|
|
getattr(r, 'promo_clawback_hours', 0) or 0,
|
|
r.reason or '',
|
|
r.created_at.strftime('%Y-%m-%d %H:%M') if r.created_at else '',
|
|
])
|
|
return export_excel('退费记录', headers, rows)
|
|
|
|
@app.route('/api/calculate_refund', methods=['POST'])
|
|
@login_required
|
|
@permission_required('refund_view')
|
|
def api_calculate_refund():
|
|
data = request.get_json() or {}
|
|
student_id = data.get('student_id')
|
|
course_id = data.get('course_id')
|
|
partial = data.get('partial_amount')
|
|
partial_amount = float(partial) if partial not in (None, '') else None
|
|
result = rules.calculate_refund(student_id, course_id, partial_amount)
|
|
return jsonify({'success': True, 'data': result})
|