【作ってみた】採用アプリ編③ -応募番号 自動採番処理-

本記事の内容

  • 応募者レコードを作成した時、応募者番号を自動で採番する処理
  • カスタム設定の作成
  • Apexクラスの実装

全体像

★採用アプリ範囲

★社員管理アプリ範囲

カスタム設定関連の設定

★カスタム設定を作成
  1. 設定アイコン押下
  2. クイック検索で「カスタム設定」と検索し、カスタム設定を選択
  3. 新規ボタン押下
  4. 下記内容で作成
ラベル名 オブジェクト名 設定種別 表示
自動採番インデックス AutoNumberingIndex リスト 公開
★カスタム設定のカスタム項目を作成
ラベル名 API参照名 データ型
インデックス Index__c 数値
★カスタム設定のレコードを作成
  1. 設定アイコン押下
  2. クイック検索で「カスタム設定」と検索し、カスタム設定を選択
  3. 一覧から「自動採番インデックス」を選択
  4. 「Manage」ボタン押下
  5. 新規ボタン押下
  6. 下記内容でレコードを作成
Name インデックス
Applicant 1

実装するApexクラス一覧

Apexクラス名 新規 / 編集
ApplicantTrigger.trigger 新規
ApplicantHandler.cls 新規
ApplicantLogic.cls 新規
Constants.cls 編集
CommonMethod.cls 編集

Constants.cls

  • 今回追加する内容
public class Constants {

    /** 
     * 応募者
     */

    /** オブジェクト名 */
    public static final String APPLICANT_OBJECT = 'Applicant__c';

    /** レコードタイプ */
    public static final String APPLICANT_RECORDTYPE_NEWGRADUATE = 'RecordType_NewGraduate';
    public static final String APPLICANT_RECORDTYPE_MIDCAREER   = 'RecordType_MidCareer';

}
  • 上記内容追加後のConstants.cls
public class Constants {
    
    /** 
     * トリガ種別 
     */
    public static final String TRIGGER_TIMING_BEFORE = 'before';
    public static final String TRIGGER_TIMING_AFTER  = 'after';
    public static final String TRIGGER_TYPE_INSERT   = 'insert';
    public static final String TRIGGER_TYPE_UPDATE   = 'update';
    public static final String TRIGGER_TYPE_DELETE   = 'delete';
    public static final String TRIGGER_TYPE_UNDELETE = 'undelete';


    /** 処理種別 */
    public static final String CUSTOMMETA_PROCESSCATEGORY_COPY   = 'コピー';
    public static final String CUSTOMMETA_PROCESSCATEGORY_INSERT = '作成';
    public static final String CUSTOMMETA_PROCESSCATEGORY_UPDATE = '更新';
    public static final String CUSTOMMETA_PROCESSCATEGORY_CHECK  = 'チェック';
    public static final String CUSTOMMETA_PROCESSCATEGORY_SUM    = '集計';
    public static final String CUSTOMMETA_PROCESSCATEGORY_SET    = 'セット';
    public static final String CUSTOMMETA_PROCESSCATEGORY_SERIAL = '連番';    


    /**
     * ひらがな・カタカナ変換用
     */
    public static final Integer CONVERT_DIFFERENCE_NUM      = 96;    // ひらがな・カタカナ間のUnicode値の差
    public static final Integer CONVERT_HIRAGANA_START_CODE = 12353;
    public static final Integer CONVERT_HIRAGANA_END_CODE   = 12438;
    public static final Integer CONVERT_KATAKANA_START_CODE = 12449;
    public static final Integer CONVERT_KATAKANA_END_CODE   = 12534;


    /** 
     * 応募者
     */

    /** オブジェクト名 */
    public static final String APPLICANT_OBJECT = 'Applicant__c';

    /** レコードタイプ */
    public static final String APPLICANT_RECORDTYPE_NEWGRADUATE = 'RecordType_NewGraduate';
    public static final String APPLICANT_RECORDTYPE_MIDCAREER   = 'RecordType_MidCareer';

}

CommonMethod.cls

  • 今回追加する内容
