Sunday, October 29, 2006

2K puntos en el SDN!


Después de mucho esfuerzo...blogs...respuestas en el foro...visitas a mi blogs...He logrado llegar a la importante marca de los 2,000 puntos en el SDN...Algo que como como verán, no lo alcanza cualquiera -;)


Saludos,

Blag.

Friday, October 27, 2006

Video Entrevista con Andre Labahn


Gracias a Björn Schotte podemos ver una excelente video entrevista con mi amigo Andre Labahn. Pueden verla aquí Video Interview with Andre Labahn.

Si les gustan los Lenguajes Script y SAP no pueden perderse esta entrevista -;)


Saludos,

Blag.

Thursday, October 26, 2006

ALV List Display dinámico!


Seguramente, algunas vez le han pedido mostrar varios ALV's en una sola pantalla...Pues ahí es donde es útil el ALV_LIST_DISPLAY, que nos permite mostrar varias listas...El problema claro está, es que necesitamos una tabla interna por lista...Eso no está mal...Pero...Que pasa si no sabemos cuantas listas son??? Que pasa por ejemplo si por cada Líneas Aerea, debemos mostrar su detalle...Pues bueno...Con un poco de creatividad y tablas internas dinámicas -:D Podemos resolver el problema. ( Ojo: Solo funciona para 20 listas...Cosas de SAP -:( ).

Agradecimientos especiales a Nacho por su Macro para limpiar tablas internas -;)

El reporte quedería así -:)



Y su código es este:

************************************************************************
* INFORMACION GENERAL *
*-----------------------------------------------------------------------
* Nombre del programa: Z_DUMMY_TREE *
* Fecha/Autor: 26.08.2006 / Alvaro Tejada Galindo. *
************************************************************************
REPORT Z_DUMMY_TREE.

*----------------------------------------------------------------------*
* DECLARACION DE TYPE-POOLS *
*----------------------------------------------------------------------*
TYPE-POOLS: SLIS.

*----------------------------------------------------------------------*
* DECLARACION DE TABLAS *
*----------------------------------------------------------------------*
TABLES: SCARR, SPFLI.

*----------------------------------------------------------------------*
* VARIABLES *
*----------------------------------------------------------------------*
DATA: G_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV,
G_SORT TYPE SLIS_T_SORTINFO_ALV WITH HEADER LINE,
GT_PRINT TYPE SLIS_PRINT_ALV,
GS_LAYOUT TYPE SLIS_LAYOUT_ALV,
GT_EVENTS TYPE SLIS_T_EVENT,
G_PROGRAM TYPE SY-REPID,
TAB_NAME TYPE STRING,
W_TABIX TYPE STRING,
G_LINES TYPE STRING.

*----------------------------------------------------------------------*
* TYPES *
*----------------------------------------------------------------------*
TYPES: BEGIN OF TY_SPFLI,
MANDT TYPE SPFLI-MANDT,
CARRID TYPE SPFLI-CARRID,
CONNID TYPE SPFLI-CONNID,
COUNTRYFR TYPE SPFLI-COUNTRYFR,
CITYFROM TYPE SPFLI-CITYFROM,
AIRPFROM TYPE SPFLI-AIRPFROM,
COUNTRYTO TYPE SPFLI-COUNTRYTO,
CITYTO TYPE SPFLI-CITYTO.
TYPES: END OF TY_SPFLI.

TYPES: BEGIN OF TY_STUFF,
TABNAME TYPE TABNAME,
TDREF TYPE REF TO DATA,
END OF TY_STUFF.

DATA T_STUFF TYPE TABLE OF TY_STUFF WITH NON-UNIQUE KEY TABNAME.

DATA: DESCR_STRUCT_REF TYPE REF TO CL_ABAP_STRUCTDESCR,
DATAREF TYPE REF TO DATA,
WA_FCAT TYPE LVC_S_FCAT,
IT_FIELDCATALOG TYPE LVC_T_FCAT.

*----------------------------------------------------------------------*
* FIELD-SYMBOLS *
*----------------------------------------------------------------------*
FIELD-SYMBOLS: <LINE> TYPE ANY,
<FIELD> TYPE ANY,
<COMPONENT> TYPE ABAP_COMPDESCR,
<DYN_TABLE> TYPE STANDARD TABLE,
<FS> TYPE ANY,
<DYN_WA>,
<TABLE>.

*----------------------------------------------------------------------*
* TABLAS INTERNAS *
*----------------------------------------------------------------------*
DATA: T_SPFLI TYPE STANDARD TABLE OF TY_SPFLI WITH HEADER LINE,
T_SPFLI_HEADER TYPE STANDARD TABLE OF TY_SPFLI WITH HEADER LINE,
T_SPFLI_DETAIL TYPE STANDARD TABLE OF TY_SPFLI WITH HEADER LINE.

*----------------------------------------------------------------------*
* MACROS *
*----------------------------------------------------------------------*
DEFINE LIMPIAR_TABLA.
CLEAR &1.
REFRESH &1.
END-OF-DEFINITION.

*----------------------------------------------------------------------*
* CRITERIOS DE SELECCIÓN *
*----------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK B01 WITH FRAME TITLE TEXT-B01.
SELECT-OPTIONS:
S_CARRID FOR SCARR-CARRID.
SELECTION-SCREEN END OF BLOCK B01.

*----------------------------------------------------------------------*
* PRINCIPAL
*----------------------------------------------------------------------*
START-OF-SELECTION.

PERFORM OBTENER_DATOS.
PERFORM GENERAR_ALV.
PERFORM GENERAR_ALV_LIST.

*---------------------------------------------------------------------*
* FORM OBTENER_DATOS *
*---------------------------------------------------------------------*
* Obtenemos los datos *
*---------------------------------------------------------------------*
FORM OBTENER_DATOS.

SELECT MANDT CARRID CONNID COUNTRYFR CITYFROM
AIRPFROM COUNTRYTO CITYTO
INTO TABLE T_SPFLI
FROM SPFLI
WHERE CARRID IN S_CARRID.

IF NOT T_SPFLI[] IS INITIAL.
T_SPFLI_HEADER[] = T_SPFLI[].
DELETE ADJACENT DUPLICATES FROM T_SPFLI_HEADER
COMPARING CARRID.
ENDIF.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form GENERAR_ALV *
*&---------------------------------------------------------------------*
* Creamos el ALV *
*----------------------------------------------------------------------*
FORM GENERAR_ALV.

IF NOT T_SPFLI_HEADER[] IS INITIAL.
PERFORM FORMATEAR_DATOS_ALV USING G_FIELDCAT[].
PERFORM BUILD_SORT.
ENDIF.

ENDFORM. "GENERAR_ALV

*&---------------------------------------------------------------------*
*& Form FORMATEAR_DATOS_ALV *
*&---------------------------------------------------------------------*
* Establecemos el catalogo de ALV. *
*----------------------------------------------------------------------*
FORM FORMATEAR_DATOS_ALV USING T_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV.

DATA: L_FIELDCAT TYPE SLIS_FIELDCAT_ALV.

CLEAR: T_FIELDCAT.
REFRESH: T_FIELDCAT.

CLEAR L_FIELDCAT.
L_FIELDCAT-TABNAME = 'T_SPFLI'.
L_FIELDCAT-FIELDNAME = 'CARRID'.
L_FIELDCAT-SELTEXT_L = 'Airline carrier ID'.
L_FIELDCAT-COL_POS = 1.
L_FIELDCAT-OUTPUTLEN = 15.
APPEND L_FIELDCAT TO T_FIELDCAT.

