Files
drl_2/xuexiao/routes/transfer.py

204 lines
9.4 KiB
Python
Raw Normal View History

2026-05-29 10:28:07 +08:00
"""转课/转赠路由"""
from flask import render_template, request, redirect, url_for, flash, session
from models import db, Student, Course, StudentAccount, TransferRecord
from utils import login_required, log_operation, permission_required, export_excel
import business_rules as rules
def register_routes(app):
@app.route('/transfers', endpoint='transfer_list')
@login_required
@permission_required('transfer_view')
def transfer_list():
records = TransferRecord.query.order_by(TransferRecord.created_at.desc()).all()
return render_template('transfer_list.html', records=records)
@app.route('/transfers/add', methods=['GET', 'POST'], endpoint='transfer_add')
@login_required
@permission_required('transfer_add')
def transfer_add():
if request.method == 'POST':
from_student_id = int(request.form.get('from_student_id'))
from_course_id = int(request.form.get('from_course_id'))
transfer_type = request.form.get('transfer_type', 'transfer')
transfer_hours = rules.normalize_consumption_hours(
request.form.get('transfer_hours', 1)
)
remark = request.form.get('remark', '')
from_account = rules.lock_student_account(from_student_id, from_course_id)
if not from_account:
flash('未找到转出课时账户', 'danger')
return redirect(url_for('transfer_add'))
normal_avail = int(float(from_account.normal_hours or 0))
if transfer_type == 'gift':
to_student_id = int(request.form.get('to_student_id'))
if transfer_hours > normal_avail:
flash(
f'赠课不可转赠。仅可转赠正课,当前正课余额{normal_avail}课时',
'danger',
)
return redirect(url_for('transfer_add'))
from_account.normal_hours = normal_avail - transfer_hours
rules.update_account_unit_price(from_account)
rules.sync_account_snapshots(from_account)
to_account = StudentAccount.query.filter_by(
student_id=to_student_id, course_id=from_course_id,
).first()
if not to_account:
to_account = StudentAccount(
student_id=to_student_id, course_id=from_course_id,
)
db.session.add(to_account)
db.session.flush()
to_account.normal_hours = int(float(to_account.normal_hours or 0)) + transfer_hours
rules.update_account_unit_price(to_account)
rules.sync_account_snapshots(to_account)
record = TransferRecord(
from_student_id=from_student_id,
to_student_id=to_student_id,
from_course_id=from_course_id,
to_course_id=from_course_id,
transfer_type='gift',
transfer_hours=transfer_hours,
operator_id=session.get('user_id'),
remark=remark,
)
db.session.add(record)
db.session.commit()
log_operation(
'转赠',
f'学员{from_student_id} 转赠正课{transfer_hours}课时给学员{to_student_id}',
)
flash('转赠成功(仅正课)', 'success')
elif transfer_type == 'upgrade':
# §五 升阶:100% 正课全额结转,不新建订单
to_course_id = int(request.form.get('to_course_id'))
from_course = db.session.get(Course, from_course_id)
to_course = db.session.get(Course, to_course_id)
from_unit = rules.account_effective_unit_price(from_account, from_course)
to_unit = rules.account_effective_unit_price(
StudentAccount.query.filter_by(
student_id=from_student_id, course_id=to_course_id,
).first() or from_account, to_course,
) or float(to_course.price_per_hour or 0) if to_course else 0
if to_unit <= 0 and to_course:
to_unit = float(to_course.price_per_hour or 0)
transfer_normal = normal_avail
to_hours = rules.calc_transfer_to_hours(
transfer_normal, from_unit, to_unit,
)
transfer_amount = transfer_normal * from_unit
from_account.normal_hours = 0
rules.update_account_unit_price(from_account)
rules.sync_account_snapshots(from_account)
to_account = StudentAccount.query.filter_by(
student_id=from_student_id, course_id=to_course_id,
).first()
if not to_account:
to_account = StudentAccount(
student_id=from_student_id, course_id=to_course_id,
)
db.session.add(to_account)
db.session.flush()
to_account.normal_hours = int(float(to_account.normal_hours or 0)) + to_hours
rules.update_account_unit_price(to_account)
rules.sync_account_snapshots(to_account)
record = TransferRecord(
from_student_id=from_student_id,
from_course_id=from_course_id,
to_course_id=to_course_id,
transfer_type='upgrade',
transfer_hours=transfer_normal,
transfer_amount=transfer_amount,
operator_id=session.get('user_id'),
remark=remark or '升阶结转',
)
db.session.add(record)
db.session.commit()
log_operation(
'升阶',
f'学员{from_student_id} 正课{transfer_normal}课时→课程{to_course_id} 转入{to_hours}课时',
)
flash(f'升阶成功!100%正课结转,转入{to_hours}课时', 'success')
else:
to_course_id = int(request.form.get('to_course_id'))
from_course = db.session.get(Course, from_course_id)
to_course = db.session.get(Course, to_course_id)
from_unit = rules.account_effective_unit_price(from_account, from_course)
to_account_pre = StudentAccount.query.filter_by(
student_id=from_student_id, course_id=to_course_id,
).first()
to_unit = rules.account_effective_unit_price(to_account_pre, to_course)
if to_unit <= 0 and to_course:
to_unit = float(to_course.price_per_hour or 0)
if transfer_hours > normal_avail:
flash(
f'仅可转出正课。当前正课{normal_avail}课时,赠课{int(float(from_account.gifted_hours or 0))}课时不可转课',
'danger',
)
return redirect(url_for('transfer_add'))
transfer_amount = transfer_hours * from_unit
to_hours = rules.calc_transfer_to_hours(
transfer_hours, from_unit, to_unit,
)
from_account.normal_hours = normal_avail - transfer_hours
rules.update_account_unit_price(from_account)
rules.sync_account_snapshots(from_account)
to_account = StudentAccount.query.filter_by(
student_id=from_student_id, course_id=to_course_id,
).first()
if not to_account:
to_account = StudentAccount(
student_id=from_student_id, course_id=to_course_id,
)
db.session.add(to_account)
db.session.flush()
to_account.normal_hours = int(float(to_account.normal_hours or 0)) + to_hours
rules.update_account_unit_price(to_account)
rules.sync_account_snapshots(to_account)
record = TransferRecord(
from_student_id=from_student_id,
from_course_id=from_course_id,
to_course_id=to_course_id,
transfer_type='transfer',
transfer_hours=transfer_hours,
transfer_amount=transfer_amount,
operator_id=session.get('user_id'),
remark=remark,
)
db.session.add(record)
db.session.commit()
log_operation(
'转课',
f'学员{from_student_id} 转出正课{transfer_hours}课时→转入{to_hours}课时',
)
flash(f'转课成功!转入{to_hours}课时(仅正课参与换算)', 'success')
return redirect(url_for('transfer_list'))
students = Student.query.filter_by(status=1).all()
courses = Course.query.filter_by(status=1).all()
return render_template('transfer_form.html', students=students, courses=courses)
@app.route('/transfers/export', endpoint='transfer_export')
@login_required
@permission_required('transfer_export')
def transfer_export():
from utils import export_transfers as do_export
return do_export()