Oracle Mobile Web Application (MWA) 學習小結(2)- 個性化詳解

MWA個性化說明

Oracle Mobile Supply Chain Application (MSCA) 是Oracle供應鏈管理解決方案的一部分,讓用戶能夠移動操作。使用手持式射頻(RF)設備和叉車安裝射頻掃描儀,保證 數據的準確性和增加流動性,同時便利而又簡化操作,減少人爲錯誤。

知識前提:瞭解並熟悉MWA開發

業務場景:在實際開發中,我們經常會遇到客戶提出如字段默認,自動enter,掃描批次轉物料等PDA常用個性化需求,這些需求雖小,但確實可以減少客戶的工作量和提高客戶操作的效率;

實現方式

  1. 客戶化開發,修改對應客戶化開發適應個性化需求,標準界面修改源碼風險較大;需要反覆修改源碼,重啓端口,較繁瑣(不推薦);
  2. MWA個性化配置界面,個性化配置界面配置字段默認,字段掃描轉換,字段自動enter等相關個性化,方便,快捷,無需重啓端口,顧問都可以設置簡單個性化(推薦);
  3. 修改標準CustomerListener.class文件增加個性化,MWA配置界面還是有一些限制性,比如說:界面增加字段,替換LOV,清除標準字段默認值等,這時,我們就需要修改ORACLE專門爲MWA開發設計的個性化文件實現需求;

MWA個性化配置界面使用說明

配置界面安裝

安裝列表:在這裏插入圖片描述
安裝方式:perl腳本安裝,將code文件夾上傳服務器,perl install.pl安裝,這裏不做詳細說明;安裝完後檢查無效對象並運行insert_global_function.sql。
注意:其中cux,inv,mwa文件要對應安裝到服務器的$OA_JAVA/oracle/apps/路徑下去,其中會替換幾項標準文件,安裝前請備份(備份文件有:inv文件中InvScanManager和mwa文件夾中CustomListener文件)

安裝結束後配置配置文件:
在這裏插入圖片描述
將圖上兩個配置文件在地點層設置爲:是,啓用個性化,其中 MWA:預處理掃描的輸入 是開啓字段預掃描的個性化設置,如:字段的裝換及防呆都是需要開啓這個配置文件。

安裝和配置結束後,重啓端口,以生效個性化配置界面。

個性化配置界面如下:
在這裏插入圖片描述

配置界面使用說明

配置界面是針對功能去實現個性化的,所以頭上是功能選擇項;針對功能個性化配置共分三個TAB頁面,分別是字段,屬性,驗證。

字段
在這裏插入圖片描述
字段TAB頁是我們維護需要對功能界面需要實現個性化功能的所需字段,以前字段相關屬性的設置;字段設置的屬性有:隱藏,必輸,只讀及啓用值來源,其中啓用值來源是配置後面字段分割需要,將在屬性TAB結合實際案例說明。

說明:其中字段名需要我們從PDA各功能登錄界面獲取。
在這裏插入圖片描述
登錄功能界面,如上圖,按Ctrl+X進入頁面信息界面,可看到當前頁面的功能名及各個字段名,如下圖所示:
在這裏插入圖片描述
如界面字段顯示不全,可通過鍵盤向下按鍵顯示更多字段名稱,字段TAB頁的字段名稱和此界面獲取的字段名稱一致就好,然後我們就可以在配置界面字段TAB頁設置這些字段的相應屬性,如只讀,必輸,隱藏等,非常方便。

屬性
在這裏插入圖片描述
屬性TAB頁我們可以設置字段的一些處理(字段名稱必須在字段TAB頁維護才能選到),值來源類型分:值字段,字段,表達式,字符,轉換及無,下面對各個類型進行詳細說明:

a. 值字段

值字段需要和字段屬性TAB啓用值來源和值分割符使用,如下圖
在這裏插入圖片描述
圖中,我們對確認子庫字段啓用值來源,值分割符爲英文逗號,然後我們再屬性頁面配置值來源類型爲值字段,設置如下圖所示:
在這裏插入圖片描述
我們設置確認子庫和輸入字段確認子庫按值分割符分割的第一部分給值,分割的第二部分給確認貨位;

