CVS Pip New Vba
CVS Pip New Vba
'Sampreedh Edited on 22Nov2022 to add Appointment dimension related changes & new
prod hier with pay vendor changes
'Sampreedh Edited on 17Jun2022 to incorporate Geography RDI removal based on small
supplier flag
' 12/16/13 : adds distinct between regular/promo sales and unit measures and total
sales - primarily impacts cell security,
' requiring additional logic to subdivide the sales measures and layer in
additional geography crap. What previously could be handled by applying
' consistent rules to members of "Sales and Units" must now be handled by applying
separate rules for "CELLSECURITY:RegPromoSalesMeasures" and
' "CELLSECURITY:BaseSalesMeasures".
'
' 4/13/2014 - added to accommodate AS cell security but with product custom aggs.
Should
' not be neccessary. Note that model changes were also required - see model
description entry
' dated 4/13/14 for more info
' 4/21/2014 - added TimeMemberDesc to get around remaining issues with WTD-YA
periodicities.
' 9/29/2015 - added logic to hide the "All CVS Geographies - Internal" hierarchy
from
' third party users (anyone going thru the security tooling for
vendor/category)
' 11/14/17 - CVS_UpdateGeographyRestrictions
'
Const colLDAPGroup = 0
Const colPayVendor = 1
Const colL1ACategories = 2
Const colL1Categories = 3
Const colL2Categories = 4
Const colL2aCategories = 5 ' added 6/16/14, shifted other columns over
Const colL3Categories = 6
Const colInventoryMeasures = 7
Const colScanMarginMeasures = 8
'Sam Start
Const colPremiumAccessLevel = 9
Const colSmallSupplier = 10
'Sam End
Const colErrorOutput = 11
Const colCategoryOutput = 12
Const colSecurityResults = 13
Const cApplyIteratively = False ' set to true to apply all security changes in
batch
If fn = "" Then
s = ReadFile(CStr(fn))
ascs = ReadFile(cYMAS_Restrictions_Template)
MsgBox n & " store keys found in file " & CStr(fn)
End Sub
Private Function CSInnerL1_AND_L2ProductOrthRestrictions(arrCategoryNumbers As
Variant, invertL1 As Boolean) As String
' 6/6/2014 - adds the product orthogonal restrictions needed for level 1 cell
security. Would be unneeded if we didn't
' need to support combining level 1 and level 2 security - as member
security would meet requirements by itself. Argh.
'
' the invertL1 boolean arguments tells us whether we are setting up the L1
product orth restrictions or the inverse restrictions for L2 categories
' / anchor node selections from the product orths
CSInnerL1_AND_L2ProductOrthRestrictions = s
End Function
CSInnerInnerL1_AND_L2ProductOrthRestrictions = s
End Function
HasDuplicateEntries = ""
r = 1
While Range("A1").Offset(r, 0) <> ""
r = r + 1
Wend
r = r - 1
While r > 0
Dim n As String
n = UCase(Range("A1").Offset(r, 0).Value)
r = r - 1
Wend
HasDuplicateEntries = s
End Function
r = 1
While Range("A1").Offset(r, 0) <> ""
r = r + 1
Wend
r = r - 1
While r >= 0
Dim n As String
n = UCase(Range("A1").Offset(r, 0).Value)
End If
r = r - 1
Wend
MsgBox "Removed " & c & " duplicates - see debug output for detail."
End Function
Public Sub ConsolidateCVSSecurityEntries()
' updated 10/31/14 for new format input, which has the following characteristics:
'
' LDAP group is in column C, starting at cell C2
' Pay Vendor number in column D, starting at cell D2
' Category number(s) are in column F, starting at cell F2, and there may be more
' one value, bar delimited
' Security level is in cell H, starting at cell H2
'
' 1/15/16 - JW - added support for suppressing inventory for LDAP groups
'
' 7/24/18 - JW - modified to support new input sheet, which uses different columns
and also requires
' testing for hidden rows
' 8/14/18 - modified for another new column format
'Sam Start
Dim dictPremiumAccess As New Dictionary
Dim dictsmallSupplier As New Dictionary
'Sam End
Dim dictAllCN As New Dictionary ' keep track of all category numbers for a
given LDAP group - make sure nothing is assigned to multiple
' levels of security
Dim r As Integer
r = 0
If dictIncludeInventory.Exists(LastUserGroup) Then
dictIncludeInventory(LastUserGroup) = "No"
Else
dictIncludeInventory.Add LastUserGroup, "No"
End If
Else
If dictIncludeInventory.Exists(LastUserGroup) Then
dictIncludeInventory(LastUserGroup) = "Yes"
Else
dictIncludeInventory.Add LastUserGroup, "Yes"
End If
End If
'Sam Start
If PremiumAccess <> "YES" And PremiumAccess <> "Y" And PremiumAccess
<> "" And PremiumAccess <> "NO" And PremiumAccess <> "N" Then
MsgBox "Invalid value in the Premium Access Level column for " &
LastUserGroup & ". Acceptable values are Yes, Y, No, N and empty cells. Please
correct.", vbCritical, "Premium Access Level flag error"
Exit Sub
End If
If dictPremiumAccess.Exists(LastUserGroup) Then
dictPremiumAccess(LastUserGroup) = "Yes"
Else
dictPremiumAccess.Add LastUserGroup, "Yes"
End If
Else
If dictPremiumAccess.Exists(LastUserGroup) Then
dictPremiumAccess(LastUserGroup) = "No"
Else
dictPremiumAccess.Add LastUserGroup, "No"
End If
End If
'
' security level
'
Level = Range(firstSecurityLevelCell).Offset(r, 0).Value
r = r + 1
'
' it is possible that there are hidden rows within a block as well -
so test to see if the new row is
' hidden, and if it is, keep bumping rows
While Range(firstUserGroupCell).Offset(r, 0).EntireRow.Hidden = True
r = r + 1
Wend
Dim k As Variant
Dim s As String
s = ""
For Each k In dictTempVN.Keys
s = s & CStr(k) & "|"
Next k
If dictConsolidatedVN.Exists(LastUserGroup) Then
MsgBox "It appears that this input sheet is not sorted by LDAP
group - please correct and try again.", vbCritical, "Input sheet error"
Exit Sub
Else
dictConsolidatedVN.Add LastUserGroup, Left(s, Len(s) - 1)
End If
s = ""
For Each k In dictTempCN_1A.Keys
If dictAllCN.Exists(k) Then
MsgBox "Category " & k & " is assigned to multiple security
levels for LDAP group " & LastUserGroup
Exit Sub
Else
dictAllCN.Add k, k
End If
If dictAllCN.Exists(k) Then
MsgBox "Category " & k & " is assigned to multiple security
levels for LDAP group " & LastUserGroup
Exit Sub
Else
dictAllCN.Add k, k
End If
s = ""
For Each k In dicttempCN_2.Keys
If dictAllCN.Exists(k) Then
MsgBox "Category " & k & " is assigned to multiple security
levels for LDAP group " & LastUserGroup
Exit Sub
Else
dictAllCN.Add k, k
End If
s = s & CStr(k) & "|"
Next k
If s <> "" Then
dictConsolidatedCN_2.Add LastUserGroup, Left(s, Len(s) - 1)
End If
s = ""
For Each k In dicttempCN_2a.Keys
If dictAllCN.Exists(k) Then
MsgBox "Category " & k & " is assigned to multiple security
levels for LDAP group " & LastUserGroup
Exit Sub
Else
dictAllCN.Add k, k
End If
s = s & CStr(k) & "|"
Next k
If s <> "" Then
dictConsolidatedCN_2a.Add LastUserGroup, Left(s, Len(s) - 1)
End If
'
' 2/5/19 - JW - added this checkpoint because the CVS team kept submitting
flawed input sheets
'
If dictConsolidatedVN.count = 0 Then
MsgBox "No valid security input found before the first blank LDAP group
name in cell " & Range(firstUserGroupCell).Offset(r, 0).Address & _
". Please validate your input sheet - this sheet will not result in
new security.", vbCritical, "Input sheet error"
Else
'
' create a new sheet for our output
If (Workbooks.count = 0) Then Workbooks.Add
ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.count)
Dim g As Variant
Range("a1").Offset(0, 0).Value = "LDAP Group"
Range("a1").Offset(0, 1).Value = "Pay Vendors"
Range("a1").Offset(0, 2).Value = "L1A Categories"
Range("a1").Offset(0, 3).Value = "L1 Categories"
Range("a1").Offset(0, 4).Value = "L2 Categories"
Range("A1").Offset(0, 5).Value = "L2a Categories"
Range("a1").Offset(0, 6).Value = "L3 Categories"
Range("a1").Offset(0, 7).Value = "Include Inventory"
Range("a1").Offset(0, 8).Value = "Include Cost Measures"
'Sam Start
Range("a1").Offset(0, 9).Value = "Premium Access"
Range("a1").Offset(0, 10).Value = "Small Supplier"
'Sam End
r = 1
For Each g In dictConsolidatedVN.Keys
Range("A1").Offset(r, 0).Value = "iricommercial.com\" & CStr(g)
Range("a1").Offset(r, 1).Value = dictConsolidatedVN(g)
Range("A1").Offset(r, 2).Value = dictConsolidatedCN_1A(g)
Range("A1").Offset(r, 3).Value = dictConsolidatedCN_1(g)
Range("A1").Offset(r, 4).Value = dictConsolidatedCN_2(g)
Range("A1").Offset(r, 5).Value = dictConsolidatedCN_2a(g)
Range("A1").Offset(r, 6).Value = "" ' level 3 ' never implement, not
fully defined
Range("A1").Offset(r, 7).Value = dictIncludeInventory(g) ' added
1/15/16, used to be hardcoded to YES
Range("A1").Offset(r, 8).Value = "No" ' cost measures
'Sam Start
Range("A1").Offset(r, 9).Value = dictPremiumAccess(g)
Range("A1").Offset(r, 10).Value = dictsmallSupplier(g)
'Sam End
If dictConsolidatedCN_1A(g) <> "" And (dictConsolidatedCN_1(g) <> "" Or
dictConsolidatedCN_2(g) <> "" Or dictConsolidatedCN_2a(g) <> "") Then
MsgBox "Group " & g & " is attempting to combine level 1A security
with level 1, level 2 or level 2a security. That is not supported.", vbCritical
Range("A1").Offset(r, 9) = "INVALID CONFIGURATION: combines level
1a security with level 1 or level 2."
End If
End Sub
'
' make sure there are no duplicate entries
'
Dim hde As String
hde = HasDuplicateEntries
If hde <> "" Then
MsgBox "You must remove duplicate entries before applying security from
this sheet. Duplicates are found on rows " & hde, vbCritical, "Duplicate entries"
Exit Sub
End If
' prevent the potentially long running operation from stealing back windows
focus on each rows
JASCS_MenuAndWizardRoutines.SuppressModalDialogs = True
'
' select a target model
'
'
' optionally refresh ldap security
'
End If
'
' 12/22/12 - added rebuild option
'
' optionally rebuild hierarchies
'
If Not verifyGroupsOnly Then
ans = MsgBox("Rebuild model hierarchies?", vbYesNo, "Rebuild")
If ans = vbYes Then
If Not (RebuildModelHierarchies(modelName)) Then
Exit Sub
End If
End If
End If
oRef.Save cachedVendorCategoryInfoFilename
Else
Set oRef = New DOMDocument
oRef.Load cachedVendorCategoryInfoFilename
End If
End If
r = 0
While Range("A2").Offset(r, colLDAPGroup).Value <> ""
Range("A2").Offset(r, colCategoryOutput).Value = ""
Range("A2").Offset(r, colSecurityResults).Value = ""
r = r + 1
Wend
r = 0
If verifyGroupsOnly Then
Range("A2").Offset(r, colCategoryOutput).Value = "Group found"
Else
Range("A2").Offset(r, colCategoryOutput).Value = "Processing..."
'
' 3/31/2014 - added logic to support deleting groups as well as
defining them
'
If UCase(Range("A2").Offset(r, colPayVendor).Value) = "DELETE" Then
Dim Accessor As String
Range("a2").Offset(r, colSecurityResults - 1).Value =
"Processing..."
Accessor = Range("a2").Offset(r, colLDAPGroup).Value
MergeAndSetMemberAndCellSecurity modelName, "Not Used", "Not
Used", Accessor, "have no member or cell security", True
Range("a2").Offset(r, colSecurityResults - 1).Value = Now
Range("A2").Offset(r, colSecurityResults).Value = "Member and
cell security cleared"
Else
' don't need to update status cells for this branch,
SetCVSSecurityForSpecificRow takes care of it
SetCVSSecurityForSpecifiedRow modelName, r, oRef, True
End If
End If
End If
r = r + 1
Wend
'
' if we are in bulk mode, only the deletes will have already taken effect in
the loop above, the rest of the calls to SetCVSSecurityForSpecifiedRow()
' will have built up text files - apply those now
'
If Not cApplyIteratively And Not verifyGroupsOnly Then
MergeAndSetMemberAndCellSecurityAndGenerateDimVisibility modelName, "Set
security in batch"
End If
JASCS_MenuAndWizardRoutines.SuppressModalDialogs = False
End Sub
'
Dim includeScanMarginMeasures As Boolean ' added 11/13/13 to override the long
term desired measure availabilities
'Sam Start Premium acces variable made as global
'Dim PremiumAccess As Boolean
'Sam End
'Dim r As Integer
Dim L1_Categories As String, L1a_Categories As String, L2_Categories As String,
L2a_Categories As String, L3_Categories As String
Dim payVendorNames As String, ldapGroup As String, includeInventory As Boolean
Dim oDictUsedCategories As New Dictionary
Dim oDictUsedCategoryNumbers As New Dictionary
'
' added 2/3/14
'
Dim oDictCategoryByNumber As New Dictionary
Dim oDictVendorByNumber As New Dictionary
includeScanMarginMeasures = False
If UCase(Left(Range("A2").Offset(r, colScanMarginMeasures).Value, 1)) = "Y"
Then
includeScanMarginMeasures = True
End If
'Sam Start
PremiumAccess = False
If UCase(Left(Range("A2").Offset(r, colPremiumAccessLevel).Value, 1)) = "Y"
Then
PremiumAccess = True
End If
smallSupplier = False
If UCase(Left(Range("A2").Offset(r, colSmallSupplier).Value, 1)) = "Y" Or
UCase(Left(Range("A2").Offset(r, colSmallSupplier).Value, 1)) = "Yes" Then
smallSupplier = True
End If
'Sam End
'
' don't want to scrub these just yet
'
'payVendorNames = XMLScrub(payVendorNames)
ldapGroup = XMLScrub(ldapGroup)
'
' don't allow L1a or L3 to combine with other levels
'
If L1a_Categories <> "" And (L1_Categories <> "" Or L2_Categories <> "" Or
L3_Categories <> "") Then
MsgBox "Level 1A security cannot be combinated with other levels for a
given user group.", vbCritical, "Entry error"
Range("a2").Offset(r, colSecurityResults - 1).Value = "SKIPPING: Level 1A
security cannot be combinated with other levels for a given user group."
Exit Sub
End If
If L3_Categories <> "" And (L1_Categories <> "" Or L2_Categories <> "" Or
L1a_Categories <> "") Then
MsgBox "Level 3 security cannot be combinated with other levels for a given
user group.", vbCritical, "Entry error"
Range("a2").Offset(r, colSecurityResults - 1).Value = "SKIPPING: Level 3
security cannot be combinated with other levels for a given user group."
Exit Sub
End If
If numberInputsOnly Then
' Debug.Print "skipping vendor name / category name validation"
'
' load up the category names and vendor names by number for output during
the mapping
'
Else
'
' this block expects the format of ABC XX for vendors and categories
'
If oDictCategoryNumberSBMappings.Exists(categoryNumber)
Then
oDictCategoryNumberSBMappings(categoryNumber) = _
oDictCategoryNumberSBMappings(categoryNumber) & ","
& SBorNB
Else
oDictCategoryNumberSBMappings.Add categoryNumber,
SBorNB
End If
'
' make sure all of the categories were found
'
Dim category As Variant
Dim sErrors As String
For Each category In arrL1a
oDictUsedCategories.Add category, category
oDictUsedCategoryNumbers.Add StripToNumber(CStr(category)),
StripToNumber(CStr(category))
If numberInputsOnly Then
Else
If Not oDictCategorySBMappings.Exists(category) Then
sErrors = sErrors & "Category '" & category & "' not in model"
End If
End If
Next category
For Each category In arrL1
oDictUsedCategories.Add category, category
oDictUsedCategoryNumbers.Add StripToNumber(CStr(category)),
StripToNumber(CStr(category))
If numberInputsOnly Then
Else
If numberInputsOnly Then
Else
If Not oDictCategorySBMappings.Exists(category) Then
sErrors = sErrors & "Category '" & category & "' not in model"
End If
End If
Next category
If numberInputsOnly Then
Else
If Not oDictCategorySBMappings.Exists(category) Then
sErrors = sErrors & "Category '" & category & "' not in model"
End If
End If
Next category
Next category
L1a_Categories = XMLScrub(L1a_Categories)
L1_Categories = XMLScrub(L1_Categories)
L2_Categories = XMLScrub(L2_Categories)
L2a_Categories = XMLScrub(L2a_Categories)
L3_Categories = XMLScrub(L3_Categories)
'
' write out what we found, store brand wise, on each category
'
'Range("A2").Offset(r, colCategoryOutput).Value = summary
'Exit Sub
'
' now scrub and reassign array - from here down we want xml safe text
'
' as part of the switch to finding categories and vendors by number only,
' reassign the arrays - ultimately this will probably happen further up
'
'
payVendorNames = XMLScrub(payVendorNames)
arrVendors = ConvertToNumberArray(payVendorNames)
arrL1a = ConvertToNumberArray(L1a_Categories)
arrL1 = ConvertToNumberArray(L1_Categories)
arrL2 = ConvertToNumberArray(L2_Categories)
arrL2a = ConvertToNumberArray(L2a_Categories)
arrL3 = ConvertToNumberArray(L3_Categories)
Dim maxSecurityLevel As String ' keep track of max security level found
' for purposes of assigning restricted measure
' attributes
maxSecurityLevel = "1a"
' note that we don't need to replace the MODEL token - the default sendACS()
function will take care of that
'
'
' l1a is the same as l1 for member security
'
If L1a_Categories <> "" Then
subS = subS & MSBlockProductL1(arrL1a, arrVendors)
maxSecurityLevel = "1a"
End If
'
' l1 access doesn't care about store brand - only categories and vendors
'
'For Each category In arrL1
If L1_Categories <> "" Then
subS = subS & MSBlockProductL1(arrL1, arrVendors)
maxSecurityLevel = "1"
End If
subS = ""
For Each category In arrL2
subS = subS & MSProductL2orL3_Step1_Category(CStr(category))
maxSecurityLevel = "2"
count = count + 1
Next category
End If
'SkipForNow:
'
' 6/16/14 - add logic for level 2a
'
subS = ""
For Each category In arrL2a
subS = subS & MSProductL2a_Category(CStr(category))
maxSecurityLevel = "2a" ' for purposes of cell security attribute measure
restrictions - note that
' any value of 1, 2, 2a (which can be mixed for a
single ldap group will
' ultimately result in the same measure attribute
restrictions.
' 2a will never trump 3, as 3 cannot be mixed and
matched
Next category
sMS = sMS & subS
'
' add the surrogates, and close out the product settings and add the other
dimension defaults
'
'
' add the product othogonal restrictions
'
sMS = sMS & ProductOrthogonalRestrictions(arrL1a, arrL1, arrL2, arrL2a, arrL3,
arrVendors)
'
' we also need to replace the VENDOR_NAME_WO_NUMBER token in the standalone
vendor dimension
' the replacement value should also be the vendorName argument, less the
trailing number
'
'
'
'
' add the remaining restrictions, including vendor
'
'
' 11/7/13 - added rule to hide the dummy DC N/A members in the All CVS by DC
hierarchy
' WARNING: ALSO HIDES THE ONTARIO BRANCH OF THE TREE WHICH DOES NOT HAVE ANY
STORES at this time. Yuch.
'"<RDIEntry>except Filter(Group(DC_DC), ""ATTRIBUTE ""DC_DC"".""Name"" =
'ONTARIO'"")</RDIEntry>" & vbCrLf & _
'
' 7/2/14
'
' 9/29/15 - JW - added exclusion of "All CVS Geographies - Internal"
' 7/21/16 - Sri - added exclusion of "Added "All CVS Target Stores" -
"<RDIEntry>except DescendantsOf(""All CVS Target Stores"")</RDIEntry>" & vbCrLf & _
' 08/26/19 - SC - added Rdi entry to exclude "All CVS Stores by Primary DC"
geography hierarchy
'
If ModelHasDistributionCenterAsDimension Then
If PremiumAccess Then
sMS = sMS & "<Dimension name=""Geography"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""All CVS Geographies -
Internal""</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""All CVS Stores""</RDIEntry>" & vbCrLf &
_
"<RDIEntry>except DescendantsOf(""All CVS Target
Stores"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""Total Alternative Store Format -
Internal""</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Time"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf
Else
sMS = sMS & "<Dimension name=""Geography"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""All CVS Geographies -
Internal""</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""All CVS Stores""</RDIEntry>" & vbCrLf &
_
"<RDIEntry>except ""All CVS Stores by Primary
DC""</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""All CVS Geographies with Alternative
Store Format""</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""Total Alternative Store Format -
Internal""</RDIEntry>" & vbCrLf & _
"<RDIEntry>except DescendantsOf(""All CVS Geographies with
Alternative Store Format"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>except DescendantsOf(""All CVS Target
Stores"")</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Time"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""Day Level Time Functions""</RDIEntry>" &
vbCrLf & _
"</Dimension>" & vbCrLf
End If
Else
sMS = sMS & "<Dimension name=""Geography"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""All CVS Geographies -
Internal""</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""All CVS Stores""</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""All CVS Stores by Primary DC""</RDIEntry>"
& vbCrLf & _
"<RDIEntry>except ""All CVS Geographies with Alternative Store
Format""</RDIEntry>" & vbCrLf & _
"<RDIEntry>except ""Total Alternative Store Format -
Internal""</RDIEntry>" & vbCrLf & _
"<RDIEntry>except DescendantsOf(""All CVS Geographies with
Alternative Store Format"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>except DescendantsOf(""All CVS Target
Stores"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>except Filter(Group(DC_DC), ""ATTRIBUTE
""DC_DC"".""Name"" = 'N/A'"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>except Filter(Group(DC_STORE), ""ATTRIBUTE
""DC_STORE"".""Name"" = 'N/A - N/A, N/A, N/A, N/A'"")</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Time"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf
End If
'Sam Start
Dim GeogRDIExclude As String
If smallSupplier Then
GeogRDIExclude = "<RDIEntry>except ""All CVS Geographies with Alternative
Store Format""</RDIEntry>"
sMS = Replace(sMS, GeogRDIExclude & vbCrLf, "")
End If
'Sam End
'
' deal with measures.
'
If includeScanMarginMeasures Then
If Not PremiumAccess Then
sMS = sMS & "<Dimension name=""Measures"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except ""QA Measures""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except
DescendantsOf(""MemberSecurity:PremiumPackageMeasures"")</RDIEntry>" & vbCrLf
Else
sMS = sMS & "<Dimension name=""Measures"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except ""QA Measures""</RDIEntry>" & vbCrLf
End If
Else
If Not PremiumAccess Then
sMS = sMS & "<Dimension name=""Measures"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except ""Scan Margin""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except DescendantsOf(""Scan Margin"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>Except ""Scan Margin TPR""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except DescendantsOf(""Scan Margin
TPR"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except ""Margin Contribution""</RDIEntry>" & vbCrLf
& _
"<RDIEntry>Except DescendantsOf(""Margin
Contribution"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except ""QA Measures""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except DescendantsOf(""QA Measures"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>Except
DescendantsOf(""MemberSecurity:PremiumPackageMeasures"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except ""Gas Measures : FOLDER""</RDIEntry>" &
vbCrLf & _
"<RDIEntry>Except ""Weather Measures : FOLDER""</RDIEntry>" &
vbCrLf
Else
sMS = sMS & "<Dimension name=""Measures"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except ""Scan Margin""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except DescendantsOf(""Scan Margin"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>Except ""Scan Margin TPR""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except DescendantsOf(""Scan Margin
TPR"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except ""Margin Contribution""</RDIEntry>" & vbCrLf
& _
"<RDIEntry>Except DescendantsOf(""Margin
Contribution"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except ""QA Measures""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except DescendantsOf(""QA Measures"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>Except
DescendantsOf(""MemberSecurity:PremiumMeasures"")</RDIEntry>" & vbCrLf
End If
End If
'
' 7/3/18 - JW - added to hide premium measures from all groups that pass thru
this logic. (Internal and QA groups do not
' pass thru this logic) When premium LDAP groups appear, this logic
will need to detect them and act accordingly
' 7/24/18 - also need to hide gas and weather measures folders, as these are
root level and stubbornly refuse to be both
' root members and members of the premium measure collection
'1/17/19-JW-modified to restrict solely on the PremiumMeasures collection and
its descendants, previous
' versions of the code explicitly listed gas and weather, but this was
redundant. With this change
' future premium measures can be added to the model so long as they are
assigned to the PremiumMeasures
' collection and there will be no need to modify this code or rerun
security.
'03/12/19-Sudhakar-As Analytical Server does not allow you to add a folder to a
collection and also have it as a
'root level member, we enabled RDI filter that excludes Gas and Weather root
level folders.
'04/03/19-Sudhakar-Added 3 new RDI Entries to exclude CVS_PIP PhaseII related
measures namely Purchase Orders, Display and Planned Delivery for Suppliers.
'
' close off measure setting, add vendor settings
'
sMS = sMS & "</Dimension>" & vbCrLf & _
"<Dimension name=""Vendor"">" & vbCrLf & _
"<RDIEntry>""All Vendors""</RDIEntry>" & vbCrLf
'
' 11/7/13 - as evidenced by B&L, sometime the Vendor name won't be unique
across pay vendor: B&L and Bausch & Lomb
' for example
'
' 2/12/14 - JW - removed access to the the three product hierachies that
start with the Vendor level (levels that start with Vend*)
' 2/20/14 - this block should not have been commented out, restored.
Next aVendorNumber
'Sam Start
If PremiumAccess Then
'sudarshan added
sMS = sMS & "<Dimension name=""Appointment Approved Date"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf
Next aVendorNumber
Next aVendorNumber
Next aVendorNumber
Else
End If
'Sam End
If False Then
' use old logic
Else
'
' use new logic
'
' 5/5/2014 - changed the dimension and anchor node names for three dimensions
to
' "Inv Director", "Store Planner" and "DC Planner"
'
' added "Sr Inv Manager"
'
sMS = sMS & "<Dimension name=""Purchase Order"">" & vbCrLf & _
"<RDIEntry>""All Purchase Orders""</RDIEntry>" & vbCrLf & _
"<RDIEntry>~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf
sMS = sMS & "<Dimension name=""Organizational Role"">" & vbCrLf & _
"<RDIEntry>""All Merchandising""</RDIEntry>" & vbCrLf & _
"<RDIEntry>~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Inv Director"">" & vbCrLf & _
"<RDIEntry>""All Inv Directors""</RDIEntry>" & vbCrLf & _
"<RDIEntry>~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Sr Inv Manager"">" & vbCrLf & _
"<RDIEntry>""All Sr Inv Managers""</RDIEntry>" & vbCrLf & _
"<RDIEntry>~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Store Planner"">" & vbCrLf & _
"<RDIEntry>""All Store Planners""</RDIEntry>" & vbCrLf & _
"<RDIEntry>~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""DC Planner"">" & vbCrLf & _
"<RDIEntry>""All DC Planners""</RDIEntry>" & vbCrLf & _
"<RDIEntry>~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Like and Comparable Items"">" & vbCrLf & _
"<RDIEntry>""Actual Item""</RDIEntry>" & vbCrLf & _
"<RDIEntry>~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf
End If ' use new logic
'
' there is at least one ldap token in the wrapping text, so make sure that is
replaced
'
sMS = Replace(sMS, "@@LDAP_TOKEN@@", ldapGroup)
'
' ok, we have all the member security, go ahead and merge that to the target
model
'
'MsgBox "skipping member security"
'
' setting the last argument to false skips prompting the user about merging
security, and does a merge
'
'
' for some reason,MergeMemberAndCellSecurity() changes the ldapgroup value, put
it back
sCS = ""
'
's = s & "<SetCellSecurityDomains modelName=""@@MODEL@@"">" & vbCrLf
If L1_Categories <> "" Or L2_Categories <> "" Or L2a_Categories <> "" Then
'
' if they literally have both l1 and (l2 or l2a), call the more fiddly
variant
'
If L1_Categories <> "" And (L2_Categories <> "" Or L2a_Categories <> "")
Then
sCS = sCS & NEW_CSBlockL1_AND_L2orL2a(ldapGroup, arrVendors, arrL1,
includeInventory)
Else
'
' call the simpler _or_ variant we have had all along
'
sCS = sCS & CSBlockProductL1_OR_L2(ldapGroup, arrVendors,
includeInventory)
End If
End If
If L3_Categories <> "" Then
sCS = sCS & CSBlockProductL3(ldapGroup, arrVendors, includeInventory)
End If
'
' if this group gets "Premium" measures, inject that rule into the sCS string
If GroupGetsPremium(ldapGroup, 1) Then
sCS = sCS & CS_AddPremiumAccess()
End If
If PremiumAccess Then
End If
's = s & "</SetCellSecurityDomains>" & vbCrLf
'
' there is at least one ldap token in the wrapping text, so make sure that is
replaced
'
sCS = Replace(sCS, "@@LDAP_TOKEN@@", ldapGroup)
'
' setting the last argument to false skips prompting the user about merging
security, and does a merge
'
If cApplyIteratively Then
MergeAndSetMemberAndCellSecurity modelName, sCS, sMS, ldapGroup,
modelSummary
Else
AppendFile ldapGroup, "C:\temp\CVS_PIP_LDAPGROUPS.txt"
AppendFile sMS, "C:\temp\CVS_PIP_MemberSecurity.txt"
AppendFile sCS, "C:\temp\CVS_PIP_CellSecurity.txt"
End If
'MergeMemberAndCellSecurity False, sMS, ldapGroup, False
'summary = "Member security: " & Len(sMS) & vbCrLf & "Cell security: " &
Len(sCS) & vbCrLf
Dim k As Variant
Const q = """"
DEBUGExit:
Exit Sub
ErrorReturn:
MsgBox "DANGER DANGER! Unhandled error in SetCVSSecurityForSpecificRow()" &
vbCrLf & Err.Description, vbCritical, "Unhandled error"
End Sub
Dim i As Variant
End Function
Private Function StripToNumber(s As String) As String
s = Trim(s)
If IsNumeric(s) Then
StripToNumber = s
Else ' must have alpha text too..
Dim i As Integer
i = Len(s)
While IsNumeric(Mid(s, i, 1)) And i > 1
i = i - 1
Wend
' Debug.Print s, Right(s, Len(s) - i)
StripToNumber = Right(s, Len(s) - i)
End If
End Function
Private Function InnerProductOrthClause(categoryNumber As Variant, groupName As
String, IsCategoryDim As Boolean)
Dim c As String
c = CStr(categoryNumber)
If IsCategoryDim Then
'c = RemoveNumberSuffix(c)
InnerProductOrthClause = "<RDIEntry>Filter(Group(" & groupName & "),
""ATTRIBUTE """ & groupName & """.""CategoryNumber"" = '" & c & "'"")</RDIEntry>" &
vbCrLf
Else
'
' don't remove suffix, include children
'
InnerProductOrthClause = "<RDIEntry>Filter(Group(" & groupName & "),
""ATTRIBUTE """ & groupName & """.""CategoryNumber"" = '" & c & "'"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>DescendantsOf(Filter(Group(" & groupName & "), ""ATTRIBUTE """ &
groupName & """.""CategoryNumber"" = '" & c & "'""))</RDIEntry>" & vbCrLf
End If
End Function
Next aVendorNumber
ElseIf Level = 1 Then
'
' they should only see their own pay vendor codes below category
'
s = "<RDIEntry>Filter(Group(Brand_Category), ""ATTRIBUTE
""Brand_Category"".""CategoryNumber"" = '" & categoryNumber & "'"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>Filter(Group(LatestBrand_Category), ""ATTRIBUTE
""LatestBrand_Category"".""CategoryNumber"" = '" & categoryNumber &
"'"")</RDIEntry>" & vbCrLf
Next aVendorNumber
Else
MsgBox "Unsupport level number in InnerProductBrandOrthClause!"
End If
InnerProductBrandOrthClause = s
End Function
Private Function ProductOrthogonalRestrictions(arrL1a As Variant, arrL1 As Variant,
arrL2 As Variant, arrL2a As Variant, arrL3 As Variant, arrVendorNumbers As Variant)
'
' 11/18/13 - JW - modified to deal with new requirement that L1A security
groups should see only anchor nodes in Merchant Group, Category,
' SubCategory, Segment and Brand.
'
' 12/30/14 - JW - added level 2a support
'
' Note that the code branch relies on the input restriction that a group that
has L1A categories cannot have L1, L2 or L3 categories
'
Dim categoryNumber As Variant
Dim s As String
'
' 5/9/14 - added access to purchased categories to level 1a
'
s = ""
'For Each categoryNumber In arrL1a
' s = s & InnerProductOrthClause(categoryNumber, "All_Categories", True)
'Next categoryNumber
For Each categoryNumber In arrL1
s = s & InnerProductOrthClause(categoryNumber, "All_Categories", True)
Next categoryNumber
For Each categoryNumber In arrL2
s = s & InnerProductOrthClause(categoryNumber, "All_Categories", True)
Next categoryNumber
' 12/30/14 - added l2a for/next loop
For Each categoryNumber In arrL2a
s = s & InnerProductOrthClause(categoryNumber, "All_Categories", True)
Next categoryNumber
For Each categoryNumber In arrL3
s = s & InnerProductOrthClause(categoryNumber, "All_Categories", True)
Next categoryNumber
'
'at this point, s holds the RDI elements - factor these into various
product orth dimensions
' (just category for now, ultimately all of them)
ProductOrthogonalRestrictions = ProductOrthogonalRestrictions & "<Dimension
name=""Category"">" & vbCrLf & _
"<RDIEntry>""All Categories""</RDIEntry>" & vbCrLf & _
s & "<RDIEntry>~</RDIEntry>" & vbCrLf & _
AddSurrogates & "</Dimension>" & vbCrLf
s = ""
'
' SubCategory
'
'For Each categoryNumber In arrL1a
' s = s & InnerProductOrthClause(categoryNumber, "SubCat_Category",
False)
'Next categoryNumber
For Each categoryNumber In arrL1
s = s & InnerProductOrthClause(categoryNumber, "SubCat_Category",
False)
Next categoryNumber
For Each categoryNumber In arrL2
s = s & InnerProductOrthClause(categoryNumber, "SubCat_Category",
False)
Next categoryNumber
' 12/30/14 - added l2a for/next loop
For Each categoryNumber In arrL2a
s = s & InnerProductOrthClause(categoryNumber, "SubCat_Category",
False)
Next categoryNumber
For Each categoryNumber In arrL3
s = s & InnerProductOrthClause(categoryNumber, "SubCat_Category",
False)
Next categoryNumber
'GoTo SkipBrandLogic
'
' if this is a 1a client, they should not see anything but the all member
of brand
'
Dim count As Integer
count = 0
For Each categoryNumber In arrL1
s = s & InnerProductBrandOrthClause(1, categoryNumber,
arrVendorNumbers)
count = count + 1
Next categoryNumber
For Each categoryNumber In arrL2
s = s & InnerProductBrandOrthClause(2, categoryNumber,
arrVendorNumbers)
Next categoryNumber
' 12/30/14 - added l2a loop
For Each categoryNumber In arrL2a
s = s & InnerProductBrandOrthClause(2, categoryNumber,
arrVendorNumbers)
Next categoryNumber
For Each categoryNumber In arrL3
s = s & InnerProductBrandOrthClause(3, categoryNumber,
arrVendorNumbers)
Next categoryNumber
End Function
i = Len(s)
End Function
End Function
End Function
Dim s As String
'
' All Products by Merch Group - desc,2 on category takes you dowo thru SubCat
and Segment. then pick up additional restrictions at PayVendor and StoreBrand
levels
' note that you have to include category number and store brand info on the
last three rules, else when level 1 and level 2 are mixed, you will grant
' inadvertant access.
'
' 6/2/14 - make sure all segments in the category are visible as well as their
ancestors
'
s = RDIFilterClause("ProdMG_Segment", "CategoryNumber", "@@CATEGORY_TOKEN@@",
0, -1)
If PremiumAccess Then
s = s & RDIFilterClause("ProdMG_Category_BM", "CategoryNumber",
"@@CATEGORY_TOKEN@@", 0, -1)
End If
' RDIFilterClause will generate ancestor and descendant variants as well for
this one
'
' All Products by Vendor-Merch Group - try approach of pivoting everything on
store brand level
'
' 2/12/14 - CVS no longer want vendor hierarchies to be visible - I'm leaving
the code block in case they later change their minds
' note that the vendor hierarchies all have level names starting with Vend*
' 3/26/14 - partially restore access to the Vendor anchor hierarchies blocked
on 2/12
'
' All Products by Vendor - requires similar logic to "All Products by Vendor-
Merch Group"
'
' 2/12/14 - CVS no longer want vendor hierarchies to be visible - I'm leaving
the code block in case they later change their minds
' note that the vendor hierarchies all have level names starting with Vend*
' 1/22/19 - CVS now wants vendor hierarchies again to be visible, restored,
line of code below, which had been commented out back on 2/12/14
s = s & RDIFilterClause("Vend_StoreBrand", "CategoryNumber_StoreBrand",
"@@CATEGORY_TOKEN@@ NATIONAL BRAND", 0, 0)
s = s & RDIFilterClause("LatestVend_StoreBrand", "CategoryNumber_StoreBrand",
"@@CATEGORY_TOKEN@@ NATIONAL BRAND", 0, 0)
'
' All Products by Brand - requires similar logic to "All Products by Merch
Group"
'
' 6/2/14 - make sure all segments in the category are visible as well as their
ancestors
'
s = s & RDIFilterClause("ProdBrand_Segment", "CategoryNumber",
"@@CATEGORY_TOKEN@@", 0, -1)
MSProductL2orL3_Step1_Category = s
End Function
Dim s As String
'
' All Products by Merch Group - all that is needed is to the specific category
as visible, along with all ancestors and
' descendants, since there are not restrictions on store brands
'
s = RDIFilterClause("ProdMG_Category", "CategoryNumber", "@@CATEGORY_TOKEN@@",
0, 0)
If PremiumAccess Then
s = s & RDIFilterClause("ProdMG_Category_BM", "CategoryNumber",
"@@CATEGORY_TOKEN@@", 0, 0)
End If
' All Products by Vendor-Merch Group - again, category is all we need to work
about for level 2a
'
' All Products by Vendor - requires similar logic to "All Products by Vendor-
Merch Group"
'
' 2/12/14 - CVS no longer want vendor hierarchies to be visible - I'm leaving
the code block in case they later change their minds
' note that the vendor hierarchies all have level names starting with Vend*
' 1/22/19 - JW - restored following line of code to give access to the All
Products by Vendor hierarchy per CVS
s = s & RDIFilterClause("Vend_Category", "CategoryNumber",
"@@CATEGORY_TOKEN@@", 0, 0)
s = s & RDIFilterClause("LatestVend_Category", "CategoryNumber",
"@@CATEGORY_TOKEN@@", 0, 0)
'
' All Products by Brand - requires similar logic to "All Products by Merch
Group"
'
' 6/2/14 - make sure all segments in the category are visible as well as their
ancestors
' 1/14/15 - changed to allow both ancestors and descendants
'
' All products by Vendor-Brand - requires similar logic to "All Products by
Vendor-Merch Group"
'
' 2/12/14 - CVS no longer want vendor hierarchies to be visible - I'm leaving
the code block in case they later change their minds
' note that the vendor hierarchies all have level names starting with Vend*
'Sri 3/18 (L2A)- Added to make sure any ldap group defined at l2a has access to
competetive vendors' store brands as well since this is the
'requirement for l2a level
'Sri 3/28 - Commented out to work on security. wait to roll this out
' 6/21/16 - JW - modified ProdBC - L2a spec for the ProdBC hierarchy allows
them to see selected categories and then all vendors / store
' brands below - so we give unfettered access to the levels above (which is
just the root) and below) the categories specified
MSProductL2a_Category = s
End Function
If exceptEntry Then
exceptClause = "Except "
Else
exceptClause = ""
End If
If (AncestorLevels = 0) Then
' all ancestors
s = s & "<RDIEntry>" & exceptClause & "AncestorsOf(Filter(Group(" &
level_name & "), ""ATTRIBUTE """ & level_name & """.""" & Attr_Name & """ = '" &
attr_value & "'""))</RDIEntry>" & vbCrLf
ElseIf (AncestorLevels > 0) Then
' restricted number of ancestors
s = s & "<RDIEntry>" & exceptClause & "AncestorsOf(" & CStr(AncestorLevels)
& ",Filter(Group(" & level_name & "), ""ATTRIBUTE """ & level_name & """.""" &
Attr_Name & """ = '" & attr_value & "'""))</RDIEntry>" & vbCrLf
'
' else no ancestor clause
End If
If (DescLevels = 0) Then
' all descendants
s = s & "<RDIEntry>" & exceptClause & "DescendantsOf(Filter(Group(" &
level_name & "), ""ATTRIBUTE """ & level_name & """.""" & Attr_Name & """ = '" &
attr_value & "'""))</RDIEntry>" & vbCrLf
ElseIf (DescLevels > 0) Then
' restricted number of ancestors
s = s & "<RDIEntry>" & exceptClause & "DescendantsOf(" & CStr(DescLevels) &
",Filter(Group(" & level_name & "), ""ATTRIBUTE """ & level_name & """.""" &
Attr_Name & """ = '" & attr_value & "'""))</RDIEntry>" & vbCrLf
'
' else no descendants clause
End If
RDIFilterClause = s
End Function
Private Function
MSProductL2OrL3_Step2New_ShowStoreBrandsForVendorCategories(oDictUsedCategoryNumber
s As Dictionary, arrVendors As Variant) As String
'
' replaces the MSProductL2orL3_Step2_HideStoreBrandsAsNeeded() function - that
function had to hide store brands by exception. But now the rule is
' always hide store brands (handled byMSProductL2orL3_Step1_Category()) and
then be careful to show everything below the paying vendor's categories
'
' 2/12/14 - JW - removed access to the the three product hierachies that start
with the Vendor level
' 3/26/14 - JW - restored access to one of the three product hierarchies (All
Products by Vendor-Merch Group) removed on 2/12. Arrgh.
'
' for these two hierarchies, vendor is below cateogry
'
s = s & RDIFilterClause("ProdMG_PayVendor",
"CategoryNumber_VendorNumber", catNumVendNum, 0, 0)
s = s & RDIFilterClause("ProdBrand_PayVendor",
"CategoryNumber_VendorNumber", catNumVendNum, 0, 0)
s = s & RDIFilterClause("ProdBC_PayVendor",
"CategoryNumber_VendorNumber", catNumVendNum, 0, 0)
'
' for these three, category is below vendor
'
' 2/12/14 - CVS no longer want vendor hierarchies to be visible - I'm
leaving the code block in case they later change their minds
' note that the vendor hierarchies all have level names starting with
Vend*
' 3/26/14 - partially restore access to the Vendor anchor hierarchies
blocked on 2/12
s = s & RDIFilterClause("VendMG_Category",
"CategoryNumber_VendorNumber", catNumVendNum, 0, 0)
' 1/22/19 - JW - restored following line of code to give access to the
All Products by Vendor hierarchy per CVS
s = s & RDIFilterClause("Vend_Category", "CategoryNumber_VendorNumber",
catNumVendNum, 0, 0)
s = s & RDIFilterClause("LatestVend_Category",
"CategoryNumber_VendorNumber", catNumVendNum, 0, 0)
's = s & RDIFilterClause("VendBrand_Category",
"CategoryNumber_VendorNumber", catNumVendNum, 0, 0)
Next categoryNumber
Next vendorNumber
MSProductL2OrL3_Step2New_ShowStoreBrandsForVendorCategories = s
End Function
Dim s As String
Dim aCategoryNumber As Variant, aVendorNumber As Variant
s = ""
'
' two of the hierarchies have Category above Vendor and can be handled in a
simple catgory loop
'
'Sri 5/5/16 - Added access to Category level to L1/L1A levels for new hierarchy
All Products by Brand Consolidated(ProdBC_Category)
' 6/21/16 - JW - modified to reflect that new product hierarchy (ProdBC) has
the Category/Pay Vendor and StoreBrand as the immediate
' top 3 levels of the hierarchy
'
For Each aCategoryNumber In arrCategoryNumbers
s = s & "<RDIEntry>Filter(Group(ProdMG_Category), ""ATTRIBUTE
""ProdMG_Category"".""CategoryNumber"" = '" & aCategoryNumber & "'"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>AncestorsOf(Filter(Group(ProdMG_Category), ""ATTRIBUTE
""ProdMG_Category"".""CategoryNumber"" = '" & aCategoryNumber & "'""))</RDIEntry>"
& vbCrLf & _
"<RDIEntry>DescendantsOf(2, Filter(Group(ProdMG_Category), ""ATTRIBUTE
""ProdMG_Category"".""CategoryNumber"" = '" & aCategoryNumber & "'""))</RDIEntry>"
& vbCrLf & _
"<RDIEntry>Filter(Group(ProdBrand_Category), ""ATTRIBUTE
""ProdBrand_Category"".""CategoryNumber"" = '" & aCategoryNumber &
"'"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>AncestorsOf(Filter(Group(ProdBrand_Category), ""ATTRIBUTE
""ProdBrand_Category"".""CategoryNumber"" = '" & aCategoryNumber &
"'""))</RDIEntry>" & vbCrLf & _
"<RDIEntry>DescendantsOf(2, Filter(Group(ProdBrand_Category), ""ATTRIBUTE
""ProdBrand_Category"".""CategoryNumber"" = '" & aCategoryNumber &
"'""))</RDIEntry>" & vbCrLf & _
"<RDIEntry>Filter(Group(ProdBC_Category), ""ATTRIBUTE
""ProdBC_Category"".""CategoryNumber"" = '" & aCategoryNumber & "'"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>AncestorsOf(Filter(Group(ProdBC_Category), ""ATTRIBUTE
""ProdBC_Category"".""CategoryNumber"" = '" & aCategoryNumber & "'""))</RDIEntry>"
& vbCrLf
If PremiumAccess Then
s = s & "<RDIEntry>Filter(Group(ProdMG_Category_BM), ""ATTRIBUTE
""ProdMG_Category_BM"".""CategoryNumber"" = '" & aCategoryNumber &
"'"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>AncestorsOf(Filter(Group(ProdMG_Category_BM), ""ATTRIBUTE
""ProdMG_Category_BM"".""CategoryNumber"" = '" & aCategoryNumber &
"'""))</RDIEntry>" & vbCrLf
End If
Next aCategoryNumber
'
' the other three hierarchies have vendor above category, and have to be
handled in a nested loop to avoid accidental access in cases where
' a client might have L1 and L2 categories -
'
' NOTE: as an optimization - this could be combined into the simpler logic
above in cases where a client had only L1 categories
'
' 2/12/14 - CVS no longer want these to be visible - I'm leaving the code block
in case they later change their minds
' 3/26/14 - partially restore access to the Vendor anchor hierarchies blocked
on 2/12
' 1/22/19 - JW - restored access to the "all Products by Vendor" hierarchy by
uncommenting the line below involving "Vend_Category"
For Each aCategoryNumber In arrCategoryNumbers
For Each aVendorNumber In arrVendorNumbers
Dim CatNumberVendorNumber As String
CatNumberVendorNumber = aCategoryNumber & " " & aVendorNumber
s = s & RDIFilterClause("VendMG_Category",
"CategoryNumber_VendorNumber", CatNumberVendorNumber, 1, 0)
s = s & RDIFilterClause("Vend_Category",
"CategoryNumber_VendorNumber", CatNumberVendorNumber, 1, 0)
s = s & RDIFilterClause("LatestVend_Category",
"CategoryNumber_VendorNumber", CatNumberVendorNumber, 1, 0)
's = s & RDIFilterClause("VendBrand_Category",
"CategoryNumber_VendorNumber", CatNumberVendorNumber, 1, 0)
Next aVendorNumber
Next aCategoryNumber
' 2/12/14 - CVS no longer want vendor hierarchies to be visible - I'm leaving
the code block in case they later change their minds
' note that the vendor hierarchies all have level names starting with Vend*
' 3/26/14 - partially restore access to the Vendor anchor hierarchies blocked
on 2/12
'6/21/16 JW - for level 1 ProdBC hierarchy, they can only see their own pay
vendor codes, and everything below (store brand / national)
' is fair game, as they are at this point restricted to the category/vendor
that are themselves
s = s & RDIFilterClause("ProdBC_PayVendor", "VendorNumber",
CStr(aVendorNumber), -1, 0)
Next aVendorNumber
MSBlockProductL1 = s
End Function
'
' CELLSECURITY:BaseSalesMeasures, Inventory and Restricted Product Attributes
'
' see CSBlockProductL2 for cell security note
'
"<RDIEntry>DescendantsOf(""CELLSECURITY:RegPromoSalesMeasures"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>DescendantsOf(""CELLSECURITY:RegPromoSalesAndUnitsDatamaps"")</
RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Product"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except RootsOf(Product)</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except Group(ProdMG_MerchGrp)</RDIEntry>" & vbCrLf &
_
"<RDIEntry>Except Group(ProdBrand_MerchGrp)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>Except Group(VendMG_MerchGrp)</RDIEntry>" & vbCrLf &
_
"<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except DescendantsOf(""All Products by Merch Group
Benchmarking"")</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
CSInnerGeographyRestriction(geogRestrictCityDistrictDCandStore) & _
"</RuleDomain>" & vbCrLf & _
"</SecurityDomain>" & vbCrLf
'
' Scan Margin, Scan Margin TPR and restricted product attributes - from pay
vendor, is restricted to vendor associated with user group. But allowed for all
members of the
' Merchant Group, Category and Subcategory levels which are found about Pay
Vendor in the Product by Merch Group hierarchy. Ditto for the same levels
' in the "All Products by Brand" hierarchy.
'
'
' as part of the 11/18/13 changes - removed this block of product RDI entries:
'
'"<RDIEntry>""All Products by Merch Group""</RDIEntry>" & vbCrLf & _
' "<RDIEntry>""All Products by Vendor-Merch Group""</RDIEntry>"
& vbCrLf & _
' "<RDIEntry>""All Products by Vendor""</RDIEntry>" & vbCrLf & _
' "<RDIEntry>""All Products by Brand""</RDIEntry>" & vbCrLf & _
' "<RDIEntry>""All Products by Vendor-Brand""</RDIEntry>" &
vbCrLf & _
'
' 2/2/2014 - removed from Measures grouping immediately below
'
' "<RDIEntry>DescendantsOf(""Restricted Product Attributes"")</RDIEntry>" &
vbCrLf & _
'
' 1/24/15 - added Margin Contribution measures
s = s & CSInnerProductFilteredVendorClause(arrVendorNumbers)
s = s & CSInnerProductFilteredVendorClause(arrVendorNumbers)
s = s & CSInnerProductFilteredVendorClause(arrVendorNumbers)
s = s & "<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf
s = s & "<RDIEntry>Except DescendantsOf(""All Products by Merch
Group Benchmarking"")</RDIEntry>" & vbCrLf
s = s & CSUnrestrictedAttributeMeasuresClause
End Function
End Function
End Function
End Function
'
' 10/6/13 - JW - added support for the newly modified "All Products by Vendor"
(Vend_* levels)
' and "All Products by Brand" (ProdBrand_* levels) hierarchies.
'
' 11/11/13 - JW - adapted to use array of vendor numbers, rather than names
'
' 3/27/14 - JW - as part of restoring access to the All Products by Vendor-
Merch Group hierarchy (VendMG*),
' CVS introduced a new requirement that POS measures not report
against the VendMG hierarchy at all.
' Bizarre, since the hierarchy is already restricted to specified pay
vendor.
'
' 8/21/14 - JW - reviewed procedure to determine whether security hack for
explicit access to
' "Vendor-PayVendor-Category-StoreBrand" product member - else time
custom aggs
' will sometimes not work is needed here. Deteremine that it was not
needed directly in this procedure, but is
' needed in the CSInnerProductFilteredVendorClause() routine called from
here.
'
' note that vendor names can be an array of vendor names
' L1A applies the same product level restrictions for all of the POS measure
groups. But Sales and Units
' still needs its own block, as it doesn't carry the same geography
restriction that the other
' groups do.
'
Dim s As String
'
' CELLSECURITY:BaseSalesMeasures, Inventory and Restricted Product Attributes
'
' we can't allow custom aggs for L1A even for Sales and Units, as the upper
levels are restricted, and
' custom aggs might allow an end run
'
' 4/13/14 - added cMeasuresForProductCustomAggHack
'
s = "<SecurityDomain>" & vbCrLf & _
"<Accessor type=""Group"">@@LDAP_GROUP@@</Accessor>" & vbCrLf & _
"<CanWriteBack>false</CanWriteBack>" & vbCrLf & _
"<CanEditUEV>false</CanEditUEV>" & vbCrLf & _
"<RuleDomain>" & vbCrLf & _
"<Dimension name=""Measures"">" & vbCrLf & _
s = s & CSInnerProductFilteredVendorClause(arrVendorNumbers)
s = s & "<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf
s = s & "<RDIEntry>Except DescendantsOf(""All Products by Merch
Group Benchmarking"")</RDIEntry>" & vbCrLf
s = s & "</Dimension>" & vbCrLf & _
CSInnerGeographyRestriction(geogNoRestrictions) & _
"</RuleDomain>" & vbCrLf & _
"</SecurityDomain>" & vbCrLf
'
' CELLSECURITY:RegPromoSalesMeasures
'
' we can't allow custom aggs for L1A even for Sales and Units, as the upper
levels are restricted, and
' custom aggs might allow an end run
'
' 2/2/2014 - removed "<RDIEntry>DescendantsOf(""Restricted Product
Attributes"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>DescendantsOf(""CELLSECURITY:RegPromoSalesMeasures"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>DescendantsOf(""CELLSECURITY:RegPromoSalesAndUnitsDatamaps"")</
RDIEntry>"
s = s & CSInnerProductFilteredVendorClause(arrVendorNumbers)
s = s & "<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf
s = s & "<RDIEntry>Except DescendantsOf(""All Products by Merch
Group Benchmarking"")</RDIEntry>" & vbCrLf
'
' Scan Margin, Scan Margin TPR, Sales and Units TPR
' must be separate from the other POS measure groups, as these are not
' allowed at the leaves of geography
' 1/24/15 - added Margin Contribution measures
'
s = s & "<SecurityDomain>" & vbCrLf & _
"<Accessor type=""Group"">@@LDAP_GROUP@@</Accessor>" & vbCrLf & _
"<CanWriteBack>false</CanWriteBack>" & vbCrLf & _
"<CanEditUEV>false</CanEditUEV>" & vbCrLf & _
"<RuleDomain>" & vbCrLf & _
"<Dimension name=""Measures"">" & vbCrLf & _
"<RDIEntry>DescendantsOf(""Scan Margin"")</RDIEntry>" & vbCrLf
& _
"<RDIEntry>DescendantsOf(""Scan Margin TPR"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>DescendantsOf(""Margin Contribution"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>DescendantsOf(""CELLSECURITY:Scan Margin
Datamaps"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>DescendantsOf(""Sales and Units TPR"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>DescendantsOf(""CELLSECURITY:Sales and Units TPR
Datamaps"")</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Product"">" & vbCrLf
s = s & CSInnerProductFilteredVendorClause(arrVendorNumbers)
'
' add the unrestricted measure attributes
'
s = s & CSUnrestrictedAttributeMeasuresClause
End Function
'
Dim aVendorNumber As Variant
'"<RDIEntry>Filter(Group(ProdMG_PayVendor), ""ATTRIBUTE
""ProdMG_PayVendor"".""VendorNumber"" = '" & aVendorNumber & "'"")</RDIEntry>" &
vbCrLf & _
'"<RDIEntry>DescendantsOf(Filter(Group(ProdMG_PayVendor),
""ATTRIBUTE ""ProdMG_PayVendor"".""VendorNumber"" = '" & aVendorNumber &
"'""))</RDIEntry>" & vbCrLf & _
'"<RDIEntry>Filter(Group(ProdBrand_PayVendor), ""ATTRIBUTE
""ProdBrand_PayVendor"".""VendorNumber"" = '" & aVendorNumber & "'"")</RDIEntry>" &
vbCrLf & _
'"<RDIEntry>DescendantsOf(Filter(Group(ProdBrand_PayVendor),
""ATTRIBUTE ""ProdBrand_PayVendor"".""VendorNumber"" = '" & aVendorNumber &
"'""))</RDIEntry>" & vbCrLf
Next aVendorNumber
Else ' include
'6/20/16 - Sri - Added ProdBC_PayVendor line
'
' 3/2/19 - JW - added support for All Products by Vendor (VEND_*) which had
been removed back in 2014
'
For Each aVendorNumber In arrVendorNumbers
CSInnerProductFilteredVendorClause = CSInnerProductFilteredVendorClause
& _
RDIFilterClause("ProdMG_PayVendor", "VendorNumber", aVendorNumber,
ancestorArg, 0) & _
RDIFilterClause("ProdBrand_PayVendor", "VendorNumber",
aVendorNumber, ancestorArg, 0) & _
RDIFilterClause("VendMG_PayVendor", "VendorNumber", aVendorNumber,
ancestorArg, 0) & _
RDIFilterClause("ProdBC_PayVendor", "VendorNumber", aVendorNumber,
ancestorArg, 0) & _
RDIFilterClause("Vend_PayVendor", "VendorNumber", aVendorNumber,
ancestorArg, 0) & _
RDIFilterClause("LatestVend_PayVendor", "VendorNumber",
aVendorNumber, ancestorArg, 0)
'"<RDIEntry>Filter(Group(ProdMG_PayVendor), ""ATTRIBUTE
""ProdMG_PayVendor"".""VendorNumber"" = '" & aVendorNumber & "'"")</RDIEntry>" &
vbCrLf & _
'"<RDIEntry>DescendantsOf(Filter(Group(ProdMG_PayVendor),
""ATTRIBUTE ""ProdMG_PayVendor"".""VendorNumber"" = '" & aVendorNumber &
"'""))</RDIEntry>" & vbCrLf & _
'"<RDIEntry>Filter(Group(ProdBrand_PayVendor), ""ATTRIBUTE
""ProdBrand_PayVendor"".""VendorNumber"" = '" & aVendorNumber & "'"")</RDIEntry>" &
vbCrLf & _
'"<RDIEntry>DescendantsOf(Filter(Group(ProdBrand_PayVendor),
""ATTRIBUTE ""ProdBrand_PayVendor"".""VendorNumber"" = '" & aVendorNumber &
"'""))</RDIEntry>" & vbCrLf & _
'"<RDIEntry>Filter(Group(VendMG_PayVendor), ""ATTRIBUTE
""VendMG_PayVendor"".""VendorNumber"" = '" & aVendorNumber & "'"")</RDIEntry>" &
vbCrLf & _
'"<RDIEntry>DescendantsOf(Filter(Group(VendMG_PayVendor),
""ATTRIBUTE ""VendMG_PayVendor"".""VendorNumber"" = '" & aVendorNumber &
"'""))</RDIEntry>" & vbCrLf
Next aVendorNumber
End If ' include VendMG
' 2/12/14 - CVS no longer want vendor hierarchies to be visible - I'm leaving
the code block in case they later change their minds
' note that the vendor hierarchies all have level names starting with Vend*
' 3/26/14 - partially restore access to the Vendor anchor hierarchies blocked
on 2/12
' still ommitting: "<RDIEntry>Except Group(VendBrand_MerchGrp)</RDIEntry>" &
vbCrLf
'
' 3/27/14 - added exclude logic - this little block could be consolidated
above, but I strongly suspect CVS will end up reversing
' themselves on this weird exclusion, and so keep this separate in
case the if/then/else block folds back into a single block
' above
'
If Not ExcludeVendMGHierarchy Then
CSInnerProductFilteredVendorClause = CSInnerProductFilteredVendorClause & _
"<RDIEntry>Except Group(VendMG_MerchGrp)</RDIEntry>" & vbCrLf
'"<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf & _
'"<RDIEntry>Except DescendantsOf(""All Products by Merch Group
Benchmarking"")</RDIEntry>" & vbCrLf
' "<RDIEntry>Except Group(VendBrand_MerchGrp)</RDIEntry>" & vbCrLf
End If
'
' 8/21/14 - added explicit access to "Vendor-PayVendor-Category-StoreBrand"
product member - else time custom aggs
' will sometimes not work.
'
CSInnerProductFilteredVendorClause = "<RDIEntry>""Vendor-PayVendor-Category-
StoreBrand""</RDIEntry>" & vbCrLf & _
CSInnerProductFilteredVendorClause
End Function
Private Function CSInnerGeographyRestriction(restriction As
enumGeographyRestriction) As String
' 2/12/14 - JW - removed access to the the three product hierachies that
start with the Vendor level (levels that start with Vend*)
' 2/24/14 - JW - added logic to deal with new Store Cluster hierarchy
(entries with StoreCluster_Store)
If ModelHasDistributionCenterAsDimension Then
CSInnerGeographyRestriction = "<Dimension name=""Geography"">" &
vbCrLf & _
"<RDIEntry>except
group(StateCounty_Store)</RDIEntry>" & vbCrLf & _
"<RDIEntry>except group(State_Store)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>except group(AdRegion_Store)</RDIEntry>"
& vbCrLf & _
"<RDIEntry>except group(DMA_Store)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>except group(Area_Store)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>except
group(StoreCluster_Store)</RDIEntry>" & vbCrLf & _
"<RDIEntry>except group(Store)</RDIEntry>" & vbCrLf
& _
"<RDIEntry>except
group(withYmasNavarro_Store)</RDIEntry>" & vbCrLf & _
"<RDIEntry>~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf
Else
CSInnerGeographyRestriction = "<Dimension name=""Geography"">" &
vbCrLf & _
"<RDIEntry>except
group(StateCounty_Store)</RDIEntry>" & vbCrLf & _
"<RDIEntry>except group(State_Store)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>except group(AdRegion_Store)</RDIEntry>"
& vbCrLf & _
"<RDIEntry>except group(DMA_Store)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>except group(Area_Store)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>except group(DC_Store)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>except
group(StoreCluster_Store)</RDIEntry>" & vbCrLf & _
"<RDIEntry>except group(Store)</RDIEntry>" & vbCrLf
& _
"<RDIEntry>except
group(withYmasNavarro_Store)</RDIEntry>" & vbCrLf & _
"<RDIEntry>~</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf
End If
Case geogRestrictCityDistrictDCandStore
If ModelHasDistributionCenterAsDimension Then
End Function
'
' CELLSECURITY:RegPromoSalesMeasures
'
' 2/2/14 - removed "<RDIEntry>DescendantsOf(""Restricted Product
Attributes"")</RDIEntry>" & vbCrLf & _
' 2/12/14 - removed these two clauses:
' "<RDIEntry>Except Group(VendMG_MerchGrp)</RDIEntry>" & vbCrLf & _
' "<RDIEntry>Except Group(VendBrand_MerchGrp)</RDIEntry>" & vbCrLf & _
' 2/13/14 - changed to use CELLSECURITY:RegPromoSalesAndUnitsDatamaps rather
than
' CELLSECURITY:Sales and Units Datamaps to get around AS custom agg bug
with cell security
'
' 3/26/14 - partially restore access to the Vendor anchor hierarchies blocked
on 2/12 (VendMG*)
'
' Note the geography restriction "geogRestrictCityDistrictDCandStore"
corresponds to security level
' yellow in the security bible.
s = s & "<SecurityDomain>" & vbCrLf & _
"<Accessor type=""Group"">@@LDAP_GROUP@@</Accessor>" & vbCrLf & _
"<CanWriteBack>false</CanWriteBack>" & vbCrLf & _
"<CanEditUEV>false</CanEditUEV>" & vbCrLf & _
"<RuleDomain>" & vbCrLf & _
"<Dimension name=""Measures"">" & vbCrLf & _
"<RDIEntry>DescendantsOf(""CELLSECURITY:RegPromoSalesMeasures"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>DescendantsOf(""CELLSECURITY:RegPromoSalesAndUnitsDatamaps"")</
RDIEntry>" & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Product"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except RootsOf(Product)</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except Group(ProdMG_MerchGrp)</RDIEntry>" & vbCrLf &
_
"<RDIEntry>Except Group(ProdBrand_MerchGrp)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>Except Group(VendMG_MerchGrp)</RDIEntry>" & vbCrLf &
_
"<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except DescendantsOf(""All Products by Merch Group
Benchmarking"")</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
CSInnerGeographyRestriction(geogRestrictCityDistrictDCandStore) & _
"</RuleDomain>" & vbCrLf & _
"</SecurityDomain>" & vbCrLf
'==================================================================================
============
'
' FROM HERE ON DOWN, IS THE SAME AS CSBLOCKL1_AND_L2 - SHOULD BE FACTORED INTO
COMMON ROUTINE
'
'==================================================================================
============
'
' Scan Margin, Scan Margin TPR and Restricted Product Attributes
'
' no datamap reference here - we don't want custom aggs to work with cell
security for these
' measures yet
'
' 2/2/14 - removed "<RDIEntry>DescendantsOf(""Restricted Product
Attributes"")</RDIEntry>" & vbCrLf & _
'
' 1/24/15 - added Margin Contribution measures
s = s & CSInnerProductFilteredVendorClause(arrVendorNumbers)
s = s & CSInnerProductFilteredVendorClause(arrVendorNumbers)
s = s & "<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf
s = s & "<RDIEntry>Except DescendantsOf(""All Products by Merch
Group Benchmarking"")</RDIEntry>" & vbCrLf
s = s & "</Dimension>" & vbCrLf & _
CSInnerGeographyRestriction(geogNoRestrictions) & _
"</RuleDomain>" & vbCrLf & _
"</SecurityDomain>" & vbCrLf
End If
End If ' includeInventory
s = s & CSUnrestrictedAttributeMeasuresClause
End Function
' 6/6/14 - JW - corner case problems with combining level 2 and level 1
categories for a single ldap group forced creation of this routine
' note that Level 2 and level 2a are the same as far as this routine is
concerned, and only the level 1 categories need to be specified
' as they are subject to additional restrictions.
'
' deal with level 2 categories. There might not be any - but we need to call
this anyway to make sure the all nodes of the product orths do the
' right thing in terms of not restricting our sales measures
'
' and level 1
'
s = s & "<SecurityDomain>" & vbCrLf & _
"<Accessor type=""Group"">@@LDAP_GROUP@@</Accessor>" & vbCrLf & _
"<CanWriteBack>false</CanWriteBack>" & vbCrLf & _
"<CanEditUEV>false</CanEditUEV>" & vbCrLf & _
"<RuleDomain>" & vbCrLf & _
"<Dimension name=""Measures"">" & vbCrLf & _
'
' CELLSECURITY:RegPromoSalesMeasures
'
' 2/2/14 - removed "<RDIEntry>DescendantsOf(""Restricted Product
Attributes"")</RDIEntry>" & vbCrLf & _
' 2/12/14 - removed these two clauses:
' "<RDIEntry>Except Group(VendMG_MerchGrp)</RDIEntry>" & vbCrLf & _
' "<RDIEntry>Except Group(VendBrand_MerchGrp)</RDIEntry>" & vbCrLf & _
' LEVEL 2
"<RDIEntry>DescendantsOf(""CELLSECURITY:RegPromoSalesAndUnitsDatamaps"")</
RDIEntry>" & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Product"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except RootsOf(Product)</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except Group(ProdMG_MerchGrp)</RDIEntry>" & vbCrLf &
_
"<RDIEntry>Except Group(ProdBrand_MerchGrp)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>Except Group(VendMG_MerchGrp)</RDIEntry>" & vbCrLf &
_
"<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except DescendantsOf(""All Products by Merch Group
Benchmarking"")</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
CSInnerL1_AND_L2ProductOrthRestrictions(arrL1CategoryNumbers,
True) & vbCrLf & _
CSInnerGeographyRestriction(geogRestrictCityDistrictDCandStore) & _
"</RuleDomain>" & vbCrLf & _
"</SecurityDomain>" & vbCrLf
'
' Level 1
'
"<RDIEntry>DescendantsOf(""CELLSECURITY:RegPromoSalesMeasures"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>DescendantsOf(""CELLSECURITY:RegPromoSalesAndUnitsDatamaps"")</
RDIEntry>" & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Product"">" & vbCrLf & _
CSInnerProductFilteredVendorClause(arrVendorNumbers, False,
True) & vbCrLf & _
ExceptProductRootsAndMerchLevels & _
"</Dimension>" & vbCrLf & _
CSInnerL1_AND_L2ProductOrthRestrictions(arrL1CategoryNumbers,
False) & vbCrLf & _
CSInnerGeographyRestriction(geogRestrictCityDistrictDCandStore) & _
"</RuleDomain>" & vbCrLf & _
"</SecurityDomain>" & vbCrLf
'==================================================================================
============
'
' FROM HERE ON DOWN, IS THE SAME AS CSBLOCKL1_OR_L2 - SHOULD BE FACTORED INTO
COMMON ROUTINE
'
'==================================================================================
============
'
' Scan Margin, Scan Margin TPR and Restricted Product Attributes
'
' no datamap reference here - we don't want custom aggs to work with cell
security for these
' measures yet
'
' 2/2/14 - removed "<RDIEntry>DescendantsOf(""Restricted Product
Attributes"")</RDIEntry>" & vbCrLf & _
'
' 1/24/15 - added Margin Contribution measures
s = s & CSInnerProductFilteredVendorClause(arrVendorNumbers)
s = s & "<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf
s = s & "<RDIEntry>Except DescendantsOf(""All Products by Merch
Group Benchmarking"")</RDIEntry>" & vbCrLf
s = s & "</Dimension>" & vbCrLf & _
CSInnerGeographyRestriction(geogRestrictStoreOnly) & _
"</RuleDomain>" & vbCrLf & _
"</SecurityDomain>" & vbCrLf
'
' Sales and Units TPR (can't be combined with Sales and Units, due to
additional geog restriction)
'
' Custom aggs with cell security are ok for these measures
'
' 2/12/14 - removed these two clauses:
' "<RDIEntry>Except Group(VendMG_MerchGrp)</RDIEntry>" & vbCrLf & _
' "<RDIEntry>Except Group(VendBrand_MerchGrp)</RDIEntry>" & vbCrLf & _
'
' 3/26/14 - partially restore access to the Vendor anchor hierarchies blocked
on 2/12 (VendMG*)
'
' 6/2/14 - changed restriction from "geogRestrictCityDistrictDCandStore" to
"geogRestrictStoreOnly" based on
' feedback from Tim.
'
s = s & "<SecurityDomain>" & vbCrLf & _
"<Accessor type=""Group"">@@LDAP_GROUP@@</Accessor>" & vbCrLf & _
"<CanWriteBack>false</CanWriteBack>" & vbCrLf & _
"<CanEditUEV>false</CanEditUEV>" & vbCrLf & _
"<RuleDomain>" & vbCrLf & _
"<Dimension name=""Measures"">" & vbCrLf & _
"<RDIEntry>DescendantsOf(""Sales and Units TPR"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>DescendantsOf(""CELLSECURITY:Sales and Units TPR
Datamaps"")</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Product"">" & vbCrLf & _
"<RDIEntry>*~</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except RootsOf(Product)</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except Group(ProdMG_MerchGrp)</RDIEntry>" & vbCrLf &
_
"<RDIEntry>Except Group(ProdBrand_MerchGrp)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>Except Group(VendMG_MerchGrp)</RDIEntry>" & vbCrLf &
_
"<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except DescendantsOf(""All Products by Merch Group
Benchmarking"")</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
CSInnerGeographyRestriction(geogRestrictStoreOnly) & _
"</RuleDomain>" & vbCrLf & _
"</SecurityDomain>" & vbCrLf
'
' Inventory - only available for purchased pay vendors, but can't be
combined with the
' Scan Margin measures, as these are not subject to geography restriction.
Can't be
' combined with Sales and Units, as those are available at all levels of
the product hierarchy.
'
' again - we don't want custom aggs to work with inventory measures yet -
'
' 10/28/13 - corrected geography restriction - was restricted, shouldn't
have een
' 20190302
If includeInventory Then
If PremiumAccess Then
s = s & "<SecurityDomain>" & vbCrLf & _
"<Accessor type=""Group"">@@LDAP_GROUP@@</Accessor>" & vbCrLf & _
"<CanWriteBack>false</CanWriteBack>" & vbCrLf & _
"<CanEditUEV>false</CanEditUEV>" & vbCrLf & _
"<RuleDomain>" & vbCrLf & _
"<Dimension name=""Measures"">" & vbCrLf & _
"<RDIEntry>DescendantsOf(""Inventory"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>DescendantsOf(""CELLSECURITY:Inventory
Datamaps"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>DescendantsOf(""Purchase Orders :
FOLDER"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>DescendantsOf(""Appointment :
FOLDER"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>DescendantsOf(""Planned Delivery :
FOLDER"")</RDIEntry>" & vbCrLf & _
"<RDIEntry>DescendantsOf(""Display : FOLDER"")</RDIEntry>"
& vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Product"">" & vbCrLf
s = s & CSInnerProductFilteredVendorClause(arrVendorNumbers)
s = s & "<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf
s = s & "<RDIEntry>Except DescendantsOf(""All Products by Merch
Group Benchmarking"")</RDIEntry>" & vbCrLf
s = s & "</Dimension>" & vbCrLf & _
CSInnerGeographyRestriction(geogNoRestrictions) & _
"</RuleDomain>" & vbCrLf & _
"</SecurityDomain>" & vbCrLf
Else
s = s & "<SecurityDomain>" & vbCrLf & _
"<Accessor type=""Group"">@@LDAP_GROUP@@</Accessor>" & vbCrLf & _
"<CanWriteBack>false</CanWriteBack>" & vbCrLf & _
"<CanEditUEV>false</CanEditUEV>" & vbCrLf & _
"<RuleDomain>" & vbCrLf & _
"<Dimension name=""Measures"">" & vbCrLf & _
"<RDIEntry>DescendantsOf(""Inventory"")</RDIEntry>" &
vbCrLf & _
"<RDIEntry>DescendantsOf(""CELLSECURITY:Inventory
Datamaps"")</RDIEntry>" & vbCrLf & _
"</Dimension>" & vbCrLf & _
"<Dimension name=""Product"">" & vbCrLf
s = s & CSInnerProductFilteredVendorClause(arrVendorNumbers)
s = s & "<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf
s = s & "<RDIEntry>Except DescendantsOf(""All Products by Merch
Group Benchmarking"")</RDIEntry>" & vbCrLf
s = s & "</Dimension>" & vbCrLf & _
CSInnerGeographyRestriction(geogNoRestrictions) & _
"</RuleDomain>" & vbCrLf & _
"</SecurityDomain>" & vbCrLf
End If
End If ' includeInventory
s = s & CSUnrestrictedAttributeMeasuresClause
End Function
ExceptProductRootsAndMerchLevels = "<RDIEntry>Except
RootsOf(Product)</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except Group(ProdMG_MerchGrp)</RDIEntry>" & vbCrLf &
_
"<RDIEntry>Except Group(ProdBrand_MerchGrp)</RDIEntry>" &
vbCrLf & _
"<RDIEntry>Except Group(VendMG_MerchGrp)</RDIEntry>" & vbCrLf &
_
"<RDIEntry>Except ""All Products by Merch Group
Benchmarking""</RDIEntry>" & vbCrLf & _
"<RDIEntry>Except DescendantsOf(""All Products by Merch Group
Benchmarking"")</RDIEntry>" & vbCrLf
End Function
'==================================================================================
===================================
'
' The following routines are based on logic fromt the JASCS_MemberSecurity module,
but have been tailored here
' to allow member and cell security to be set together for 1 or more groups at once
' Note that there exists a separate version of this routine which handles only a
single LDAP group at a time. That
' version also allows for deleting an entry, which the batch version does not
'
'==================================================================================
===================================
Public Sub MergeAndSetMemberAndCellSecurityAndGenerateDimVisibility(modelName As
String, modelSummary As String)
'
' 5/9/14 - JW - created
' 7/24/18 - JW - extended to also generate dimension visible by LDAP groups,
since CVS now want to selecting
' hide/show one or more dimensions
'
Dim s As String, ldapGroups As String, memberSecurityContent As String,
cellSecurityContent As String
'Dim cellSecurityContent As String
Dim oD As DOMDocument
Dim accessorList As String
' read in the files that were built up by processing the security input sheet -
they specify the groups that
' are getting replaced or added and member and cell security content for those
groups
'
ldapGroups = ReadFile("C:\temp\CVS_PIP_LDAPGROUPS.txt")
memberSecurityContent = ReadFile("C:\temp\CVS_PIP_MemberSecurity.txt")
cellSecurityContent = ReadFile("C:\temp\CVS_PIP_CellSecurity.txt")
'
' get dim list
'
Dim oDimensionXML As DOMDocument
Set oDimensionXML = JASCS_ASCS.SendASCSRequest("Fetching dimension
information", "<ascs:getDimensions modelName=""@@MODEL@@""/>", modelName, False)
Dim sDimVizCSV As String
'
' get the existing member and cell security
Set oD = GetMemberAndCellSecurityForModel(modelName, True)
'
' build a dictionary of the accessors
'
Dim oDictAccessors As New Dictionary
'
' spin through our existing cell and member security dom twice - on the first
pass merge member security, on the second do
' cell
For iteration = 1 To 2
'
Dim oNode As IXMLDOMNode
'
' 11/4/15 - we need to convert "a" to uppercase when doing the
comparison, as the xmlscrub
' routine may insert lower case. We don't want to permanently change
a, however, as the
' upper case magic XML characters won't do what is needed
'
' go ahead and generate dim viz before we tackle the model changes
'
Dim oDV As New DOMDocument
Dim nn As Integer
oDV.LoadXML "<foo>" & memberSecurityContent & "</foo>"
If oDV.parseError.reason <> "" Then
MsgBox "Invalid member security: " & oD.parseError.reason & vbCrLf &
oD.parseError.srcText, vbCritical, "Invalid member security"
Exit Sub
Else
Dim oUG As IXMLDOMNode
Dim dictUsers As New Dictionary
'
' use a dict to make sure we have no dupes
sDimVizCSV = ""
For Each oUG In oDV.SelectNodes("//Accessor")
If Not dictUsers.Exists(oUG.Text) Then
dictUsers.Add oUG.Text, oUG.Text
End If
If InStr(1, oUG.Text, ",") Then
' Debug.Print oUG.Text
End If
Next oUG
For Each k In dictUsers.Keys
sDimVizCSV = sDimVizCSV & ",""" & k & """"
'Debug.Print oUG.xml
nn = nn + 1
Next k
'Debug.Print "group count " & nn
End If
Else
sDimVizCSV = sDimVizCSV & ",X"
nn = nn + 1
End If
Next k
' Debug.Print "visible dim " & nn
sDimVizCSV = sDimVizCSV & vbCrLf
Else
'
' hidden dim - hidden dims stay hidden for everyone
'
nn = 0
For Each k In dictUsers.Keys
sDimVizCSV = sDimVizCSV & ","
'Debug.Print oUG.xml
nn = nn + 1
Next k
' Debug.Print "hidden dim group count " & nn
sDimVizCSV = sDimVizCSV & vbCrLf
End If
Next oDim
End If
WriteFile sDimVizCSV, cPathToDimensionScopingFile
End Sub
GroupGetsPremium = False
internalPremiumGroups = "|IRICOMMERCIAL.COM\CVS_PIP_ADMIN|IRICOMMERCIAL.COM\
CVS_PIP_CVS|IRICOMMERCIAL.COM\CVS_PIP_INTERNAL|IRICOMMERCIAL.COM\
CVS_PIP_INV_MEASURES|IRICOMMERCIAL.COM\LD_DEMO_ADMIN|INFORES.COM\LD_DEMO_ADMIN|"
Dim s As String
s = "|" & UCase(groupName) & "|"
'
' any DEV or QA group gets access
'Sam Start
If (isCSOrMS = 0) Then
Dim r As Integer
Dim ldapGroup As String
r = 0
While Range("A2").Offset(r, 0) <> ""
ldapGroup = Range("A2").Offset(r, colLDAPGroup).Value
If ldapGroup = groupName Then
If UCase(Left(Range("A2").Offset(r,
colPremiumAccessLevel).Value, 1)) = "Y" Then
GroupGetsPremium = True
Else
GroupGetsPremium = False
End If
End If
r = r + 1
Wend
'Sam End
End If
If GroupGetsPremium Then
Debug.Print "Premium Access:" & groupName
End If
End Function
'==================================================================================
===================================
'
' The following routines are based on logic fromt the JASCS_MemberSecurity module,
but have been tailored here
' to allow member and cell security to be set together, and to reduce the number of
questions posed to the user.
' This version assumes that only one LDAP group is being handled at a time. There
is a separate routine for doing
' batch changes.
' Note that only the iterative vesion below can handle deletes
'
'==================================================================================
===================================
Private Sub MergeAndSetMemberAndCellSecurity(modelName As String,
cellSecurityContent As String, memberSecurityContent As String, _
Accessor As String, modelSummary As String,
Optional DeleteAccessor As Boolean = False)
'
' 10/8/13 - based on more iteractive version in JASCS_MemberSecurity
'
' 3/26/14 - added modelSummary - which is intended to keep a short notation of
the vendor/category settings in the model
' description
' 3/31/14 - added DeleteAccessor optional arg to allow this same function to
delete a group. AS APIs don't have a way to
' do that short of simply resubmitting the entire block of security,
less the entry that is no longer desired.
'
Dim s As String, mergeSecurity As Boolean
'Dim cellSecurityContent As String
Dim oD As DOMDocument
'
' get both member and cell security
Set oD = GetMemberAndCellSecurityForModel(modelName, True)
'
' spin through our existing cell and member security dom twice - on the first
pass merge member security, on the second do
' cell
For iteration = 1 To 2
'
Dim oNode As IXMLDOMNode
End Sub
MergeMemberAndCellSecurityInner = False
'
' check both payloads to make sure they are valid XML
'
oD.LoadXML "<foo>" & cellSecurityContent & "</foo>"
If oD.parseError.reason <> "" Then
MsgBox "Invalid cell security: " & oD.parseError.reason & vbCrLf &
oD.parseError.srcText, vbCritical, "Invalid cell security"
Exit Function
End If
Set oD = Nothing
Set oD = SendASCSRequestToChangeModel(caption, s, Model, False, 900)
s = ""
s = s & "<ascs:setModelProperties modelName='@@MODEL@@'>" & vbCrLf
s = s & "<IsMemberSecurityEnabled>true</IsMemberSecurityEnabled>" & vbCrLf
s = s & "</ascs:setModelProperties>" & vbCrLf
s = s & "<ascs:setModelMemberSecurityDomains modelName='@@MODEL@@'
action='Replace'>" & vbCrLf
s = s & memberSecurityContent & vbCrLf
s = s & "</ascs:setModelMemberSecurityDomains>" & vbCrLf
Set oD = Nothing
Set oD = SendASCSRequestToChangeModel(caption, s, Model, False, 900)
'
' If there had been an error, it will have already been display and oD will
have been returned as nothing
'
If Not oD Is Nothing And Trim(oD.xml) <> "" Then
'MsgBox "Member and cell security applied to " & model, vbOKOnly, model &
"Security"
MergeMemberAndCellSecurityInner = True
End If
End Function
End Function
oRef.Load cachedVendorCategoryInfoFilename
r = 2
SKIP:
With frmWizard
.ListBox1.Clear
.ListBox1.MultiSelect = fmMultiSelectMulti
.caption = "foo"
cats = ""
For Each oCategory In oVendor.ChildNodes
'Debug.Print "foo"
'Debug.Print vbTab & oCategory.Attributes.getNamedItem("name").Text
If InStr(1, oCategory.xml, "name=""STORE BRAND""") > 0 Then
cats = cats & oCategory.Attributes.getNamedItem("name").Text &
"|"
Else
cats = cats & oCategory.Attributes.getNamedItem("name").Text &
"[NATIONAL BRAND ONLY]" & "|"
End If
Next oCategory
.ListBox1.AddItem oVendor.Attributes.getNamedItem("name").Text
oDictVendor.Add oVendor.Attributes.getNamedItem("name").Text,
Left(cats, Len(cats) - 1)
Next oVendor
.Cancelled = False
.cmdOK.Enabled = True
.Show vbModal
Dim i As Integer
For i = 0 To .ListBox1.ListCount - 1
If .ListBox1.Selected(i) Then
'Debug.Print .ListBox1.List(i)
'Debug.Print oDictVendor(.ListBox1.List(i))
End If
Next i
'
' now find the categories owned by these vendors
'
End With
End Sub
oMS.Load "c:\temp\CVS_PIP_Security.xml"
Dim oAccessor As IXMLDOMNode
Set oMeasures =
oAccessor.SelectSingleNode("RuleDomain/Dimension[@name='Measures']")
GoTo SKIP
Next oAccessor
End Sub