【代碼解析】深入理解 BkTrSyutokuHenkan.java 及其 matomeCd 使用情況

| Java | 3 Reads

該博文介紹了對 BkTrSyutokuHenkan.java 的深入分析,重點討論了在 registTouroku 方法中關於
“matomeCd = commonManager.getNewMatomeCd();” 之後可能出現“生成的 matomeCd 沒有被使用”的情況。
以下內容包含完整代碼(原代碼經過整理,並將注釋換成中文)以及我們的思考與分析。


引言

在我們的舊系統中,BkTrSyutokuHenkan.java 是處理管理官獲取返還事務的重要模塊。
其中有一段代碼負責調用 commonManager.getNewMatomeCd() 以生成“まとめ碼(matomeCd)”,
並把它放入一個 Hashtable(matomeHash)中,以便後續在生成修正鏈接(Link)等操作時覆用這個值。

本文主要分析 registTouroku(BKSManager manager) 方法中“matomeCd”生成後的使用情況,
重點討論以下問題:

  • 在哪些場景下會生成 matomeCd?

  • 如果條件不滿足(例如 rec.kanriboCd_henpin 為 null 或剩余個數(kosuuFlg)不為 1),
    是否會導致生成的 matomeCd 沒有被使用,僅用於更新 henpin_tbl 和 kobetu_tbl?

  • 結合代碼,我們總結出此處雖然存在“資源浪費”的可能,但設計上是基於延遲加載與緩存設計。

接下來,我們給出整理後的完整代碼,並在每個關鍵位置提供中文注釋。


完整代碼(帶中文注釋)

下面代碼為 BkTrSyutokuHenkan.java 整理版
所有原注釋均已翻譯為中文,並在關鍵點強調了關於 matomeCd 使用的邏輯
(注:代碼僅供參考,部分業務邏輯和方法名原樣保留)

/**
 * $Id: BkTrSyutokuHenkan.java,v 1.23 2010/05/12 01:59:13 kodama Exp $
 * 
 * 管理官獲取返還 —— BkTrSyutokuHenkan 類(處理返還操作)
 */
package jp.go.jda_trdi.bks.bk;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.sql.Date;
import java.math.BigDecimal;
import java.sql.SQLException;

import jp.go.jda_trdi.bks.*;
import jp.go.jda_trdi.bks.db.*;
import jp.go.jda_trdi.bks.db.bk.*;

import jp.go.jda_trdi.bks.report.*;
import jp.go.jda_trdi.bks.report.param.bk.paramBK08_HenpinZairyouMeisai;
import jp.go.jda_trdi.bks.report.param.bk.paramBK08_HenpinZairyouMeisaiUtiwake;
import jp.go.jda_trdi.bks.report.print.bk.printBK08_HenpinZairyouMeisai;

import util.DbUtil;
import util.EtcFuncUtil;
import webkcore.report.ReportGeneratorException;

import java.io.IOException;
import java.io.FileOutputStream;

import javax.servlet.http.HttpSession;

import constant.ConstValue;

import bean.KobetuList;
import bean.Kyouyoubo;
import bean.Link;
import bean.OperatorInfo;
import bean.ZougenRireki;

/**
 * 管理官獲取返還(返還操作)
 *
 * @version $Revision: 1.23 $
 * @author $Author: kodama $
 */
public class BkTrSyutokuHenkan extends BkTransaction {
    public Date shutokuYmd = null;

    /* 退貨單(返品書) */
    public HenpinDoc docParent = null; // 退貨單

    /**
     * 初始化新生成的 BkTrSyutokuHenkan 實例
     *
     * @param session - SQLJ用上下文
     * @param logger - 日志輸出對象
     * @param seiriKbn - 整理區分
     * @param shoriSts - 處理狀態
     * @param oper - 操作員信息
     */
    public BkTrSyutokuHenkan(HttpSession session, Logger logger, Integer seiriKbn, Integer shoriSts, AuthOperator oper) {
        super(session, logger, seiriKbn, shoriSts, oper);
        // 初始化物品列表管理對象
        buppinList = new BuppinListManager(seiriKbn, logger, this);
        // 創建退貨單對象
        docParent = new HenpinDoc(session, logger, seiriKbn, oper.opCd);
    }

    /**
     * 為交易創建用於處理證明書明細的類
     *
     * @return - 明細類
     */
    public DocMeisai createMeisai() {
        return createHenpinMeisai();
    }

    /**
     * 創建退貨單明細類
     *
     * @return - 明細類
     */
    public HenpinMeisai createHenpinMeisai() {
        return new HenpinMeisai(session, logger);
    }

    /**
     * 從指定的證明書代碼加載交易數據
     *
     * @param docCd - 證明書代碼
     * @throws BKSSQLException, BKSException, SQLException
     */
    public void loadDocumentData(Long docCd) throws BKSSQLException, BKSException, SQLException {
        docParent.create(docCd);
        this.docCd = docParent.getDocCd();
        return;
    }

    /**
     * 從交易對象中構建報表數據
     *
     * @param manager - BKSManager
     * @param vLink   - 存放鏈接的向量
     * @exception BKSException 當報表創建失敗時拋出
     * @throws SQLException
     */
    public void makeReportData(BKSManager manager, Vector vLink) throws BKSException, BKSSQLException, SQLException {
        try {
            BkReportManager reportManager = manager.getBkReportManager();
            Vector vect = null;
            // 設置生成 PDF 的文件名
            String filename = ConstValue.PDF_HOME + seiriKbn.toString() + "_" + docParent.getDocCd().toString() +
                              "_BK08_henpin_" + manager.getAuthOperator().sishoCd + manager.getAuthOperator().opCd + ".pdf";
            FileOutputStream fos = new FileOutputStream(filename);

            printBK08_HenpinZairyouMeisai printParent = new printBK08_HenpinZairyouMeisai(fos);
            printParent.Init();
            // 獲取退貨報表數據
            vect = reportManager.getHenpinReportData(docParent.getDocCd(), seiriKbn, new Integer(BkCode.SS_COMPLETE));
            printParent.printBK08_HenpinZairyouMeisai((paramBK08_HenpinZairyouMeisai) vect.elementAt(0));
            for (int i = 1; i < vect.size(); i++) {
                printParent.printBK08_HenpinZairyouMeisaiUtiwake((paramBK08_HenpinZairyouMeisaiUtiwake) vect.elementAt(i));
            }
            printParent.Close();
            printParent.doFinal();
            fos = null;
            vLink.addElement(ConstValue.PDF_HOME + seiriKbn.toString() + "_" + docParent.getDocCd().toString() +
                              "_BK08_henpin_" + manager.getAuthOperator().sishoCd + manager.getAuthOperator().opCd + ".pdf");
            return;
        } catch (PrintListException e) {
            logger.log(e);
            throw new BKSException("無法輸出報表");
        } catch (ReportGeneratorException e) {
            logger.log(e);
            throw new BKSException("WebkCore 錯誤");
        } catch (IOException e) {
            logger.log(e);
            throw new BKSException("IOException 錯誤");
        }
    }

    /**
     * 處理點擊【登記】按鈕時的業務邏輯
     *
     * @param manager - BKSManager
     * @exception BKSSQLException 當將證明書信息寫入數據庫失敗時拋出
     * @exception BKSException
     */
    public void regist(BKSManager manager) throws BKSSQLException, BKSException {
        // 管理官登記時(狀態代碼:12)
        if (shoriSts.intValue() == BkCode.SS_KANRIKAN_TOUROKU) {
            registTouroku(manager);
        }
        // 供用官受理時(狀態代碼:51)
        else if (shoriSts.intValue() == BkCode.SS_UKEIRE) {
            registUkeire(manager);
        }
        else {
            throw new BKSException("BkTrSyutokuHenkan:regist 無法登記處理狀態 [" + shoriSts + "]");
        }
        return;
    }