CLEAR L_FIELDCAT.
L_FIELDCAT-TABNAME = 'T_SPFLI'.
L_FIELDCAT-FIELDNAME = 'CONNID'.
L_FIELDCAT-SELTEXT_L = 'Flight connection Id'.
L_FIELDCAT-COL_POS = 2.
L_FIELDCAT-OUTPUTLEN = 15.
APPEND L_FIELDCAT TO T_FIELDCAT.

CLEAR L_FIELDCAT.
L_FIELDCAT-TABNAME = 'T_SPFLI'.
L_FIELDCAT-FIELDNAME = 'COUNTRYFR'.
L_FIELDCAT-SELTEXT_L = 'Country key'.
L_FIELDCAT-COL_POS = 3.
L_FIELDCAT-OUTPUTLEN = 15.
APPEND L_FIELDCAT TO T_FIELDCAT.

CLEAR L_FIELDCAT.
L_FIELDCAT-TABNAME = 'T_SPFLI'.
L_FIELDCAT-FIELDNAME = 'CITYFROM'.
L_FIELDCAT-SELTEXT_L = 'City of departure'.
L_FIELDCAT-COL_POS = 4.
L_FIELDCAT-OUTPUTLEN = 15.
APPEND L_FIELDCAT TO T_FIELDCAT.

CLEAR L_FIELDCAT.
L_FIELDCAT-TABNAME = 'T_SPFLI'.
L_FIELDCAT-FIELDNAME = 'AIRPFROM'.
L_FIELDCAT-SELTEXT_L = 'Airport of departure'.
L_FIELDCAT-COL_POS = 5.
L_FIELDCAT-OUTPUTLEN = 15.
APPEND L_FIELDCAT TO T_FIELDCAT.

CLEAR L_FIELDCAT.
L_FIELDCAT-TABNAME = 'T_SPFLI'.
L_FIELDCAT-FIELDNAME = 'COUNTRYTO'.
L_FIELDCAT-SELTEXT_L = 'Country key'.
L_FIELDCAT-COL_POS = 6.
L_FIELDCAT-OUTPUTLEN = 15.
APPEND L_FIELDCAT TO T_FIELDCAT.

CLEAR L_FIELDCAT.
L_FIELDCAT-TABNAME = 'T_SPFLI'.
L_FIELDCAT-FIELDNAME = 'CITYTO'.
L_FIELDCAT-SELTEXT_L = 'Arrival city'.
L_FIELDCAT-COL_POS = 7.
L_FIELDCAT-OUTPUTLEN = 15.
APPEND L_FIELDCAT TO T_FIELDCAT.

ENDFORM. "FORMATEAR_DATOS_ALV

*&---------------------------------------------------------------------*
*& Form BUILD_SORT
*&---------------------------------------------------------------------*
* Crea el ordenamiento del reporte
*----------------------------------------------------------------------*
FORM BUILD_SORT.

CLEAR G_SORT.

G_SORT-SPOS = 1.
G_SORT-FIELDNAME = 'CARRID'.
G_SORT-UP = 'X'.
APPEND G_SORT.

ENDFORM.

*---------------------------------------------------------------------*
* FORM CREAR_ALV_LIST *
*---------------------------------------------------------------------*
* ........ *
*---------------------------------------------------------------------*
FORM GENERAR_ALV_LIST.

DATA L_STUFF TYPE TY_STUFF.

G_PROGRAM = SY-REPID.

CALL FUNCTION 'REUSE_ALV_BLOCK_LIST_INIT'
EXPORTING
I_CALLBACK_PROGRAM = G_PROGRAM.

LOOP AT T_SPFLI_HEADER.
W_TABIX = SY-TABIX.
LIMPIAR_TABLA T_SPFLI_DETAIL.
LOOP AT T_SPFLI INTO T_SPFLI_DETAIL
WHERE CARRID EQ T_SPFLI_HEADER-CARRID.
APPEND T_SPFLI_DETAIL.
ENDLOOP.

CONCATENATE 'TABLE_' W_TABIX INTO
TAB_NAME.

PERFORM CREATE_TABLE USING 'SPFLI' TAB_NAME.

LOOP AT T_SPFLI_DETAIL ASSIGNING <LINE>.
G_LINES = <LINE>.
ASSIGN <DYN_WA> TO <TABLE>.
<TABLE> = G_LINES.
APPEND <DYN_WA> TO <DYN_TABLE>.
ENDLOOP.

PERFORM CREAR_ALV_LIST TABLES <DYN_TABLE>.

ENDLOOP.

CALL FUNCTION 'REUSE_ALV_BLOCK_LIST_DISPLAY'
EXPORTING
IS_PRINT = GT_PRINT.

ENDFORM.

*---------------------------------------------------------------------*
* FORM CREAR_ALV_LIST *
*---------------------------------------------------------------------*
* ........ *
*---------------------------------------------------------------------*
FORM CREAR_ALV_LIST TABLES T_TABLE STRUCTURE T_SPFLI_DETAIL.

CALL FUNCTION 'REUSE_ALV_BLOCK_LIST_APPEND'
EXPORTING
IT_FIELDCAT = G_FIELDCAT
IS_LAYOUT = GS_LAYOUT
I_TABNAME = 'T_SPFLI'
IT_EVENTS = GT_EVENTS
TABLES
T_OUTTAB = T_TABLE.

ENDFORM.

*---------------------------------------------------------------------*
* FORM CREATE_TABLE *
*---------------------------------------------------------------------*
* ........ *
*---------------------------------------------------------------------*
FORM CREATE_TABLE USING MY_TAB TAB_NAME.

DATA L_STUFF TYPE TY_STUFF.

CREATE DATA DATAREF TYPE (MY_TAB).

ASSIGN DATAREF->* TO <FS>.

DESCR_STRUCT_REF ?= CL_ABAP_TYPEDESCR=>DESCRIBE_BY_DATA( <FS> ).

LIMPIAR_TABLA IT_FIELDCATALOG.

LOOP AT DESCR_STRUCT_REF->COMPONENTS ASSIGNING <COMPONENT>.
WA_FCAT-FIELDNAME = <COMPONENT>-NAME.
WA_FCAT-REF_TABLE = MY_TAB.
WA_FCAT-REF_FIELD = <COMPONENT>-NAME.
APPEND WA_FCAT TO IT_FIELDCATALOG.
ENDLOOP.

CALL METHOD CL_ALV_TABLE_CREATE=>CREATE_DYNAMIC_TABLE
EXPORTING
IT_FIELDCATALOG = IT_FIELDCATALOG
IMPORTING
EP_TABLE = DATAREF
EXCEPTIONS
OTHERS = 1.

ASSIGN DATAREF->* TO <DYN_TABLE>.

L_STUFF-TABNAME = TAB_NAME.
CREATE DATA L_STUFF-TDREF LIKE LINE OF <DYN_TABLE>.
ASSIGN L_STUFF-TDREF->* TO <DYN_WA>.

ENDFORM. "CREATE_TABLE

Saludos,

Blag.

Wednesday, October 25, 2006

Blag Runs SAP


Quien lo hubiera dicho -:P




Saludos,

Blag.

Tuesday, October 24, 2006

Algoritmo del Índice Menor en PHP


Cada vez que nosotros creamos una tabla en MySQL, asignamos un valor de índice a cada uno de los registros que la conforman. Teniendo por ejemplo esto:

