Record being modified but can't find where even exporting all objects to txt - microsoft-dynamics

In Dynamics Nav 2018, I'm using the selected action in this page rows, when I click "Validar", all selected rows will change it's status to "Pendiente".
After some time, the row will change to status "Error":
I can see in debugger when it changes from "Registrando" to "Pendiente". But I can't see when it's changing to "Error" and when it's inserting data to column "Descripción Estado":
Validar - OnAction()
UserSetup.GET(USERID);
UserSetup.TESTFIELD("Superusuario SII",TRUE);
//++SII V.08
CurrPage.SETSELECTIONFILTER(SII);
WITH SII DO BEGIN
IF FINDSET(TRUE,TRUE) THEN
REPEAT
//--SII V.08
//++SII JUL-2018
IF SII."Pendiente de validar" THEN BEGIN
TempHistSII.RESET;
TempHistSII.SETCURRENTKEY("N Doc NAV","Fecha Registro");
TempHistSII.SETRANGE("N Doc NAV",SII."N Doc NAV");
TempHistSII.SETRANGE("Fecha Registro",SII."Fecha Registro");
TempHistSII.SETRANGE(TempHistSII."Nº Mov",SII."Nº Mov");
//++SII JUL-2018 12/06/18
//IF TempHistSII.FINDFIRST THEN BEGIN
IF TempHistSII.FINDLAST THEN BEGIN
//--SII JUL-2018 12/06/18
HistRegSII.INIT;
HistRegSII.TRANSFERFIELDS(TempHistSII);
HistRegSII."Usuario modificación" := USERID;
HistRegSII."Fecha modificación" := TODAY;
HistRegSII."Hora modificación" := TIME;
HistRegSII.INSERT;
//++SII JUL-2018 12/06/18
//Inserto en tabla temporal
TempHistSII.INIT;
TempHistSII.TRANSFERFIELDS(SII);
TempHistSII."Nº línea registro" := HistRegSII."Nº línea registro" + 10000;
TempHistSII.INSERT;
//--SII JUL-2018 12/06/18
END;
SII."Pendiente de validar" := FALSE;
END;
//--SII JUL-2018
CASE Estado OF
//++SII JUL-2018
//Estado::"Registrada con error",Estado::Registrada: //++SII V.07
Estado::"Registrada con error",Estado::Registrada,Estado::"Error por inmuebles adicionales":
//--SII JUL-2018
BEGIN
"Tipo comunicacion" := "Tipo comunicacion"::A1;
Estado := Estado::Pendiente;
"Descripción Estado" := '';
END;
//++SII V.06
//Estado::Error:
Estado::Error,Estado::"Error configuración":
//--SII V.06
BEGIN
Estado := Estado::Pendiente;
"Descripción Estado" := '';
END;
//++SII V.07
Estado::Pendiente,Estado::"Pendiente Devengo":
"Descripción Estado" := '';
//--SII V.07
ELSE
ERROR(Text001,Estado);
END;
MODIFY;
//++SII V.08
UNTIL NEXT = 0;
END;
//--SII V.08
So I can see there when it's changing the status when clicking "Validar" button... but I can't find the process that is changing later the status to "Error"...
I'm checking the Job Queue Entries and I don't see anything that affects this columns.
Using the tool whereused I can't find anything.
I've also checked the table triggers and there's nothing, all empty.
I don't know how it's possible that I can't find anything exporting all objects to txt... I should be able to search "Descripción Estado" := or No existe el Registro
What could write to this column that it's not displayed in txt objects and not triggering the debugger?

Table can still be modified through SQL. This you will only find using SQL Server Profiler.
THEORETICALLY your version supports extensions v1, which you will not see when exporting objects to txt. So check if you have any extensions installed.
Maybe you just searching wrong. Try using Statical Prism. This is a greater tool for code exploring.
There is a trick I like to use. Your version supports subscriptions. Create a codeunit, put a subscriber function to it, subscribe to table's OnModify event and just throw an error when record is being modified and the value of the field is error. This will break some processes so do this on test DB. Then reproduce the behavior. Then check windows logs on server where nav instance is installed. Find your error in the log. Along with the error you will find stack trace. By stack trace you will see which object caused record modification.

Related

How to call Jira Rest API from Oracle APEX Page