public class CommonMethod {
    /**
     * レコードタイプ名からレコードタイプIDを取得
     * @param  objName オブジェクト名
     * @param  rtName  レコードタイプ名
     * @return rtId    レコードタイプID
     */
    public static Id getRecordTypeId(String objName, String rtName) {
        Schema.DescribeSObjectResult so = Schema.getGlobalDescribe().get(objName).getDescribe();
        List<Schema.RecordTypeInfo> rtList = so.getRecordTypeInfos();

        Id rtId = null;

        for (Schema.RecordTypeInfo rt : rtList) {
            if (rt.getDeveloperName().equals(rtName)) {
                rtId = rt.getRecordTypeId();
                break;
            }
        }
        return rtId;
    }

    /**
     * 会計年度を考慮した今年度を取得
     * @return currentYear
     */
    public static String getCurrentYear() {

        // 組織の会計年度開始月を取得
        Organization org = [SELECT                                      
                                FiscalYearStartMonth
                            FROM
                                Organization
                            WHERE
                                id = :UserInfo.getOrganizationId()];
        
        String currentYear = '';            // 今年度
        Date   today       = Date.today();  // 本日

        // 今月が会計年度開始月より大きい場合
        if (today.month() >= org.FiscalYearStartMonth) {                
            currentYear = String.valueOf(today.year());
        // 今月が会計年度開始月より小さい場合
        } else {                                                        
            currentYear = String.valueOf(today.year() - 1);
        }
        return currentYear;
    }

ApplicantTrigger.trigger

trigger ApplicantTrigger on Applicant__c (before insert, before update, before delete, after insert, after update, after delete, after undelete) {

// スキップユーザを指定
String skipUserName = SkipUserFlg__c.getOrgDefaults().ApplicantTrgSkipUser__c;
if (!String.isBlank(skipUserName) && UserInfo.getUserName().equals(skipUserName)) return;

    new ApplicantHandler().run();
}

ApplicantHandler.cls

public class ApplicantHandler extends TriggerHandler {
    
    private static boolean firstRunBeforeInsert  = true;
    private static boolean firstRunBeforeUpdate  = true;
    private static boolean firstRunBeforeDelete  = true;
    private static boolean firstRunAfterInsert   = true;
    private static boolean firstRunAfterUpdate   = true;
    private static boolean firstRunAfterDelete   = true;
    private static boolean firstRunAfterUnDelete = true;

    private List<SObject> newList;
    private List<SObject> oldList;

    /**
     * コンストラクタ
     */
    public ApplicantHandler() {
        this.newList = Trigger.new;
        this.oldList = Trigger.old;
    }

    /** Before Insert */
    public override void onBeforeInsert() {
        // 2重起動防止
        if (!firstRunBeforeInsert) return;
        firstRunBeforeInsert = false;

        ApplicantLogic logic = new ApplicantLogic(Constants.TRIGGER_TIMING_BEFORE, Constants.TRIGGER_TYPE_INSERT, this.newList);
        logic.onBeforeInsert(this.newList);
    }

    /** Before Update */
    public override void onBeforeUpdate() {
        // 2重起動防止
        if (!firstRunBeforeUpdate) return;
        firstRunBeforeUpdate = false;

        ApplicantLogic logic = new ApplicantLogic(Constants.TRIGGER_TIMING_BEFORE, Constants.TRIGGER_TYPE_UPDATE, this.newList);
        logic.onBeforeUpdate(this.oldList, this.newList);
    }

    /** Before Delete */
    public override void onBeforeDelete() {
        // 2重起動防止
        if (!firstRunBeforeDelete) return;
        firstRunBeforeDelete = false;
    }

    /** After Insert */
    public override void onAfterInsert() {
        // 2重起動防止
        if (!firstRunAfterInsert) return;
        firstRunAfterInsert = false;
    }

    /** After Update */
    public override void onAfterUpdate() {
        // 2重起動防止
        if (!firstRunAfterUpdate) return;
        firstRunAfterUpdate = false;
    }

    /** After Delete */
    public override void onAfterDelete() {
        // 2重起動防止
        if (!firstRunAfterDelete) return;
        firstRunAfterDelete = false;
    }