Id Nombre
-- ------
1 Manzanas
2 Peras
3 Platanos
4 Chirimoyas
5 Mandarinas

Ahora, supongamos que ya nos gustan las peras, y decidimos eliminarlas. Nuestra tabla quedaría así:

Id Nombre
-- ------
1 Manzanas
3 Platanos
4 Chirimoyas
5 Mandarinas

Y ustedes se preguntarán...¿Y dónde quedó el registro 2?
Es lo mismo que yo me pregunté...Por eso escribí el "Algoritmo del Índice Menor".

Este código lo escribí tanto para MySQL como para SQLite hace un par de años -:)

Versión MySQL

/*-------------------Algoritmo del Indice Menor-------------*/
/* Autor: Alvaro "Blag" Tejada Galindo */
/* Mail: atejada@gmail.com */
/* Fecha: 24 de Marzo del 2004 */
/*----------------------------------------------------------*/

function Indice_Menor($Table_Name)
{
$Get_Key = mysql_query("SELECT MIN(Id) FROM $Table_Name")
or die(mysql_error());

while($row = mysql_fetch_array($Get_Key))
{
$Key = $row["MIN(Id)"];
}

$Key_Plus = 1;

$query = mysql_query("SELECT * FROM $Table_Name")
or die(mysql_error());

while($row = mysql_fetch_array($query))
{

$query_update = mysql_query("UPDATE $Table_Name
SET Id='$Key_Plus'
WHERE Id = '$Key'")
or die(mysql_error());

$Key += 1;
$Key_Plus += 1;

if($Key == $Id)
{
$Key += 1;
}
}
}
?>

Versión SQLite

/*-------------------Algoritmo del Indice Menor-------------*/
/* Autor: Alvaro "Blag" Tejada Galindo */
/* Mail: atejada@gmail.com */
/* Fecha: 16 de Junio del 2004 */
/*----------------------------------------------------------*/

function Indice_Menor($DB_Name,$Table_Name,$Id)
{
$sqldb = sqlite_open($DB_Name);
$db = new SQLiteDatabase($DB_Name);

$Get_Key = sqlite_query($sqldb,"SELECT Id FROM $Table_Name");
$Num_Rows = sqlite_num_rows($Get_Key);

if($Num_Rows >= 0)
{$MKey = 1;}

$Key_Plus = 1;

while(list($row) = sqlite_fetch_array($Get_Key))
{
$db->query("BEGIN;
UPDATE $Table_Name SET Id=$Key_Plus
WHERE Id = $MKey;
COMMIT");

$MKey += 1;
$Key_Plus += 1;

if($MKey == $Id)
{
$MKey += 1;
}
}
}
?>

Luego de aplicar cualquiera de estos códigos, nuestra tabla quedaría así:

Id Nombre
-- ------
1 Manzanas
2 Platanos
3 Chirimoyas
4 Mandarinas

Saludos,

Blag.

Tiempo de ejecución en ABAP


Muchas veces, queremos saber si un SELECT va a ejecutar más rápido utilizando SELECT o INNER JOIN...O simplemente queremos saber que condiciones en el WHRE nos va a ayudar a mejorar el performance...Con este código podemos hacer pruebas de RunTime y determinar la mejor opción.

REPORT Z_TEST_RUNTIME.

DATA: T1 TYPE I,
T2 TYPE I,
T TYPE P DECIMALS 2,
N TYPE I VALUE 1000.

DATA: NUM TYPE I.

NUM = 10.
T = 0.

DO N TIMES.
GET RUN TIME FIELD T1.
*-----Inicio código a validar-----*
WHILE NUM GT 0.
WRITE:/ NUM.
NUM = NUM - 1.
ENDWHILE.
*-----Fín código a validar-----*
GET RUN TIME FIELD T2.
T2 = T2 - T1.
T = T + T2 / N.
ENDDO.

SKIP 1.
WRITE:/ 'Tiempo de Ejecución: ', T, 'microsegundos'.

El resultado en mi sistema...

10
9
8
7
6
5
4
3
2
1

Tiempo de Ejecución: 0.17 microsegundos

Saludos,

Blag.

Reloj de Progreso en ABAP


Si bien este es un código muy simple, mucha gente nunca lo ha utilizado. Supongamos que tienen un programa que ejecuta muchos procesos, y por ende...Es un poco lento.

Definitivamente, al cliente no le va a gustar esperar a que nuestro programa termine de hacer lo que necesita hacer...Por lo tanto, poner un reloj de progreso es una excelente manera de mostrar en que porcentaje de ejecución va nuestro programa.

Veamos el código...

REPORT Z_PROGRESS_CLOCK.

DATA: A LIKE SY-UCOMM.

DO 100 TIMES.
DO 300 TIMES.
GET TIME.
ENDDO.

A(3) = SY-INDEX.A+3 = '%'.

CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
EXPORTING
PERCENTAGE = SY-INDEX
TEXT = A.
ENDDO.

Saludos,

Blag.

Friday, October 20, 2006

Backup de Programas en ABAP


Este pequeño programa, nos permite grabar el código fuente, includes y elementos de texto de cualquier programa -:) Es bastante simple, solamente nos pide el nombre del programa y una ruta donde guardarlo -;)


**************************************************************
* Programa : Z_PROGRAMS_DOWNLOAD. *
* Módulo : BC - Basis. *
* Consultor ABAP : Alvaro Tejada Galindo. *
* February 14, 2006 12:33:22 PM *
**************************************************************

REPORT Z_DUMMY_ATG NO STANDARD PAGE HEADING.

*=============================================================
* VARIABLES
*=============================================================
DATA: FULLNAME(30) TYPE C,
ONE LIKE PCFILE-DRIVE,
TWO LIKE PCFILE-PATH,
FILEPATH(128) TYPE C.

DATA: APP_NAME TYPE STRING,
DDTEXT_NAME TYPE STRING,
DUMMY TYPE STRING,
INCLUDE_NAME TYPE STRING.

*=============================================================
* TABLAS INTERNAS
*=============================================================
DATA: BEGIN OF SOURCE_TABLE OCCURS 0,
LINEA(150) TYPE C.
DATA: END OF SOURCE_TABLE.

DATA: BEGIN OF INCLUDE_TABLE OCCURS 0,
LINEA(150) TYPE C.
DATA: END OF INCLUDE_TABLE.

DATA: BEGIN OF DYNPRO_TABLE OCCURS 0,
LINEA(250) TYPE C.
DATA: END OF DYNPRO_TABLE.

DATA: BEGIN OF T_TRDIR OCCURS 0,
NAME LIKE TRDIR-NAME,
END OF T_TRDIR.

DATA: BEGIN OF T_LOG OCCURS 0,
ERROR TYPE STRING,
END OF T_LOG.

DATA: DATA_DDTEXT TYPE STANDARD TABLE OF TEXTPOOL
WITH HEADER LINE.

*=============================================================
* SELECTION-SCREEN
*=============================================================
SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME.
PARAMETERS:
PRGNAME LIKE TRDIR-NAME,
LISTNAME LIKE RLGRAP-FILENAME.
SELECTION-SCREEN END OF BLOCK TEST.

*=============================================================
* AT SELECTION-SCREEN
*=============================================================
AT SELECTION-SCREEN ON VALUE-REQUEST FOR LISTNAME.
PERFORM GET_FILENAME CHANGING LISTNAME.

*=============================================================
* START-OF-SELECTION
*=============================================================
START-OF-SELECTION.
PERFORM LOAD_DATA.