Requirement -
Below fields to be displayed on a APEX page for any Jira issue created.
Issue Number/Issue Id
Summary
Description
Status
Assignee
Example, user01 and user02 both having access to Oracle APEX and Jira. user01 created 3 issues and user02 created 5 issues in Jira. Now when user01 who logs into Oracle APEX, should see 3 issues and when user02 who logs into Oracle APEX, should see 5 issues on a APEX page.
https://jira.local.com/jira/rest/api2
I'm new to APEX Rest service call and request to all of you to provide some sample APEX code to call Jira REST API using username/password for the above requirement.
Thanks all.
I have done something similar before. In my case, the goal was to get all the issues of project PRJ001 (Jira Project Key) from Jira and store them in a local database table (J_ISSUES), periodically, so I've created a Job that executed the following procedure from time to time:
create or replace PROCEDURE "JIRA_SYNC_ISSUES" as
var_response CLOB;
var_counter number := 0;
var_total number := 1;
var_prj_key varchar2(10);
begin
var_prj_key := 'PRJ001';
var_total := 1;
var_counter := 0;
while var_total > var_counter
loop
apex_session.create_session (p_app_id => 107, p_page_id => 1, p_username => 'USERNAME01');
var_response:= apex_web_service.make_rest_request(
p_url => 'https://yourcompany.atlassian.net/rest/api/2/search?jql=project="'|| var_prj_key ||'"&maxResults=100&startAt=' || var_counter || '',
p_http_method => 'GET',
p_credential_static_id => 'oud_rest'
);
SELECT JSON_VALUE(var_response, '$.total' RETURNING NUMBER) into var_total
FROM DUAL;
for i in (SELECT *
FROM
JSON_TABLE(var_response, '$.issues[*]'
COLUMNS (
key VARCHAR2(100) PATH '$.key',
prj_key VARCHAR2(100) PATH '$.fields.project.key',
status VARCHAR2(100) PATH '$.fields.status.name',
updated VARCHAR2(100) PATH '$.fields.updated',
assignee VARCHAR2(100) PATH '$.fields.assignee.name',
time_spent NUMBER PATH '$.fields.timespent'
)))
loop
begin
insert into j_issues (jis_key, jis_jpr_key, jis_status, jis_updated, jis_assignee, jis_time_spent)
values (i.key,
i.prj_key,
i.status,
to_timestamp(substr(i.updated,1,10)||' '||substr(i.updated,12,8),'YYYY-MM-DD HH24:MI:SS'),
i.assignee,
i.time_spent);
exception
when dup_val_on_index then
update j_issues
set jis_jpr_key = i.prj_key,
jis_status = i.status,
jis_updated = to_timestamp(substr(i.updated,1,10)||' '||substr(i.updated,12,8),'YYYY-MM-DD HH24:MI:SS'),
jis_assignee = i.assignee,
jis_time_spent = i.time_spent
where jis_key = i.key;
end;
var_counter := var_counter + 1;
end loop;
end loop;
end jira_sync_issues;
In the first part it is authenticating and making the call to the API. In the second, it takes the var_response and inserts it into the required table.
For the first part, I've read this: https://www.jmjcloud.com/blog/simplifying-apex_web_service-oauth2-client-credentials
For the second: https://docs.oracle.com/database/121/SQLRF/functions092.htm
Notice the var_counter and var_total variables. They are used to iterate through the Jira responses, because there is a limit of items being retrieved in each response. So, if you are expecting more than that limit, you should make more calls to retrieve them.
If the volume of issues is big, there are advantages in doing a scheduled sync like this instead of letting the user wait for the entire result. After the data is in your database, you can just query it as usual.
Let me know if it helps ;)

Alert message after submit and validation page in oracle apex

