Initial commit
This commit is contained in:
115
xuexiao/routes/refund.py
Normal file
115
xuexiao/routes/refund.py
Normal file
@@ -0,0 +1,115 @@
|
||||
"""退费管理路由"""
|
||||
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})
|
||||
Reference in New Issue
Block a user