2013年1月30日

增加是否有相關文件的圖示

查詢資料的時候,都看不出來那些是有附上相關文件的檔案,
需使用者點擊相關文件 action ,再看有沒有資料才知道有沒有附上去。


我們可以參照 E-Mail 的樣式,只要在程式上面加上一個迴紋針的圖示,
就知道那些單子有沒有相關文件了。

首先要把圖先上傳,一般是上傳到 /u1/topprod/tiptop/doc/pic 目錄,
TIPTOP 的圖示是透過 web 的方式,將網址傳給 GDC ,
然後 GDC 再依 HTTP 網址抓取圖片來顯示。

程式的部份,比照 cl_set_pic1 函式的寫法就差不多了,
因 cl_set_pic1 的畫面變數一定要命名為 imgmksg ,
要顯示是否有相關文件的圖示的話,就必須要另外寫程式了。

以 aqct110 當範例:

FUNCTION t110_show_attache()
   DEFINE   l_cnt              LIKE   type_file.num5,
            ls_sql             STRING,
            l_wc               STRING
   DEFINE   ls_pic_url         STRING,
            ls_imgmksg         STRING
   DEFINE   lr_key       RECORD
               gca01 LIKE gca_file.gca01,
               gca02 LIKE gca_file.gca02,
               gca03 LIKE gca_file.gca03
            END RECORD
           
   IF g_qcs.qcs01 IS NOT NULL THEN
      LET l_cnt = 0
      LET g_doc.column1 = "qcs01"
      LET g_doc.column2 = "qcs02"
      LET g_doc.column3 = "qcs05"
      LET g_doc.value1 = g_qcs.qcs01
      LET g_doc.value2 = g_qcs.qcs02
      LET g_doc.value3 = g_qcs.qcs05
   
      LET lr_key.gca01 = g_doc.column1 CLIPPED || "=" || g_doc.value1 CLIPPED
      LET lr_key.gca02 = g_doc.column2 CLIPPED || "=" || g_doc.value2 CLIPPED
      LET lr_key.gca03 = g_doc.column3 CLIPPED || "=" || g_doc.value3 CLIPPED
   
      LET l_wc = "gca01 = '", lr_key.gca01 CLIPPED, "' AND gca02 = '", lr_key.gca02 CLIPPED,
                         "' AND gca03 = '", lr_key.gca03 CLIPPED, "'  AND gca04 = ' ' AND gca05 = ' '"
   
      # 是否有相關文件的紀錄
      LET ls_sql = "SELECT COUNT(*) FROM gca_file WHERE ", l_wc,
                   " AND gca08 IN ('DOC','TXT') AND gca11 = 'Y' ORDER BY gca06"
   
      PREPARE t110_doc_p FROM ls_sql
      DECLARE t110_doc_d CURSOR FOR t110_doc_p
   
      OPEN t110_doc_d
      FETCH t110_doc_d INTO l_cnt
      # 有的話顯示迴紋針圖檔,不然就顯示空白的圖檔,
      #因為下一筆可能沒有要給他一個空白來更新畫面
      IF SQLCA.SQLCODE = 0 AND l_cnt > 0 THEN
        LET ls_pic_url = FGL_GETENV("FGLASIP") || "/tiptop/pic/"
        LET ls_imgmksg = ls_pic_url.trim() || "attache.jpg"
        # 傳送網址給畫面變數  imgattch 
        DISPLAY ls_imgmksg TO imgattach
      ELSE
        LET ls_pic_url = FGL_GETENV("FGLASIP") || "/tiptop/pic/"
        LET ls_imgmksg = ls_pic_url.trim() || "space_0.gif"
        DISPLAY ls_imgmksg TO imgattach
      END IF
   END IF
END FUNCTION

最後只要再 show 的 Function 加 CALL t110_show_attache() 就可以了。

2013年1月25日

指定畫面單身資料匯出 Excel

TIPTOP 提供一個的 Library 可以將畫面單身的資料匯出到 Excel ,
例如:CALL cl_export_to_excel(ui.Interface.getRootNode(),base.TypeInfo.create(g_sfq),'','')