效果,確認子庫輸入如下圖所示:
在這裏插入圖片描述
按回車,效果如下:
在這裏插入圖片描述
以上就可以達到我們的值分割效果,此功能主要設計爲二維碼截取字段所需。

說明:如果值分割符有多個,我們用@@隔開各個分割符就好,如分割符爲逗號和上尖號,應維護:,@@^

b.字段

值來源類型爲字段其實很好理解,就是值來源於哪個字段,若維護如下:在這裏插入圖片描述
則進入頁面效果如下:
在這裏插入圖片描述
其中,屬性頁面右邊有兩個複選框設置是否自動enter和是否啓用當前個性化,默認勾選,若勾選自動enter,則當進入頁面,字段會自動獲取來源字段值並觸發自動回車,否則需要自己手動按enter,這也是爲減少用戶操作而設計。

c.表達式/字符

表達式和字符類型都是光標進入該字段就觸發,表達式可以是function,也可以是sql,字符即設置字段默認值,這裏只對表達式做說明;

sql設置如下:
在這裏插入圖片描述
效果如下:
在這裏插入圖片描述
function設置如下:
在這裏插入圖片描述Function內容如下:

/*==================================================
  Procedure/Function Name :
      get_subinv
  Description:     

  Argument:   
      p_organization_id          :organization_id
  Return:     

  History: 
      1.00 2018-10-11 Fang  Creation 
==================================================*/ 
FUNCTION get_subinv(p_organization_id IN NUMBER) RETURN VARCHAR2 IS
    l_result VARCHAR2(40); 
BEGIN
    SELECT msi.secondary_inventory_name
      INTO l_result
      FROM mtl_secondary_inventories msi
     WHERE msi.organization_id = p_organization_id
       AND msi.secondary_inventory_name = '0013';
    RETURN l_result; 
EXCEPTION
    WHEN OTHERS THEN
      RETURN NULL;
END;

效果如下:
在這裏插入圖片描述
說明,function中參數如需要界面字段的值,可以用英文逗號分隔,‘:’+字段名稱 獲取對應字段值(例如,: MAIN.FROM_SUB),如果是session中的值可以直接通過‘:’獲取(例如,:ORGID);

d.轉換

轉換觸發的時間點是字段按enter後觸發,但是先於字段的所有驗證邏輯,是掃描時預輸入的處理(需要開啓配置文件:MWA:預處理掃描的輸入),主要用於字段的裝換,屬性界面設置如下:
在這裏插入圖片描述
進入PDA功能界面如下:
在這裏插入圖片描述
子庫確認字段沒有值,當我們輸入其他值時,如0015,敲回車,子庫確認字段會自動修改爲0013;

轉換函數:

/*==================================================
  Procedure/Function Name :
      get_subinv
  Description:     

  Argument:       
      p_organization_id          : organization_id
      p_subinventory_code        : subinventory_code
  Return:       

  History: 
      1.00 2018-10-11 Fang  Creation
  ==================================================*/
  FUNCTION get_subinv(p_organization_id IN NUMBER, p_subinventory_code IN VARCHAR2)    RETURN VARCHAR2 IS
    l_result VARCHAR2(40); 
BEGIN
    SELECT msi.secondary_inventory_name
      INTO l_result
      FROM mtl_secondary_inventories msi  
  WHERE msi.organization_id = p_organization_id
       AND msi.secondary_inventory_name = '0013';
    RETURN l_result; 
EXCEPTION
    WHEN OTHERS THEN
      RETURN p_subinventory_code;
  END;

驗證在這裏插入圖片描述

驗證界面主要是爲了增加頁面的字段驗證控制,減少不必要的代碼修改;

說明:程序包名和過程名按實際情況填寫,參數文本如圖上說明,參數必須用逗號分隔,且程序包必須包含三個固定輸出參數(x_return_status,x_msg_count, x_msg_data);

驗證函數如下:

