project BLF > class BSODViolationRule2 > method CheckRule2

Description

This method will check the current database situation for violations to SOD rule 2 and register new conflicts. Check can be done for a single user, a single role, for a single SOD category, or for the entire system.


Parameters


iiUsrIDinputinteger
iiRoleIDinputinteger
iiSODCategoryIDinputinteger
icUsrLogininputcharacter
oiReturnStatusoutputintegerReturn status of the method.


Internal usage


BLF
method BResource.PostTransaction
method BRole.PostTransaction
method BSODCategoryExclusion.PostTransaction
method BSODPolicyException.PostTransaction
method BSystem.PostTransaction


program code (program1/bsodviolationrule2.p)

define buffer Resources1 for Resources.
define buffer Resources2 for Resources.
define buffer RoleResource1 for RoleResource.
define buffer RoleResource2 for RoleResource.
define buffer Role1 for Role.
define buffer Role2 for Role.
define buffer UsrRoleCompany1 for UsrRoleCompany.
define buffer UsrRoleCompany2 for UsrRoleCompany.

if iiSODCategoryID = 0
then do:
    /* ================================================================= */
    /* Validate by user : make a list of users to validate.              */
    /* ================================================================= */
    empty temp-table tUsersForCheckRule2.
    
    if iiUsrID = 0
    then for each Role fields (Role_ID RoleName RoleSODException) no-lock where
                 (Role.Role_ID = iiRoleID or iiRoleID = 0) and
                  Role.RoleSODException = no,
             each UsrRoleCompany fields (Usr_ID Role_ID Company_ID) no-lock where
                  UsrRoleCompany.Role_ID = Role.Role_ID,
            first Usr fields (Usr_ID UsrLogin) no-lock where
                  Usr.Usr_ID = UsrRoleCompany.Usr_ID,
            first Company fields (Company_ID CompanyCode Domain_ID) no-lock where
                  Company.Company_ID = UsrRoleCompany.Company_ID,
            first Domains fields (Domain_ID DomainCode) no-lock where
                  Domains.Domain_ID = Company.Domain_ID on error undo, throw:
        create tUsersForCheckRule2.
        assign tUsersForCheckRule2.tiUsrId       = Usr.Usr_ID
               tUsersForCheckRule2.tcUserLogin   = Usr.UsrLogin
               tUsersForCheckRule2.tiCompany_ID  = Company.Company_ID
               tUsersForCheckRule2.tcCompanyCode = Company.CompanyCode
               tUsersForCheckRule2.tiDomain_ID   = Domains.Domain_ID
               tUsersForCheckRule2.tcDomainCode  = Domains.DomainCode
               tUsersForCheckRule2.tiRole_ID     = Role.Role_ID
               tUsersForCheckRule2.tcRoleName    = Role.RoleName.
    end.    /* each Role */
    else for first Usr fields (Usr_ID UsrLogin) no-lock where
                   Usr.Usr_ID = iiUsrID,
              each UsrRoleCompany fields (Usr_ID Role_ID Company_ID) no-lock where
                   UsrRoleCompany.Usr_ID = Usr.Usr_ID,
             first Role fields (Role_ID RoleName RoleSODException) no-lock where
                   Role.Role_ID = UsrRoleCompany.Role_ID and
                   Role.RoleSODException = no,
             first Company fields (Company_ID CompanyCode Domain_ID) no-lock where
                   Company.Company_ID = UsrRoleCompany.Company_ID,
             first Domains fields (Domain_ID DomainCode) no-lock where
                   Domains.Domain_ID = Company.Domain_ID on error undo, throw:
        create tUsersForCheckRule2.
        assign tUsersForCheckRule2.tiUsrId       = Usr.Usr_ID
               tUsersForCheckRule2.tcUserLogin   = Usr.UsrLogin
               tUsersForCheckRule2.tiCompany_ID  = Company.Company_ID
               tUsersForCheckRule2.tcCompanyCode = Company.CompanyCode
               tUsersForCheckRule2.tiDomain_ID   = Domains.Domain_ID
               tUsersForCheckRule2.tcDomainCode  = Domains.DomainCode
               tUsersForCheckRule2.tiRole_ID     = Role.Role_ID
               tUsersForCheckRule2.tcRoleName    = Role.RoleName.
    end.    /* first Usr */
    
    /* =========================================================================== */
    /* Remove users with only one role as they cannot ever have a rule 2 violation */
    /* =========================================================================== */
    if iiRoleID = 0
    then for each tUsersForCheckRule2 break by tUsersForCheckRule2.tiUsrId by tUsersForCheckRule2.tiCompany_ID:
        if first-of(tUsersForCheckRule2.tiCompany_ID)
        and last-of(tUsersForCheckRule2.tiCompany_ID)
        then delete tUsersForCheckRule2.
    end.
    
    /* ================================================================= */
    /* Validate user by user (1 user = 1 transaction)                    */
    /* ================================================================= */
    for each tUsersForCheckRule2 break by tUsersForCheckRule2.tiUsrId on error undo, throw:

        if first-of (tUsersForCheckRule2.tiUsrId)
        then do:
            <M-5 run DataLoad
               (input  '' (icRowids), 
                input  '' (icPkeys), 
                input  '' (icObjectIds), 
                input  'for each SODViolation2 where SODViolation2.Usr_ID = ' + string(tusersForCheckRule2.tiUsrId) (icFreeform), 
                input  no (ilKeepPrevious), 
                output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
            if viFcReturnSuper = -4
            then viFcReturnSuper = 0.
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
        end.    /* first-of (tUsersForCheckRule2.tiUsrId) */
        
        for each RoleResource1 fields (Role_ID Resource_ID) no-lock where
                 RoleResource1.Role_ID = tUsersForCheckRule2.tiRole_ID,
           first Resources1 fields (Resource_ID ResourceURI SODCategory_ID) no-lock where
                 Resources1.Resource_ID = RoleResource1.Resource_ID and
                 Resources1.SODcategory_ID <> 0
                 break by Resources1.SODcategory_ID on error undo, throw:
                 
            /* If no violations are found for a SOD category then skip validations for all next resources in this SOD category.
             * If violations are found keep validating because violations must be reported on resource level.
             */
            if first-of (Resources1.SODcategory_ID)
            then vlConflictFound = no.
            
            if first-of (Resources1.SODcategory_ID)
            or vlConflictFound
            then
            /* Lookup user-company combinations with access to current edited role and to any other role with access to any resource from a conflicting category */
            if iiRoleID = 0
            then
            for each bUsersForCheckRule2 where
                     bUsersForCheckRule2.tiUsrId = tUsersForCheckRule2.tiUsrId and
                     bUsersForCheckRule2.tiCompany_ID = tUsersForCheckRule2.tiCompany_ID and
                     bUsersForCheckRule2.tiRole_ID > tUsersForCheckRule2.tiRole_ID,   /* yes > not <>, to avoid checking A-B and B-A */
                each Role fields (Role_ID RoleName RoleSODException) no-lock where
                     Role.Role_ID = bUsersForCheckRule2.tiRole_ID and
                     Role.RoleSODException = no,
                each RoleResource2 fields (Role_ID Resource_ID) no-lock where
                     RoleResource2.Role_ID = Role.Role_ID,
                each Resources2 fields (Resource_ID ResourceURI SODCategory_ID) no-lock where
                     Resources2.Resource_ID = RoleResource2.Resource_ID and
                     Resources2.SODcategory_ID <> 0,
                each SODExclusion fields (SODCategory1_ID SODCategory2_ID SODExclusionLevel) no-lock where
                     SODExclusion.SODCategory1_ID = Resources1.SODcategory_ID and
                     SODExclusion.SODCategory2_ID = Resources2.SODcategory_ID on error undo, throw:
                
                vlAdded = no.
                vlPolicyException = no.
                for each SODException fields (SODException_ID Usr_ID) no-lock where
                         SODException.Usr_ID = bUsersForCheckRule2.tiUsrId:
                    if can-find (first SODExceptionLn where
                         SODExceptionLn.SODException_ID = SODException.SODException_ID and
                         SODExceptionLn.SODCategory1_ID = Resources1.SODcategory_ID and
                         SODExceptionLn.SODCategory2_ID = Resources2.SODcategory_ID and
                        (SODExceptionLn.Company_ID = bUsersForCheckRule2.tiCompany_ID or SODExceptionLn.Company_ID = 0) and
                        (SODExceptionLn.Domain_ID = bUsersForCheckRule2.tiDomain_ID or SODExceptionLn.Domain_ID = 0))
                    or can-find (first SODExceptionLn where
                         SODExceptionLn.SODException_ID = SODException.SODException_ID and
                         SODExceptionLn.SODCategory1_ID = Resources2.SODcategory_ID and
                         SODExceptionLn.SODCategory2_ID = Resources1.SODcategory_ID and
                        (SODExceptionLn.Company_ID = bUsersForCheckRule2.tiCompany_ID or SODExceptionLn.Company_ID = 0) and
                        (SODExceptionLn.Domain_ID = bUsersForCheckRule2.tiDomain_ID or SODExceptionLn.Domain_ID = 0))
                    then do:
                        vlPolicyException = yes.
                        leave.
                    end.
                end.    /* each SODException */
                if vlPolicyException = no
                then do:
                    vlConflictFound = yes.
        
                    vcSODCategoryCode1 = "".
                    for first SODCategory fields (SODCategory_ID SODCategoryCode) no-lock where
                              SODCategory.SODCategory_ID = Resources1.SODcategory_ID:
                        vcSODCategoryCode1 = SODCategory.SODCategoryCode.
                    end.
            
                    vcSODCategoryCode2 = "".
                    for first SODCategory fields (SODCategory_ID SODCategoryCode) no-lock where
                              SODCategory.SODCategory_ID = Resources2.SODcategory_ID:
                        vcSODCategoryCode2 = SODCategory.SODCategoryCode.
                    end.

                    /* conflict found. Check if it is already known */
                    find first tSODViolation2 where
                               tSODViolation2.Usr_ID          = tUsersForCheckRule2.tiUsrId              and
                               tSODViolation2.Domain_ID       = tUsersForCheckRule2.tiDomain_ID      and
                               tSODViolation2.Company_ID      = tUsersForCheckRule2.tiCompany_ID     and
                               tSODViolation2.Role2_ID        = tUsersForCheckRule2.tiRole_ID        and
                               tSODViolation2.SODCategory2_ID = Resources1.SODCategory_ID and
                               tSODViolation2.Role1_ID        = Role.Role_ID        and
                               tSODViolation2.SODCategory1_ID = Resources2.SODCategory_ID no-error.
                    if available tSODViolation2
                    then assign vlSwitch = yes.
                    else do:
                        find first tSODViolation2 where
                                   tSODViolation2.Usr_ID          = tUsersForCheckRule2.tiUsrId              and
                                   tSODViolation2.Domain_ID       = tUsersForCheckRule2.tiDomain_ID      and
                                   tSODViolation2.Company_ID      = tUsersForCheckRule2.tiCompany_ID     and
                                   tSODViolation2.Role1_ID        = tUsersForCheckRule2.tiRole_ID        and
                                   tSODViolation2.SODCategory1_ID = Resources1.SODCategory_ID and
                                   tSODViolation2.Role2_ID        = Role.Role_ID        and
                                   tSODViolation2.SODCategory2_ID = Resources2.SODCategory_ID no-error.
                        if available tSODViolation2
                        then assign vlSwitch = no.
                        else do:
                            <M-74 run AddDetailLine
                               (input  'SODViolation2' (icTable), 
                                input  '' (icParentRowid), 
                                output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
                            if viFcReturnSuper <> 0
                            then oiReturnStatus = viFcReturnSuper.
                            if viFcReturnSuper < 0
                            then return.
                            
                            /* BLF-4424
                             * Conflicts should always be reported as 'A conflicts with B', never as 'B conflicts with A'.
                             */
                            if vcSODCategoryCode1 > vcSODCategoryCode2
                            then assign tSODViolation2.Usr_ID          = tUsersForCheckRule2.tiUsrId
                                        tSODViolation2.Domain_ID       = tUsersForCheckRule2.tiDomain_ID
                                        tSODViolation2.Company_ID      = tUsersForCheckRule2.tiCompany_ID
                                        tSODViolation2.Role1_ID        = Role.Role_ID
                                        tSODViolation2.SODCategory1_ID = Resources2.SODCategory_ID
                                        tSODViolation2.Role2_ID        = tUsersForCheckRule2.tiRole_ID
                                        tSODViolation2.SODCategory2_ID = Resources1.SODCategory_ID
                                        vlSwitch = yes.
                            else assign tSODViolation2.Usr_ID          = tUsersForCheckRule2.tiUsrId
                                        tSODViolation2.Domain_ID       = tUsersForCheckRule2.tiDomain_ID
                                        tSODViolation2.Company_ID      = tUsersForCheckRule2.tiCompany_ID
                                        tSODViolation2.Role1_ID        = tUsersForCheckRule2.tiRole_ID
                                        tSODViolation2.SODCategory1_ID = Resources1.SODCategory_ID
                                        tSODViolation2.Role2_ID        = Role.Role_ID
                                        tSODViolation2.SODCategory2_ID = Resources2.SODCategory_ID
                                        vlSwitch = no.
                        end.    /* available tSODViolation2 */
                    end.    /* available tSODViolation2 */
    
                    if not can-find (first tSODViolation2R where
                                           tSODViolation2R.tc_ParentRowid = tSODViolation2.tc_Rowid and
                                           tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 2 else 1) and
                                           tSODViolation2R.Resource_ID = Resources1.Resource_ID)
                    then do:
                        <M-89 run AddDetailLine
                           (input  'SODViolation2R' (icTable), 
                            input  tSODViolation2.tc_Rowid (icParentRowid), 
                            output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
                        if viFcReturnSuper <> 0
                        then oiReturnStatus = viFcReturnSuper.
                        if viFcReturnSuper < 0
                        then return.
                        assign tSODViolation2R.SODViolation2_ID       = tSODViolation2.SODViolation2_ID
                               tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 2 else 1)
                               tSODViolation2R.Resource_ID            = Resources1.Resource_ID
                               vlAdded = yes.
                    end.    /* can-find (first tSODViolation2R) */
                            
                    if not can-find (first tSODViolation2R where
                                           tSODViolation2R.tc_ParentRowid = tSODViolation2.tc_Rowid and
                                           tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 1 else 2) and
                                           tSODViolation2R.Resource_ID = Resources2.Resource_ID)
                    then do:
                        <M-45 run AddDetailLine
                           (input  'SODViolation2R' (icTable), 
                            input  tSODViolation2.tc_Rowid (icParentRowid), 
                            output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
                        if viFcReturnSuper <> 0
                        then oiReturnStatus = viFcReturnSuper.
                        if viFcReturnSuper < 0
                        then return.
                        assign tSODViolation2R.SODViolation2_ID       = tSODViolation2.SODViolation2_ID
                               tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 1 else 2)
                               tSODViolation2R.Resource_ID            = Resources2.Resource_ID
                               vlAdded = yes.
                    end.    /* can-find (first tSODViolation2R) */
    
                    if vlAdded
                    then do:
                        if vhBSODLog7Inst = ?
                        then do:
                            <I-85 {bFcAddToTransaction
                                 &CLASS           = "BSODLog"}>
                        end.
                        <M-43 run AddLogEntry
                           (input  {&SODLOG-RULE2} (icRule), 
                            input  {&SODLOG-STATUS-VIOLATION} (icStatus), 
                            input  tUsersForCheckRule2.tcUserLogin (icUsrLogin), 
                            input  tUsersForCheckRule2.tcDomainCode (icDomainCode), 
                            input  tUsersForCheckRule2.tcCompanyCode (icCompanyCode), 
                            input  tUsersForCheckRule2.tcRoleName (icRole1Name), 
                            input  Role.RoleName (icRole2Name), 
                            input  vcSODCategoryCode1 (icCategory1Code), 
                            input  vcSODCategoryCode2 (icCategory2Code), 
                            input  Resources1.ResourceURI (icResource1URI), 
                            input  Resources2.ResourceURI (icResource2URI), 
                            input  SODExclusion.SODExclusionLevel (icExclusionLevel)) in BSODLog>
                    end.
                end.    /* vlPolicyException = no */
            end.    /* each bUsersForCheckRule2 */
            else
            for each UsrRoleCompany fields (Role_ID Usr_ID Company_ID Domain_ID) no-lock where
                     UsrRoleCompany.Usr_ID = tUsersForCheckRule2.tiUsrId and
                     UsrRoleCompany.Company_ID = tUsersForCheckRule2.tiCompany_ID and
                     UsrRoleCompany.Role_ID <> tUsersForCheckRule2.tiRole_ID,
                each Role fields (Role_ID RoleName RoleSODException) no-lock where
                     Role.Role_ID = UsrRoleCompany.Role_ID and
                     Role.RoleSODException = no,
                each RoleResource2 fields (Role_ID Resource_ID) no-lock where
                     RoleResource2.Role_ID = Role.Role_ID,
                each Resources2 fields (Resource_ID ResourceURI SODCategory_ID) no-lock where
                     Resources2.Resource_ID = RoleResource2.Resource_ID and
                     Resources2.SODcategory_ID <> 0,
                each SODExclusion fields (SODCategory1_ID SODCategory2_ID SODExclusionLevel) no-lock where
                     SODExclusion.SODCategory1_ID = Resources1.SODcategory_ID and
                     SODExclusion.SODCategory2_ID = Resources2.SODcategory_ID on error undo, throw:
                
                vlAdded = no.
                vlPolicyException = no.
                for each SODException fields (SODException_ID Usr_ID) no-lock where
                         SODException.Usr_ID = UsrRoleCompany.Usr_ID:
                    if can-find (first SODExceptionLn where
                         SODExceptionLn.SODException_ID = SODException.SODException_ID and
                         SODExceptionLn.SODCategory1_ID = Resources1.SODcategory_ID and
                         SODExceptionLn.SODCategory2_ID = Resources2.SODcategory_ID and
                        (SODExceptionLn.Company_ID = UsrRoleCompany.Company_ID or SODExceptionLn.Company_ID = 0) and
                        (SODExceptionLn.Domain_ID = UsrRoleCompany.Domain_ID or SODExceptionLn.Domain_ID = 0))
                    or can-find (first SODExceptionLn where
                         SODExceptionLn.SODException_ID = SODException.SODException_ID and
                         SODExceptionLn.SODCategory1_ID = Resources2.SODcategory_ID and
                         SODExceptionLn.SODCategory2_ID = Resources1.SODcategory_ID and
                        (SODExceptionLn.Company_ID = UsrRoleCompany.Company_ID or SODExceptionLn.Company_ID = 0) and
                        (SODExceptionLn.Domain_ID = UsrRoleCompany.Domain_ID or SODExceptionLn.Domain_ID = 0))
                    then do:
                        vlPolicyException = yes.
                        leave.
                    end.
                end.    /* each SODException */
                if vlPolicyException = no
                then do:
                    vlConflictFound = yes.
        
                    vcSODCategoryCode1 = "".
                    for first SODCategory fields (SODCategory_ID SODCategoryCode) no-lock where
                              SODCategory.SODCategory_ID = Resources1.SODcategory_ID:
                        vcSODCategoryCode1 = SODCategory.SODCategoryCode.
                    end.
            
                    vcSODCategoryCode2 = "".
                    for first SODCategory fields (SODCategory_ID SODCategoryCode) no-lock where
                              SODCategory.SODCategory_ID = Resources2.SODcategory_ID:
                        vcSODCategoryCode2 = SODCategory.SODCategoryCode.
                    end.

                    /* conflict found. Check if it is already known */
                    find first tSODViolation2 where
                               tSODViolation2.Usr_ID          = tUsersForCheckRule2.tiUsrId              and
                               tSODViolation2.Domain_ID       = tUsersForCheckRule2.tiDomain_ID      and
                               tSODViolation2.Company_ID      = tUsersForCheckRule2.tiCompany_ID     and
                               tSODViolation2.Role2_ID        = tUsersForCheckRule2.tiRole_ID        and
                               tSODViolation2.SODCategory2_ID = Resources1.SODCategory_ID and
                               tSODViolation2.Role1_ID        = Role.Role_ID        and
                               tSODViolation2.SODCategory1_ID = Resources2.SODCategory_ID no-error.
                    if available tSODViolation2
                    then assign vlSwitch = yes.
                    else do:
                        find first tSODViolation2 where
                                   tSODViolation2.Usr_ID          = tUsersForCheckRule2.tiUsrId              and
                                   tSODViolation2.Domain_ID       = tUsersForCheckRule2.tiDomain_ID      and
                                   tSODViolation2.Company_ID      = tUsersForCheckRule2.tiCompany_ID     and
                                   tSODViolation2.Role1_ID        = tUsersForCheckRule2.tiRole_ID        and
                                   tSODViolation2.SODCategory1_ID = Resources1.SODCategory_ID and
                                   tSODViolation2.Role2_ID        = Role.Role_ID        and
                                   tSODViolation2.SODCategory2_ID = Resources2.SODCategory_ID no-error.
                        if available tSODViolation2
                        then assign vlSwitch = no.
                        else do:
                            <M-19 run AddDetailLine
                               (input  'SODViolation2' (icTable), 
                                input  '' (icParentRowid), 
                                output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
                            if viFcReturnSuper <> 0
                            then oiReturnStatus = viFcReturnSuper.
                            if viFcReturnSuper < 0
                            then return.
                            
                            /* BLF-4424
                             * Conflicts should always be reported as 'A conflicts with B', never as 'B conflicts with A'.
                             */
                            if vcSODCategoryCode1 > vcSODCategoryCode2
                            then assign tSODViolation2.Usr_ID          = tUsersForCheckRule2.tiUsrId
                                        tSODViolation2.Domain_ID       = tUsersForCheckRule2.tiDomain_ID
                                        tSODViolation2.Company_ID      = tUsersForCheckRule2.tiCompany_ID
                                        tSODViolation2.Role1_ID        = Role.Role_ID
                                        tSODViolation2.SODCategory1_ID = Resources2.SODCategory_ID
                                        tSODViolation2.Role2_ID        = tUsersForCheckRule2.tiRole_ID
                                        tSODViolation2.SODCategory2_ID = Resources1.SODCategory_ID
                                        vlSwitch = yes.
                            else assign tSODViolation2.Usr_ID          = tUsersForCheckRule2.tiUsrId
                                        tSODViolation2.Domain_ID       = tUsersForCheckRule2.tiDomain_ID
                                        tSODViolation2.Company_ID      = tUsersForCheckRule2.tiCompany_ID
                                        tSODViolation2.Role1_ID        = tUsersForCheckRule2.tiRole_ID
                                        tSODViolation2.SODCategory1_ID = Resources1.SODCategory_ID
                                        tSODViolation2.Role2_ID        = Role.Role_ID
                                        tSODViolation2.SODCategory2_ID = Resources2.SODCategory_ID
                                        vlSwitch = no.
                        end.    /* available tSODViolation2 */
                    end.    /* available tSODViolation2 */
    
                    if not can-find (first tSODViolation2R where
                                           tSODViolation2R.tc_ParentRowid = tSODViolation2.tc_Rowid and
                                           tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 2 else 1) and
                                           tSODViolation2R.Resource_ID = Resources1.Resource_ID)
                    then do:
                        <M-20 run AddDetailLine
                           (input  'SODViolation2R' (icTable), 
                            input  tSODViolation2.tc_Rowid (icParentRowid), 
                            output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
                        if viFcReturnSuper <> 0
                        then oiReturnStatus = viFcReturnSuper.
                        if viFcReturnSuper < 0
                        then return.
                        assign tSODViolation2R.SODViolation2_ID       = tSODViolation2.SODViolation2_ID
                               tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 2 else 1)
                               tSODViolation2R.Resource_ID            = Resources1.Resource_ID
                               vlAdded = yes.
                    end.    /* can-find (first tSODViolation2R) */
                            
                    if not can-find (first tSODViolation2R where
                                           tSODViolation2R.tc_ParentRowid = tSODViolation2.tc_Rowid and
                                           tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 1 else 2) and
                                           tSODViolation2R.Resource_ID = Resources2.Resource_ID)
                    then do:
                        <M-21 run AddDetailLine
                           (input  'SODViolation2R' (icTable), 
                            input  tSODViolation2.tc_Rowid (icParentRowid), 
                            output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
                        if viFcReturnSuper <> 0
                        then oiReturnStatus = viFcReturnSuper.
                        if viFcReturnSuper < 0
                        then return.
                        assign tSODViolation2R.SODViolation2_ID       = tSODViolation2.SODViolation2_ID
                               tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 1 else 2)
                               tSODViolation2R.Resource_ID            = Resources2.Resource_ID
                               vlAdded = yes.
                    end.    /* can-find (first tSODViolation2R) */
    
                    if vlAdded
                    then do:
                        if vhBSODLog7Inst = ?
                        then do:
                            <I-17 {bFcAddToTransaction
                                 &CLASS           = "BSODLog"}>
                        end.
                        <M-18 run AddLogEntry
                           (input  {&SODLOG-RULE2} (icRule), 
                            input  {&SODLOG-STATUS-VIOLATION} (icStatus), 
                            input  tUsersForCheckRule2.tcUserLogin (icUsrLogin), 
                            input  tUsersForCheckRule2.tcDomainCode (icDomainCode), 
                            input  tUsersForCheckRule2.tcCompanyCode (icCompanyCode), 
                            input  tUsersForCheckRule2.tcRoleName (icRole1Name), 
                            input  Role.RoleName (icRole2Name), 
                            input  vcSODCategoryCode1 (icCategory1Code), 
                            input  vcSODCategoryCode2 (icCategory2Code), 
                            input  Resources1.ResourceURI (icResource1URI), 
                            input  Resources2.ResourceURI (icResource2URI), 
                            input  SODExclusion.SODExclusionLevel (icExclusionLevel)) in BSODLog>
                    end.
                end.    /* vlPolicyException = no */
            end.    /* each UsrRoleCompany */
        end.    /* each RoleResource1 */
        
        if last-of (tUsersForCheckRule2.tiUsrId)
        and vhBSODLog7Inst <> ?
        then do:
            <I-25 {bFcCloseInstance
                 &CLASS           = "BSODLog"}>

            <M-22 run ValidateBC  (output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
        
            <M-23 run AdditionalUpdates  (output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
        
            <M-24 run DataSave  (output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
        
            vhBSODLog7Inst = ?.    /* stopped by the transaction component in DataSave */
            viBSODLog7ID   = 0.
        end.    /* last-of (tUsersForCheckRule2.tiUsrId) */
    end.    /* each tUsersForCheckRule2 */
end.
else for each Resources1 fields (Resource_ID ResourceURI SODCategory_ID) no-lock where
              Resources1.SODCategory_ID = iiSODCategoryID,
         each RoleResource1 fields (Resource_ID Role_ID) no-lock where
              RoleResource1.Resource_ID = Resources1.Resource_ID,
         each Role1 fields (Role_ID RoleName RoleSODException) no-lock where
              Role1.Role_ID = RoleResource1.Role_ID and
              Role1.RoleSODException = no,
         each UsrRoleCompany1 fields (Usr_ID Role_ID Company_ID Domain_ID) no-lock where
              UsrRoleCompany1.Role_ID = Role1.Role_ID,
         each UsrRoleCompany2 fields (Usr_ID Role_ID Company_ID Domain_ID) no-lock where
              UsrRoleCompany2.Usr_ID = UsrRoleCompany1.Usr_ID and
              UsrRoleCompany2.Company_ID = UsrRoleCompany1.Company_ID and
              UsrRoleCompany2.Role_ID <> UsrRoleCompany1.Role_ID, 
         each Role2 fields (Role_ID RoleName RoleSODException) no-lock where
              Role2.Role_ID = UsrRoleCompany2.Role_ID and
              Role2.RoleSODException = no,
         each RoleResource2 fields (Resource_ID ) no-lock where
              RoleResource2.Role_ID = Role2.Role_ID,
         each Resources2 fields (Resource_ID ResourceURI SODCategory_ID) no-lock where
              Resources2.Resource_ID = RoleResource2.Resource_ID,
         each SODExclusion fields (SODCategory1_ID SODCategory2_ID SODExclusionLevel) no-lock where
              SODExclusion.SODCategory1_ID = Resources1.SODCategory_ID and
              SODExclusion.SODCategory2_ID = Resources2.SODCategory_ID
         break by UsrRoleCompany1.Usr_ID on error undo, throw:
         
    /* ================================================================= */
    /* Validate a single SOD category.                                   */
    /* ================================================================= */
    if first-of (UsrRoleCompany1.Usr_ID)
    then do:
        <M-62 run DataLoad
           (input  '' (icRowids), 
            input  '' (icPkeys), 
            input  '' (icObjectIds), 
            input  'for each SODViolation2 where SODViolation2.Usr_ID = ' + string(UsrRoleCompany1.Usr_ID) (icFreeform), 
            input  no (ilKeepPrevious), 
            output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
        if viFcReturnSuper = -4
        then viFcReturnSuper = 0.
        if viFcReturnSuper <> 0
        then oiReturnStatus = viFcReturnSuper.
        if viFcReturnSuper < 0
        then return.
    end.    /* first-of (UsrRoleCompany1.Usr_ID) */

    /* Skip resources for which an exception exists */
    vlAdded = no.
    vlPolicyException = no.
    for each SODException fields (SODException_ID Usr_ID) no-lock where
             SODException.Usr_ID = UsrRoleCompany1.Usr_ID:
        if can-find (first SODExceptionLn where
             SODExceptionLn.SODException_ID = SODException.SODException_ID and
             SODExceptionLn.SODCategory1_ID = Resources1.SODcategory_ID and
             SODExceptionLn.SODCategory2_ID = Resources2.SODcategory_ID and
            (SODExceptionLn.Company_ID = UsrRoleCompany1.Company_ID or SODExceptionLn.Company_ID = 0) and
            (SODExceptionLn.Domain_ID = UsrRoleCompany1.Domain_ID or SODExceptionLn.Domain_ID = 0))
        or can-find (first SODExceptionLn where
             SODExceptionLn.SODException_ID = SODException.SODException_ID and
             SODExceptionLn.SODCategory1_ID = Resources2.SODcategory_ID and
             SODExceptionLn.SODCategory2_ID = Resources1.SODcategory_ID and
            (SODExceptionLn.Company_ID = UsrRoleCompany1.Company_ID or SODExceptionLn.Company_ID = 0) and
            (SODExceptionLn.Domain_ID = UsrRoleCompany1.Domain_ID or SODExceptionLn.Domain_ID = 0))
        then do:
            vlPolicyException = yes.
            leave.
        end.
    end.    /* each SODException */
    if vlPolicyException = no
    then do:
        vcSODCategoryCode1 = "".
        for first SODCategory fields (SODCategory_ID SODCategoryCode) no-lock where
                  SODCategory.SODCategory_ID = Resources1.SODcategory_ID:
            vcSODCategoryCode1 = SODCategory.SODCategoryCode.
        end.

        vcSODCategoryCode2 = "".
        for first SODCategory fields (SODCategory_ID SODCategoryCode) no-lock where
                  SODCategory.SODCategory_ID = Resources2.SODcategory_ID:
            vcSODCategoryCode2 = SODCategory.SODCategoryCode.
        end.
            
        /* conflict found. Check if it is already known */
        find first tSODViolation2 where
                   tSODViolation2.Usr_ID          = UsrRoleCompany1.Usr_ID              and
                   tSODViolation2.Domain_ID       = UsrRoleCompany1.Domain_ID      and
                   tSODViolation2.Company_ID      = UsrRoleCompany1.Company_ID     and
                   tSODViolation2.Role2_ID        = Role1.Role_ID        and
                   tSODViolation2.SODCategory2_ID = Resources1.SODCategory_ID and
                   tSODViolation2.Role1_ID        = Role2.Role_ID        and
                   tSODViolation2.SODCategory1_ID = Resources2.SODCategory_ID no-error.
        if available tSODViolation2
        then assign vlSwitch = yes.
        else do:
            find first tSODViolation2 where
                       tSODViolation2.Usr_ID          = UsrRoleCompany1.Usr_ID              and
                       tSODViolation2.Domain_ID       = UsrRoleCompany1.Domain_ID      and
                       tSODViolation2.Company_ID      = UsrRoleCompany1.Company_ID     and
                       tSODViolation2.Role1_ID        = Role1.Role_ID        and
                       tSODViolation2.SODCategory1_ID = Resources1.SODCategory_ID and
                       tSODViolation2.Role2_ID        = Role2.Role_ID        and
                       tSODViolation2.SODCategory2_ID = Resources2.SODCategory_ID no-error.
            if available tSODViolation2
            then assign vlSwitch = no.
            else do:
                <M-28 run AddDetailLine
                   (input  'SODViolation2' (icTable), 
                    input  '' (icParentRowid), 
                    output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
                if viFcReturnSuper <> 0
                then oiReturnStatus = viFcReturnSuper.
                if viFcReturnSuper < 0
                then return.
                
                /* BLF-4424
                 * Conflicts should always be reported as 'A conflicts with B', never as 'B conflicts with A'.
                 */
                if vcSODCategoryCode1 > vcSODCategoryCode2
                then assign tSODViolation2.Usr_ID          = UsrRoleCompany1.Usr_ID
                            tSODViolation2.Domain_ID       = UsrRoleCompany1.Domain_ID
                            tSODViolation2.Company_ID      = UsrRoleCompany1.Company_ID
                            tSODViolation2.Role1_ID        = Role2.Role_ID
                            tSODViolation2.SODCategory1_ID = Resources2.SODCategory_ID
                            tSODViolation2.Role2_ID        = Role1.Role_ID
                            tSODViolation2.SODCategory2_ID = Resources1.SODCategory_ID
                            vlSwitch = yes.
                else assign tSODViolation2.Usr_ID          = UsrRoleCompany1.Usr_ID
                            tSODViolation2.Domain_ID       = UsrRoleCompany1.Domain_ID
                            tSODViolation2.Company_ID      = UsrRoleCompany1.Company_ID
                            tSODViolation2.Role1_ID        = Role1.Role_ID
                            tSODViolation2.SODCategory1_ID = Resources1.SODCategory_ID
                            tSODViolation2.Role2_ID        = Role2.Role_ID
                            tSODViolation2.SODCategory2_ID = Resources2.SODCategory_ID
                            vlSwitch = no.
            end.    /* not available tSODViolation2 */
        end.    /* not available tSODViolation2 */

        if not can-find (first tSODViolation2R where
                               tSODViolation2R.tc_ParentRowid = tSODViolation2.tc_Rowid and
                               tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 2 else 1) and
                               tSODViolation2R.Resource_ID = Resources1.Resource_ID)
        then do:
            <M-95 run AddDetailLine
               (input  'SODViolation2R' (icTable), 
                input  tSODViolation2.tc_Rowid (icParentRowid), 
                output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
            assign tSODViolation2R.SODViolation2_ID       = tSODViolation2.SODViolation2_ID
                   tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 2 else 1)
                   tSODViolation2R.Resource_ID            = Resources1.Resource_ID
                   vlAdded = yes.
        end.    /* not can-find (first tSODViolation2R) */
                
        if not can-find (first tSODViolation2R where
                               tSODViolation2R.tc_ParentRowid = tSODViolation2.tc_Rowid and
                               tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 1 else 2) and
                               tSODViolation2R.Resource_ID = Resources2.Resource_ID)
        then do:
            <M-79 run AddDetailLine
               (input  'SODViolation2R' (icTable), 
                input  tSODViolation2.tc_Rowid (icParentRowid), 
                output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
            assign tSODViolation2R.SODViolation2_ID       = tSODViolation2.SODViolation2_ID
                   tSODViolation2R.SODViolation2RCategory = (if vlSwitch then 1 else 2)
                   tSODViolation2R.Resource_ID            = Resources2.Resource_ID
                   vlAdded = yes.
        end.    /* not can-find (first tSODViolation2R) */
        
        if vlAdded
        then do:
            if vhBSODLog7Inst = ?
            then do:
                <I-87 {bFcAddToTransaction
                     &CLASS           = "BSODLog"}>
            end.
            
            vcSODDomainCode = "".
            for first Domains fields (Domain_ID DomainCode) no-lock where
                      Domains.Domain_ID = UsrRoleCompany1.Domain_ID:
                vcSODDomainCode = Domains.DomainCode.
            end.
            
            vcSODCompanyCode = "".
            for first Company fields (Company_ID CompanyCode) no-lock where
                      Company.Company_ID = UsrRoleCompany1.Company_ID:
                vcSODCompanyCode = Company.CompanyCode.
            end.
            
            vcSODUserLogin = "".
            for first Usr fields (Usr_ID UsrLogin) no-lock where
                      Usr.Usr_ID = UsrRoleCompany1.Usr_ID:
                vcSODUserLogin = Usr.UsrLogin.
            end.
    
            <M-33 run AddLogEntry
               (input  {&SODLOG-RULE2} (icRule), 
                input  {&SODLOG-STATUS-VIOLATION} (icStatus), 
                input  vcSODUserLogin (icUsrLogin), 
                input  vcSODDomainCode (icDomainCode), 
                input  vcSODCompanyCode (icCompanyCode), 
                input  Role1.RoleName (icRole1Name), 
                input  Role2.RoleName (icRole2Name), 
                input  vcSODCategoryCode1 (icCategory1Code), 
                input  vcSODCategoryCode2 (icCategory2Code), 
                input  Resources1.ResourceURI (icResource1URI), 
                input  Resources2.ResourceURI (icResource2URI), 
                input  SODExclusion.SODExclusionLevel (icExclusionLevel)) in BSODLog>
        end.    /* vlAdded */
        
        if last-of (UsrRoleCompany1.Usr_ID)
        and vhBSODLog7Inst <> ?
        then do:
            <I-10 {bFcCloseInstance
                 &CLASS           = "BSODLog"}>

            <M-69 run ValidateBC  (output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
        
            <M-38 run AdditionalUpdates  (output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
        
            <M-66 run DataSave  (output viFcReturnSuper (oiReturnStatus)) in BSODViolationRule2>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
        
            vhBSODLog7Inst = ?.    /* stopped by the transaction component in DataSave */
            viBSODLog7ID   = 0.
        end.    /* last-of (UsrRoleCompany1.Usr_ID) */
    end.    /* vlPolicyException = no */
end.    /* each Resources1 */

finally:
    empty temp-table tUsersForCheckRule2.
end finally.