Pages

Sunday 19 January 2014

Display Google Map in ABAP


I. Skenario. 
Tutorial ini merupakan tutorial awal membahas mengenai display data koordinat map (latitude -longitude) menggunakan integrasi ABAP dengan service dari Google Map ™. Contoh kasus yang diangkat adalah data customer, sebagai latihan table customer akan dibuat di z-table. Table tersebut berisi Customer number, data latitude dan longitude. Pengembangan nantinya data koordinat customer itu bisa dihubungkan dengan data customer yang ada di SAP. 
Style coding yang digunakan pada contoh masih bersifat prosedural. Namun di dalam prakteknya, report ini membutuhkan class dari SAP custom control framework (cl_gui_custom_container dan cl_gui_html_viewer). Alv pada report ini menggunakan class SALV, namun bagi yang terbiasa menggunakan cl_gui_alv_grid juga dapat menggunakannya di report ini.


II. Design dan Specification.
Berikut ini adalah desain awal dan spesifikasi umum dari sistem yang akan dirancang.

I. PERMINTAAN
Module
SD
Date
13 December 2013
Request By
Lina Inverse
Initial Name
-
Request Type
Report ABAP
Characteristic
Dialog Programming
Printer
-
Reference T-Code
-
 II. INFO OBJECT
1
Package
$TMP
4
T-Code
ZMAP01
2
Program Name
ZLAT_MAP01
5
Include Program
-
3
Function Modul
 -
6


III. DESKRIPSI DETAIL INFO OBJECT
1
Background
Displaying Customer List in ALV and Google Map.
2
Flow of Process
Select Customer no. -> Displays
3
Tables
zcustomer_01
4
Input Screen/Selection
Customer No (zcustomer_01-KUNNR)
5.
Output
  
III. Prasyarat.

1. Google account.
2. API Key.
3. Basic knowledge in HTML & Js.
4. Basic Knowledge in ABAP (Dialog Programming, HTML Viewer , Class).
5. Komputer user memiliki koneksi internet.
IV. Langkah-langkah.

1. Buat account google di : www.google.com.
2. Buat API key google map di https://code.google.com/apis/console. Api yang digunakan adalah Google Maps API v3. Adapun langkah-langkah pembuatan bisa dilihat di : https://developers.google.com/maps/documentation/javascript/tutorial#api_key. Jika kesulitan membuat api key, masih dapat menggunakan api key pada coding yang tersedia (namun sewaktu-waktu dapat expired).
3. Buka SE11. Create new Z-table untuk data koordinat. misalkan : zcustomer_01. Berikut screenshoot untuk fields nya.

SAP sebenarnya telah menyediakan domain khusus koordinat geospatial yaitu
GEOLONLAT. Namun untuk alasan mempermudah proses display di html viewer,  maka
dipilihlah tipe data char :) Buatlah Table maintenance agar mudah untuk membuat input
data dummy nantinya. Contoh data dummy :
 
4.   Buka SE38. Create Program ZLAT_MAP01 (atau apa saja ) type : Executable.
5.   Create SCREEN 9000.

 
Screen FLow Logic.





6.   Create GUI Status ST_9000.
7.   Create GUI Title TL_9000.

8.    Main Coding.