I have a dynamic action doing the below ,
Submit page ,
Successful Alert message,
Log out and redirect to another website (www.google.com),
And I have two required item in page.
When pressed the button and the item is null ,the successful Alert message appears and after that the system shows the error (the item is required). How can I show the successful alert message only when the process and validation are done without errors ,and when ok is pressed in the alert message redirect to website and log out from the sessions
There are different ways you could approach this. You're currently using a mix of Dynamic Actions and page-level validations and processes that aren't going to play well together. I suggest you move all the logic to Dynamic Actions. Here are step by step instructions to do what I think you're trying to do. You can learn from this and then integrate what you want back to your solution.
Create a new blank page. Mine was page 17. You'll need to update references to "P17" with your page number if it's different. Disable the page level attribute Warn on Unsaved Changes to prevent prompts before the redirect to Google.
Add a new HTML region to the page.
Add a new item to the region. Set Name to P17_FIRST_NAME and leave the default Type of Text Field.
Add a new item to the region. Set Name to P17_LAST_NAME and leave the default Type of Text Field.
Add a new item to the region. Set Name to P17_RESULT, Type to Hidden, and Value Protected to No. This item will be used to transfer messages from the server to the client via Ajax.
Add a button to the region. Set Name to RUN_PROCESS and Action to Defined by Dynamic Action.
Create a new Dynamic Action that fires when the button is clicked. The easiest way to do this is to right-click the button and select Create Dynamic Action. Set the Name to RUN_PROCESS clicked.
Select the Show action that was created by default for the Dynamic Action. Set Action to Execute PL/SQL Code and copy-paste the following code into the PL/SQL Code attribute.
declare
l_result_obj json_object_t := json_object_t();
l_errors_arr json_array_t := json_array_t();
l_error_obj json_object_t;
begin
if :P17_FIRST_NAME is null
then
l_error_obj := json_object_t();
l_error_obj.put('pageItem', 'P17_FIRST_NAME');
l_error_obj.put('message', 'First Name is required.');
l_errors_arr.append(l_error_obj);
end if;
if :P17_LAST_NAME is null
then
l_error_obj := json_object_t();
l_error_obj.put('pageItem', 'P17_LAST_NAME');
l_error_obj.put('message', 'Last Name is required.');
l_errors_arr.append(l_error_obj);
end if;
if l_errors_arr.get_size() > 0
then
l_result_obj.put('status', 'error');
l_result_obj.put('errors', l_errors_arr);
:P17_RESULT := l_result_obj.to_string();
return;
end if;
null; -- do "success" processing here
l_result_obj.put('status', 'success');
l_result_obj.put('message', 'Hi ' || :P17_LAST_NAME || ' ' || :P17_LAST_NAME ||
'! You will now be redirected to Google.');
:P17_RESULT := l_result_obj.to_string();
end;
As you can see, the validations are now being done inside the process. The PL/SQL code is making use of the JSON types introduced with Oracle 12.2. If you're on an older version of the database, you can adapt the code to use APEX_JSON instead.
While still in the Execute PL/SQL Code action, set Items to Submit to P17_FIRST_NAME,P17_LAST_NAME and Items to Return to P17_RESULT. This is how you can transfer values from the page into session state before the process executes and then back to the page after the process finishes executing.
Create a new Dynamic Action that fires on the Change event of P17_RESULT. The easiest way to do this is to right-click the item and select Create Dynamic Action. Set the Name to P17_RESULT changed.
Select the Show action that was created by default for the Dynamic Action. Set Action to Execute JavaScript Code and copy-paste the following code into the Code attribute.
var result = JSON.parse($v('P17_RESULT'));
apex.message.clearErrors();
if (result.status === 'error') {
for (var idx = 0; idx < result.errors.length; idx++) {
result.errors[idx].type = 'error';
result.errors[idx].location = ['page', 'inline'];
result.errors[idx].unsafe = false;
}
apex.message.showErrors(result.errors);
} else if (result.status === 'success') {
apex.message.alert(result.message, function(){
apex.navigation.redirect('https://google.com');
});
}
The JavaScript code takes the result from the process and either displays error messages or an alert. I'm using apex.message.alert instead of apex.message.showPageSuccess because the former supports a callback when the message is dismissed. When the message is dismissed, apex.navigation.redirect takes the user to Google.
Here's what it should look like in the end:
I hope there's enough information here for you to understand what's going on. Let me know if you have any questions. You'll find the documentation for apex.navigation and apex.message here: https://apex.oracle.com/jsapi
P.S. Here's an example of what the PL/SQL code would look like using APEX_JSON.
declare
l_error_count pls_integer := 0;
l_result_obj clob;
begin
apex_json.initialize_clob_output;
apex_json.open_object();
apex_json.open_array('errors');
if :P17_FIRST_NAME is null
then
l_error_count := l_error_count + 1;
apex_json.open_object();
apex_json.write('pageItem', 'P17_FIRST_NAME');
apex_json.write('message', 'First Name is required.');
apex_json.close_object();
end if;
if :P17_LAST_NAME is null
then
l_error_count := l_error_count + 1;
apex_json.open_object();
apex_json.write('pageItem', 'P17_LAST_NAME');
apex_json.write('message', 'Last Name is required.');
apex_json.close_object();
end if;
apex_json.close_array();
if l_error_count > 0
then
apex_json.write('status', 'error');
apex_json.close_object();
:P17_RESULT := apex_json.get_clob_output();
apex_json.free_output;
return;
end if;
null; -- do "success" processing here
apex_json.write('status', 'success');
apex_json.write('message', 'Hi ' || :P17_LAST_NAME || ' ' || :P17_LAST_NAME ||
'! You will now be redirected to Google.');
apex_json.close_object();
:P17_RESULT := apex_json.get_clob_output();
apex_json.free_output;
end;

