Actions¶
An action executes in the database, and is always followed by an automatic commit or rollback. Actions can be connected to an entity, or specified directly in the main section.
action MoveSelectedPart {
parameter MoveDirection Text;
}
action SetEmuFromDate {
ludependencies = CurrencyCode;
parameter EmuCurrencyFromDate Date {
required = [false];
}
}
Implementation¶
The code example below changes the implementation handling of an item (typically attribute or action) to Java, instead of the default which is PL/SQL.
Note! It is recommended to only use this when a custom implementation is necessary, where the default PL/SQL implementation does not suffice.
action DeleteFile {
implementation = "Java";
}
Ludependencies¶
A list of model entities that are a part of the returned data.
action MyAction Text {
ludependencies = CustomerOrder, SalesPart;
}
Parameter¶
Input parameter to an action or function.
Note: For actions and functions on entities, the entity key is always the first parameter and has no need to be specified, only additional parameters need to be specified.
action LostLine {
parameter ReasonId Text;
parameter LostTo Text;
parameter ReasonNote Text {
required = [false];
}
ludependencies = BusinessOpportunityLine;
}
Example 1 (All connected code to an Action called by a command button)¶
Projection file:
action PromoteObsolete {
ludependencies = DocIssue;
parameter DocClass Text;
parameter DocNo Text;
parameter DocSheet Text;
parameter DocRev Text;
parameter Option Text {
required = [false];
}
}
Plsvc file:
PROCEDURE Promote_Obsolete (
docclass_ IN VARCHAR2,
doc_no_ IN VARCHAR2,
doc_sheet_ IN VARCHAR2,
doc_rev_ IN VARCHAR2,
option_ IN VARCHAR2 )
IS
objid_ VARCHAR2(2000);
objversion_ VARCHAR2(2000);
info_ VARCHAR2(2000);
attr_ VARCHAR2(32000);
BEGIN
Doc_Issue_API.Get_Id_Version_By_Keys(doc_class_, doc_no_, doc_sheet_, doc_rev_, objid_, objversion_);
Doc_Issue_API.Promote_To_Obsolete(info_, objid_, objversion_, attr_, 'DO');
IF option_ = 'MOVED' THEN
Move_Object_Connections(docclass_, doc_no_, doc_sheet_, doc_rev_, option_);
END IF;
END Promote_Obsolete;
PROCEDURE Move_Object_Connections (
docclass_ IN VARCHAR2,
doc_no_ IN VARCHAR2,
doc_sheet_ IN VARCHAR2,
doc_rev_ IN VARCHAR2,
option_ IN VARCHAR2 )
IS
BEGIN
Doc_Reference_Object_API.Move_From_Obsolete(doc_class_, doc_no_, doc_sheet_, doc_rev_, option_);
END Move_Object_Connections;
Client file:
command Obsolete {
label = "Obsolete";
variable HasMovedObj {
type = Text;
}
variable Option {
type = Text;
}
variable IsStructureDoc;
enabled = [(Objstate = "Preliminary" or Objstate = "Approved" or Objstate = "Released") and EdmFileRef.Objstate != "CheckedOut" and EdmFileRef.Objstate != "OperationInProgress" and IsAccessOwner = "TRUE"];
execute {
if [RedlineFileStatus = "TRUE"] {
alert("Cannot set documents to obsolete when comment file is checked out.");
exit CANCEL;
}
call CheckStrucObsolete(DocClass, DocNo) into IsStructureDoc;
if [IsStructureDoc = "TRUE"] {
confirm("Warning: The document you are trying to set to obsolete is part of a document structure. Do you want to continue with this operation?") {
when CANCEL {
exit CANCEL;
}
}
}
call IsObjConSatisfied(DocClass, DocNo, DocSheet, DocRev) into HasMovedObj;
if [HasMovedObj = "TRUE"] {
dialog RestoreObjConDlg into(Option) {
when OK {
if [Option = "Inherited"] {
set Option = "MOVED";
}
}
when CANCEL {
exit CANCEL;
}
}
}
else {
confirm("Do you wish to obsolete the Document?") {
when CANCEL {
exit CANCEL;
}
}
}
call PromoteObsolete(DocClass, DocNo, DocSheet, DocRev, Option);
}
}
Example 2 (All connected code to an Action called by an Assistant)¶
Projection file:
action ReportQuickTime {
ludependencies = JtTaskTransaction, JtExecutionInstance;
parameter TaskSeq Number;
parameter ExecutionInstanceSeq Number;
parameter MaintOrgSite Text;
parameter MaintOrg Text;
parameter ResourceSeq Number;
parameter TransactionDate Timestamp;
parameter Hours Number;
parameter TimeType Text;
parameter Comment Text {
required = [false];
}
}
Client file:
assistant QuickReportAssistant using QuickTimeReportSet
{
label = "Report Time";
setup InitAssignment {
variable TaskNo;
variable AssignmentNo;
variable PlannedHr;
variable TimeReportDefault {
type = Structure(QuickToolReportStruct);
}
execute {
set TaskSeq = TaskNo;
set ExecutionInstanceSeq = AssignmentNo;
set Hours = PlannedHr;
call GetTimeQuickReport(TaskSeq, ExecutionInstanceSeq) into TimeReportDefault;
set TaskSite = TimeReportDefault.TaskSite;
set TransactionDate = TimeReportDefault.TodayDate;
set TimeType = TimeReportDefault.DefTimeType;
set WoNo = TimeReportDefault.WoNo;
set Company = TimeReportDefault.Company;
set MaintOrgSite = TimeReportDefault.MaintOrgSite;
set MaintOrg = TimeReportDefault.MaintOrg;
set ResourceId = TimeReportDefault.ResourceId;
set ResourceSeq = TimeReportDefault.ResourceSeq;
}
}
steps {
step {
label = "Report Time";
group QuickReportGroup;
//list ReportedTimeList(ReportedTimeArray);
}
final step {
}
cancelled step {
}
}
finish command {
execute {
call ReportQuickTime(TaskSeq, ExecutionInstanceSeq, MaintOrgSite, MaintOrg, ResourceSeq, TransactionDate, Hours, TimeType, TimeReportComment);
navigate back;
}
}
cancel command {
execute {
navigate back;
}
}
restart command {
visible = [false];
}
}
Plsvc file:
PROCEDURE Report_Quick_Time (
taskseq_ IN NUMBER,
execution_instance_seq_ IN NUMBER,
maint_org_site_ IN VARCHAR2,
maint_org_ IN VARCHAR2,
resource_seq_ IN NUMBER,
transaction_date_ IN DATE,
hours_ IN NUMBER,
time_type_ IN VARCHAR2,
comment_ IN VARCHAR2)
IS
transaction_id_ NUMBER;
BEGIN
IF(Resource_API.Get_Resource_Type_Db(resource_seq_) != Resource_Types_API.DB_PERSON) THEN
Jt_Task_Transaction_API.Create_Time_Tool_Transaction(
transaction_id_,
'TOOLS',
task_seq_,
Jt_Execution_Instance_API.Get_Task_Resource_Seq(task_seq_,execution_instance_seq_),
execution_instance_seq_,
NULL,
NULL,
resource_seq_,
hours_,
transaction_date_,
maint_org_site_,
maint_org_,
time_type_,
comment_
);
END IF;
END Report_Quick_Time_;
Unbound Actions and Security¶
Unlike bound actions, unbound actions do not come with its own row level security, and have to be defined by the developer.
Initialcheck for securing Unbound Actions¶
Due to security reasons, unbound actions require a value set against the initialcheck
property. The initialcheck
specifies a piece of code that needs to be executed before the actual action takes place, to enforce row level security for the action (provided it is needed).
If an action is bound, initialcheck
is normally not needed since the action operates on the data provided by the OData entity. This is where security is enforced by fetching the record, using the row-level security defined on the corresponding View.
For an unbound action it is possible define one more initialcheck
as per the requirement. They can be defined in several different ways as follows:
No Security¶
initialcheck none;
Typically, this applies to actions without any parameters or with parameters that are not keys. Actions connected to a virtual or structures also normally use this initialcheck
definition.
Security implemented in PLSQL Logic¶
initialcheck implementation;
Indicates that row level security is implemented by manually written code somewhere within the action implementation (that is the business logic or the PLSVC file).
Security using predefined checks¶
initialcheck UserAllowedSite(Contract);
parameter Contract Text;
parameter PartNo Text;
This is the use of one (of several) predefined initialcheck
definitions that makes use of the "user allowed site function". Using one of the predefined checks results in code generation enforcing the security using the specified function in the PLSVC layer.
Note! When using predefined checks, the argument that is passed in the function needs to be defined as a parameter. In the example above Contract
is a parameter.
Security using custom check¶
initialcheck MyOwnCheck(Contract, PartNo);
A custom check can also be implemented for enforcing the security. It is necessary to ensure that the function used together with the initialcheck
actually exists in the.plsvc file with the exact method signature. In the above example, the PLSVC file must contain a function called My_Own_Check___
, with two parameters with the same datatype that is defined in the action definition. The functions used in the custom check must also return a Boolean value where TRUE means the user is allowed to run the action, and FALSE means otherwise.
List of available predefined initialcheck functions¶
Following initialcheck
functions are predefined in Developer Studio:
UserAllowedSite(Contract)
UserAllowedCompany(Company)
UserAllowedHrCompany(Company)
UserAllowedHrEmployee(Company, EmpNo)
UserAllowedHrEmployee(Company, EmpNo, LogicalUnit)
UserAllowedHrEmployee(Company, EmpNo, LogicalUnit, TransactionDate)
UserAllowedHrPerson(PersonId)
UserAllowedHrPerson(PersonId, LogicalUnit)
UserAllowedHrPerson(PersonId, LogicalUnit, TransactionDate)
What this means is that if any of these function names, with the correct number of parameters, are set with the initialcheck
, the corresponding PL/SQL code is automatically generated, without having to be defined by the developer.
Each one of the reserved initialcheck
functions have a corresponding PL/SQL procedure, which can be used when there is a need to do such checks from within the PLSVC file.
The function and their corresponding PL/SQL Procedures are listed below:
InitialCheck Function | Corresponding PL/SQL Procedure |
---|---|
UserAllowedSite | User_Allowed_Site_API.Is_Authorized |
UserAllowedCompany | User_Finance_API.Is_User_Authorized |
UserAllowedHrCompany | User_Access_API.Is_User_Company_Id |
UserAllowedHrEmployee | User_Access_API.Is_User_Available_Emp_No |
UserAllowedHrPerson | User_Access_API. Is_User_Available_Person_Id |
Typical usage for these can be when unpacking a string with a selection containing key references (that is KeyRef
s) where once unpacked, there is a need to perform the security enforcement for each key reference.