This commit is contained in:
louiscklaw
2025-01-31 19:29:24 +08:00
parent 843c590c8b
commit abff74fd77
81 changed files with 7754 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
function appendResult(row, comment_to_write) {
var output = { state: "init", debug: { comment_to_write }, error: "" };
try {
var sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(
SHEET_STUDENT_PROGRESS
);
var result_cell = getCell(sheet, row, COL_STUDENT_PROGRESS_RESULT);
var result_value = readCell(result_cell);
if (result_value.trim() == "") {
writeCell(result_cell, comment_to_write);
} else {
writeCell(result_cell, [result_value, comment_to_write].join("\n"));
}
} catch (error) {
output = { ...output, error };
console.log(output);
}
}

View File

@@ -0,0 +1,12 @@
function checkEmailQuotaAvailable() {
var output = { state: "init", debug: {}, error: {} };
try {
var emailQuotaRemaining = MailApp.getRemainingDailyQuota();
return emailQuotaRemaining > 0;
} catch (error) {
output = {...output , error}
console.log('checkEmailQuotaAvailable error')
console.log(output);
}
}

View File

@@ -0,0 +1,57 @@
function checkLastRow(sheet, current_row) {
// return true if considered last row, false if not
// check email column only
output = {state:'init', debug:{sheet, current_row}, error:{}}
try {
var current_row_cell = getCell(
sheet,
current_row,
COL_STUDENT_PROGRESS_EMAIL_ADDRESS
);
var current_row_cell_1 = getCell(
sheet,
current_row + 1,
COL_STUDENT_PROGRESS_EMAIL_ADDRESS
);
var current_row_cell_2 = getCell(
sheet,
current_row + 2,
COL_STUDENT_PROGRESS_EMAIL_ADDRESS
);
var current_row_cell_3 = getCell(
sheet,
current_row + 3,
COL_STUDENT_PROGRESS_EMAIL_ADDRESS
);
var current_row_cell_4 = getCell(
sheet,
current_row + 4,
COL_STUDENT_PROGRESS_EMAIL_ADDRESS
);
var current_row_cell_5 = getCell(
sheet,
current_row + 5,
COL_STUDENT_PROGRESS_EMAIL_ADDRESS
);
var check_is_empty = [
isCellEmpty(current_row_cell),
isCellEmpty(current_row_cell_1),
isCellEmpty(current_row_cell_2),
isCellEmpty(current_row_cell_3),
isCellEmpty(current_row_cell_4),
isCellEmpty(current_row_cell_5),
];
return check_is_empty.indexOf(false) < 0;
} catch (error) {
output ={...output, error}
console.log("checkLastRow: error");
console.log(output)
return false;
}
}

View File

@@ -0,0 +1,10 @@
function checkNotNotifiedForPayment(cell_value) {
var output = { state: "init", debug: {}, error: "" };
try {
return cell_value == CONST_NOT_NOTIFIED;
} catch (error) {
console.log('checkNotNotifiedForPayment error')
output = { ...output, error };
console.log(output);
}
}

View File

@@ -0,0 +1,27 @@
function checkPaymentLinkAvailable(current_row) {
var output = { state: "init", debug: { current_row }, error: {} };
try {
var sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(
SHEET_STUDENT_PROGRESS
);
var payment_link_cell = getCell(
sheet,
current_row,
COL_STUDENT_PROGRESS_PAYMENT_LINK
);
var payment_link = readCell(payment_link_cell);
console.log({ payment_link });
if (payment_link.search(/^https?:\/\/.+/) > -1) {
return true;
}
return false;
} catch (error) {
output = { ...output, error };
console.log('checkPaymentLinkAvailable error')
console.log(output);
return false;
}
}

View File

@@ -0,0 +1,10 @@
function getCell(sheet, row, column) {
output = {state:'init', debug:{}, error:{}}
try {
var cell = sheet.getRange(column + row);
return cell;
} catch (error) {
output = {...output, error}
console.log(output);
}
}

View File

@@ -0,0 +1,3 @@
function getChineseDayString() {
return Utilities.formatDate(new Date(), "GMT+8", "yyyy 年 MM 月 dd 日");
}