Read-only condition not working

I'm developing an Oracle Application express (APEX 4.2) application.
One of the page controls (text box, title) have a "PL/SQL Expression" read-only condition:
:APP_PROJECT_READ_ONLY = 'YES'
:APP_PROJECT_READ_ONLY is an application item and it's set from a dynamic action on_load which fires on page load:
DECLARE
CURR_USER VARCHAR2(50);
BEGIN
IF :REQUEST = 'NEW' THEN
:APP_PROJECT_ID := 0;
:APP_PROJECT_READ_ONLY := 'NO';
ELSE
:APP_PROJECT_ID := :P2_ID;
SELECT OWNER INTO CURR_USER
FROM PROJECTS
WHERE ID = :APP_PROJECT_ID;
IF CURR_USER = :APP_USER THEN
:APP_PROJECT_READ_ONLY := 'NO';
ELSE
:APP_PROJECT_READ_ONLY := 'YES';
END IF;
END IF;
EXCEPTION WHEN NO_DATA_FOUND THEN
NULL;
END;
Checking session state shows that :APP_PROJECT_READ_ONLY's value is correct, but it doesn't seem to drive whether title is read only:
If I leave on_load's "page items to return" blank, then title is always editable.
However if I set it to title, then title will be always read-only and also it's source control doesn't work, it's leaved empty (in previous case it was working correctly).
How can I fix it?
Your problem is chronology.
The page renders, conditions evaluated, then you calculate your application item on the browser's page load.
Move your code into a computation, perhaps before regions, hence done as part of page render.
REQUEST values are organically only available in page processing, so unless you're explicitly setting that, it may be something to look out for.
You should also consider using declarative actions, where possible.
www.grassroots-oracle.com/2013/05/performance-of-apex-conditions.html

Deleting files from the users profile when uninstalling an Inno based setup

Is it possible to delete files from this folder and how?
Currently i have this which doesnt work
[UninstallDelete]
Type: files; Name: "{userappdata}\Roaming\Myapp\*";
Type: files; Name: "{commonappdata}\Roaming\Myapp\*";
Type: files; Name: "{app}\*.*";
[Code]
/////////////////////////////////////////////////////////////////////
function GetUninstallString(): String;
var
sUnInstPath: String;
sUnInstallString: String;
begin
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
sUnInstallString := '';
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
Result := sUnInstallString;
end;
/////////////////////////////////////////////////////////////////////
function IsUpgrade(): Boolean;
begin
Result := (GetUninstallString() <> '');
end;
/////////////////////////////////////////////////////////////////////
function UnInstallOldVersion(): Integer;
var
sUnInstallString: String;
iResultCode: Integer;
begin
// Return Values:
// 1 - uninstall string is empty
// 2 - error executing the UnInstallString
// 3 - successfully executed the UnInstallString
// default return value
Result := 0;
// get the uninstall string of the old app
sUnInstallString := GetUninstallString();
if sUnInstallString <> '' then begin
sUnInstallString := RemoveQuotes(sUnInstallString);
if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
Result := 3
else
Result := 2;
end else
Result := 1;
end;
/////////////////////////////////////////////////////////////////////
procedure CurStepChanged(CurStep: TSetupStep);
begin
if (CurStep=ssInstall) then
begin
if (IsUpgrade()) then
begin
UnInstallOldVersion();
end;
end;
end;
While Inno can remove files from the profile of the user running the uninstaller, it can not touch any other user's profile.
If the user trying to run the uninstaller is a limited user, it will ask for the admin details and so any {user...} constants will resolve to the admin user, NOT the limited user.
Your best option in this case is it leave any of the user's configuration and data in case they want to reinstall or have roaming profiles. Also note that in your code above, the old setup is removed during the upgrade which will trigger the "remove all the user's data" option. I'm sure that's not what you want...

