method/testControl.js

/**
 * @module method/testControl
 */
const getUserMeta = require('./get');
const updateUserMeta = require('./update');

const admin = require('firebase-admin');
const functions = require('firebase-functions');
const axios = require('axios');

const db = admin.firestore();
const FieldValue = admin.firestore.FieldValue;
const Timestamp = admin.firestore.Timestamp;

const { loandisk, simplybook } = functions.config();
// Hard-coded to make sure only dev branch will be affected
const branchId = '8895';
const config = {
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Basic ${loandisk.authcode}`,
  },
};

const simplybookApi = axios.create({
  baseURL: 'https://user-api-v2.simplybook.me/', // NOTE: This uses the v2 ReST API
  headers: {
    'Content-Type': 'application/json',
    'X-Company-Login': simplybook.company,
  }
});

/**
 * Run a command to control the test environment
 *
 * - resetData: Resets all Firestore, Loandisk and Firebase Auth records to their initial state.
 * - unlockReloanAppointment - Allows the given user to make an appointment.
 *
 * @requires method/get
 * @requires method/update
 *
 * @param  {object} data - The data object attached to the request
 * @param  {string} data.command - The command to execute
 * @param  {object} data.params - Object with named parameters for the command
 *
 * @return {(string|boolean)} True if the command is executed, otherwise false.
 */
const testControl = {
  run: async ({ command, params }) => {
    // TODO Authorization?
    switch (command) {
      case 'resetData':
        await testControl.resetData();
        break;
      case 'unlockReloanAppointment':
        await updateUserMeta({
          uid: params.uid,
          appointmentType: params.appointmentType,
        })
        break;
      default:
        console.warn(`Unknown command: ${command}`)
        return false;
    }

    return true;
  },
  resetData: () => {
    return Promise.all([
      // Delete everything
      getUserMeta({
        uid: 'hk_wx0000009',
      }).then((userMeta) => {
        return Promise.all([
          testControl.cancelAppointmentForUserSync(userMeta),
          testControl.deleteUserSync(userMeta),
        ])
      }),

      // Delete reloan data
      getUserMeta({
        uid: 'hk_wx1111114',
      }).then((userMeta) => {
        return testControl.cancelAppointmentForUserSync(userMeta);
      }),

      testControl.updateUserMetaForUid({
        uid: 'hk_wx1111114',
        hasReloanPhoneNumber: FieldValue.delete(),
        reloanStartTime: FieldValue.delete(),
        appointmentType: FieldValue.delete(),
      }),

      // Reset expired reloan application
      testControl.updateUserMetaForUid({
        uid: 'hk_wx222222a',
        hasReloanPhoneNumber: "Yes",
        reloanStartTime: Timestamp.fromMillis(0),
      }),

      // Reset loan release date and status
      testControl.resetWX40Loan(),

      // Delete simplybook appointment and reset account to initial state
      getUserMeta({
        uid: 'hk_wx5555556',
      }).then((userMeta) => {
        return testControl.cancelAppointmentForUserSync(userMeta);
      }).then((response) => {
        testControl.updateUserMetaForUid({
          uid: 'hk_wx5555556',
          borrowerID: 1305255,
          branchID: 8895,
          country: 'HK',
          failCount: 0,
          idNumber: 'WX555555(6)',
          passwordHash: 'af41e68e1309fa29a5044cbdc36b90a3821d8807e68c7675a6c495112bc8a55f',
        }, true)
      }),
    ]).then(() => {
      return true
    });
  },
  cancelAppointmentForUserSync: async ({bookingID, uid}) => {
    if (bookingID !== undefined) {
      const authResponse = await simplybookApi.post('/admin/auth', {
        "company": simplybook.company,
        "login": simplybook.username,
        "password": simplybook.password
      });

      const deleteResponse = await simplybookApi.delete(`/admin/bookings/${bookingID}`, {
        headers: {
          'X-Token': authResponse.data.token,
        }
      });

      const { status } = deleteResponse.data;

      if (status === 'canceled') {
        console.info(`[Success] Deleted booking ${bookingID} for ${uid}`)
        return deleteResponse;
      } else {
        console.warn(`[Warning] Unable to delete booking ${bookingID} for ${uid}`);
        throw new Error(deleteResponse);
      }
    }
  },
  deleteUserSync: async ({borrowerID, branchID, uid}) => {
    if (borrowerID !== undefined) {
      try {
        const {data} = await axios.delete(
          `${loandisk.url}/${loandisk.publickey}/${branchID}/borrower/${borrowerID}`,
          config
        )

        if (data.error) {
          if (data.error.code === '404') {
            console.warn(`[Warning] No Loandisk borrower found for ${uid}`);
            return;
          }
        } else {
          if (data.response === 'deleted') {
            console.info(`[Success] Deleted Loandisk borrower for ${uid}`);
          } else {
            console.warn(`[Failure] Loandisk sent an unexpected response when trying to delete ${uid}`);
          }
        }
        console.debug(`${data.response}`);
      } catch (error) {
        console.error('[Failure] An issue occured while communicating with Loandisk:', error.details);
      }
    }

    try {
      const userMetaRef = db.collection('appUserMeta');
      await userMetaRef.doc(uid).delete()
      console.info('[Success] Deleted user meta data');
    } catch (error) {
      console.log('[Failure] Error deleting user meta data', error);
    }

    try {
      await admin.auth().deleteUser(uid)
      console.info('[Success] Deleted user');
    } catch (error) {
      console.log('[Failure] Error deleting user', error);
    }
  },
  resetWX40Loan: async () => {
    try {
      const { data } = await axios.put(
        `${loandisk.url}/${loandisk.publickey}/${branchId}/loan/1469453`,
        {
          'loan_id': 1469453,
          'loan_product_id': 55315,
          'borrower_id': 1303604,
          'loan_application_id': '1000063',
          'loan_disbursed_by_id': 19412,
          'loan_principal_amount': '15000.00',
          'loan_released_date': '28/09/2021',
          'loan_interest_method': 'flat_rate',
          'loan_interest_type': 'percentage',
          'loan_interest_period': 'Month',
          'loan_interest': '1.5000',
          'loan_duration_period': 'Months',
          'loan_duration': 15,
          'loan_payment_scheme_id': 3,
          'loan_num_of_repayments': 15,
          'loan_decimal_places': 'round_off_to_two_decimal',
          'loan_interest_start_date': null,
          'loan_fees_pro_rata': 0,
          'loan_do_not_adjust_remaining_pro_rata': 0,
          'loan_first_repayment_pro_rata': 0,
          'loan_first_repayment_date': '07/11/2022',
          'first_repayment_amount': '0.00',
          'last_repayment_amount': '0.00',
          'loan_override_maturity_date': null,
          'override_each_repayment_amount': '0.00',
          'loan_interest_each_repayment_pro_rata': null,
          'loan_interest_schedule': 'charge_interest_normally',
          'loan_principal_schedule': null,
          'loan_balloon_repayment_amount': null,
          'automatic_payments': 0,
          'payment_posting_period': 0,
          'total_amount_due': null,
          'balance_amount': '18375.00',
          'due_date': '07/01/2024',
          'total_paid': '0.00',
          'child_status_id': 18,
          'loan_fee_schedule_2523': null,
          'loan_fee_id_2523': 0,
          'loan_override_sys_gen_penalty': 0,
          'loan_manual_penalty_amount': '0.00',
          'loan_status_id': 8,
          'loan_title': null,
          'loan_description': '',
          'custom_field_1757': '33.8',
          'custom_field_2422': '',
          'custom_field_2423': '',
          'custom_field_2424': '',
          'custom_field_2425': '',
          'custom_field_2439': '',
          'custom_field_2864': '1500',
          'custom_field_3190': '31/12/2022',
          'custom_field_4447': '',
          'custom_field_5319': '1500',
          'custom_field_5355': '15000'
        },
        config
      );
      console.info(`[Success] Reset processing loan for WX444444(0)`);
    } catch (error) {
      console.log('[Failure] Error resetting processing loan for WX444444(0)', error);
    }
  },
  updateUserMetaForUid: (user, forceSet) => {
    if (forceSet === undefined) {
      forceSet = false;
    }

    return updateUserMeta(user, forceSet).then(() => {
      console.info(`[Success] User meta data updated for ${user.uid}`);
      return true;
    });
  },
};

module.exports = testControl.run;