/*==================================================
  Procedure/Function Name :
      validate_locator
  Description:
      驗證挑庫貨位
  Argument: 

  Return: 

  History:
      1.00 2018-10-11 Fang Creation 
==================================================*/
  PROCEDURE validate_locator(x_return_status   OUT NOCOPY VARCHAR2,
                             x_msg_count       OUT NOCOPY NUMBER,
                             x_msg_data        OUT NOCOPY VARCHAR2,
                             p_locator         IN VARCHAR2,
                             p_locator_confirm IN VARCHAR2) IS
    l_api_name       CONSTANT VARCHAR2(30) := 'validate_locator';
    l_savepoint_name CONSTANT VARCHAR2(30) := NULL;
    l_count NUMBER; 
BEGIN
    -- start activity to create savepoint,check compatibility
    -- and initialize message list, include debug message hint to enter api
    x_return_status := cux_api.start_activity(p_pkg_name       => g_pkg_name,                                            
					      p_api_name       => l_api_name,                                             
           				      p_savepoint_name => l_savepoint_name,                                             
           				      p_init_msg_list  => fnd_api.g_true);
    raise_exception(x_return_status);

    -- API body
    IF p_locator <> p_locator_confirm THEN
      cux_api.set_message('CUX','CUX_WMS_LOCATOR_NOT_CORRECT'); --貨位不正確
      RAISE fnd_api.g_exc_error;
    END IF;

    -- API end body
    -- end activity, include debug message hint to exit api
    x_return_status :=cux_api.end_activity(p_pkg_name  => g_pkg_name,                                           
					   p_api_name  => l_api_name,                                           
					   p_commit    => fnd_api.g_false,                                           
					   x_msg_count => x_msg_count,                                           
					   x_msg_data  => x_msg_data);
 
EXCEPTION
    WHEN fnd_api.g_exc_error THEN
      x_return_status := cux_api.handle_exceptions(p_pkg_name       => g_pkg_name, 
                                                   p_api_name       => l_api_name,                                                              
                                                   p_savepoint_name => l_savepoint_name,
                                                   p_exc_name       => cux_api.g_exc_name_error,
                                                   x_msg_count      => x_msg_count,
                                                   x_msg_data       => x_msg_data);
    WHEN fnd_api.g_exc_unexpected_error THEN
      x_return_status := cux_api.handle_exceptions(p_pkg_name       => g_pkg_name, 
                                                   p_api_name       => l_api_name,                                                              
                                                   p_savepoint_name => l_savepoint_name,
                                                   p_exc_name       => cux_api.g_exc_name_unexp,
                                                   x_msg_count      => x_msg_count,
                                                   x_msg_data       => x_msg_data);
    WHEN OTHERS THEN
     x_return_status := cux_api.handle_exceptions(p_pkg_name       => g_pkg_name, 
                                                   p_api_name       => l_api_name,                                                              
                                                   p_savepoint_name => l_savepoint_name,
                                                   p_exc_name       => cux_api.g_exc_name_others,
                                                   x_msg_count      => x_msg_count,
                                                   x_msg_data       => x_msg_data);    
  END;

執行層次說明:

之前:在觸發標準驗證邏輯之前觸發

之後:在觸發標準驗證邏輯之後觸發

終止說明:若勾上,則客戶化程序報錯會停止PDA操作,若不夠,PDA還是能正常操作;

如程序中寫明,若貨位和確認貨位不同,則報錯,標準的邏輯若不走例外替換貨位是有校驗的,如果我們執行層次選之前,則會報出客戶化消息,如下:
在這裏插入圖片描述

小結

經過以上介紹,是不是覺得這個配置界面很強大?

實現界面的字段屬性控制:隱藏,必輸,只讀

實現界面字段的控制:值來源,字段,表達式,字符,裝換,無(自動enter)

增強界面字段的驗證:之前/之後的驗證層次更好的滿足驗證需求;

亮點:無需重啓端口,即時生效,不影響業務操作;

但是……

配置界面也有一些侷限性,也有一些功能是不能做到,這些就是我後面需要講的,通過修改CuxWmsCusListener文件去做一些特殊的個性化。

MWA CustomerListener個性化

個性化實現說明