    /**
     * 管理官登記時的處理(此方法重點討論 matomeCd 的使用)
     */
    private void registTouroku(BKSManager manager) throws BKSSQLException, BKSException {
        Integer writeStatus = null;       // 寫入證明書的狀態
        Integer writeKanriboSeiriKbn = new Integer(BkCode.KAN_SYUTOKU_HENKAN); // 管理簿寫入時的整理區分
        Integer writeKanriSts = null;       // 寫入個別信息時的狀態
        // 此處注釋中提到:KobetuRireki 未被使用,所以注釋掉
        // Enumeration enum1; 
        Hashtable<String, BigDecimal> matomeHash = new Hashtable<String, BigDecimal>(); // 用於緩存 matomeCd,key 為 matomeKbn

        BkCommonManager commonManager = manager.getBkCommonManager(); // 初始化共通管理器
        KanriboManager kanriboManager = manager.getKanriboManager();     // 管理簿管理器
        LinkManager linkManager = manager.getLinkManager();             // 鏈接管理器

        // 根據是否存在供用官代碼決定狀態:存在時,表示該物品正在使用中,否則為管理官保管物品
        try {
            if (docParent.getKyouyoukanCd() != null) {
                writeStatus = new Integer(BkCode.SS_UKEIRE);
                writeKanriSts = new Integer(BkCode.KS_LOCKED);
            }
            else {
                writeStatus = new Integer(BkCode.SS_COMPLETE);
                writeKanriSts = new Integer(BkCode.KS_KANRI_HOKAN);
            }

            // 如果所有明細的退貨數量均為 0,則不執行供用官受理處理
            boolean henpinFlg = false;
            Enumeration enum1 = docParent.getMeisai().elements();
            while (enum1.hasMoreElements()) {
                HenpinMeisai rec = (HenpinMeisai) enum1.nextElement();
                rec.modify(docCd, seiriKbn, oper.opCd, writeStatus);
                if (rec.getHenpinSuryo().intValue() > 0)
                    henpinFlg = true;
            }
            if (henpinFlg)
                docParent.modify(writeStatus); // 設置為供用官受理待命
            else
                docParent.modify(new Integer(BkCode.SS_COMPLETE)); // 狀態直接為處理完成

            /***** 開始:管理官保管管理簿創建 *****/
            if (docParent.getKyouyoukanCd() == null) {
                // 為進行退貨處理的物品創建管理簿記錄
                MakeBookRecord makeBookRecord = new MakeBookRecord(
                    manager,
                    seiriKbn,
                    writeKanriboSeiriKbn,
                    null,
                    docParent.getKanrikanCd(),
                    null,
                    docParent.getKanriDocNo(),
                    docParent.getWatasiGyoushaCd(),
                    null,
                    docParent.getKeiyakuNo(),
                    docParent.getKonkyo(),
                    null,
                    null
                );

                // 為使用處理的物品創建管理簿記錄
                MakeBookRecord makeBookRecord_siyou = new MakeBookRecord(
                    manager,
                    seiriKbn,
                    new Integer(BkCode.KAN_HARAI_HENKAN_ZAKKEN),
                    null,
                    docParent.getKanrikanCd(),
                    null,
                    docParent.getKanriDocNo(),
                    docParent.getWatasiGyoushaCd(),
                    null,
                    docParent.getKeiyakuNo(),
                    docParent.getKonkyo(),
                    null,
                    null
                );

                // 遍歷退貨單中的每個明細
                enum1 = docParent.getMeisai().elements();
                while (enum1.hasMoreElements()) {
                    HenpinMeisai rec = (HenpinMeisai) enum1.nextElement();
                    BigDecimal idoKakaku = rec.getTanka().multiply(new BigDecimal(rec.getHenpinSuryo().toString()));
                    // 如果退貨數量大於0,則創建退貨的管理簿
                    if (rec.getHenpinSuryo().intValue() > 0) {
                        // 獲取新的管理簿代碼
                        BigDecimal kanriboCd = commonManager.getNewKanriboCd();
                        Kanribo kanribo = makeBookRecord.makeKanriboUke(
                            rec.getBuppinCd(),
                            rec.getShoumouKbn(),
//                          docParent.getUketukeYmd(),
                            docParent.getKanriYmd(),
                            rec.getHenpinSuryo(),
                            null,
                            idoKakaku,
                            rec.getHinsituKikaku(),
                            rec.getZeiGaku()
                        );
                        // 將管理簿代碼從自動生成切換到手動設置
                        kanribo.setKanriboCd(kanriboCd);
                        kanriboManager.add2(kanribo, oper.opCd);
                        // 將退貨管理簿代碼臨時保存在明細中
                        rec.kanriboCd_henpin = kanriboCd;
                    }

                    // 同理,為使用數量大於0的明細創建管理簿
                    BigDecimal idoKakaku_siyou = rec.getTanka().multiply(new BigDecimal(rec.getSiyouSuryo().toString()));
                    if (rec.getSiyouSuryo().intValue() > 0) {
                        BigDecimal kanriboCd = commonManager.getNewKanriboCd();
                        Kanribo kanribo = makeBookRecord_siyou.makeKanriboHarai(
                            rec.getBuppinCd(),
                            rec.getShoumouKbn(),
//                          docParent.getUketukeYmd(),
                            docParent.getKanriYmd(),
                            rec.getSiyouSuryo(),
                            null,
                            idoKakaku_siyou,
                            rec.getHinsituKikaku(),
                            rec.getZeiGaku()
                        );
                        kanribo.setKanriboCd(kanriboCd);
                        kanriboManager.add2(kanribo, oper.opCd);
                        rec.kanriboCd_siyou = kanriboCd;
                    }
                }
            }
            /***** 結束:管理官保管管理簿創建 *****/

            /***** 開始:使用者供用管理簿創建 *****/
            // 如果供用官代碼存在,則創建僅針對使用數量的管理簿
            if (docParent.getKyouyoukanCd() != null) {
                MakeBookRecord makeBookRecord_siyou = new MakeBookRecord(
                    manager,
                    seiriKbn,
                    new Integer(BkCode.KAN_HENNOU_HENKAN_ZAKKEN),
                    null,
                    docParent.getKanrikanCd(),
                    docParent.getKyouyoukanCd(),
                    docParent.getKanriDocNo(),
                    docParent.getWatasiGyoushaCd(),
                    null,
                    docParent.getKeiyakuNo(),
                    docParent.getKonkyo(),
                    null,
                    null
                );
                enum1 = docParent.getMeisai().elements();
                while (enum1.hasMoreElements()) {
                    HenpinMeisai rec = (HenpinMeisai) enum1.nextElement();
                    if (rec.getSiyouSuryo().intValue() > 0) {
                        BigDecimal idoKakaku_siyou = rec.getTanka().multiply(new BigDecimal(rec.getSiyouSuryo().toString()));
                        BigDecimal kanriboCd = commonManager.getNewKanriboCd();
                        Kanribo kanribo = makeBookRecord_siyou.makeKanriboHarai(
                            rec.getBuppinCd(),
                            rec.getShoumouKbn(),
//                          docParent.getUketukeYmd(),
                            docParent.getKanriYmd(),
                            rec.getSiyouSuryo(),
                            null,
                            idoKakaku_siyou,
                            rec.getHinsituKikaku(),
                            rec.getZeiGaku()
                        );
                        kanribo.setKanriboCd(kanriboCd);
                        // 將課室代碼設置為 NULL
                        kanribo.setKasituCd(null);
                        kanriboManager.add2(kanribo, oper.opCd);
                        rec.kanriboCd_siyou = kanriboCd;
                    }
                }
            }
            /***** 結束:使用者供用管理簿創建 *****/

            /************ 開始:共通處理 **********/
            // 將退貨狀態的個別物品數據放入 KobetuListManager 中
            KobetuListManager kobetuListManager = new KobetuListManager(seiriKbn);
            KobetuManager kobetuManager = manager.getKobetuManager();
            enum1 = docParent.getMeisai().elements();
            while (enum1.hasMoreElements()) {
                HenpinMeisai rec = (HenpinMeisai) enum1.nextElement();
                BigDecimal[] kobetuCdArray = rec.getKobetuCdArray();
                int kosuuFlg = 1;    // 表示剩余的個數
                Kobetu kobetu = null;  // 個別物品信息
                boolean chkflg = true; // 標記:是否轉向下一個個別物品
                int k = 0;           // 用於獲取個別物品的序號

                // ------------- 關鍵點:下面開始取“まとめ碼”(matomeCd)的處理 -------------
                // 根據明細信息生成“まとめ區分”
                BigDecimal matomeCd = null;
                String matomeKbn = rec.getBuppinCd() + "," + rec.getHinsituKikaku() + "," +
                                   rec.getTanka().toString() + "," + rec.getShoumouKbn() + "," +
                                   rec.getShutokuYmd().toString();
                // 如果該 key 已經存在,則直接取出對應的 matomeCd,否則生成新的並放入緩存
                if (matomeHash.get(matomeKbn) != null) {
                    matomeCd = matomeHash.get(matomeKbn);
                }
                else {
                    matomeCd = commonManager.getNewMatomeCd();
                    matomeHash.put(matomeKbn, matomeCd);
                }
                // ------------- 結束:まとめ碼的處理 -------------
                // 注:此處存在一種潛在情況:如果後續流程中因為某些條件(如 rec.kanriboCd_henpin 為 null 或剩余個數不滿足條件)而未使用 matomeCd,
                // 那麽這個生成的 matomeCd 只存在於緩存中,但未參與後續的鏈接創建。這種情況可能只是影響了 ID 生成效率,而不會導致業務邏輯出錯。

                // 遍歷退貨數量的循環,對個別物品進行處理
                for (int i = 0; i < rec.getHenpinSuryo().intValue(); i++) {
                    // 當需要轉向下個個別物品時
                    if (chkflg) {
                        // 獲取當前個別物品信息
                        kobetu = kobetuManager.findByPrimaryKey(kobetuCdArray[k]);
                        kosuuFlg = kobetu.getKosuu().intValue(); // 記錄剩余個數
                        chkflg = false; // 在轉向之前,將標記設為 false
                    }
                    // 當剩余個數恰好為 1 時,將該個別物品加入列表
                    if (kosuuFlg == 1) {
                        kobetuListManager.add(kobetu);
                        // 如果退貨管理簿代碼已存在,則添加修正鏈接,
                        // 此處將 matomeCd 用於設置退貨鏈接(即 link.setMatomeCdUke(matomeCd))
                        if (rec.kanriboCd_henpin != null) {
                            Link link = new Link();
                            link.setKobetuCd(kobetu.getKobetuCd());
                            link.setMatomeCdUke(matomeCd);
                            link.setKanriboCdUke(rec.kanriboCd_henpin);
                            // 同時更新鏈接中物品代碼
                            linkManager.add(link, oper.opCd, kobetu.getBuppinCd());
                        }
                        chkflg = true; // 轉向下個個別物品
                        k++;
                    }
                    // 每次循環減少剩余個數
                    kosuuFlg--;
                }
                // 如果退貨數量未完全對應(即退貨數量結束前剩余個數仍存在),將當前個別物品加入列表
                if (rec.getHenpinSuryo().intValue() > 0 && kosuuFlg >= 1) {
                    kobetuListManager.add(kobetu);
                    if (rec.kanriboCd_henpin != null) {
                        Link link = new Link();
                        link.setKobetuCd(kobetu.getKobetuCd());
                        link.setMatomeCdUke(matomeCd);
                        link.setKanriboCdUke(rec.kanriboCd_henpin);
                        linkManager.add(link, oper.opCd, kobetu.getBuppinCd());
                    }
                }
            }

            // 更新個別物品數據,將退貨物品的狀態更新為 writeKanriSts
            enum1 = kobetuListManager.kobetuElements();
            while (enum1.hasMoreElements()) {
                KobetuList kobetu = (KobetuList) enum1.nextElement();
                kobetu.setKanriSts(writeKanriSts);
                kobetuManager.modify(kobetu.get(), oper.opCd);
            }

            // 創建新的退貨單(涉及使用物品的拆分等處理)
            // 參數 henpinFlg 表示:如果存在供用官受理待命,則為 true;否則為 false(管理官保管情況)
            createNewHenpinDoc(manager, henpinFlg);
            commonManager.executeCommit();
            /************ 結束:共通處理 **********/
        }
        catch (BKSSQLException e) {
            logger.log(e);
            try {
                commonManager.executeRollback();
                throw new BKSException("退貨回滾");
            }
            catch (BKSSQLException ie) {
                throw new BKSException("退貨回滾失敗");
            }
        }
        catch (BKSException e) {
            logger.log(e);
            try {
                commonManager.executeRollback();
                throw new BKSException("退貨回滾");
            }
            catch (BKSSQLException ie) {
                throw new BKSException("退貨回滾失敗");
            }
        }
    }

