발주서 취합 업무를 AI로 자동화: ChatGPT와 Apps Script 활용기

업체에서 서로 다른 양식의 발주서를 받아 이를 하나의 송하인 양식으로 취합하는 업무를 합니다.
단순 반복적인 작업이 많아 실수할 위험이 있었고, 집중력이 떨어지면 더 많은 시간이 소요되었습니다.

이를 개선하고자 AI 도구를 활용해 자동화 프로세스를 만들어 보았습니다.

  • 사용한 도구: ChatGPT, Google Apps Script

  1. 각 발주서는 CSV 형식이며, 헤더 이름도 파일마다 다를 수 있습니다.

    예) 수령자명, 수취인명, 받는분, 수취인 주소, 주 소, 품목, 품명, 모델명 .. etc

  2. 내가 원하는 결과는 다음과 같습니다:

    • 특정 열(예: 품목, 옵션, 수량)을 조합하여 하나의 열로 표시하고 싶습니다.
      ex) 품목-청소기,옵션-화이트,수량-2 -> '청소기 화이트 2'

    • 우편번호와 전화번호는 맨 앞의 0이 사라지지 않도록 처리해야 합니다.

    • 동일한 이름의 헤더(예: '우편번호')가 서로 다른 데이터를 포함하는 경우도 정확히 구분해야 합니다.
      ->(보내는분)우편번호,주소 와 (받는분)우편번호,주소는 동일한 헤더이지만 구분해야합니다.

    • 보내는 사람의 정보(우편번호, 주소 등)는 고정값으로 설정하고, 받는 사람의 정보는 각 CSV 파일에서 가져오도록 하고 싶습니다.

    • 결과는 구글 스프레드시트에 저장되도록 설정해주세요.

  1. (1) 연습용으로 두개의 발주서를 가지고 자동화 했습니다.

    중앙에 숫자가 있는 컴퓨터 화면의 스크린샷
    회색 배경에 흰색 선이 한 줄

    (2) 송하인 양식에 맞춰 하나의 발주서를 통합하는 사례입니다.

    컴퓨터 화면에 있는 텍스트 줄의 스크린샷

  • 진행 과정:

1. ChatGPT로 Google Apps Script의 기초를 배우며 코드를 하나씩 작성했습니다.

한국어로 된 문자 메시지의 스크린샷
구글 앱스 스크립트 한국어로

하나씩 떠먹여 주는 지피티 유치원 선생님

구글 드라이브 코리아
한국어 문자 메시지 스크린샷

파일을 불러올수있도록 하는 파일 id를 url에서 찾는 법도 배웠습니다 .

러시아 비자 신청서 샘플

엑셀 업로드 했더니 와장창 깨져버린 모습

한국어로 된 Google 검색 페이지의 스크린샷

CSV 형식의 파일만 읽을 수 있다는 이야기를 듣구 머리털 나고 처음으로 csv 파일을 저장해보았습니다....만

역시나 계속되는 오류에 그만 정신을 잃고 말았습니다.

google app script라는 단어가 포함된 한국어 메시지

처음부터 알려달라고 빌었더니 그 후로 오류가 생기지 않더군요.

2. 여러 CSV 파일을 읽어와 원하는 송하인 양식으로 데이터를 취합하는 코드를 작성했습니다.

3. 작성한 Apps Script 코드는 아래와 같습니다.