個性化實現其實oracle標準支持的實現方式是在$ OA_JAVA/oracle/apps/mwa/beans中的CustomListener.class來實現相關的個性化,但是我們修改了該文件,繼承出來一套獨立實現個性化並支持了MWA配置界面;其中預掃描的輸入實現是通過修改$ OA_JAVA/oracle/apps/inv/lov/server中的InvScanManager.class文件,繼承出來單獨實現。

修改的CustomListener文件
在這裏插入圖片描述
所以我們一些修改都是在客戶化的繼承的CuxWmsCusListener.java文件就好,修改如下:

package oracle.apps.cux.wms.fnd;
import java.sql.SQLException;
import java.util.Hashtable;
import oracle.apps.cux.wms.fnd.im.CuxWmsFieldBeanUtil;
import oracle.apps.cux.wms.fnd.im.CuxWmsImManager;
import oracle.apps.inv.invinq.server.ItemOnhandQueryPage;
import oracle.apps.inv.lov.server.ItemLOV;
import oracle.apps.inv.lov.server.LPNLOV;
import oracle.apps.inv.lov.server.LotLOV;
import oracle.apps.inv.utilities.server.InvOrganizationPageBean;
import oracle.apps.inv.utilities.server.NumberFieldBean;
import oracle.apps.inv.utilities.server.UtilFns;
import oracle.apps.mwa.beans.ButtonFieldBean;
import oracle.apps.mwa.beans.CustomListener;
import oracle.apps.mwa.beans.FieldBean;
import oracle.apps.mwa.beans.InputableFieldBean;
import oracle.apps.mwa.beans.LOVFieldBean;
import oracle.apps.mwa.beans.PageBean;
import oracle.apps.mwa.beans.TextFieldBean;
import oracle.apps.mwa.container.Session;
import oracle.apps.mwa.eventmodel.AbortHandlerException;
import oracle.apps.mwa.eventmodel.DefaultOnlyHandlerException;
import oracle.apps.mwa.eventmodel.InterruptedHandlerException;
import oracle.apps.mwa.eventmodel.MWAEvent;
import oracle.apps.mwa.eventmodel.MWAFieldListener;
import oracle.apps.wms.td.server.PickDropPage;
import oracle.apps.wms.td.server.PutawayPage;
import oracle.apps.wip.wma.page.MovePage;

public class CuxWmsCusListener implements MWAFieldListener {
	private Session session;
	private PageBean currentPage;
	private PageBean previousPage;
	private FieldBean fieldBean;
	private String action; 

	private Long organizationId;
	private CustomListener customListener =null;

	public CuxWmsCusListener() {
	} 