    /**
     * 供用官受理時的處理
     */
    private void registUkeire(BKSManager manager) throws BKSSQLException, BKSException {
        Integer writeStatus = new Integer(BkCode.SS_COMPLETE); // 寫入證明書的狀態
        Integer writeKanriboSeiriKbn = new Integer(BkCode.KAN_SYUTOKU_HENKAN_KYOUYOU); // 管理簿整理區分
        Integer writeKyouyouboSeiriKbn = new Integer(BkCode.KYOU_UKEIRE_KYOUYOU);    // 供用簿整理區分

        Enumeration enum1 = null;
        Hashtable<String, BigDecimal> matomeHash = new Hashtable<String, BigDecimal>();

        BkCommonManager commonManager = manager.getBkCommonManager();
        LinkManager linkManager = manager.getLinkManager();

        try {
            OperatorManager operatorManager = manager.getOperatorManager();
            OperatorInfo kyouyouOp = operatorManager.getOpInfo(docParent.getKyouyoukanCd());
            Object[] nendo = BKSUtil.getVariousDate(manager, docParent.getKyouyouYmd());

            docParent.modify(writeStatus);
            enum1 = docParent.getMeisai().elements();
            while (enum1.hasMoreElements()) {
                DocMeisai rec = (DocMeisai) enum1.nextElement();
                rec.modify(docCd, seiriKbn, oper.opCd, writeStatus);
            }

            KobetuManager kobetuManager = manager.getKobetuManager();
            KanriboManager kanriboManager = manager.getKanriboManager();
            KyouyouboManager kyouyouboManager = manager.getKyouyouboManager();

            MakeBookRecord makeBookRecord = new MakeBookRecord(
                manager,
                seiriKbn,
                writeKanriboSeiriKbn,
                writeKyouyouboSeiriKbn,
                docParent.getKanrikanCd(),
                docParent.getKyouyoukanCd(),
                docParent.getKanriDocNo(),
                docParent.getWatasiGyoushaCd(),
                null,
                null,
                docParent.getKonkyo(),
                null,
                null
            );

            enum1 = docParent.getMeisai().elements();
            while (enum1.hasMoreElements()) {
                HenpinMeisai rec = (HenpinMeisai) enum1.nextElement();
                int nHenpinSu = rec.getHenpinSuryo().intValue();
                if (nHenpinSu > 0) {
                    BigDecimal idoKakaku = rec.getTanka().multiply(new BigDecimal(rec.getHenpinSuryo().toString()));
                    BigDecimal zeiGaku = rec.getTanka().multiply(new BigDecimal(rec.getHenpinSuryo().toString()));
                    // 創建管理簿、供用簿記錄
                    BigDecimal kanriboCd = commonManager.getNewKanriboCd();
                    Kanribo kanribo = makeBookRecord.makeKanriboUke(
                        rec.getBuppinCd(),
                        rec.getShoumouKbn(),
//                      rec.getShutokuYmd(),
                        docParent.getKanriYmd(),
                        rec.getHenpinSuryo(),
                        null,
                        idoKakaku,
                        rec.getHinsituKikaku(),
                        zeiGaku
                    );
                    kanribo.setKanriboCd(kanriboCd);
                    kanriboManager.add2(kanribo, oper.opCd);

                    BigDecimal kyouyouboCd = commonManager.getNewKyouyouboCd();
                    Kyouyoubo kyouyoubo = makeBookRecord.makeKyouyouboKyouyou(
                        rec.getBuppinCd(),
                        rec.getShoumouKbn(),
                        rec.getSiyoushaCd(),
//                      rec.getShutokuYmd(),
                        docParent.getKanriYmd(),
                        rec.getHenpinSuryo(),
                        null,
                        idoKakaku,
                        rec.getHinsituKikaku(),
                        zeiGaku
                    );
                    kyouyoubo.setKyouyouboCd(kyouyouboCd);
                    kyouyouboManager.add2(kyouyoubo, oper.opCd);

                    // 以下對明細進行“まとめ碼”的處理,同 registTouroku 中類似
                    BigDecimal matomeCd = null;
                    String matomeKbn = rec.getBuppinCd() + "," + rec.getHinsituKikaku() + "," +
                                       rec.getTanka().toString() + "," + rec.getShoumouKbn() + "," +
                                       rec.getShutokuYmd().toString();
                    if (matomeHash.get(matomeKbn) != null) {
                        matomeCd = matomeHash.get(matomeKbn);
                    }
                    else {
                        matomeCd = commonManager.getNewMatomeCd();
                        matomeHash.put(matomeKbn, matomeCd);
                    }

                    // 更新個別數據
                    BigDecimal[] kobetuCdArray = rec.getKobetuCdArray();
                    int j = 0;
                    for (int i = 0; i < nHenpinSu; i++) {
                        Kobetu kobetu = kobetuManager.findByPrimaryKey(kobetuCdArray[j]);
                        j++;
                        i = i + kobetu.getKosuu().intValue() - 1;
                        kobetu.setSiyoushaCd(rec.getSiyoushaCd());
                        kobetu.setKanriSts(rec.getSiyoushaCd() == null ? new Integer(BkCode.KS_KYOUYOU_HOKAN) : new Integer(BkCode.KS_KYOUYOU_KYOUYOU));

                        int retry = BkCode.RETRY_CNT;
                        while (true) {
                            try {
                                kobetu.setHontaiNo(kobetuManager.getNextHontaiNo(kyouyouOp.getOpCd(), (Integer) nendo[2]));
                                kobetuManager.modify(kobetu, oper.opCd);
                                break;
                            }
                            catch (SQLException e) {
                                if (e.getErrorCode() == 1) {
                                    if (--retry <= 0)
                                        throw new BKSSQLException("getNextHontaiNo failure");
                                }
                            }
                        }
                        // 向修正鏈接表中插入數據
                        Link link = new Link();
                        link.setKobetuCd(kobetu.getKobetuCd());
                        link.setMatomeCdUke(matomeCd);
                        link.setKanriboCdUke(kanriboCd);
                        link.setKyouyouboCdUke(kyouyouboCd);
                        linkManager.add(link, oper.opCd, kobetu.getBuppinCd());
                    }
                }
            }

            commonManager.executeCommit();
        }
        catch (BKSSQLException e) {
            logger.log(e);
            try {
                commonManager.executeRollback();
                throw new BKSException("供用官受理回滾");
            }
            catch (BKSSQLException ie) {
                throw new BKSException("供用官受理回滾失敗");
            }
        }
        catch (BKSException e) {
            logger.log(e);
            try {
                commonManager.executeRollback();
                throw new BKSException("供用官受理回滾");
            }
            catch (BKSSQLException ie) {
                throw new BKSException("供用官受理回滾失敗");
            }
        }
    }