View File

@@ -0,0 +1,27 @@
function getLastRow(sheet) {
var output = { state: "init", debug: {sheet}, error: "" };
try {
var last_row = -1;
var row_scan = 99999;
for (let i = 1; i < row_scan; i++) {
if (checkLastRow(sheet, i)) {
// print last row number
last_row = i - 1;
output = { ...output, debug: { ...output.debug, last_row } };
console.log("last row is " + last_row.toString());
break;
} else {
// keep going
}
}
if (last_row == -1) {
throw new Error('cannot find the last row')
}
return last_row;
} catch (error) {
console.log('getLastRow error')
output = { ...output, error };
console.log(output);
}
}

View File

@@ -0,0 +1,14 @@
function getSheetStudentProgress() {
output = {state:'init', debug:{}, error:{}}
try {
var sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(
SHEET_STUDENT_PROGRESS
);
return sheet;
} catch (error) {
output = {...output, error}
console.log("getSheetStudentProgress error")
console.log(output);
}
}

View File

@@ -0,0 +1,12 @@
function isCellEmpty(cell) {
var output = { state: "init", debug: {}, error: {} };
try {
// console.log("isCellEmpty:" + cell.getValue());
var temp = cell.getValue().toString().trim();
return temp == "";
} catch (error) {
console.log("isCellEmpty error");
output = { ...output, error };
console.log(output);
}
}

View File

@@ -0,0 +1,51 @@
function processPaymentNotice() {
var output = { state: "init", debug: {}, error: "" };
try {
var sheet = getSheetStudentProgress();
var last_row = getLastRow(sheet);
output = { ...output, debug: { ...output.debug, last_row } };
for (var i = ROW_START; i < last_row + 1; i++) {
var email_cell = getCell(sheet, i, COL_STUDENT_PROGRESS_EMAIL_ADDRESS);
var payment_progress_cell = getCell(
sheet,
i,
COL_STUDENT_PROGRESS_PAYMENT_PROGRESS
);
var payment_progress = readCell(payment_progress_cell);
if (checkNotNotifiedForPayment(payment_progress)) {
resetResult(i);
appendResult(
i,
`not notified(${CONST_NOT_NOTIFIED}), proceed send payment notification email`
);
var quota_available = checkEmailQuotaAvailable();
var payment_link_available = checkPaymentLinkAvailable(i);
if (quota_available && payment_link_available) {
try {
sendPaymentNoticeEmail(i);
updateRowToNotificationSent(i);
} catch (error) {
Browser.msgBox("error during sending email");
}
} else {
if (quota_available < 1) {
Browser.msgBox(EMAIL_QUOTA_USED_UP);
}
if (!payment_link_available) {
appendResult(i, `payment link not exist, skipping`);
}
}
} else {
resetResult(i);
appendResult(i, `not "${CONST_NOT_NOTIFIED}" skipping`);
// var student_email = readCell(email_cell);
}
}
} catch (error) {
output = { ...output, error };
console.log(output);
}
}

View File

@@ -0,0 +1,10 @@
function readCell(cell) {
var output = { state: "init", debug: {}, error: {} };
try {
return cell.getValue() || "";
} catch (error) {
output = {...output, err: error}
console.log(error);
}
}

View File

@@ -0,0 +1,16 @@
function resetResult(row) {
var output = { state: "init", debug: {}, error: "" };
try {
var sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(
SHEET_STUDENT_PROGRESS
);
var result_cell = getCell(sheet, row, COL_STUDENT_PROGRESS_RESULT);
return writeCell(result_cell, null);
} catch (error) {
console.log("resetResult error");
output = { ...output, error };
console.log(output);
console.log(error);
}
}

View File

@@ -0,0 +1,3 @@
function sayHelloworld() {
console.log("say helloworld");
}

View File

@@ -0,0 +1,11 @@
function sendEmail(options) {
var output = { state: "init", debug: {}, error: {} };
try {
MailApp.sendEmail(options);
output = { ...output, state: "done" };
} catch (error) {
output = { ...output, error };
console.log("sendEmail error");
console.log(output);
}
}

View File