IF NOT T_LOG[] IS INITIAL.
WRITE: 'Se encontraron los siguientes errores: '.
ENDIF.

ULINE.
SKIP 1.

LOOP AT T_LOG.
WRITE:/ T_LOG-ERROR.
ENDLOOP.

*-----------------------------------------------------------*
* FORM GET_FILENAME *
*-----------------------------------------------------------*
FORM GET_FILENAME CHANGING LISTNAME.

CALL FUNCTION 'WS_FILENAME_GET'
EXPORTING
DEF_FILENAME = LISTNAME
DEF_PATH = 'C:\downloads\lista'
MASK = ',*.*,*.*. '
MODE = 'S'
TITLE = 'Guardar en'
IMPORTING
FILENAME = LISTNAME
EXCEPTIONS
INV_WINSYS = 1
NO_BATCH = 2
SELECTION_CANCEL = 3
SELECTION_ERROR = 4
OTHERS = 5.
ENDFORM. "GET_FILENAME

*-----------------------------------------------------------*
* FORM LOAD_DATA *
*-----------------------------------------------------------*
FORM LOAD_DATA.
DATA: W_FILE LIKE PCFILE-PATH.
W_FILE = LISTNAME.
CALL FUNCTION 'PC_SPLIT_COMPLETE_FILENAME'
EXPORTING
COMPLETE_FILENAME = W_FILE
IMPORTING
DRIVE = ONE
PATH = TWO
EXCEPTIONS
INVALID_DRIVE = 1
INVALID_EXTENSION = 2
INVALID_NAME = 3
INVALID_PATH = 4
OTHERS = 5.
CONCATENATE ONE ':' TWO INTO FILEPATH.

CONCATENATE PRGNAME '%' INTO FULLNAME.

SELECT NAME
INTO TABLE T_TRDIR
FROM TRDIR
WHERE NAME LIKE FULLNAME.

IF SY-SUBRC EQ 0.
PERFORM FILL_LIST.

PERFORM DOWNLOAD_APPS.
ENDIF.

ENDFORM. "LOAD_DATA

*-----------------------------------------------------------*
* FORM FILL_LIST *
*-----------------------------------------------------------*
FORM FILL_LIST.
CALL FUNCTION 'WS_DOWNLOAD'
EXPORTING
FILENAME = FILEPATH
FILETYPE = 'ASC'
TABLES
DATA_TAB = T_TRDIR
EXCEPTIONS
FILE_OPEN_ERROR = 1
FILE_WRITE_ERROR = 02
INVALID_FILESIZE = 03
INVALID_TABLE_WIDTH = 04
INVALID_TYPE = 05
NO_BATCH = 06
UNKNOWN_ERROR = 07.
ENDFORM. "FILL_LIST

*-----------------------------------------------------------*
* FORM FILL_LIST *
*-----------------------------------------------------------*
FORM FILL_LIST_INCLUDE.

CONCATENATE FILEPATH 'Includes.txt' INTO LISTNAME.

CALL FUNCTION 'WS_DOWNLOAD'
EXPORTING
FILENAME = LISTNAME
FILETYPE = 'ASC'
MODE = 'A'
TABLES
DATA_TAB = INCLUDE_TABLE
EXCEPTIONS
FILE_OPEN_ERROR = 1
FILE_WRITE_ERROR = 02
INVALID_FILESIZE = 03
INVALID_TABLE_WIDTH = 04
INVALID_TYPE = 05
NO_BATCH = 06
UNKNOWN_ERROR = 07.
ENDFORM. "FILL_LIST_INCLUDE

*&----------------------------------------------------------*
*& Form DOWNLOAD_APPS *
*&----------------------------------------------------------*
FORM DOWNLOAD_APPS.

LOOP AT T_TRDIR.
CLEAR: APP_NAME, INCLUDE_NAME.

REFRESH: SOURCE_TABLE.
CLEAR: SOURCE_TABLE.

READ REPORT T_TRDIR-NAME INTO SOURCE_TABLE.
READ TEXTPOOL T_TRDIR-NAME INTO DATA_DDTEXT LANGUAGE SY-LANGU.

CONCATENATE FILEPATH T_TRDIR-NAME '.abp' INTO APP_NAME.
CONCATENATE FILEPATH T_TRDIR-NAME '_DDTEXT.txt'
INTO DDTEXT_NAME.

PERFORM DOWNLOAD_FORM USING APP_NAME.
PERFORM DOWNLOAD_DDTEXT USING DDTEXT_NAME.

LOOP AT SOURCE_TABLE.
SEARCH SOURCE_TABLE-LINEA FOR 'INCLUDE'.
IF SY-SUBRC EQ 0.

IF SOURCE_TABLE-LINEA+0(8) NE 'INCLUDE'.
CONTINUE.
ENDIF.

CLEAR INCLUDE_NAME.

SPLIT SOURCE_TABLE-LINEA AT SPACE
INTO DUMMY INCLUDE_NAME.
SPLIT INCLUDE_NAME AT '.'
INTO INCLUDE_NAME DUMMY.

REFRESH: SOURCE_TABLE.
CLEAR: SOURCE_TABLE.

MOVE INCLUDE_NAME TO INCLUDE_TABLE.
READ TABLE INCLUDE_TABLE WITH KEY LINEA = INCLUDE_TABLE.
IF SY-SUBRC NE 0.
APPEND INCLUDE_TABLE.
ENDIF.

READ REPORT INCLUDE_TABLE INTO SOURCE_TABLE.

IF SY-SUBRC EQ 0.
CONCATENATE FILEPATH INCLUDE_NAME '.abp'
INTO INCLUDE_NAME.
PERFORM DOWNLOAD_FORM USING INCLUDE_NAME.
PERFORM FILL_LIST_INCLUDE.
ENDIF.

ENDIF.
ENDLOOP.

ENDLOOP.

ENDFORM. "DOWNLOAD_APPS

*-----------------------------------------------------------*
* FORM DOWNLOAD_FORM *
*-----------------------------------------------------------*
FORM DOWNLOAD_FORM USING APP_NAME.

CALL FUNCTION 'GUI_DOWNLOAD'
EXPORTING
FILENAME = APP_NAME
FILETYPE = 'ASC'
TABLES
DATA_TAB = SOURCE_TABLE
EXCEPTIONS
FILE_WRITE_ERROR = 1
NO_BATCH = 2
INVALID_TYPE = 4
NO_AUTHORITY = 5
UNKNOWN_ERROR = 6
FILE_NOT_FOUND = 19
OTHERS = 22.

IF SY-SUBRC NE 0.
T_LOG-ERROR = APP_NAME.
APPEND T_LOG.
ENDIF.
ENDFORM. "DOWNLOAD_FORM

*-----------------------------------------------------------*
* FORM DOWNLOAD_DDTEXT *
*-----------------------------------------------------------*
FORM DOWNLOAD_DDTEXT USING DDTEXT_NAME.

CALL FUNCTION 'GUI_DOWNLOAD'
EXPORTING
FILENAME = DDTEXT_NAME
FILETYPE = 'ASC'
TABLES
DATA_TAB = DATA_DDTEXT
EXCEPTIONS
FILE_WRITE_ERROR = 1
NO_BATCH = 2
INVALID_TYPE = 4
NO_AUTHORITY = 5
UNKNOWN_ERROR = 6
FILE_NOT_FOUND = 19
OTHERS = 22.