1:  *&---------------------------------------------------------------------*
2:  *& Report ZTEST_GMAP  
3:  *& Created by : Lina Inverse 
4:  *&---------------------------------------------------------------------*  
5:  *& Change logs.  
6:  *&  
7:  *&---------------------------------------------------------------------*  
8:  REPORT ztest_gmap.  
9:  TABLES : zcustomer_01.  
10:  *------------------ Types and Data Declaration -------------------------*  
11:  TYPES : BEGIN OF ty_html,  
12:       dataset(255) TYPE c,"HTML Line  
13:      END OF ty_html,  
14:      BEGIN OF ty_data_alv,  
15:       kunnr TYPE zcustomer_01-kunnr, "Cust. no  
16:       name TYPE zcustomer_01-name, "Cust. name  
17:      END OF ty_data_alv,  
18:      BEGIN OF ty_data_map,  
19:       kunnr   TYPE zcustomer_01-kunnr,    "Cust. no  
20:       name   TYPE zcustomer_01-name,    "Cust. name  
21:       latitude TYPE zcustomer_01-latitude,  "Cust. latitude  
22:       longitude TYPE zcustomer_01-longitude,  "Cust. longitude  
23:      END OF ty_data_map.  
24:  DATA : wa_data TYPE ty_html,            "Wa for HTML content  
25:      gt_data TYPE STANDARD TABLE OF ty_html,   "Itab untuk isi html  
26:      ok_code TYPE sy-ucomm,           "ok code  
27:      gv_url TYPE char255,            "Url file html  
28:      gv_key TYPE c LENGTH 50,          "API Key  
29:      wa_alv TYPE ty_data_alv,  
30:      gt_alv TYPE STANDARD TABLE OF ty_data_alv,         "itab untuk ALV  
31:      gt_cust TYPE STANDARD TABLE OF ty_data_map WITH HEADER LINE. "Itab data cust  
32:  DATA : gr_cc    TYPE REF TO cl_gui_custom_container,      "Custom container untuk ALV  
33:      gr_alv    TYPE REF TO cl_salv_table,           "ALV Table  
34:      gr_columns  TYPE REF TO cl_salv_columns,          "ALV Columns Desc.  
35:      gr_cont_map TYPE REF TO cl_gui_custom_container,      "Map object Custom container  
36:      gr_html   TYPE REF TO cl_gui_html_viewer.         "Html viewer  
37:  *----------------------- Selection Screen -------------------------------*  
38:  SELECTION-SCREEN BEGIN OF SCREEN 0100 AS SUBSCREEN.  
39:  SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME.  
40:  SELECTION-SCREEN BEGIN OF LINE.  
41:  SELECTION-SCREEN COMMENT 1(20) txt1 FOR FIELD pa_kunnr.  
42:  PARAMETERS pa_kunnr TYPE c LENGTH 10.  
43:  SELECTION-SCREEN END OF LINE.  
44:  SELECTION-SCREEN END OF BLOCK b1.  
45:  SELECTION-SCREEN END OF SCREEN 0100.  
46:  INITIALIZATION.  
47:   txt1  = 'No. Customer'.  
48:   "!! Perhatian. API Key pada contoh sewaktu2 dapat berubah. Sebaiknya Gunakan API key pribadi yah :)  
49:   gv_key = 'AIzaSyADjWAt-nKmreVBK5YNEacbFRDNSQRZPxI'.  
50:  START-OF-SELECTION.  
51:   SET SCREEN 9000.  
52:  *&---------------------------------------------------------------------*  
53:  *&   Module STATUS_9000 OUTPUT  
54:  *&---------------------------------------------------------------------*  
55:  *    PBO for 9000  
56:  *----------------------------------------------------------------------*  
57:  MODULE status_9000 OUTPUT.  
58:   SET PF-STATUS 'ST_9000'.  
59:   SET TITLEBAR 'TL_9000'.  
60:   PERFORM f_get_data_cust. "Ambil data cust  
61:   PERFORM f_generate_html. "Generate syntax HTML  
62:   "Check gr_alv obj. has been created or not.  
63:   IF gr_alv IS BOUND.  
64:    gr_alv->refresh( ).  
65:    gr_alv->set_data(  
66:     CHANGING  
67:      t_table = gt_alv ).  
68:   ELSE.  
69:    CREATE OBJECT gr_cc  
70:     EXPORTING  
71:      container_name = 'CC_ALV'.  
72:    TRY.  
73:      CALL METHOD cl_salv_table=>factory  
74:       EXPORTING  
75:        r_container  = gr_cc  
76:        container_name = 'CC_ALV'  
77:       IMPORTING  
78:        r_salv_table  = gr_alv  
79:       CHANGING  
80:        t_table    = gt_alv.  
81:     CATCH cx_salv_msg.  
82:    ENDTRY.  
83:   ENDIF.  
84:   "kustomisasi Kolom ALV  
85:   gr_columns = gr_alv->get_columns( ).  
86:   gr_columns->set_optimize( abap_true ).  
87:   PERFORM fm_change_column USING gr_columns :  
88:     'KUNNR'  ' ' ' ' '' '' 'ID Customer'  'ID Customer',  
89:     'NAME'  ' ' ' ' '' '' 'Customer Name' 'Cust. Name.  
90:   "Tampilkan ALV.  
91:   gr_alv->display( ).  
92:   "Cek object container map.  
93:   IF gr_cont_map IS BOUND.  
94:    CALL METHOD gr_cont_map->free.  
95:    FREE gr_cont_map.  
96:   ENDIF.  
97:   "Create map container obj  
98:   CREATE OBJECT gr_cont_map  
99:    EXPORTING  
100:     container_name       = 'CC_MAP'  
101:    EXCEPTIONS  
102:     cntl_error         = 1  
103:     cntl_system_error      = 2  
104:     create_error        = 3  
105:     lifetime_error       = 4  
106:     lifetime_dynpro_dynpro_link = 5  
107:     OTHERS           = 6.  
108:   IF sy-subrc <> 0.  
109:   ENDIF.  
110:   "Create html object on container map  
111:   CREATE OBJECT gr_html  
112:    EXPORTING  
113:     parent       = gr_cont_map  
114:    EXCEPTIONS  
115:     cntl_error     = 1  
116:     cntl_install_error = 2  
117:     dp_install_error  = 3  
118:     dp_error      = 4  
119:     OTHERS       = 5.  
120:   IF sy-subrc <> 0.  
121:   ENDIF.  
122:   "Load data dari table berisi kode html (gt_data) ke sebuah url  
123:   CALL METHOD gr_html->load_data  
124:    EXPORTING  
125:     type         = 'text'  
126:     subtype       = 'html'  
127:    IMPORTING  
128:     assigned_url     = gv_url  "Dynamically assign url name  
129:    CHANGING  
130:     data_table      = gt_data "Data skrip HTML  
131:    EXCEPTIONS  
132:     dp_invalid_parameter = 1  
133:     dp_error_general   = 2  
134:     cntl_error      = 3  
135:     OTHERS        = 4.  
136:   IF sy-subrc <> 0.  
137:   ENDIF.  
138:   "Tampilkan html dari url hasil bentukan.  
139:   CALL METHOD gr_html->show_url  
140:    EXPORTING  
141:     url          = gv_url  
142:    EXCEPTIONS  
143:     cntl_error       = 1  
144:     cnht_error_not_allowed = 2  
145:     cnht_error_parameter  = 3  
146:     dp_error_general    = 4  
147:     OTHERS         = 5.  
148:   IF sy-subrc <> 0.  
149:   ENDIF.  
150:  ENDMODULE.         " STATUS_9000 OUTPUT  
151:  *&---------------------------------------------------------------------*  
152:  *&   Module USER_COMMAND_9000 INPUT  
153:  *&---------------------------------------------------------------------*  
154:  *    PAI for screen 9000  
155:  *----------------------------------------------------------------------*  
156:  MODULE user_command_9000 INPUT.  
157:   CASE ok_code.  
158:    WHEN '&BACK' OR '&EXIT' OR '&CANCEL'.  
159:     LEAVE TO SCREEN 0.  
160:    WHEN OTHERS.  
161:  *   CALL METHOD cl_gui_cfw=>dispatch.  
162:   ENDCASE.  
163:  ENDMODULE.         " USER_COMMAND_9000 INPUT  
164:  *&---------------------------------------------------------------------*  
165:  *&   Form F_GENEARTE_HTML  
166:  *&---------------------------------------------------------------------*  
167:  *  HTML code. Logika dan contoh bisa dicopy dari :  
168:  *  https://developers.google.com/maps/documentation/javascript/tutorial#HelloWorld  
169:  *----------------------------------------------------------------------*  
170:  FORM f_generate_html .  
171:   CLEAR wa_data. FREE gt_data.  
172:   "Mulai membuat html  
173:   wa_data-dataset = '<html>'. APPEND wa_data TO gt_data.  
174:   wa_data-dataset = '<head>'. APPEND wa_data TO gt_data.  
175:   wa_data-dataset = '<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />'. APPEND wa_data TO gt_data.  
176:   wa_data-dataset = '<style type="text/css">'. APPEND wa_data TO gt_data.  
177:   wa_data-dataset = 'html { height: 100% }'. APPEND wa_data TO gt_data.  
178:   wa_data-dataset = 'body { height: 100%; margin: 0; padding: 0 }'. APPEND wa_data TO gt_data.  
179:   wa_data-dataset = '#map-canvas { height: 100% }'. APPEND wa_data TO gt_data.  
180:   wa_data-dataset = '</style>'. APPEND wa_data TO gt_data.  
181:   "!! Attention : gunakan gv_key (api key) milik pribadi, api key pada tutorial dapat diganti sewaktu waktu !!.  
182:   CONCATENATE '<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=' gv_key '&sensor=false"></script>'  
183:    INTO wa_data-dataset.  
184:   APPEND wa_data TO gt_data.  
185:   " {{ == Start Java script ------------------------------------------------------------------------  
186:   CONCATENATE '<script type="text/javascript">'  
187:           'function initialize(){'  
188:            'var mapOptions = { center: new google.maps.LatLng(-8.674367, 115.202451), zoom: 12 };' INTO wa_data-dataset.  
189:   "mapOptions center (-8.674367, 115.202451) = titik tengah Map, pada contoh masih di-hardcode. pada tutorial selanjutnya akan dinamis.  
190:   APPEND wa_data TO gt_data.  
191:   CONCATENATE    'var map'   ' = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);' INTO wa_data-dataset.  
192:   APPEND wa_data TO gt_data.  
193:   "Loop untuk data customer dimulai disini.  
194:   LOOP AT gt_cust.  
195:    "Pastikan data latitude longitude ada isinya.  
196:    IF gt_cust-latitude IS NOT INITIAL AND gt_cust-longitude IS NOT INITIAL.  
197:     CONDENSE : gt_cust-latitude, gt_cust-longitude.  
198:     CONCATENATE 'var position = new google.maps.LatLng( ' gt_cust-latitude ',' gt_cust-longitude ' );' INTO wa_data-dataset. APPEND wa_data TO gt_data.  
199:     CONCATENATE 'var marker  = new google.maps.Marker({ '  
200:             'position: position,'  
201:             'map: map });' INTO wa_data-dataset. APPEND wa_data TO gt_data.  
202:     CONCATENATE 'marker.setTitle(' '''' gt_cust-name '''' '); ' INTO wa_data-dataset. APPEND wa_data TO gt_data.  
203:    ENDIF.  
204:   ENDLOOP.  
205:   wa_data-dataset = '}'. APPEND wa_data TO gt_data.  
206:   CONCATENATE    'google.maps.event.addDomListener(window, ' '''load''' ', initialize); '  
207:         '</script>' INTO wa_data-dataset.  
208:   APPEND wa_data TO gt_data.  
209:   " ==== }} ----------End Java script ------------------------------------------------------------------------  
210:   wa_data-dataset = '</head>'.APPEND wa_data TO gt_data.  
211:   " Script Body, hanya berisi pemanggilan ID map-canvas.  
212:   wa_data-dataset = '<body>'.APPEND wa_data TO gt_data.  
213:   wa_data-dataset = '<div id="map-canvas"/>'. APPEND wa_data TO gt_data.  
214:   wa_data-dataset = '</body>'.APPEND wa_data TO gt_data.  
215:   wa_data-dataset = '</html>'.APPEND wa_data TO gt_data.  
216:  ENDFORM.          " F_GENEARTE_HTML  
217:  *&---------------------------------------------------------------------*  
218:  *&   Form F_GET_DATA_CUST  
219:  *&---------------------------------------------------------------------*  
220:  * Logika tarik data dari z table.  
221:  *&---------------------------------------------------------------------*  
222:  FORM f_get_data_cust .  
223:   CONDENSE pa_kunnr.  
224:   IF pa_kunnr IS INITIAL OR pa_kunnr = '*'.  
225:    SELECT kunnr name latitude longitude FROM zcustomer_01  
226:    INTO TABLE gt_cust.  
227:   ELSE.  
228:    SELECT kunnr name latitude longitude FROM zcustomer_01  
229:    INTO TABLE gt_cust  
230:     WHERE kunnr = pa_kunnr.  
231:   ENDIF.  
232:   "Isi table untuk ALV  
233:   IF gt_cust[] IS NOT INITIAL.  
234:    CLEAR wa_alv.  
235:    REFRESH gt_alv.  
236:    LOOP AT gt_cust.  
237:     wa_alv-kunnr = gt_cust-kunnr.  
238:     wa_alv-name = gt_cust-name.  
239:     APPEND wa_alv TO gt_alv.  
240:     CLEAR wa_alv.  
241:    ENDLOOP.  
242:   ENDIF.  
243:  ENDFORM.          " F_GET_DATA_TOKO  
244:  *&---------------------------------------------------------------------*  
245:  *&   Form change_column  
246:  *&---------------------------------------------------------------------*  
247:  *  form untuk penamaan kolom ALV.  
248:  *----------------------------------------------------------------------*  
249:  *   -->PO_COLUMNS   text  
250:  *   -->PV_FIELDNAME  text  
251:  *   -->PV_TECHNICAL  text  
252:  *   -->PV_INVISIBLE  text  
253:  *   -->PV_CURRREF   text  
254:  *   -->PV_QUANREF   text  
255:  *   -->PV_FIELDTEXTLM text  
256:  *   -->PV_FIELDTEXTS  text  
257:  *----------------------------------------------------------------------*  
258:  FORM fm_change_column USING po_columns   TYPE REF TO cl_salv_columns  
259:                 pv_fieldname  TYPE c "Nama Kolom  
260:                 pv_technical  TYPE c  
261:                 pv_invisible  TYPE c  
262:                 pv_currref   TYPE c "Curr Ref  
263:                 pv_quanref   TYPE c "Quan ref  
264:                 pv_fieldtextlm TYPE c "Nama Kolom Medium Length  
265:                 pv_fieldtexts TYPE c."Nama Kolom Short Length  
266:   DATA lo_column TYPE REF TO cl_salv_column_table.  
267:   DATA lv_short TYPE scrtext_s.  
268:   DATA lv_medium TYPE scrtext_m.  
269:   DATA lv_long TYPE scrtext_l.  
270:   TRY .  
271:     lo_column ?= po_columns->get_column( pv_fieldname ).  
272:     IF pv_technical IS NOT INITIAL.  
273:      lo_column->set_technical( abap_true ).  
274:     ENDIF.  
275:     IF pv_invisible IS NOT INITIAL.  
276:      lo_column->set_visible( abap_false ).  
277:      RETURN.  
278:     ENDIF.  
279:     IF pv_currref IS NOT INITIAL.  
280:      lo_column->set_currency_column( pv_currref ).  
281:     ELSEIF pv_quanref IS NOT INITIAL.  
282:      lo_column->set_quantity_column( pv_quanref ).  
283:     ENDIF.  
284:     IF pv_fieldtextlm IS NOT INITIAL.  
285:      lv_medium = lv_long = pv_fieldtextlm.  
286:      lo_column->set_medium_text( lv_medium ).  
287:      lo_column->set_long_text( lv_long ).  
288:     ENDIF.  
289:     IF pv_fieldtexts IS NOT INITIAL.  
290:      lv_short = pv_fieldtexts.  
291:      lo_column->set_short_text( lv_short ).  
292:     ENDIF.  
293:    CATCH cx_salv_not_found.              "#EC NO_HANDLER  
294:    CATCH cx_salv_data_error.              "#EC NO_HANDLER  
295:   ENDTRY.  
296:  ENDFORM.          " CHANGE_COLUMN   


