import logging from odoo import http from odoo.http import request from odoo.addons.encoach_api.controllers.base import ( jwt_required, _json_response, _error_response, _get_json_body, _paginate, ) _logger = logging.getLogger(__name__) class GradesController(http.Controller): # ── Grades (simple list) ───────────────────────────────────────── @http.route('/api/grades', type='http', auth='public', methods=['GET'], csrf=False) @jwt_required def list_grades(self, **kw): try: M = request.env['encoach.gradebook.line'].sudo() offset, limit, page = _paginate(kw) total = M.search_count([]) recs = M.search([], offset=offset, limit=limit, order='id desc') data = [] for r in recs: gb = r.gradebook_id data.append({ 'id': r.id, 'course_id': gb.course_id.id if gb.course_id else 0, 'course_name': gb.course_id.name if gb.course_id else '', 'student_id': gb.student_id.id if gb.student_id else 0, 'student_name': gb.student_id.partner_id.name if gb.student_id and gb.student_id.partner_id else '', 'assignment_title': r.assignment_name or '', 'grade': r.marks, 'max_grade': 100, 'date': str(r.create_date.date()) if r.create_date else '', 'type': r.state or 'graded', }) return _json_response({'data': data}) except Exception as e: _logger.exception('list_grades') return _error_response(str(e), 500) # ── Gradebooks ─────────────────────────────────────────────────── @http.route('/api/gradebooks', type='http', auth='public', methods=['GET'], csrf=False) @jwt_required def list_gradebooks(self, **kw): try: M = request.env['encoach.gradebook'].sudo() offset, limit, page = _paginate(kw) total = M.search_count([]) recs = M.search([], offset=offset, limit=limit, order='id desc') items = [{ 'id': r.id, 'student_id': r.student_id.id if r.student_id else 0, 'student_name': r.student_id.partner_id.name if r.student_id and r.student_id.partner_id else '', 'course_id': r.course_id.id if r.course_id else 0, 'course_name': r.course_id.name if r.course_id else '', 'academic_year_id': r.academic_year_id.id if r.academic_year_id else 0, 'academic_year_name': r.academic_year_id.name if r.academic_year_id else '', } for r in recs] return _json_response({'items': items, 'data': items, 'total': total, 'page': page, 'size': limit}) except Exception as e: return _error_response(str(e), 500) # ── Gradebook Lines ────────────────────────────────────────────── @http.route('/api/gradebook-lines', type='http', auth='public', methods=['GET'], csrf=False) @jwt_required def list_gradebook_lines(self, **kw): try: M = request.env['encoach.gradebook.line'].sudo() offset, limit, page = _paginate(kw) domain = [] gb_id = kw.get('gradebook_id') if gb_id: try: domain.append(('gradebook_id', '=', int(gb_id))) except Exception: pass total = M.search_count(domain) recs = M.search(domain, offset=offset, limit=limit, order='id desc') items = [{ 'id': r.id, 'gradebook_id': r.gradebook_id.id, 'student_name': r.gradebook_id.student_id.partner_id.name if r.gradebook_id.student_id and r.gradebook_id.student_id.partner_id else '', 'assignment_name': r.assignment_name or '', 'marks': r.marks, 'percentage': r.percentage, 'state': r.state or 'draft', } for r in recs] return _json_response({'items': items, 'data': items, 'total': total, 'page': page, 'size': limit}) except Exception as e: return _error_response(str(e), 500) # ── Grading Assignments (using openeducat grading.assignment) ──── @http.route('/api/grading-assignments', type='http', auth='public', methods=['GET'], csrf=False) @jwt_required def list_grading_assignments(self, **kw): try: M = request.env['grading.assignment'].sudo() offset, limit, page = _paginate(kw) total = M.search_count([]) recs = M.search([], offset=offset, limit=limit, order='id desc') items = [{ 'id': r.id, 'sequence': getattr(r, 'sequence', '') or '', 'name': r.name or '', 'course_id': r.course_id.id if hasattr(r, 'course_id') and r.course_id else 0, 'course_name': r.course_id.name if hasattr(r, 'course_id') and r.course_id else '', 'subject_id': r.subject_id.id if hasattr(r, 'subject_id') and r.subject_id else 0, 'subject_name': r.subject_id.name if hasattr(r, 'subject_id') and r.subject_id else '', 'state': getattr(r, 'state', 'draft') or 'draft', 'issued_date': str(r.issued_date) if hasattr(r, 'issued_date') and r.issued_date else '', } for r in recs] return _json_response({'items': items, 'data': items, 'total': total, 'page': page, 'size': limit}) except Exception as e: return _error_response(str(e), 500) @http.route('/api/grading-assignments', type='http', auth='public', methods=['POST'], csrf=False) @jwt_required def create_grading_assignment(self, **kw): try: from odoo import fields as odoo_fields body = _get_json_body() # assignment_type is required on grading.assignment. Find or create a default. AType = request.env['grading.assignment.type'].sudo() atype_id = body.get('assignment_type') or body.get('assignment_type_id') if atype_id: atype_id = int(atype_id) else: atype = AType.search([('code', '=', 'DEFAULT')], limit=1) if not atype: atype = AType.create({'name': 'Default', 'code': 'DEFAULT'}) atype_id = atype.id # faculty_id is required. Prefer body, otherwise first available. Faculty = request.env['op.faculty'].sudo() faculty_id = body.get('faculty_id') if faculty_id: faculty_id = int(faculty_id) else: fac = Faculty.search([], limit=1) if fac: faculty_id = fac.id if not faculty_id: return _error_response('A faculty is required but none exist in the system.', 400) vals = { 'name': body.get('name') or 'Assignment', 'issued_date': body.get('issued_date') or odoo_fields.Datetime.now(), 'assignment_type': atype_id, 'faculty_id': faculty_id, } if body.get('course_id'): vals['course_id'] = int(body['course_id']) if body.get('subject_id'): vals['subject_id'] = int(body['subject_id']) if body.get('point') is not None: vals['point'] = float(body['point']) rec = request.env['grading.assignment'].sudo().create(vals) return _json_response({'data': {'id': rec.id, 'name': rec.name}}) except Exception as e: _logger.exception('create_grading_assignment') return _error_response(str(e), 500) @http.route('/api/grading-assignments/', type='http', auth='public', methods=['PATCH', 'PUT'], csrf=False) @jwt_required def update_grading_assignment(self, gid, **kw): try: rec = request.env['grading.assignment'].sudo().browse(gid) if not rec.exists(): return _error_response('Not found', 404) body = _get_json_body() vals = {} for k in ('name', 'issued_date'): if k in body: vals[k] = body[k] if 'course_id' in body: vals['course_id'] = int(body['course_id']) if 'subject_id' in body: vals['subject_id'] = int(body['subject_id']) if vals: rec.write(vals) return _json_response({'data': {'id': rec.id, 'name': rec.name}}) except Exception as e: return _error_response(str(e), 500) @http.route('/api/grading-assignments/', type='http', auth='public', methods=['DELETE'], csrf=False) @jwt_required def delete_grading_assignment(self, gid, **kw): try: rec = request.env['grading.assignment'].sudo().browse(gid) if rec.exists(): rec.unlink() return _json_response({'success': True}) except Exception as e: return _error_response(str(e), 500)