IF SY-SUBRC NE 0.
T_LOG-ERROR = DDTEXT_NAME.
APPEND T_LOG.
ENDIF.
ENDFORM. "DOWNLOAD_DDTEXT

Saludos,

Blag.

Thursday, October 19, 2006

RIDE-ME en busca de programadores...


Acabo de leer en el blog de RIDE-ME, un IDE para Rails...Que el lider del proyecto, no puede continuar con el desarrollo de esta excelente herramienta...Así como el, extiendo un llamado a los programadores .NET ( Obviamente yo no lo soy -:P ) que puedan participar para no dejar que este proyecto termine en el olvido...

RIDE-ME me ha gustado mucho desde que comencé a utilizarlo...Bueno...desde ayer en la noche -:D Así que espero que escuchen este llamado y apoyen a la causa...

Saludos,

Blag.

Comenzando con Rails...


A pesar de lo que puedo haber dicho antes...Ayer en la noche ( Después de terminar mi primer juego en Ruby -:P ), comencé a aprender Rails.

Para esto, estoy leyendo Agile Web Development with Rails - First Edition y lo único que hecho hasta ahora...jejeje...Es el ejemplo de las dos páginas enlazadas mediante un link que saludan y se despiden. En fín...Hasta ahora, me gustan mucho tanto Rails como el modelo MVC.

Para la programación estoy utilizando el Ride-Me, un IDE gratuito hecho con el Microsoft .NET Framework, realmente muy recomendable y liviano -:)

A medida que vaya aprendiendo y haciendo mejores aplicaciones...Iré posteando mis experiencias en el blog -;)

Saludos,

Blag.

Primer juego en Ruby!!!


Ayer en la noche, luego de unos pequeños ajustes...Terminé mi primer juego en Ruby...El famoso juego Michi, Gato, Tic-Tac-Toe o como quieran llamarlo -;)
Como está hecho en Ruby tiene una simple interface de DOS, aunque es más que suficiente para un juego sencillo -:)



Este es el código fuente por si quieren revisarlo -:)


#TIC_TAC_TOE

$game = false
$cheat = false
$player_won = ""
$player_turn = "1"

def clean_lines()
$line1 = ""
$line2 = ""
$line3 = ""
$line4 = ""
$line5 = ""
end

def initial_board()
clean_lines()
$line1 << " | | "
$line2 << "---+---+---"
$line3 << " | | "
$line4 << "---+---+---"
$line5 << " | | "

print "#{$line1}\n"
print "#{$line2}\n"
print "#{$line3}\n"
print "#{$line4}\n"
print "#{$line5}\n\n"
end

def board(coordenates,player)
clean_lines()

if $board_array[coordenates] == nil
$board_array[coordenates] = player
else
cheat = true
end

$Move_1 = $board_array[0]
if $Move_1 == nil
$Move_1 = " "
end
$Move_2 = $board_array[1]
if $Move_2 == nil
$Move_2 = " "
end
$Move_3 = $board_array[2]
if $Move_3 == nil
$Move_3 = " "
end
$Move_4 = $board_array[3]
if $Move_4 == nil
$Move_4 = " "
end
$Move_5 = $board_array[4]
if $Move_5 == nil
$Move_5 = " "
end
$Move_6 = $board_array[5]
if $Move_6 == nil
$Move_6 = " "
end
$Move_7 = $board_array[6]
if $Move_7 == nil
$Move_7 = " "
end
$Move_8 = $board_array[7]
if $Move_8 == nil
$Move_8 = " "
end
$Move_9 = $board_array[8]
if $Move_9 == nil
$Move_9 = " "
end

$line1 << " #{$Move_1} | #{$Move_2} | #{$Move_3} "
$line2 << "---+---+---"
$line3 << " #{$Move_4} | #{$Move_5} | #{$Move_6} "
$line4 << "---+---+---"
$line5 << " #{$Move_7} | #{$Move_8} | #{$Move_9} "

print "#{$line1}\n"
print "#{$line2}\n"
print "#{$line3}\n"
print "#{$line4}\n"
print "#{$line5}\n\n"
end

def check_who_wins()
if $board_array[0] != nil &&
$board_array[0] == $board_array[1] &&
$board_array[1] == $board_array[2]
$game = true
if $board_array[0] == "*"
print "El Jugador 1 gano\n\n"
else
print "El Jugador 2 gano\n\n"
end
end
if $board_array[3] != nil &&
$board_array[3] == $board_array[4] &&
$board_array[4] == $board_array[5]
$game = true
if $board_array[3] == "*"
print "El Jugador 1 gano\n\n"
else
print "El Jugador 2 gano\n\n"
end
end
if $board_array[0] != nil &&
$board_array[0] == $board_array[3] &&
$board_array[3] == $board_array[6]
$game = true
if $board_array[0] == "*"
print "El Jugador 1 gano\n\n"
else
print "El Jugador 2 gano\n\n"
end
end
if $board_array[1] != nil &&
$board_array[1] == $board_array[4] &&
$board_array[4] == $board_array[7]
$game = true
if $board_array[1] == "*"
print "El Jugador 1 gano\n\n"
else
print "El Jugador 2 gano\n\n"
end
end
if $board_array[2] != nil &&
$board_array[2] == $board_array[5] &&
$board_array[5] == $board_array[8]
$game = true
if $board_array[2] == "*"
print "El Jugador 1 gano\n\n"
else
print "El Jugador 2 gano\n\n"
end
end
if $board_array[0] != nil &&
$board_array[0] == $board_array[4] &&
$board_array[4] == $board_array[8]
$game = true
if $board_array[0] == "*"
print "El Jugador 1 gano\n\n"
else
print "El Jugador 2 gano\n\n"
end
end
if $board_array[2] != nil &&
$board_array[2] == $board_array[4] &&
$board_array[4] == $board_array[6]
$game = true
if $board_array[2] == "*"
print "El Jugador 1 gano\n\n"
else
print "El Jugador 2 gano\n\n"
end
end
end

$board_array = Array.new
$played_moves = Array.new
initial_board()

while($game == false)

if $player_turn == "1"
print "Jugador 1: "
$coordenates = gets
$coordenates = $coordenates.chop!.to_i
if $coordenates <= 0 || $coordenates > 9
print "Por favor ingresar valores del 1 al 9\n"
redo
end
for moves in $played_moves
moves += 1
if moves == $coordenates
$cheat = true
end
end
if $cheat == true
$cheat = false
print "Esa jugada ya ha sido hecha!\n"
redo
end
$coordenates -= 1
$played_moves.push($coordenates)
$player = "*"
board($coordenates,$player)
check_who_wins()
$player_turn = "2"
end

if $game == true
break
end

if $player_turn == "2"
print "Jugador 2: "
$coordenates = gets
$coordenates = $coordenates.chop!.to_i
if $coordenates <= 0 || $coordenates > 9
print "Por favor ingresar valores del 1 al 9\n"
redo
end
for moves in $played_moves
moves += 1
if moves == $coordenates
$cheat = true
end
end
if $cheat == true
$cheat = false
print "Esa jugada ya ha sido hecha!\n"
redo
end
$coordenates -= 1
$played_moves.push($coordenates)
$player = "O"
board($coordenates,$player)
check_who_wins()
$player_turn = "1"
end

if $game == true
break
end

print "#{$player_won}"
end

Saludos,

Blag.

Wednesday, October 18, 2006

¿Realmente me gusta programar?


Ustedes se preguntarán...¿A Blag realmente le gusta programar...o sólo escribe un blog para tener fama?
Pues la respuesta es muy sencilla...Vean un screenshot de mi carpeta Programación y juzgen ustedes mismos -:P