	public CuxWmsCusListener(CustomListener customListener) {
	this.customListener = customListener;
	} 

@Override

public void fieldEntered(MWAEvent paramMWAEvent) throws AbortHandlerException, InterruptedHandlerException, DefaultOnlyHandlerException {

	this.session = paramMWAEvent.getSession();
	this.currentPage = this.session.getCurrentPage();
	this.previousPage = this.session.getPreviousPage();
	this.fieldBean = this.currentPage.getCurrentFieldBean();
	
	if (!(paramMWAEvent.getAction().equals("MWA_NEXTFIELD") || paramMWAEvent.getAction().equals("MWA_SUBMIT"))) {
		return;
	}
	
	// replace lov all parameters for cux extends standard page
	if (this.currentPage.getName().contains("CuxWms") && !this.currentPage.getClass().getSuperclass().getName().equals("oracle.apps.mwa.beans.PageBean")) {
		if (this.fieldBean instanceofLOVFieldBean) {
			CuxWmsUtil.replaceLovParameter((LOVFieldBean) this.fieldBean,this.currentPage.getClass().getSuperclass().getName(),this.currentPage.getName());
		}
	}
	if (this.customListener != null && this.fieldBean.getListeners().lastElement().equals(this.customListener)) {
		CuxWmsUtil.clearFieldCusListener(fieldBean);
	}
	
	//addded by Fang@2018-06-12:轉移並完工界面數量字段清空
	if (this.currentPage.getName().equals("oracle.apps.wip.wma.page.MovePage") && ((String)  this.session.getObject("MWA_FUNCTION_NAME")).equals("CUX_WMA_MOVE_EZ_COMPLETE") && this.fieldBean.getName().equals("quantity")) {
		((InputableFieldBean) this.fieldBean).setValue("");
	}
	//added end by Fang@2018-06-12
	
	//added by Fang@2018-07-03:卸貨去除自動帶出的卸載LPN
	if (this.currentPage.getName().equals("oracle.apps.wms.td.server.PickDropPage") || this.currentPage.getName().equals("oracle.apps.wms.td.server.PutawayPage")) {
		if (((String) this.session.getObject("MWA_FUNCTION_NAME")).equals("CUX_IN_WMS_DROP_LOADED_LPNS_MO") || ((String) this.session.getObject("MWA_FUNCTION_NAME")).equals("CUX_OUT_WMS_DROP_LOADED_LPNS_M") || ((String) this.session.getObject("MWA_FUNCTION_NAME")).equals("CUX_WMS_MOVE_ANY_LPN_MOB")) {
			if (this.fieldBean.getName().equals("PKD.CONFIRM_ZONE")) {
				((PickDropPage) this.currentPage).getDropLPN().setValue("");
			}
			(new CuxWmsCusUtil()).addItemInfoField(this.session,this.currentPage);  //added by Fang@2018-07-23:增加顯示LPN物料信息
		}
	}
	//added end by Fang@2018-07-03
	
	//added by @2018-06-11:增加MWA配置界面邏輯
	if ((this.fieldBean instanceofInputableFieldBean) || (this.fieldBean instanceof ButtonFieldBean)) {
		CuxWmsImManager.fieldValueIm(this.session,this.fieldBean);
	}
	//added end by @2018-06-11
}

@Override

public void fieldExited(MWAEvent paramMWAEvent) throws AbortHandlerException, InterruptedHandlerException,DefaultOnlyHandlerException {
	
	this.session = paramMWAEvent.getSession();
	this.currentPage = this.session.getCurrentPage();
	this.previousPage = this.session.getPreviousPage();
	this.fieldBean = (FieldBean) paramMWAEvent.getSource();
	
	this.action = paramMWAEvent.getAction();
	this.organizationId = Long.parseLong(this.session.getObject("ORGID").toString());
	
	if (this.action.equals("MWA_SUBMIT") || this.action.equals("MWA_NEXTFIELD")) {
		//modified by Fang@2018-06-21:增加對客戶化挑庫功能的限制
		//快速挑庫,替換批次狀態必須一致
		if ((this.currentPage.getName().equals("oracle.apps.wms.td.server.MainPickPage") || 
this.currentPage.getName().equals("oracle.apps.wms.td.server.CuxWmsMainPickPage")) && this.fieldBean.getName().equals("MAIN.LPN") && (((String)
this.session.getObject("MWA_FUNCTION_NAME")).equals("CUX_WMS_TASKS_OUT_NOLPN_MOB") || ((String)  this.session.getObject("MWA_FUNCTION_NAME")).equals("CUX_WMS_TASKS_OUT_NOLPN_MOB_N"))) {		
			CuxWmsCusUtil.validLpnLotStatus(this.session,this.currentPage);
		}
		//modified end by Fang@2018-06-21 
		
		// for buttons
		if (action == "MWA_SUBMIT") {
			;
		}
	}

	//added by Fang@2018-08-06:增加限制字段跳轉
	if (this.currentPage.getName().equals("oracle.apps.wip.wma.page.MovePage") && ((String) this.session.getObject("MWA_FUNCTION_NAME")).equals("CUX_WMA_MOVE_EZ_COMPLETE") && this.fieldBean.getName().equals("INV.LOT_QTY")) {
		UtilFns.trace("CUX remain qty :" + ((MovePage) currentPage).getRemainingQtyFld().getValue());
		
		if (((MovePage) currentPage).getRemainingQtyFld().getValue().equals("0")) {
			UtilFns.trace("CUX: goto next field: reference");
			this.session.setNextFieldName("reference");
		}
	}
	//added end by Fang@2018-08-06
	
	//added by@2018-06-11:增加MWA配置界面邏輯
	if (this.action.equals("MWA_SUBMIT") || this.action.equals("MWA_NEXTFIELD")) {
		if ((this.fieldBean instanceofInputableFieldBean)) {
			CuxWmsImManager.fieldValidIm(this.session,this.fieldBean);
		}
	}

	if (this.action == "MWA_SUBMIT") {
		if ((this.fieldBean instanceofButtonFieldBean)) {
			CuxWmsImManager.fieldValidIm(this.session,this.fieldBean);
		}
	}
	//added end by@2018-06-11
}
}