@@ -0,0 +1,121 @@
function sendPaymentNoticeEmail(row) {
var output = { state: "init", debug: {}, error: {} };
var sheet = getSheetStudentProgress();
// var filename = "payment_guide.pdf";
var fps_tutorial_pdf_file_id = "1iD4CL8X-Nr7vfmj3UI3OzrJaKl1Gbg8tGAi6T6EmEJ0";
var fps_tutorial_pdf_file = DriveApp.getFileById(fps_tutorial_pdf_file_id);
// NOTE: student email?
var student_email_address_cell = getCell(
sheet,
row,
COL_STUDENT_PROGRESS_EMAIL_ADDRESS
);
var student_email_address = readCell(student_email_address_cell);
var student_chinese_name_cell = getCell(
sheet,
row,
COL_STUDENT_PROGRESS_CHINESE_NAME
);
var student_chinese_name = readCell(student_chinese_name_cell);
// NOTE: courase_name
var course_offered_cell = getCell(
sheet,
row,
COL_STUDENT_PROGRESS_COURSE_OFFERED
);
var course_offered = readCell(course_offered_cell);
if (course_offered == "") {
output = {
...output,
debug: {
...output.debug,
remarks: {
course_offered,
comment: "found empty",
},
},
};
}
// NOTE: course_code
var course_code_cell = getCell(sheet, row, COL_STUDENT_PROGRESS_COURSE_CODE);
var course_code = readCell(course_code_cell);
if (course_code == "") {
output = {
...output,
debug: {
...output.debug,
remarks: {
course_code,
comment: "found empty",
},
},
};
}
// NOTE: payment_link
var payment_link_cell = getCell(
sheet,
row,
COL_STUDENT_PROGRESS_PAYMENT_LINK
);
var payment_link = readCell(payment_link_cell);
if (payment_link == "") {
output = {
...output,
debug: {
...output.debug,
remarks: {
payment_link,
comment: "found empty",
},
},
};
}
// NOTE: courase_name
// NOTE: courase_name
try {
var subject = email_title(course_offered);
// var body = email_content("中文名", "chinese 中文科", "CHI001");
var htmlBody = email_content(
student_chinese_name,
course_offered,
course_code,
payment_link,
getChineseDayString()
);
var recipient = student_email_address;
if (recipient=='') throw new Error('email address not valid');
var sender = "testhelloworld04@gmail.com";
// https://developers.google.com/apps-script/reference/mail/mail-app
var options = {
bcc: sender,
replyTo: sender,
to: recipient,
subject: subject,
// body: body,
htmlBody: htmlBody,
attachments: [fps_tutorial_pdf_file.getAs(MimeType.PDF)],
};
sendEmail(options);
updateNotificationDate(row)
appendResult(row, "send email done");
output = { ...output, state: "send email done" };
} catch (error) {
output = { ...output, error };
console.log("sendEmail error");
console.log(error);
throw error;
}
}

View File

@@ -0,0 +1,15 @@
function updateNotificationDate(row) {
output = {state:"init", debug:{}, error:{}}
try {
var student_progress_sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(
SHEET_STUDENT_PROGRESS
);
var notification_date_cell = getCell(student_progress_sheet, row, COL_STUDENT_PROGRESS_NOTIFICATION_DATE)
writeCell(notification_date_cell, getChineseDayString().replace(/ /g,''))
} catch (error) {
output = {...output, error}
console.log('updateNotificationDate error')
console.log(output)
}
}

View File

@@ -0,0 +1,17 @@
function updateRowToNotificationSent(row) {
var output = { state: "init", debug: { row }, error: {} };
try {
var sheet = getSheetStudentProgress();
var payment_progress_cell = getCell(
sheet,
row,
COL_STUDENT_PROGRESS_PAYMENT_PROGRESS
);
writeCell(payment_progress_cell, CONST_NOTIFIED_ALREADY);
return;
} catch (error) {
output = { ...output, error };
console.log(error);
}
}

View File

@@ -0,0 +1,11 @@
function writeCell(cell, content) {
var output = { state: "init", debug: {}, error: "" };
try {
cell.setValue(content);
} catch (error) {
output = {...output, error}
console.log("writeCell error");
console.log(output);
}
}