Saludos,

Blag.

Tuesday, October 17, 2006

Ruby QuickRef


Navegando por la red, encontré esta útil Referencia Rápida de Ruby creada por ryand en inglés -:)

Es bueno contar con estas guías rápidas, puesto que no siempre nos acordamos de todos los comandos y a veces es un poco tedioso tener que estar buscando en los manuales o libros -:P

Saludos,

Blag.

Nuevo WIKI en el SDN!


El SDN, cuenta desde algunos días con un nuevo sistema de WIKI.

Como es de suponerse, aquí se muestran los temas y respuestas más buscadas dentro del SDN, con lo cual, se hace mucho más fácil encontrar soluciones a nuestros problemas cotidianos.

Demás está decir, que aún es una versión BETA y necesita que los miembros del SDN colaboremos incluyendo la información que creamos relevante. -;)

Saludos,

Blag.

Monday, October 16, 2006

Cantidad de ocurrencias en un texto


Alguna vez han necesitado saber cuantas veces se repite un caracter o un texto dentro de otros texto? Por ejemplo, cuantas veces se repite la letra A en Alvaro Tejada Galindo...Pues como ya he dicho en posts anteriores, el ABAP no es precisamente bueno para este tipo de manejo de Strings, así que este pequeño código, puede ser de utilidad.


*&-----------------------------------------------------------*
*& Form OCURRENCIAS_TEXTO *
*&-----------------------------------------------------------*
* Encuentra la cantidad de occurencias de un texto *
*------------------------------------------------------------*
FORM OCURRENCIA_TEXTO USING L_TEXTO CHAR_OCCUR
CHANGING L_OCURRENCIAS.

DATA: L_TEXT TYPE STRING.
L_TEXT = L_TEXTO.

FLAG = 'X'.

LONG = STRLEN( L_TEXT ).

WHILE FLAG EQ 'X'.
SEARCH L_TEXT FOR CHAR_OCCUR.
IF SY-SUBRC NE 0.
FLAG = ''.
ELSE.
COUNTER = COUNTER + 1.
POS = SY-FDPOS + 1.
NEW_POS = LONG - POS.
LONG = NEW_POS.
L_TEXT = L_TEXT+POS(NEW_POS).
ENDIF.
ENDWHILE.

L_OCURRENCIAS = COUNTER.

ENDFORM. "OCURRENCIA_TEXTO

Saludos,

Blag.

Decimal a Romanos en ABAP


Esto de las conversiones, me ha gustado -:) Así que después de mi post de "Decimal a Romanos en Ruby", decidí hacer la misma implementación en ABAP.


REPORT Z_DECIMAL_TO_ROMAN.

DATA: BEGIN OF T_ROMAN_TABLE OCCURS 0,
KEY TYPE I,
VALUE TYPE STRING,
END OF T_ROMAN_TABLE.

DATA: RESULTADO TYPE STRING.

SELECTION-SCREEN BEGIN OF BLOCK TEST.
PARAMETERS:
DEC_NUM TYPE I.
SELECTION-SCREEN END OF BLOCK TEST.

T_ROMAN_TABLE-KEY = 1000.
T_ROMAN_TABLE-VALUE = 'M'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 900.
T_ROMAN_TABLE-VALUE = 'CM'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 500.
T_ROMAN_TABLE-VALUE = 'D'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 400.
T_ROMAN_TABLE-VALUE = 'CD'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 100.
T_ROMAN_TABLE-VALUE = 'C'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 90.
T_ROMAN_TABLE-VALUE = 'XC'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 50.
T_ROMAN_TABLE-VALUE = 'L'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 40.
T_ROMAN_TABLE-VALUE = 'XL'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 10.
T_ROMAN_TABLE-VALUE = 'X'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 9.
T_ROMAN_TABLE-VALUE = 'IX'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 5.
T_ROMAN_TABLE-VALUE = 'V'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 4.
T_ROMAN_TABLE-VALUE = 'IV'.
APPEND T_ROMAN_TABLE.
T_ROMAN_TABLE-KEY = 1.
T_ROMAN_TABLE-VALUE = 'I'.
APPEND T_ROMAN_TABLE.

WHILE DEC_NUM GT 0.
LOOP AT T_ROMAN_TABLE.
IF DEC_NUM GE T_ROMAN_TABLE-KEY.
CONCATENATE RESULTADO T_ROMAN_TABLE-VALUE INTO RESULTADO.
DEC_NUM = DEC_NUM - T_ROMAN_TABLE-KEY.
EXIT.
ENDIF.
ENDLOOP.
ENDWHILE.

WRITE:/ 'El número en Romanos es: ', RESULTADO.

Saludos,

Blag.

Más de 1,000 visitas en el Blog!


El blog tecnológico de Blag ha superado el límite de las 1,000 visitas! La verdad es que esto me llena de alegría, porque me doy cuenta de que este humilde blog ha tenido éxito y ha servido como una herramienta para poder transmitir el conocimiento que tengo en algunos temas poco comunes como ABAP y Ruby -;)

Gracias a todos por visitar mi blog!!!


Saludos,

Blag.

Textos en Infotipos


Si bien leer los textos de los infotipos, es bastante sencillo, la mayoría de personas no saben como hacerlo, y se pasan horas o días buscando una solución...Este código aliviará mucho su trabajo.


REPORT Z_ATG_DUMMY.

DATA: BEGIN OF PSKEY OCCURS 1.
INCLUDE STRUCTURE PSKEY.
DATA: END OF PSKEY.

DATA: INFOTYPE_TEXT LIKE HRWPC_S_INFOTYPE_TEXT
OCCURS 0 WITH HEADER LINE.

PSKEY-PERNR = '00000003'.
PSKEY-INFTY = '0001'.
PSKEY-BEGDA = '20050201'.
PSKEY-ENDDA = '99991231'.

CALL FUNCTION 'HRWPC_RFC_IT0XXX_TEXT_GET'
EXPORTING
PSKEY = PSKEY
TABLES
INFOTYPE_TEXT = INFOTYPE_TEXT.

LOOP AT INFOTYPE_TEXT.
WRITE:/ INFOTYPE_TEXT-TEXTLINE.
ENDLOOP.


Saludos,

Blag.

Friday, October 13, 2006

Emulador de BASH en Windows


Todos los que me conocen (Y los que no me conocen se van a enterar), saben que no soy ningún simpatizante de Linux, aunque tampoco soy fanático de Windows, aunque mi Windows XP Home Edition no me ha fallado hasta ahora -:)


En fín...Por cosas del destino, y porque realmente soy fanático de los Lenguajes Script me he visto en la necesidad de hacer algunos scripts sencillos en BASH. Como saben, el BASH es un entorno de programación Script en Linux y como solo tengo el GNOPPIX (Linux Live CD) y la verdad es que no me gusta estar reiniciando mi Laptop cada vez que quiero hacer algo con Linux, decidí navegar un poco por la red...Y adivinen que encontre! -:D Un emulador de BASH para Windows llamado GNU BASH


El GNU BASH es realmente impresionante...Pesa muy poco (solo 529 Kb en .zip), y no necesita instalarse...Solamente configurar una ruta HOME en las variables del sistema...Con eso, estamos listos para programar en BASH.

Saludos,

Blag.

Thursday, October 12, 2006

Crear PDF en ABAP


Esto si es algo que puede serles muy útil...Por lo menos a mi me ha servido de mucho -:)

