📖

smartHRから部署をツリー構造で取得する

2024/11/27に公開

はじめに

特定の条件に当てはまる部署を検知することになった。親部署や子部署も確認しなければならないため、ツリー構造で部署を集めることにした。ただし、smartHRのAPIは現状部署がない。(人の部署は取れる)。そのため

  1. 人の情報をAPIで取得
  2. 部署をツリー構造で編集する
  3. 特定条件に合致した場合通知する

を行う

code

main.js
function main(){
    // crew取得処理は省略
    const crewList = getCrewListFromSheet();
  
    const depertmentList = crewList.reduce((depertmentList, crew) => {
      crew.getDepertmentList().forEach(depertment => {
        if(!depertment.name) return;
        depertment.name.split(DEPERTMENT.route.spliter).reduce((routeList, depertmentName) => {
          routeList.push(depertmentName);
          
          const depertment = new Depertment([].concat(routeList), crew);
          !depertmentList.length
            ? depertmentList.push(depertment)
            : depertmentList.some(bd => bd.findSet(depertment, crew));
          
          return routeList;
        }, []);
      });
      return depertmentList;
    }, []);
  
    const findSetReplenishmentPosition = positionName => {
      return depertmentList.forEach(depertment => {
        depertment.findSetReplenishmentPosition(positionName, depertment.getCrewListholdPosition(positionName));
      });
    };
  
    findSetReplenishmentPosition('取締役');
    findSetReplenishmentPosition('役員');
    findSetReplenishmentPosition('部長');
  }
crew.js
const CREW = {
  status: {
    valid: '有効',
  },
  position: {
    ceo: '社長',
    board: '役員',
    generalManager: '部長',
    manager: 'マネージャー',
    member: 'メンバー',
  }
};

class Crew{
  constructor(){
    this.email;
    this.name;
    this.id;
    this.emp_code;
    this.departmentList = [];
  }
  
  setDataFromSheet(row){
    this.id = row[SHEET.crew.column.id - 1];
    this.email = row[SHEET.crew.column.email - 1];
  }

  setDataFromSmartHRCrew(crew){
    this.name = crew.getName();
    this.email = crew.getEmail();
    this.emp_code = crew.getEmpCode();
    this.departmentList = crew.getDepartmentList();
  }

  addDepertmentList(departmentList){
    this.departmentList = this.departmentList.concat(departmentList);
  }

  isSameEmail(email){
    return this.email === email;
  }

  isNoId(){
    return this.id === undefined;
  }

  isPosition(positionName){
    return this.departmentList.some(d => d.position.includes(positionName));
  }

  findSetId(crewList){
    this.id = crewList.find(bc => this.isSameEmail(bc.email))?.id;
  }

  getDepertmentList(){
    return this.departmentList;
  }

  getEmail(){
    return this.email;
  }


  getOutList(){
    // 以下参照
  }
}
depertment.js
const DEPERTMENT = {
  route: {
    spliter: '/',
  },
};

class Depertment{
  constructor(routeList, crew){
    this.routeList = routeList;
    this.crewList = [crew];
    this.childrenDepertmentList = [];
  }

  findSet(depertment, crew){
    if(!depertment.getRouteText().includes(this.getRouteText()))return false;
    if(this.isSame(depertment)){
      this.crewList.push(crew);
      return true;
    }
    if(this.childrenDepertmentList.some(cd => cd.findSet(depertment, crew))) return true;
    this.childrenDepertmentList.push(depertment);
    return true;
  }

  
  findSetReplenishmentPosition(positionName, crewListWithPositionFromParentDepertment){
    crewListWithPositionFromParentDepertment = crewListWithPositionFromParentDepertment.filter(c => {
        return c.getDepertmentList().every(d => d.name === '' || !(d.position.includes(positionName) && this.getRouteText().includes(d.name)));
    });

    if(!this.getCrewListholdPosition(positionName).length && crewListWithPositionFromParentDepertment.length){
      Logger.log(crewListWithPositionFromParentDepertment.map(c => c.getEmail()));
      return;
    }
    
    this.childrenDepertmentList.forEach(cd => cd.findSetReplenishmentPosition(positionName, this.getCrewListholdPosition(positionName)));
    }

  getCrewListholdPosition(positionName){
    return this.crewList.filter(crew => crew.isPosition(positionName));
  }


  isSame(depertment){
    return this.getRouteText() === depertment.getRouteText();
  }

  getRouteList(){
    return this.routeList;
  }

  getRouteText(){
    return this.routeList.join(DEPERTMENT.route.spliter);
  }

}

Discussion