9.    Activate. Jika sukses bisa langsung di-execute F8.

10.  Buat Tcodenya di SE93.

 


V. Kesimpulan

Sistem Display Mapping Customer menggunakan Google Map ini merupakan rancangan sederhana memanfaatkan media html_viewer dan koneksi internet untuk mengakses google map. Parameter dan nilai-nilai dinamis dibentuk dan dimasukkan ke dalam kerangka HTML. FIle HTML yang dinamis ini dibentuk dengan mengakomodasi seluruh informasi yang dibutuhkan user. Program awal ini merupakan contoh yang masih simple karena program hanya bersifat satu arah yaitu dari input selection screen (filter ABAP Program) menghasilkan informasi pada citra GoogleMap, masih belum bersifat vice versa  ( proses sebaliknya, action pada map belum bisa ditangkap ABAP). Beberapa nilai masih di hardcode seperti inisiasi nilai titik tengah koordinat dari map, nantinya dapat dikembangkan dengan penentuan titik tengah yang dinamis.

Pengembangan program dan eksperimen dapat dilakukan mengingat masih banyak tools dari SAP sendiri yang bisa digunakan untuk membaca ajax hasil response google map. Demikian pula element-element API Google Map sendiri masih banyak sekali yang dapat di dalami dan di eksplore untuk menghasilkan report display koordinat geospatial data yang lebih baik. Kritik dan saran atau penambahan dapat disampaikan ke email saptestqa@gmail.com. Happy coding, all :)

VI. Reference

1. Reinandang, A (2012). ABAP - Basic Knowledge Revision 7. SAP-Interface.
2. Google Maps JavaScript API v3 . https://developers.google.com/maps/documentation/javascript/tutorial
.

No comments:

Post a Comment