Supongamos que tienen que hacer un formulario SapScript y tienen que enviarlo por correo...¿Cómo lo hacen? Muy simple -;) Lo convierten en PDF.

Esta función, pide solamente una ruta donde generar el PDF, y toma los datos de la última orden de Spool que hayamos creado.

*"----------------------------------------------------------
*"*"Interfase local
*" IMPORTING
*" REFERENCE(FILENAME) TYPE STRING
*"----------------------------------------------------------

SELECT RQIDENT
INTO (T_TSP01-RQIDENT)
FROM TSP01
WHERE RQOWNER EQ SY-UNAME
AND RQCLIENT EQ SY-MANDT.
APPEND T_TSP01.
ENDSELECT.

SORT T_TSP01 DESCENDING.

CALL FUNCTION 'CONVERT_OTFSPOOLJOB_2_PDF'
EXPORTING
SRC_SPOOLID = T_TSP01-RQIDENT
NO_DIALOG = ''
IMPORTING
PDF_BYTECOUNT = NUMBYTES
PDF_SPOOLID = PDFSPOOLID
BTC_JOBNAME = JOBNAME
BTC_JOBCOUNT = JOBCOUNT
TABLES
PDF = PDF
EXCEPTIONS
ERR_NO_OTF_SPOOLJOB = 1
ERR_NO_SPOOLJOB = 2
ERR_NO_PERMISSION = 3
ERR_CONV_NOT_POSSIBLE = 4
ERR_BAD_DSTDEVICE = 5
USER_CANCELLED = 6
ERR_SPOOLERROR = 7
ERR_TEMSEERROR = 8
ERR_BTCJOB_OPEN_FAILED = 9
ERR_BTCJOB_SUBMIT_FAILED = 10
ERR_BTCJOB_CLOSE_FAILED = 11
OTHERS = 12.

IF SY-SUBRC EQ 0.

CALL FUNCTION 'GUI_DOWNLOAD'
EXPORTING
BIN_FILESIZE = NUMBYTES
FILENAME = FILENAME
FILETYPE = 'BIN'
TABLES
DATA_TAB = PDF
EXCEPTIONS
FILE_WRITE_ERROR = 1
NO_BATCH = 2
GUI_REFUSE_FILETRANSFER = 3
INVALID_TYPE = 4
NO_AUTHORITY = 5
UNKNOWN_ERROR = 6.

IF SY-SUBRC EQ 0.
DELETE FROM TSP01 WHERE RQIDENT EQ T_TSP01-RQIDENT.
ENDIF.

ENDIF.

ENDFUNCTION.


Saludos,

Blag.

Decimal a Binario en ABAP


Continuando con los programas sin mucho sentido...Que les parece un Decimal a Binario en ABAP...Dudo mucho que alguna vez lo necesiten, pero bueno, un pequeño código nunca está de más -;)

REPORT ZDECIMAL_A_BINARIO.

DATA: SUMA TYPE I,
EXPONENTE TYPE I,
DIGITO TYPE I,
SUMA_TEXT(50) TYPE C.

SELECTION-SCREEN BEGIN OF BLOCK DEC_TO_BIN WITH FRAME.
PARAMETERS:
P_NUMERO TYPE I.
SELECTION-SCREEN END OF BLOCK DEC_TO_BIN.

START-OF-SELECTION.

SUMA = 0.
EXPONENTE = 1.

CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5.
WHILE P_NUMERO GT 0.
DIGITO = P_NUMERO MOD 2.
P_NUMERO = P_NUMERO DIV 2.
SUMA = SUMA + DIGITO * EXPONENTE.
EXPONENTE = EXPONENTE * 10.
ENDWHILE.
ENDCATCH.

IF SY-SUBRC = 5.
WRITE / 'Número demasiado grande!'.
ELSE.
SUMA_TEXT = SUMA.
REPLACE '.' WITH SPACE INTO SUMA_TEXT.
REPLACE ',' WITH SPACE INTO SUMA_TEXT.
CONDENSE SUMA_TEXT NO-GAPS.

WRITE: 'El numero binario es: ', SUMA_TEXT.
ENDIF.


Saludos,

Blag.

TRY-CATCH en ABAP


Como mucho sabes, el TRY-CATCH es muy utilizado en Java, para el manejo de errores y excepciones.

Lo que quizás no sabían, es que también podemos utilizarlo en ABAP. Gracias a esto, podemos evitarnos muchos molestos Short Dumps -;)

Veamos un ejemplo sencillo...

DATA: RESULT TYPE P DECIMALS 3,
NUMBER TYPE I VALUE 11.

CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5.
DO.
NUMBER = NUMBER - 1.
RESULT = 1 / NUMBER.
WRITE: / NUMBER, RESULT.
ENDDO.
ENDCATCH.

SKIP.

IF SY-SUBRC = 5.
WRITE / 'Division por cero!'.
ENDIF.

El resultado de ejecutar este código sería...
                            
10 0.100
9 0.111
8 0.125
7 0.143
6 0.167
5 0.200
4 0.250
3 0.333
2 0.500
1 1.000

Division por cero!

Como pueden ver...Obtenemos un mensaje, en vez del Short Dump correspondiente -:)


Saludos,

Blag.

Wednesday, October 11, 2006

Restar horas a una fecha???


Muchas veces, en los proyectos, nos van a pedir restar una cantidad de días, meses o años a una determinada fecha...Pero alguna vez les han pedido que resten horas a una fecha???

Bueno, si alguna vez se ven en ese problema, esta pequeña función puede ayudarles -;)


FUNCTION Z_CALCULATE_DATE_FROM_TIME.
*"-------------------------------------------------------
*"*"Interfase local
*" IMPORTING
*" REFERENCE(DATE) TYPE D
*" REFERENCE(TIME) TYPE T
*" REFERENCE(HOURS) TYPE T
*" REFERENCE(OPERATION) TYPE CHAR1
*" EXPORTING
*" REFERENCE(NEW_DATE) TYPE D
*" REFERENCE(NEW_TIME) TYPE T
*" EXCEPTIONS
*" FORBIDDEN_OPERATION
*"-------------------------------------------------------

DATA: DAYS TYPE I,
MONTHS LIKE T5A4A-DLYMO,
YEARS LIKE T5A4A-DLYYR.

IF OPERATION EQ 'S'.
NEW_TIME = TIME + HOURS.

IF TIME LE '240000' AND NEW_TIME LT TIME.
CALL FUNCTION 'RP_CALC_DATE_IN_INTERVAL'
EXPORTING
DATE = DATE
DAYS = '01'
MONTHS = MONTHS
SIGNUM = '+'
YEARS = YEARS
IMPORTING
CALC_DATE = NEW_DATE.
ELSE.
NEW_DATE = DATE.
ENDIF.

ELSEIF OPERATION EQ 'R'.
NEW_TIME = TIME - HOURS.

IF TIME GE '000000' AND NEW_TIME GT TIME.
CALL FUNCTION 'RP_CALC_DATE_IN_INTERVAL'
EXPORTING
DATE = DATE
DAYS = '01'
MONTHS = MONTHS
SIGNUM = '-'
YEARS = YEARS
IMPORTING
CALC_DATE = NEW_DATE.
ELSE.
NEW_DATE = DATE.
ENDIF.

ELSE.
RAISE FORBIDDEN_OPERATION.
ENDIF.

ENDFUNCTION.


Saludos,

Blag.

Tuesday, October 10, 2006