    /**
     * 檢查交付數量與退貨數量,若仍有剩余,則創建新的退貨單
     * 
     * 參數 henpinFlg 指示:若存在供用官受理待命則為 true,否則為 false(即管理官保管情況)
     */
    private void createNewHenpinDoc(BKSManager manager, boolean henpinFlg) throws BKSSQLException, BKSException {
        logger.log("createNewHenpinDoc henpinFlg = '" + henpinFlg + "'");

        KobetuManager kobetuManager = manager.getKobetuManager();
        // 新建用於存放“剩余”物品和“使用”物品的管理對象
        KobetuListManager kobetuListManager_siyou = new KobetuListManager(seiriKbn);
        KobetuListManager kobetuListManager_zan = new KobetuListManager(seiriKbn);
        Enumeration enum1 = docParent.getMeisai().elements(); // 獲取明細數據
        BkCommonManager commonManager = manager.getBkCommonManager();
        LinkManager linkManager = manager.getLinkManager();

        Hashtable<String, BigDecimal> matomeHash = new Hashtable<String, BigDecimal>();
        
        // 2010.3.15 增減功能相關:開始
        ZougenRirekiManager zougenRirekiManager = manager.getZougenRirekiManager();
        NendoManager nendoManager = manager.getNendoManager();
        OperatorManager operatorManager = manager.getOperatorManager();
        DbUtil dbutil = new DbUtil(session, manager.getLogger());
        // 用於鏈接個別物品與管理簿的哈希表
        Hashtable<BigDecimal, BigDecimal> kobetuKanriboLinkHash = new Hashtable<BigDecimal, BigDecimal>();
        // 2010.3.15 增減功能相關:結束
        
        while (enum1.hasMoreElements()) {
            HenpinMeisai rec = (HenpinMeisai) enum1.nextElement();
            BigDecimal[] kobetuCdArray = rec.getKobetuCdArray();
            
            // 重新構造用於緩存“まとめ碼”的哈希表(局部變量)
            KobetuListManager kobetuListManager_sz = new KobetuListManager(seiriKbn);
            
            // 生成“まとめ區分”:由物品代碼、質量規格、單價、消耗區分和取得日期組成
            BigDecimal matomeCd = null;
            String matomeKbn = rec.getBuppinCd() + "," + rec.getHinsituKikaku() + "," +
                               rec.getTanka().toString() + "," + rec.getShoumouKbn() + "," +
                               rec.getShutokuYmd().toString();
            // 如果緩存中已有相同的 key,則直接取出,否則生成新的並放入緩存
            if (matomeHash.get(matomeKbn) != null) {
                matomeCd = matomeHash.get(matomeKbn);
            }
            else {
                matomeCd = commonManager.getNewMatomeCd();
                matomeHash.put(matomeKbn, matomeCd);
            }
            
            // ★★★ 開始:退貨處理(返品) ★★★
            int kosuuFlg = 1;        // 剩余個數
            Kobetu kobetu = null;    // 當前個別物品
            boolean chkflg1 = true;  // 標記1:是否轉向下一個個別物品
            boolean chkflg2 = true;  // 標記2:用於區分處理A與處理B
            int k = 0;               // 序號變量
            // 對交付數量進行循環處理
            for (int i = 0; i < rec.getKoufuSuryo().intValue(); i++) {
                if (chkflg1) {
                    kobetu = kobetuManager.findByPrimaryKey(kobetuCdArray[k]);
                    kosuuFlg = kobetu.getKosuu().intValue();
                    chkflg1 = false;
                }
                // 如果剩余個數恰好為 1
                if (kosuuFlg == 1) {
                    // 如果退貨數量已超出,則進入處理B,將物品放入剩余列表
                    if (i >= rec.getHenpinSuryo().intValue()) {
                        if (chkflg2) {
                            if (i - rec.getHenpinSuryo().intValue() + 1 == kobetu.getKosuu().intValue()) {
                                kobetuListManager_sz.add(kobetu);
                            }
                            // 若需要拆分(分割)處理時
                            else {
                                // 分割物品 A(部分退貨的物品)
                                Kobetu newKobetu = kobetuManager.findByPrimaryKey(kobetu.getKobetuCd());
                                int bunkatuHenpin = newKobetu.getKosuu().intValue() - i + rec.getHenpinSuryo().intValue() - 1;
                                int bunkatuSiyouZan = i - rec.getHenpinSuryo().intValue() + 1;
                                if (newKobetu.getPKobetuCd() == null) {
                                    // ★★★ 分割物品處理開始 ★★★
                                    newKobetu.setKosuu(new Integer(bunkatuHenpin));
                                    kobetuManager.modify(newKobetu, oper.opCd);
                                    BigDecimal newKobetuCd = commonManager.getNewKobetuCd();
                                    // 分割物品 B(不退貨的物品,新生成的)
                                    kobetu.setKosuu(new Integer(bunkatuSiyouZan));
                                    kobetu.setKanriSts(new Integer(13));
                                    kobetu.setHontaiNo(null);
                                    kobetu.setKobetuCd(newKobetuCd);
                                    kobetuManager.add(kobetu, oper.opCd);
                                    kobetuListManager_sz.add(kobetu);
                                    // 針對增減功能的處理
                                    if (kobetu.getZougenKbn().equals("1")) {
                                        List<ZougenRireki> zougenRirekiList = new ArrayList<ZougenRireki>();
                                        zougenRirekiList = zougenRirekiManager.getZougenRirekiDataByKobetuCd(newKobetu.getKobetuCd());
                                        Iterator ite = zougenRirekiList.iterator();
                                        while (ite.hasNext()) {
                                            ZougenRireki zougenRireki = (ZougenRireki) ite.next();
                                            zougenRireki.setKosuu(new Integer(bunkatuHenpin));
                                            zougenRirekiManager.zougenRirekiModifyKosuu(zougenRireki, manager.getAuthOperator().opCd);
                                            zougenRireki.setZougenId(dbutil.getNewZougenId());
                                            zougenRireki.setKobetuCd(kobetu.getKobetuCd());
                                            zougenRireki.setKosuu(new Integer(bunkatuSiyouZan));
                                            zougenRirekiManager.zougenRirekiAdd(zougenRireki, manager.getAuthOperator().opCd);
                                        }
                                    }
                                    logger.log("newKobetu.getKobetuCd()上 = '" + newKobetu.getKobetuCd() + "'");
                                    // 將分割物品 A 的鏈接覆制給物品 B
                                    Enumeration enumLink = linkManager.kobetuElements(newKobetu.getKobetuCd().toString());
                                    while (enumLink.hasMoreElements()) {
                                        Link link = (Link) enumLink.nextElement();
                                        if (rec.kanriboCd_henpin != null && link.getKanriboCdUke() != null) {
                                            if (link.getKanriboCdUke().compareTo(rec.kanriboCd_henpin) == 0) {
                                                continue;
                                            }
                                        }
                                        link.setKobetuCd(newKobetuCd);
                                        linkManager.add(link, oper.opCd, newKobetu.getBuppinCd());
                                    }
                                    linkManager.setZero();
                                    // ★★★ 分割物品處理結束 ★★★
                                }
                                else if (newKobetu.getPKobetuCd() != null) {
                                    // ★★★ 本體分割處理開始 ★★★
                                    Kobetu kobetuHontai = kobetuManager.findByPrimaryKey(newKobetu.getPKobetuCd());
                                    kobetuHontai.setKosuu(new Integer(bunkatuHenpin));
                                    kobetuManager.modify(kobetuHontai, oper.opCd);
                                    BigDecimal newKobetuCdHontai = commonManager.getNewKobetuCd();
                                    kobetuHontai.setKosuu(new Integer(bunkatuSiyouZan));
                                    kobetuHontai.setHontaiNo(null);
                                    kobetuHontai.setKobetuCd(newKobetuCdHontai);
                                    kobetuManager.add(kobetuHontai, oper.opCd);
                                    if (kobetuHontai.getZougenKbn().equals("1")) {
                                        List<ZougenRireki> zougenRirekiList = new ArrayList<ZougenRireki>();
                                        zougenRirekiList = zougenRirekiManager.getZougenRirekiDataByKobetuCd(newKobetu.getPKobetuCd());
                                        Iterator ite = zougenRirekiList.iterator();
                                        while (ite.hasNext()) {
                                            ZougenRireki zougenRireki = (ZougenRireki) ite.next();
                                            zougenRireki.setKosuu(new Integer(bunkatuHenpin));
                                            zougenRirekiManager.zougenRirekiModifyKosuu(zougenRireki, manager.getAuthOperator().opCd);
                                            zougenRireki.setZougenId(dbutil.getNewZougenId());
                                            zougenRireki.setKobetuCd(kobetuHontai.getKobetuCd());
                                            zougenRireki.setKosuu(new Integer(bunkatuSiyouZan));
                                            zougenRirekiManager.zougenRirekiAdd(zougenRireki, manager.getAuthOperator().opCd);
                                        }
                                    }
                                    Enumeration enumLinkHontai = linkManager.kobetuElements(newKobetu.getPKobetuCd().toString());
                                    while (enumLinkHontai.hasMoreElements()) {
                                        Link link = (Link) enumLinkHontai.nextElement();
                                        link.setKobetuCd(kobetuHontai.getKobetuCd());
                                        linkManager.add(link, oper.opCd, newKobetu.getBuppinCd());
                                    }
                                    linkManager.setZero();
                                    // ★★★ 本體分割處理結束 ★★★
                                    // ★★★ 開始:虛擬物品分割處理 ★★★
                                    Enumeration<Object> enumDummyKobetu = kobetuManager.getChildKobetuElements(newKobetu.getPKobetuCd());
                                    while (enumDummyKobetu.hasMoreElements()) {
                                        Kobetu dummyKobetu = (Kobetu) enumDummyKobetu.nextElement();
                                        BigDecimal dummyKobetuCd = dummyKobetu.getKobetuCd();
                                        boolean kobetuHenpinJudgeFlg = false;
                                        if (dummyKobetuCd.compareTo(newKobetu.getKobetuCd()) == 0) {
                                            kobetuHenpinJudgeFlg = true;
                                        }
                                        // 調整個別物品數量
                                        dummyKobetu.setKosuu(new Integer(bunkatuHenpin));
                                        kobetuManager.modify(dummyKobetu, manager.getAuthOperator().opCd);
                                        // 新生成個別代碼
                                        BigDecimal newDummyKobetuCd = commonManager.getNewKobetuCd();
                                        dummyKobetu.setKobetuCd(newDummyKobetuCd);
                                        dummyKobetu.setKosuu(new Integer(bunkatuSiyouZan));
                                        dummyKobetu.setHontaiNo(null);
                                        dummyKobetu.setPKobetuCd(newKobetuCdHontai); // P個別代碼設置為本體的代碼
                                        if (kobetuHenpinJudgeFlg) {
                                            dummyKobetu.setKanriSts(new Integer(13));
                                        }
                                        kobetuManager.add3(dummyKobetu, manager.getAuthOperator().opCd);
                                        if (kobetuHenpinJudgeFlg) {
                                            kobetuListManager_sz.add(dummyKobetu);
                                            if (rec.kanriboCd_siyou != null) {
                                                Link link = new Link();
                                                link.setKobetuCd(dummyKobetu.getKobetuCd());
                                                link.setMatomeCdHarai(matomeCd);
                                                link.setKanriboCdHarai(rec.kanriboCd_siyou);
                                                linkManager.add(link, oper.opCd, newKobetuSiyou.getBuppinCd());
                                                kobetuKanriboLinkHash.put(dummyKobetu.getKobetuCd(), rec.kanriboCd_siyou);
                                            }
                                        }
                                        if (dummyKobetu.getZougenKbn().equals("1")) {
                                            List<ZougenRireki> zougenRirekiDummyList = new ArrayList<ZougenRireki>();
                                            zougenRirekiDummyList = zougenRirekiManager.getZougenRirekiDataByKobetuCd(dummyKobetuCd);
                                            Iterator ite = zougenRirekiDummyList.iterator();
                                            while (ite.hasNext()) {
                                                ZougenRireki zougenRirekiDummy = (ZougenRireki) ite.next();
                                                zougenRirekiDummy.setKosuu(new Integer(bunkatuSiyou));
                                                zougenRirekiManager.zougenRirekiModifyKosuu(zougenRirekiDummy, manager.getAuthOperator().opCd);
                                                zougenRirekiDummy.setZougenId(dbutil.getNewZougenId());
                                                zougenRirekiDummy.setKobetuCd(newDummyKobetuCd);
                                                zougenRirekiDummy.setKosuu(new Integer(bunkatuZan));
                                                zougenRirekiManager.zougenRirekiAdd(zougenRirekiDummy, manager.getAuthOperator().opCd);
                                            }
                                        }
                                        // 開始:鏈接數據覆制處理
                                        Enumeration enumDummyLink = linkManager.kobetuElements(dummyKobetuCd.toString());
                                        while (enumDummyLink.hasMoreElements()) {
                                            Link link = (Link) enumDummyLink.nextElement();
                                            if (rec.kanriboCd_siyou != null && link.getKanriboCdHarai() != null) {
                                                if (link.getKanriboCdHarai().compareTo(rec.kanriboCd_siyou) == 0) {
                                                    continue;
                                                }
                                            }
                                            link.setKobetuCd(newDummyKobetuCd);
                                            linkManager.add(link, manager.getAuthOperator().opCd, dummyKobetu.getBuppinCd());
                                        }
                                        linkManager.setZero();
                                    }
                                    // ★★★ 虛擬物品分割處理結束 ★★★
                                    kobetuManager.setZero();
                                    // 20100215 p_kobetu_cd 相關處理結束
                                }
                            }
                            // ★★★ 退貨用物品分割處理結束 ★★★
                            chkflg2 = false;
                        }
                        // 如果超過退貨數量,直接將剩余個別數據加入
                        else {
                            kobetuListManager_zan.add(kobetuList.get());
                        }
                    }
                    // 在處理完一批個別物品後,重新置標記,以便讀取下一個個別物品
                    chkflg1 = true;
                    k++;
                }
                // 每次循環後減少剩余個數標記
                kosuuFlg--;
            }
            // ★★★ 退貨處理結束 ★★★

            // ★★★ 開始:材料使用處理 ★★★
            // 此處對交付數量與退貨數量之差進行處理,將結果分別加入“使用”和“剩余”的列表
            Enumeration enumKobetu = kobetuListManager_sz.kobetuElements();
            kosuuFlg = 1;
            chkflg1 = true;
            chkflg2 = true;
            k = 0;
            KobetuList kobetuList = null;

            if (enumKobetu.hasMoreElements()) {
                for (int i = 0; i < (rec.getKoufuSuryo().intValue() - rec.getHenpinSuryo().intValue()); i++) {
                    if (chkflg1) {
                        kobetuList = (KobetuList) enumKobetu.nextElement();
                        kosuuFlg = kobetuList.getKosuu().intValue();
                        chkflg1 = false;
                    }
                    if (kosuuFlg == 1) {
                        if (i >= rec.getSiyouSuryo().intValue()) {
                            if (chkflg2) {
                                if (i - rec.getSiyouSuryo().intValue() + 1 == kobetuList.getKosuu().intValue()) {
                                    kobetuListManager_zan.add(kobetuList.get());
                                }
                                // 若需拆分處理
                                else {
                                    Kobetu newKobetuSiyou = kobetuManager.findByPrimaryKey(kobetuList.get().getKobetuCd());
                                    int bunkatuSiyou = newKobetuSiyou.getKosuu().intValue() - i + rec.getSiyouSuryo().intValue() - 1;
                                    int bunkatuZan = i - rec.getSiyouSuryo().intValue() + 1;
                                    if (newKobetuSiyou.getPKobetuCd() == null) {
                                        // ★★★ 分割處理開始(使用部分) ★★★
                                        newKobetuSiyou.setKosuu(new Integer(bunkatuSiyou));
                                        newKobetuSiyou.setKanriSts(new Integer(30));
                                        kobetuManager.modify(newKobetuSiyou, oper.opCd);
                                        kobetuListManager_siyou.add(newKobetuSiyou);
                                        if (rec.kanriboCd_siyou != null) {
                                            Link link = new Link();
                                            link.setKobetuCd(kobetuList.get().getKobetuCd());
                                            link.setMatomeCdHarai(matomeCd);
                                            link.setKanriboCdHarai(rec.kanriboCd_siyou);
                                            linkManager.add(link, oper.opCd, newKobetuSiyou.getBuppinCd());
                                            kobetuKanriboLinkHash.put(kobetuList.get().getKobetuCd(), rec.kanriboCd_siyou);
                                        }
                                        BigDecimal newKobetuCdZan = commonManager.getNewKobetuCd();
                                        kobetuList.setKosuu(new Integer(bunkatuZan));
                                        kobetuList.setKanriSts(new Integer(13));
                                        kobetuList.setHontaiNo(null);
                                        kobetuList.setKobetuCd(newKobetuCdZan);
                                        kobetuManager.add(kobetuList.get(), oper.opCd);
                                        kobetuListManager_zan.add(kobetuList.get());
                                        if (newKobetuSiyou.getZougenKbn().equals("1")) {
                                            List<ZougenRireki> zougenRirekiListSiyou = new ArrayList<ZougenRireki>();
                                            zougenRirekiListSiyou = zougenRirekiManager.getZougenRirekiDataByKobetuCd(newKobetuSiyou.getKobetuCd());
                                            Iterator ite = zougenRirekiListSiyou.iterator();
                                            while (ite.hasNext()) {
                                                ZougenRireki zougenRirekiSiyou = (ZougenRireki) ite.next();
                                                zougenRirekiSiyou.setKosuu(new Integer(bunkatuSiyou));
                                                zougenRirekiManager.zougenRirekiModifyKosuu(zougenRirekiSiyou, manager.getAuthOperator().opCd);
                                                zougenRirekiSiyou.setZougenId(dbutil.getNewZougenId());
                                                zougenRirekiSiyou.setKobetuCd(newKobetuCdZan);
                                                zougenRirekiSiyou.setKosuu(new Integer(bunkatuZan));
                                                zougenRirekiManager.zougenRirekiAdd(zougenRirekiSiyou, manager.getAuthOperator().opCd);
                                            }
                                        }
                                        Enumeration enumLinkSiyou = linkManager.kobetuElements(newKobetuSiyou.getKobetuCd().toString());
                                        while (enumLinkSiyou.hasMoreElements()) {
                                            Link link = (Link) enumLinkSiyou.nextElement();
                                            if (rec.kanriboCd_siyou != null && link.getKanriboCdHarai() != null) {
                                                if (link.getKanriboCdHarai().compareTo(rec.kanriboCd_siyou) == 0) {
                                                    continue;
                                                }
                                            }
                                            link.setKobetuCd(newKobetuCdZan);
                                            linkManager.add(link, oper.opCd, kobetuList.getBuppinCd());
                                        }
                                        linkManager.setZero();
                                        // ★★★ 分割處理結束(使用部分) ★★★
                                    }
                                    else if (newKobetuSiyou.getPKobetuCd() != null) {
                                        // ★★★ 本體分割處理開始(使用部分) ★★★
                                        Kobetu kobetuSiyouHontai = kobetuManager.findByPrimaryKey(newKobetuSiyou.getPKobetuCd());
                                        kobetuSiyouHontai.setKosuu(new Integer(bunkatuSiyou));
                                        kobetuManager.modify(kobetuSiyouHontai, oper.opCd);
                                        BigDecimal newKobetuCdHontai = commonManager.getNewKobetuCd();
                                        kobetuSiyouHontai.setKosuu(new Integer(bunkatuZan));
                                        kobetuSiyouHontai.setHontaiNo(null);
                                        kobetuSiyouHontai.setKobetuCd(newKobetuCdHontai);
                                        kobetuManager.add(kobetuSiyouHontai, oper.opCd);
                                        if (kobetuSiyouHontai.getZougenKbn().equals("1")) {
                                            List<ZougenRireki> zougenRirekiList = new ArrayList<ZougenRireki>();
                                            zougenRirekiList = zougenRirekiManager.getZougenRirekiDataByKobetuCd(newKobetuSiyou.getPKobetuCd());
                                            Iterator ite = zougenRirekiList.iterator();
                                            while (ite.hasNext()) {
                                                ZougenRireki zougenRireki = (ZougenRireki) ite.next();
                                                zougenRireki.setKosuu(new Integer(bunkatuSiyou));
                                                zougenRirekiManager.zougenRirekiModifyKosuu(zougenRireki, manager.getAuthOperator().opCd);
                                                zougenRireki.setZougenId(dbutil.getNewZougenId());
                                                zougenRireki.setKobetuCd(kobetuSiyouHontai.getKobetuCd());
                                                zougenRireki.setKosuu(new Integer(bunkatuZan));
                                                zougenRirekiManager.zougenRirekiAdd(zougenRireki, manager.getAuthOperator().opCd);
                                            }
                                        }
                                        Enumeration enumLinkHontai = linkManager.kobetuElements(newKobetuSiyou.getPKobetuCd().toString());
                                        while (enumLinkHontai.hasMoreElements()) {
                                            Link link = (Link) enumLinkHontai.nextElement();
                                            link.setKobetuCd(kobetuSiyouHontai.getKobetuCd());
                                            linkManager.add(link, oper.opCd, newKobetuSiyou.getBuppinCd());
                                        }
                                        linkManager.setZero();
                                        // ★★★ 本體分割處理結束(使用部分) ★★★
                                        // ★★★ 開始:虛擬分割處理(使用部分) ★★★
                                        Enumeration<Object> enumDummyKobetu = kobetuManager.getChildKobetuElements(newKobetuSiyou.getPKobetuCd());
                                        while (enumDummyKobetu.hasMoreElements()) {
                                            Kobetu dummyKobetu = (Kobetu) enumDummyKobetu.nextElement();
                                            BigDecimal dummyKobetuCd = dummyKobetu.getKobetuCd();
                                            boolean kobetuSiyouJudgeFlg = false;
                                            if (dummyKobetuCd.compareTo(newKobetuSiyou.getKobetuCd()) == 0) {
                                                kobetuSiyouJudgeFlg = true;
                                            }
                                            dummyKobetu.setKosuu(new Integer(bunkatuSiyou));
                                            if (kobetuSiyouJudgeFlg) {
                                                dummyKobetu.setKanriSts(30);
                                            }
                                            kobetuManager.modify(dummyKobetu, manager.getAuthOperator().opCd);
                                            BigDecimal newDummyKobetuCd = commonManager.getNewKobetuCd();
                                            if (kobetuSiyouJudgeFlg) {
                                                kobetuListManager_siyou.add(dummyKobetu);
                                                if (rec.kanriboCd_siyou != null) {
                                                    Link link = new Link();
                                                    link.setKobetuCd(dummyKobetu.getKobetuCd());
                                                    link.setMatomeCdHarai(matomeCd);
                                                    link.setKanriboCdHarai(rec.kanriboCd_siyou);
                                                    linkManager.add(link, oper.opCd, newKobetuSiyou.getBuppinCd());
                                                    kobetuKanriboLinkHash.put(dummyKobetu.getKobetuCd(), rec.kanriboCd_siyou);
                                                }
                                                Kobetu zanKobetu = kobetuManager.findByPrimaryKey(dummyKobetuCd);
                                                zanKobetu.setKobetuCd(newDummyKobetuCd);
                                                zanKobetu.setKosuu(new Integer(bunkatuZan));
                                                zanKobetu.setHontaiNo(null);
                                                zanKobetu.setKanriSts(new Integer(13));
                                                zanKobetu.setPKobetuCd(newKobetuCdHontai);
                                                kobetuManager.add3(zanKobetu, manager.getAuthOperator().opCd);
                                                kobetuListManager_zan.add(zanKobetu);
                                            }
                                            else {
                                                dummyKobetu.setKobetuCd(newDummyKobetuCd);
                                                dummyKobetu.setKosuu(new Integer(bunkatuZan));
                                                dummyKobetu.setHontaiNo(null);
                                                dummyKobetu.setPKobetuCd(newKobetuCdHontai);
                                                kobetuManager.add3(dummyKobetu, manager.getAuthOperator().opCd);
                                            }
                                            if (dummyKobetu.getZougenKbn().equals("1")) {
                                                List<ZougenRireki> zougenRirekiDummyList = new ArrayList<ZougenRireki>();
                                                zougenRirekiDummyList = zougenRirekiManager.getZougenRirekiDataByKobetuCd(dummyKobetuCd);
                                                Iterator ite = zougenRirekiDummyList.iterator();
                                                while (ite.hasNext()) {
                                                    ZougenRireki zougenRirekiDummy = (ZougenRireki) ite.next();
                                                    zougenRirekiDummy.setKosuu(new Integer(bunkatuSiyou));
                                                    zougenRirekiManager.zougenRirekiModifyKosuu(zougenRirekiDummy, manager.getAuthOperator().opCd);
                                                    zougenRirekiDummy.setZougenId(dbutil.getNewZougenId());
                                                    zougenRirekiDummy.setKobetuCd(newDummyKobetuCd);
                                                    zougenRirekiDummy.setKosuu(new Integer(bunkatuZan));
                                                    zougenRirekiManager.zougenRirekiAdd(zougenRirekiDummy, manager.getAuthOperator().opCd);
                                                }
                                            }
                                            Enumeration enumDummyLink = linkManager.kobetuElements(dummyKobetuCd.toString());
                                            while (enumDummyLink.hasMoreElements()) {
                                                Link link = (Link) enumDummyLink.nextElement();
                                                if (rec.kanriboCd_siyou != null && link.getKanriboCdHarai() != null) {
                                                    if (link.getKanriboCdHarai().compareTo(rec.kanriboCd_siyou) == 0) {
                                                        continue;
                                                    }
                                                }
                                                link.setKobetuCd(newDummyKobetuCd);
                                                linkManager.add(link, manager.getAuthOperator().opCd, dummyKobetu.getBuppinCd());
                                            }
                                            linkManager.setZero();
                                        }
                                        // ★★★ 虛擬分割處理結束(使用部分) ★★★
                                        kobetuManager.setZero();
                                    }
                                    // 20100215 p_kobetu_cd 相關處理結束
                                }
                            }
                            // ★★★ 材料使用物品分割處理結束 ★★★
                            chkflg2 = false;
                        }
                        // 超過使用數量後,將剩余數據直接放入剩余列表
                        else {
                            kobetuListManager_zan.add(kobetuList.get());
                        }
                    }
                    // 使用數量未超前時,更新狀態並將數據加入使用列表
                    else {
                        kobetuList.setKanriSts(new Integer(30));
                        kobetuManager.modify(kobetuList.get(), oper.opCd);
                        kobetuListManager_siyou.add(kobetuList.get());
                        if (rec.kanriboCd_siyou != null) {
                            Link link = new Link();
                            link.setKobetuCd(kobetuList.get().getKobetuCd());
                            link.setMatomeCdHarai(matomeCd);
                            link.setKanriboCdHarai(rec.kanriboCd_siyou);
                            linkManager.add(link, oper.opCd, kobetuList.getBuppinCd());
                            kobetuKanriboLinkHash.put(kobetuList.get().getKobetuCd(), rec.kanriboCd_siyou);
                        }
                    }
                    chkflg1 = true;
                    k++;
                }
                kosuuFlg--;
            }
        }
        
        // 更新使用物品狀態:將所有使用物品標記為“30 處理完成”
        enum1 = kobetuListManager_siyou.kobetuElements();
        while (enum1.hasMoreElements()) {
            KobetuList kobetu = (KobetuList) enum1.nextElement();
            kobetu.setKanriSts(new Integer(30));
            kobetu.setHaraidasiYmd(docParent.getKanriYmd());
            // 更新減區分為 63(材料使用分離減)
            kobetu.setGenKbn(new Integer("63"));
            kobetuManager.modify(kobetu.get(), oper.opCd);
            // 針對增減功能的處理:如果該個別物品符合條件,則在增減歷史表中記錄
            if (kobetu.getZougenKbn().equals("1")) {
                ZougenRireki zougenRireki = new ZougenRireki();
                Date sysDateYmd = EtcFuncUtil.getSysDate();
                Integer sysDateNendo = nendoManager.findByDate(sysDateYmd).getNendo();
                Integer seiriKbn = 0;
                Integer gobyuuSeiriKbn = 0;
                Date ymd = null;
                if (kobetu.getGenKbn() != null) {
                    ymd = kobetu.getHaraidasiYmd();
                    seiriKbn = kobetu.getGenKbn();
                    gobyuuSeiriKbn = BkCode.GEN_Z_GOBYUUTEISEI;
                    zougenRireki.setRiyuu(kobetu.getGenRiyuu());
                }
                else {
                    ymd = kobetu.getShutokuYmd();
                    seiriKbn = kobetu.getZouKbn();
                    gobyuuSeiriKbn = BkCode.ZOU_Z_GOBYUUTEISEI;
                    zougenRireki.setRiyuu(kobetu.getZouRiyuu());
                }
                Integer kobetuNendo = nendoManager.findByDate(ymd).getNendo();
                Integer gobyuuJudgeFlg = dbutil.getGobyuuJudgeFlg(sysDateNendo, kobetuNendo);
                zougenRireki.setZougenId(dbutil.getNewZougenId());
                zougenRireki.setSishoCd(operatorManager.getOpInfo(kobetu.getKanrikanCd()).getSishoCd());
                zougenRireki.setKobetuCd(kobetu.getKobetuCd());
                zougenRireki.setBuppinCd(kobetu.getBuppinCd());
                zougenRireki.setShuhinmokuCd(EtcFuncUtil.getShuhinmokuCd(kobetu.getBuppinCd()));
                zougenRireki.setTanka(kobetu.getTanka());
                zougenRireki.setKosuu(kobetu.getKosuu());
                if (gobyuuJudgeFlg == 1) {
                    zougenRireki.setSeiriKbn(seiriKbn);
                    zougenRireki.setYmd(ymd);
                    zougenRireki.setGobyuuFlg("0");
                }
                else if (gobyuuJudgeFlg == 2) {
                    zougenRireki.setSeiriKbn(gobyuuSeiriKbn);
                    zougenRireki.setYmd(nendoManager.getNendoStart(sysDateNendo));
                    zougenRireki.setGobyuuFlg("1");
                }
                else if (gobyuuJudgeFlg == 3) {
                    zougenRireki.setSeiriKbn(gobyuuSeiriKbn);
                    zougenRireki.setYmd(nendoManager.getNendoStart(sysDateNendo - 1));
                    zougenRireki.setGobyuuFlg("1");
                }
                zougenRireki.setDocCd(docParent.getDocCd());
                zougenRireki.setKanriboCd(kobetuKanriboLinkHash.get(kobetu.getKobetuCd()));
                zougenRireki.setDelFlg("0");
                zougenRirekiManager.zougenRirekiAdd(zougenRireki, oper.opCd);
            }
        }
        
        // ★★★ 結束:材料使用處理 ★★★

        // 若存在剩余物品,則創建新的退貨單用於處理剩余部分
        enum1 = kobetuListManager_zan.meisaiElements();
        if (enum1.hasMoreElements()) {
            HenpinDoc docwait = new HenpinDoc(session, logger, new Integer(BkCode.SK_KANRI_SYUTOKU_HENKAN), oper.opCd);
            Long newWaitDocCd = commonManager.getNewDocCd();
            docwait.setUketukeYmd(docParent.getUketukeYmd());
            docwait.setKanrikanCd(docParent.getKanrikanCd());
            docwait.setKyouyoukanCd(docParent.getKyouyoukanCd());
            docwait.setKanriYmd(docParent.getKanriYmd());
            if (docParent.getKanriDocNo() != null)
                docwait.setKanriDocNo(docParent.getOriginalKanriDocNo());
            docwait.setWatasiGyoushaCd(docParent.getWatasiGyoushaCd());
            docwait.setKeiyakuYmd(docParent.getKeiyakuYmd());
            docwait.setKeiyakuNo(docParent.getKeiyakuNo());
            
            KobetuRirekiManager kobetuRirekiManager = manager.getKobetuRirekiManager();
            KobetuRireki rireki = new KobetuRireki();
            rireki.setDocCd(newWaitDocCd);

            Vector<Object> v = new Vector<Object>();
            int i = 0;
            while (enum1.hasMoreElements()) {
                MeisaiList rec = (MeisaiList) enum1.nextElement();
                HenpinMeisai meisai = createHenpinMeisai();
                meisai.setMeisaiNo(new Integer(++i));
                meisai.setBuppinCd(rec.getBuppinCd());
                meisai.setKoufuSuryo(new Integer(rec.kobetuSize()));
                meisai.setSiyouSuryo(new Integer(0));
                meisai.setHenpinSuryo(new Integer(0));
                meisai.setZanSuryo(new Integer(rec.kobetuSize()));
                v.addElement(meisai);

                rireki.setMeisaiNo(new Integer(i));
                Enumeration e = rec.kobetuElements();
                while (e.hasMoreElements()) {
                    KobetuList kobetu = (KobetuList) e.nextElement();
                    rireki.setKobetuCd(kobetu.getKobetuCd());
                    kobetuRirekiManager.add(rireki, oper.opCd);
                }
            }
            docwait.setMeisai(v);
            docwait.write(newWaitDocCd, new Integer(BkCode.SS_KANRIKAN_TOUROKU));
        }
    }
}

