Generate Students

mail@pastecode.io avatar
unknown
javascript
2 years ago
15 kB
1
Indexable
Never
import { Request, Response } from 'lambda-api';
import { ClientBase } from 'pg';
// import { Endpoint } from 'aws-sdk';
import { failure, success } from '../../../shared/libs/response';
import { getAuth, setAuth } from '../../../shared/libs/auth';
import code from '../../../shared/libs/code';
import { AuthModel } from '../../../shared/models/auth.model';
import lambda from '../../../shared/libs/lambda';
import config from '../../../shared/libs/config';
import { ApiModel } from '../../../shared/models/api.model';

async function queryGetPeriodsByAcademicYear(
  db: ClientBase,
  auth: AuthModel,
  academicYear: string
): Promise<any> {
  try {
    const queryResult = await db.query(
      `
      SELECT DISTINCT   period.period_id,
                        period.period_name
      FROM period
        JOIN academic_calendar
            ON academic_calendar.period_id = period.period_id
                AND academic_calendar.deleted_at IS NULL 
                AND academic_calendar.tenant_uuid = $1
      WHERE period.deleted_at IS NULL 
        AND period.tenant_uuid = $1
        AND academic_calendar.academic_year = $2
      ORDER BY period.period_id
    `,
      [auth.tenant_uuid, academicYear]
    );

    if (queryResult.rowCount === 0) {
      return null;
    }

    return queryResult.rows;
  } catch (e) {
    console.error('[ERROR-QUERY] - func: queryGetPeriodsByAcademicYear', e);
    throw Error(code.database_error);
  }
}

async function queryGetYearLevelsBySchoolLevel(
  db: ClientBase,
  auth: AuthModel,
  params: {
    school_level_id: number;
    school_location_id: number;
  }
): Promise<any> {
  try {
    const queryResult = await db.query(
      `
        SELECT DISTINCT school_level_relation.year_level_id,
                        year_level.year_level_name,
                        school_level_relation.order_number
        FROM year_level
            JOIN school_level_relation
                ON school_level_relation.year_level_id = year_level.year_level_id
                    AND school_level_relation.deleted_at IS NULL
                    AND school_level_relation.tenant_uuid = $1
        WHERE year_level.deleted_at IS NULL
            AND year_level.tenant_uuid = $1
            AND school_level_relation.school_level_id = $2
            AND school_level_relation.school_location_id = $3
        ORDER BY school_level_relation.order_number
    `,
      [auth.tenant_uuid, params.school_level_id, params.school_location_id]
    );

    if (queryResult.rowCount === 0) {
      return null;
    }

    return queryResult.rows;
  } catch (e) {
    console.error('[ERROR-QUERY] - func: queryGetYearLevelsBySchoolLevel', e);
    throw Error(code.database_error);
  }
}

async function queryGetClassMembers(db: ClientBase, auth: AuthModel, params: any): Promise<any> {
  try {
    let filterQueryIndex = 1;

    const filteredColumns = {
      academic_year: 'academic_calendar.academic_year',
      period_id: 'academic_calendar.period_id',
      school_level_id: 'school_level_relation.school_level_id',
      school_location_id: 'school_level_relation.school_location_id',
      year_level_id: 'school_level_relation.year_level_id',
    };

    const queryStrings = [];
    const queryValues = [];

    for (const key in filteredColumns) {
      if (Object.prototype.hasOwnProperty.call(filteredColumns, key)) {
        const value = filteredColumns[key];

        if (!params[key] || params[key] === 'null' || params[key] === 'undefined') {
          continue;
        }

        queryStrings.push(`AND ${value} = $${++filterQueryIndex}`);

        queryValues.push(params[key] || null);
      }
    }

    const queryResult = await db.query(
      `
        SELECT DISTINCT class_member.student_id,
                        class.class_name,
                        academic_calendar.academic_start_date,
                        academic_calendar.academic_end_date
        FROM  class_member
            JOIN class
                ON class.class_id = class_member.class_id
                    AND class.deleted_at IS NULL 
                    AND class.tenant_uuid = $1
            JOIN academic_calendar
                ON academic_calendar.academic_calendar_id = class.academic_calendar_id
                    AND academic_calendar.deleted_at IS NULL 
                    AND academic_calendar.tenant_uuid = $1
            JOIN school_level_relation
                ON school_level_relation.school_level_relation_id = academic_calendar.school_level_relation_id
                    AND school_level_relation.deleted_at IS NULL 
                    AND school_level_relation.tenant_uuid = $1
        WHERE class_member.deleted_at IS NULL 
            AND class_member.tenant_uuid = $1
            ${queryStrings.join(' ')}
        ORDER BY class_member.student_id ASC
    `,
      [auth.tenant_uuid, ...queryValues]
    );

    if (queryResult.rowCount === 0) {
      return null;
    }

    return queryResult.rows;
  } catch (e) {
    console.error('[ERROR-QUERY] - func: queryGetClassMembers', e);
    throw Error(code.database_error);
  }
}