但是有程式在視窗上是有二個單身,像是工單發料、工單退料、付款沖帳、收款沖帳…等,
或是有程式會開啟另一個視窗的明細資料,像出貨單的單價,應付帳款的多發票…等。
同一支程式會呼叫多個畫面或是有多單身的情況時,
用 cl_export_to_excel 就會發現,怎麼匯出到 Excel 的資料是對的,但是欄位的名稱是錯的。
造成匯出來就會不整齊,不會依序排好。
因為 ui.Interface.getRootNode() 都是抓第一個顯示的單身來當作匯出的資料陣列。
所以我們就要把 ui.Interface.getRootNode() 改成正確的 node (節點)。
TIPTOP 並非 MDI 視窗架構,所以一個 Windows 只會有一個 Form。

畫面的架構:
UserInterface
 |--Windows
 |        |-- Form
 |        |        |--Table
 |        |--Dialog
 |--TopMenu
 |--ToolBar

如下圖所示:


參考 4js 網站說明,提供 ui.window 的函數說明:
CLASS Method:
forName( name STRING ):回傳目前是否有開啟 name 視窗,並傳回位置
getCurrent():回傳目前的視窗位置

OBJECT Method:
findNode( t STRING, n STRING ):找尋類型為 t,且名稱為 n 的節點
createForm( n STRING ):開啟一個新的畫面,且傳回新畫面的位置
getForm():回傳目前畫面的位置
getNode():回傳目前節點的位置
setText( t STRING ) :設定視窗的標題名稱
getText():回傳視窗的標題名稱
setImage( n STRING ):設定視窗的 icon 圖示
getImage():回傳視窗的 icon 圖示

首先要先宣告二個變數:
DEFINE w ui.Window
DEFINE n om.DomNode

再來就是要取得目前的視窗和要匯出 Excel 的 Node:
如果是新的視窗來顯示的話,只要用 getNode 即可,
LET w = ui.Window.getCurrent()
LET n = w.getNode()

如果是多單身的視窗,就要告訴系統是那一個單身 Node:
LET w = ui.Window.getCurrent()
LET n = w.findNode("Table","s_sfs")

然後再修改  cl_export_to_excel 把 ui.Interface.getRootNode() 改為 n 就可以了,
CALL cl_export_to_excel(n,base.TypeInfo.create(g_sfs),'','')

SQL 語法將群組的資料全部列出來

我們都知道 GROUP 可以用 AVG、SUM、COUNT、MIN、MAX…等,
可以做數字、日期或是字串的運算。

但是如果群組不想要運算,要合起來全部都列出來呢 ?
通常我們就用程式跑迴圈的方式來將資料連接成一個字串。
我們知道 Oracle 有一個函數叫 concat 也就是將二個字串連接在一起,
這時候也可以用在 group 囉~~

介紹一個函數 wm_concat ,但重複資料不會排除,所以再加上 distinct 就更完美了。
欄位內容會以逗號來分隔。
不想用逗號來分隔的話,就只能用 replace 的方式來取代了。

範例:顯示部門內的所有員工資料。
SELECT gen03,wm_concat(gen01) FROM gen_file
GROUP BY gen03
ORDER BY 1

要注意,wm_concat 的欄位是以 CLOB 格式來呈現的,
所以如果有建立 view 或是直接在 p_query 使用的話,記得要轉成 VARCHAR 的格式。
原因就是 p_query 所有欄位都是依照 gaq_file.gaq03 欄位來宣告的。
用 CAST 將 CLOB 改為 VARCHAR 的格式。
範例:
SELECT gen03,cast(wm_concat(gen01) as varchar(255)) FROM gen_file
GROUP BY gen03
ORDER BY 1

另一個需注意就是 wm_concat 的資料是不能排序,
所以有可能資料所列出來的順序會不一樣。必需改為先 wm_concat 合併再 GROUP來處理。
範例:
SELECT gen03,max(cast(gen01 as varchar(255))) FROM (
SELECT gen03,wm_concat(gen01) OVER (PARTITION BY gen03 ORDER BY gen03,gen01) gen01 FROM gen_file
)
GROUP BY gen03

