Creating new record results running error block - openedge

I'm attempting to return a value from 1-4 depending on whether the transaction failed or not. Adding a new record shows up in the database but the code returns 4 which means that the error block is being run, why does this happen?
I'm sending input parameters from java and returning a number as output parameter from ABL.
/*Input parameters*/
DEFINE INPUT PARAMETER i_cCode LIKE Unit.Code NO-UNDO.
DEFINE INPUT PARAMETER i_iTransactionType AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER i_cName LIKE UNIT.Name NO-UNDO.
/*Output parameters*/
DEFINE OUTPUT PARAMETER o_iStatus AS INTEGER NO-UNDO.
/*Local variables*/
DEFINE VARIABLE iModifySuccess AS INTEGER INITIAL 1.
DEFINE VARIABLE iModifyFailed AS INTEGER INITIAL 2.
DEFINE VARIABLE iAddedSuccessful AS INTEGER INITIAL 3.
DEFINE VARIABLE iCreateFailed AS INTEGER INITIAL 4.
/*Transaction types*/
DEFINE VARIABLE iCreate AS INTEGER INITIAL 1.
DEFINE VARIABLE iModify AS INTEGER INITIAL 2.
FIND FIRST Unit WHERE Unit.Code = i_cCode EXCLUSIVE-LOCK NO-ERROR.
IF AVAIL(Unit) AND i_iTransactionType = iModify THEN DO:
ASSIGN
Unit.Name = i_cName
/*Other fields as well*/
NO-ERROR.
MESSAGE "Unit has been modified".
o_iStatus = iModifySuccess.
IF ERROR-STATUS:ERROR THEN DO:
MESSAGE "Error Modifying Unit" + ERROR-STATUS:GET-MESSAGE(1).
o_iStatus = iModifyFailed.
END.
END.
ELSE DO:
IF i_iTransactionType = iCreate THEN DO:
/*Create new record*/
CREATE Unit NO-ERROR.
ASSIGN
Unit.Name = i_cName
/*Other fields as well*/
NO-ERROR.
MESSAGE "New Unit Created"
o_iStatus = iAddedSuccessful.
IF ERROR-STATUS:ERROR THEN DO:
MESSAGE "ERROR creating a new Unit" + ERROR-STATUS:GET-MESSAGE(1).
o_iStatus = iCreateFailed.
END.
END.
END.

Seems to be that there was a missing . after MESSAGE "New Unit Created" which caused the error block to run. Building the project didn't give any warnings.

Related

While processing XML, how to insert a node after a specific node?

Consider the following XML document that I receive and parse:
<Courses>
<Course>
<Name>Intro to DB</Name>
<Credits>3.0</Credits>
</Course>
<Course>
<Name>Intro to Programming</Name>
<Credits>3.0</Credits>
</Course>
</Courses>
If I want to add a new course between two courses or a new element within each course (e.g. courseId). How can I achieve this in Progress? I've given a read to Progress' XML documentation (for DOM and SAX) and found INSERT-BEFORE(), not sure if that can be used to achieve this.
Do I have to use temp-table/ ProDataSets to achieve this?
a example with a temp-table and a dataset
the dataset here is only defined for formatting the xml output
DEFINE TEMP-TABLE ttCourse NO-UNDO XML-NODE-NAME "Course"
FIELD dSORT AS DECIMAL SERIALIZE-HIDDEN // hidden in xml output
FIELD Name AS CHARACTER
FIELD Credits AS DECIMAL
FIELD NEWFIELD AS CHARACTER
INDEX SORT dSORT ASCENDING. // this index for sorting the xml output Course
DEFINE VARIABLE cxml AS LONGCHAR NO-UNDO.
DEFINE VARIABLE iCnt AS INTEGER NO-UNDO.
// DEFINE DATASET only for xml-node-name
DEFINE DATASET ds
XML-NODE-NAME "Courses" FOR ttCourse.
cxml = "<Courses>
<Course>
<Name>Intro to DB</Name>
<Credits>3.0</Credits>
</Course>
<Course>
<Name>Intro to Programming</Name>
<Credits>3.0</Credits>
</Course>
</Courses>".
TEMP-TABLE ttCourse:READ-XML ("LONGCHAR", cxml, "MERGE", "", FALSE, ?, ?).
// for sorting output use field dsort
FOR EACH ttCourse WHERE ttCourse.DSORT = 0:
iCnt = iCnt + 1.
ttCourse.DSORT = iCnt.
END.
// insert a record in the middle
CREATE ttCourse.
ASSIGN
ttCourse.DSORT = 1.5
ttCourse.name = "test"
ttCourse.credits = 5.5
ttCourse.NEWFIELD = "NEWFIELD"
.
DATASET ds:WRITE-XML ("file", "C:/temp/baz/courses.xml", TRUE,?,?,FALSE,FALSE).

