5장 실전! 거래처별 월정산서 자동으로 만들기
5장 그림 보기
[예제 05-01] 판매데이터 탭의 데이터 전체를 가져와서 로그를 표시
function filterSalesData() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
Logger.log(`총 ${salesData.length - 1} 행의 판매데이터가 있습니다.`)
Logger.log(salesData[0])
Logger.log(salesData[0][1])
Logger.log(salesData)
}
JavaScript
복사
전체 데이터를 거래처100으로 필터링
function filterSalesData() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
const salesDataFiltered = salesData.filter(row => row[1] == '거래처100')
Logger.log(salesDataFiltered.length)
Logger.log(salesDataFiltered)
}
JavaScript
복사
[예제 05-02] 데이터를 거래처명과 날짜 범위로 필터링하기
function filterSalesDataByCustomerAndDate() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
const startDate = new Date('2023-06-01')
const endDate = new Date('2023-06-30')
Logger.log(startDate)
Logger.log(endDate)
const salesDataFiltered = salesData.filter(row => row[1] == '거래처100' && row[0] >= startDate && row[0] <= endDate)
Logger.log(salesDataFiltered.length)
Logger.log(salesDataFiltered)
}
JavaScript
복사
데이터를 거래처명과 시분초를 포함한 날짜 범위로 필터링하기
function filterSalesDataByCustomerAndDate() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
Logger.log(startDate)
Logger.log(endDate)
const salesDataFiltered = salesData.filter(row => row[1] == '거래처100' && row[0] >= startDate && row[0] <= endDate)
Logger.log(salesDataFiltered.length)
Logger.log(salesDataFiltered)
}
JavaScript
복사
map으로 원하는 열을 가져오고, 순번 매기기
function filterSalesDataByCustomerAndDate() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
Logger.log(startDate)
Logger.log(endDate)
const salesDataFiltered = salesData.filter(row => row[1] == '거래처100' && row[0] >= startDate && row[0] <= endDate)
Logger.log(salesDataFiltered.length)
Logger.log(salesDataFiltered)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
Logger.log(salesDataResult)
}
JavaScript
복사
filter, map 결과를 newSheet 파일에 붙여넣기 최종 코드
function filterSalesDataByCustomerAndDate() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const salesDataFiltered = salesData.filter(row => row[1] == '거래처100' && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
const NEW_SS = SpreadsheetApp.create('newSheet')
NEW_SS.getActiveSheet().getRange(1, 1, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
const newSheetUrl = NEW_SS.getUrl()
Logger.log(newSheetUrl)
}
JavaScript
복사
[예제 05-03] for문을 적용해서 4개 거래처 필터링 결과를 파일로 만들기
function createSheetsByCustomers() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = ['거래처100', '거래처20', '거래처793', '거래처142']
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
for (i = 0; i < customers.length; i++) {
const salesDataFiltered = salesData.filter(row => row[1] == customers[i] && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
const NEW_SS = SpreadsheetApp.create('newSheet')
NEW_SS.getActiveSheet().getRange(1, 1, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
const newSheetUrl = NEW_SS.getUrl()
Logger.log(newSheetUrl)
}
}
JavaScript
복사
Utilities.formatDate()를 사용해서 날짜 형식 변경하기
function createSheetsByCustomers() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = ['거래처100', '거래처20', '거래처793', '거래처142']
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
Logger.log(startDateForName)
Logger.log(endDateForName)
/* for (i = 0; i < customers.length; i++) {
const salesDataFiltered = salesData.filter(row => row[1] == customers[i] && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
const NEW_SS = SpreadsheetApp.create('newSheet')
NEW_SS.getActiveSheet().getRange(1, 1, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
const newSheetUrl = NEW_SS.getUrl()
Logger.log(newSheetUrl)
} */
}
JavaScript
복사
[예제 05-04] 파일명과 저장되는 폴더를 지정하는 최종 코드
function createSheetsByCustomersMoveToFolder() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = ['거래처100', '거래처20', '거래처793', '거래처142']
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const resultFolderId = '폴더ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
for (i = 0; i < customers.length; i++) {
Logger.log(`${customers[i]}의 작업을 시작합니다.`)
const salesDataFiltered = salesData.filter(row => row[1] == customers[i] && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
const NEW_SS = SpreadsheetApp.create('newSheet')
NEW_SS.getActiveSheet().getRange(1, 1, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
const newSheetUrl = NEW_SS.getUrl()
const newSheetName = `${customers[i]}_${startDateForName}_${endDateForName}`
const newSheetId = NEW_SS.getId()
DriveApp.getFileById(newSheetId).moveTo(resultFolder).setName(newSheetName)
Logger.log(newSheetUrl)
}
}
JavaScript
복사
[예제 05-05] 월정산서를 생성하는 중간 코드
function createMonthlyInvoice() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
const T_CUSTOMER = SS.getSheetByName('거래처')
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
for (i = 0; i < customers.length; i++) {
Logger.log(`${customers[i][1]}의 작업을 시작합니다.`)
const salesDataFiltered = salesData.filter(row => row[1] == customers[i][1] && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 여기에 템플릿 탭을 복사하고 위치에 맞추어 데이터를 입력하는 코드가 들어갈 예정
}
}
JavaScript
복사
[예제 05-06] 월정산서 생성하는 최종 코드
function createMonthlyInvoice() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
const T_CUSTOMER = SS.getSheetByName('거래처')
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
for (i = 0; i < customers.length; i++) {
Logger.log(`${customers[i][1]}의 작업을 시작합니다.`)
const salesDataFiltered = salesData.filter(row => row[1] == customers[i][1] && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
const newTabName = `${customers[i][1]}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
newTab.getRange('C8').setValue(customers[i][1]) // 거래처명
newTab.getRange('C9').setValue(customers[i][4]) // 담당자
newTab.getRange('C10').setValue(customers[i][5]) // 연락처
newTab.getRange('E10').setValue(customers[i][6]) // 이메일
newTab.getRange('H13').setValue(startDateForName)
newTab.getRange('K13').setValue(endDateForName)
newTab.getRange('B13').setValue(new Date())
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
newTab.getRange('H9').setValue(salesDataSum)
}
Logger.log(templateCopy.getUrl())
}
JavaScript
복사
[예제 05-07] 월정산서 생성하는 최종 코드에 주석 추가하기
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoice () {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const salesData = T_SALESDATA.getDataRange().getValues()
const T_CUSTOMER = SS.getSheetByName('거래처')
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
JavaScript
복사
[예제 05-08] 코드 위치 변경 및 블록 주석 추가하기
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoice() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
JavaScript
복사
[예제 05-09] customer 변수를 객체로 추가해서 활용하기
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
(중략)
}
JavaScript
복사
for문으로 셀 배열에 맞추어 값 입력하기
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (let j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
JavaScript
복사
[예제 05-10] 주석을 추가하고 리팩터링한 최종 코드
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoice() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
}
Logger.log(templateCopy.getUrl())
}
JavaScript
복사
익숙해지기
// 1) resultFolderId를 알고 있을 때, 이 ID로 폴더를 지정하려면 어떻게 해야할까요?
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
JavaScript
복사
// 2) '2023-06-01 00:00:00' 문자열로 날짜를 생성하려면 어떻게 해야할까요?
const startDate = new Date('2023-06-01 00:00:00')
JavaScript
복사
// 3) arr의 크기(길이)를 알기 위해서는 어떻게 할 수 있을까요? 크기는 몇일까요?
function myFunction() {
const arr = [[1, 2], [3, 4], [5]]
Logger.log(arr.length) // 실행로그 3
}
JavaScript
복사
// 4) 메서드 체이닝을 사용해서 다음의 코드를 1행으로 줄여보세요.
file.moveTo(resultFolder)
file.setName(newSheetName)
file.moveTo(resultFolder).setName(newSheetName)
JavaScript
복사
// 5) startDate의 형식을 yy-MM-dd로 변경해서 startDateForName에 할당하려면 어떻게 해야할까요?
const startDate = new Date('2023-06-01 00:00:00')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yy-MM-dd')
JavaScript
복사
6장 실전! 월정산서를 PDF로 변환하고 구글 드라이브에 저장하기
6장 그림 보기
[예제 06-01] A4용지에 맞춰 페이지 단위로 행을 조절하는 함수
function adjustTabRowsByPage(salesDataResult, newTab) {
const pageNo = Math.ceil((salesDataResult.length - 56) / 73 + 1)
const deleteRowStart = pageNo * 73
const deleteRows = 1000 - deleteRowStart + 1
newTab.deleteRows(deleteRowStart, deleteRows)
}
JavaScript
복사
[예제 06-02] 데이터에 맞춰 행을 조절하는 함수
function adjustTabRowsByData(salesDataResult, newTab) {
const deleteRowStart = 17 + salesDataResult.length
const deleteRows = 1000 - deleteRowStart + 1
newTab.deleteRows(deleteRowStart, deleteRows)
}
JavaScript
복사
[예제 06-03] 전체 탭을 포함한 통합문서 PDF를 다운로드하는 HtmlService를 추가한 함수
function pdfDownloadWhole(templateCopyId){
const ui = SpreadsheetApp.getUi()
const pdfUrl = `https://docs.google.com/spreadsheets/d/${templateCopyId}/export?format=pdf&size=A4`
const html = `<script>
window.location.href="${pdfUrl}"
setTimeout(function(){google.script.host.close()}, 10000)
</script>`
const htmlOutput = HtmlService.createHtmlOutput(html)
ui.showModalDialog(htmlOutput, 'PDF를 다운로드 합니다.')
}
JavaScript
복사
createMonthlyInvoice_WholeDN 함수
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoice_WholeDN() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
}
Logger.log(templateCopy.getUrl())
pdfDownloadWhole(templateCopyId)
}
JavaScript
복사
[예제 06-04] 각 탭의 PDF를 다운로드받는 HtmlService를 추가한 코드
function pdfDownloadTab(templateCopyId, tabId){
const ui = SpreadsheetApp.getUi()
const pdfUrl = `https://docs.google.com/spreadsheets/d/${templateCopyId}/export?format=pdf&size=A4&gid=${tabId}`
const html = `<script>
window.location.href="${pdfUrl}"
setTimeout(function(){google.script.host.close()},5000)
</script>`
const htmlOutput = HtmlService.createHtmlOutput(html)
ui.showModalDialog(htmlOutput, 'PDF를 다운로드 합니다.')
Utilities.sleep(7000)
}
JavaScript
복사
createMonthlyInvoice_TabDN 함수
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoice_TabDN() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
// 월정산서 탭 다운로드
const tabId = newTab.getSheetId()
pdfDownloadTab(templateCopyId, tabId)
}
Logger.log(templateCopy.getUrl())
}
JavaScript
복사
[예제 06-05] 구글 홈페이지를 PDF로 변환해서 드라이브에 저장하기
function getPdfTest(){
const blob = UrlFetchApp.fetch('https://www.google.com/').getAs('application/pdf')
DriveApp.createFile(blob).setName('test.pdf')
}
JavaScript
복사
[예제 06-06] 전체 페이지 PDF를 구글 드라이브에 저장하는 함수
createMonthlyInvoice_WholeDrive함수
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoice_WholeDrive() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
}
Logger.log(templateCopy.getUrl())
pdfSaveWhole(templateCopyId, resultFolder, templateCopyName)
}
JavaScript
복사
[예제 06-07] 월정산 탭을 PDF로 변환해서 드라이브에 저장하는 함수
function pdfSaveTab(templateCopyId, resultFolder, newTabName, tabId) {
const pdfUrl = `https://docs.google.com/spreadsheets/d/${templateCopyId}/export?format=pdf&size=A4&gid=${tabId}`
const options = { headers: { 'Authorization': `Bearer ${ScriptApp.getOAuthToken()}` } }
const blob = UrlFetchApp.fetch(pdfUrl, options).getAs('application/pdf')
DriveApp.createFile(blob).moveTo(resultFolder).setName(newTabName)
}
JavaScript
복사
createMonthlyInvoice_TabDrive함수
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoice_TabDrive() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
// 월정산서 탭 드라이브 저장
const tabId = newTab.getSheetId()
pdfSaveTab(templateCopyId, resultFolder, newTabName, tabId)
}
Logger.log(templateCopy.getUrl())
}
JavaScript
복사
월정산서 템플릿 탭 숨기거나 삭제하기
// 템플릿 탭 숨기기
templateCopy.getSheetByName('템플릿').hideSheet()
//템플릿 탭 삭제하기
templateCopy.deleteSheet(templateCopy.getSheetByName('템플릿'))
JavaScript
복사
createMonthlyInvoice_WholeDrive에 템플릿 숨기기 적용
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoice_WholeDrive() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
}
Logger.log(templateCopy.getUrl())
templateCopy.getSheetByName('템플릿').hideSheet()
pdfSaveWhole(templateCopyId, resultFolder, templateCopyName)
}
JavaScript
복사
익숙해지기
// 1) 숫자의 올림 값을 반환하는 메서드는 무엇일까요?
const number = 1.5
const roundup = Math.ceil(number)
JavaScript
복사
// 2) www.google.com 의 페이지 소스를 가져오는 코드를 완성해보세요.
UrlFetchApp.fetch('www.google.com')
JavaScript
복사
// 3) 구글 시트를 PDF로 변환하기 위해서는 권한 정보를 전달해야 합니다. 권한 정보를 담은 매개변수를 options로 선언할 때, 다음의 코드에서 틀린 부분을 두 군데를 찾아보세요.
const options = { head: { 'Authorization': `Bearer${ScriptApp.getOAuthToken()}` } }
// 1. head => headers
// 2. Bearer 뒤에 스페이스바 추가 필요
JavaScript
복사
7장 실전! 월정산서 PDF를 거래처 이메일로 전송하기
7장 그림 보기
이메일 전송가능 횟수 조회하기
function getRemainingEmailQuota(){
Logger.log(MailApp.getRemainingDailyQuota())
}
JavaScript
복사
[예제 07-01] sendEmail을 사용해 이메일 전송 테스트
function testEmail() {
MailApp.sendEmail('수신자이메일', '회신용이메일', '이메일 테스트', '안녕하세요?');
}
JavaScript
복사
[예제 07-02] 매개변수 객체를 사용하여 이메일 전송하기 (body)
function sendEmailBody() {
const attachBlob1 = DriveApp.getFileById('파일ID').getAs('application/pdf')
const attachBlob2 = DriveApp.getFileById('파일ID').getAs('application/pdf')
const attachBlob = [attachBlob1, attachBlob2]
const message = {
to: '수신자이메일',
replyTo: '회신용이메일',
name: '발신자명',
cc: 'CC용이메일1, CC용이메일2',
bcc: 'BCC용이메일',
subject: '테스트 이메일',
body: `
안녕하세요? 오토오피스입니다.
이메일 발송을 테스트합니다.
감사합니다.`,
attachments: attachBlob
}
MailApp.sendEmail(message)
Logger.log(`이메일이 전송되었습니다. 남은 이메일 발송 가능 수는 ${MailApp.getRemainingDailyQuota()}입니다.`)
}
JavaScript
복사
[예제 07-03] 매개변수 객체를 사용하여 이메일 전송하기 (htmlBody)
function sendEmailHtmlBody() {
const attachBlob1 = DriveApp.getFileById('파일ID').getAs('application/pdf')
const attachBlob2 = DriveApp.getFileById('파일ID').getAs('application/pdf')
const attachBlob = [attachBlob1, attachBlob2]
const autoofficeLogoBlob = UrlFetchApp.fetch('이미지URL').getBlob()
const davidBlob = UrlFetchApp.fetch('이미지URL').getBlob()
const message = {
to: '수신자이메일',
replyTo: '회신용이메일',
name: '오토오피스',
cc: 'CC용이메일1, CC용이메일2',
bcc: 'BCC용이메일',
subject: '테스트 이메일',
htmlBody: `
<img src='cid:autoofficeLogo' height='20'>
<h1>안녕하세요?</h1>
<b>오토오피스입니다.</b><br>
<span style='color:red'>이메일을 테스트합니다.</span><br>
감사합니다.<br>
<img src='cid:davidPhoto' height='50'>
`,
inlineImages: {
autoofficeLogo: autoofficeLogoBlob,
davidPhoto: davidBlob
},
attachments: attachBlob
}
MailApp.sendEmail(message)
Logger.log(`이메일이 전송되었습니다. 남은 이메일 발송 가능 수는 ${MailApp.getRemainingDailyQuota()}입니다.`)
}
JavaScript
복사
[예제 07-04] 매개변수 객체를 사용하여 이메일 전송하기 (htmlBody)
function sendEmailHtmlDriveImg() {
const attachBlob1 = DriveApp.getFileById('파일ID').getAs('application/pdf')
const attachBlob2 = DriveApp.getFileById('파일ID').getAs('application/pdf')
const attachBlob = [attachBlob1, attachBlob2]
const message = {
to: '수신자이메일',
replyTo: '회신용이메일',
name: '오토오피스',
cc: 'CC용이메일1, CC용이메일2',
bcc: 'BCC용이메일',
subject: '테스트 이메일',
htmlBody: `
<img src='https://drive.google.com/uc?id=1qQUTdgG0e2gD8hkGU72w-tH96MDj-DKt' height='20'>
<h1>안녕하세요?</h1>
<b>오토오피스입니다.</b><br>
<span style='color:red'>이메일을 테스트합니다.</span><br>
감사합니다.<br>
<img src='https://drive.google.com/uc?id=1HfUTUXuGjJYSSMlHNM6WO8XO26bXB-LC' height='50'>
`,
attachments: attachBlob
}
MailApp.sendEmail(message)
Logger.log(`이메일이 전송되었습니다. 남은 이메일 발송 가능 수는 ${MailApp.getRemainingDailyQuota()}입니다.`)
}
JavaScript
복사
[예제 07-05] 디자인된 HTML 템플릿 (htmlBodyInline.html)
<!DOCTYPE html>
<html>
<head></head>
<body>
<table style="width: 800px; background-color: gainsboro; margin-left: auto; margin-right: auto;">
<tr>
<td>
<table
style="width: 600px; background-color: white; margin-left: auto; margin-right: auto; margin-top: 60px; margin-bottom: 60px; border-collapse: collapse;">
<tr bgColor="gainsboro" border="none">
<td>
<img src="https://autooffice.co.kr/img/autooffice-logo.png" style="margin-top: 30px; margin-bottom: 30px; height: 30px;">
</td>
<td>
<div style="margin-top: 30px; margin-bottom: 30px; height: 30px; text-align:right; font-size: 14px;">
<!-- 치환코드 위치: 월 -->
</div>
</td>
</tr>
<tr>
<td colspan=2>
<img src="https://autooffice.co.kr/img/autooffice-work.png" style="width: 600px;">
</td>
</tr>
<tr>
<td colspan=2>
<div style="font-size: 30px; font-weight: normal; text-align: center; margin-top: 20px; margin-bottom: 20px;">월정산서가 도착했습니다.</div>
</td>
</tr>
<tr>
<td colspan=2>
<div style="font-size: 18px; font-weight: normal; text-align: center; color: darkslategray;">
<b><!-- 치환코드 위치: 거래처명 --></b>의
<b><!-- 치환코드 위치: 담당자명 --></b> 점주님,<br>
<b><!-- 치환코드 위치: 정산시작일 --></b>부터
<b><!-- 치환코드 위치: 정산종료일 --></b>까지의 월정산서를 보내드립니다.<br>
아래의 버튼을 클릭해서 다운로드하실 수 있습니다. <br>
</div>
<div style="font-size: 18px; font-weight: normal; text-align: center; margin-top: 30px; margin-bottom: 30px;">
<a href="<!-- 치환코드 위치: 파일URL -->" target="_blank">
<span style=" display:inline-block; background-color: deeppink; color: white; padding: 10px">월정산서 다운로드</span>
</a>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
JavaScript
복사
[예제 07-06] 디자인된 HTML 템플릿에 변수를 치환
<!DOCTYPE html>
<html>
<head></head>
<body>
<table style="width: 800px; background-color: gainsboro; margin-left: auto; margin-right: auto;">
<tr>
<td>
<table
style="width: 600px; background-color: white; margin-left: auto; margin-right: auto; margin-top: 60px; margin-bottom: 60px; border-collapse: collapse;">
<tr bgColor="gainsboro" border="none">
<td>
<img src="https://autooffice.co.kr/img/autooffice-logo.png" style="margin-top: 30px; margin-bottom: 30px; height: 30px;">
</td>
<td>
<div style="margin-top: 30px; margin-bottom: 30px; height: 30px; text-align:right; font-size: 14px;">
<?!= content.invoiceMonth ?>
</div>
</td>
</tr>
<tr>
<td colspan=2>
<img src="https://autooffice.co.kr/img/autooffice-work.png" style="width: 600px;">
</td>
</tr>
<tr>
<td colspan=2>
<div style="font-size: 30px; font-weight: normal; text-align: center; margin-top: 20px; margin-bottom: 20px;">월정산서가 도착했습니다.</div>
</td>
</tr>
<tr>
<td colspan=2>
<div style="font-size: 18px; font-weight: normal; text-align: center; color: darkslategray;">
<b><?!= content.customerName ?></b>의
<b><?!= content.ceoName ?></b> 점주님,<br>
<b><?!= content.startDateForName ?></b>부터
<b><?!= content.endDateForName ?></b>까지의 월정산서를 보내드립니다.<br>
아래의 버튼을 클릭해서 다운로드하실 수 있습니다. <br>
</div>
<div style="font-size: 18px; font-weight: normal; text-align: center; margin-top: 30px; margin-bottom: 30px;">
<a href="<?!= content.shareUrl ?>" target="_blank">
<span style=" display:inline-block; background-color: deeppink; color: white; padding: 10px">월정산서 다운로드</span>
</a>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
JavaScript
복사
[예제 07-07] HTML 파일에 변수를 치환해서 최종 HTML 페이지를 생성하는 함수
function evalEmailTemplate(templateName, content) {
const template = HtmlService.createTemplateFromFile(templateName)
template.content = content
const htmlBody = template.evaluate().getContent()
return htmlBody
}
JavaScript
복사
[예제 07-08] 디자인된 이메일 전송하기 최종 코드
function sendEmailHtmlBodyFileShare() {
const shareFile = DriveApp.getFileById('파일ID')
shareFile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW)
const shareUrl = shareFile.getUrl()
const content = {
customerName: '거래처793',
ceoName: '김석창',
startDateForName: '2023-06-01',
endDateForName: '2023-06-30',
shareUrl: shareUrl,
invoiceMonth: '2023년 6월'
}
const htmlBodyTemplate = evalEmailTemplate('htmlBodyInline', content)
const message = {
to: 'autooffice@naver.com',
name: '오토오피스',
subject: '오토오피스 월정산서',
htmlBody: htmlBodyTemplate
}
MailApp.sendEmail(message)
Logger.log(`이메일이 전송되었습니다. 남은 이메일 발송 가능 수는 ${MailApp.getRemainingDailyQuota()}입니다.`)
}
JavaScript
복사
[예제 07-09] 거래처별 월정산서를 구글 드라이브에 저장하는 함수
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoice_TabDrive() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
// 월정산서 탭 드라이브 저장
const tabId = newTab.getSheetId()
pdfSaveTab(templateCopyId, resultFolder, newTabName, tabId)
}
Logger.log(templateCopy.getUrl())
}
JavaScript
복사
[예제 07-10] 월정산 탭을 PDF로 변환해서 드라이브에 저장하고 파일 ID를 반환하는 함수
function pdfSaveTabReturnFileID(templateCopyId, resultFolder, newTabName, tabId) {
const pdfUrl = `https://docs.google.com/spreadsheets/d/${templateCopyId}/export?format=pdf&size=A4&gid=${tabId}`
const options = { headers: { 'Authorization': `Bearer ${ScriptApp.getOAuthToken()}` } }
const blob = UrlFetchApp.fetch(pdfUrl, options).getAs('application/pdf')
const fileId = DriveApp.createFile(blob).moveTo(resultFolder).setName(newTabName).getId()
return fileId
}
JavaScript
복사
[예제 07-11] 날짜에서 연도와 월 추출하기
function getDate() {
const startDate = new Date('2023-06-01 00:00:00')
const year = startDate.getFullYear()
const month = startDate.getMonth()
Logger.log(year)
Logger.log(month)
}
JavaScript
복사
[예제 07-12] startDate의 다음달로 정산월 값 생성하기
function getInvoiceMonth() {
const startDate = new Date('2023-06-01 00:00:00')
const year = startDate.getFullYear()
const month = startDate.getMonth()
const invoiceMonthDate = new Date(year, month + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
Logger.log(invoiceMonthDate)
Logger.log(invoiceMonth)
}
JavaScript
복사
[예제 07-13] 매개변수를 받을 수 있도록 수정한 이메일 전송 함수
function sendEmailParam(fileId, customer, startDateForName, endDateForName, invoiceMonth) {
const shareFile = DriveApp.getFileById(fileId)
shareFile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW)
const shareUrl = shareFile.getUrl()
const content = {
customerName: customer.customerName,
ceoName: customer.ceoName,
startDateForName: startDateForName,
endDateForName: endDateForName,
shareUrl: shareUrl,
invoiceMonth: invoiceMonth
}
const htmlBodyTemplate = evalEmailTemplate('htmlBodyInline', content)
const message = {
to: customer.email,
name: '오토오피스',
subject: '오토오피스 월정산서',
htmlBody: htmlBodyTemplate
}
MailApp.sendEmail(message)
Logger.log(`이메일이 전송되었습니다. 남은 이메일 발송 가능 수는 ${MailApp.getRemainingDailyQuota()}입니다.`)
}
JavaScript
복사
[예제 07-14] 거래처별 월정산서를 구글 드라이브에 저장하고 이메일로 전송하는 함수
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoiceAndSendEmail() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const invoiceMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
// 월정산서 탭 드라이브 저장
const tabId = newTab.getSheetId()
const fileId = pdfSaveTabReturnFileID(templateCopyId, resultFolder, newTabName, tabId)
// 월정산서 PDF 이메일 발송
sendEmailParam(fileId, customer, startDateForName, endDateForName, invoiceMonth)
}
Logger.log(templateCopy.getUrl())
}
JavaScript
복사
[예제 07-15] try…catch 로 알아보는 오류 예시
function tryTest() {
const arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
try {
for (i = 0; i < 3; i++) {
Logger.log(`i는 ${i}입니다.`)
arr.pop()
Logger.log(`arr는 ${arr}`)
Logger.log(`arr[0]은 ${arr[0]}`)
Logger.log(`arr[0] === undefined 입니까? ${arr[0] === undefined}`)
Logger.log(`arr[0] === null 입니까? ${arr[0] === null}`)
Logger.log(`arr[0].length는 ${arr[0].length}`)
}
} catch (e) {
Logger.log(`오류가 발생했습니다: ${e}`)
}
}
JavaScript
복사
null과 undefined의 실행 로그
function nullAndUndefined(){
let a = null
let b
Logger.log(a)
Logger.log(b)
Logger.log(a === undefined)
Logger.log(b === undefined)
Logger.log(typeof a)
Logger.log(typeof b)
}
JavaScript
복사
[예제 07-16] try…catch를 적용한 거래처별 월정산서 이메일 전송 함수
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoiceAndSendEmail() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = new Date('2023-06-01 00:00:00')
const endDate = new Date('2023-06-30 23:59:59')
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const invoiceMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
try {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
// 월정산서 탭 드라이브 저장
const tabId = newTab.getSheetId()
const fileId = pdfSaveTabReturnFileID(templateCopyId, resultFolder, newTabName, tabId)
// 월정산서 PDF 이메일 발송
sendEmailParam(fileId, customer, startDateForName, endDateForName, invoiceMonth)
} catch (e) {
Logger.log(`오류가 발생했습니다: ${e}`)
}
}
Logger.log(templateCopy.getUrl())
}
JavaScript
복사
익숙해지기
// 1) 발송가능한 이메일 잔여 수량을 확인하는 방법은 무엇일까요?
MailApp.getRemainingDailyQuota()
JavaScript
복사
// 2) 파일을 두 개 첨부하기 위해서 attachBlob에 어떻게 할당해야 할까요?
function testEmail() {
const attachBlob1 = DriveApp.getFileById('파일ID').getAs('application/pdf')
const attachBlob2 = DriveApp.getFileById('파일ID').getAs('application/pdf')
const attachBlob = [attachBlob1, attachBlob2]
const message = {
to: 'autooffice@naver.com',
subject: '테스트 이메일',
attachments: attachBlob
}
MailApp.sendEmail(message)
}
JavaScript
복사
// 3) 오류가 발생했을 때 예외 처리를 하면서 오류 내용을 실행 로그에 표시하는 코드를 작성해보세요.
try {
// 실행할 코드
} catch (e) {
Logger.log(`오류가 발생했습니다: ${e}`)
}
JavaScript
복사
8장 실전! 월정산 시작일과 종료일 설정하기
8장 그림 보기
세팅 탭에서 날짜를 불러오도록 코드를 추가
const T_SETTING = SS.getSheetByName('세팅')
const startDate = T_SETTING.getRange('A2').getValue()
const endDate = T_SETTING.getRange('B2').getValue()
JavaScript
복사
종료일자에 23:59:59 추가하기
const endDate = T_SETTING.getRange('B2').getValue()
const endDateFormat = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd 23:59:59')
const endDateNew = new Date(endDateFormat)
// 1줄로 쓰기
const endDate = new Date(Utilities.formatDate(T_SETTING.getRange('B2').getValue(), 'GMT+9', 'yyyy-MM-dd 23:59:59'))
JavaScript
복사
세팅 탭에서 날짜를 불러오는 createMonthlyInvoiceAndSendEmail 함수
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoiceAndSendEmail() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const T_SETTING = SS.getSheetByName('세팅')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = T_SETTING.getRange('A2').getValue()
const endDate = new Date(Utilities.formatDate(T_SETTING.getRange('B2').getValue(), 'GMT+9', 'yyyy-MM-dd 23:59:59'))
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const invoiceMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
try {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
// 월정산서 탭 드라이브 저장
const tabId = newTab.getSheetId()
const fileId = pdfSaveTabReturnFileID(templateCopyId, resultFolder, newTabName, tabId)
// 월정산서 PDF 이메일 발송
sendEmailParam(fileId, customer, startDateForName, endDateForName, invoiceMonth)
} catch (e) {
Logger.log(`오류가 발생했습니다: ${e}`)
}
}
Logger.log(templateCopy.getUrl())
}
JavaScript
복사
[예제 08-01] 프롬프트 테스트 함수
function promptTest() {
const ui = SpreadsheetApp.getUi()
const response = ui.prompt('아무거나 입력해보세요')
Logger.log(response.getResponseText())
}
JavaScript
복사
parseInt를 사용해 문자열을 정수로 변환하고 계산을 수행
function promptTestAddNum() {
const ui = SpreadsheetApp.getUi()
const response = ui.prompt('아무거나 입력해보세요')
Logger.log(response.getResponseText())
const addNumber = parseInt(response.getResponseText()) + 100
Logger.log(addNumber)
}
JavaScript
복사
[예제 08-02] 프롬프트 응답을 날짜로 변환하기
function getPromptAsDate() {
const ui = SpreadsheetApp.getUi()
const response = ui.prompt('날짜를 입력해보세요. yyyy-MM-dd의 형식을 지켜주세요.')
const resText = response.getResponseText()
Logger.log(resText)
const date = new Date(`${resText} 00:00:00`)
Logger.log(date)
}
JavaScript
복사
[예제 08-03] 프롬프트 창 두 번 표시해서 시작일과 종료일 입력받기
function getPromptDates() {
const ui = SpreadsheetApp.getUi()
const responseStart = ui.prompt('정산 시작일자를 입력하세요')
const resStartText = responseStart.getResponseText()
Logger.log(resStartText)
const startDate = new Date(`${resStartText} 00:00:00`) // 시작일자에 자정을 설정
Logger.log(startDate)
const responseEnd = ui.prompt('정산 종료일자를 입력하세요')
const resEndText = responseEnd.getResponseText()
Logger.log(resEndText)
const endDate = new Date(`${resEndText} 23:59:59`) // 종료일자에 23:59:59를 설정
Logger.log(endDate)
}
JavaScript
복사
[예제 08-04] 정규 표현식으로 가장 먼저 나오는 숫자 1개 추출하기
function regexTest() {
const date = '2023-06-01'
const regex = new RegExp(/\d/)
const dateRegex = regex.exec(date)
Logger.log(dateRegex)
}
JavaScript
복사
정규표현식으로 숫자 4개 추출하기
function regexTest() {
const date = '2023-06-01'
const regex = new RegExp(/\d{4}/)
const dateRegex = regex.exec(date)
Logger.log(dateRegex)
}
JavaScript
복사
정규표현식으로 yyyy-MM-dd 추출하기
function regexTest() {
const date = '2023-06-31'
const regex = new RegExp(/\d{4}-\d{2}-\d{2}/)
const dateRegex = regex.exec(date)
Logger.log(dateRegex)
}
JavaScript
복사
정규표현식으로 yyyy-MM-dd 추출하기 (시작과 종료 제한)
function regexTest() {
const date = '2023-06-31'
const regex = new RegExp(/^\d{4}-\d{2}-\d{2}$/)
const dateRegex = regex.exec(date)
Logger.log(dateRegex)
}
JavaScript
복사
[예제 08-05] 정규표현식으로 정산 시작일자 검증하기
function getPromptDateRegex() {
const ui = SpreadsheetApp.getUi()
const regex = new RegExp(/^\d{4}-\d{2}-\d{2}$/)
const response = ui.prompt('정산 시작일자를 입력하세요')
const resText = response.getResponseText()
Logger.log(resText)
const resTextRegex = regex.exec(resText)
Logger.log(resTextRegex)
const date = new Date(`${resTextRegex[0]} 00:00:00`)
Logger.log(date)
}
JavaScript
복사
[예제 08-06] while문으로 올바른 날짜를 입력받을 때까지 프롬프트 표시하기
function getPromptDateRegex() {
const ui = SpreadsheetApp.getUi()
const regex = new RegExp(/^\d{4}-\d{2}-\d{2}$/)
// while문의 초기값
let resTextRegex = null
Logger.log(`resTextRegex의 초기값은 ${resTextRegex}`)
// 정규 표현식에 해당하는 값이 입력되지 않으면 while문을 계속 실행
while (resTextRegex == null) {
const response = ui.prompt('정산 시작일자를 입력하세요')
const resText = response.getResponseText()
resTextRegex = regex.exec(resText)
Logger.log(resText)
Logger.log(`정규표현식을 적용한 resTextRegex는 ${resTextRegex}`)
Logger.log(`resTextRegex == null? ${resTextRegex == null}`)
}
// 정규 표현식에 해당하는 값이 입력되면 while문을 종료하고 날짜로 변환
const date = new Date(`${resTextRegex[0]} 00:00:00`)
Logger.log(date)
}
JavaScript
복사
[예제 08-07] 공백 또는 0을 입력하면 프롬프트 종료하기 추가한 함수
function getPromptDateRegex() {
const ui = SpreadsheetApp.getUi()
const regex = new RegExp(/^\d{4}-\d{2}-\d{2}$/)
// while문의 초기값
let resTextRegex = null
let resText
Logger.log(`resTextRegex의 초기값은 ${resTextRegex}`)
// 정규 표현식에 해당하는 값이 입력되지 않으면 while문을 계속 실행
while (resTextRegex == null && resText != 0) {
const response = ui.prompt('정산 시작일자를 입력하세요')
resText = response.getResponseText()
resTextRegex = regex.exec(resText)
Logger.log(resText)
Logger.log(`정규표현식을 적용한 resTextRegex는는 ${resTextRegex}`)
Logger.log(`resTextRegex == null? ${resTextRegex == null}`)
Logger.log(`resText != 0? ${resText != 0}`)
}
// 올바른 날짜가 입력된 경우에만 startDate에 값을 할당
let date
if (resTextRegex != null) {
date = new Date(`${resTextRegex[0]} 00:00:00`)
}
Logger.log(date)
}
JavaScript
복사
[예제 08-08] 매개변수를 입력받는 프롬프트 함수
function getPromptDateRegex(promptTitle = '정산 시작일자를 입력하세요', startDatebool = true) {
const ui = SpreadsheetApp.getUi()
const regex = new RegExp(/^\d{4}-\d{2}-\d{2}$/)
// while문의 초기값
let resTextRegex = null
let resText
Logger.log(`resTextRegex의 초기값은 ${resTextRegex}`)
// 정규 표현식에 해당하는 값이 입력되지 않으면 while문을 계속 실행
while (resTextRegex == null && resText != 0) {
const response = ui.prompt(promptTitle)
resText = response.getResponseText()
resTextRegex = regex.exec(resText)
Logger.log(resText)
Logger.log(`정규표현식을 적용한 resTextRegex는는 ${resTextRegex}`)
Logger.log(`resTextRegex == null? ${resTextRegex == null}`)
Logger.log(`resText != 0? ${resText != 0}`)
}
// 올바른 날짜가 입력된 경우에만 date에 값을 할당
let date
if (resTextRegex != null) {
time = startDatebool == true ? '00:00:00' : '23:59:59'
date = new Date(`${resTextRegex[0]} ${time}`)
}
Logger.log(date)
return date
}
JavaScript
복사
[예제 08-09] 오류 발생시 프로세스를 중단시키는 프롬프트 함수
function getPromptDateRegex(promptTitle = '정산 시작일자를 입력하세요', startDateBool = true) {
const ui = SpreadsheetApp.getUi()
const regex = new RegExp(/^\d{4}-\d{2}-\d{2}$/)
// while문의 초기값
let resTextRegex = null
let resText
Logger.log(`resTextRegex의 초기값은 ${resTextRegex}`)
// 정규 표현식에 해당하는 값이 입력되지 않으면 while문을 계속 실행
while (resTextRegex == null && resText != 0) {
const response = ui.prompt(promptTitle)
resText = response.getResponseText()
resTextRegex = regex.exec(resText)
Logger.log(resText)
Logger.log(`정규표현식을 적용한 resTextRegex는 ${resTextRegex}`)
Logger.log(`resTextRegex == null? ${resTextRegex == null}`)
Logger.log(`resText != 0? ${resText != 0}`)
}
// 올바른 날짜가 입력된 경우에만 date에 값을 할당
let date
if (resTextRegex != null) {
const time = startDateBool == true ? '00:00:00' : '23:59:59'
date = new Date(`${resTextRegex[0]} ${time}`)
} else {
throw new Error('올바른 날짜 값이 입력되지 않아서 종료합니다.')
}
Logger.log(date)
return date
}
JavaScript
복사
프롬프트 입력을 받는 createMonthlyInvoiceAndSendEmailPrompt 함수
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoiceAndSendEmailPrompt() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const startDate = getPromptDateRegex(promptTitle = '정산 시작일자를 입력하세요', startDateBool = true)
const endDate = getPromptDateRegex(promptTitle = '정산 종료일자를 입력하세요', startDateBool = false)
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const invoiceMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
try {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
// 월정산서 탭 드라이브 저장
const tabId = newTab.getSheetId()
const fileId = pdfSaveTabReturnFileID(templateCopyId, resultFolder, newTabName, tabId)
// 월정산서 PDF 이메일 발송
sendEmailParam(fileId, customer, startDateForName, endDateForName, invoiceMonth)
} catch (e) {
Logger.log(`오류가 발생했습니다: ${e}`)
}
}
Logger.log(templateCopy.getUrl())
}
JavaScript
복사
[예제 08-10] 확인 버튼만 있는 알림 메시지 표시하기
function alert() {
const ui = SpreadsheetApp.getUi()
ui.alert('알림 메시지입니다.')
}
JavaScript
복사
알림을 추가한 프롬프트 함수
function getPromptDateRegex(promptTitle = '정산 시작일자를 입력하세요', startDateBool = true) {
const ui = SpreadsheetApp.getUi()
const regex = new RegExp(/^\d{4}-\d{2}-\d{2}$/)
// while문의 초기값
let resTextRegex = null
let resText
Logger.log(`resTextRegex의 초기값은 ${resTextRegex}`)
ui.alert('날짜는 yyyy-MM-dd 서식으로 입력하셔야 합니다.')
// 정규 표현식에 해당하는 값이 입력되지 않으면 while문을 계속 실행
while (resTextRegex == null && resText != 0) {
const response = ui.prompt(promptTitle)
resText = response.getResponseText()
resTextRegex = regex.exec(resText)
Logger.log(resText)
Logger.log(`정규표현식을 적용한 resTextRegex는 ${resTextRegex}`)
Logger.log(`resTextRegex == null? ${resTextRegex == null}`)
Logger.log(`resText != 0? ${resText != 0}`)
}
// 올바른 날짜가 입력된 경우에만 date에 값을 할당
let date
if (resTextRegex != null) {
const time = startDateBool == true ? '00:00:00' : '23:59:59'
date = new Date(`${resTextRegex[0]} ${time}`)
} else {
ui.alert('공백 또는 0이 입력되어서 종료합니다.')
throw new Error('올바른 날짜 값이 입력되지 않아서 종료합니다.')
}
Logger.log(date)
return date
}
JavaScript
복사
[예제 08-11] 확인, 취소가 선택가능한 알림메시지 표시하기
function alertSelect() {
const ui = SpreadsheetApp.getUi()
const response = ui.alert('프로세스를 진행할까요?', ui.ButtonSet.OK_CANCEL)
Logger.log(response)
if(response == ui.Button.OK){
Logger.log('확인을 클릭하셨습니다.')
}else{
Logger.log('취소를 클릭하셨습니다.')
}
}
JavaScript
복사
[예제 08-12] 확인, 취소가 선택가능한 프롬프트 표시하기
function promptSelect(){
const ui = SpreadsheetApp.getUi()
const response = ui.prompt('알림','날짜를 입력해주세요', ui.ButtonSet.OK_CANCEL)
Logger.log(response.getResponseText())
Logger.log(response.getSelectedButton())
if(response.getSelectedButton() == 'OK'){
Logger.log(`응답: ${response.getResponseText()}`)
Logger.log('확인을 클릭하셨습니다.')
}else{
Logger.log(`응답: ${response.getResponseText()}`)
Logger.log('취소를 클릭하셨습니다.')
}
}
JavaScript
복사
[예제 08-13] 토스트 메시지
function toast() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
SS.toast('토스트 메시지입니다.')
}
JavaScript
복사
익숙해지기
// 1) 프롬프트의 응답을 로그에 표시하려면 어떻게 해야 할까요?
function promptTest() {
const ui = SpreadsheetApp.getUi()
const response = ui.prompt('아무거나 입력해보세요')
Logger.log(response.getResponseText())
}
JavaScript
복사
// 2) yyyy-MM-dd 형식의 값을 추출하는 정규 표현식을 작성해보세요.
const regex = new RegExp(/^\d{4}-\d{2}-\d{2}$/)
JavaScript
복사
// 3) 확인, 취소버튼이 있는 알림 메시지를 띄우려면 어떻게 해야 할까요?
function alertSelect() {
const ui = SpreadsheetApp.getUi()
const response = ui.alert('프로세스를 진행할까요?', ui.ButtonSet.OK_CANCEL)
Logger.log(response)
if(response == ui.Button.OK){
Logger.log('확인을 클릭하셨습니다.')
}else{
Logger.log('취소를 클릭하셨습니다.')
}
}
JavaScript
복사
9장 트리거 사용하기
9장 그림 보기
[예제 09-01] onOpen(e)를 사용한 메뉴 추가
function onOpen(e) {
SpreadsheetApp.getUi()
.createMenu('자동화 함수')
.addItem('월정산서 이메일 발송', 'createMonthlyInvoiceAndSendEmailPrompt')
.addSeparator()
.addSubMenu(SpreadsheetApp.getUi().createMenu('서브 메뉴')
.addItem('서브메뉴 1', '서브 함수 1')
.addItem('서브메뉴 2', '서브 함수 2'))
.addToUi()
}
JavaScript
복사
[예제 09-02] onEdit(e)의 매개변수 e 파악하기
function onEdit(e){
Logger.log(e)
Logger.log(`e.source는 ${e.source}`)
Logger.log(`e.source의 이름은 ${e.source.getName()}`)
Logger.log(`e.range는 ${e.range}`)
Logger.log(`e.range의 A1노테이션은 ${e.range.getA1Notation()}`)
Logger.log(`e.oldValue는 ${e.oldValue}`)
Logger.log(`e.value는 ${e.value}`)
Logger.log(`e.user는 ${e.user}`)
}
JavaScript
복사
[예제 09-03] onEdit(e)로 거래처 체크박스 토글하기
function onEdit(e) {
const SS = e.source
const T_ACTIVE = SS.getActiveSheet()
const T_ACTIVE_NAME = T_ACTIVE.getName()
const editCell = e.range.getA1Notation()
const editCellValue = e.value
const T_ACTIVE_LASTROW = getLastRowOfCol(T_ACTIVE, 'A')
const checkArr = new Array(T_ACTIVE_LASTROW - 1)
Logger.log(T_ACTIVE_NAME)
Logger.log(editCell)
Logger.log(editCellValue)
if (T_ACTIVE_NAME == '거래처' && editCell == 'H1' && editCellValue == 'TRUE') {
checkArr.fill([true])
T_ACTIVE.getRange(`H2:H${T_ACTIVE_LASTROW}`).setValues(checkArr)
} else if (T_ACTIVE_NAME == '거래처' && editCell == 'H1' && editCellValue == 'FALSE') {
checkArr.fill([false])
T_ACTIVE.getRange(`H2:H${T_ACTIVE_LASTROW}`).setValues(checkArr)
} else {
Logger.log('거래처의 H1셀이 변경되지 않았습니다.')
}
}
JavaScript
복사
지난달 월정산서 이메일로 보내기 함수 (트리거)
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoiceAndSendEmailTrigger() {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().filter(row => row[7] == true)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const today = new Date()
const startDate = new Date(today.getFullYear(), today.getMonth() - 1, 1, 00, 00, 00)
const endDate = new Date(today.getFullYear(), today.getMonth(), 0, 23, 59, 59)
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const invoiceMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
try {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
// 월정산서 탭 드라이브 저장
const tabId = newTab.getSheetId()
const fileId = pdfSaveTabReturnFileID(templateCopyId, resultFolder, newTabName, tabId)
// 월정산서 PDF 이메일 발송
sendEmailParam(fileId, customer, startDateForName, endDateForName, invoiceMonth)
} catch (e) {
Logger.log(`오류가 발생했습니다: ${e}`)
}
}
Logger.log(templateCopy.getUrl())
}
JavaScript
복사
[예제 09-04] 매달 1일 01시 00분 부근에 함수를 실행하는 트리거 추가하기
function addTrigger() {
ScriptApp.newTrigger('createMonthlyInvoiceAndSendEmailTrigger')
.timeBased()
.onMonthDay(1)
.atHour(01)
.nearMinute(00)
.create()
}
JavaScript
복사
[예제 09-05] 트리거 정보 확인하기
function checkTriggers() {
const triggers = ScriptApp.getProjectTriggers()
Logger.log(triggers)
triggers.forEach(trigger => {
const triggerId = trigger.getUniqueId()
const triggerHF = trigger.getHandlerFunction()
const triggerET = trigger.getEventType()
const triggerSource = trigger.getTriggerSource()
const triggerSourceId = trigger.getTriggerSourceId()
Logger.log(triggerId)
Logger.log(triggerHF)
Logger.log(triggerET)
Logger.log(triggerSource)
Logger.log(triggerSourceId)
})
}
JavaScript
복사
[예제 09-06] 고유 식별자로 트리거 삭제하기
function deleteTrigger() {
const triggers = ScriptApp.getProjectTriggers()
triggers.forEach((trigger, index) => {
const triggerId = trigger.getUniqueId()
Logger.log([triggerId, index])
if (triggerId == '6886916666966533390') {
ScriptApp.deleteTrigger(triggers[index])
Logger.log('트리거가 삭제되었습니다.')
}
})
}
JavaScript
복사
[예제 09-07] 함수명 createMonthlyInvoiceAndSendEmailTrigger만 제외하고 모든 트리거 삭제하기
function deleteTriggerExcept() {
const triggers = ScriptApp.getProjectTriggers()
triggers.forEach((trigger, index) => {
const triggerId = trigger.getUniqueId()
const triggerHF = trigger.getHandlerFunction()
Logger.log([triggerId, index, triggerHF])
if (triggerHF != 'createMonthlyInvoiceAndSendEmailTrigger') {
ScriptApp.deleteTrigger(triggers[index])
Logger.log('트리거가 삭제되었습니다.')
}
})
}
JavaScript
복사
[예제 09-08] 거래처를 그룹으로 만들기
function createTriggers() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_CUSTOMER = SS.getSheetByName('거래처')
const customersSize = T_CUSTOMER.getDataRange().getValues().slice(1, 51).length
Logger.log(customersSize)
const groupSize = 15
const quotient = Math.floor(customersSize / groupSize)
const remainder = customersSize % groupSize
let customerGroups = []
for (i = 0; i < quotient; i++) {
const groupStartRow = groupSize * i
const groupEndRow = groupSize * (i + 1) - 1
const customerGroupIndexes = [groupStartRow, groupEndRow]
customerGroups.push(customerGroupIndexes)
}
if (remainder != 0) {
const customerGroupIndexesLast = [groupSize * i, groupSize * i + remainder - 1]
customerGroups.push(customerGroupIndexesLast)
}
Logger.log(customerGroups)
}
JavaScript
복사
일정 그룹 만들기
let scheduleGroups = []
for (j = 0; j < customerGroups.length; j++) {
const schedule = 360000 * j + 1000
scheduleGroups.push(schedule)
}
JavaScript
복사
그룹별로 트리거 생성하기
for (k = 0; k < customerGroups.length; k++) {
const trigger = ScriptApp.newTrigger('triggerHF')
.timeBased()
.after(scheduleGroups[k])
.create()
const triggerId = trigger.getUniqueId()
let groupInfo = {}
groupInfo.customerGroup = customerGroups[k]
const cache = CacheService.getDocumentCache()
cache.put(triggerId, JSON.stringify(groupInfo), 1800)
Logger.log(triggerId)
}
JavaScript
복사
[예제 09-09] createTriggers 함수
function createTriggers() {
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_CUSTOMER = SS.getSheetByName('거래처')
const customersSize = T_CUSTOMER.getDataRange().getValues().slice(1, 51).length
Logger.log(customersSize)
const groupSize = 15
const quotient = Math.floor(customersSize / groupSize)
const remainder = customersSize % groupSize
let customerGroups = []
for (i = 0; i < quotient; i++) {
const groupStartRow = groupSize * i
const groupEndRow = groupSize * (i + 1) - 1
const customerGroupIndexes = [groupStartRow, groupEndRow]
customerGroups.push(customerGroupIndexes)
}
if (remainder != 0) {
const customerGroupIndexesLast = [groupSize * i, groupSize * i + remainder - 1]
customerGroups.push(customerGroupIndexesLast)
}
Logger.log(customerGroups)
let scheduleGroups = []
for (j = 0; j < customerGroups.length; j++) {
const schedule = 1000
scheduleGroups.push(schedule)
}
Logger.log(scheduleGroups)
for (k = 0; k < customerGroups.length; k++) {
const trigger = ScriptApp.newTrigger('triggerHF')
.timeBased()
.after(scheduleGroups[k])
.create()
const triggerId = trigger.getUniqueId()
let groupInfo = {}
groupInfo[triggerId] = customerGroups[k]
const cache = CacheService.getDocumentCache()
cache.put(triggerId, JSON.stringify(groupInfo), 1800)
Logger.log(triggerId)
}
}
JavaScript
복사
[예제 09-10] triggerHF 함수
function triggerHF(e) {
Logger.log(e)
const triggerId = e.triggerUid
const cache = CacheService.getDocumentCache()
const groupInfo = JSON.parse(cache.get(triggerId))
Logger.log(groupInfo)
createMonthlyInvoiceGroup(groupInfo)
}
JavaScript
복사
[예제 09-11] createMonthlyInvoiceGroup 함수
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoiceGroup(groupInfo) {
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const resultFolderId = '폴더ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const groupStartRow = groupInfo.customerGroup[0]
const groupEndRow = groupInfo.customerGroup[1]
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().slice(1).slice(groupStartRow, groupEndRow + 1)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const today = new Date()
const startDate = new Date(today.getFullYear(), today.getMonth() - 1, 1, 00, 00, 00)
const endDate = new Date(today.getFullYear(), today.getMonth(), 0, 23, 59, 59)
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const invoiceMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
try {
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
// 월정산서 탭 드라이브 저장
const tabId = newTab.getSheetId()
const fileId = pdfSaveTabReturnFileID(templateCopyId, resultFolder, newTabName, tabId)
// 월정산서 PDF 이메일 발송
sendEmailParam(fileId, customer, startDateForName, endDateForName, invoiceMonth)
} catch (e) {
Logger.log(`오류가 발생했습니다: ${e}`)
}
}
Logger.log(templateCopy.getUrl())
}
JavaScript
복사
10장 스크립트 로그 기록하기
10장 그림 보기
[예제 10-01] 10자리의 영문과 숫자의 랜덤한 조합 생성하기
function getRandomId() {
const idLength = 10
const charPool = 'abcdefghijklmnopqrstuvwxyz0123456789'
let randomId = ''
for (let i = 0; i < idLength; i++) {
randomId += charPool.charAt(Math.floor(Math.random() * charPool.length))
}
return randomId
}
JavaScript
복사
[예제 10-02] 로그 배열 생성을 추가한 createTriggersWithLog 함수
function createTriggersWithLog() {
// 로그를 위한 변수 정의
const logId = getRandomId()
const scriptName = '월정산서 발송 스크립트'
const scriptStartTime = new Date()
const userEmail = Session.getActiveUser().getEmail()
const today = new Date('2023-07-01')
const startDate = new Date(today.getFullYear(), today.getMonth() - 1, 1, 00, 00, 00)
const endDate = new Date(today.getFullYear(), today.getMonth(), 0, 23, 59, 59)
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const invoiceMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
// 거래처 목록 정의
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_CUSTOMER = SS.getSheetByName('거래처')
const customersSize = T_CUSTOMER.getDataRange().getValues().slice(1, 11).length
Logger.log(customersSize)
// 거래처를 나눌 그룹 사이즈 정의
const groupSize = 3
const quotient = Math.floor(customersSize / groupSize)
const remainder = customersSize % groupSize
// 거래처 그룹의 시작과 종료 순번을 배열로 생성
let customerGroups = []
for (i = 0; i < quotient; i++) {
const groupStartRow = groupSize * i
const groupEndRow = groupSize * (i + 1) - 1
const customerGroupIndexes = [groupStartRow, groupEndRow]
customerGroups.push(customerGroupIndexes)
}
if (remainder != 0) {
const customerGroupIndexesLast = [groupSize * i, groupSize * i + remainder - 1]
customerGroups.push(customerGroupIndexesLast)
}
Logger.log(customerGroups)
// 거래처 그룹의 수만큼 트리거 예약 일정을 배열로 생성
let scheduleGroups = []
for (j = 0; j < customerGroups.length; j++) {
const schedule = 1000
scheduleGroups.push(schedule)
}
Logger.log(scheduleGroups)
// 거래처 그룹의 수만큼 트리거를 예약
for (k = 0; k < customerGroups.length; k++) {
const trigger = ScriptApp.newTrigger('triggerHF')
.timeBased()
.after(scheduleGroups[k])
.create()
const triggerId = trigger.getUniqueId()
let groupInfo = {}
groupInfo.customerGroup = customerGroups[k]
const cache = CacheService.getDocumentCache()
cache.put(triggerId, JSON.stringify(groupInfo), 1800)
Logger.log(triggerId)
}
// 로그를 위한 변수 정의
const scriptEndTime = new Date()
const scriptDuration = (scriptEndTime.getTime() - scriptStartTime.getTime()) / 1000
const triggerCounts = customerGroups.length
// 로그 배열 정의
const logArr = [logId, scriptName, scriptStartTime, scriptEndTime, scriptDuration, userEmail, invoiceMonth, startDateForName, endDateForName, customersSize, triggerCounts]
Logger.log(logArr)
}
JavaScript
복사
로그 배열을 appendRow로 입력하는 createTriggersWithLog 함수
function createTriggersWithLog() {
// 로그를 위한 변수 정의
const logId = getRandomId()
const scriptName = '월정산서 발송 스크립트'
const scriptStartTime = new Date()
const userEmail = Session.getActiveUser().getEmail()
const today = new Date('2023-07-01')
const startDate = new Date(today.getFullYear(), today.getMonth() - 1, 1, 00, 00, 00)
const endDate = new Date(today.getFullYear(), today.getMonth(), 0, 23, 59, 59)
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const invoiceMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
// 거래처 목록 정의
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_LOG = SS.getSheetByName('실행로그')
const T_CUSTOMER = SS.getSheetByName('거래처')
const customersSize = T_CUSTOMER.getDataRange().getValues().slice(1, 11).length
Logger.log(customersSize)
// 거래처를 나눌 그룹 사이즈 정의
const groupSize = 3
const quotient = Math.floor(customersSize / groupSize)
const remainder = customersSize % groupSize
// 거래처 그룹의 시작과 종료 순번을 배열로 생성
let customerGroups = []
for (i = 0; i < quotient; i++) {
const groupStartRow = groupSize * i
const groupEndRow = groupSize * (i + 1) - 1
const customerGroupIndexes = [groupStartRow, groupEndRow]
customerGroups.push(customerGroupIndexes)
}
if (remainder != 0) {
const customerGroupIndexesLast = [groupSize * i, groupSize * i + remainder - 1]
customerGroups.push(customerGroupIndexesLast)
}
Logger.log(customerGroups)
// 거래처 그룹의 수만큼 트리거 예약 일정을 배열로 생성
let scheduleGroups = []
for (j = 0; j < customerGroups.length; j++) {
const schedule = 1000
scheduleGroups.push(schedule)
}
Logger.log(scheduleGroups)
// 거래처 그룹의 수만큼 트리거를 예약
for (k = 0; k < customerGroups.length; k++) {
const trigger = ScriptApp.newTrigger('triggerHF')
.timeBased()
.after(scheduleGroups[k])
.create()
const triggerId = trigger.getUniqueId()
let groupInfo = {}
groupInfo.customerGroup = customerGroups[k]
const cache = CacheService.getDocumentCache()
cache.put(triggerId, JSON.stringify(groupInfo), 1800)
Logger.log(triggerId)
}
// 로그를 위한 변수 정의
const scriptEndTime = new Date()
const scriptDuration = (scriptEndTime.getTime() - scriptStartTime.getTime()) / 1000
const triggerCounts = customerGroups.length
// 로그 배열 정의
const logArr = [logId, scriptName, scriptStartTime, scriptEndTime, scriptDuration, userEmail, invoiceMonth, startDateForName, endDateForName, customersSize, triggerCounts]
Logger.log(logArr)
T_LOG.appendRow(logArr)
}
JavaScript
복사
[예제 10-03] getLastRowOfCol을 활용한 로그 기록 함수 writeLog
function writeLog(T_LOG, logArr) {
const lastRow = getLastRowOfCol(T_LOG, 'A')
T_LOG.getRange(lastRow + 1, 1, logArr.length, logArr[0].length).setValues(logArr)
}
JavaScript
복사
writeLog를 사용하는 createTriggersWithLog 함수
function createTriggersWithLog() {
// 로그를 위한 변수 정의
const logId = getRandomId()
const scriptName = '월정산서 발송 스크립트'
const scriptStartTime = new Date()
const userEmail = Session.getActiveUser().getEmail()
const today = new Date('2023-07-01')
const startDate = new Date(today.getFullYear(), today.getMonth() - 1, 1, 00, 00, 00)
const endDate = new Date(today.getFullYear(), today.getMonth(), 0, 23, 59, 59)
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const invoiceMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
// 거래처 목록 정의
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_LOG = SS.getSheetByName('실행로그')
const T_CUSTOMER = SS.getSheetByName('거래처')
const customersSize = T_CUSTOMER.getDataRange().getValues().slice(1, 11).length
Logger.log(customersSize)
// 거래처를 나눌 그룹 사이즈 정의
const groupSize = 3
const quotient = Math.floor(customersSize / groupSize)
const remainder = customersSize % groupSize
// 거래처 그룹의 시작과 종료 순번을 배열로 생성
let customerGroups = []
for (i = 0; i < quotient; i++) {
const groupStartRow = groupSize * i
const groupEndRow = groupSize * (i + 1) - 1
const customerGroupIndexes = [groupStartRow, groupEndRow]
customerGroups.push(customerGroupIndexes)
}
if (remainder != 0) {
const customerGroupIndexesLast = [groupSize * i, groupSize * i + remainder - 1]
customerGroups.push(customerGroupIndexesLast)
}
Logger.log(customerGroups)
// 거래처 그룹의 수만큼 트리거 예약 일정을 배열로 생성
let scheduleGroups = []
for (j = 0; j < customerGroups.length; j++) {
const schedule = 1000
scheduleGroups.push(schedule)
}
Logger.log(scheduleGroups)
// 거래처 그룹의 수만큼 트리거를 예약
for (k = 0; k < customerGroups.length; k++) {
const trigger = ScriptApp.newTrigger('triggerHF')
.timeBased()
.after(scheduleGroups[k])
.create()
const triggerId = trigger.getUniqueId()
let groupInfo = {}
groupInfo.customerGroup = customerGroups[k]
const cache = CacheService.getDocumentCache()
cache.put(triggerId, JSON.stringify(groupInfo), 1800)
Logger.log(triggerId)
}
// 로그를 위한 변수 정의
const scriptEndTime = new Date()
const scriptDuration = (scriptEndTime.getTime() - scriptStartTime.getTime()) / 1000
const triggerCounts = customerGroups.length
// 로그 배열 정의
const logArr = [[logId, scriptName, scriptStartTime, scriptEndTime, scriptDuration, userEmail, invoiceMonth, startDateForName, endDateForName, customersSize, triggerCounts]]
Logger.log(logArr)
writeLog(T_LOG, logArr)
}
JavaScript
복사
logArrDetail을 기록하기 위한 createTriggersWithLogDetail
function createTriggersWithLogDetail() {
// 로그를 위한 변수 정의
const logId = getRandomId()
const scriptName = '월정산서 발송 스크립트'
const scriptStartTime = new Date()
const userEmail = Session.getActiveUser().getEmail()
const today = new Date('2023-07-01')
const startDate = new Date(today.getFullYear(), today.getMonth() - 1, 1, 00, 00, 00)
const endDate = new Date(today.getFullYear(), today.getMonth(), 0, 23, 59, 59)
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const invoiceMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
// 거래처 목록 정의
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_LOG = SS.getSheetByName('실행로그')
const T_CUSTOMER = SS.getSheetByName('거래처')
const customersSize = T_CUSTOMER.getDataRange().getValues().slice(1, 11).length
Logger.log(customersSize)
// 거래처를 나눌 그룹 사이즈 정의
const groupSize = 3
const quotient = Math.floor(customersSize / groupSize)
const remainder = customersSize % groupSize
// 거래처 그룹의 시작과 종료 순번을 배열로 생성
let customerGroups = []
for (i = 0; i < quotient; i++) {
const groupStartRow = groupSize * i
const groupEndRow = groupSize * (i + 1) - 1
const customerGroupIndexes = [groupStartRow, groupEndRow]
customerGroups.push(customerGroupIndexes)
}
if (remainder != 0) {
const customerGroupIndexesLast = [groupSize * i, groupSize * i + remainder - 1]
customerGroups.push(customerGroupIndexesLast)
}
Logger.log(customerGroups)
// 거래처 그룹의 수만큼 트리거 예약 일정을 배열로 생성
let scheduleGroups = []
for (j = 0; j < customerGroups.length; j++) {
const schedule = 1000
scheduleGroups.push(schedule)
}
Logger.log(scheduleGroups)
// 거래처 그룹의 수만큼 트리거를 예약
for (k = 0; k < customerGroups.length; k++) {
const trigger = ScriptApp.newTrigger('triggerHF')
.timeBased()
.after(scheduleGroups[k])
.create()
const triggerId = trigger.getUniqueId()
let groupInfo = {}
groupInfo.customerGroup = customerGroups[k]
groupInfo.logId = logId
groupInfo.triggerId = triggerId
const cache = CacheService.getDocumentCache()
cache.put(triggerId, JSON.stringify(groupInfo), 1800)
Logger.log(triggerId)
}
// 로그를 위한 변수 정의
const scriptEndTime = new Date()
const scriptDuration = (scriptEndTime.getTime() - scriptStartTime.getTime()) / 1000
const triggerCounts = customerGroups.length
// 로그 배열 정의
const logArr = [[logId, scriptName, scriptStartTime, scriptEndTime, scriptDuration, userEmail, invoiceMonth, startDateForName, endDateForName, customersSize, triggerCounts]]
Logger.log(logArr)
writeLog(T_LOG, logArr)
}
JavaScript
복사
[예제 10-04] 상세로그를 기록하는 createMonthlyInvoiceGroupWithLog 함수
/* [거래처] 탭에 선택된 거래처의 월정산서를 생성하는 함수
최종 업데이트: YYYY년 MM월 DD일
작성자: 오토오피스
*/
function createMonthlyInvoiceGroupWithLog(groupInfo) {
// 로그를 위한 변수 정의
const logId = groupInfo.logId
const triggerId = groupInfo.triggerId
// 탭, 템플릿과 결과물 저장 폴더 변수 선언 및 할당
const SS = SpreadsheetApp.getActiveSpreadsheet()
const T_SALESDATA = SS.getSheetByName('판매데이터')
const T_CUSTOMER = SS.getSheetByName('거래처')
const T_LOGDETAIL = SS.getSheetByName('상세로그')
const resultFolderId = '폴더 ID'
const resultFolder = DriveApp.getFolderById(resultFolderId)
const templateFile = DriveApp.getFileById('파일 ID')
// 판매데이터, 대상 거래처 변수 선언 및 할당
const groupStartRow = groupInfo.customerGroup[0]
const groupEndRow = groupInfo.customerGroup[1]
const salesData = T_SALESDATA.getDataRange().getValues()
const customers = T_CUSTOMER.getDataRange().getValues().slice(1).slice(groupStartRow, groupEndRow + 1)
Logger.log(customers)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 시작
const today = new Date('2023-07-01')
const startDate = new Date(today.getFullYear(), today.getMonth() - 1, 1, 00, 00, 00)
const endDate = new Date(today.getFullYear(), today.getMonth(), 0, 23, 59, 59)
const startDateForName = Utilities.formatDate(startDate, 'GMT+9', 'yyyy-MM-dd')
const endDateForName = Utilities.formatDate(endDate, 'GMT+9', 'yyyy-MM-dd')
const invoiceMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1)
const invoiceMonth = Utilities.formatDate(invoiceMonthDate, 'GMT+9', 'yyyy년 MM월')
const templateCopyName = `월정산서_${startDateForName}_${endDateForName}`
const templateCopyId = templateFile.makeCopy().moveTo(resultFolder).setName(templateCopyName).getId()
const templateCopy = SpreadsheetApp.openById(templateCopyId)
// 판매데이터 필터링 기간 및 템플릿 복사본 정의 종료
let logArrDetail = []
// 거래처별 정산서탭 생성 및 데이터 입력
for (i = 0; i < customers.length; i++) {
const customerStartTime = new Date()
const logDetailId = getRandomId()
const customerOrder = groupStartRow + i + 1
// 거래처 정보 정의
const customer = {
customerName: customers[i][1],
ceoName: customers[i][4],
contactNo: customers[i][5],
email: customers[i][6]
}
Logger.log(`${customer.customerName}의 작업을 시작합니다.`)
try {
// salesData를 거래처명과 판매일시로 필터링하고, 정산서의 양식에 맞춰 열을 재배치
const salesDataFiltered = salesData.filter(row => row[1] == customer.customerName && row[0] >= startDate && row[0] <= endDate)
const salesDataResult = salesDataFiltered.map((item, index) => [index + 1, item[0], item[4], item[5], item[6], item[7], item[8], item[9], item[10], item[11]])
// 탭이름을 정의하고, 템플릿 탭을 복사해서 탭이름으로 설정
const newTabName = `${customer.customerName}_${startDateForName}_${endDateForName}`
const newTab = templateCopy.getSheetByName('템플릿').copyTo(templateCopy).setName(newTabName)
// 새로운 탭에 해당 거래처의 판매데이터 입력
newTab.getRange(17, 2, salesDataResult.length, salesDataResult[0].length).setValues(salesDataResult)
// 정산서에 거래처 정보 및 정산 금액 입력 시작
const salesDataSum = salesDataResult.map(item => item[9]).reduce((acc, cur) => acc + cur, 0)
const cells = ['C8', 'C9', 'C10', 'E10', 'H13', 'K13', 'B13', 'H9']
const customerValues = [customer.customerName, customer.ceoName, customer.contactNo, customer.email, startDateForName, endDateForName, new Date(), salesDataSum]
for (j = 0; j < cells.length; j++) {
newTab.getRange(cells[j]).setValue(customerValues[j])
}
// 정산서에 거래처 정보 및 정산 금액 입력 종료
// 페이지 행 조절
adjustTabRowsByPage(salesDataResult, newTab)
// 월정산서 탭 드라이브 저장
const tabId = newTab.getSheetId()
const fileId = pdfSaveTabReturnFileID(templateCopyId, resultFolder, newTabName, tabId)
// 월정산서 PDF 이메일 발송
sendEmailParam(fileId, customer, startDateForName, endDateForName, invoiceMonth)
// 로그 종료를 위한 변수 정의
const customerEndTime = new Date()
const customerDuration = (customerEndTime.getTime() - customerStartTime.getTime()) / 1000
const downloadPdfUrl = DriveApp.getFileById(fileId).getUrl()
const successYN = '성공'
const emailRemaining = MailApp.getRemainingDailyQuota()
const logArrDetailCustomer = [logId, logDetailId, triggerId, customerOrder, customer.customerName, customer.email, customerStartTime, customerEndTime, customerDuration, downloadPdfUrl, successYN, emailRemaining]
logArrDetail.push(logArrDetailCustomer)
} catch (e) {
Logger.log(`오류가 발생했습니다: ${e}`)
// 로그 종료를 위한 변수 정의
const customerEndTime = new Date()
const customerDuration = (customerEndTime.getTime() - customerStartTime.getTime()) / 1000
const successYN = '실패'
const logArrDetailCustomer = [logId, logDetailId, triggerId, customerOrder, customer.customerName, customer.email, customerStartTime, customerEndTime, customerDuration, null, successYN, null]
logArrDetail.push(logArrDetailCustomer)
}
}
Logger.log(templateCopy.getUrl())
writeLog(T_LOGDETAIL,logArrDetail)
}
JavaScript
복사
상세로그를 기록하는 함수를 호출하는 triggerHF
function triggerHF(e) {
Logger.log(e)
const triggerId = e.triggerUid
const cache = CacheService.getDocumentCache()
const groupInfo = JSON.parse(cache.get(triggerId))
Logger.log(groupInfo)
createMonthlyInvoiceGroupWithLog(groupInfo)
}
JavaScript
복사