2013年1月23日

當站下線的成本該如何計算?

當站下線的意思就是,工單生產的途中要進行在製品的入庫。
可能是要抽原料來變更生產料號,可能是設計變更換新料號生產…情況。
因已經在製程中生產了,用挪料、退料的方式也是可行,
但所投入的人工、製費在成本計算,就會造成舊工單結案變調整金額,
新工單的在製金額也會低估,就不會是那麼的恰當。
需要進行在製成本的調整,料件的單位成本才能夠準確。
所以當站下線的料號就必須要再編一個新的料號,一般都是工單生產的料號+製程碼。

我們瞭解了當站下線的意思,報工有當站下線時製程移轉和 WIP 量是不會有問題的,
比較有問題的就是工單是不會自動結案,
另一個就是下線的庫存單位必須要和工單製程的轉出單位要一樣。
但是成本計算時在製金額是如何表示的呢?

在 TIPTOP 系統當站下線是以退料的方式來呈現的,
也就是在製的本期投入的數量和金額為負數,
和正常完工入庫是在轉出數量和金額概念是不同的。
再加上成本計算時沒辦法知道當站下線的金額是多少,所以我們就要附予單價啦~~

當站下線在成本計算前要先在 axct510 先填入材料、人工、製費、加工的單價,
然後要注意一點,如果是同月當站下線所入庫當月又被另一工單領用接下去生產的時候,
則需要在 axct001 庫存開帳補上此料件的前期單價資料,避免領用當線下線的料號單價為 0 ,
因 axcp500 執行的先後順序的關係,當站下站是退料並非入庫而計算月加權平均,
所以工單領用的單價就抓不到的關係。

最後成本計算後檢查相關資料時,
當站下線和拆件工單在 axcr370 成本計算後勾稽報表都會出現本期投入金額為負的錯誤訊息,
就把他當作是正常吧~~~

2013年1月17日

開啟 GDC 的 Debug 模式

找系統問題的時候,需要找畫面的欄位對應到資料庫那一個 Column、
action 按鈕對應是 4gl 程式那一個 action 名稱…等,這些除錯常常會遇到。

GDC 有提供一個 Debug 的功能,可以直接看到目前視窗所有欄位或按鈕的變數值 or 名稱。

1. 在程式集的捷徑加上參數 -aD (-M 是最小化開啟)。


GDC 就會多出二個按鈕。


2. 使用 ssh 或是 telnet 的方式來登入 TIPTOP,開啟你所要的畫面。

3. 將滑鼠游標移到你要看的上方,然後按下組合鍵 Ctrl + 滑鼠右鍵,就出現 Debug 視窗。
    然後你所點選的地方也會有紅色的標示框在那閃動著,就可以快速知道 action 的名稱。
    也試試看看其他欄位,可以顯示欄位的變數值喔~





讓 TIPTOP 下拉式選單可以動態的顯示

在 Genero Studio 設計 ComboBox 下拉式選單的時候,
通常都是直接在 4fd 檔上面定義固定的 item 項目。
然後再到 p_perlang 修改多國語言顯示的名稱。

提供一個方式可以讓 ComboBox 物件可以隨著其他欄位的變化,來改變下拉式選單的項目。
就是用 ui.ComboBox 的方法。

參考 Genero 的說明文件,ui.ComboBox 提供下式的 Function。
CLASS Method:
1. forname :物件名稱

2. setDefaultInitializer:設定初始的項目

OBJECT Method:
1. addItem(name,text) :增加項目,name 是值,text 是顯示名稱

2. getColumnName():回傳欄位的名稱

3. getIndexOf(name):回傳 name 是在項目的第幾個,沒有回傳 0

4. getItemCount():回傳項目的數量

5. getItemName(index):回傳第 index 個的項目 name 值

6. getItemText(index):回傳第 index 個的項目 text 值

7. getTableName():回傳欄位的 table_name 或是 FORMONLY

8. getTag():回傳欄位的 tag 值