function importAndMergeCSVForCustomOrder() {
  // 1. 불러올 파일 이름 설정
  var fileNames = ["h_commerce.csv", "custom.csv"];

  // 2. 취합 문서의 열 순서 (기본 헤더)
  var processedData = [["보내는분", "연락처1", "담당자", "핸드폰", "우편번호", "총주소", 
                        "받는분", "연락처1", "담당자", "핸드폰", "우편번호", "총주소", 
                        "수량", "품목", "운임타입", "지불조건", "출고번호", 
                        "특기사항", "메모1", "메모2"]];

  // 3. 보내는 사람의 기본 데이터 설정
  var senderInfo = {
    우편번호: "'00000", // 맨 앞 0이 유지되도록 문자열로 처리
    총주소: "서울 어쩌구 어쩌로 19",
    연락처1: "'0200000000",
    핸드폰: "'01000000000"
  };

  // 4. 파일 처리
  fileNames.forEach(function (fileName) {
    var files = DriveApp.getFilesByName(fileName);

    if (!files.hasNext()) {
      Logger.log("파일을 찾을 수 없습니다: " + fileName);
      return;
    }

    var file = files.next();
    var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
    var header = csvData[0];

    // 열 위치 매핑
    var columns = {};
    header.forEach(function (colName, index) {
      // 공백 제거 후 이름을 소문자로 비교
      colName = colName.replace(/\s+/g, "").toLowerCase();
      if (colName.includes("받는분") || colName.includes("수취인")) columns["받는분"] = index;
      if (colName.includes("연락처") || colName.includes("전화번호")) columns["연락처1"] = index;
      if (colName.includes("핸드폰") || colName.includes("모바일")) columns["핸드폰"] = index;
      if (colName.includes("우편번호") || colName.includes("zip")) columns["받는우편번호"] = index;
      if (colName.includes("주소")) columns["받는총주소"] = index;
      if (colName.includes("수량") || colName.includes("개수")) columns["수량"] = index;
      if (colName.includes("품명") || colName.includes("품목") || colName.includes("상품명")) columns["품목"] = index; // 품명 추가
      if (colName.includes("옵션") || colName.includes("선택사항")) columns["옵션"] = index;
      if (colName.includes("특기사항") || colName.includes("요청사항")) columns["특기사항"] = index;
    });

    // 데이터 처리
    for (var i = 1; i < csvData.length; i++) {
      var row = csvData[i];

      // 빈 줄 건너뛰기
      if (row.every(cell => !cell.trim())) continue;

      // "품목" 데이터 조합
      var itemDescription = [
        columns["품목"] !== undefined ? row[columns["품목"]] : "",
        columns["옵션"] !== undefined ? row[columns["옵션"]] : "",
        columns["수량"] !== undefined ? row[columns["수량"]] : ""
      ].filter(Boolean).join(" ");

      // "메모1" 데이터 조합
      var memo1Content = [
        columns["특기사항"] !== undefined ? row[columns["특기사항"]] : ""
      ].filter(Boolean).join(" / ");

      var processedRow = [
        // 보내는 사람 정보
        "(주)000", // 보내는분
        senderInfo.연락처1, // 연락처1
        "", // 담당자
        senderInfo.핸드폰, // 핸드폰
        senderInfo.우편번호, // 우편번호 (보내는 사람)
        senderInfo.총주소, // 총주소 (보내는 사람)

        // 받는 사람 정보
        row[columns["받는분"]] || "", // 받는분
        row[columns["연락처1"]] ? `'${row[columns["연락처1"]]}` : "", // 연락처1
        fileName.split(".")[0], // 담당자 (CSV 파일 이름 추가)
        row[columns["핸드폰"]] ? `'${row[columns["핸드폰"]]}` : "", // 핸드폰
        row[columns["받는우편번호"]] ? `'${row[columns["받는우편번호"]]}` : "", // 우편번호 (받는 사람)
        row[columns["받는총주소"]] || "", // 총주소 (받는 사람)

        // 주문 정보
        row[columns["수량"]] || "", // 수량
        itemDescription.trim(), // 품목: 품명 + 옵션 + 수량
        "S", // 운임타입
        "", // 지불조건
        "", // 출고번호 (항상 공란)
        "", // 특기사항 (항상 공란)
        memo1Content, // 메모1
        "" // 메모2 (항상 공란)
      ];

      processedData.push(processedRow);
    }
  });

  // 5. "orderlist" 스프레드시트 열기
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();
  sheet.clear();

  // 6. 정리된 데이터 저장
  sheet.getRange(1, 1, processedData.length, processedData[0].length).setValues(processedData);

  Logger.log("CSV 데이터를 'orderlist' 시트에 취합 완료!");
}
한국어 한국어 한국어 한국어 한국어 한국어 한국어 한국어

custom.csv 와 h_commerce.csv 두개의 발주서가 하나의 송하인 양식으로 정리되었습니다.

결과와 배운 점

  • 성과:

    • ChatGPT를 활용해 처음 접하는 Google Apps Script의 기초를 이해하고, 기본적인 자동화 스크립트를 작성할 수 있었습니다.

    • 중복된 작업에서 발생하던 실수를 줄이고, 단순 반복 작업에서 시간을 절약할 가능성을 탐구했습니다.

  • 어려움:

    • 처음에는 Google Apps Script의 문법과 기본적인 개념을 전혀 몰라 어려움이 많았습니다. 특히 오류가 발생했을 때 그 의미를 이해하고 해결하는 데 시간이 걸렸습니다.

    • 각 CSV 파일의 헤더 이름이 제각각이라 이를 모두 매핑하는 과정이 복잡하고 까다로웠습니다. 일부 양식은 손으로 직접 처리하는 것이 더 효율적이라는 생각도 들었습니다.

    • CSV 파일 변환과 스프레드시트 저장 등 새로운 작업 단계가 추가되면서 업무가 더 복잡하게 느껴지기도 했습니다.

  • 앞으로의 개선 방향:

    • 엑셀 파일 그 자체를 처리할 수 있는 자동화 도구를 사용하는 방향을 모색하고 싶습니다.

4
2개의 답글

👉 이 게시글도 읽어보세요