GCP/Apps Script

Apps Script๋กœ Google Sheets์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์„ ํƒ ํ•ด ๋ช…์„ธ์„œ๋‚˜ ์„ธ๊ธˆ๊ณ„์‚ฐ์„œ, invoice ๋“ฑ๊ณผ ๊ฐ™์€ ์–‘์‹์„ pdf ํŒŒ์ผ๋กœ ์ƒ์„ฑํ•ด ์ด๋ฉ”์ผ๋กœ ์ „์†กํ•˜๊ธฐ

whistory 2023. 4. 19. 11:09
๋ฐ˜์‘ํ˜•

 

 

 

๐Ÿ’ก Google Sheets์—์„œ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ๋กœ pdfํŒŒ์ผ์„ ์ƒ์„ฑ ํ•ด ์ด๋ฉ”์ผ๋กœ ์ „์†กํ•ด๋ณธ๋‹ค.

 

Google Sheets ์—์„œ, ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ๋“ค์— ๋Œ€ํ•ด ๋ช…์„ธ์„œ ์ด๋ฉ”์ผ์„ ์ „์†กํ•œ๋‹ค.

์ด๋ฉ”์ผ์„ ๋ณด๋‚ผ ๋•Œ, pdfํŒŒ์ผ๋„ ์ƒ์„ฑํ•ด ๊ฐ™์ด ์ฒจ๋ถ€ํ•ด์„œ ๋ณด๋‚ด์ค˜ ๋ณธ๋‹ค.

 

์•„๋ž˜์—์„œ ์ •๋ฆฌํ•œ ๋‚ด์šฉ๋“ค์„ ํ™œ์šฉํ•ด์„œ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•ด๋ณธ๋‹ค.

 

 

 

Apps Script๋กœ Google Sheets์˜ Checkbox ์ƒ์„ฑ ํ›„, Checkbox ์กฐ์ž‘ํ•˜๊ธฐ