async function getDetailStudents(req: Request, studentIds: Array<number>): Promise<any> {
  let students = [];

  try {
    // lambda.endpoint = new Endpoint('http://localhost:3012');

    const result = await lambda
      .invoke({
        FunctionName: `student-service-${config.stage}-api-v1`,
        InvocationType: 'RequestResponse',
        LogType: 'Tail',
        Payload: JSON.stringify({
          ...setAuth(req),
          httpMethod: 'POST',
          path: '/student/api/v1/student-by-student-ids',
          body: {
            student_ids: studentIds,
          },
        }),
      })
      .promise();

    const payload = JSON.parse(result.Payload as string);
    const body: ApiModel<any> = JSON.parse(payload.body);

    if (body.status) {
      students = body.data;
    } else {
      console.error(body.message);
      throw Error(body.message);
    }
  } catch (e) {
    console.error('[ERROR-INVOKE] - func: getDetailStudents', e);
    throw Error(e);
  }

  return students;
}

async function getReligions(req: Request): Promise<any> {
  let religions = [];

  try {
    // lambda.endpoint = new Endpoint('http://localhost:3014');

    const result = await lambda
      .invoke({
        FunctionName: `general-service-${config.stage}-api-v1`,
        InvocationType: 'RequestResponse',
        LogType: 'Tail',
        Payload: JSON.stringify({
          ...setAuth(req),
          httpMethod: 'GET',
          path: '/general/v1/religion-list',
        }),
      })
      .promise();

    const payload = JSON.parse(result.Payload as string);
    const body: ApiModel<any> = JSON.parse(payload.body);

    if (body.status) {
      religions = body.data;
    } else {
      console.error(body.message);
      throw Error(body.message);
    }
  } catch (e) {
    console.error(e);
    throw e;
  }

  return religions;
}

async function getStudentsByJoinDate(req: Request, params: any): Promise<any> {
  let students = [];

  try {
    // lambda.endpoint = new Endpoint('http://localhost:3012');

    const result = await lambda
      .invoke({
        FunctionName: `student-service-${config.stage}-api-v1`,
        InvocationType: 'RequestResponse',
        LogType: 'Tail',
        Payload: JSON.stringify({
          ...setAuth(req),
          httpMethod: 'GET',
          path: '/student/api/v1/students/join-date',
          queryStringParameters: {
            year: params.year,
            school_level_id: params.school_level_id,
            school_location_id: params.school_location_id,
            year_level_id: params.year_level_id,
          }
        }),
      })
      .promise();

    const payload = JSON.parse(result.Payload as string);
    const body: ApiModel<any> = JSON.parse(payload.body);

    if (body.status) {
      students = body.data;
    } else {
      console.error(body.message);
      throw Error(body.message);
    }
  } catch (e) {
    console.error('[ERROR-INVOKE] - func: getStudentsByJoinDate', e);
    throw Error(e);
  }

  return students;
}