    /** After UnDelete */
    public override void onAfterUnDelete() {
        // 2重起動防止
        if (!firstRunAfterUnDelete) return;
        firstRunAfterUnDelete = false;
    }
}

ApplicantLogic.cls

public class ApplicantLogic {

    String                      triggerType;            // トリガ種別
    ID                          newRtId;                // レコードタイプ「新卒」
    ID                          midRtId;                // レコードタイプ「中途」 
    AutoNumberingIndex__c       index;                  // 自動採番インデックス
    
    /**
     * コンストラクタ
     */
    public ApplicantLogic(String triggerTiming, String triggerType, List<Applicant__c> newAppList) {
        /** 共通 */
        initCommonTrigger(triggerTiming, triggerType, newAppList);
        /** Before */
        if ((Constants.TRIGGER_TIMING_BEFORE.equals(triggerTiming) && Constants.TRIGGER_TYPE_INSERT.equals(triggerType))
        ||  (Constants.TRIGGER_TIMING_BEFORE.equals(triggerTiming) && Constants.TRIGGER_TYPE_UPDATE.equals(triggerType))) {
            initBeforeTrigger(newAppList);
        }
    }


    /**
     * 共通初期処理
     */
    private void initCommonTrigger(String triggerTiming, String triggerType, List<Applicant__c> newAppList) {
        this.triggerType = triggerType;
        this.newRtId = CommonMethod.getRecordTypeId(Constants.APPLICANT_OBJECT, Constants.APPLICANT_RECORDTYPE_NEWGRADUATE);    // レコードタイプID取得:新卒
        this.midRtId = CommonMethod.getRecordTypeId(Constants.APPLICANT_OBJECT, Constants.APPLICANT_RECORDTYPE_MIDCAREER);      // レコードタイプID取得:中途
    }


    /**
     * Beforeトリガ用初期処理
     */
    private void initBeforeTrigger(List<Applicant__c> newAppList) {                                                                                     // END: 処理毎のカスタムメタデータ型Listを作成

        this.index = new AutoNumberingIndex__c();                                                   // カスタム設定「自動採番インデックス」を取得
        this.index = AutoNumberingIndex__c.getInstance('Applicant');
    }


    /**
     * Before Insert
     */
    public void onBeforeInsert(List<Applicant__c> newAppList) {
        for (Applicant__c newApp : newAppList) {
            setApplicantDataLogic(null, newApp);    // 応募者レコードに関する処理
        }

        update this.index;                          // 応募番号インデックスを更新
    }


    /**
     * Before Update
     */
    public void onBeforeUpdate(List<Applicant__c> oldAppList, List<Applicant__c> newAppList) {
        for (Integer i = 0; i < newAppList.size(); i++) {
            Applicant__c oldApp = oldAppList.get(i);
            Applicant__c newApp = newAppList.get(i);

            setApplicantDataLogic(oldApp, newApp);  // 応募者レコードに関する処理
        }
    }


    /**
     * 応募者レコードに関する処理
     * @param oldApp 更新前応募者レコード
     * @param newApp 更新後応募者レコード
     */
    private void setApplicantDataLogic(Applicant__c oldApp, Applicant__c newApp) {
        /** Insert */
        if (Constants.TRIGGER_TYPE_INSERT.equals(this.triggerType)) {
            setAppNumber(newApp);                                             // 応募番号自動採番
        /** Update */
        } else if (Constants.TRIGGER_TYPE_UPDATE.equals(this.triggerType)) {

        }
        /** Insert & Update */
    }


    /**
     * 応募番号自動採番
     * @param newApp 応募者レコード
     */
    private void setAppNumber(Applicant__c newApp) {
        Decimal appNum      = this.index.Index__c;                                      // インデックス取得
        String  year        = CommonMethod.getCurrentYear();                            // 今年度を取得
        newApp.Name         = year + String.valueOf(appNum.intValue()).leftPad(3, '0'); // 文字列に変換し、5桁まで左詰め
        appNum              += 1;                                                       // インデックスに「1」加算
        this.index.Index__c = appNum;                                                   // 「1」加算した値をカスタム設定に設定
    }
}

次回記事