Apps Script๋ฅผ ์ด์šฉํ•ด, 1. Google Sheets์— Checkbox๋ฅผ ์ƒ์„ฑ 2. ์ฒดํฌ๊ฐ€ ๋˜์—‡์„๋–„ ๋‹ค์Œ์…€์— ๊ฐ’์„ ์ž…๋ ฅ 3. ์ฒดํฌ๋œ checkbox ์ˆ˜ ์„ธ๊ธฐ 4. ์ „์ฒด์„ ํƒ/์ „์ฒด์„ ํƒํ•ด์ œ ๋ฅผ ํ•ด๋ณด๊ฒ ๋‹ค. ์ฒดํฌ๋ฐ•์Šค ์ƒ์„ฑ function createCheckbox() { cons

whiseung.tistory.com

 

 

Apps Script๋กœ Email ๋ณด๋‚ด๊ธฐ (HTML ์–‘์‹)

์ด๋ฉ”์ผ์„ ๋ณด๋‚ด๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค. ์ด๋ฉ”์ผ์˜ ๊ฒฝ์šฐ๋Š”, Google Sheets๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๊ฑฐ๋ž˜๋‚ด์—ญ์ด๋‚˜ ๊ธ‰์—ฌ๋‚ด์—ญ ๋“ฑ์„ ๋‹ค์ˆ˜ ์ „์†ก ํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ์„๊ฒƒ์ด๋‹ค. ํ…œํ”Œ๋ฆฟ์„ ๋งŒ๋“ค๊ณ , Google Sheets์˜ ๋ฐ์ดํ„ฐ๋“ค์„

whiseung.tistory.com

 

 

 

 

์•„๋ž˜์™€ ๊ฐ™์€ ํ™”๋ฉด์ด ์žˆ๋‹ค.

์ง„ํ–‰ํ•  ๋‚ด์šฉ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

  1. A์—ด์˜ checkbox์˜ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ๋“ค๋งŒ ๋ฉ”์ผ์„ ๋ณด๋‚ธ๋‹ค.
  2. Fํ–‰์˜ ์ž…๋ ฅ๋œ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋กœ ๋ฉ”์ผ์„ ๋ณด๋‚ธ๋‹ค.
  3. C, D, E, G ํ–‰์˜ ๊ฐ’๋“ค์„ ์กฐํ•ฉํ•ด ์ด๋ฉ”์ผ ๋‚ด์šฉ์„ ๊ตฌ์„ฑํ•œ๋‹ค.
  4. ๋ฉ”์ผ์ „์†ก์„ ์™„๋ฃŒํ•˜๊ณ  H, I ์— ์ „์†ก์ผ์‹œ์™€ ๋น„๊ณ ๊ฐ’์„ ์ž…๋ ฅํ•ด์ค€๋‹ค.

 

 

๋จผ์ € checkbox๊ฐ€ ์„ ํƒ ๋œ ์—ด์˜ ๋ฐ์ดํ„ฐ๋“ค๋งŒ ๊ฐ€์ ธ์˜จ๋‹ค.

function sendInvoice() {
  const sheet   = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("invoice");
  const values  = sheet.getRange("A2:I"+sheet.getLastRow()).getValues();
  
  const checkCnt = countCheckboxData(values);
  if ( checkCnt < 1 ) {
    console.log("์„ ํƒ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.");
  } else {
    console.log(`${checkCnt}๊ฑด์˜ ๋ฉ”์ผ์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.`);
  }

  values.forEach((row, idx) => {
    if ( row[0] === true ) {
      console.log(row);
    }
  });
}

/**
 * ์ฒดํฌ๋ฐ•์Šค ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ ์ˆ˜ ์ถ”์ถœ์ถœ
 * @param {object} values = ๋ฐ์ดํ„ฐ
 */
function countCheckboxData(values) {
  var checkCount = values.reduce(function (a, b) {
    return a + (b[0] === true ? 1 : 0);
  }, 0);
  return checkCount
}

 

 

 

 

 

 

 

 

function sendInvoice() {
  const sheet   = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("invoice");
  const values  = sheet.getRange("A2:I"+sheet.getLastRow()).getValues();
  
  // ์ฒดํฌ๋ฐ•์Šค ์„ ํƒ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ๋ถ„๊ธฐ์ฒ˜๋ฆฌ
  const checkCnt = countCheckboxData(values);
  if ( checkCnt < 1 ) {
    console.log("์„ ํƒ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.");
    alertMessage("์•Œ๋ฆผ", "์„ ํƒ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.");
    return;
  } else {
    const confirm = confirmMessage('ํ™•์ธ',`${checkCnt}๊ฑด ๋ฉ”์ผ์„ ์ „์†กํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?`);
    if (!confirm) { return; }
  }

  var cnt = 0;
  values.forEach((row, idx) => {
    if ( row[0] == true ) {
      // html contents ์ƒ์„ฑ
      let html = `<h1>[${row[2]}] ${row[3]} ๊ณ ๊ฐ๋‹˜.</h1>`;
      html += `<div>์ด๋ฒˆ๋‹ฌ๋„ ์ €ํฌ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.</div>`;
      html += `<div>์ด๋ฒˆ๋‹ฌ ๋‚ฉ๋ถ€ ๊ธˆ์•ก์€ ${row[6]} ์› ์ž…๋‹ˆ๋‹ค.</div>`;
      html += `<div>์‹ ํ•œ์€ํ–‰ 110-9999-9999999 ์œผ๋กœ ๋‚ฉ๋ถ€ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.</div>`;
      html += `<div>๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.</div>`;

      // pdf contents ์ƒ์„ฑ
      let pdfContents = `<h1>[${row[2]}] ${row[3]} ๊ณ ๊ฐ๋‹˜.</h1>`;
      pdfContents += `<div>์„œ๋น„์Šค ๋‚ฉ๋ถ€์š”๊ธˆ ๋ช…์„ธ์„œ</div>`;
      pdfContents += `<table border="1" style="border-collapse: collapse;">`;
      pdfContents += `  <tr>`;
      pdfContents += `    <th>๊ณ ๊ฐ๋ช…</th>`;
      pdfContents += `    <th>${row[3]}</th>  `;
      pdfContents += `  </tr>`;
      pdfContents += `  <tr>`;
      pdfContents += `    <td>์‚ฌ์—…์ž๋“ฑ๋ก๋ฒˆํ˜ธ</td>`;
      pdfContents += `    <td>${row[4]}</td>`;
      pdfContents += `  </tr>`;
      pdfContents += `  <tr>`;
      pdfContents += `    <td>์ด๋ฉ”์ผ</td>`;
      pdfContents += `    <td>${row[5]}</td>`;
      pdfContents += `  </tr>`;
      pdfContents += `  <tr>`;
      pdfContents += `    <td>๊ธˆ์•ก</td>`;
      pdfContents += `    <td>${row[6]}</td>`;
      pdfContents += `  </tr>`;
      pdfContents += `</table>`;
      pdfContents += `<div>๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.</div>`;

      const blob = Utilities.newBlob(pdfContents, MimeType.HTML);
      blob.setName(`${row[3]}_${getDateTime()}.pdf`);

      const email   = row[5];
      const subject = `${row[3]} ๋ช…์„ธ์„œ`;

      // ๋ฉ”์ผ ์ „์†ก
      MailApp.sendEmail({
                htmlBody    : html,
                to          : email,
                subject     : subject,
                attachments : [blob.getAs(MimeType.PDF)]
              });
      
      // ๋ฉ”์ผ์ „์†ก ํ›„ cell ์ƒํƒœ๊ฐ’ update
      sheet.getRange((idx+2),8).setValue(getDateTime("TS"));
      sheet.getRange((idx+2),9).setValue("์ „์†ก์™„๋ฃŒ");

      cnt++;
    }
  });

  console.log(`${cnt} ๊ฑด ๋ฉ”์ผ์„ ์ „์†กํ•˜์˜€์Šต๋‹ˆ๋‹ค.`);
  alertMessage("์„ฑ๊ณต", `${cnt} ๊ฑด ๋ฉ”์ผ์„ ์ „์†กํ•˜์˜€์Šต๋‹ˆ๋‹ค.`);
}

/**
 * ์ฒดํฌ๋ฐ•์Šค ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ ์ˆ˜ ์ถ”์ถœ์ถœ
 * @param {object} values = ๋ฐ์ดํ„ฐ
 */
function countCheckboxData(values) {
  var checkCount = values.reduce(function (a, b) {
    return a + (b[0] === true ? 1 : 0);
  }, 0);
  return checkCount
}
/**
 * Alert Message for Google sheet.
 * @param {string} tit = ํƒ€์ดํ‹€
 * @param {string} msg = ๋ฉ”์„ธ์ง€
 */
function alertMessage(tit, msg) {
  var ui = SpreadsheetApp.getUi();
  ui.alert(tit, msg, ui.ButtonSet.OK);
}
/**
 * Confrim Message for Google sheet.
 * @param {string} tit = ํƒ€์ดํ‹€
 * @param {string} msg = ๋ฉ”์„ธ์ง€
 */
function confirmMessage(tit, msg) {
  const ui        = SpreadsheetApp.getUi();
  const response  = ui.alert(tit, msg, ui.ButtonSet.YES_NO);

  if ( response == ui.Button.YES ) {
    return true;
  } else {
    return false;
  }
}
/**
 * ํ˜„์žฌ ์‹œ๊ฐ„(KST) return
 * @param {string} gubun  = ๊ตฌ๋ถ„์ž (Default / Timestamp)
 */
function getDateTime(gubun) {
  const curr          = new Date();
  const utc           = curr.getTime() + (curr.getTimezoneOffset() * 60 * 1000);
  const KR_TIME_DIFF  = 9 * 60 * 60 * 1000;
  const today         = new Date(utc + (KR_TIME_DIFF));
  
  var dateConcat  = "";
  var timeConcat  = "";
  var allConcat   = "";

  if ( !isNull(gubun) && gubun.toUpperCase() == "TS" ) {
    dateConcat  = "-";
    timeConcat  = ":";
    allConcat   =  "T";
  } else {
    dateConcat  = "";
    timeConcat  = "";
    allConcat   =  "_";
  }

  const date    = today.getFullYear() + dateConcat + lpad((today.getMonth()+1), 2, '0') + dateConcat + lpad(today.getDate(), 2, '0');
  const time    = lpad(today.getHours(), 2, '0') + timeConcat + lpad(today.getMinutes(), 2, '0') + timeConcat + lpad(today.getSeconds(), 2, '0');
  const result  = date + allConcat + time;
  return result;
}
/**
 * ์ขŒ์ธก ๋ฌธ์ž์—ด ์ฑ„์šฐ๊ธฐ
 * @param {string}  str     = ์› ๋ฌธ์ž์—ด
 * @param {int}     padLen  = ์ตœ๋Œ€ ์ฑ„์šฐ๊ณ ์ž ํ•˜๋Š” ๊ธธ์ด
 * @param {string}  padStr  = ์ฑ„์šฐ๊ณ ์žํ•˜๋Š” ๋ฌธ์ž(char)
 */
function lpad(str, padLen, padStr) {
  if ( padStr.length > padLen ) {
    console.log("์˜ค๋ฅ˜ : ์ฑ„์šฐ๊ณ ์ž ํ•˜๋Š” ๋ฌธ์ž์—ด์ด ์š”์ฒญ ๊ธธ์ด๋ณด๋‹ค ํฝ๋‹ˆ๋‹ค");
    return str;
  }
  str     += "";
  padStr  += "";
  while (str.length < padLen) {
    str = padStr + str;
  }
  str = str.length >= padLen ? str.substring(0, padLen) : str;
  return str;
}

 

 

Alert ๊ณผ Confirm ๋ฉ”์‹œ์ง€

 

๋ฉ”์ผ์€ ์ „์†กํ•˜๋ฉด, ๋งˆ์ง€๋ง‰๋ฉ”์ผ์ „์†ก์ผ๊ณผ ๋น„๊ณ ์— ๊ฐ’์„ ์ž…๋ ฅํ•ด์ค€๋‹ค.

 

 

์‹ค์ œ ์ „์†ก๋œ ๋ฉ”์ผ ์ƒ˜ํ”Œ

 

 

html์„ ์ž˜ ๋‹ค๋“ฌ์–ด์ฃผ๋ฉด, ์‹œ์Šคํ…œ์ฒ˜๋Ÿผ ์žˆ์–ด๋ณด์ด๊ฒŒ ๊ณ ๊ฐ๋“ค์—๊ฒŒ ๋ฉ”์ผ์„ ์ „์†ก ํ•  ์ˆ˜ ์žˆ์„๊ฒƒ์ด๋‹ค.

 

 

๋ฐ˜์‘ํ˜•