其中增加MWA配置界面邏輯的代碼片段是MWA配置界面實現地方,由Fang添加的代碼塊是MWA配置界面不能實現的個性化修改。

替換LOV

在CuxWmsCusListener文件的fieldEntered方法裏面添加如下代碼:

//added by Fang@2018-10-15:批次替換增加物料字段,先掃描物料再掃描批次      
if (this.currentPage.getName().equals("oracle.apps.inv.lots.server.LotTranslateStartPage")){
            if (((String) this.session.getObject("MWA_FUNCTION_NAME")).equals("CUX_INV_MOB_LOT_TRANSLATE")){
                    (new CuxWmsCusUtil()).addSplitItemInfoField(this.session, this.currentPage);
                    if (this.fieldBean.getName().equals("StartLot")) {
                        (new CuxWmsCusUtil()).replaceStartLotLov(this.session, this.currentPage); 
                    }
             }

       
}  //added end by Fang@2018-10-15

具體CuxWmsCusUtil中替換LOV的方法如下:

//替換批次LOV   
public void replaceStartLotLov(Session session, PageBean pageBean) throws AbortHandlerException {
      LOVFieldBean StartLotLovField = ((LotTranslateStartPage) pageBean).getStartLot();
      String[] arrayOfString1 = { " ", "WMSINSTALL", "ORGID", "TXNID", "oracle.apps.inv.lots.server.LotTranslateStartPage.CUX.ITEM_NUM", "oracle.apps.inv.lots.server.LotTranslateStartPage.StartLot", "", "" };
      StartLotLovField.setlovStatement("cux_dwms_split_lot_pkg.get_lot_num_lov");
      StartLotLovField.setInputParameters(arrayOfString1);
  }

效果如下:
在這裏插入圖片描述

我們前面替換掉了批次的LOV,增加物料限制,在此處,由於物料未啓用批次控制,故未找到結果;

通過以上方式,我們可以替換一些標準界面的LOV,增加一些客戶化的邏輯限制,無須修改標準源碼,風險較低。

修改標準字段默認值

MWA中的表達式並不能將已有值得字段實現賦值,這樣,我們就可以在修改CuxWmsCusListener中實現此種賦值,比如清空標準字段的默認值 ,在fieldEntered方法中添加如下代碼:

  //addded by Fang@2018-06-12:轉移並完工界面數量字段清空
  if (this.currentPage.getName().equals("oracle.apps.wip.wma.page.MovePage") && ((String) this.session.getObject("MWA_FUNCTION_NAME")).equals("CUX_WMA_MOVE_EZ_COMPLETE") && this.fieldBean.getName().equals("quantity")) {
           ((InputableFieldBean) this.fieldBean).setValue("");
    }
  //added end by Fang@2018-06-12

標準界面的完工數量默認值並不準確,所以用戶不想每次去刪掉再重新輸入,比較麻煩,此處就清掉標準完工界面的數量默認值,減少用戶操作,增加效率;

效果如下:
在這裏插入圖片描述

小結

通過以上幾個例子的簡單說明,MWA個性化可以實現很多用戶需求,對用戶和開發人員都有很多益處;

用戶:減少操作,增加效率;

開發人員:減少開發,開發高效便捷;

相對於MWA配置界面,修改個性化代碼是對MWA配置界面的一個補充,修改完後也需重啓端口才生效,沒有MWA配置界面來的方便,但對一些標準界面的修改,MWA配置界面無法滿足的情況下,修改個性化代碼是一個非常不錯的選擇;

各位在後面的項目實戰中就會發現,MWA個性化非常強大,能實現很多用戶的常用需求,貼近實際業務操作,方便快捷;希望大家在後面的開發中熟悉並喜歡上MWA個性化開發。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章