How to target a child widget that is contained within multiple parent widgets in order to change the properties?

A client needs the application to have colour inserted into the application for specific instances, so the fields will only be populated with colour when necessary, I'm doing this with a right-click context menu.
I created an example application that uses this code and pulls the widget names from a JSON file.
DEFINE VARIABLE hHandle AS HANDLE NO-UNDO.
DEFINE VARIABLE widgetName AS CHARACTER NO-UNDO.
DEFINE VARIABLE colourNumber AS INTEGER NO-UNDO.
FOR EACH Results-WidgetList:
ASSIGN
widgetName = Results-WidgetList.tt-widName /* these assignments are just getting the info */
colourNumber = INT(Results-WidgetList.tt-colour)
.
hHandle = SESSION:FIRST-CHILD.
DO WHILE VALID-HANDLE(hHandle):
IF hHandle:TYPE = "FIELD-GROUP" THEN LEAVE.
hHandle = hHandle:FIRST-CHILD.
END.
hHandle = hHandle:FIRST-CHILD.
DO WHILE VALID-HANDLE(hHandle):
IF hHandle:TYPE = "FILL-IN" AND hHandle:NAME = widgetName THEN LEAVE.
hHandle = hHandle:NEXT-SIBLING.
END.
ASSIGN
hHandle:BGCOLOR = colourNumber.
END.
This worked perfectly fine in my example application, but once I try implement it in the main application it can't see the specific widgets because it is looping through the topmost parent container and going no further.
Is there a way to get to the elements that are contained within?
I'm not sure why you are loading stuff from a JSON file and you don't show that so I can't really comment on it. But, in general, you need to "Walk the widget tree". The following snippet might be helpful:
/* walk the widget tree so that we can update the dcolor for the named field
*/
procedure tweakTree:
define input parameter w as handle no-undo.
define input parameter wName as character no-undo.
define input parameter dClr as integer no-undo.
define variable n as handle no-undo.
n = w:first-child no-error.
if valid-handle( n ) then
run tweakTree( n, wName, dClr ).
n = w:next-sibling no-error.
if valid-handle( n ) then
run tweakTree( n, wName, dClr ).
if w:type = "fill-in" and w:name = wName then
do:
if session:window-system = "tty" then
w:dcolor = dClr.
else
w:fgcolor = dClr.
end.
return.
end.
define variable c1 as character no-undo.
define variable c2 as character no-undo.
form c1 with frame f1.
form c2 with frame f2.
assign
c1 = "abc"
c2 = "123"
.
display c1 with frame f1.
display c2 with frame f2.
pause.
run tweakTree( current-window, "c1", 2 ).
run tweaktree( current-window, "c2", 1 ).
pause.

PDSOE Custom Toolbar option "Send file name of the current selection" with multi select?

I am playing around with adding some custom tools to my PSDOE. I have added a new toolbar entry to experiment with the OpenEdge Customization Options. I have checked the option "Send file name of the current selection" and modified the procedure it is calling to have a single input parameter to get the selected file name when it is clicked.
This works great on a single select. When I start messing around with a multi select of files in the project explorer, it only passes the last one selected into the procedure file.
ROUTINE-LEVEL on error undo, throw.
define input parameter ip_cParameters as character no-undo.
{adecomm/oeideservice.i}
/* *************************** Main Block *************************** */
define variable cParamters as character no-undo.
define variable cFileName as character no-undo.
define variable cProjectName as character no-undo.
define variable cProjectDisplayName as character no-undo.
assign
cParamters = entry( 1, ip_cParameters, chr(3) )
cFileName = entry( 2, ip_cParameters, chr(3) )
cProjectName = getProjectName()
cProjectDisplayName = getProjectDisplayName().
message
"Parameters: " cParamters skip(1)
"FileName: " cFileName skip(1)
"Project Name: " cProjectName skip(1)
"Project Display Name: " cProjectDisplayName skip(1)
view-as alert-box title "info".