export default async function classGenerateStudents(req: Request, res: Response): Promise<any> {
  try {
    const auth = getAuth(req);
    const params = req.body;

    if (
      !params.academic_year ||
      !params.periods ||
      !params.school_level_id ||
      !params.school_location_id ||
      !params.year_level_id
    ) {
      throw Error(code.input_invalid);
    }

    const periods = params.periods;

    const previousSchoolLocationsIds = params.previous_school_location_ids;
    const otherSchoolLocationIds = params.other_school_location_ids;

    let schoolLocationIds = [+params.school_location_id];

    if (otherSchoolLocationIds) {
      schoolLocationIds = schoolLocationIds.concat(otherSchoolLocationIds);
    }

    if (previousSchoolLocationsIds) {
      schoolLocationIds = schoolLocationIds.concat(previousSchoolLocationsIds);
    }

    const isFirstYearLevel = params.is_first_year_level;

    const classMembers = [];

    // [START] logic class members from previous class
    const masterPeriods = await queryGetPeriodsByAcademicYear(req.namespace.db, auth, params.academic_year);
    if (!masterPeriods) {
      throw Error(code.data_not_found);
    }

    // Masih Hardcode
    const oddPeriod = masterPeriods[0];
    const evenPeriod = masterPeriods[1];

    const yearLevelsParams = {
      school_level_id: +params.school_level_id,
      school_location_id: +params.school_location_id,
    };

    // check year level
    const yearLevels = await queryGetYearLevelsBySchoolLevel(req.namespace.db, auth, yearLevelsParams);
    if (!yearLevels) {
      throw Error(code.data_not_found);
    }

    const currentYearLevel = yearLevels.find((i) => +i.year_level_id === +params.year_level_id);
    if (!currentYearLevel) {
      throw Error(code.data_not_found);
    }

    if (isFirstYearLevel) {

      /**
       * TODO
       */

    } else {

      for (const period of periods) {

        // odd period
        if (+period === +oddPeriod.period_id) {

          // const currentAcademicYear = params.academic_year;
          // const previousAcademicYear = currentAcademicYear
          //   .split('-')
          //   .map((i) => +(i - 1))
          //   .join('-');

          // get previous year_level
          // const currentYearLevelIndex = yearLevels.findIndex((i) => +i.year_level_id === +currentYearLevel.year_level_id);
          // const previousYearLevel = yearLevels[currentYearLevelIndex - 1];
          //
          // const previousAcademicDataParams = {
          //   academic_year: previousAcademicYear,
          //   period_id: +period,
          //   school_level_id: +params.school_level_id,
          //   school_location_id: null,
          //   year_level_id: previousYearLevel,
          // };

          /**
           * TODO
           * previous class members (graduate status === PASSED)
           */

        }

        // even period
        if (+period === +evenPeriod.period_id) {

          /**
           * TODO
           * previous class members (graduate status === PASSED)
           */

          // unallocated class members from odd period
          for (const schoolLocationId of schoolLocationIds) {

            const unallocatedClassMemberParams = {
              academic_year: params.academic_year,
              school_level_id: +params.school_level_id,
              school_location_id: +schoolLocationId,
              year_level_id: +params.year_level_id,
            }

            const unallocatedClassMembers = await queryGetClassMembers(req.namespace.db, auth, unallocatedClassMemberParams);

            if (unallocatedClassMembers) {
              for (const classMember of unallocatedClassMembers) {
                classMembers.push(classMember);
              }
            }
          }

        }

      }

    }

    // new students
    for (const schoolLocationId of schoolLocationIds) {

      const newStudentsParams = {
        year: params.academic_year.slice(0, 4),
        school_level_id: +params.school_level_id,
        school_location_id: +schoolLocationId,
        year_level_id: +params.year_level_id,
      }

      const newStudents = await getStudentsByJoinDate(req, newStudentsParams);

      if (newStudents) {
        for (const student of newStudents) {
          classMembers.push(student);
        }
      }

    }

    const masterClassMembers = [];

    // get allocated class members
    for (const period of periods) {

      for (const schoolLocationId of schoolLocationIds) {

        const allocatedClassMemberParams = {
          academic_year: params.academic_year,
          period_id: +period,
          school_level_id: +params.school_level_id,
          school_location_id: +schoolLocationId,
          year_level_id: +params.year_level_id,
        }

        const allocatedClassMembers = await queryGetClassMembers(req.namespace.db, auth, allocatedClassMemberParams);

        if (allocatedClassMembers) {
          for (const classMember of allocatedClassMembers) {
            masterClassMembers.push(classMember);
          }
        }

      }

    }

    // check allocated class members with unallocated class members
    for (const masterClassMember of masterClassMembers) {
      const index = classMembers.findIndex(i => +i.student_id === +masterClassMember.student_id);
      if (index > -1) {
        classMembers.splice(index, 1);
      }

    }


    // get students detail and religions
    if (classMembers.length > 0) {

      // get students detail
      const studentsDetail = await getDetailStudents(req, classMembers.map((i) => +i.student_id));
      if (!studentsDetail) {
        throw Error(code.data_not_found);
      }

      // get religions
      const religions = await getReligions(req);
      if (!religions) {
        throw Error(code.data_not_found);
      }

      for (const classMember of classMembers) {
        const index = studentsDetail.findIndex((i) => +i.student_id === +classMember.student_id);
        if (index < 0) {
          continue;
        }

        classMember.student_name = studentsDetail[index].student_name;
        classMember.nis = studentsDetail[index].nis;
        classMember.religion_id = +studentsDetail[index].religion_id;
      }

      for (const classMember of classMembers) {
        const index = religions.findIndex((i) => +i.religion_id === +classMember.religion_id);
        if (index < 0) {
          continue;
        }

        classMember.religion_name = religions[index].religion_name;
      }
    }

    success(res, {
      status: true,
      version: req.version,
      message: 'success',
      data: classMembers,
      meta: null,
    });
  } catch (e) {
    failure(res, e);
  }
}