Es malo ser famoso en Internet???


Bueno...luego de más de 8 años en el mundo de la programación...Me he dado cuenta de que no siempre es bueno ser conocido en Internet.
¿Por qué lo digo? Pues muy simple...La gente cree que porque se un poco de ABAP, C++, Ruby y PHP, automáticamente tengo que convertirme en su tutor particular.

La verdad ya estoy cansado de recibir mail, alabando mis grandes conocimientos, con el único fín de que les haga sus tareas, que coincidentemente, siempre son necesarias para que los pobres principiantes puedan terminar su curso, su carrera, etc...

La gente debería de entender, que si soy conocido en Internet, es porque trabajo mucho y por lo mismo, no tengo tiempo para estar resolviendo las dudas de todos los que me envién un mail o me contacten vía el Skype o el GoogleTalk...Gracias a Dios que no utilizo Messenger...

Creanme que no es tarea fácil:


  • Trabajar como Consultor ABAP Senior
  • Tener un blog tecnológico
  • Ser blogger del SDN
  • Ser blogger del Huica.net
  • Ser editor de Código Latino
  • Ser moderador en SoloCodigo, ABAP en Castellano, Lenguajes Script y SAP
  • Participar activamente en los foros de PuneRuby, TeleportMedia, CAAD, SDN
  • Escribir libros de programación El Arte de Programar, El Arte de Programar - C++, El Arte de Programar - Ruby (Próximamente)


Para encima de todo, estar resolviendo tareas de personas que ni siquiera se molestan en enviarme lo que ha avanzado, sino que me envian un word lleno de problemas para que se lo regrese al día siguiente, comentado para que lo entiendan bien, por si el profesor les pregunta...

Bueno -;) Siempre es bueno desahogarse no??? Y como es mi blog -:P Hago lo que quiero...


Saludos,

Blag.

Archivos planos y ABAP


Muchas veces tenemos que hacer programas de integración, en los cuales debemos descargar muchas tablas en archivos planos. Lo que se hacía antes era crear un GUI_DOWNLOAD por cada archivo...Pero que pasa si tenemos que crear 5,6 o 7 archivos planos? Pues muy simple, creamos una tabla interna dinámica y un solo GUI_DOWNLOAD que descargue todas las tablas. Aquí está el código -;)

*------------------------------------------------------------*
* DECLARACION DE VARIABLES *
*------------------------------------------------------------*
DATA: DESCR_STRUCT_REF TYPE REF TO CL_ABAP_STRUCTDESCR,
DATAREF TYPE REF TO DATA,
WA_FCAT TYPE LVC_S_FCAT,
IT_FIELDCATALOG TYPE LVC_T_FCAT,
TABNAME TYPE DD02L-TABNAME,
NEW_LINE TYPE REF TO DATA,
FILE_TAB TYPE STRING,
LONG TYPE I.

*&-----------------------------------------------------------*
*& Form CREATE_TABLE *
*&-----------------------------------------------------------*
* Creamos una tabla interna dinámica *
*------------------------------------------------------------*
FORM CREATE_TABLE USING MY_TAB.

CREATE DATA DATAREF TYPE (MY_TAB).

ASSIGN DATAREF->* TO <FS>.

DESCR_STRUCT_REF ?= CL_ABAP_TYPEDESCR=>DESCRIBE_BY_DATA( <FS> ).

LOOP AT DESCR_STRUCT_REF->COMPONENTS ASSIGNING <COMPONENT>.
WA_FCAT-FIELDNAME = <COMPONENT>-NAME.
WA_FCAT-REF_TABLE = MY_TAB.
WA_FCAT-REF_FIELD = <COMPONENT>-NAME.
APPEND WA_FCAT TO IT_FIELDCATALOG.
ENDLOOP.

CALL METHOD CL_ALV_TABLE_CREATE=>CREATE_DYNAMIC_TABLE
EXPORTING
IT_FIELDCATALOG = IT_FIELDCATALOG
IMPORTING
EP_TABLE = DATAREF
EXCEPTIONS
GENERATE_SUBPOOL_DIR_FULL = 1
OTHERS = 2.

ASSIGN DATAREF->* TO <DYN_TABLE>.

CREATE DATA NEW_LINE LIKE LINE OF <DYN_TABLE>.
ASSIGN NEW_LINE->* TO <DYN_WA>.

ENDFORM. "CREATE_TABLE

*&-----------------------------------------------------------*
*& Form DESCARGAR_TABLA *
*&-----------------------------------------------------------*
* Descargamos la tabla interna a un archivo plano *
*------------------------------------------------------------*
FORM DESCARGAR_TABLA TABLES P_TABLA.

LOOP AT P_TABLA ASSIGNING <LINE>.
G_LINES = <LINE>.
ASSIGN <DYN_WA> TO <TABLE>.
<TABLE> = G_LINES.
APPEND <DYN_WA> TO <DYN_TABLE>.
ENDLOOP.

FILE_TAB = P_FILE.

CALL FUNCTION 'GUI_DOWNLOAD'
EXPORTING
FILENAME = FILE_TAB
FILETYPE = 'ASC'
IMPORTING
FILELENGTH = LONG
TABLES
DATA_TAB = <DYN_TABLE>
EXCEPTIONS
FILE_WRITE_ERROR = 1
NO_BATCH = 2
GUI_REFUSE_FILETRANSFER = 3
INVALID_TYPE = 4
NO_AUTHORITY = 5
UNKNOWN_ERROR = 6
HEADER_NOT_ALLOWED = 7
SEPARATOR_NOT_ALLOWED = 8
FILESIZE_NOT_ALLOWED = 9
HEADER_TOO_LONG = 10
DP_ERROR_CREATE = 11
DP_ERROR_SEND = 12
DP_ERROR_WRITE = 13
UNKNOWN_DP_ERROR = 14
ACCESS_DENIED = 15
DP_OUT_OF_MEMORY = 16
DISK_FULL = 17
DP_TIMEOUT = 18
FILE_NOT_FOUND = 19
DATAPROVIDER_EXCEPTION = 20
CONTROL_FLUSH_ERROR = 21
OTHERS = 22.

ENDFORM. "DESCARGAR_TABLA


La forma de utilizar el código sería la siguiente:

DATA: T_MARA TYPE STANDARD TABLE OF MARA
WITH HEADER LINE.

TABNAME = 'T_MARA'.
PERFORM CREATE_TABLE USING TABNAME.
PERFORM DESCARGAR_TABLA TABLES T_MARA.


Saludos,

Blag.

Monday, October 02, 2006

Decimal a Romanos en Ruby

Hace un par de semanas, he estado resolviendo los famosos Ruby Quiz, que son problemas propuestos para la comunidad de programadores Ruby -:)

Aquí les dejo, mi código para hacer un Decimal a Romanos


#Roman Numerals

Roman_Table = {
1000 => "M",
900 => "CM",
500 => "D",
400 => "CD",
100 =>"C",
90 => "XC",
50 => "L",
40 => "XL",
10 => "X",
9 => "IX",
5 => "V",
4 => "IV",
1 => "I"
}

$Result = ""

def Roman_Number(number)
while number > 0
Roman_Table.keys.sort {|a,b| b<=>a}.inject do |key,value|}
if number >= value.to_i
$Result << Roman_Table[value]
number = number - value.to_i
break
end
end
end
end

print "Ingresa un numero: "
$Numero = gets

Roman_Number($Numero.chop!.to_i)

print "#{$Result}\n"


Saludos,

Blag.