A program that outputs a report, as a CSV

Ho do I write code for a program that can accept three input parameters: x , y, and the filename to write to?
I should be able to call the program like this:
run prog.p (input “1”, input 5, input “filename1.csv”).
so far my I have written the code below and not sure how to go around it.
OUTPUT TO xxxxxx\filename1.csv".
DEFINE VARIABLE Profit AS DECIMAL FORMAT "->>,>>9.99":U INITIAL 0 NO-UNDO.
EXPORT DELIMITER "," "Amount" "Customer Number" "Invoice Date" "Invoice Number" "Total_Paid" "Profit".
FOR EACH Invoice WHERE Invoice.Ship-charge > 5.00
AND Invoice.Total-Paid > 0.01
AND Invoice.Invoice-Date GE 01/31/93 /* this is between also can use < >*/
AND Invoice.Invoice-Date LE TODAY NO-LOCK:
Profit = (Invoice.Invoice-Num / Invoice.Total-Paid) * 100.
EXPORT DELIMITER "," Amount Cust-Num Invoice-Date Invoice-Num Total-Paid Profit.
END.
OUTPUT CLOSE.
Thank you.
You're on the right track! OUTPUT TO VALUE(variable) is what might help you. Also you should possibly use a named stream.
It's not clear to me what parameters x and y should do so I just inserted them as dummies below.
Note:
You're commenting about using <> instead of GE. That might work logically but could (will) effect your performance by forcing the database to scan entires tables instead of using an index.
Something like this:
DEFINE INPUT PARAMETER pcX AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER piY AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER pcFile AS CHARACTER NO-UNDO.
/* Bogus temp-table to make the program run... */
/* Remove this unless just testing without database ...*/
DEFINE TEMP-TABLE Invoice NO-UNDO
FIELD Ship-Charge AS DECIMAL
FIELD Total-Paid AS DECIMAL
FIELD Invoice-Date AS DATE
FIELD Invoice-Num AS INTEGER
FIELD Amount AS INTEGER
FIELD Cust-Num AS INTEGER.
DEFINE STREAM str.
DEFINE VARIABLE Profit AS DECIMAL FORMAT "->>,>>9.99":U INITIAL 0 NO-UNDO.
OUTPUT STREAM str TO VALUE(pcFile).
EXPORT STREAM str DELIMITER "," "Amount" "Customer Number" "Invoice Date" "Invoice Number" "Total_Paid" "Profit".
FOR EACH Invoice WHERE Invoice.Ship-charge > 5.00
AND Invoice.Total-Paid > 0.01
AND Invoice.Invoice-Date GE 01/31/93 /* this is between also can use < >*/
AND Invoice.Invoice-Date LE TODAY NO-LOCK:
Profit = (Invoice.Invoice-Num / Invoice.Total-Paid) * 100.
EXPORT STREAM str DELIMITER "," Amount Cust-Num Invoice-Date Invoice-Num Total-Paid Profit.
END.
OUTPUT STREAM str CLOSE.
Now you can run this program, assuming it's named "program.p":
RUN program.p("1", 5, "c:\temp\file.txt").
or
RUN program.p(INPUT "1", INPUT 5, INPUT "c:\temp\file.txt").
(INPUT is the default direction for parameters).
EDIT:
Run example + changed first input to CHARACTER instead of integer

Enable standard toolbar for ALV grid