How to hide standard interfaces from the default page WebService

Some time ago I've been thinking about how to hide from default page of the web service the IAppServer and IAppServerSOAP interfaces and that appear by default. I know that my Webservice interface, has these interfaces as ancestors, but I believe pointless "see" these interfaces on the default page, as the client programs do not use them directly.
Is there any way to hide these interfaces and just keep our interface and others that were created?
You should be able to alter the WSDL returned by the service. I think there's a WSDL control, where you can override the WSDL response to either edit it, or substitute whatever you want.
Specifically, add a TWSDLHTMLPublish component to your WebModule form. Use the OnBeforePublishingWSDL to write your own WSDL, like this:
procedure TWebModule2.WSDLHTMLPublish1BeforePublishingWSDL(
const IntfName: WideString; var WSDL: WideString; var Handled: Boolean);
begin
WSDL := '<foo>bar</foo>';
Handled := true;
end;
Thanks Carlos!
But finally I found other approach . . . simply unregister the interface
InvRegistry.UnRegisterInterface(TypeInfo(IAppServer));
InvRegistry.UnRegisterInterface(TypeInfo(IAppServerSOAP));
InvRegistry.UnRegisterInterface(TypeInfo(IWSDLPublish));
If your client applications do not need server to implement IAppServer (or IAppServerSOAP) then it is pointless to implement these. I expect you have implemented them - as you already said - because they are already implemented in ancestors of your objects - I expect it to be TSOAPDataModule.
So, instead of hiding them in the WSDL, i would suggest descending your server objects from a class that does not already introduce IAppServerxxxx. Which might be simple TDataModule (if you need a "container" object) or TInvokableClass.
Finally I got it!
To do so, all I had to do was edit the WebModule2DefaultHandlerAction method, i.e., the OnAction event handler of the DefaultHandler WebActionItem.
The final event handler looks like this now:
procedure TWEBMWebService.WebModule2DefaultHandlerAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
Conteudo: String;
begin
WSHPWebService.ServiceInfo(Sender, Request, Response, Handled);
Conteudo := Response.Content;
try
HideInterfaces(Conteudo,['IAppServer','IAppServerSOAP']);
finally
Response.Content := Conteudo;
end;
end;
The HideInterfaces procedure follows:
procedure HideInterfaces(var aContent: String; aInterfaces: array of string);
var
Intf: String;
i: Integer;
begin
if Length(aInterfaces) = 0 then
Exit;
with TStringList.Create do
try
{ Remove todos os enters }
aContent := StringReplace(aContent,#13#10,' ',[rfreplaceAll]);
{ Separa tudo baseando-se nos TR }
Text := StringReplace(aContent,'<tr>',#13#10'<tr>'#13#10,[rfreplaceAll,rfIgnoreCase]);
Text := StringReplace(Text,'</tr>',#13#10'</tr>'#13#10,[rfreplaceAll,rfIgnoreCase]);
{ Neste ponto, cada linha do StringList contém ou <TR>, ou </TR>, ou o que
houver entre os dois, então circulamos por cada interface que precisa ser
ocultada }
for Intf in aInterfaces do
begin
for i := 0 to Pred(Count) do
if Pos(LowerCase(Intf),LowerCase(Strings[i])) > 0 then
Break;
{ Se achou a interface, oculta a linha inteira de tabela, removendo do
StringList i, i-1 e i+1 }
if i < Count then
begin
Delete(i+1);
Delete(i);
Delete(i-1);
end;
end;
aContent := Text;
finally
Free;
end;
end;
The comments are in Portuguese, sorry, but it's easy to understand the code. If you like it and use it, please let me know and give me some credits, right ;)
I would like to thank you all for the valuable answers. Without your help I would never find the solution! Thank You All!