9. getTextOf(name) :回傳 name 是在項目的第幾個的 text 值,沒有回傳 null

10. removeItem(name):刪除名稱是 name 的項目

11. clear():清除所有的項目

範例1:ComboBox 依開啟時可以顯示 1~5 的項目選單
方法1:
1. 在 4fd 檔中的 ComboBox 欄位 Initializer 屬性加上 cb_load 字串

2. 在 4gl 檔中增加一個 Function
    FUNCTION cb_load(combox)
         DEFINE combox ui.ComboBox
         LET combox = ui.ComboBox.forname("ima12")
         CALL combox.clear()
         FOR g_num = 1 TO 5
             CALL combox.addItem(g_num ,g_num)
         END FOR
    END FUNCTION

方法2:
1. 在 OPEN WINDOW 之前加上:
     CALL ui.ComboBox.setDefaultInitializer("cb_load")

2. 同上增加 cb_load 的 Function

範例2:ComboBox 可以隨著某個欄位所選擇的,列出對應的選單
 1. 新增 cb_load 的 Function
    FUNCTION cb_load(combox)
         DEFINE combox ui.ComboBox
         DEFINE l_azf01   LIKE  azf_file.azf01,
                       l_azf03    LIKE azf_file.azf03
         LET combox = ui.ComboBox.forname("ima12")
         DECLARE ima12 CURSOR FOR
            SELECT azf01,azf03 FROM azf_file
                WHERE azf02 = g_ima.ima12
         FOREACH ima12  INTO l_azf01,l_azf03
                 CALL combox.addItem( l_azf01,l_azf03)
         END FOREACH
    END FUNCTION

2. 然後再 INPUT 段的 BEFORE FIELD 欄位的時候,呼叫就可以變化了
    BEFORE FIELD ima12
           CALL cb_load("")

當欄位 ima12 選擇是那一個的時候,跳到 ComboxBox 欄位的時候,
就會帶出不同的下拉式選單

總結:在 Genero 的 ComboBox 有一些可惜的地方,只能在查詢的時候才能夠輸入資料
(要開啟 queryEditabile ),不能提供新增的時候可以輸入選單以外的值。
再來就是如果是用此方式的話,多國語言的功能就不能再維護了,
如果是帶 Table 的資料多國語言就沒問題,但是是自定的話,當然也可以用 p_ze 來定義啦~~~
要注意的另一點,如果下拉式選單因其他欄位的變化而造成值是相同但是顯示的名稱不同,
再查詢的時候就要再多判斷要帶出來的顯示名稱,並上下筆做查詢的時候也要判斷。

Genero 的檔案管理指令

需要檔案管理的時候,都要再查一次 Genero 的文件,
所以就把常用的指令都整理一下啦~~

其實就是可以用 Genero 進行檔案或資料夾的新增、修改、刪除,或是權限設定的功能。
有時候報表的資料太多,或是其他系統做資料交換的時候,就可以轉文字檔的方式來匯出。

首先要記得在程式最上方加上 Library:
IMPORT os

再來利用 CALL Function RETURNING value 的方式來使用。
以下就是常用的 Function:

1. os.Path.separator() :路徑的系統符號,傳回 / 或是 \ 符號

2. ps.Path.pathseparator() :磁碟的系統符號,傳回  : 或是 ; 的符號

3. os.Path.exists(filename) :傳回 true 或是 false

4. os.Path.basename(Fullname) :去除路徑只回傳檔案名稱

5. os.Path.dirname(Fullname) :去除檔案名稱只回傳路徑

6. os.Path.rootname(filename):回傳路徑+檔案名稱

7.  os.Path.extension(filename):回傳檔案的 extension

8.  os.Path.join ( "/u1", "topprod") :回傳 /u1/topprod

9.  os.Path.chrwx(file,511) :變更檔案的權限,回傳 true 或是 false,十進位的 511 = 八進位的 777

當然也可以不要用 os 的 Library ,大多的指令也是直接也可用 RUN 的指令來達成。

例:
LET l_cmd = "chmod 777 ", filename
RUN l_cmd