I created a screen for displaying ALV output but I am not able to show standard toolbar buttons (save, exit, back, etc.).
Can any one suggest how to enable them?
DATA: it_zztstudent type STANDARD TABLE OF zztstudent,
it_fcat TYPE STANDARD TABLE OF lvc_s_fcat,
i_selected_rows TYPE lvc_t_row,
w_selected_rows type lvc_s_row,
it_modified type STANDARD TABLE OF zztstudent,
lw_modified type zztstudent,
lw_zztstudent type zztstudent,
w_variant TYPE disvariant,
o_docking type REF TO cl_gui_docking_container,
o_grid type ref to cl_gui_alv_grid.
FIELD-SYMBOLS: <fs_fieldcat> type lvc_s_fcat.
tables: zztstudent.
select-OPTIONS: sst_id for zztstudent-st_id.
select * from zztstudent
into table it_zztstudent
where st_id in sst_id.
if sy-subrc NE 0.
message e001(zmsgpr).
ENDIF.
call screen 9000.
module status_9000 OUTPUT.
if o_docking is initial.
set PF-STATUS 'ZSTATUS'.
set titlebar 'ZTITLE'.
"Creating Docking Container and grid
PERFORM create_object.
"filling the fieldcatalog table
PERFORM create_fieldcat.
"Modifying the fieldcatalog table
PERFORM modify_fieldcat.
"Registering edit
PERFORM register_edit.
"displaying the output
PERFORM display_output.
ENDIF.
endmodule.
MODULE user_command_9000 INPUT.
Data: lv_ucomm TYPE sy-ucomm.
lv_ucomm = sy-ucomm.
CASE lv_ucomm.
WHEN 'CANCEL' oR 'EXIT'.
PERFORM free_objects.
leave program.
WHEN 'BACK'.
PERFORM free_objects.
SET SCREEN '0'.
leave SCREEN.
WHEN 'SAVE'.
PERFORM save_database.
CALL METHOD o_grid->refresh_table_display.
ENDCASE.
ENDMODULE.
Form create_object.
"create docking container
create object o_docking
exporting
ratio = '95'.
if sy-subrc eq 0.
"create grid
create OBJECT o_grid
exporting
i_parent = o_docking.
endif.
ENDFORM.
FORM create_fieldcat.
CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
EXPORTING
* I_BUFFER_ACTIVE =
I_STRUCTURE_NAME = 'ZZTSTUDENT'
* I_CLIENT_NEVER_DISPLAY = 'X'
* I_BYPASSING_BUFFER =
* I_INTERNAL_TABNAME =
CHANGING
CT_FIELDCAT = IT_FCAT
EXCEPTIONS
INCONSISTENT_INTERFACE = 1
PROGRAM_ERROR = 2
OTHERS = 3
.
IF SY-SUBRC <> 0.
* Implement suitable error handling here
ENDIF.
ENDFORM.
"making the column as editable
FORM modify_fieldcat.
loop at it_fcat ASSIGNING <fs_fieldcat>.
CASE <fs_fieldcat>-fieldname.
WHEN 'ST_NAME'.
<fs_fieldcat>-edit = 'X'.
WHEN 'ST_CITY'.
<fs_fieldcat>-edit = 'X'.
ENDCASE.
ENDLOOP.
ENDFORM.
FORM register_edit.
call METHOD o_grid->register_edit_event
exporting
i_event_id = cl_gui_alv_grid=>mc_evt_modified.
ENDFORM.
FORM display_output.
w_variant-report = sy-repid.
call METHOD o_grid->set_table_for_first_display
EXPORTING
is_variant = w_variant
i_save = 'A'
CHANGING
it_outtab = it_zztstudent
IT_FIELDCATALOG = it_fcat
EXCEPTIONS
invalid_parameter_combination = 1
program_error = 2
too_many_lines = 3
others = 4.
if sy-subrc <> 0.
message e001(zmsgpr).
endif.
ENDFORM.
FORM free_objects.
call method o_grid->free
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
others = 3.
if sy-subrc <> 0.
message e001(zmsgpr).
endif.
call method o_docking->free
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
others = 3.
if sy-subrc <> 0.
message e001(zmsgpr).
endif.
ENDFORM.
First double click on set PF-STATUS 'ZSTATUS' on ZSTATUS and create object.
After that you will get here:
Click in functions Keys and add what code you want for each button.
Finally in a case statement, check if sy-ucomm has the value of the code you entered.
First you must create a method, in your class definition like this:
METHODS on_toolbar
FOR EVENT toolbar
OF cl_gui_alv_grid
IMPORTING e_object.
After that you must create an event object and there you must set the handler for the alvgrid object, like these:
IF gcl_container IS INITIAL.
CREATE OBJECT gcl_container
EXPORTING
container_name = 'CONTAINER'.
CREATE OBJECT gcl_grid
EXPORTING
i_parent = gcl_container.
"erstellt einen Handler der alle ereignisse aufnimmt
"created object and set a handler of all events
CREATE OBJECT gcl_event.
SET HANDLER gcl_event->on_toolbar
FOR gcl_grid.
ENDIF.
Hope it helps you. :)

Resources