分析總結

  1. 關於 matomeCd 的生成與使用
    在 registTouroku 方法中,針對每個明細數據,利用明細中的幾個屬性拼接成“まとめ區分”(matomeKbn)。
    如果緩存(matomeHash)中沒有對應的記錄,則調用 commonManager.getNewMatomeCd() 生成新的 matomeCd 並存入緩存。
    然後在創建個別物品的處理過程中,在生成修正鏈接(Link)的地方將這個 matomeCd 設置到鏈接對象中(link.setMatomeCdUke(matomeCd) 或 link.setMatomeCdHarai(matomeCd))。

    不過正如之前指出的,如果當前明細中:

    • rec.kanriboCd_henpin 為 null(即沒有退貨管理簿記錄),或者

    • 在循環處理個別物品時,條件不滿足(比如剩余個數不為 1),
      則生成的 matomeCd 就可能不會被用到。

    這並非業務邏輯上的錯誤,而是基於延遲加載與緩存的設計,可能會產生少量資源浪費。

  2. 其他部分說明
    除了 registTouroku 方法外,供用官受理(registUkeire)和創建新退貨單(createNewHenpinDoc)中也均有類似的“まとめ碼”生成邏輯。
    我們采用的做法是先通過 key(matomeKbn)檢查緩存,若無則生成;這樣可以確保相同屬性的物品共用同一個 matomeCd,從而減少重覆調用。

  3. 博客結尾
    本文通過對 BkTrSyutokuHenkan.java 中關鍵代碼的逐行注釋和分析,展示了如何通過代碼審查,判斷在調用 commonManager.getNewMatomeCd() 後是否存在未使用的情況。
    盡管在某些分支下生成的 matomeCd 可能不會進入實際的鏈接創建,但從整體設計上看,這是為了避免多次生成同一分組編碼的正常設計,僅會導致極少量的性能浪費,而不會影響功能實現。

This article was last edited at